From c8692c0887191667c1335814eb05f2a77c90ee2a Mon Sep 17 00:00:00 2001 From: tienifr Date: Fri, 27 Oct 2023 00:44:15 +0700 Subject: [PATCH 001/175] fix: app uses ultra-wide camera by default --- src/pages/iou/ReceiptSelector/index.js | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/pages/iou/ReceiptSelector/index.js b/src/pages/iou/ReceiptSelector/index.js index ca9fe90575e7..9181d0bd2701 100644 --- a/src/pages/iou/ReceiptSelector/index.js +++ b/src/pages/iou/ReceiptSelector/index.js @@ -1,5 +1,5 @@ import {View, Text, PixelRatio, ActivityIndicator, PanResponder} from 'react-native'; -import React, {useCallback, useContext, useReducer, useRef, useState} from 'react'; +import React, {useCallback, useContext, useEffect, useReducer, useRef, useState} from 'react'; import lodashGet from 'lodash/get'; import _ from 'underscore'; import PropTypes from 'prop-types'; @@ -84,6 +84,7 @@ function ReceiptSelector({route, transactionID, iou, report}) { const [isFlashLightOn, toggleFlashlight] = useReducer((state) => !state, false); const [isTorchAvailable, setIsTorchAvailable] = useState(true); const cameraRef = useRef(null); + const normalCameraDeviceIdRef = useRef(null); const hideReciptModal = () => { setIsAttachmentInvalid(false); @@ -169,6 +170,24 @@ function ReceiptSelector({route, transactionID, iou, report}) { }), ).current; + /** + * On phones that have ultra-wide lens, default camera is ultra-wide. + * The last deviceId is of regular len camera. + */ + useEffect(() => { + if (!navigator || !navigator.mediaDevices || !navigator.mediaDevices.enumerateDevices) { + return; + } + + navigator.mediaDevices.enumerateDevices().then((devices) => { + normalCameraDeviceIdRef.current = _.chain(devices) + .filter((device) => device.kind === 'videoinput') + .last() + .get('deviceId', '') + .value(); + }); + }, []); + const mobileCameraView = () => ( <> @@ -197,7 +216,7 @@ function ReceiptSelector({route, transactionID, iou, report}) { style={{...styles.videoContainer, display: cameraPermissionState !== 'granted' ? 'none' : 'block'}} ref={cameraRef} screenshotFormat="image/png" - videoConstraints={{facingMode: {exact: 'environment'}}} + videoConstraints={{facingMode: {exact: 'environment'}, deviceId: normalCameraDeviceIdRef.current}} torchOn={isFlashLightOn} onTorchAvailability={setIsTorchAvailable} forceScreenshotSourceSize From 3d3bd77d7c1d633ed42adef361952bc588db050f Mon Sep 17 00:00:00 2001 From: tienifr Date: Fri, 27 Oct 2023 16:54:07 +0700 Subject: [PATCH 002/175] useState approach --- src/pages/iou/ReceiptSelector/index.js | 47 +++++++++++++++----------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/src/pages/iou/ReceiptSelector/index.js b/src/pages/iou/ReceiptSelector/index.js index 9181d0bd2701..601a1abd4773 100644 --- a/src/pages/iou/ReceiptSelector/index.js +++ b/src/pages/iou/ReceiptSelector/index.js @@ -84,7 +84,32 @@ function ReceiptSelector({route, transactionID, iou, report}) { const [isFlashLightOn, toggleFlashlight] = useReducer((state) => !state, false); const [isTorchAvailable, setIsTorchAvailable] = useState(true); const cameraRef = useRef(null); - const normalCameraDeviceIdRef = useRef(null); + const [videoConstraints, setVideoConstraints] = useState({facingMode: {exact: 'environment'}}); + + /** + * On phones that have ultra-wide lens, react-webcam uses ultra-wide by default. + * The last deviceId is of regular len camera. + */ + useEffect(() => { + navigator.mediaDevices.getUserMedia({audio: true, video: true}).then(() => { + if (!navigator.mediaDevices.enumerateDevices) { + return; + } + + navigator.mediaDevices.enumerateDevices().then((devices) => { + const lastBackDeviceId = _.chain(devices) + .reverse() + .find((item) => item.label && item.label.endsWith('facing back')) + .get('deviceId', '') + .value(); + + if (!lastBackDeviceId) { + return; + } + setVideoConstraints({deviceId: lastBackDeviceId}); + }); + }); + }, []); const hideReciptModal = () => { setIsAttachmentInvalid(false); @@ -170,24 +195,6 @@ function ReceiptSelector({route, transactionID, iou, report}) { }), ).current; - /** - * On phones that have ultra-wide lens, default camera is ultra-wide. - * The last deviceId is of regular len camera. - */ - useEffect(() => { - if (!navigator || !navigator.mediaDevices || !navigator.mediaDevices.enumerateDevices) { - return; - } - - navigator.mediaDevices.enumerateDevices().then((devices) => { - normalCameraDeviceIdRef.current = _.chain(devices) - .filter((device) => device.kind === 'videoinput') - .last() - .get('deviceId', '') - .value(); - }); - }, []); - const mobileCameraView = () => ( <> @@ -216,7 +223,7 @@ function ReceiptSelector({route, transactionID, iou, report}) { style={{...styles.videoContainer, display: cameraPermissionState !== 'granted' ? 'none' : 'block'}} ref={cameraRef} screenshotFormat="image/png" - videoConstraints={{facingMode: {exact: 'environment'}, deviceId: normalCameraDeviceIdRef.current}} + videoConstraints={videoConstraints} torchOn={isFlashLightOn} onTorchAvailability={setIsTorchAvailable} forceScreenshotSourceSize From 56f99e6edd04dbf09188dce97e9c61820be40f8c Mon Sep 17 00:00:00 2001 From: tienifr Date: Mon, 30 Oct 2023 09:44:17 +0700 Subject: [PATCH 003/175] remove getUserMedia --- src/pages/iou/ReceiptSelector/index.js | 56 +++++++++++++------------- 1 file changed, 29 insertions(+), 27 deletions(-) diff --git a/src/pages/iou/ReceiptSelector/index.js b/src/pages/iou/ReceiptSelector/index.js index 1ead9ca45076..168ee8230ff1 100644 --- a/src/pages/iou/ReceiptSelector/index.js +++ b/src/pages/iou/ReceiptSelector/index.js @@ -84,30 +84,30 @@ function ReceiptSelector({route, transactionID, iou, report}) { const [isFlashLightOn, toggleFlashlight] = useReducer((state) => !state, false); const [isTorchAvailable, setIsTorchAvailable] = useState(true); const cameraRef = useRef(null); - const [videoConstraints, setVideoConstraints] = useState({facingMode: {exact: 'environment'}}); + const [videoConstraints, setVideoConstraints] = useState(null); /** * On phones that have ultra-wide lens, react-webcam uses ultra-wide by default. * The last deviceId is of regular len camera. */ useEffect(() => { - navigator.mediaDevices.getUserMedia({audio: true, video: true}).then(() => { - if (!navigator.mediaDevices.enumerateDevices) { + if (!navigator.mediaDevices.enumerateDevices) { + setVideoConstraints({facingMode: {exact: 'environment'}}); + return; + } + + navigator.mediaDevices.enumerateDevices().then((devices) => { + const lastBackDeviceId = _.chain(devices) + .filter((item) => item.label && item.label.endsWith('facing back')) + .last() + .get('deviceId', '') + .value(); + + if (!lastBackDeviceId) { + setVideoConstraints({facingMode: {exact: 'environment'}}); return; } - - navigator.mediaDevices.enumerateDevices().then((devices) => { - const lastBackDeviceId = _.chain(devices) - .reverse() - .find((item) => item.label && item.label.endsWith('facing back')) - .get('deviceId', '') - .value(); - - if (!lastBackDeviceId) { - return; - } - setVideoConstraints({deviceId: lastBackDeviceId}); - }); + setVideoConstraints({deviceId: lastBackDeviceId}); }); }, []); @@ -217,17 +217,19 @@ function ReceiptSelector({route, transactionID, iou, report}) { {translate('receipt.cameraAccess')} )} - setCameraPermissionState('granted')} - onUserMediaError={() => setCameraPermissionState('denied')} - style={{...styles.videoContainer, display: cameraPermissionState !== 'granted' ? 'none' : 'block'}} - ref={cameraRef} - screenshotFormat="image/png" - videoConstraints={videoConstraints} - torchOn={isFlashLightOn} - onTorchAvailability={setIsTorchAvailable} - forceScreenshotSourceSize - /> + {videoConstraints && ( + setCameraPermissionState('granted')} + onUserMediaError={() => setCameraPermissionState('denied')} + style={{...styles.videoContainer, display: cameraPermissionState !== 'granted' ? 'none' : 'block'}} + ref={cameraRef} + screenshotFormat="image/png" + videoConstraints={videoConstraints} + torchOn={isFlashLightOn} + onTorchAvailability={setIsTorchAvailable} + forceScreenshotSourceSize + /> + )} From 3180d32f66ebd7cc30603e17cae250d3bb705368 Mon Sep 17 00:00:00 2001 From: tienifr Date: Mon, 30 Oct 2023 18:11:32 +0700 Subject: [PATCH 004/175] close active stream --- src/pages/iou/ReceiptSelector/index.js | 30 +++++++++++++++----------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/src/pages/iou/ReceiptSelector/index.js b/src/pages/iou/ReceiptSelector/index.js index 168ee8230ff1..304d7c44da43 100644 --- a/src/pages/iou/ReceiptSelector/index.js +++ b/src/pages/iou/ReceiptSelector/index.js @@ -91,23 +91,27 @@ function ReceiptSelector({route, transactionID, iou, report}) { * The last deviceId is of regular len camera. */ useEffect(() => { - if (!navigator.mediaDevices.enumerateDevices) { - setVideoConstraints({facingMode: {exact: 'environment'}}); - return; - } + navigator.mediaDevices.getUserMedia({audio: true, video: true}).then((stream) => { + _.forEach(stream.getTracks(), (videoStream) => videoStream.stop()); - navigator.mediaDevices.enumerateDevices().then((devices) => { - const lastBackDeviceId = _.chain(devices) - .filter((item) => item.label && item.label.endsWith('facing back')) - .last() - .get('deviceId', '') - .value(); - - if (!lastBackDeviceId) { + if (!navigator.mediaDevices.enumerateDevices) { setVideoConstraints({facingMode: {exact: 'environment'}}); return; } - setVideoConstraints({deviceId: lastBackDeviceId}); + + navigator.mediaDevices.enumerateDevices().then((devices) => { + const lastBackDeviceId = _.chain(devices) + .filter((item) => item.kind === 'videoinput') + .last() + .get('deviceId', '') + .value(); + + if (!lastBackDeviceId) { + setVideoConstraints({facingMode: {exact: 'environment'}}); + return; + } + setVideoConstraints({deviceId: lastBackDeviceId}); + }); }); }, []); From c853f697eafa8d3b070bf4bf518aae31f769e720 Mon Sep 17 00:00:00 2001 From: tienifr Date: Mon, 6 Nov 2023 12:22:43 +0700 Subject: [PATCH 005/175] do not request permission on desktop --- src/pages/iou/ReceiptSelector/index.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/pages/iou/ReceiptSelector/index.js b/src/pages/iou/ReceiptSelector/index.js index fdef1a7af941..17323b3ae687 100644 --- a/src/pages/iou/ReceiptSelector/index.js +++ b/src/pages/iou/ReceiptSelector/index.js @@ -91,6 +91,10 @@ function ReceiptSelector({route, transactionID, iou, report}) { * The last deviceId is of regular len camera. */ useEffect(() => { + if (!Browser.isMobile()) { + return; + } + navigator.mediaDevices.getUserMedia({video: true}).then((stream) => { _.forEach(stream.getTracks(), (videoStream) => videoStream.stop()); From c7bbfd4cf1529e6ba40bf206e96bc70eee26c9a9 Mon Sep 17 00:00:00 2001 From: tienifr Date: Wed, 8 Nov 2023 16:59:28 +0700 Subject: [PATCH 006/175] only request permission on Scan tab focus --- src/pages/iou/ReceiptSelector/index.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/pages/iou/ReceiptSelector/index.js b/src/pages/iou/ReceiptSelector/index.js index 4e482d13fb44..6d65d250f1a6 100644 --- a/src/pages/iou/ReceiptSelector/index.js +++ b/src/pages/iou/ReceiptSelector/index.js @@ -1,8 +1,10 @@ +import {useIsFocused} from '@react-navigation/native'; import lodashGet from 'lodash/get'; import PropTypes from 'prop-types'; import React, {useCallback, useContext, useEffect, useReducer, useRef, useState} from 'react'; import {ActivityIndicator, PanResponder, PixelRatio, Text, View} from 'react-native'; import {withOnyx} from 'react-native-onyx'; +import _ from 'underscore'; import Hand from '@assets/images/hand.svg'; import ReceiptUpload from '@assets/images/receipt-upload.svg'; import Shutter from '@assets/images/shutter.svg'; @@ -84,13 +86,14 @@ function ReceiptSelector({route, transactionID, iou, report}) { const [isTorchAvailable, setIsTorchAvailable] = useState(true); const cameraRef = useRef(null); const [videoConstraints, setVideoConstraints] = useState(null); + const isCameraActive = useIsFocused(); /** * On phones that have ultra-wide lens, react-webcam uses ultra-wide by default. * The last deviceId is of regular len camera. */ useEffect(() => { - if (!Browser.isMobile()) { + if (!_.isEmpty(videoConstraints) || !isCameraActive || !Browser.isMobile()) { return; } @@ -116,7 +119,7 @@ function ReceiptSelector({route, transactionID, iou, report}) { setVideoConstraints({deviceId: lastBackDeviceId}); }); }); - }, []); + }, [isCameraActive]); const hideReciptModal = () => { setIsAttachmentInvalid(false); From 586259d96d984f6fdeb0dfab37700a8248e841f2 Mon Sep 17 00:00:00 2001 From: tienifr Date: Wed, 8 Nov 2023 17:02:22 +0700 Subject: [PATCH 007/175] fix lint --- src/pages/iou/ReceiptSelector/index.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pages/iou/ReceiptSelector/index.js b/src/pages/iou/ReceiptSelector/index.js index 6d65d250f1a6..63f382baa7ed 100644 --- a/src/pages/iou/ReceiptSelector/index.js +++ b/src/pages/iou/ReceiptSelector/index.js @@ -119,6 +119,7 @@ function ReceiptSelector({route, transactionID, iou, report}) { setVideoConstraints({deviceId: lastBackDeviceId}); }); }); + // eslint-disable-next-line react-hooks/exhaustive-deps }, [isCameraActive]); const hideReciptModal = () => { From 8b7f74c22a935f44879af65c652dec2c32360bbf Mon Sep 17 00:00:00 2001 From: tienifr Date: Mon, 4 Dec 2023 15:58:16 +0700 Subject: [PATCH 008/175] bool check videoConstraints --- src/pages/iou/ReceiptSelector/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/iou/ReceiptSelector/index.js b/src/pages/iou/ReceiptSelector/index.js index 67211f5c42ee..c68c20b5c643 100644 --- a/src/pages/iou/ReceiptSelector/index.js +++ b/src/pages/iou/ReceiptSelector/index.js @@ -229,7 +229,7 @@ function ReceiptSelector({route, transactionID, iou, report}) { {translate('receipt.cameraAccess')} )} - {videoConstraints && ( + {!_.isEmpty(videoConstraints) && ( setCameraPermissionState('granted')} onUserMediaError={() => setCameraPermissionState('denied')} From 167775a4d69447f674cad364a891105e53b83e09 Mon Sep 17 00:00:00 2001 From: tienifr Date: Fri, 12 Jan 2024 14:19:45 +0700 Subject: [PATCH 009/175] Reapply changes --- .../request/step/IOURequestStepScan/index.js | 68 +++++++++++++++---- 1 file changed, 55 insertions(+), 13 deletions(-) diff --git a/src/pages/iou/request/step/IOURequestStepScan/index.js b/src/pages/iou/request/step/IOURequestStepScan/index.js index c0c96826d124..3aa4235dea5d 100644 --- a/src/pages/iou/request/step/IOURequestStepScan/index.js +++ b/src/pages/iou/request/step/IOURequestStepScan/index.js @@ -1,6 +1,7 @@ import lodashGet from 'lodash/get'; -import React, {useCallback, useContext, useReducer, useRef, useState} from 'react'; +import React, {useCallback, useContext, useEffect, useReducer, useRef, useState} from 'react'; import {ActivityIndicator, PanResponder, PixelRatio, Text, View} from 'react-native'; +import _ from 'underscore'; import Hand from '@assets/images/hand.svg'; import ReceiptUpload from '@assets/images/receipt-upload.svg'; import Shutter from '@assets/images/shutter.svg'; @@ -14,6 +15,7 @@ import * as Expensicons from '@components/Icon/Expensicons'; import PressableWithFeedback from '@components/Pressable/PressableWithFeedback'; import transactionPropTypes from '@components/transactionPropTypes'; import useLocalize from '@hooks/useLocalize'; +import useTabNavigatorFocus from '@hooks/useTabNavigatorFocus'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import useWindowDimensions from '@hooks/useWindowDimensions'; @@ -74,6 +76,44 @@ function IOURequestStepScan({ const [isTorchAvailable, setIsTorchAvailable] = useState(false); const cameraRef = useRef(null); + const [videoConstraints, setVideoConstraints] = useState(null); + const tabIndex = 1; + const isScanTabActive = useTabNavigatorFocus({tabIndex}); + + /** + * On phones that have ultra-wide lens, react-webcam uses ultra-wide by default. + * The last deviceId is of regular len camera. + */ + useEffect(() => { + if (!_.isEmpty(videoConstraints) || !isScanTabActive || !Browser.isMobile()) { + return; + } + + navigator.mediaDevices.getUserMedia({video: true}).then((stream) => { + _.forEach(stream.getTracks(), (videoStream) => videoStream.stop()); + + if (!navigator.mediaDevices.enumerateDevices) { + setVideoConstraints({facingMode: {exact: 'environment'}}); + return; + } + + navigator.mediaDevices.enumerateDevices().then((devices) => { + const lastBackDeviceId = _.chain(devices) + .filter((item) => item.kind === 'videoinput') + .last() + .get('deviceId', '') + .value(); + + if (!lastBackDeviceId) { + setVideoConstraints({facingMode: {exact: 'environment'}}); + return; + } + setVideoConstraints({deviceId: lastBackDeviceId}); + }); + }); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [isScanTabActive]); + const hideRecieptModal = () => { setIsAttachmentInvalid(false); }; @@ -211,18 +251,20 @@ function IOURequestStepScan({ {translate('receipt.cameraAccess')} )} - setCameraPermissionState('granted')} - onUserMediaError={() => setCameraPermissionState('denied')} - style={{...styles.videoContainer, display: cameraPermissionState !== 'granted' ? 'none' : 'block'}} - ref={cameraRef} - screenshotFormat="image/png" - videoConstraints={{facingMode: {exact: 'environment'}}} - torchOn={isFlashLightOn} - onTorchAvailability={setIsTorchAvailable} - forceScreenshotSourceSize - cameraTabIndex={1} - /> + {!_.isEmpty(videoConstraints) && ( + setCameraPermissionState('granted')} + onUserMediaError={() => setCameraPermissionState('denied')} + style={{...styles.videoContainer, display: cameraPermissionState !== 'granted' ? 'none' : 'block'}} + ref={cameraRef} + screenshotFormat="image/png" + videoConstraints={videoConstraints} + torchOn={isFlashLightOn} + onTorchAvailability={setIsTorchAvailable} + forceScreenshotSourceSize + cameraTabIndex={tabIndex} + /> + )} From 6afd422e26ec35c5912b7b00945dc9c3d57e2804 Mon Sep 17 00:00:00 2001 From: tienifr Date: Fri, 12 Jan 2024 14:30:37 +0700 Subject: [PATCH 010/175] fix lint --- src/pages/iou/request/step/IOURequestStepScan/index.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/pages/iou/request/step/IOURequestStepScan/index.js b/src/pages/iou/request/step/IOURequestStepScan/index.js index 3aa4235dea5d..2a7c8be25950 100644 --- a/src/pages/iou/request/step/IOURequestStepScan/index.js +++ b/src/pages/iou/request/step/IOURequestStepScan/index.js @@ -78,14 +78,14 @@ function IOURequestStepScan({ const [videoConstraints, setVideoConstraints] = useState(null); const tabIndex = 1; - const isScanTabActive = useTabNavigatorFocus({tabIndex}); + const isTabActive = useTabNavigatorFocus({tabIndex}); /** * On phones that have ultra-wide lens, react-webcam uses ultra-wide by default. * The last deviceId is of regular len camera. */ useEffect(() => { - if (!_.isEmpty(videoConstraints) || !isScanTabActive || !Browser.isMobile()) { + if (!_.isEmpty(videoConstraints) || !isTabActive || !Browser.isMobile()) { return; } @@ -112,7 +112,7 @@ function IOURequestStepScan({ }); }); // eslint-disable-next-line react-hooks/exhaustive-deps - }, [isScanTabActive]); + }, [isTabActive]); const hideRecieptModal = () => { setIsAttachmentInvalid(false); From bd5f17703af96409056a743804362e7f7efbf149 Mon Sep 17 00:00:00 2001 From: Toby Sullivan Date: Fri, 24 Nov 2023 16:07:50 -0800 Subject: [PATCH 011/175] Include comment in report name for amounts owing --- src/languages/en.ts | 2 +- src/languages/es.ts | 2 +- src/languages/types.ts | 2 +- src/libs/ReportUtils.ts | 38 +++++++++++++++++++++++--------------- 4 files changed, 26 insertions(+), 18 deletions(-) diff --git a/src/languages/en.ts b/src/languages/en.ts index b6da38df21a0..87b12f631631 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -601,7 +601,7 @@ export default { splitAmount: ({amount}: SplitAmountParams) => `split ${amount}`, didSplitAmount: ({formattedAmount, comment}: DidSplitAmountMessageParams) => `split ${formattedAmount}${comment ? ` for ${comment}` : ''}`, amountEach: ({amount}: AmountEachParams) => `${amount} each`, - payerOwesAmount: ({payer, amount}: PayerOwesAmountParams) => `${payer} owes ${amount}`, + payerOwesAmount: ({payer, amount, comment}: PayerOwesAmountParams) => `${payer} owes ${amount}${comment ? ` for ${comment}` : ''}`, payerOwes: ({payer}: PayerOwesParams) => `${payer} owes: `, payerPaidAmount: ({payer, amount}: PayerPaidAmountParams): string => `${payer ? `${payer} ` : ''}paid ${amount}`, payerPaid: ({payer}: PayerPaidParams) => `${payer} paid: `, diff --git a/src/languages/es.ts b/src/languages/es.ts index 2478c8ba8bd2..2c7e58655ca8 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -594,7 +594,7 @@ export default { splitAmount: ({amount}: SplitAmountParams) => `dividir ${amount}`, didSplitAmount: ({formattedAmount, comment}: DidSplitAmountMessageParams) => `dividió ${formattedAmount}${comment ? ` para ${comment}` : ''}`, amountEach: ({amount}: AmountEachParams) => `${amount} cada uno`, - payerOwesAmount: ({payer, amount}: PayerOwesAmountParams) => `${payer} debe ${amount}`, + payerOwesAmount: ({payer, amount, comment}: PayerOwesAmountParams) => `${payer} debe ${amount}${comment ? ` para ${comment}` : ''}`, payerOwes: ({payer}: PayerOwesParams) => `${payer} debe: `, payerPaidAmount: ({payer, amount}: PayerPaidAmountParams) => `${payer ? `${payer} ` : ''}pagó ${amount}`, payerPaid: ({payer}: PayerPaidParams) => `${payer} pagó: `, diff --git a/src/languages/types.ts b/src/languages/types.ts index 3185b7a8f6f1..eab9991b73d8 100644 --- a/src/languages/types.ts +++ b/src/languages/types.ts @@ -115,7 +115,7 @@ type DidSplitAmountMessageParams = {formattedAmount: string; comment: string}; type AmountEachParams = {amount: number}; -type PayerOwesAmountParams = {payer: string; amount: number | string}; +type PayerOwesAmountParams = {payer: string; amount: number | string; comment?: string}; type PayerOwesParams = {payer: string}; diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index d48567ebdaf3..32fb047d9126 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -2178,26 +2178,28 @@ function getReportPreviewMessage( return reportActionMessage; } + let linkedTransaction: Transaction | EmptyObject = {}; + if (!isEmptyObject(reportAction)) { + linkedTransaction = TransactionUtils.getLinkedTransaction(reportAction); + } + if (!isEmptyObject(reportAction) && !isIOUReport(report) && reportAction && ReportActionsUtils.isSplitBillAction(reportAction)) { // This covers group chats where the last action is a split bill action - const linkedTransaction = TransactionUtils.getLinkedTransaction(reportAction); if (isEmptyObject(linkedTransaction)) { return reportActionMessage; } - if (!isEmptyObject(linkedTransaction)) { - if (TransactionUtils.isReceiptBeingScanned(linkedTransaction)) { - return Localize.translateLocal('iou.receiptScanning'); - } - - if (TransactionUtils.hasMissingSmartscanFields(linkedTransaction)) { - return Localize.translateLocal('iou.receiptMissingDetails'); - } + if (TransactionUtils.isReceiptBeingScanned(linkedTransaction)) { + return Localize.translateLocal('iou.receiptScanning'); + } - const transactionDetails = getTransactionDetails(linkedTransaction); - const formattedAmount = CurrencyUtils.convertToDisplayString(transactionDetails?.amount ?? 0, transactionDetails?.currency ?? ''); - return Localize.translateLocal('iou.didSplitAmount', {formattedAmount, comment: transactionDetails?.comment ?? ''}); + if (TransactionUtils.hasMissingSmartscanFields(linkedTransaction)) { + return Localize.translateLocal('iou.receiptMissingDetails'); } + + const transactionDetails = getTransactionDetails(linkedTransaction); + const formattedAmount = CurrencyUtils.convertToDisplayString(transactionDetails?.amount ?? 0, transactionDetails?.currency ?? ''); + return Localize.translateLocal('iou.didSplitAmount', {formattedAmount, comment: transactionDetails?.comment ?? ''}); } const totalAmount = getMoneyRequestReimbursableTotal(report); @@ -2214,8 +2216,6 @@ function getReportPreviewMessage( } if (!isEmptyObject(reportAction) && shouldConsiderReceiptBeingScanned && reportAction && ReportActionsUtils.isMoneyRequestAction(reportAction)) { - const linkedTransaction = TransactionUtils.getLinkedTransaction(reportAction); - if (!isEmptyObject(linkedTransaction) && TransactionUtils.hasReceipt(linkedTransaction) && TransactionUtils.isReceiptBeingScanned(linkedTransaction)) { return Localize.translateLocal('iou.receiptScanning'); } @@ -2261,7 +2261,15 @@ function getReportPreviewMessage( return `${requestorName ? `${requestorName}: ` : ''}${Localize.translateLocal('iou.requestedAmount', {formattedAmount: amountToDisplay})}`; } - return Localize.translateLocal(containsNonReimbursable ? 'iou.payerSpentAmount' : 'iou.payerOwesAmount', {payer: payerName ?? '', amount: formattedAmount}); + if (containsNonReimbursable) { + return Localize.translateLocal('iou.payerSpentAmount', {payer: payerName ?? '', amount: formattedAmount}); + } + + if (!isEmptyObject(linkedTransaction)) { + const comment = TransactionUtils.getDescription(linkedTransaction); + return Localize.translateLocal('iou.payerOwesAmount', {payer: payerName ?? '', amount: formattedAmount, comment}); + } + return Localize.translateLocal('iou.payerOwesAmount', {payer: payerName ?? '', amount: formattedAmount}); } /** From ee2c15d47495cc7a81ffc8e52319cd0bcd817fdc Mon Sep 17 00:00:00 2001 From: Toby Sullivan Date: Fri, 19 Jan 2024 09:30:14 -0800 Subject: [PATCH 012/175] Reuse translateLocal call --- src/libs/ReportUtils.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 32fb047d9126..4cdcdc863aa3 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -2265,11 +2265,11 @@ function getReportPreviewMessage( return Localize.translateLocal('iou.payerSpentAmount', {payer: payerName ?? '', amount: formattedAmount}); } + let comment: string | undefined if (!isEmptyObject(linkedTransaction)) { - const comment = TransactionUtils.getDescription(linkedTransaction); - return Localize.translateLocal('iou.payerOwesAmount', {payer: payerName ?? '', amount: formattedAmount, comment}); + comment = TransactionUtils.getDescription(linkedTransaction); } - return Localize.translateLocal('iou.payerOwesAmount', {payer: payerName ?? '', amount: formattedAmount}); + return Localize.translateLocal('iou.payerOwesAmount', {payer: payerName ?? '', amount: formattedAmount, comment}); } /** From eeca194eaaddc0ef1ae75312d29b4552e8024aab Mon Sep 17 00:00:00 2001 From: Toby Sullivan Date: Fri, 19 Jan 2024 10:29:53 -0800 Subject: [PATCH 013/175] Remove redundant type declaration --- src/libs/ReportUtils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 4cdcdc863aa3..d1d38bbff305 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -2265,7 +2265,7 @@ function getReportPreviewMessage( return Localize.translateLocal('iou.payerSpentAmount', {payer: payerName ?? '', amount: formattedAmount}); } - let comment: string | undefined + let comment if (!isEmptyObject(linkedTransaction)) { comment = TransactionUtils.getDescription(linkedTransaction); } From db0d8d1ecc0436fbba67479a230a9de0809850f4 Mon Sep 17 00:00:00 2001 From: Toby Sullivan Date: Fri, 19 Jan 2024 10:51:27 -0800 Subject: [PATCH 014/175] Avoid variable reassignments --- src/libs/ReportUtils.ts | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index d1d38bbff305..e57dff6b4ae2 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -2178,11 +2178,7 @@ function getReportPreviewMessage( return reportActionMessage; } - let linkedTransaction: Transaction | EmptyObject = {}; - if (!isEmptyObject(reportAction)) { - linkedTransaction = TransactionUtils.getLinkedTransaction(reportAction); - } - + const linkedTransaction = !isEmptyObject(reportAction) ? TransactionUtils.getLinkedTransaction(reportAction) : {}; if (!isEmptyObject(reportAction) && !isIOUReport(report) && reportAction && ReportActionsUtils.isSplitBillAction(reportAction)) { // This covers group chats where the last action is a split bill action if (isEmptyObject(linkedTransaction)) { @@ -2265,10 +2261,7 @@ function getReportPreviewMessage( return Localize.translateLocal('iou.payerSpentAmount', {payer: payerName ?? '', amount: formattedAmount}); } - let comment - if (!isEmptyObject(linkedTransaction)) { - comment = TransactionUtils.getDescription(linkedTransaction); - } + const comment = !isEmptyObject(linkedTransaction) ? TransactionUtils.getDescription(linkedTransaction) : undefined; return Localize.translateLocal('iou.payerOwesAmount', {payer: payerName ?? '', amount: formattedAmount, comment}); } From c2731c056e804b06b93cbe63c0ed79f9ab8d9ea6 Mon Sep 17 00:00:00 2001 From: Toby Sullivan Date: Fri, 19 Jan 2024 10:52:31 -0800 Subject: [PATCH 015/175] Remove unrelated code change --- src/libs/ReportUtils.ts | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index e57dff6b4ae2..ee85c1aca958 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -2185,17 +2185,19 @@ function getReportPreviewMessage( return reportActionMessage; } - if (TransactionUtils.isReceiptBeingScanned(linkedTransaction)) { - return Localize.translateLocal('iou.receiptScanning'); - } + if (!isEmptyObject(linkedTransaction)) { + if (TransactionUtils.isReceiptBeingScanned(linkedTransaction)) { + return Localize.translateLocal('iou.receiptScanning'); + } - if (TransactionUtils.hasMissingSmartscanFields(linkedTransaction)) { - return Localize.translateLocal('iou.receiptMissingDetails'); - } + if (TransactionUtils.hasMissingSmartscanFields(linkedTransaction)) { + return Localize.translateLocal('iou.receiptMissingDetails'); + } - const transactionDetails = getTransactionDetails(linkedTransaction); - const formattedAmount = CurrencyUtils.convertToDisplayString(transactionDetails?.amount ?? 0, transactionDetails?.currency ?? ''); - return Localize.translateLocal('iou.didSplitAmount', {formattedAmount, comment: transactionDetails?.comment ?? ''}); + const transactionDetails = getTransactionDetails(linkedTransaction); + const formattedAmount = CurrencyUtils.convertToDisplayString(transactionDetails?.amount ?? 0, transactionDetails?.currency ?? ''); + return Localize.translateLocal('iou.didSplitAmount', {formattedAmount, comment: transactionDetails?.comment ?? ''}); + } } const totalAmount = getMoneyRequestReimbursableTotal(report); From 036ac5c5a87fb72784b60fb899c656d346b29a74 Mon Sep 17 00:00:00 2001 From: Toby Sullivan Date: Fri, 19 Jan 2024 14:51:11 -0800 Subject: [PATCH 016/175] Update editRegularMoneyTransaction --- src/libs/actions/IOU.js | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index 7ee752a1f0ef..410da027351a 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -2272,10 +2272,16 @@ function editRegularMoneyRequest(transactionID, transactionThreadReportID, trans // Update the last message of the chat report const hasNonReimbursableTransactions = ReportUtils.hasNonReimbursableTransactions(iouReport); - const messageText = Localize.translateLocal(hasNonReimbursableTransactions ? 'iou.payerSpentAmount' : 'iou.payerOwesAmount', { - payer: ReportUtils.getPersonalDetailsForAccountID(updatedMoneyRequestReport.managerID).login || '', - amount: CurrencyUtils.convertToDisplayString(updatedMoneyRequestReport.total, updatedMoneyRequestReport.currency), - }); + const payer = ReportUtils.getPersonalDetailsForAccountID(updatedMoneyRequestReport.managerID).login || '' + const formattedAmount = CurrencyUtils.convertToDisplayString(updatedMoneyRequestReport.total, updatedMoneyRequestReport.currency) + let messageText + if (hasNonReimbursableTransactions) { + messageText = Localize.translateLocal('iou.payerSpentAmount', { payer, amount: formattedAmount }); + } else { + const comment = TransactionUtils.getDescription(updatedTransaction) + messageText = Localize.translateLocal('iou.payerOwesAmount', { payer, amount: formattedAmount, comment }); + } + updatedChatReport.lastMessageText = messageText; updatedChatReport.lastMessageHtml = messageText; } From 40073f04b4eed15987aa815497b75776cefc2e5b Mon Sep 17 00:00:00 2001 From: Toby Sullivan Date: Fri, 19 Jan 2024 16:00:57 -0800 Subject: [PATCH 017/175] Include request description when request deleted --- src/libs/actions/IOU.js | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index 410da027351a..f861a37b1051 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -28,6 +28,7 @@ import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import * as Policy from './Policy'; import * as Report from './Report'; +import { isEmptyObject } from '@src/types/utils/EmptyObject'; let betas; Onyx.connect({ @@ -2569,10 +2570,16 @@ function deleteMoneyRequest(transactionID, reportAction, isSingleTransactionView updatedIOUReport.lastVisibleActionCreated = lodashGet(lastVisibleAction, 'created'); const hasNonReimbursableTransactions = ReportUtils.hasNonReimbursableTransactions(iouReport); - const messageText = Localize.translateLocal(hasNonReimbursableTransactions ? 'iou.payerSpentAmount' : 'iou.payerOwesAmount', { - payer: ReportUtils.getPersonalDetailsForAccountID(updatedIOUReport.managerID).login || '', - amount: CurrencyUtils.convertToDisplayString(updatedIOUReport.total, updatedIOUReport.currency), - }); + const payer = ReportUtils.getPersonalDetailsForAccountID(updatedIOUReport.managerID).login || ''; + const formattedAmount = CurrencyUtils.convertToDisplayString(updatedIOUReport.total, updatedIOUReport.currency); + let messageText + if (hasNonReimbursableTransactions) { + messageText = Localize.translateLocal('iou.payerSpentAmount', {payer, amount: formattedAmount}) + } else { + const comment = !isEmptyObject(transaction) ? TransactionUtils.getDescription(transaction) : undefined; + messageText = Localize.translateLocal('iou.payerOwesAmount', {payer, amount: formattedAmount, comment}) + } + updatedReportPreviewAction.message[0].text = messageText; updatedReportPreviewAction.message[0].html = messageText; From f7032dd759854ce6da538e79dd855894814c9b12 Mon Sep 17 00:00:00 2001 From: Toby Sullivan Date: Fri, 19 Jan 2024 16:03:13 -0800 Subject: [PATCH 018/175] Include IOU description in report name --- src/libs/ReportUtils.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index ee85c1aca958..2928e54a79ee 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -1928,7 +1928,9 @@ function getMoneyRequestReportName(report: OnyxEntry, policy: OnyxEntry< } if (isProcessingReport(report) || isDraftExpenseReport(report) || moneyRequestTotal === 0) { - return Localize.translateLocal('iou.payerOwesAmount', {payer: payerOrApproverName, amount: formattedAmount}); + const reportTransactions = !isEmptyObject(report) ? TransactionUtils.getAllReportTransactions(report.reportID) : [] + const comment = reportTransactions.length === 1 ? TransactionUtils.getDescription(reportTransactions[0]) : undefined + return Localize.translateLocal('iou.payerOwesAmount', {payer: payerOrApproverName, amount: formattedAmount, comment}); } return payerPaidAmountMessage; From 2e2ac1f645337fa4d5255fc2fbfe350384a2571a Mon Sep 17 00:00:00 2001 From: Toby Sullivan Date: Fri, 19 Jan 2024 16:06:50 -0800 Subject: [PATCH 019/175] Run prettier and lint --- src/libs/ReportUtils.ts | 4 ++-- src/libs/actions/IOU.js | 20 ++++++++++---------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 2928e54a79ee..004488d3a151 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -1928,8 +1928,8 @@ function getMoneyRequestReportName(report: OnyxEntry, policy: OnyxEntry< } if (isProcessingReport(report) || isDraftExpenseReport(report) || moneyRequestTotal === 0) { - const reportTransactions = !isEmptyObject(report) ? TransactionUtils.getAllReportTransactions(report.reportID) : [] - const comment = reportTransactions.length === 1 ? TransactionUtils.getDescription(reportTransactions[0]) : undefined + const reportTransactions = !isEmptyObject(report) ? TransactionUtils.getAllReportTransactions(report.reportID) : []; + const comment = reportTransactions.length === 1 ? TransactionUtils.getDescription(reportTransactions[0]) : undefined; return Localize.translateLocal('iou.payerOwesAmount', {payer: payerOrApproverName, amount: formattedAmount, comment}); } diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index f861a37b1051..e7a579d7b671 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -26,9 +26,9 @@ import ViolationsUtils from '@libs/Violations/ViolationsUtils'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; +import {isEmptyObject} from '@src/types/utils/EmptyObject'; import * as Policy from './Policy'; import * as Report from './Report'; -import { isEmptyObject } from '@src/types/utils/EmptyObject'; let betas; Onyx.connect({ @@ -2273,14 +2273,14 @@ function editRegularMoneyRequest(transactionID, transactionThreadReportID, trans // Update the last message of the chat report const hasNonReimbursableTransactions = ReportUtils.hasNonReimbursableTransactions(iouReport); - const payer = ReportUtils.getPersonalDetailsForAccountID(updatedMoneyRequestReport.managerID).login || '' - const formattedAmount = CurrencyUtils.convertToDisplayString(updatedMoneyRequestReport.total, updatedMoneyRequestReport.currency) - let messageText + const payer = ReportUtils.getPersonalDetailsForAccountID(updatedMoneyRequestReport.managerID).login || ''; + const formattedAmount = CurrencyUtils.convertToDisplayString(updatedMoneyRequestReport.total, updatedMoneyRequestReport.currency); + let messageText; if (hasNonReimbursableTransactions) { - messageText = Localize.translateLocal('iou.payerSpentAmount', { payer, amount: formattedAmount }); + messageText = Localize.translateLocal('iou.payerSpentAmount', {payer, amount: formattedAmount}); } else { - const comment = TransactionUtils.getDescription(updatedTransaction) - messageText = Localize.translateLocal('iou.payerOwesAmount', { payer, amount: formattedAmount, comment }); + const comment = TransactionUtils.getDescription(updatedTransaction); + messageText = Localize.translateLocal('iou.payerOwesAmount', {payer, amount: formattedAmount, comment}); } updatedChatReport.lastMessageText = messageText; @@ -2572,12 +2572,12 @@ function deleteMoneyRequest(transactionID, reportAction, isSingleTransactionView const hasNonReimbursableTransactions = ReportUtils.hasNonReimbursableTransactions(iouReport); const payer = ReportUtils.getPersonalDetailsForAccountID(updatedIOUReport.managerID).login || ''; const formattedAmount = CurrencyUtils.convertToDisplayString(updatedIOUReport.total, updatedIOUReport.currency); - let messageText + let messageText; if (hasNonReimbursableTransactions) { - messageText = Localize.translateLocal('iou.payerSpentAmount', {payer, amount: formattedAmount}) + messageText = Localize.translateLocal('iou.payerSpentAmount', {payer, amount: formattedAmount}); } else { const comment = !isEmptyObject(transaction) ? TransactionUtils.getDescription(transaction) : undefined; - messageText = Localize.translateLocal('iou.payerOwesAmount', {payer, amount: formattedAmount, comment}) + messageText = Localize.translateLocal('iou.payerOwesAmount', {payer, amount: formattedAmount, comment}); } updatedReportPreviewAction.message[0].text = messageText; From 719d63d473ecb93ecc8894b9598c47bbae4d7158 Mon Sep 17 00:00:00 2001 From: Toby Sullivan Date: Fri, 26 Jan 2024 10:29:54 -0800 Subject: [PATCH 020/175] Undo changes to text outside LHN preview --- src/libs/ReportUtils.ts | 4 +--- src/libs/actions/IOU.js | 29 ++++++++--------------------- 2 files changed, 9 insertions(+), 24 deletions(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index ac1686f88544..edcd57078e0c 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -1931,9 +1931,7 @@ function getMoneyRequestReportName(report: OnyxEntry, policy: OnyxEntry< } if (isProcessingReport(report) || isDraftExpenseReport(report) || moneyRequestTotal === 0) { - const reportTransactions = !isEmptyObject(report) ? TransactionUtils.getAllReportTransactions(report.reportID) : []; - const comment = reportTransactions.length === 1 ? TransactionUtils.getDescription(reportTransactions[0]) : undefined; - return Localize.translateLocal('iou.payerOwesAmount', {payer: payerOrApproverName, amount: formattedAmount, comment}); + return Localize.translateLocal('iou.payerOwesAmount', {payer: payerOrApproverName, amount: formattedAmount}); } return payerPaidAmountMessage; diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index e7a579d7b671..7ee752a1f0ef 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -26,7 +26,6 @@ import ViolationsUtils from '@libs/Violations/ViolationsUtils'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; -import {isEmptyObject} from '@src/types/utils/EmptyObject'; import * as Policy from './Policy'; import * as Report from './Report'; @@ -2273,16 +2272,10 @@ function editRegularMoneyRequest(transactionID, transactionThreadReportID, trans // Update the last message of the chat report const hasNonReimbursableTransactions = ReportUtils.hasNonReimbursableTransactions(iouReport); - const payer = ReportUtils.getPersonalDetailsForAccountID(updatedMoneyRequestReport.managerID).login || ''; - const formattedAmount = CurrencyUtils.convertToDisplayString(updatedMoneyRequestReport.total, updatedMoneyRequestReport.currency); - let messageText; - if (hasNonReimbursableTransactions) { - messageText = Localize.translateLocal('iou.payerSpentAmount', {payer, amount: formattedAmount}); - } else { - const comment = TransactionUtils.getDescription(updatedTransaction); - messageText = Localize.translateLocal('iou.payerOwesAmount', {payer, amount: formattedAmount, comment}); - } - + const messageText = Localize.translateLocal(hasNonReimbursableTransactions ? 'iou.payerSpentAmount' : 'iou.payerOwesAmount', { + payer: ReportUtils.getPersonalDetailsForAccountID(updatedMoneyRequestReport.managerID).login || '', + amount: CurrencyUtils.convertToDisplayString(updatedMoneyRequestReport.total, updatedMoneyRequestReport.currency), + }); updatedChatReport.lastMessageText = messageText; updatedChatReport.lastMessageHtml = messageText; } @@ -2570,16 +2563,10 @@ function deleteMoneyRequest(transactionID, reportAction, isSingleTransactionView updatedIOUReport.lastVisibleActionCreated = lodashGet(lastVisibleAction, 'created'); const hasNonReimbursableTransactions = ReportUtils.hasNonReimbursableTransactions(iouReport); - const payer = ReportUtils.getPersonalDetailsForAccountID(updatedIOUReport.managerID).login || ''; - const formattedAmount = CurrencyUtils.convertToDisplayString(updatedIOUReport.total, updatedIOUReport.currency); - let messageText; - if (hasNonReimbursableTransactions) { - messageText = Localize.translateLocal('iou.payerSpentAmount', {payer, amount: formattedAmount}); - } else { - const comment = !isEmptyObject(transaction) ? TransactionUtils.getDescription(transaction) : undefined; - messageText = Localize.translateLocal('iou.payerOwesAmount', {payer, amount: formattedAmount, comment}); - } - + const messageText = Localize.translateLocal(hasNonReimbursableTransactions ? 'iou.payerSpentAmount' : 'iou.payerOwesAmount', { + payer: ReportUtils.getPersonalDetailsForAccountID(updatedIOUReport.managerID).login || '', + amount: CurrencyUtils.convertToDisplayString(updatedIOUReport.total, updatedIOUReport.currency), + }); updatedReportPreviewAction.message[0].text = messageText; updatedReportPreviewAction.message[0].html = messageText; From 2060d5e2bfc161a08b7058ce88b3603add93a3bc Mon Sep 17 00:00:00 2001 From: Jayesh Mangwani Date: Tue, 30 Jan 2024 20:15:47 +0530 Subject: [PATCH 021/175] TS-migration: TermsStep Page --- .../{TermsStep.js => TermsStep.tsx} | 69 ++++++++----------- 1 file changed, 30 insertions(+), 39 deletions(-) rename src/pages/EnablePayments/{TermsStep.js => TermsStep.tsx} (67%) diff --git a/src/pages/EnablePayments/TermsStep.js b/src/pages/EnablePayments/TermsStep.tsx similarity index 67% rename from src/pages/EnablePayments/TermsStep.js rename to src/pages/EnablePayments/TermsStep.tsx index a09e1801c3b0..a03f3607d56e 100644 --- a/src/pages/EnablePayments/TermsStep.js +++ b/src/pages/EnablePayments/TermsStep.tsx @@ -6,39 +6,34 @@ import FormAlertWithSubmitButton from '@components/FormAlertWithSubmitButton'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import Text from '@components/Text'; import TextLink from '@components/TextLink'; -import withLocalize, {withLocalizePropTypes} from '@components/withLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; -import compose from '@libs/compose'; import * as ErrorUtils from '@libs/ErrorUtils'; import * as BankAccounts from '@userActions/BankAccounts'; import ONYXKEYS from '@src/ONYXKEYS'; import LongTermsForm from './TermsPage/LongTermsForm'; import ShortTermsForm from './TermsPage/ShortTermsForm'; -import userWalletPropTypes from './userWalletPropTypes'; -import walletTermsPropTypes from './walletTermsPropTypes'; - -const propTypes = { - /** The user's wallet */ - userWallet: userWalletPropTypes, +import useLocalize from '@hooks/useLocalize'; +import type {OnyxEntry} from 'react-native-onyx'; +import {WalletTerms, UserWallet} from '@src/types/onyx'; +type TermsStepOnyxProps = { /** Comes from Onyx. Information about the terms for the wallet */ - walletTerms: walletTermsPropTypes, - - ...withLocalizePropTypes, -}; + walletTerms: OnyxEntry; +} -const defaultProps = { - userWallet: {}, - walletTerms: {}, +type TermsStepProps = TermsStepOnyxProps & { + /** The user's wallet */ + userWallet: OnyxEntry; }; -function TermsStep(props) { +function TermsStep(props: TermsStepProps) { const styles = useThemeStyles(); const [hasAcceptedDisclosure, setHasAcceptedDisclosure] = useState(false); const [hasAcceptedPrivacyPolicyAndWalletAgreement, setHasAcceptedPrivacyPolicyAndWalletAgreement] = useState(false); const [error, setError] = useState(false); + const {translate} = useLocalize(); - const errorMessage = error ? 'common.error.acceptTerms' : ErrorUtils.getLatestErrorMessage(props.walletTerms) || ''; + const errorMessage = error ? 'common.error.acceptTerms' : ErrorUtils.getLatestErrorMessage(props.walletTerms??{}) || ''; const toggleDisclosure = () => { setHasAcceptedDisclosure(!hasAcceptedDisclosure); @@ -59,7 +54,7 @@ function TermsStep(props) { return ( <> - + ( - {`${props.translate('termsStep.haveReadAndAgree')}`} - {`${props.translate('termsStep.electronicDisclosures')}.`} + {`${translate('termsStep.haveReadAndAgree')}`} + {`${translate('termsStep.electronicDisclosures')}.`} )} /> ( - {`${props.translate('termsStep.agreeToThe')} `} + {`${translate('termsStep.agreeToThe')} `} - {`${props.translate('common.privacy')} `} + {`${translate('common.privacy')} `} - {`${props.translate('common.and')} `} + {`${translate('common.and')} `} - {`${props.translate('termsStep.walletAgreement')}.`} + {`${translate('termsStep.walletAgreement')}.`} )} /> { if (!hasAcceptedDisclosure || !hasAcceptedPrivacyPolicyAndWalletAgreement) { setError(true); @@ -104,12 +99,12 @@ function TermsStep(props) { setError(false); BankAccounts.acceptWalletTerms({ hasAcceptedTerms: hasAcceptedDisclosure && hasAcceptedPrivacyPolicyAndWalletAgreement, - reportID: props.walletTerms.chatReportID, + reportID: props.walletTerms?.chatReportID??'', }); }} message={errorMessage} isAlertVisible={error || Boolean(errorMessage)} - isLoading={!!props.walletTerms.isLoading} + isLoading={!!props.walletTerms?.isLoading} containerStyles={[styles.mh0, styles.mv4]} /> @@ -118,13 +113,9 @@ function TermsStep(props) { } TermsStep.displayName = 'TermsPage'; -TermsStep.propTypes = propTypes; -TermsStep.defaultProps = defaultProps; -export default compose( - withLocalize, - withOnyx({ - walletTerms: { - key: ONYXKEYS.WALLET_TERMS, - }, - }), -)(TermsStep); + +export default withOnyx({ + walletTerms: { + key: ONYXKEYS.WALLET_TERMS, + }, +})(TermsStep); From 744a3b5f380317b65ac91925a7e1f37d36273a79 Mon Sep 17 00:00:00 2001 From: Jayesh Mangwani Date: Tue, 30 Jan 2024 20:19:34 +0530 Subject: [PATCH 022/175] TS-migration: ShortTermsForm Page --- .../{ShortTermsForm.js => ShortTermsForm.tsx} | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) rename src/pages/EnablePayments/TermsPage/{ShortTermsForm.js => ShortTermsForm.tsx} (93%) diff --git a/src/pages/EnablePayments/TermsPage/ShortTermsForm.js b/src/pages/EnablePayments/TermsPage/ShortTermsForm.tsx similarity index 93% rename from src/pages/EnablePayments/TermsPage/ShortTermsForm.js rename to src/pages/EnablePayments/TermsPage/ShortTermsForm.tsx index 40824f47b036..1c9d37bb30e9 100644 --- a/src/pages/EnablePayments/TermsPage/ShortTermsForm.js +++ b/src/pages/EnablePayments/TermsPage/ShortTermsForm.tsx @@ -5,19 +5,16 @@ import TextLink from '@components/TextLink'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import * as CurrencyUtils from '@libs/CurrencyUtils'; -import userWalletPropTypes from '@pages/EnablePayments/userWalletPropTypes'; import CONST from '@src/CONST'; +import type {OnyxEntry} from 'react-native-onyx'; +import {UserWallet} from '@src/types/onyx'; -const propTypes = { - /** The user's wallet */ - userWallet: userWalletPropTypes, +type ShortTermsFormProps = { + /** The user's wallet */ + userWallet: OnyxEntry; }; -const defaultProps = { - userWallet: {}, -}; - -function ShortTermsForm(props) { +function ShortTermsForm(props: ShortTermsFormProps) { const styles = useThemeStyles(); const {translate, numberFormat} = useLocalize(); return ( @@ -25,7 +22,7 @@ function ShortTermsForm(props) { {translate('termsStep.shortTermsForm.expensifyPaymentsAccount', { walletProgram: - props.userWallet.walletProgramID === CONST.WALLET.MTL_WALLET_PROGRAM_ID ? CONST.WALLET.PROGRAM_ISSUERS.EXPENSIFY_PAYMENTS : CONST.WALLET.PROGRAM_ISSUERS.BANCORP_BANK, + props.userWallet?.walletProgramID === CONST.WALLET.MTL_WALLET_PROGRAM_ID ? CONST.WALLET.PROGRAM_ISSUERS.EXPENSIFY_PAYMENTS : CONST.WALLET.PROGRAM_ISSUERS.BANCORP_BANK, })} @@ -150,8 +147,6 @@ function ShortTermsForm(props) { ); } -ShortTermsForm.propTypes = propTypes; -ShortTermsForm.defaultProps = defaultProps; ShortTermsForm.displayName = 'ShortTermsForm'; export default ShortTermsForm; From 3f86b2eb3d06eef77cfc51c34a51b4945dddc1a3 Mon Sep 17 00:00:00 2001 From: Jayesh Mangwani Date: Tue, 30 Jan 2024 20:22:23 +0530 Subject: [PATCH 023/175] TS-migration: LongTermsForm Page --- .../TermsPage/{LongTermsForm.js => LongTermsForm.tsx} | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) rename src/pages/EnablePayments/TermsPage/{LongTermsForm.js => LongTermsForm.tsx} (98%) diff --git a/src/pages/EnablePayments/TermsPage/LongTermsForm.js b/src/pages/EnablePayments/TermsPage/LongTermsForm.tsx similarity index 98% rename from src/pages/EnablePayments/TermsPage/LongTermsForm.js rename to src/pages/EnablePayments/TermsPage/LongTermsForm.tsx index fad19c5ecf6f..ec89856642d9 100644 --- a/src/pages/EnablePayments/TermsPage/LongTermsForm.js +++ b/src/pages/EnablePayments/TermsPage/LongTermsForm.tsx @@ -66,7 +66,7 @@ function LongTermsForm() { ]; const getLongTermsSections = () => - _.map(termsData, (section, index) => ( + termsData.map((section, index) => ( // eslint-disable-next-line react/no-array-index-key @@ -105,7 +105,6 @@ function LongTermsForm() { Date: Tue, 30 Jan 2024 20:24:10 +0530 Subject: [PATCH 024/175] TS-migration: FailedKYC Page --- .../{FailedKYC.js => FailedKYC.tsx} | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) rename src/pages/EnablePayments/{FailedKYC.js => FailedKYC.tsx} (65%) diff --git a/src/pages/EnablePayments/FailedKYC.js b/src/pages/EnablePayments/FailedKYC.tsx similarity index 65% rename from src/pages/EnablePayments/FailedKYC.js rename to src/pages/EnablePayments/FailedKYC.tsx index fc54ea9c1074..25672772c216 100644 --- a/src/pages/EnablePayments/FailedKYC.js +++ b/src/pages/EnablePayments/FailedKYC.tsx @@ -2,35 +2,31 @@ import React from 'react'; import {View} from 'react-native'; import Text from '@components/Text'; import TextLink from '@components/TextLink'; -import withLocalize, {withLocalizePropTypes} from '@components/withLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import CONST from '@src/CONST'; +import useLocalize from '@hooks/useLocalize'; -const propTypes = { - ...withLocalizePropTypes, -}; - -function FailedKYC(props) { +function FailedKYC() { + const {translate} = useLocalize(); const styles = useThemeStyles(); return ( - {props.translate('additionalDetailsStep.failedKYCTextBefore')} + {translate('additionalDetailsStep.failedKYCTextBefore')} {CONST.EMAIL.CONCIERGE} - {props.translate('additionalDetailsStep.failedKYCTextAfter')} + {translate('additionalDetailsStep.failedKYCTextAfter')} ); } -FailedKYC.propTypes = propTypes; FailedKYC.displayName = 'FailedKYC'; -export default withLocalize(FailedKYC); +export default FailedKYC; From b4c5a8a9d66a629167114fd56c2bb68850a27d11 Mon Sep 17 00:00:00 2001 From: Jayesh Mangwani Date: Tue, 30 Jan 2024 20:38:51 +0530 Subject: [PATCH 025/175] TS-migration: ActivateStep Page --- src/pages/EnablePayments/ActivateStep.js | 72 ----------------------- src/pages/EnablePayments/ActivateStep.tsx | 62 +++++++++++++++++++ 2 files changed, 62 insertions(+), 72 deletions(-) delete mode 100644 src/pages/EnablePayments/ActivateStep.js create mode 100644 src/pages/EnablePayments/ActivateStep.tsx diff --git a/src/pages/EnablePayments/ActivateStep.js b/src/pages/EnablePayments/ActivateStep.js deleted file mode 100644 index 92342c28af73..000000000000 --- a/src/pages/EnablePayments/ActivateStep.js +++ /dev/null @@ -1,72 +0,0 @@ -import React from 'react'; -import {withOnyx} from 'react-native-onyx'; -import _ from 'underscore'; -import ConfirmationPage from '@components/ConfirmationPage'; -import HeaderWithBackButton from '@components/HeaderWithBackButton'; -import LottieAnimations from '@components/LottieAnimations'; -import withLocalize, {withLocalizePropTypes} from '@components/withLocalize'; -import compose from '@libs/compose'; -import * as PaymentMethods from '@userActions/PaymentMethods'; -import CONST from '@src/CONST'; -import ONYXKEYS from '@src/ONYXKEYS'; -import userWalletPropTypes from './userWalletPropTypes'; -import walletTermsPropTypes from './walletTermsPropTypes'; - -const propTypes = { - ...withLocalizePropTypes, - - /** The user's wallet */ - userWallet: userWalletPropTypes, - - /** Information about the user accepting the terms for payments */ - walletTerms: walletTermsPropTypes, -}; - -const defaultProps = { - userWallet: {}, - walletTerms: { - source: '', - chatReportID: 0, - }, -}; - -function ActivateStep(props) { - const isActivatedWallet = _.contains([CONST.WALLET.TIER_NAME.GOLD, CONST.WALLET.TIER_NAME.PLATINUM], props.userWallet.tierName); - const animation = isActivatedWallet ? LottieAnimations.Fireworks : LottieAnimations.ReviewingBankInfo; - let continueButtonText = ''; - - if (props.walletTerms.chatReportID) { - continueButtonText = props.translate('activateStep.continueToPayment'); - } else if (props.walletTerms.source === CONST.KYC_WALL_SOURCE.ENABLE_WALLET) { - continueButtonText = props.translate('common.continue'); - } else { - continueButtonText = props.translate('activateStep.continueToTransfer'); - } - - return ( - <> - - PaymentMethods.continueSetup()} - /> - - ); -} - -ActivateStep.propTypes = propTypes; -ActivateStep.defaultProps = defaultProps; -ActivateStep.displayName = 'ActivateStep'; - -export default compose( - withLocalize, - withOnyx({ - walletTerms: { - key: ONYXKEYS.WALLET_TERMS, - }, - }), -)(ActivateStep); diff --git a/src/pages/EnablePayments/ActivateStep.tsx b/src/pages/EnablePayments/ActivateStep.tsx new file mode 100644 index 000000000000..d16190f0c0af --- /dev/null +++ b/src/pages/EnablePayments/ActivateStep.tsx @@ -0,0 +1,62 @@ +import React from 'react'; +import {withOnyx} from 'react-native-onyx'; +import ConfirmationPage from '@components/ConfirmationPage'; +import HeaderWithBackButton from '@components/HeaderWithBackButton'; +import LottieAnimations from '@components/LottieAnimations'; +import * as PaymentMethods from '@userActions/PaymentMethods'; +import CONST from '@src/CONST'; +import ONYXKEYS from '@src/ONYXKEYS'; +import useLocalize from '@hooks/useLocalize'; +import type {OnyxEntry} from 'react-native-onyx'; +import {WalletTerms, UserWallet} from '@src/types/onyx'; + +type ActivateStepOnyxProps = { + /** Information about the user accepting the terms for payments */ + walletTerms: OnyxEntry; +}; + +type ActivateStepProps = ActivateStepOnyxProps & { + /** The user's wallet */ + userWallet: OnyxEntry; +}; + +function ActivateStep({ + userWallet, + walletTerms +}: ActivateStepProps) { + const {translate} = useLocalize(); + const isActivatedWallet = userWallet?.tierName && [CONST.WALLET.TIER_NAME.GOLD, CONST.WALLET.TIER_NAME.PLATINUM].some((name) => name === userWallet.tierName); + + const animation = isActivatedWallet ? LottieAnimations.Fireworks : LottieAnimations.ReviewingBankInfo; + let continueButtonText = ''; + + if (walletTerms?.chatReportID) { + continueButtonText = translate('activateStep.continueToPayment'); + } else if (walletTerms?.source === CONST.KYC_WALL_SOURCE.ENABLE_WALLET) { + continueButtonText = translate('common.continue'); + } else { + continueButtonText = translate('activateStep.continueToTransfer'); + } + + return ( + <> + + PaymentMethods.continueSetup()} + /> + + ); +} + +ActivateStep.displayName = 'ActivateStep'; + +export default withOnyx({ + walletTerms: { + key: ONYXKEYS.WALLET_TERMS, + }, +})(ActivateStep); \ No newline at end of file From e48ebb1d332c795947548c4027161b791b5869ff Mon Sep 17 00:00:00 2001 From: Toby Sullivan Date: Tue, 30 Jan 2024 09:46:28 -0800 Subject: [PATCH 026/175] Display report description for 1-to-1 money request --- src/libs/ReportUtils.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index edcd57078e0c..eeebe7e8b78a 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -2247,7 +2247,7 @@ function getReportPreviewMessage( return Localize.translateLocal('iou.waitingOnBankAccount', {submitterDisplayName}); } - const containsNonReimbursable = hasNonReimbursableTransactions(report.reportID); + const comment = !isEmptyObject(linkedTransaction) ? TransactionUtils.getDescription(linkedTransaction) : undefined; const lastActorID = reportAction?.actorAccountID; @@ -2259,14 +2259,14 @@ function getReportPreviewMessage( // We only want to show the actor name in the preview if it's not the current user who took the action const requestorName = lastActorID && lastActorID !== currentUserAccountID ? getDisplayNameForParticipant(lastActorID, !isPreviewMessageForParentChatReport) : ''; - return `${requestorName ? `${requestorName}: ` : ''}${Localize.translateLocal('iou.requestedAmount', {formattedAmount: amountToDisplay})}`; + return `${requestorName ? `${requestorName}: ` : ''}${Localize.translateLocal('iou.requestedAmount', {formattedAmount: amountToDisplay, comment})}`; } + const containsNonReimbursable = hasNonReimbursableTransactions(report.reportID); if (containsNonReimbursable) { return Localize.translateLocal('iou.payerSpentAmount', {payer: payerName ?? '', amount: formattedAmount}); } - const comment = !isEmptyObject(linkedTransaction) ? TransactionUtils.getDescription(linkedTransaction) : undefined; return Localize.translateLocal('iou.payerOwesAmount', {payer: payerName ?? '', amount: formattedAmount, comment}); } From 0ac0bedbd17cf7e86935e71828efd1175a7ac131 Mon Sep 17 00:00:00 2001 From: Jayesh Mangwani Date: Wed, 31 Jan 2024 01:59:28 +0530 Subject: [PATCH 027/175] TS-migration: OnfidoStep & OnfidoPrivacy Page --- src/pages/EnablePayments/ActivateStep.tsx | 13 ++-- src/pages/EnablePayments/FailedKYC.tsx | 2 +- .../{OnfidoPrivacy.js => OnfidoPrivacy.tsx} | 64 +++++++++---------- .../{OnfidoStep.js => OnfidoStep.tsx} | 35 +++++----- .../TermsPage/ShortTermsForm.tsx | 8 ++- src/pages/EnablePayments/TermsStep.tsx | 12 ++-- 6 files changed, 64 insertions(+), 70 deletions(-) rename src/pages/EnablePayments/{OnfidoPrivacy.js => OnfidoPrivacy.tsx} (74%) rename src/pages/EnablePayments/{OnfidoStep.js => OnfidoStep.tsx} (69%) diff --git a/src/pages/EnablePayments/ActivateStep.tsx b/src/pages/EnablePayments/ActivateStep.tsx index d16190f0c0af..0dbb98e53a5f 100644 --- a/src/pages/EnablePayments/ActivateStep.tsx +++ b/src/pages/EnablePayments/ActivateStep.tsx @@ -1,14 +1,14 @@ import React from 'react'; import {withOnyx} from 'react-native-onyx'; +import type {OnyxEntry} from 'react-native-onyx'; import ConfirmationPage from '@components/ConfirmationPage'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import LottieAnimations from '@components/LottieAnimations'; +import useLocalize from '@hooks/useLocalize'; import * as PaymentMethods from '@userActions/PaymentMethods'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; -import useLocalize from '@hooks/useLocalize'; -import type {OnyxEntry} from 'react-native-onyx'; -import {WalletTerms, UserWallet} from '@src/types/onyx'; +import {UserWallet, WalletTerms} from '@src/types/onyx'; type ActivateStepOnyxProps = { /** Information about the user accepting the terms for payments */ @@ -20,10 +20,7 @@ type ActivateStepProps = ActivateStepOnyxProps & { userWallet: OnyxEntry; }; -function ActivateStep({ - userWallet, - walletTerms -}: ActivateStepProps) { +function ActivateStep({userWallet, walletTerms}: ActivateStepProps) { const {translate} = useLocalize(); const isActivatedWallet = userWallet?.tierName && [CONST.WALLET.TIER_NAME.GOLD, CONST.WALLET.TIER_NAME.PLATINUM].some((name) => name === userWallet.tierName); @@ -59,4 +56,4 @@ export default withOnyx({ walletTerms: { key: ONYXKEYS.WALLET_TERMS, }, -})(ActivateStep); \ No newline at end of file +})(ActivateStep); diff --git a/src/pages/EnablePayments/FailedKYC.tsx b/src/pages/EnablePayments/FailedKYC.tsx index 25672772c216..6b393229d62f 100644 --- a/src/pages/EnablePayments/FailedKYC.tsx +++ b/src/pages/EnablePayments/FailedKYC.tsx @@ -2,9 +2,9 @@ import React from 'react'; import {View} from 'react-native'; import Text from '@components/Text'; import TextLink from '@components/TextLink'; +import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import CONST from '@src/CONST'; -import useLocalize from '@hooks/useLocalize'; function FailedKYC() { const {translate} = useLocalize(); diff --git a/src/pages/EnablePayments/OnfidoPrivacy.js b/src/pages/EnablePayments/OnfidoPrivacy.tsx similarity index 74% rename from src/pages/EnablePayments/OnfidoPrivacy.js rename to src/pages/EnablePayments/OnfidoPrivacy.tsx index 77b884fb2934..d8e9f616b8a7 100644 --- a/src/pages/EnablePayments/OnfidoPrivacy.js +++ b/src/pages/EnablePayments/OnfidoPrivacy.tsx @@ -1,7 +1,8 @@ import lodashGet from 'lodash/get'; import React, {useRef} from 'react'; -import {View} from 'react-native'; +import {ScrollView, View} from 'react-native'; import {withOnyx} from 'react-native-onyx'; +import type {OnyxEntry} from 'react-native-onyx'; import _ from 'underscore'; import FixedFooter from '@components/FixedFooter'; import FormAlertWithSubmitButton from '@components/FormAlertWithSubmitButton'; @@ -9,43 +10,41 @@ import FormScrollView from '@components/FormScrollView'; import FullscreenLoadingIndicator from '@components/FullscreenLoadingIndicator'; import Text from '@components/Text'; import TextLink from '@components/TextLink'; -import withLocalize, {withLocalizePropTypes} from '@components/withLocalize'; +import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; -import compose from '@libs/compose'; import * as ErrorUtils from '@libs/ErrorUtils'; import * as BankAccounts from '@userActions/BankAccounts'; import ONYXKEYS from '@src/ONYXKEYS'; -import walletOnfidoDataPropTypes from './walletOnfidoDataPropTypes'; +import {WalletOnfido} from '@src/types/onyx'; -const propTypes = { - /** Stores various information used to build the UI and call any APIs */ - walletOnfidoData: walletOnfidoDataPropTypes, - - ...withLocalizePropTypes, +const DEFAULT_WALLET_ONFIDO_DATA = { + applicantID: '', + sdkToken: '', + loading: false, + errors: {}, + fixableErrors: [], + hasAcceptedPrivacyPolicy: false, }; -const defaultProps = { - walletOnfidoData: { - applicantID: '', - sdkToken: '', - loading: false, - errors: {}, - fixableErrors: [], - hasAcceptedPrivacyPolicy: false, - }, +type OnfidoPrivacyOnyxProps = { + /** Stores various information used to build the UI and call any APIs */ + walletOnfidoData: OnyxEntry; }; -function OnfidoPrivacy({walletOnfidoData, translate, form}) { +type OnfidoPrivacyProps = OnfidoPrivacyOnyxProps & {}; + +function OnfidoPrivacy({walletOnfidoData = DEFAULT_WALLET_ONFIDO_DATA}: OnfidoPrivacyProps) { + const {translate} = useLocalize(); const styles = useThemeStyles(); - const {isLoading = false, hasAcceptedPrivacyPolicy} = walletOnfidoData; + const {isLoading = false, hasAcceptedPrivacyPolicy} = walletOnfidoData ?? {}; - const formRef = useRef(null); + const formRef = useRef(null); const openOnfidoFlow = () => { BankAccounts.openOnfidoFlow(); }; - let onfidoError = ErrorUtils.getLatestErrorMessage(walletOnfidoData) || ''; + let onfidoError = ErrorUtils.getLatestErrorMessage(walletOnfidoData ?? {}) || ''; const onfidoFixableErrors = lodashGet(walletOnfidoData, 'fixableErrors', []); onfidoError += !_.isEmpty(onfidoFixableErrors) ? `\n${onfidoFixableErrors.join('\n')}` : ''; @@ -70,7 +69,7 @@ function OnfidoPrivacy({walletOnfidoData, translate, form}) { isAlertVisible={Boolean(onfidoError)} onSubmit={openOnfidoFlow} onFixTheErrorsLinkPressed={() => { - form.scrollTo({y: 0, animated: true}); + formRef.current?.scrollTo({y: 0, animated: true}); }} message={onfidoError} isLoading={isLoading} @@ -85,18 +84,13 @@ function OnfidoPrivacy({walletOnfidoData, translate, form}) { ); } -OnfidoPrivacy.propTypes = propTypes; -OnfidoPrivacy.defaultProps = defaultProps; OnfidoPrivacy.displayName = 'OnfidoPrivacy'; -export default compose( - withLocalize, - withOnyx({ - walletOnfidoData: { - key: ONYXKEYS.WALLET_ONFIDO, +export default withOnyx({ + walletOnfidoData: { + key: ONYXKEYS.WALLET_ONFIDO, - // Let's get a new onfido token each time the user hits this flow (as it should only be once) - initWithStoredValues: false, - }, - }), -)(OnfidoPrivacy); + // Let's get a new onfido token each time the user hits this flow (as it should only be once) + initWithStoredValues: false, + }, +})(OnfidoPrivacy); diff --git a/src/pages/EnablePayments/OnfidoStep.js b/src/pages/EnablePayments/OnfidoStep.tsx similarity index 69% rename from src/pages/EnablePayments/OnfidoStep.js rename to src/pages/EnablePayments/OnfidoStep.tsx index 8b40c88f62fb..5e36f2f302a6 100644 --- a/src/pages/EnablePayments/OnfidoStep.js +++ b/src/pages/EnablePayments/OnfidoStep.tsx @@ -1,7 +1,9 @@ import React, {useCallback} from 'react'; import {withOnyx} from 'react-native-onyx'; +import type {OnyxEntry} from 'react-native-onyx'; import FullPageOfflineBlockingView from '@components/BlockingViews/FullPageOfflineBlockingView'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; +// @ts-expect-error TODO: Remove this once Onfido (https://github.com/Expensify/App/issues/25136) is migrated to TypeScript. import Onfido from '@components/Onfido'; import useLocalize from '@hooks/useLocalize'; import Growl from '@libs/Growl'; @@ -11,25 +13,25 @@ import * as Wallet from '@userActions/Wallet'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; +import {WalletOnfido} from '@src/types/onyx'; import OnfidoPrivacy from './OnfidoPrivacy'; -import walletOnfidoDataPropTypes from './walletOnfidoDataPropTypes'; -const propTypes = { - /** Stores various information used to build the UI and call any APIs */ - walletOnfidoData: walletOnfidoDataPropTypes, +const DEFAULT_WALLET_ONFIDO_DATA = { + loading: false, + hasAcceptedPrivacyPolicy: false, }; -const defaultProps = { - walletOnfidoData: { - loading: false, - hasAcceptedPrivacyPolicy: false, - }, +type OnfidoStepOnyxProps = { + /** Stores various information used to build the UI and call any APIs */ + walletOnfidoData: OnyxEntry; }; -function OnfidoStep({walletOnfidoData}) { +type OnfidoStepProps = OnfidoStepOnyxProps; + +function OnfidoStep({walletOnfidoData = DEFAULT_WALLET_ONFIDO_DATA}: OnfidoStepProps) { const {translate} = useLocalize(); - const shouldShowOnfido = walletOnfidoData.hasAcceptedPrivacyPolicy && !walletOnfidoData.isLoading && !walletOnfidoData.error && walletOnfidoData.sdkToken; + const shouldShowOnfido = walletOnfidoData?.hasAcceptedPrivacyPolicy && !walletOnfidoData.isLoading && !walletOnfidoData.errors && walletOnfidoData.sdkToken; const goBack = useCallback(() => { Navigation.goBack(ROUTES.HOME); @@ -44,15 +46,16 @@ function OnfidoStep({walletOnfidoData}) { }, [translate]); const verifyIdentity = useCallback( + // @ts-expect-error TODO: Remove this once Onfido (https://github.com/Expensify/App/issues/25136) is migrated to TypeScript. (data) => { BankAccounts.verifyIdentity({ onfidoData: JSON.stringify({ ...data, - applicantID: walletOnfidoData.applicantID, + applicantID: walletOnfidoData?.applicantID, }), }); }, - [walletOnfidoData.applicantID], + [walletOnfidoData?.applicantID], ); return ( @@ -70,18 +73,16 @@ function OnfidoStep({walletOnfidoData}) { onSuccess={verifyIdentity} /> ) : ( - + )} ); } -OnfidoStep.propTypes = propTypes; -OnfidoStep.defaultProps = defaultProps; OnfidoStep.displayName = 'OnfidoStep'; -export default withOnyx({ +export default withOnyx({ walletOnfidoData: { key: ONYXKEYS.WALLET_ONFIDO, diff --git a/src/pages/EnablePayments/TermsPage/ShortTermsForm.tsx b/src/pages/EnablePayments/TermsPage/ShortTermsForm.tsx index 1c9d37bb30e9..b45b8b657a75 100644 --- a/src/pages/EnablePayments/TermsPage/ShortTermsForm.tsx +++ b/src/pages/EnablePayments/TermsPage/ShortTermsForm.tsx @@ -1,16 +1,16 @@ import React from 'react'; import {View} from 'react-native'; +import type {OnyxEntry} from 'react-native-onyx'; import Text from '@components/Text'; import TextLink from '@components/TextLink'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import * as CurrencyUtils from '@libs/CurrencyUtils'; import CONST from '@src/CONST'; -import type {OnyxEntry} from 'react-native-onyx'; import {UserWallet} from '@src/types/onyx'; type ShortTermsFormProps = { - /** The user's wallet */ + /** The user's wallet */ userWallet: OnyxEntry; }; @@ -22,7 +22,9 @@ function ShortTermsForm(props: ShortTermsFormProps) { {translate('termsStep.shortTermsForm.expensifyPaymentsAccount', { walletProgram: - props.userWallet?.walletProgramID === CONST.WALLET.MTL_WALLET_PROGRAM_ID ? CONST.WALLET.PROGRAM_ISSUERS.EXPENSIFY_PAYMENTS : CONST.WALLET.PROGRAM_ISSUERS.BANCORP_BANK, + props.userWallet?.walletProgramID === CONST.WALLET.MTL_WALLET_PROGRAM_ID + ? CONST.WALLET.PROGRAM_ISSUERS.EXPENSIFY_PAYMENTS + : CONST.WALLET.PROGRAM_ISSUERS.BANCORP_BANK, })} diff --git a/src/pages/EnablePayments/TermsStep.tsx b/src/pages/EnablePayments/TermsStep.tsx index a03f3607d56e..cef54ba463e6 100644 --- a/src/pages/EnablePayments/TermsStep.tsx +++ b/src/pages/EnablePayments/TermsStep.tsx @@ -1,25 +1,25 @@ import React, {useEffect, useState} from 'react'; import {ScrollView} from 'react-native'; import {withOnyx} from 'react-native-onyx'; +import type {OnyxEntry} from 'react-native-onyx'; import CheckboxWithLabel from '@components/CheckboxWithLabel'; import FormAlertWithSubmitButton from '@components/FormAlertWithSubmitButton'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import Text from '@components/Text'; import TextLink from '@components/TextLink'; +import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import * as ErrorUtils from '@libs/ErrorUtils'; import * as BankAccounts from '@userActions/BankAccounts'; import ONYXKEYS from '@src/ONYXKEYS'; +import {UserWallet, WalletTerms} from '@src/types/onyx'; import LongTermsForm from './TermsPage/LongTermsForm'; import ShortTermsForm from './TermsPage/ShortTermsForm'; -import useLocalize from '@hooks/useLocalize'; -import type {OnyxEntry} from 'react-native-onyx'; -import {WalletTerms, UserWallet} from '@src/types/onyx'; type TermsStepOnyxProps = { /** Comes from Onyx. Information about the terms for the wallet */ walletTerms: OnyxEntry; -} +}; type TermsStepProps = TermsStepOnyxProps & { /** The user's wallet */ @@ -33,7 +33,7 @@ function TermsStep(props: TermsStepProps) { const [error, setError] = useState(false); const {translate} = useLocalize(); - const errorMessage = error ? 'common.error.acceptTerms' : ErrorUtils.getLatestErrorMessage(props.walletTerms??{}) || ''; + const errorMessage = error ? 'common.error.acceptTerms' : ErrorUtils.getLatestErrorMessage(props.walletTerms ?? {}) || ''; const toggleDisclosure = () => { setHasAcceptedDisclosure(!hasAcceptedDisclosure); @@ -99,7 +99,7 @@ function TermsStep(props: TermsStepProps) { setError(false); BankAccounts.acceptWalletTerms({ hasAcceptedTerms: hasAcceptedDisclosure && hasAcceptedPrivacyPolicyAndWalletAgreement, - reportID: props.walletTerms?.chatReportID??'', + reportID: props.walletTerms?.chatReportID ?? '', }); }} message={errorMessage} From 0feb8c4e71dad1c3cd3d11f7a2c7670387bd09c7 Mon Sep 17 00:00:00 2001 From: Jayesh Mangwani Date: Wed, 31 Jan 2024 04:23:28 +0530 Subject: [PATCH 028/175] TS-migration: EnablePaymentsPage Page --- ...PaymentsPage.js => EnablePaymentsPage.tsx} | 29 +++++++++---------- 1 file changed, 13 insertions(+), 16 deletions(-) rename src/pages/EnablePayments/{EnablePaymentsPage.js => EnablePaymentsPage.tsx} (78%) diff --git a/src/pages/EnablePayments/EnablePaymentsPage.js b/src/pages/EnablePayments/EnablePaymentsPage.tsx similarity index 78% rename from src/pages/EnablePayments/EnablePaymentsPage.js rename to src/pages/EnablePayments/EnablePaymentsPage.tsx index 257eab1d38d3..6d2defc82df0 100644 --- a/src/pages/EnablePayments/EnablePaymentsPage.js +++ b/src/pages/EnablePayments/EnablePaymentsPage.tsx @@ -1,6 +1,6 @@ import React, {useEffect} from 'react'; import {withOnyx} from 'react-native-onyx'; -import _ from 'underscore'; +import type {OnyxEntry} from 'react-native-onyx'; import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import ScreenWrapper from '@components/ScreenWrapper'; @@ -11,28 +11,27 @@ import * as Wallet from '@userActions/Wallet'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; +import type {UserWallet} from '@src/types/onyx'; +import {isEmptyObject} from '@src/types/utils/EmptyObject'; import ActivateStep from './ActivateStep'; import AdditionalDetailsStep from './AdditionalDetailsStep'; import FailedKYC from './FailedKYC'; // Steps import OnfidoStep from './OnfidoStep'; import TermsStep from './TermsStep'; -import userWalletPropTypes from './userWalletPropTypes'; -const propTypes = { +type EnablePaymentsPageOnyxProps = { /** The user's wallet */ - userWallet: userWalletPropTypes, + userWallet: OnyxEntry; }; -const defaultProps = { - userWallet: {}, -}; +type EnablePaymentsPageProps = EnablePaymentsPageOnyxProps & {}; -function EnablePaymentsPage({userWallet}) { +function EnablePaymentsPage({userWallet}: EnablePaymentsPageProps) { const {translate} = useLocalize(); const {isOffline} = useNetwork(); - const {isPendingOnfidoResult, hasFailedOnfido} = userWallet; + const {isPendingOnfidoResult, hasFailedOnfido} = userWallet ?? {}; useEffect(() => { if (isOffline) { @@ -47,18 +46,18 @@ function EnablePaymentsPage({userWallet}) { Wallet.openEnablePaymentsPage(); }, [isOffline, isPendingOnfidoResult, hasFailedOnfido]); - if (_.isEmpty(userWallet)) { + if (isEmptyObject(userWallet)) { return ; } return ( {() => { - if (userWallet.errorCode === CONST.WALLET.ERROR.KYC) { + if (userWallet?.errorCode === CONST.WALLET.ERROR.KYC) { return ( <> ({ userWallet: { key: ONYXKEYS.USER_WALLET, From 9bd67d67aee253e4614ef64854169229282f806d Mon Sep 17 00:00:00 2001 From: Jayesh Mangwani Date: Mon, 5 Feb 2024 16:14:46 +0530 Subject: [PATCH 029/175] merge main, fix lint --- src/pages/EnablePayments/ActivateStep.tsx | 2 +- .../EnablePayments/EnablePaymentsPage.tsx | 3 ++- src/pages/EnablePayments/OnfidoPrivacy.tsx | 23 +++++++++++-------- src/pages/EnablePayments/OnfidoStep.tsx | 2 +- .../TermsPage/LongTermsForm.tsx | 1 - .../TermsPage/ShortTermsForm.tsx | 2 +- src/pages/EnablePayments/TermsStep.tsx | 2 +- 7 files changed, 19 insertions(+), 16 deletions(-) diff --git a/src/pages/EnablePayments/ActivateStep.tsx b/src/pages/EnablePayments/ActivateStep.tsx index 0dbb98e53a5f..e0bea7488140 100644 --- a/src/pages/EnablePayments/ActivateStep.tsx +++ b/src/pages/EnablePayments/ActivateStep.tsx @@ -8,7 +8,7 @@ import useLocalize from '@hooks/useLocalize'; import * as PaymentMethods from '@userActions/PaymentMethods'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; -import {UserWallet, WalletTerms} from '@src/types/onyx'; +import type {UserWallet, WalletTerms} from '@src/types/onyx'; type ActivateStepOnyxProps = { /** Information about the user accepting the terms for payments */ diff --git a/src/pages/EnablePayments/EnablePaymentsPage.tsx b/src/pages/EnablePayments/EnablePaymentsPage.tsx index 6d2defc82df0..1384875fe031 100644 --- a/src/pages/EnablePayments/EnablePaymentsPage.tsx +++ b/src/pages/EnablePayments/EnablePaymentsPage.tsx @@ -25,7 +25,7 @@ type EnablePaymentsPageOnyxProps = { userWallet: OnyxEntry; }; -type EnablePaymentsPageProps = EnablePaymentsPageOnyxProps & {}; +type EnablePaymentsPageProps = EnablePaymentsPageOnyxProps; function EnablePaymentsPage({userWallet}: EnablePaymentsPageProps) { const {translate} = useLocalize(); @@ -38,6 +38,7 @@ function EnablePaymentsPage({userWallet}: EnablePaymentsPageProps) { return; } + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing if (isPendingOnfidoResult || hasFailedOnfido) { Navigation.navigate(ROUTES.SETTINGS_WALLET, CONST.NAVIGATION.TYPE.UP); return; diff --git a/src/pages/EnablePayments/OnfidoPrivacy.tsx b/src/pages/EnablePayments/OnfidoPrivacy.tsx index d8e9f616b8a7..80fa08c009ca 100644 --- a/src/pages/EnablePayments/OnfidoPrivacy.tsx +++ b/src/pages/EnablePayments/OnfidoPrivacy.tsx @@ -1,9 +1,8 @@ -import lodashGet from 'lodash/get'; import React, {useRef} from 'react'; -import {ScrollView, View} from 'react-native'; +import {View} from 'react-native'; +import type {ScrollView} from 'react-native'; import {withOnyx} from 'react-native-onyx'; import type {OnyxEntry} from 'react-native-onyx'; -import _ from 'underscore'; import FixedFooter from '@components/FixedFooter'; import FormAlertWithSubmitButton from '@components/FormAlertWithSubmitButton'; import FormScrollView from '@components/FormScrollView'; @@ -15,7 +14,8 @@ import useThemeStyles from '@hooks/useThemeStyles'; import * as ErrorUtils from '@libs/ErrorUtils'; import * as BankAccounts from '@userActions/BankAccounts'; import ONYXKEYS from '@src/ONYXKEYS'; -import {WalletOnfido} from '@src/types/onyx'; +import type {WalletOnfido} from '@src/types/onyx'; +import {isEmptyObject} from '@src/types/utils/EmptyObject'; const DEFAULT_WALLET_ONFIDO_DATA = { applicantID: '', @@ -31,22 +31,25 @@ type OnfidoPrivacyOnyxProps = { walletOnfidoData: OnyxEntry; }; -type OnfidoPrivacyProps = OnfidoPrivacyOnyxProps & {}; +type OnfidoPrivacyProps = OnfidoPrivacyOnyxProps; function OnfidoPrivacy({walletOnfidoData = DEFAULT_WALLET_ONFIDO_DATA}: OnfidoPrivacyProps) { const {translate} = useLocalize(); - const styles = useThemeStyles(); - const {isLoading = false, hasAcceptedPrivacyPolicy} = walletOnfidoData ?? {}; - const formRef = useRef(null); + const styles = useThemeStyles(); + if (!walletOnfidoData) { + return; + } + const {isLoading = false, hasAcceptedPrivacyPolicy} = walletOnfidoData; const openOnfidoFlow = () => { BankAccounts.openOnfidoFlow(); }; let onfidoError = ErrorUtils.getLatestErrorMessage(walletOnfidoData ?? {}) || ''; - const onfidoFixableErrors = lodashGet(walletOnfidoData, 'fixableErrors', []); - onfidoError += !_.isEmpty(onfidoFixableErrors) ? `\n${onfidoFixableErrors.join('\n')}` : ''; + + const onfidoFixableErrors = walletOnfidoData?.fixableErrors ?? []; + onfidoError += !isEmptyObject(onfidoFixableErrors) ? `\n${onfidoFixableErrors.join('\n')}` : ''; return ( diff --git a/src/pages/EnablePayments/OnfidoStep.tsx b/src/pages/EnablePayments/OnfidoStep.tsx index 5e36f2f302a6..04cadb24fecf 100644 --- a/src/pages/EnablePayments/OnfidoStep.tsx +++ b/src/pages/EnablePayments/OnfidoStep.tsx @@ -13,7 +13,7 @@ import * as Wallet from '@userActions/Wallet'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; -import {WalletOnfido} from '@src/types/onyx'; +import type {WalletOnfido} from '@src/types/onyx'; import OnfidoPrivacy from './OnfidoPrivacy'; const DEFAULT_WALLET_ONFIDO_DATA = { diff --git a/src/pages/EnablePayments/TermsPage/LongTermsForm.tsx b/src/pages/EnablePayments/TermsPage/LongTermsForm.tsx index ec89856642d9..81d18c5dfc44 100644 --- a/src/pages/EnablePayments/TermsPage/LongTermsForm.tsx +++ b/src/pages/EnablePayments/TermsPage/LongTermsForm.tsx @@ -1,6 +1,5 @@ import React from 'react'; import {View} from 'react-native'; -import _ from 'underscore'; import CollapsibleSection from '@components/CollapsibleSection'; import Icon from '@components/Icon'; import * as Expensicons from '@components/Icon/Expensicons'; diff --git a/src/pages/EnablePayments/TermsPage/ShortTermsForm.tsx b/src/pages/EnablePayments/TermsPage/ShortTermsForm.tsx index b45b8b657a75..f4db904c07f3 100644 --- a/src/pages/EnablePayments/TermsPage/ShortTermsForm.tsx +++ b/src/pages/EnablePayments/TermsPage/ShortTermsForm.tsx @@ -7,7 +7,7 @@ import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import * as CurrencyUtils from '@libs/CurrencyUtils'; import CONST from '@src/CONST'; -import {UserWallet} from '@src/types/onyx'; +import type {UserWallet} from '@src/types/onyx'; type ShortTermsFormProps = { /** The user's wallet */ diff --git a/src/pages/EnablePayments/TermsStep.tsx b/src/pages/EnablePayments/TermsStep.tsx index cef54ba463e6..fe463f88792d 100644 --- a/src/pages/EnablePayments/TermsStep.tsx +++ b/src/pages/EnablePayments/TermsStep.tsx @@ -12,7 +12,7 @@ import useThemeStyles from '@hooks/useThemeStyles'; import * as ErrorUtils from '@libs/ErrorUtils'; import * as BankAccounts from '@userActions/BankAccounts'; import ONYXKEYS from '@src/ONYXKEYS'; -import {UserWallet, WalletTerms} from '@src/types/onyx'; +import type {UserWallet, WalletTerms} from '@src/types/onyx'; import LongTermsForm from './TermsPage/LongTermsForm'; import ShortTermsForm from './TermsPage/ShortTermsForm'; From c0f4f030db1ff9e61da920b9c4393a82cf42a59b Mon Sep 17 00:00:00 2001 From: Jayesh Mangwani Date: Mon, 5 Feb 2024 19:22:28 +0530 Subject: [PATCH 030/175] TS-migration: IdologyQuestions Page --- src/ONYXKEYS.ts | 4 + ...ologyQuestions.js => IdologyQuestions.tsx} | 81 +++++++------------ src/types/onyx/Form.ts | 5 ++ src/types/onyx/index.ts | 2 + 4 files changed, 39 insertions(+), 53 deletions(-) rename src/pages/EnablePayments/{IdologyQuestions.js => IdologyQuestions.tsx} (69%) diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index 7328fb2543ad..3046b5a16bdd 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -367,6 +367,8 @@ const ONYXKEYS = { REIMBURSEMENT_ACCOUNT_FORM_DRAFT: 'reimbursementAccountDraft', PERSONAL_BANK_ACCOUNT: 'personalBankAccountForm', PERSONAL_BANK_ACCOUNT_DRAFT: 'personalBankAccountFormDraft', + IDOLOGY_QUESTIONS_FORM: 'idologyQuestions', + IDOLOGY_QUESTIONS_FORM_DRAFT: 'idologyQuestionsDraft', }, } as const; @@ -556,6 +558,8 @@ type OnyxValues = { [ONYXKEYS.FORMS.REIMBURSEMENT_ACCOUNT_FORM_DRAFT]: OnyxTypes.Form; [ONYXKEYS.FORMS.PERSONAL_BANK_ACCOUNT]: OnyxTypes.PersonalBankAccount; [ONYXKEYS.FORMS.PERSONAL_BANK_ACCOUNT_DRAFT]: OnyxTypes.PersonalBankAccount; + [ONYXKEYS.FORMS.IDOLOGY_QUESTIONS_FORM]: OnyxTypes.IdologyQuestionsForm; + [ONYXKEYS.FORMS.IDOLOGY_QUESTIONS_FORM_DRAFT]: OnyxTypes.IdologyQuestionsForm; }; type OnyxKeyValue = OnyxEntry; diff --git a/src/pages/EnablePayments/IdologyQuestions.js b/src/pages/EnablePayments/IdologyQuestions.tsx similarity index 69% rename from src/pages/EnablePayments/IdologyQuestions.js rename to src/pages/EnablePayments/IdologyQuestions.tsx index a0c202b0bbbc..4a5ef72019c0 100644 --- a/src/pages/EnablePayments/IdologyQuestions.js +++ b/src/pages/EnablePayments/IdologyQuestions.tsx @@ -1,10 +1,10 @@ -import PropTypes from 'prop-types'; import React, {useState} from 'react'; import {View} from 'react-native'; -import {withOnyx} from 'react-native-onyx'; -import _ from 'underscore'; +import type {WalletAdditionalQuestionDetails} from 'src/types/onyx'; import FormProvider from '@components/Form/FormProvider'; import InputWrapper from '@components/Form/InputWrapper'; +import type {OnyxFormValuesFields} from '@components/Form/types'; +import type {Choice} from '@components/RadioButtons'; import SingleChoiceQuestion from '@components/SingleChoiceQuestion'; import Text from '@components/Text'; import TextLink from '@components/TextLink'; @@ -12,53 +12,36 @@ import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import * as BankAccounts from '@userActions/BankAccounts'; import ONYXKEYS from '@src/ONYXKEYS'; +import type {Errors} from '@src/types/onyx/OnyxCommon'; const MAX_SKIP = 1; const SKIP_QUESTION_TEXT = 'Skip Question'; -const propTypes = { +type IdologyQuestionsProps = { /** Questions returned by Idology */ /** example: [{"answer":["1251","6253","113","None of the above","Skip Question"],"prompt":"Which number goes with your address on MASONIC AVE?","type":"street.number.b"}, ...] */ - questions: PropTypes.arrayOf( - PropTypes.shape({ - prompt: PropTypes.string, - type: PropTypes.string, - answer: PropTypes.arrayOf(PropTypes.string), - }), - ), + questions: WalletAdditionalQuestionDetails[]; /** ID from Idology, referencing those questions */ - idNumber: PropTypes.string, - - walletAdditionalDetails: PropTypes.shape({ - /** Are we waiting for a response? */ - isLoading: PropTypes.bool, - - /** Any additional error message to show */ - errors: PropTypes.objectOf(PropTypes.string), - - /** What error do we need to handle */ - errorCode: PropTypes.string, - }), + idNumber: string; }; -const defaultProps = { - questions: [], - idNumber: '', - walletAdditionalDetails: {}, +type Answer = { + question: string; + answer: string; }; -function IdologyQuestions({questions, idNumber}) { +function IdologyQuestions({questions, idNumber}: IdologyQuestionsProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); const [currentQuestionIndex, setCurrentQuestionIndex] = useState(0); const [shouldHideSkipAnswer, setShouldHideSkipAnswer] = useState(false); - const [userAnswers, setUserAnswers] = useState([]); + const [userAnswers, setUserAnswers] = useState([]); const currentQuestion = questions[currentQuestionIndex] || {}; - const possibleAnswers = _.filter( - _.map(currentQuestion.answer, (answer) => { + const possibleAnswers: Choice[] = currentQuestion.answer + .map((answer) => { if (shouldHideSkipAnswer && answer === SKIP_QUESTION_TEXT) { return; } @@ -67,15 +50,11 @@ function IdologyQuestions({questions, idNumber}) { label: answer, value: answer, }; - }), - ); + }) + .filter((answer): answer is Choice => answer !== undefined); - /** - * Put question answer in the state. - * @param {String} answer - */ - const chooseAnswer = (answer) => { - const tempAnswers = _.map(userAnswers, _.clone); + const chooseAnswer = (answer: string) => { + const tempAnswers: Answer[] = userAnswers.map((userAnswer) => ({...userAnswer})); tempAnswers[currentQuestionIndex] = {question: currentQuestion.type, answer}; @@ -90,11 +69,11 @@ function IdologyQuestions({questions, idNumber}) { return; } // Get the number of questions that were skipped by the user. - const skippedQuestionsCount = _.filter(userAnswers, (answer) => answer.answer === SKIP_QUESTION_TEXT).length; + const skippedQuestionsCount = userAnswers.filter((answer) => answer.answer === SKIP_QUESTION_TEXT).length; // We have enough answers, let's call expectID KBA to verify them if (userAnswers.length - skippedQuestionsCount >= questions.length - MAX_SKIP) { - const tempAnswers = _.map(userAnswers, _.clone); + const tempAnswers: Answer[] = userAnswers.map((answer) => ({...answer})); // Auto skip any remaining questions if (tempAnswers.length < questions.length) { @@ -112,8 +91,8 @@ function IdologyQuestions({questions, idNumber}) { } }; - const validate = (values) => { - const errors = {}; + const validate = (values: OnyxFormValuesFields) => { + const errors: Errors = {}; if (!values.answer) { errors.answer = translate('additionalDetailsStep.selectAnswer'); } @@ -132,7 +111,7 @@ function IdologyQuestions({questions, idNumber}) { @@ -155,11 +136,5 @@ function IdologyQuestions({questions, idNumber}) { } IdologyQuestions.displayName = 'IdologyQuestions'; -IdologyQuestions.propTypes = propTypes; -IdologyQuestions.defaultProps = defaultProps; - -export default withOnyx({ - walletAdditionalDetails: { - key: ONYXKEYS.WALLET_ADDITIONAL_DETAILS, - }, -})(IdologyQuestions); + +export default IdologyQuestions; diff --git a/src/types/onyx/Form.ts b/src/types/onyx/Form.ts index 48f386afcbb0..79190aa3e6f6 100644 --- a/src/types/onyx/Form.ts +++ b/src/types/onyx/Form.ts @@ -68,6 +68,10 @@ type CloseAccountForm = Form<{ phoneOrEmail: string; }>; +type IdologyQuestionsForm = Form<{ + answer: string; +}>; + export default Form; export type { @@ -84,4 +88,5 @@ export type { WorkspaceSettingsForm, ReportFieldEditForm, CloseAccountForm, + IdologyQuestionsForm, }; diff --git a/src/types/onyx/index.ts b/src/types/onyx/index.ts index d0ac2ce395fa..13c305abe384 100644 --- a/src/types/onyx/index.ts +++ b/src/types/onyx/index.ts @@ -14,6 +14,7 @@ import type { CloseAccountForm, DateOfBirthForm, DisplayNameForm, + IdologyQuestionsForm, IKnowATeacherForm, IntroSchoolPrincipalForm, NewRoomForm, @@ -165,4 +166,5 @@ export type { IntroSchoolPrincipalForm, PrivateNotesForm, ReportFieldEditForm, + IdologyQuestionsForm, }; From 61d24b89c0132dd7ce1049a62b0e88e9814b3c5f Mon Sep 17 00:00:00 2001 From: Jayesh Mangwani Date: Mon, 5 Feb 2024 21:29:42 +0530 Subject: [PATCH 031/175] TS-migration: AdditionalDetailsStep Page --- src/ONYXKEYS.ts | 4 + .../withCurrentUserPersonalDetails.tsx | 2 +- src/libs/actions/PersonalDetails.ts | 3 +- ...tailsStep.js => AdditionalDetailsStep.tsx} | 120 ++++++------------ src/types/onyx/Form.ts | 13 ++ src/types/onyx/index.ts | 2 + 6 files changed, 64 insertions(+), 80 deletions(-) rename src/pages/EnablePayments/{AdditionalDetailsStep.js => AdditionalDetailsStep.tsx} (73%) diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index 3046b5a16bdd..2e4e5b564616 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -369,6 +369,8 @@ const ONYXKEYS = { PERSONAL_BANK_ACCOUNT_DRAFT: 'personalBankAccountFormDraft', IDOLOGY_QUESTIONS_FORM: 'idologyQuestions', IDOLOGY_QUESTIONS_FORM_DRAFT: 'idologyQuestionsDraft', + ADDITIONAL_DETAILS_FORM: 'additionalDetailStep', + ADDITIONAL_DETAILS_FORM_DRAFT: 'additionalDetailStepDraft', }, } as const; @@ -560,6 +562,8 @@ type OnyxValues = { [ONYXKEYS.FORMS.PERSONAL_BANK_ACCOUNT_DRAFT]: OnyxTypes.PersonalBankAccount; [ONYXKEYS.FORMS.IDOLOGY_QUESTIONS_FORM]: OnyxTypes.IdologyQuestionsForm; [ONYXKEYS.FORMS.IDOLOGY_QUESTIONS_FORM_DRAFT]: OnyxTypes.IdologyQuestionsForm; + [ONYXKEYS.FORMS.ADDITIONAL_DETAILS_FORM]: OnyxTypes.AdditionalDetailStepForm; + [ONYXKEYS.FORMS.ADDITIONAL_DETAILS_FORM_DRAFT]: OnyxTypes.AdditionalDetailStepForm; }; type OnyxKeyValue = OnyxEntry; diff --git a/src/components/withCurrentUserPersonalDetails.tsx b/src/components/withCurrentUserPersonalDetails.tsx index 9406c8634c1b..75bdb03ea6d8 100644 --- a/src/components/withCurrentUserPersonalDetails.tsx +++ b/src/components/withCurrentUserPersonalDetails.tsx @@ -64,4 +64,4 @@ export default function ; }; -const defaultProps = { - walletAdditionalDetails: { - errorFields: {}, - isLoading: false, - errors: {}, - questions: [], - idNumber: '', - errorCode: '', - }, - ...withCurrentUserPersonalDetailsDefaultProps, -}; +type AdditionalDetailsStepProps = AdditionalDetailsStepOnyxProps & WithCurrentUserPersonalDetailsProps; const fieldNameTranslationKeys = { legalFirstName: 'additionalDetailsStep.legalFirstNameLabel', @@ -77,20 +50,17 @@ const fieldNameTranslationKeys = { dob: 'common.dob', ssn: 'common.ssnLast4', ssnFull9: 'common.ssnFull9', -}; +} as const; -function AdditionalDetailsStep({walletAdditionalDetails, translate, currentUserPersonalDetails}) { +function AdditionalDetailsStep({walletAdditionalDetails = DEFAULT_WALLET_ADDITIONAL_DETAILS, currentUserPersonalDetails}: AdditionalDetailsStepProps) { + const {translate} = useLocalize(); const styles = useThemeStyles(); const currentDate = new Date(); const minDate = subYears(currentDate, CONST.DATE_BIRTH.MAX_AGE); const maxDate = subYears(currentDate, CONST.DATE_BIRTH.MIN_AGE_FOR_PAYMENT); - const shouldAskForFullSSN = walletAdditionalDetails.errorCode === CONST.WALLET.ERROR.SSN; + const shouldAskForFullSSN = walletAdditionalDetails?.errorCode === CONST.WALLET.ERROR.SSN; - /** - * @param {Object} values The values object is passed from FormProvider and contains info for each form element that has an inputID - * @returns {Object} - */ - const validate = (values) => { + const validate = (values: OnyxFormValuesFields) => { const requiredFields = ['legalFirstName', 'legalLastName', 'addressStreet', 'addressCity', 'addressZipCode', 'phoneNumber', 'dob', 'ssn', 'addressState']; const errors = ValidationUtils.getFieldRequiredErrors(values, requiredFields); @@ -116,7 +86,7 @@ function AdditionalDetailsStep({walletAdditionalDetails, translate, currentUserP // walletAdditionalDetails stores errors returned by the server. If the server returns an SSN error // then the user needs to provide the full 9 digit SSN. - if (walletAdditionalDetails.errorCode === CONST.WALLET.ERROR.SSN) { + if (walletAdditionalDetails?.errorCode === CONST.WALLET.ERROR.SSN) { if (values.ssn && !ValidationUtils.isValidSSNFullNine(values.ssn)) { errors.ssn = 'additionalDetailsStep.ssnFull9Error'; } @@ -127,26 +97,23 @@ function AdditionalDetailsStep({walletAdditionalDetails, translate, currentUserP return errors; }; - /** - * @param {Object} values The values object is passed from FormProvider and contains info for each form element that has an inputID - */ - const activateWallet = (values) => { + const activateWallet = (values: OnyxFormValuesFields) => { const personalDetails = { - phoneNumber: parsePhoneNumber(values.phoneNumber, {regionCode: CONST.COUNTRY.US}).number.significant || '', - legalFirstName: values.legalFirstName || '', - legalLastName: values.legalLastName || '', - addressStreet: values.addressStreet || '', - addressCity: values.addressCity || '', - addressState: values.addressState || '', - addressZip: values.addressZipCode || '', - dob: values.dob || '', - ssn: values.ssn || '', + phoneNumber: (values.phoneNumber && parsePhoneNumber(values.phoneNumber, {regionCode: CONST.COUNTRY.US}).number?.significant) ?? '', + legalFirstName: values.legalFirstName ?? '', + legalLastName: values.legalLastName ?? '', + addressStreet: values.addressStreet ?? '', + addressCity: values.addressCity ?? '', + addressState: values.addressState ?? '', + addressZip: values.addressZipCode ?? '', + dob: values.dob ?? '', + ssn: values.ssn ?? '', }; // Attempt to set the personal details Wallet.updatePersonalDetails(personalDetails); }; - if (!_.isEmpty(walletAdditionalDetails.questions)) { + if (walletAdditionalDetails?.questions && walletAdditionalDetails.questions.length > 0) { return ( Wallet.setAdditionalDetailsQuestions(null)} + onBackButtonPress={() => Wallet.setAdditionalDetailsQuestions([], walletAdditionalDetails?.idNumber ?? '')} /> ); @@ -180,7 +147,7 @@ function AdditionalDetailsStep({walletAdditionalDetails, translate, currentUserP ({ walletAdditionalDetails: { key: ONYXKEYS.WALLET_ADDITIONAL_DETAILS, }, - }), -)(AdditionalDetailsStep); + })(AdditionalDetailsStep), +); diff --git a/src/types/onyx/Form.ts b/src/types/onyx/Form.ts index 79190aa3e6f6..646950dcb986 100644 --- a/src/types/onyx/Form.ts +++ b/src/types/onyx/Form.ts @@ -72,6 +72,18 @@ type IdologyQuestionsForm = Form<{ answer: string; }>; +type AdditionalDetailStepForm = Form<{ + legalFirstName: string; + legalLastName: string; + addressStreet: string; + addressCity: string; + addressZipCode: string; + phoneNumber: string; + dob: string; + ssn: string; + addressState: string; +}>; + export default Form; export type { @@ -89,4 +101,5 @@ export type { ReportFieldEditForm, CloseAccountForm, IdologyQuestionsForm, + AdditionalDetailStepForm, }; diff --git a/src/types/onyx/index.ts b/src/types/onyx/index.ts index 13c305abe384..ff6c782a37e1 100644 --- a/src/types/onyx/index.ts +++ b/src/types/onyx/index.ts @@ -11,6 +11,7 @@ import type CustomStatusDraft from './CustomStatusDraft'; import type Download from './Download'; import type { AddDebitCardForm, + AdditionalDetailStepForm, CloseAccountForm, DateOfBirthForm, DisplayNameForm, @@ -167,4 +168,5 @@ export type { PrivateNotesForm, ReportFieldEditForm, IdologyQuestionsForm, + AdditionalDetailStepForm, }; From 1ad742de9d5b27113e74d85691016089ff0d89ae Mon Sep 17 00:00:00 2001 From: Toby Sullivan Date: Tue, 6 Feb 2024 08:08:34 -0800 Subject: [PATCH 032/175] Fix prettier formatting --- src/libs/ReportUtils.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 09496c6b18f1..e485cf615a41 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -2257,7 +2257,14 @@ function getReportPreviewMessage( }); } - if (!isEmptyObject(linkedTransaction) && !isEmptyObject(reportAction) && shouldConsiderReceiptBeingScanned && TransactionUtils.hasReceipt(linkedTransaction) && TransactionUtils.isReceiptBeingScanned(linkedTransaction) && ReportActionsUtils.isMoneyRequestAction(reportAction)) { + if ( + !isEmptyObject(linkedTransaction) && + !isEmptyObject(reportAction) && + shouldConsiderReceiptBeingScanned && + TransactionUtils.hasReceipt(linkedTransaction) && + TransactionUtils.isReceiptBeingScanned(linkedTransaction) && + ReportActionsUtils.isMoneyRequestAction(reportAction) + ) { return Localize.translateLocal('iou.receiptScanning'); } From 5f89ad6cf8fdcc0a4a5522a35588a36c40670f70 Mon Sep 17 00:00:00 2001 From: Jayesh Mangwani Date: Thu, 8 Feb 2024 17:16:50 +0530 Subject: [PATCH 033/175] merge main, lint fixed and prettified code --- src/libs/PersonalDetailsUtils.ts | 2 +- src/pages/EnablePayments/OnfidoPrivacy.tsx | 2 +- src/pages/EnablePayments/TermsStep.tsx | 2 +- src/types/onyx/Form.ts | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libs/PersonalDetailsUtils.ts b/src/libs/PersonalDetailsUtils.ts index aa9a7f79e582..69b0f386a76c 100644 --- a/src/libs/PersonalDetailsUtils.ts +++ b/src/libs/PersonalDetailsUtils.ts @@ -1,11 +1,11 @@ import Str from 'expensify-common/lib/str'; import type {OnyxEntry, OnyxUpdate} from 'react-native-onyx'; import Onyx from 'react-native-onyx'; +import type {CurrentUserPersonalDetails} from '@components/withCurrentUserPersonalDetails'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type {PersonalDetails, PersonalDetailsList, PrivatePersonalDetails} from '@src/types/onyx'; import type {OnyxData} from '@src/types/onyx/Request'; -import type {CurrentUserPersonalDetails} from '@components/withCurrentUserPersonalDetails'; import * as LocalePhoneNumber from './LocalePhoneNumber'; import * as Localize from './Localize'; import * as UserUtils from './UserUtils'; diff --git a/src/pages/EnablePayments/OnfidoPrivacy.tsx b/src/pages/EnablePayments/OnfidoPrivacy.tsx index 80fa08c009ca..5d8cdc751e87 100644 --- a/src/pages/EnablePayments/OnfidoPrivacy.tsx +++ b/src/pages/EnablePayments/OnfidoPrivacy.tsx @@ -46,7 +46,7 @@ function OnfidoPrivacy({walletOnfidoData = DEFAULT_WALLET_ONFIDO_DATA}: OnfidoPr BankAccounts.openOnfidoFlow(); }; - let onfidoError = ErrorUtils.getLatestErrorMessage(walletOnfidoData ?? {}) || ''; + let onfidoError = ErrorUtils.getLatestErrorMessage(walletOnfidoData ?? {}) ?? ''; const onfidoFixableErrors = walletOnfidoData?.fixableErrors ?? []; onfidoError += !isEmptyObject(onfidoFixableErrors) ? `\n${onfidoFixableErrors.join('\n')}` : ''; diff --git a/src/pages/EnablePayments/TermsStep.tsx b/src/pages/EnablePayments/TermsStep.tsx index fe463f88792d..4836feae9f9b 100644 --- a/src/pages/EnablePayments/TermsStep.tsx +++ b/src/pages/EnablePayments/TermsStep.tsx @@ -33,7 +33,7 @@ function TermsStep(props: TermsStepProps) { const [error, setError] = useState(false); const {translate} = useLocalize(); - const errorMessage = error ? 'common.error.acceptTerms' : ErrorUtils.getLatestErrorMessage(props.walletTerms ?? {}) || ''; + const errorMessage = error ? 'common.error.acceptTerms' : ErrorUtils.getLatestErrorMessage(props.walletTerms ?? {}) ?? ''; const toggleDisclosure = () => { setHasAcceptedDisclosure(!hasAcceptedDisclosure); diff --git a/src/types/onyx/Form.ts b/src/types/onyx/Form.ts index bb78487892bf..7043449ae6cf 100644 --- a/src/types/onyx/Form.ts +++ b/src/types/onyx/Form.ts @@ -82,7 +82,7 @@ type AdditionalDetailStepForm = Form<{ dob: string; ssn: string; addressState: string; -}> +}>; type RoomNameForm = Form<{ roomName: string; From ed7c4d21e101a1aeede28c6eaeb20e81101938d7 Mon Sep 17 00:00:00 2001 From: Jayesh Mangwani Date: Fri, 9 Feb 2024 20:05:31 +0530 Subject: [PATCH 034/175] fix: lint --- src/pages/EnablePayments/OnfidoPrivacy.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/EnablePayments/OnfidoPrivacy.tsx b/src/pages/EnablePayments/OnfidoPrivacy.tsx index 8618499397dc..03f8df3ad82a 100644 --- a/src/pages/EnablePayments/OnfidoPrivacy.tsx +++ b/src/pages/EnablePayments/OnfidoPrivacy.tsx @@ -46,8 +46,8 @@ function OnfidoPrivacy({walletOnfidoData = DEFAULT_WALLET_ONFIDO_DATA}: OnfidoPr BankAccounts.openOnfidoFlow(); }; - const onfidoError = ErrorUtils.getLatestErrorMessage(walletOnfidoData) || ''; - const onfidoFixableErrors = walletOnfidoData?.fixableErrors??[]; + const onfidoError = ErrorUtils.getLatestErrorMessage(walletOnfidoData) ?? ''; + const onfidoFixableErrors = walletOnfidoData?.fixableErrors ?? []; if (Array.isArray(onfidoError)) { onfidoError[0] += !isEmptyObject(onfidoFixableErrors) ? `\n${onfidoFixableErrors.join('\n')}` : ''; } From e6df088475612cd7578a3c3036bd21036a9701ff Mon Sep 17 00:00:00 2001 From: Jayesh Mangwani Date: Sat, 10 Feb 2024 13:11:13 +0530 Subject: [PATCH 035/175] updated key from ADDITIONAL_DETAILS_FORM to WALLET_ADDITIONAL_DETAILS --- src/ONYXKEYS.ts | 8 ++++---- src/libs/actions/Wallet.ts | 9 +++++---- src/pages/EnablePayments/AdditionalDetailsStep.tsx | 6 +++--- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index 90a6860fb1de..b14f0985bfed 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -369,8 +369,8 @@ const ONYXKEYS = { PERSONAL_BANK_ACCOUNT_DRAFT: 'personalBankAccountFormDraft', IDOLOGY_QUESTIONS_FORM: 'idologyQuestions', IDOLOGY_QUESTIONS_FORM_DRAFT: 'idologyQuestionsDraft', - ADDITIONAL_DETAILS_FORM: 'additionalDetailStep', - ADDITIONAL_DETAILS_FORM_DRAFT: 'additionalDetailStepDraft', + WALLET_ADDITIONAL_DETAILS: 'walletAdditionalDetailsForm', + WALLET_ADDITIONAL_DETAILS_DRAFT: 'walletAdditionalDetailsFormDraft', }, } as const; @@ -562,8 +562,8 @@ type OnyxValues = { [ONYXKEYS.FORMS.PERSONAL_BANK_ACCOUNT_DRAFT]: OnyxTypes.PersonalBankAccount; [ONYXKEYS.FORMS.IDOLOGY_QUESTIONS_FORM]: OnyxTypes.IdologyQuestionsForm; [ONYXKEYS.FORMS.IDOLOGY_QUESTIONS_FORM_DRAFT]: OnyxTypes.IdologyQuestionsForm; - [ONYXKEYS.FORMS.ADDITIONAL_DETAILS_FORM]: OnyxTypes.AdditionalDetailStepForm; - [ONYXKEYS.FORMS.ADDITIONAL_DETAILS_FORM_DRAFT]: OnyxTypes.AdditionalDetailStepForm; + [ONYXKEYS.FORMS.WALLET_ADDITIONAL_DETAILS]: OnyxTypes.AdditionalDetailStepForm; + [ONYXKEYS.FORMS.WALLET_ADDITIONAL_DETAILS_DRAFT]: OnyxTypes.AdditionalDetailStepForm; }; type OnyxKeyValue = OnyxEntry; diff --git a/src/libs/actions/Wallet.ts b/src/libs/actions/Wallet.ts index b03b5e8f6d3d..4d0ba7a67fd1 100644 --- a/src/libs/actions/Wallet.ts +++ b/src/libs/actions/Wallet.ts @@ -75,11 +75,12 @@ function setKYCWallSource(source?: ValueOf, chatRe /** * Validates a user's provided details against a series of checks */ + function updatePersonalDetails(personalDetails: UpdatePersonalDetailsForWalletParams) { const optimisticData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, - key: ONYXKEYS.WALLET_ADDITIONAL_DETAILS, + key: ONYXKEYS.FORMS.WALLET_ADDITIONAL_DETAILS, value: { isLoading: true, errors: null, @@ -91,7 +92,7 @@ function updatePersonalDetails(personalDetails: UpdatePersonalDetailsForWalletPa const finallyData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, - key: ONYXKEYS.WALLET_ADDITIONAL_DETAILS, + key: ONYXKEYS.FORMS.WALLET_ADDITIONAL_DETAILS, value: { isLoading: false, }, @@ -232,7 +233,7 @@ function answerQuestionsForWallet(answers: WalletQuestionAnswer[], idNumber: str const optimisticData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, - key: ONYXKEYS.WALLET_ADDITIONAL_DETAILS, + key: ONYXKEYS.FORMS.WALLET_ADDITIONAL_DETAILS, value: { isLoading: true, }, @@ -242,7 +243,7 @@ function answerQuestionsForWallet(answers: WalletQuestionAnswer[], idNumber: str const finallyData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, - key: ONYXKEYS.WALLET_ADDITIONAL_DETAILS, + key: ONYXKEYS.FORMS.WALLET_ADDITIONAL_DETAILS, value: { isLoading: false, }, diff --git a/src/pages/EnablePayments/AdditionalDetailsStep.tsx b/src/pages/EnablePayments/AdditionalDetailsStep.tsx index ad802a74c050..c9b557a197e8 100644 --- a/src/pages/EnablePayments/AdditionalDetailsStep.tsx +++ b/src/pages/EnablePayments/AdditionalDetailsStep.tsx @@ -60,7 +60,7 @@ function AdditionalDetailsStep({walletAdditionalDetails = DEFAULT_WALLET_ADDITIO const maxDate = subYears(currentDate, CONST.DATE_BIRTH.MIN_AGE_FOR_PAYMENT); const shouldAskForFullSSN = walletAdditionalDetails?.errorCode === CONST.WALLET.ERROR.SSN; - const validate = (values: OnyxFormValuesFields) => { + const validate = (values: OnyxFormValuesFields) => { const requiredFields = ['legalFirstName', 'legalLastName', 'addressStreet', 'addressCity', 'addressZipCode', 'phoneNumber', 'dob', 'ssn', 'addressState']; const errors = ValidationUtils.getFieldRequiredErrors(values, requiredFields); @@ -97,7 +97,7 @@ function AdditionalDetailsStep({walletAdditionalDetails = DEFAULT_WALLET_ADDITIO return errors; }; - const activateWallet = (values: OnyxFormValuesFields) => { + const activateWallet = (values: OnyxFormValuesFields) => { const personalDetails = { phoneNumber: (values.phoneNumber && parsePhoneNumber(values.phoneNumber, {regionCode: CONST.COUNTRY.US}).number?.significant) ?? '', legalFirstName: values.legalFirstName ?? '', @@ -147,7 +147,7 @@ function AdditionalDetailsStep({walletAdditionalDetails = DEFAULT_WALLET_ADDITIO Date: Mon, 12 Feb 2024 12:58:28 +0530 Subject: [PATCH 036/175] rearranged import for GetPhysicalCardForm --- src/types/onyx/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/types/onyx/index.ts b/src/types/onyx/index.ts index ca3abbca28b9..c9742595272f 100644 --- a/src/types/onyx/index.ts +++ b/src/types/onyx/index.ts @@ -16,8 +16,8 @@ import type { CloseAccountForm, DateOfBirthForm, DisplayNameForm, - IdologyQuestionsForm, GetPhysicalCardForm, + IdologyQuestionsForm, IKnowATeacherForm, IntroSchoolPrincipalForm, NewRoomForm, From ee76e50335a44ed6053292ee8deb78423a3edacf Mon Sep 17 00:00:00 2001 From: Jayesh Mangwani Date: Mon, 12 Feb 2024 20:17:11 +0530 Subject: [PATCH 037/175] updated IDOLOGY_QUESTIONS_FORM key name --- src/ONYXKEYS.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index f19adfbeedd3..29a2955facfa 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -367,8 +367,8 @@ const ONYXKEYS = { REIMBURSEMENT_ACCOUNT_FORM_DRAFT: 'reimbursementAccountDraft', PERSONAL_BANK_ACCOUNT: 'personalBankAccountForm', PERSONAL_BANK_ACCOUNT_DRAFT: 'personalBankAccountFormDraft', - IDOLOGY_QUESTIONS_FORM: 'idologyQuestions', - IDOLOGY_QUESTIONS_FORM_DRAFT: 'idologyQuestionsDraft', + IDOLOGY_QUESTIONS_FORM: 'idologyQuestionsForm', + IDOLOGY_QUESTIONS_FORM_DRAFT: 'idologyQuestionsFormDraft', WALLET_ADDITIONAL_DETAILS: 'walletAdditionalDetailsForm', WALLET_ADDITIONAL_DETAILS_DRAFT: 'walletAdditionalDetailsFormDraft', }, From 26e354f83e6c3fc8c7281d12d911ecd8c24ff0d4 Mon Sep 17 00:00:00 2001 From: Toby Sullivan Date: Mon, 12 Feb 2024 09:12:06 -0800 Subject: [PATCH 038/175] Fix formatting error --- src/libs/ReportUtils.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index e329d6e51a49..d86c838ccccd 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -2308,7 +2308,6 @@ function getReportPreviewMessage( return Localize.translateLocal('iou.waitingOnBankAccount', {submitterDisplayName}); } - const lastActorID = reportAction?.actorAccountID; const comment = !isEmptyObject(linkedTransaction) ? TransactionUtils.getDescription(linkedTransaction) : undefined; let amount = originalMessage?.amount; From 2c34dbf214c8511caa8357cfc186aacec0b0fef1 Mon Sep 17 00:00:00 2001 From: Jayesh Mangwani Date: Fri, 16 Feb 2024 14:39:23 +0530 Subject: [PATCH 039/175] fixed additional details step and idology questions types errors --- src/ONYXKEYS.ts | 2 ++ .../EnablePayments/AdditionalDetailsStep.tsx | 24 +++++++++++++------ src/pages/EnablePayments/IdologyQuestions.tsx | 4 ++-- src/types/form/index.ts | 2 ++ 4 files changed, 23 insertions(+), 9 deletions(-) diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index d94f65954a98..05f064d90d5f 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -429,6 +429,8 @@ type OnyxFormValuesMapping = { [ONYXKEYS.FORMS.REIMBURSEMENT_ACCOUNT_FORM]: FormTypes.ReimbursementAccountForm; [ONYXKEYS.FORMS.PERSONAL_BANK_ACCOUNT]: FormTypes.PersonalBankAccountForm; [ONYXKEYS.FORMS.WORKSPACE_DESCRIPTION_FORM]: FormTypes.WorkspaceDescriptionForm; + [ONYXKEYS.FORMS.WALLET_ADDITIONAL_DETAILS]: FormTypes.AdditionalDetailStepForm; + [ONYXKEYS.FORMS.IDOLOGY_QUESTIONS_FORM]: FormTypes.IdologyQuestionsForm; }; type OnyxFormDraftValuesMapping = { diff --git a/src/pages/EnablePayments/AdditionalDetailsStep.tsx b/src/pages/EnablePayments/AdditionalDetailsStep.tsx index c9b557a197e8..b347c93e296e 100644 --- a/src/pages/EnablePayments/AdditionalDetailsStep.tsx +++ b/src/pages/EnablePayments/AdditionalDetailsStep.tsx @@ -6,7 +6,7 @@ import type {OnyxEntry} from 'react-native-onyx'; import DatePicker from '@components/DatePicker'; import FormProvider from '@components/Form/FormProvider'; import InputWrapper from '@components/Form/InputWrapper'; -import type {OnyxFormValuesFields} from '@components/Form/types'; +import type {FormInputErrors, FormOnyxValues} from '@components/Form/types'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import ScreenWrapper from '@components/ScreenWrapper'; import Text from '@components/Text'; @@ -25,6 +25,7 @@ import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type {WalletAdditionalDetails} from '@src/types/onyx'; import IdologyQuestions from './IdologyQuestions'; +import INPUT_IDS from '@src/types/form/AdditionalDetailStepForm'; const DEFAULT_WALLET_ADDITIONAL_DETAILS = { errorFields: {}, @@ -51,7 +52,16 @@ const fieldNameTranslationKeys = { ssn: 'common.ssnLast4', ssnFull9: 'common.ssnFull9', } as const; - +const STEP_FIELDS = [ + INPUT_IDS.LEGAL_FIRST_NAME, + INPUT_IDS.LEGAL_LAST_NAME, + INPUT_IDS.ADDRESS_STREET, + INPUT_IDS.ADDRESS_CITY, + INPUT_IDS.PHONE_NUMBER, + INPUT_IDS.DOB, + INPUT_IDS.ADDRESS_STATE, + INPUT_IDS.SSN +]; function AdditionalDetailsStep({walletAdditionalDetails = DEFAULT_WALLET_ADDITIONAL_DETAILS, currentUserPersonalDetails}: AdditionalDetailsStepProps) { const {translate} = useLocalize(); const styles = useThemeStyles(); @@ -60,9 +70,9 @@ function AdditionalDetailsStep({walletAdditionalDetails = DEFAULT_WALLET_ADDITIO const maxDate = subYears(currentDate, CONST.DATE_BIRTH.MIN_AGE_FOR_PAYMENT); const shouldAskForFullSSN = walletAdditionalDetails?.errorCode === CONST.WALLET.ERROR.SSN; - const validate = (values: OnyxFormValuesFields) => { + const validate = (values: FormOnyxValues): FormInputErrors => { const requiredFields = ['legalFirstName', 'legalLastName', 'addressStreet', 'addressCity', 'addressZipCode', 'phoneNumber', 'dob', 'ssn', 'addressState']; - const errors = ValidationUtils.getFieldRequiredErrors(values, requiredFields); + const errors = ValidationUtils.getFieldRequiredErrors(values, STEP_FIELDS); if (values.dob) { if (!ValidationUtils.isValidPastDate(values.dob) || !ValidationUtils.meetsMaximumAgeRequirement(values.dob)) { @@ -97,7 +107,7 @@ function AdditionalDetailsStep({walletAdditionalDetails = DEFAULT_WALLET_ADDITIO return errors; }; - const activateWallet = (values: OnyxFormValuesFields) => { + const activateWallet = (values: FormOnyxValues) => { const personalDetails = { phoneNumber: (values.phoneNumber && parsePhoneNumber(values.phoneNumber, {regionCode: CONST.COUNTRY.US}).number?.significant) ?? '', legalFirstName: values.legalFirstName ?? '', @@ -197,10 +207,10 @@ function AdditionalDetailsStep({walletAdditionalDetails = DEFAULT_WALLET_ADDITIO placeholder={translate('common.phoneNumberPlaceholder')} shouldSaveDraft /> - InputComponent={DatePicker} inputID="dob" - // @ts-expect-error TODO: Remove this once DatePicker (https://github.com/Expensify/App/issues/25148) is migrated to TypeScript. containerStyles={[styles.mt4]} label={translate(fieldNameTranslationKeys.dob)} placeholder={translate('common.dob')} diff --git a/src/pages/EnablePayments/IdologyQuestions.tsx b/src/pages/EnablePayments/IdologyQuestions.tsx index 4a5ef72019c0..f54f5a7cccba 100644 --- a/src/pages/EnablePayments/IdologyQuestions.tsx +++ b/src/pages/EnablePayments/IdologyQuestions.tsx @@ -3,7 +3,7 @@ import {View} from 'react-native'; import type {WalletAdditionalQuestionDetails} from 'src/types/onyx'; import FormProvider from '@components/Form/FormProvider'; import InputWrapper from '@components/Form/InputWrapper'; -import type {OnyxFormValuesFields} from '@components/Form/types'; +import type {FormOnyxValues,FormInputErrors} from '@components/Form/types'; import type {Choice} from '@components/RadioButtons'; import SingleChoiceQuestion from '@components/SingleChoiceQuestion'; import Text from '@components/Text'; @@ -91,7 +91,7 @@ function IdologyQuestions({questions, idNumber}: IdologyQuestionsProps) { } }; - const validate = (values: OnyxFormValuesFields) => { + const validate = (values: FormOnyxValues) => { const errors: Errors = {}; if (!values.answer) { errors.answer = translate('additionalDetailsStep.selectAnswer'); diff --git a/src/types/form/index.ts b/src/types/form/index.ts index d9263991023c..9e457f83ace6 100644 --- a/src/types/form/index.ts +++ b/src/types/form/index.ts @@ -34,4 +34,6 @@ export type {WorkspaceRateAndUnitForm} from './WorkspaceRateAndUnitForm'; export type {WorkspaceSettingsForm} from './WorkspaceSettingsForm'; export type {WorkspaceDescriptionForm} from './WorkspaceDescriptionForm'; export type {WorkspaceProfileDescriptionForm} from './WorkspaceProfileDescriptionForm'; +export type {AdditionalDetailStepForm} from './AdditionalDetailStepForm'; +export type {IdologyQuestionsForm} from './IdologyQuestionsForm'; export type {default as Form} from './Form'; From 98ef6936cc57af1d9b20a24e1053eb8b7dad7a04 Mon Sep 17 00:00:00 2001 From: Jayesh Mangwani Date: Fri, 16 Feb 2024 14:46:29 +0530 Subject: [PATCH 040/175] code prettified & lint fixed --- .../EnablePayments/AdditionalDetailsStep.tsx | 5 ++--- src/pages/EnablePayments/IdologyQuestions.tsx | 4 ++-- src/types/form/AdditionalDetailStepForm.ts | 2 +- src/types/form/IdologyQuestionsForm.ts | 2 +- src/types/onyx/index.ts | 18 +----------------- 5 files changed, 7 insertions(+), 24 deletions(-) diff --git a/src/pages/EnablePayments/AdditionalDetailsStep.tsx b/src/pages/EnablePayments/AdditionalDetailsStep.tsx index b347c93e296e..97041a5b021a 100644 --- a/src/pages/EnablePayments/AdditionalDetailsStep.tsx +++ b/src/pages/EnablePayments/AdditionalDetailsStep.tsx @@ -23,9 +23,9 @@ import AddressForm from '@pages/ReimbursementAccount/AddressForm'; import * as Wallet from '@userActions/Wallet'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; +import INPUT_IDS from '@src/types/form/AdditionalDetailStepForm'; import type {WalletAdditionalDetails} from '@src/types/onyx'; import IdologyQuestions from './IdologyQuestions'; -import INPUT_IDS from '@src/types/form/AdditionalDetailStepForm'; const DEFAULT_WALLET_ADDITIONAL_DETAILS = { errorFields: {}, @@ -60,7 +60,7 @@ const STEP_FIELDS = [ INPUT_IDS.PHONE_NUMBER, INPUT_IDS.DOB, INPUT_IDS.ADDRESS_STATE, - INPUT_IDS.SSN + INPUT_IDS.SSN, ]; function AdditionalDetailsStep({walletAdditionalDetails = DEFAULT_WALLET_ADDITIONAL_DETAILS, currentUserPersonalDetails}: AdditionalDetailsStepProps) { const {translate} = useLocalize(); @@ -71,7 +71,6 @@ function AdditionalDetailsStep({walletAdditionalDetails = DEFAULT_WALLET_ADDITIO const shouldAskForFullSSN = walletAdditionalDetails?.errorCode === CONST.WALLET.ERROR.SSN; const validate = (values: FormOnyxValues): FormInputErrors => { - const requiredFields = ['legalFirstName', 'legalLastName', 'addressStreet', 'addressCity', 'addressZipCode', 'phoneNumber', 'dob', 'ssn', 'addressState']; const errors = ValidationUtils.getFieldRequiredErrors(values, STEP_FIELDS); if (values.dob) { diff --git a/src/pages/EnablePayments/IdologyQuestions.tsx b/src/pages/EnablePayments/IdologyQuestions.tsx index f54f5a7cccba..cadb7092f0c4 100644 --- a/src/pages/EnablePayments/IdologyQuestions.tsx +++ b/src/pages/EnablePayments/IdologyQuestions.tsx @@ -3,7 +3,7 @@ import {View} from 'react-native'; import type {WalletAdditionalQuestionDetails} from 'src/types/onyx'; import FormProvider from '@components/Form/FormProvider'; import InputWrapper from '@components/Form/InputWrapper'; -import type {FormOnyxValues,FormInputErrors} from '@components/Form/types'; +import type {FormInputErrors, FormOnyxValues} from '@components/Form/types'; import type {Choice} from '@components/RadioButtons'; import SingleChoiceQuestion from '@components/SingleChoiceQuestion'; import Text from '@components/Text'; @@ -91,7 +91,7 @@ function IdologyQuestions({questions, idNumber}: IdologyQuestionsProps) { } }; - const validate = (values: FormOnyxValues) => { + const validate = (values: FormOnyxValues): FormInputErrors => { const errors: Errors = {}; if (!values.answer) { errors.answer = translate('additionalDetailsStep.selectAnswer'); diff --git a/src/types/form/AdditionalDetailStepForm.ts b/src/types/form/AdditionalDetailStepForm.ts index b432ae87e2cf..f102d03679ba 100644 --- a/src/types/form/AdditionalDetailStepForm.ts +++ b/src/types/form/AdditionalDetailStepForm.ts @@ -25,4 +25,4 @@ type AdditionalDetailStepForm = Form<{ }>; export type {AdditionalDetailStepForm}; -export default INPUT_IDS; \ No newline at end of file +export default INPUT_IDS; diff --git a/src/types/form/IdologyQuestionsForm.ts b/src/types/form/IdologyQuestionsForm.ts index eb48b9027541..5b8d50c68abf 100644 --- a/src/types/form/IdologyQuestionsForm.ts +++ b/src/types/form/IdologyQuestionsForm.ts @@ -9,4 +9,4 @@ type IdologyQuestionsForm = Form<{ }>; export type {IdologyQuestionsForm}; -export default INPUT_IDS; \ No newline at end of file +export default INPUT_IDS; diff --git a/src/types/onyx/index.ts b/src/types/onyx/index.ts index e116aa99e95a..de9e96d8590b 100644 --- a/src/types/onyx/index.ts +++ b/src/types/onyx/index.ts @@ -11,23 +11,7 @@ import type Credentials from './Credentials'; import type Currency from './Currency'; import type CustomStatusDraft from './CustomStatusDraft'; import type Download from './Download'; -import type { - AddDebitCardForm, - AdditionalDetailStepForm, - CloseAccountForm, - DateOfBirthForm, - DisplayNameForm, - GetPhysicalCardForm, - IdologyQuestionsForm, - IKnowATeacherForm, - IntroSchoolPrincipalForm, - NewRoomForm, - PrivateNotesForm, - ReportFieldEditForm, - RoomNameForm, - WorkspaceSettingsForm, -} from './Form'; -import type Form from './Form'; +import type {AdditionalDetailStepForm, IdologyQuestionsForm, PrivateNotesForm, ReportFieldEditForm, RoomNameForm} from './Form'; import type FrequentlyUsedEmoji from './FrequentlyUsedEmoji'; import type {FundList} from './Fund'; import type Fund from './Fund'; From b258238c5c7150ad34fef64b086d1f649be3266d Mon Sep 17 00:00:00 2001 From: Andrew Gable Date: Fri, 16 Feb 2024 17:34:00 -0700 Subject: [PATCH 041/175] Add back some HybridApp logic after TS migration to fix Authentication --- src/pages/LogOutPreviousUserPage.tsx | 36 +++++++++++++++++++++------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/src/pages/LogOutPreviousUserPage.tsx b/src/pages/LogOutPreviousUserPage.tsx index f68344604dfa..5191756ccf0b 100644 --- a/src/pages/LogOutPreviousUserPage.tsx +++ b/src/pages/LogOutPreviousUserPage.tsx @@ -1,6 +1,6 @@ import type {StackScreenProps} from '@react-navigation/stack'; -import React, {useEffect} from 'react'; -import {Linking} from 'react-native'; +import React, {useContext, useEffect} from 'react'; +import {Linking, NativeModules} from 'react-native'; import {withOnyx} from 'react-native-onyx'; import type {OnyxEntry} from 'react-native-onyx'; import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator'; @@ -9,11 +9,17 @@ import type {AuthScreensParamList} from '@navigation/types'; import * as SessionActions from '@userActions/Session'; import ONYXKEYS from '@src/ONYXKEYS'; import type SCREENS from '@src/SCREENS'; -import type {Session} from '@src/types/onyx'; +import type {Account, Session} from '@src/types/onyx'; +import InitialUrlContext from "@libs/InitialUrlContext"; +import CONST from "@src/CONST"; +import lodashGet from "lodash/get"; +import ROUTES, {type Route} from "@src/ROUTES"; +import Navigation from "@navigation/Navigation"; type LogOutPreviousUserPageOnyxProps = { /** The data about the current session which will be set once the user is authenticated and we return to this component as an AuthScreen */ session: OnyxEntry; + account: OnyxEntry; }; type LogOutPreviousUserPageProps = LogOutPreviousUserPageOnyxProps & StackScreenProps; @@ -22,10 +28,12 @@ type LogOutPreviousUserPageProps = LogOutPreviousUserPageOnyxProps & StackScreen // out if the transition is for another user. // // This component should not do any other navigation as that handled in App.setUpPoliciesAndNavigate -function LogOutPreviousUserPage({session, route}: LogOutPreviousUserPageProps) { +function LogOutPreviousUserPage({session, route, account}: LogOutPreviousUserPageProps) { + const initUrl = useContext(InitialUrlContext); useEffect(() => { - Linking.getInitialURL().then((transitionURL) => { + Linking.getInitialURL().then((url) => { const sessionEmail = session?.email; + const transitionURL = NativeModules.HybridAppModule ? CONST.DEEPLINK_BASE_URL + initUrl : url; const isLoggingInAsNewUser = SessionUtils.isLoggingInAsNewUser(transitionURL ?? undefined, sessionEmail); if (isLoggingInAsNewUser) { @@ -42,11 +50,20 @@ function LogOutPreviousUserPage({session, route}: LogOutPreviousUserPageProps) { const shortLivedAuthToken = route.params.shortLivedAuthToken ?? ''; SessionActions.signInWithShortLivedAuthToken(email, shortLivedAuthToken); } + const exitTo = route.params.exitTo as Route | null; + // We don't want to navigate to the exitTo route when creating a new workspace from a deep link, + // because we already handle creating the optimistic policy and navigating to it in App.setUpPoliciesAndNavigate, + // which is already called when AuthScreens mounts. + if (exitTo && exitTo !== ROUTES.WORKSPACE_NEW && !account?.isLoading && !isLoggingInAsNewUser) { + Navigation.isNavigationReady().then(() => { + // remove this screen and navigate to exit route + const exitUrl = NativeModules.HybridAppModule ? Navigation.parseHybridAppUrl(exitTo) : exitTo; + Navigation.goBack(); + Navigation.navigate(exitUrl); + }); + } }); - - // We only want to run this effect once on mount (when the page first loads after transitioning from OldDot) - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); + }, [initUrl]); return ; } @@ -54,6 +71,7 @@ function LogOutPreviousUserPage({session, route}: LogOutPreviousUserPageProps) { LogOutPreviousUserPage.displayName = 'LogOutPreviousUserPage'; export default withOnyx({ + account: {key: ONYXKEYS.ACCOUNT}, session: { key: ONYXKEYS.SESSION, }, From 2961243d5da20f2336fe43adbfa15d9de9ffb469 Mon Sep 17 00:00:00 2001 From: Andrew Gable Date: Fri, 16 Feb 2024 17:42:50 -0700 Subject: [PATCH 042/175] Fix lint --- src/pages/LogOutPreviousUserPage.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/LogOutPreviousUserPage.tsx b/src/pages/LogOutPreviousUserPage.tsx index 5191756ccf0b..297a9166956c 100644 --- a/src/pages/LogOutPreviousUserPage.tsx +++ b/src/pages/LogOutPreviousUserPage.tsx @@ -12,8 +12,8 @@ import type SCREENS from '@src/SCREENS'; import type {Account, Session} from '@src/types/onyx'; import InitialUrlContext from "@libs/InitialUrlContext"; import CONST from "@src/CONST"; -import lodashGet from "lodash/get"; -import ROUTES, {type Route} from "@src/ROUTES"; +import ROUTES from "@src/ROUTES"; +import type {Route} from "@src/ROUTES"; import Navigation from "@navigation/Navigation"; type LogOutPreviousUserPageOnyxProps = { From 87817e505679354928b93145edf8a450b109e4fe Mon Sep 17 00:00:00 2001 From: Andrew Gable Date: Fri, 16 Feb 2024 17:54:14 -0700 Subject: [PATCH 043/175] More lint --- src/pages/LogOutPreviousUserPage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/LogOutPreviousUserPage.tsx b/src/pages/LogOutPreviousUserPage.tsx index 297a9166956c..c6144c70db3e 100644 --- a/src/pages/LogOutPreviousUserPage.tsx +++ b/src/pages/LogOutPreviousUserPage.tsx @@ -63,7 +63,7 @@ function LogOutPreviousUserPage({session, route, account}: LogOutPreviousUserPag }); } }); - }, [initUrl]); + }, [initUrl, account, route, session]); return ; } From d72cda0382c4d6f35d7f040bf14d31aa7c062d55 Mon Sep 17 00:00:00 2001 From: Andrew Gable Date: Fri, 16 Feb 2024 18:00:05 -0700 Subject: [PATCH 044/175] Prettier fixes --- src/pages/LogOutPreviousUserPage.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/pages/LogOutPreviousUserPage.tsx b/src/pages/LogOutPreviousUserPage.tsx index c6144c70db3e..a10988945c4e 100644 --- a/src/pages/LogOutPreviousUserPage.tsx +++ b/src/pages/LogOutPreviousUserPage.tsx @@ -4,17 +4,17 @@ import {Linking, NativeModules} from 'react-native'; import {withOnyx} from 'react-native-onyx'; import type {OnyxEntry} from 'react-native-onyx'; import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator'; +import InitialUrlContext from '@libs/InitialUrlContext'; import * as SessionUtils from '@libs/SessionUtils'; +import Navigation from '@navigation/Navigation'; import type {AuthScreensParamList} from '@navigation/types'; import * as SessionActions from '@userActions/Session'; +import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; +import ROUTES from '@src/ROUTES'; +import type {Route} from '@src/ROUTES'; import type SCREENS from '@src/SCREENS'; import type {Account, Session} from '@src/types/onyx'; -import InitialUrlContext from "@libs/InitialUrlContext"; -import CONST from "@src/CONST"; -import ROUTES from "@src/ROUTES"; -import type {Route} from "@src/ROUTES"; -import Navigation from "@navigation/Navigation"; type LogOutPreviousUserPageOnyxProps = { /** The data about the current session which will be set once the user is authenticated and we return to this component as an AuthScreen */ From 24fb379d31f4fa6647a12795ff7308be4cdd8f47 Mon Sep 17 00:00:00 2001 From: Jayesh Mangwani Date: Wed, 21 Feb 2024 19:48:37 +0530 Subject: [PATCH 045/175] fix loading issue for idology questions and fixed onValueChange for SingleChoiceQuestion --- src/libs/actions/Wallet.ts | 4 ++-- src/pages/EnablePayments/IdologyQuestions.tsx | 7 ++++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/libs/actions/Wallet.ts b/src/libs/actions/Wallet.ts index 9cb4b28bef20..ffc68c562c4c 100644 --- a/src/libs/actions/Wallet.ts +++ b/src/libs/actions/Wallet.ts @@ -233,7 +233,7 @@ function answerQuestionsForWallet(answers: WalletQuestionAnswer[], idNumber: str const optimisticData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, - key: ONYXKEYS.FORMS.WALLET_ADDITIONAL_DETAILS, + key: ONYXKEYS.FORMS.IDOLOGY_QUESTIONS_FORM, value: { isLoading: true, }, @@ -243,7 +243,7 @@ function answerQuestionsForWallet(answers: WalletQuestionAnswer[], idNumber: str const finallyData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, - key: ONYXKEYS.FORMS.WALLET_ADDITIONAL_DETAILS, + key: ONYXKEYS.FORMS.IDOLOGY_QUESTIONS_FORM, value: { isLoading: false, }, diff --git a/src/pages/EnablePayments/IdologyQuestions.tsx b/src/pages/EnablePayments/IdologyQuestions.tsx index cadb7092f0c4..b00010671518 100644 --- a/src/pages/EnablePayments/IdologyQuestions.tsx +++ b/src/pages/EnablePayments/IdologyQuestions.tsx @@ -126,9 +126,10 @@ function IdologyQuestions({questions, idNumber}: IdologyQuestionsProps) { prompt={currentQuestion.prompt} possibleAnswers={possibleAnswers} currentQuestionIndex={currentQuestionIndex} - onInputChange={chooseAnswer} - // NOTEME: check the PR where this was added - // onValueChange={chooseAnswer} + onValueChange={(value) => { + chooseAnswer(String(value)); + }} + onInputChange={() => {}} /> From 708e818589c46508701cf0c6bfc0c93bbef437c8 Mon Sep 17 00:00:00 2001 From: Jayesh Mangwani Date: Wed, 21 Feb 2024 20:46:53 +0530 Subject: [PATCH 046/175] extracted URLs to CONST and deleted unused files --- src/CONST.ts | 4 ++++ .../EnablePayments/AdditionalDetailsStep.tsx | 2 +- src/pages/EnablePayments/IdologyQuestions.tsx | 3 ++- src/pages/EnablePayments/OnfidoPrivacy.tsx | 7 ++++--- src/pages/EnablePayments/TermsStep.tsx | 8 ++++--- .../walletAdditionalDetailsDraftPropTypes.js | 13 ------------ .../walletOnfidoDataPropTypes.js | 21 ------------------- .../ReimbursementAccount/BankAccountStep.js | 2 +- .../substeps/ConfirmAgreements.tsx | 3 ++- 9 files changed, 19 insertions(+), 44 deletions(-) delete mode 100644 src/pages/EnablePayments/walletAdditionalDetailsDraftPropTypes.js delete mode 100644 src/pages/EnablePayments/walletOnfidoDataPropTypes.js diff --git a/src/CONST.ts b/src/CONST.ts index ac8533c620b9..228f8bb97953 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -505,6 +505,10 @@ const CONST = { TERMS_URL: `${USE_EXPENSIFY_URL}/terms`, PRIVACY_URL: `${USE_EXPENSIFY_URL}/privacy`, LICENSES_URL: `${USE_EXPENSIFY_URL}/licenses`, + ACH_TERMS_URL: `${USE_EXPENSIFY_URL}/achterms`, + WALLET_AGREEMENT_URL: `${USE_EXPENSIFY_URL}/walletagreement`, + HELP_LINK_URL: `${USE_EXPENSIFY_URL}/usa-patriot-act`, + ELECTRONIC_DISCLOSURES_URL: `${USE_EXPENSIFY_URL}/esignagreement`, GITHUB_RELEASE_URL: 'https://api.github.com/repos/expensify/app/releases/latest', ADD_SECONDARY_LOGIN_URL: encodeURI('settings?param={"section":"account","openModal":"secondaryLogin"}'), MANAGE_CARDS_URL: 'domain_companycards', diff --git a/src/pages/EnablePayments/AdditionalDetailsStep.tsx b/src/pages/EnablePayments/AdditionalDetailsStep.tsx index 97041a5b021a..cdf166536c5f 100644 --- a/src/pages/EnablePayments/AdditionalDetailsStep.tsx +++ b/src/pages/EnablePayments/AdditionalDetailsStep.tsx @@ -150,7 +150,7 @@ function AdditionalDetailsStep({walletAdditionalDetails = DEFAULT_WALLET_ADDITIO {translate('additionalDetailsStep.helpText')} {translate('additionalDetailsStep.helpLink')} diff --git a/src/pages/EnablePayments/IdologyQuestions.tsx b/src/pages/EnablePayments/IdologyQuestions.tsx index b00010671518..13c71f7005a9 100644 --- a/src/pages/EnablePayments/IdologyQuestions.tsx +++ b/src/pages/EnablePayments/IdologyQuestions.tsx @@ -11,6 +11,7 @@ import TextLink from '@components/TextLink'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import * as BankAccounts from '@userActions/BankAccounts'; +import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type {Errors} from '@src/types/onyx/OnyxCommon'; @@ -105,7 +106,7 @@ function IdologyQuestions({questions, idNumber}: IdologyQuestionsProps) { {translate('additionalDetailsStep.helpTextIdologyQuestions')} {translate('additionalDetailsStep.helpLink')} diff --git a/src/pages/EnablePayments/OnfidoPrivacy.tsx b/src/pages/EnablePayments/OnfidoPrivacy.tsx index 03f8df3ad82a..99117e3f1e99 100644 --- a/src/pages/EnablePayments/OnfidoPrivacy.tsx +++ b/src/pages/EnablePayments/OnfidoPrivacy.tsx @@ -13,6 +13,7 @@ import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import * as ErrorUtils from '@libs/ErrorUtils'; import * as BankAccounts from '@userActions/BankAccounts'; +import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type {WalletOnfido} from '@src/types/onyx'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; @@ -60,11 +61,11 @@ function OnfidoPrivacy({walletOnfidoData = DEFAULT_WALLET_ONFIDO_DATA}: OnfidoPr {translate('onfidoStep.acceptTerms')} - {translate('onfidoStep.facialScan')} + {translate('onfidoStep.facialScan')} {', '} - {translate('common.privacy')} + {translate('common.privacy')} {` ${translate('common.and')} `} - {translate('common.termsOfService')}. + {translate('common.termsOfService')}. diff --git a/src/pages/EnablePayments/TermsStep.tsx b/src/pages/EnablePayments/TermsStep.tsx index 4836feae9f9b..ecb636e854f0 100644 --- a/src/pages/EnablePayments/TermsStep.tsx +++ b/src/pages/EnablePayments/TermsStep.tsx @@ -11,6 +11,7 @@ import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import * as ErrorUtils from '@libs/ErrorUtils'; import * as BankAccounts from '@userActions/BankAccounts'; +import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type {UserWallet, WalletTerms} from '@src/types/onyx'; import LongTermsForm from './TermsPage/LongTermsForm'; @@ -69,7 +70,8 @@ function TermsStep(props: TermsStepProps) { LabelComponent={() => ( {`${translate('termsStep.haveReadAndAgree')}`} - {`${translate('termsStep.electronicDisclosures')}.`} + + {`${translate('termsStep.electronicDisclosures')}.`} )} /> @@ -80,11 +82,11 @@ function TermsStep(props: TermsStepProps) { {`${translate('termsStep.agreeToThe')} `} - {`${translate('common.privacy')} `} + {`${translate('common.privacy')} `} {`${translate('common.and')} `} - {`${translate('termsStep.walletAgreement')}.`} + {`${translate('termsStep.walletAgreement')}.`} )} /> diff --git a/src/pages/EnablePayments/walletAdditionalDetailsDraftPropTypes.js b/src/pages/EnablePayments/walletAdditionalDetailsDraftPropTypes.js deleted file mode 100644 index 747fa82f9fa3..000000000000 --- a/src/pages/EnablePayments/walletAdditionalDetailsDraftPropTypes.js +++ /dev/null @@ -1,13 +0,0 @@ -import PropTypes from 'prop-types'; - -export default PropTypes.shape({ - legalFirstName: PropTypes.string, - legalLastName: PropTypes.string, - addressStreet: PropTypes.string, - addressCity: PropTypes.string, - addressState: PropTypes.string, - addressZip: PropTypes.string, - phoneNumber: PropTypes.string, - dob: PropTypes.string, - ssn: PropTypes.string, -}); diff --git a/src/pages/EnablePayments/walletOnfidoDataPropTypes.js b/src/pages/EnablePayments/walletOnfidoDataPropTypes.js deleted file mode 100644 index cedc1f2777b5..000000000000 --- a/src/pages/EnablePayments/walletOnfidoDataPropTypes.js +++ /dev/null @@ -1,21 +0,0 @@ -import PropTypes from 'prop-types'; - -export default PropTypes.shape({ - /** Unique identifier returned from openOnfidoFlow then re-sent to ActivateWallet with Onfido response data */ - applicantID: PropTypes.string, - - /** Token used to initialize the Onfido SDK token */ - sdkToken: PropTypes.string, - - /** Loading state to provide feedback when we are waiting for a request to finish */ - loading: PropTypes.bool, - - /** Error message to inform the user of any problem that might occur */ - error: PropTypes.string, - - /** A list of Onfido errors that the user can fix in order to attempt the Onfido flow again */ - fixableErrors: PropTypes.arrayOf(PropTypes.string), - - /** Whether the user has accepted the privacy policy of Onfido or not */ - hasAcceptedPrivacyPolicy: PropTypes.bool, -}); diff --git a/src/pages/ReimbursementAccount/BankAccountStep.js b/src/pages/ReimbursementAccount/BankAccountStep.js index 278036430dbf..2c40c5a2ed2f 100644 --- a/src/pages/ReimbursementAccount/BankAccountStep.js +++ b/src/pages/ReimbursementAccount/BankAccountStep.js @@ -179,7 +179,7 @@ function BankAccountStep(props) { )} - {props.translate('common.privacy')} + {props.translate('common.privacy')} Link.openExternalLink('https://community.expensify.com/discussion/5677/deep-dive-how-expensify-protects-your-information/')} style={[styles.flexRow, styles.alignItemsCenter]} diff --git a/src/pages/ReimbursementAccount/CompleteVerification/substeps/ConfirmAgreements.tsx b/src/pages/ReimbursementAccount/CompleteVerification/substeps/ConfirmAgreements.tsx index aa554ca87eb2..fae7702053b7 100644 --- a/src/pages/ReimbursementAccount/CompleteVerification/substeps/ConfirmAgreements.tsx +++ b/src/pages/ReimbursementAccount/CompleteVerification/substeps/ConfirmAgreements.tsx @@ -11,6 +11,7 @@ import useLocalize from '@hooks/useLocalize'; import type {SubStepProps} from '@hooks/useSubStep/types'; import useThemeStyles from '@hooks/useThemeStyles'; import * as ValidationUtils from '@libs/ValidationUtils'; +import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import INPUT_IDS from '@src/types/form/ReimbursementAccountForm'; import type {ReimbursementAccount} from '@src/types/onyx'; @@ -90,7 +91,7 @@ function ConfirmAgreements({onNext, reimbursementAccount}: ConfirmAgreementsProp LabelComponent={() => ( {translate('common.iAcceptThe')} - {`${translate('completeVerificationStep.termsAndConditions')}`} + {`${translate('completeVerificationStep.termsAndConditions')}`} )} defaultValue={defaultValues.acceptTermsAndConditions} From ce8832837a03264d7a95085f06a247a03fdd0ff2 Mon Sep 17 00:00:00 2001 From: Toby Sullivan Date: Wed, 21 Feb 2024 09:21:25 -0800 Subject: [PATCH 047/175] Get linked transaction only when absent --- src/libs/ReportUtils.ts | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 9f150c241540..1a2a435199d0 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -2305,9 +2305,9 @@ function getReportPreviewMessage( return reportActionMessage; } - const linkedTransaction = !isEmptyObject(reportAction) ? TransactionUtils.getLinkedTransaction(reportAction) : {}; if (!isEmptyObject(reportAction) && !isIOUReport(report) && reportAction && ReportActionsUtils.isSplitBillAction(reportAction)) { // This covers group chats where the last action is a split bill action + const linkedTransaction = TransactionUtils.getLinkedTransaction(reportAction); if (isEmptyObject(linkedTransaction)) { return reportActionMessage; } @@ -2341,14 +2341,12 @@ function getReportPreviewMessage( }); } - if ( - !isEmptyObject(linkedTransaction) && - !isEmptyObject(reportAction) && - shouldConsiderScanningReceiptOrPendingRoute && - TransactionUtils.hasReceipt(linkedTransaction) && - TransactionUtils.isReceiptBeingScanned(linkedTransaction) && - ReportActionsUtils.isMoneyRequestAction(reportAction) - ) { + let linkedTransaction; + if (!isEmptyObject(reportAction) && shouldConsiderScanningReceiptOrPendingRoute && reportAction && ReportActionsUtils.isMoneyRequestAction(reportAction)) { + linkedTransaction = TransactionUtils.getLinkedTransaction(reportAction); + } + + if (!isEmptyObject(linkedTransaction) && TransactionUtils.hasReceipt(linkedTransaction) && TransactionUtils.isReceiptBeingScanned(linkedTransaction)) { return Localize.translateLocal('iou.receiptScanning'); } @@ -2385,7 +2383,6 @@ function getReportPreviewMessage( } const lastActorID = reportAction?.actorAccountID; - const comment = !isEmptyObject(linkedTransaction) ? TransactionUtils.getDescription(linkedTransaction) : undefined; let amount = originalMessage?.amount; let currency = originalMessage?.currency ? originalMessage?.currency : report.currency; @@ -2394,6 +2391,11 @@ function getReportPreviewMessage( currency = TransactionUtils.getCurrency(linkedTransaction); } + if (isEmptyObject(linkedTransaction) && !isEmptyObject(reportAction)) { + linkedTransaction = TransactionUtils.getLinkedTransaction(reportAction); + } + const comment = !isEmptyObject(linkedTransaction) ? TransactionUtils.getDescription(linkedTransaction) : undefined; + // if we have the amount in the originalMessage and lastActorID, we can use that to display the preview message for the latest request if (amount !== undefined && lastActorID && !isPreviewMessageForParentChatReport) { const amountToDisplay = CurrencyUtils.convertToDisplayString(Math.abs(amount), currency); From 579a227a7b8c369fdf376382d5e9066c0cd17745 Mon Sep 17 00:00:00 2001 From: tienifr Date: Mon, 26 Feb 2024 18:54:01 +0700 Subject: [PATCH 048/175] fix: telephoto camera on safari 17+ --- .../request/step/IOURequestStepScan/index.js | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/pages/iou/request/step/IOURequestStepScan/index.js b/src/pages/iou/request/step/IOURequestStepScan/index.js index 2f7ca1519144..09eb85348ef7 100644 --- a/src/pages/iou/request/step/IOURequestStepScan/index.js +++ b/src/pages/iou/request/step/IOURequestStepScan/index.js @@ -90,14 +90,24 @@ function IOURequestStepScan({ return; } - navigator.mediaDevices.getUserMedia({video: true}).then((stream) => { - _.forEach(stream.getTracks(), (videoStream) => videoStream.stop()); - + navigator.mediaDevices.getUserMedia({video: {facingMode: {exact: 'environment'}, zoom: {ideal: 1}}}).then((stream) => { + // Only Safari 17+ supports zoom constraint + if (Browser.isMobileSafari() && stream.getTracks().length > 0) { + const deviceId = _.chain(stream.getTracks()) + .map((track) => track.getSettings()) + .find((setting) => setting.zoom === 1) + .get('deviceId') + .value(); + if (deviceId) { + setVideoConstraints({deviceId}); + return; + } + } + _.forEach(stream.getTracks(), (track) => track.stop()); if (!navigator.mediaDevices.enumerateDevices) { setVideoConstraints({facingMode: {exact: 'environment'}}); return; } - navigator.mediaDevices.enumerateDevices().then((devices) => { const lastBackDeviceId = _.chain(devices) .filter((item) => item.kind === 'videoinput') From f011e58cac8812b6fd09c2c03a198c5f6ba0b32c Mon Sep 17 00:00:00 2001 From: Toby Sullivan Date: Tue, 27 Feb 2024 08:12:02 -0800 Subject: [PATCH 049/175] Hide description when last message is multi-request preview --- src/libs/OptionsListUtils.ts | 1 + src/libs/ReportUtils.ts | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/libs/OptionsListUtils.ts b/src/libs/OptionsListUtils.ts index 3d11795f5452..3e2f89f274a1 100644 --- a/src/libs/OptionsListUtils.ts +++ b/src/libs/OptionsListUtils.ts @@ -561,6 +561,7 @@ function getLastMessageTextForReport(report: OnyxEntry, lastActorDetails ReportUtils.isChatReport(report), null, true, + lastReportAction, ); } else if (ReportActionUtils.isReimbursementQueuedAction(lastReportAction)) { lastMessageTextFromReport = ReportUtils.getReimbursementQueuedActionMessage(lastReportAction, report); diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index be1fd977c145..e6775ef59bd3 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -2289,6 +2289,7 @@ function getReportPreviewMessage( isPreviewMessageForParentChatReport = false, policy: OnyxEntry = null, isForListPreview = false, + originalReportAction: OnyxEntry | EmptyObject = reportAction, ): string { const reportActionMessage = reportAction?.message?.[0].html ?? ''; @@ -2387,7 +2388,9 @@ function getReportPreviewMessage( if (isEmptyObject(linkedTransaction) && !isEmptyObject(reportAction)) { linkedTransaction = TransactionUtils.getLinkedTransaction(reportAction); } - const comment = !isEmptyObject(linkedTransaction) ? TransactionUtils.getDescription(linkedTransaction) : undefined; + const hideComment = + !isEmptyObject(originalReportAction) && ReportActionsUtils.isReportPreviewAction(originalReportAction) && ReportActionsUtils.getNumberOfMoneyRequests(originalReportAction) !== 1; + const comment = !isEmptyObject(linkedTransaction) && !hideComment ? TransactionUtils.getDescription(linkedTransaction) : undefined; // if we have the amount in the originalMessage and lastActorID, we can use that to display the preview message for the latest request if (amount !== undefined && lastActorID && !isPreviewMessageForParentChatReport) { From a818f52490e9b109c408c5d7349f987fcfc206a1 Mon Sep 17 00:00:00 2001 From: Toby Sullivan Date: Tue, 27 Feb 2024 09:51:03 -0800 Subject: [PATCH 050/175] Tidy up conditions for request descriptions --- src/libs/ReportUtils.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 9ecfd2e92beb..4dcbc60dd849 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -2395,9 +2395,11 @@ function getReportPreviewMessage( if (isEmptyObject(linkedTransaction) && !isEmptyObject(reportAction)) { linkedTransaction = TransactionUtils.getLinkedTransaction(reportAction); } - const hideComment = - !isEmptyObject(originalReportAction) && ReportActionsUtils.isReportPreviewAction(originalReportAction) && ReportActionsUtils.getNumberOfMoneyRequests(originalReportAction) !== 1; - const comment = !isEmptyObject(linkedTransaction) && !hideComment ? TransactionUtils.getDescription(linkedTransaction) : undefined; + + let comment = !isEmptyObject(linkedTransaction) ? TransactionUtils.getDescription(linkedTransaction) : undefined; + if (!isEmptyObject(originalReportAction) && ReportActionsUtils.isReportPreviewAction(originalReportAction) && ReportActionsUtils.getNumberOfMoneyRequests(originalReportAction) !== 1) { + comment = undefined; + } // if we have the amount in the originalMessage and lastActorID, we can use that to display the preview message for the latest request if (amount !== undefined && lastActorID && !isPreviewMessageForParentChatReport) { From f2d910b045b28d8d95a0e8e0dce3b8f3959f00ac Mon Sep 17 00:00:00 2001 From: Jayesh Mangwani Date: Wed, 28 Feb 2024 19:25:41 +0530 Subject: [PATCH 051/175] fix: updated IdologyQuestionsForm and AdditionalDetailStepForm values usage of the updated Form --- src/pages/EnablePayments/TermsStep.tsx | 2 -- src/types/form/AdditionalDetailStepForm.ts | 28 +++++++++++++--------- src/types/form/IdologyQuestionsForm.ts | 12 +++++++--- 3 files changed, 26 insertions(+), 16 deletions(-) diff --git a/src/pages/EnablePayments/TermsStep.tsx b/src/pages/EnablePayments/TermsStep.tsx index 7a4fc76d87c5..df9b14cffca4 100644 --- a/src/pages/EnablePayments/TermsStep.tsx +++ b/src/pages/EnablePayments/TermsStep.tsx @@ -7,8 +7,6 @@ import FormAlertWithSubmitButton from '@components/FormAlertWithSubmitButton'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import Text from '@components/Text'; import TextLink from '@components/TextLink'; - -import withLocalize, {withLocalizePropTypes} from '@components/withLocalize'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import * as ErrorUtils from '@libs/ErrorUtils'; diff --git a/src/types/form/AdditionalDetailStepForm.ts b/src/types/form/AdditionalDetailStepForm.ts index f102d03679ba..0d2c96487392 100644 --- a/src/types/form/AdditionalDetailStepForm.ts +++ b/src/types/form/AdditionalDetailStepForm.ts @@ -1,3 +1,4 @@ +import type {ValueOf} from 'type-fest'; import type Form from './Form'; const INPUT_IDS = { @@ -12,17 +13,22 @@ const INPUT_IDS = { SSN: 'ssn', } as const; -type AdditionalDetailStepForm = Form<{ - [INPUT_IDS.LEGAL_FIRST_NAME]: string; - [INPUT_IDS.LEGAL_LAST_NAME]: string; - [INPUT_IDS.PHONE_NUMBER]: string; - [INPUT_IDS.ADDRESS_STREET]: string; - [INPUT_IDS.ADDRESS_CITY]: string; - [INPUT_IDS.ADDRESS_ZIP_CODE]: string; - [INPUT_IDS.ADDRESS_STATE]: string; - [INPUT_IDS.DOB]: string; - [INPUT_IDS.SSN]: string; -}>; +type InputID = ValueOf; + +type AdditionalDetailStepForm = Form< + InputID, + { + [INPUT_IDS.LEGAL_FIRST_NAME]: string; + [INPUT_IDS.LEGAL_LAST_NAME]: string; + [INPUT_IDS.PHONE_NUMBER]: string; + [INPUT_IDS.ADDRESS_STREET]: string; + [INPUT_IDS.ADDRESS_CITY]: string; + [INPUT_IDS.ADDRESS_ZIP_CODE]: string; + [INPUT_IDS.ADDRESS_STATE]: string; + [INPUT_IDS.DOB]: string; + [INPUT_IDS.SSN]: string; + } +>; export type {AdditionalDetailStepForm}; export default INPUT_IDS; diff --git a/src/types/form/IdologyQuestionsForm.ts b/src/types/form/IdologyQuestionsForm.ts index 5b8d50c68abf..250e8c6f7766 100644 --- a/src/types/form/IdologyQuestionsForm.ts +++ b/src/types/form/IdologyQuestionsForm.ts @@ -1,12 +1,18 @@ +import type {ValueOf} from 'type-fest'; import type Form from './Form'; const INPUT_IDS = { ANSWER: 'answer', } as const; -type IdologyQuestionsForm = Form<{ - [INPUT_IDS.ANSWER]: string; -}>; +type InputID = ValueOf; + +type IdologyQuestionsForm = Form< + InputID, + { + [INPUT_IDS.ANSWER]: string; + } +>; export type {IdologyQuestionsForm}; export default INPUT_IDS; From 57370c83d1ea54e9a7f4753bcdd47f7fc42e58de Mon Sep 17 00:00:00 2001 From: Filip Solecki Date: Fri, 1 Mar 2024 10:10:16 +0100 Subject: [PATCH 052/175] Migrate web proxy to TS --- config/{proxyConfig.js => proxyConfig.ts} | 2 +- package.json | 2 +- web/{proxy.js => proxy.ts} | 22 +++++++++++++--------- 3 files changed, 15 insertions(+), 11 deletions(-) rename config/{proxyConfig.js => proxyConfig.ts} (92%) rename web/{proxy.js => proxy.ts} (78%) diff --git a/config/proxyConfig.js b/config/proxyConfig.ts similarity index 92% rename from config/proxyConfig.js rename to config/proxyConfig.ts index fa09c436461f..6a74d145df85 100644 --- a/config/proxyConfig.js +++ b/config/proxyConfig.ts @@ -3,7 +3,7 @@ * We only specify for staging URLs as API requests are sent to the production * servers by default. */ -module.exports = { +export default { STAGING: '/staging/', STAGING_SECURE: '/staging-secure/', }; diff --git a/package.json b/package.json index e3c23d4538d3..e757f000f5be 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ "ipad-sm": "concurrently \"npx react-native run-ios --simulator=\\\"iPad Pro (11-inch) (4th generation)\\\" --mode=\\\"DebugDevelopment\\\" --scheme=\\\"New Expensify Dev\\\"\"", "start": "npx react-native start", "web": "scripts/set-pusher-suffix.sh && concurrently npm:web-proxy npm:web-server", - "web-proxy": "ts-node web/proxy.js", + "web-proxy": "ts-node web/proxy.ts", "web-server": "webpack-dev-server --open --config config/webpack/webpack.dev.js", "build": "webpack --config config/webpack/webpack.common.js --env envFile=.env.production", "build-staging": "webpack --config config/webpack/webpack.common.js --env envFile=.env.staging", diff --git a/web/proxy.js b/web/proxy.ts similarity index 78% rename from web/proxy.js rename to web/proxy.ts index 0d82ae60b678..130f5a67e51a 100644 --- a/web/proxy.js +++ b/web/proxy.ts @@ -1,7 +1,10 @@ -const http = require('http'); -const https = require('https'); -const proxyConfig = require('../config/proxyConfig'); -require('dotenv').config(); +import dotenv from 'dotenv'; +import http from 'http'; +import type {IncomingMessage, ServerResponse} from 'http'; +import https from 'https'; +import proxyConfig from '../config/proxyConfig'; + +dotenv.config(); if (process.env.USE_WEB_PROXY === 'false') { process.stdout.write('Skipping proxy as USE_WEB_PROXY was set to false.\n'); @@ -20,7 +23,7 @@ console.log(`Creating proxy with host: ${host} for production API and ${stagingH * possible to work on the app within a limited development * environment that has no local API. */ -const server = http.createServer((request, response) => { +const server = http.createServer((request: IncomingMessage, response: ServerResponse) => { let hostname = host; let requestPath = request.url; @@ -37,10 +40,10 @@ const server = http.createServer((request, response) => { * /receipts/w_... => request sent to production server * /staging/chat-attachments/46545... => request sent to staging server */ - if (request.url.startsWith(proxyConfig.STAGING_SECURE)) { + if (request.url?.startsWith(proxyConfig.STAGING_SECURE)) { hostname = stagingSecureHost; requestPath = request.url.replace(proxyConfig.STAGING_SECURE, '/'); - } else if (request.url.startsWith(proxyConfig.STAGING)) { + } else if (request.url?.startsWith(proxyConfig.STAGING)) { hostname = stagingHost; requestPath = request.url.replace(proxyConfig.STAGING, '/'); } @@ -52,14 +55,15 @@ const server = http.createServer((request, response) => { headers: { ...request.headers, host: hostname, - 'user-agent': request.headers['user-agent'].concat(' Development-NewDot/1.0'), + // eslint-disable-next-line @typescript-eslint/naming-convention + 'user-agent': request.headers['user-agent']?.concat(' Development-NewDot/1.0'), }, port: 443, }); request.pipe(proxyRequest); proxyRequest.on('response', (proxyResponse) => { - response.writeHead(proxyResponse.statusCode, proxyResponse.headers); + response.writeHead(proxyResponse.statusCode ?? 0, proxyResponse.headers); proxyResponse.pipe(response); }); From 3c5b6a272a89cda8d9a17d50008f24a84b4ea91d Mon Sep 17 00:00:00 2001 From: Filip Solecki Date: Fri, 1 Mar 2024 10:22:24 +0100 Subject: [PATCH 053/175] Fix GH actions --- .github/actions/javascript/bumpVersion/index.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/actions/javascript/bumpVersion/index.js b/.github/actions/javascript/bumpVersion/index.js index d17760baa91f..8fe84446ba82 100644 --- a/.github/actions/javascript/bumpVersion/index.js +++ b/.github/actions/javascript/bumpVersion/index.js @@ -2657,12 +2657,17 @@ createToken('XRANGELOOSE', `^${src[t.GTLT]}\\s*${src[t.XRANGEPLAINLOOSE]}$`) // Coercion. // Extract anything that could conceivably be a part of a valid semver -createToken('COERCE', `${'(^|[^\\d])' + +createToken('COERCEPLAIN', `${'(^|[^\\d])' + '(\\d{1,'}${MAX_SAFE_COMPONENT_LENGTH}})` + `(?:\\.(\\d{1,${MAX_SAFE_COMPONENT_LENGTH}}))?` + - `(?:\\.(\\d{1,${MAX_SAFE_COMPONENT_LENGTH}}))?` + + `(?:\\.(\\d{1,${MAX_SAFE_COMPONENT_LENGTH}}))?`) +createToken('COERCE', `${src[t.COERCEPLAIN]}(?:$|[^\\d])`) +createToken('COERCEFULL', src[t.COERCEPLAIN] + + `(?:${src[t.PRERELEASE]})?` + + `(?:${src[t.BUILD]})?` + `(?:$|[^\\d])`) createToken('COERCERTL', src[t.COERCE], true) +createToken('COERCERTLFULL', src[t.COERCEFULL], true) // Tilde ranges. // Meaning is "reasonably at or greater than" From c19ccde1e07006228b2eb26752c03680e5580564 Mon Sep 17 00:00:00 2001 From: Filip Solecki Date: Fri, 1 Mar 2024 10:25:34 +0100 Subject: [PATCH 054/175] Revert unnecessary changes --- config/{proxyConfig.ts => proxyConfig.js} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename config/{proxyConfig.ts => proxyConfig.js} (92%) diff --git a/config/proxyConfig.ts b/config/proxyConfig.js similarity index 92% rename from config/proxyConfig.ts rename to config/proxyConfig.js index 6a74d145df85..fa09c436461f 100644 --- a/config/proxyConfig.ts +++ b/config/proxyConfig.js @@ -3,7 +3,7 @@ * We only specify for staging URLs as API requests are sent to the production * servers by default. */ -export default { +module.exports = { STAGING: '/staging/', STAGING_SECURE: '/staging-secure/', }; From 9eab6033922d3cade18acc4c1f827776f4c79871 Mon Sep 17 00:00:00 2001 From: Andrew Gable Date: Fri, 1 Mar 2024 11:39:47 -0700 Subject: [PATCH 055/175] Apply suggestions from code review Co-authored-by: Rory Abraham <47436092+roryabraham@users.noreply.github.com> Co-authored-by: Manan --- src/pages/LogOutPreviousUserPage.tsx | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/pages/LogOutPreviousUserPage.tsx b/src/pages/LogOutPreviousUserPage.tsx index a10988945c4e..522883c38881 100644 --- a/src/pages/LogOutPreviousUserPage.tsx +++ b/src/pages/LogOutPreviousUserPage.tsx @@ -29,11 +29,11 @@ type LogOutPreviousUserPageProps = LogOutPreviousUserPageOnyxProps & StackScreen // // This component should not do any other navigation as that handled in App.setUpPoliciesAndNavigate function LogOutPreviousUserPage({session, route, account}: LogOutPreviousUserPageProps) { - const initUrl = useContext(InitialUrlContext); + const initUrlFromOldApp = useContext(InitialUrlContext); useEffect(() => { Linking.getInitialURL().then((url) => { const sessionEmail = session?.email; - const transitionURL = NativeModules.HybridAppModule ? CONST.DEEPLINK_BASE_URL + initUrl : url; + const transitionURL = NativeModules.HybridAppModule ? `${CONST.DEEPLINK_BASE_URL}${initUrl}` : url; const isLoggingInAsNewUser = SessionUtils.isLoggingInAsNewUser(transitionURL ?? undefined, sessionEmail); if (isLoggingInAsNewUser) { @@ -71,7 +71,10 @@ function LogOutPreviousUserPage({session, route, account}: LogOutPreviousUserPag LogOutPreviousUserPage.displayName = 'LogOutPreviousUserPage'; export default withOnyx({ - account: {key: ONYXKEYS.ACCOUNT}, + isAccountLoading: { + key: ONYXKEYS.ACCOUNT, + selector: (account) => account?.isLoading, + }, session: { key: ONYXKEYS.SESSION, }, From ce048d53cf21d17eb4ae0ce7ca4031ef9f16e699 Mon Sep 17 00:00:00 2001 From: Jayesh Mangwani Date: Sat, 2 Mar 2024 12:06:35 +0530 Subject: [PATCH 056/175] revert the WALLET_ADDITIONAL_DETAILS key name --- src/ONYXKEYS.ts | 4 ++-- src/pages/EnablePayments/AdditionalDetailsStep.tsx | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index afcbd059a9f8..389c270f7510 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -399,8 +399,8 @@ const ONYXKEYS = { EXIT_SURVEY_RESPONSE_FORM_DRAFT: 'exitSurveyResponseFormDraft', IDOLOGY_QUESTIONS_FORM: 'idologyQuestionsForm', IDOLOGY_QUESTIONS_FORM_DRAFT: 'idologyQuestionsFormDraft', - WALLET_ADDITIONAL_DETAILS: 'walletAdditionalDetailsForm', - WALLET_ADDITIONAL_DETAILS_DRAFT: 'walletAdditionalDetailsFormDraft', + WALLET_ADDITIONAL_DETAILS: 'walletAdditionalDetails', + WALLET_ADDITIONAL_DETAILS_DRAFT: 'walletAdditionalDetailsDraft', }, } as const; diff --git a/src/pages/EnablePayments/AdditionalDetailsStep.tsx b/src/pages/EnablePayments/AdditionalDetailsStep.tsx index cdf166536c5f..0b663261865f 100644 --- a/src/pages/EnablePayments/AdditionalDetailsStep.tsx +++ b/src/pages/EnablePayments/AdditionalDetailsStep.tsx @@ -237,6 +237,7 @@ AdditionalDetailsStep.displayName = 'AdditionalDetailsStep'; export default withCurrentUserPersonalDetails( withOnyx({ + // @ts-expect-error: ONYXKEYS.WALLET_ADDITIONAL_DETAILS is conflicting with ONYXKEYS.FORMS.WALLET_ADDITIONAL_DETAILS walletAdditionalDetails: { key: ONYXKEYS.WALLET_ADDITIONAL_DETAILS, }, From 0f1fb25ffd036dc02b3e7aba1730a2ee46baeb44 Mon Sep 17 00:00:00 2001 From: Jayesh Mangwani Date: Mon, 4 Mar 2024 20:17:26 +0530 Subject: [PATCH 057/175] removed unused onyx/Form --- src/types/onyx/Form.ts | 140 ---------------------------------------- src/types/onyx/index.ts | 6 -- 2 files changed, 146 deletions(-) delete mode 100644 src/types/onyx/Form.ts diff --git a/src/types/onyx/Form.ts b/src/types/onyx/Form.ts deleted file mode 100644 index 3743468b39b0..000000000000 --- a/src/types/onyx/Form.ts +++ /dev/null @@ -1,140 +0,0 @@ -import type * as OnyxCommon from './OnyxCommon'; -import type PersonalBankAccount from './PersonalBankAccount'; - -type FormValueType = string | boolean | Date | OnyxCommon.Errors; - -type BaseForm = { - /** Controls the loading state of the form */ - isLoading?: boolean; - - /** Server side errors keyed by microtime */ - errors?: OnyxCommon.Errors | null; - - /** Field-specific server side errors keyed by microtime */ - errorFields?: OnyxCommon.ErrorFields | null; -}; - -type Form = Record> = TFormValues & BaseForm; - -type AddDebitCardForm = Form<{ - /** Whether the form has been submitted */ - setupComplete: boolean; -}>; - -type DateOfBirthForm = Form<{ - /** Date of birth */ - dob?: string; -}>; - -type DisplayNameForm = Form<{ - firstName: string; - lastName: string; -}>; - -type NewRoomForm = Form<{ - roomName?: string; - reportDescription?: string; - policyID?: string; - writeCapability?: string; - visibility?: string; -}>; - -type IKnowATeacherForm = Form<{ - firstName: string; - lastName: string; - partnerUserID: string; -}>; - -type IntroSchoolPrincipalForm = Form<{ - firstName: string; - lastName: string; - partnerUserID: string; -}>; - -type PrivateNotesForm = Form<{ - privateNotes: string; -}>; - -type GetPhysicalCardForm = Form<{ - /** Address line 1 for delivery */ - addressLine1?: string; - - /** Address line 2 for delivery */ - addressLine2?: string; - - /** City for delivery */ - city?: string; - - /** Country for delivery */ - country?: string; - - /** First name for delivery */ - legalFirstName?: string; - - /** Last name for delivery */ - legalLastName?: string; - - /** Phone number for delivery */ - phoneNumber?: string; - - /** State for delivery */ - state?: string; - - /** Zip code for delivery */ - zipPostCode?: string; -}>; - -type PersonalBankAccountForm = Form; - -type WorkspaceSettingsForm = Form<{ - name: string; -}>; - -type ReportFieldEditForm = Form>; - -type CloseAccountForm = Form<{ - reasonForLeaving: string; - phoneOrEmail: string; -}>; - -type IdologyQuestionsForm = Form<{ - answer: string; -}>; - -type AdditionalDetailStepForm = Form<{ - legalFirstName: string; - legalLastName: string; - addressStreet: string; - addressCity: string; - addressZipCode: string; - phoneNumber: string; - dob: string; - ssn: string; - addressState: string; -}>; - -type RoomNameForm = Form<{ - roomName: string; -}>; - -export default Form; - -export type { - AddDebitCardForm, - DateOfBirthForm, - PrivateNotesForm, - DisplayNameForm, - FormValueType, - GetPhysicalCardForm, - NewRoomForm, - BaseForm, - IKnowATeacherForm, - IntroSchoolPrincipalForm, - PersonalBankAccountForm, - WorkspaceSettingsForm, - ReportFieldEditForm, - CloseAccountForm, - IdologyQuestionsForm, - AdditionalDetailStepForm, - RoomNameForm, -}; diff --git a/src/types/onyx/index.ts b/src/types/onyx/index.ts index 277011602a17..6846fc302639 100644 --- a/src/types/onyx/index.ts +++ b/src/types/onyx/index.ts @@ -12,7 +12,6 @@ import type Currency from './Currency'; import type {CurrencyList} from './Currency'; import type CustomStatusDraft from './CustomStatusDraft'; import type Download from './Download'; -import type {AdditionalDetailStepForm, IdologyQuestionsForm, PrivateNotesForm, ReportFieldEditForm, RoomNameForm} from './Form'; import type FrequentlyUsedEmoji from './FrequentlyUsedEmoji'; import type {FundList} from './Fund'; import type Fund from './Fund'; @@ -154,10 +153,5 @@ export type { RecentlyUsedReportFields, LastPaymentMethod, InvitedEmailsToAccountIDs, - PrivateNotesForm, - ReportFieldEditForm, - IdologyQuestionsForm, - AdditionalDetailStepForm, - RoomNameForm, Log, }; From 8a2b943aa3ab57c38d487f7de31307dadd0b28ca Mon Sep 17 00:00:00 2001 From: Jayesh Mangwani Date: Mon, 4 Mar 2024 22:09:08 +0530 Subject: [PATCH 058/175] removed IdologyQuestionsForm instead used AdditionalDetailStepForm --- src/ONYXKEYS.ts | 3 --- src/libs/actions/Wallet.ts | 4 ++-- src/pages/EnablePayments/IdologyQuestions.tsx | 4 ++-- src/types/form/AdditionalDetailStepForm.ts | 2 ++ src/types/form/IdologyQuestionsForm.ts | 18 ------------------ src/types/form/index.ts | 1 - 6 files changed, 6 insertions(+), 26 deletions(-) delete mode 100644 src/types/form/IdologyQuestionsForm.ts diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index 389c270f7510..6834fcaa13ce 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -397,8 +397,6 @@ const ONYXKEYS = { EXIT_SURVEY_REASON_FORM_DRAFT: 'exitSurveyReasonFormDraft', EXIT_SURVEY_RESPONSE_FORM: 'exitSurveyResponseForm', EXIT_SURVEY_RESPONSE_FORM_DRAFT: 'exitSurveyResponseFormDraft', - IDOLOGY_QUESTIONS_FORM: 'idologyQuestionsForm', - IDOLOGY_QUESTIONS_FORM_DRAFT: 'idologyQuestionsFormDraft', WALLET_ADDITIONAL_DETAILS: 'walletAdditionalDetails', WALLET_ADDITIONAL_DETAILS_DRAFT: 'walletAdditionalDetailsDraft', }, @@ -446,7 +444,6 @@ type OnyxFormValuesMapping = { [ONYXKEYS.FORMS.PERSONAL_BANK_ACCOUNT]: FormTypes.PersonalBankAccountForm; [ONYXKEYS.FORMS.WORKSPACE_DESCRIPTION_FORM]: FormTypes.WorkspaceDescriptionForm; [ONYXKEYS.FORMS.WALLET_ADDITIONAL_DETAILS]: FormTypes.AdditionalDetailStepForm; - [ONYXKEYS.FORMS.IDOLOGY_QUESTIONS_FORM]: FormTypes.IdologyQuestionsForm; }; type OnyxFormDraftValuesMapping = { diff --git a/src/libs/actions/Wallet.ts b/src/libs/actions/Wallet.ts index ffc68c562c4c..9cb4b28bef20 100644 --- a/src/libs/actions/Wallet.ts +++ b/src/libs/actions/Wallet.ts @@ -233,7 +233,7 @@ function answerQuestionsForWallet(answers: WalletQuestionAnswer[], idNumber: str const optimisticData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, - key: ONYXKEYS.FORMS.IDOLOGY_QUESTIONS_FORM, + key: ONYXKEYS.FORMS.WALLET_ADDITIONAL_DETAILS, value: { isLoading: true, }, @@ -243,7 +243,7 @@ function answerQuestionsForWallet(answers: WalletQuestionAnswer[], idNumber: str const finallyData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, - key: ONYXKEYS.FORMS.IDOLOGY_QUESTIONS_FORM, + key: ONYXKEYS.FORMS.WALLET_ADDITIONAL_DETAILS, value: { isLoading: false, }, diff --git a/src/pages/EnablePayments/IdologyQuestions.tsx b/src/pages/EnablePayments/IdologyQuestions.tsx index 13c71f7005a9..6baea2158613 100644 --- a/src/pages/EnablePayments/IdologyQuestions.tsx +++ b/src/pages/EnablePayments/IdologyQuestions.tsx @@ -92,7 +92,7 @@ function IdologyQuestions({questions, idNumber}: IdologyQuestionsProps) { } }; - const validate = (values: FormOnyxValues): FormInputErrors => { + const validate = (values: FormOnyxValues): FormInputErrors => { const errors: Errors = {}; if (!values.answer) { errors.answer = translate('additionalDetailsStep.selectAnswer'); @@ -112,7 +112,7 @@ function IdologyQuestions({questions, idNumber}: IdologyQuestionsProps) { ; @@ -27,6 +28,7 @@ type AdditionalDetailStepForm = Form< [INPUT_IDS.ADDRESS_STATE]: string; [INPUT_IDS.DOB]: string; [INPUT_IDS.SSN]: string; + [INPUT_IDS.ANSWER]: string; } >; diff --git a/src/types/form/IdologyQuestionsForm.ts b/src/types/form/IdologyQuestionsForm.ts deleted file mode 100644 index 250e8c6f7766..000000000000 --- a/src/types/form/IdologyQuestionsForm.ts +++ /dev/null @@ -1,18 +0,0 @@ -import type {ValueOf} from 'type-fest'; -import type Form from './Form'; - -const INPUT_IDS = { - ANSWER: 'answer', -} as const; - -type InputID = ValueOf; - -type IdologyQuestionsForm = Form< - InputID, - { - [INPUT_IDS.ANSWER]: string; - } ->; - -export type {IdologyQuestionsForm}; -export default INPUT_IDS; diff --git a/src/types/form/index.ts b/src/types/form/index.ts index 498265848e37..0ab53ba9ec0e 100644 --- a/src/types/form/index.ts +++ b/src/types/form/index.ts @@ -38,5 +38,4 @@ export type {WorkspaceSettingsForm} from './WorkspaceSettingsForm'; export type {ReportPhysicalCardForm} from './ReportPhysicalCardForm'; export type {WorkspaceDescriptionForm} from './WorkspaceDescriptionForm'; export type {AdditionalDetailStepForm} from './AdditionalDetailStepForm'; -export type {IdologyQuestionsForm} from './IdologyQuestionsForm'; export type {default as Form} from './Form'; From e9140e1aafc1e0e9cb836c34294a7fdbcfa9b14d Mon Sep 17 00:00:00 2001 From: Jayesh Mangwani Date: Tue, 5 Mar 2024 22:02:32 +0530 Subject: [PATCH 059/175] updated setAdditionalDetailsQuestions prop to handle null and added missed addressZipCode INPUT_ID to STEP_FIELDS --- src/libs/actions/Wallet.ts | 3 +-- src/pages/EnablePayments/AdditionalDetailsStep.tsx | 3 ++- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libs/actions/Wallet.ts b/src/libs/actions/Wallet.ts index 9cb4b28bef20..097d9ee0419a 100644 --- a/src/libs/actions/Wallet.ts +++ b/src/libs/actions/Wallet.ts @@ -52,7 +52,7 @@ function openOnfidoFlow() { API.read(READ_COMMANDS.OPEN_ONFIDO_FLOW, {}, {optimisticData, finallyData}); } -function setAdditionalDetailsQuestions(questions: WalletAdditionalQuestionDetails[], idNumber: string) { +function setAdditionalDetailsQuestions(questions: WalletAdditionalQuestionDetails[] | null, idNumber?: string) { Onyx.merge(ONYXKEYS.WALLET_ADDITIONAL_DETAILS, {questions, idNumber}); } @@ -75,7 +75,6 @@ function setKYCWallSource(source?: ValueOf, chatRe /** * Validates a user's provided details against a series of checks */ - function updatePersonalDetails(personalDetails: UpdatePersonalDetailsForWalletParams) { const optimisticData: OnyxUpdate[] = [ { diff --git a/src/pages/EnablePayments/AdditionalDetailsStep.tsx b/src/pages/EnablePayments/AdditionalDetailsStep.tsx index 0b663261865f..57b9c7c6ade4 100644 --- a/src/pages/EnablePayments/AdditionalDetailsStep.tsx +++ b/src/pages/EnablePayments/AdditionalDetailsStep.tsx @@ -57,6 +57,7 @@ const STEP_FIELDS = [ INPUT_IDS.LEGAL_LAST_NAME, INPUT_IDS.ADDRESS_STREET, INPUT_IDS.ADDRESS_CITY, + INPUT_IDS.ADDRESS_ZIP_CODE, INPUT_IDS.PHONE_NUMBER, INPUT_IDS.DOB, INPUT_IDS.ADDRESS_STATE, @@ -132,7 +133,7 @@ function AdditionalDetailsStep({walletAdditionalDetails = DEFAULT_WALLET_ADDITIO > Wallet.setAdditionalDetailsQuestions([], walletAdditionalDetails?.idNumber ?? '')} + onBackButtonPress={() => Wallet.setAdditionalDetailsQuestions(null)} /> Date: Tue, 5 Mar 2024 14:11:05 -0500 Subject: [PATCH 060/175] Change API to new schema --- package-lock.json | 6 +++--- package.json | 2 +- src/libs/ApiUtils.ts | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 81e5b036a5be..c416a788e7c7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -52,7 +52,7 @@ "date-fns-tz": "^2.0.0", "dom-serializer": "^0.2.2", "domhandler": "^4.3.0", - "expensify-common": "git+ssh://git@github.com/Expensify/expensify-common.git#45d3b61bb38b4f9a19ddf573ce1e212369b242db", + "expensify-common": "git+ssh://git@github.com/Expensify/expensify-common.git#8dd750aee6a5403365007861cc6b6e6e1fddb8ff", "expo": "^50.0.3", "expo-av": "~13.10.4", "expo-image": "1.10.1", @@ -30751,8 +30751,8 @@ }, "node_modules/expensify-common": { "version": "1.0.0", - "resolved": "git+ssh://git@github.com/Expensify/expensify-common.git#45d3b61bb38b4f9a19ddf573ce1e212369b242db", - "integrity": "sha512-R1ykTwH3Pdp2sFqE6AL3ihmo4OjLMDEc8mEqQwD9W+yoIDIScT6Wi5ewO5vZUNsyCiKnD+xvNU7I1d9VNRJkXw==", + "resolved": "git+ssh://git@github.com/Expensify/expensify-common.git#8dd750aee6a5403365007861cc6b6e6e1fddb8ff", + "integrity": "sha512-hsP+sd3jc752y402gAoJbmk8eTkAIbWBhV2nXuAsRl86jt79qQvgkfDheG0TWmcYrO+7RApqkok0OfZJuyI5nA==", "license": "MIT", "dependencies": { "classnames": "2.5.0", diff --git a/package.json b/package.json index 47ea222bfb91..c028c884e243 100644 --- a/package.json +++ b/package.json @@ -101,7 +101,7 @@ "date-fns-tz": "^2.0.0", "dom-serializer": "^0.2.2", "domhandler": "^4.3.0", - "expensify-common": "git+ssh://git@github.com/Expensify/expensify-common.git#45d3b61bb38b4f9a19ddf573ce1e212369b242db", + "expensify-common": "git+ssh://git@github.com/Expensify/expensify-common.git#8dd750aee6a5403365007861cc6b6e6e1fddb8ff", "expo": "^50.0.3", "expo-av": "~13.10.4", "expo-image": "1.10.1", diff --git a/src/libs/ApiUtils.ts b/src/libs/ApiUtils.ts index 67feb18b36fa..78bcc000318c 100644 --- a/src/libs/ApiUtils.ts +++ b/src/libs/ApiUtils.ts @@ -52,7 +52,7 @@ function getApiRoot(request?: Request): string { * @param - the name of the API command */ function getCommandURL(request: Request): string { - return `${getApiRoot(request)}api?command=${request.command}`; + return `${getApiRoot(request)}api/${request.command}?`; } /** From 01ca51592899313913c58ad31e5fa072615b0083 Mon Sep 17 00:00:00 2001 From: Jayesh Mangwani Date: Wed, 6 Mar 2024 21:54:40 +0530 Subject: [PATCH 061/175] deleted unused walletTermsPropTypes --- .../EnablePayments/walletTermsPropTypes.js | 18 ------------------ 1 file changed, 18 deletions(-) delete mode 100644 src/pages/EnablePayments/walletTermsPropTypes.js diff --git a/src/pages/EnablePayments/walletTermsPropTypes.js b/src/pages/EnablePayments/walletTermsPropTypes.js deleted file mode 100644 index 4420a2dd0861..000000000000 --- a/src/pages/EnablePayments/walletTermsPropTypes.js +++ /dev/null @@ -1,18 +0,0 @@ -import PropTypes from 'prop-types'; -import _ from 'underscore'; -import CONST from '@src/CONST'; - -/** Prop types related to the Terms step of KYC flow */ -export default PropTypes.shape({ - /** Any error message to show */ - errors: PropTypes.objectOf(PropTypes.string), - - /** The source that triggered the KYC wall */ - source: PropTypes.oneOf(_.values(CONST.KYC_WALL_SOURCE)), - - /** When the user accepts the Wallet's terms in order to pay an IOU, this is the ID of the chatReport the IOU is linked to */ - chatReportID: PropTypes.string, - - /** Boolean to indicate whether the submission of wallet terms is being processed */ - isLoading: PropTypes.bool, -}); From 89418e8070cbcd569de4a039148fba593efd369a Mon Sep 17 00:00:00 2001 From: Toby Sullivan Date: Wed, 6 Mar 2024 13:33:17 -0800 Subject: [PATCH 062/175] Add and update comments for report action params --- src/libs/ReportUtils.ts | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 350a08b43821..1508f5362406 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -2331,18 +2331,21 @@ function getTransactionReportName(reportAction: OnyxEntry | EmptyObject, - reportAction: OnyxEntry | EmptyObject = {}, + iouReportAction: OnyxEntry | EmptyObject = {}, shouldConsiderScanningReceiptOrPendingRoute = false, isPreviewMessageForParentChatReport = false, policy: OnyxEntry = null, isForListPreview = false, - originalReportAction: OnyxEntry | EmptyObject = reportAction, + originalReportAction: OnyxEntry | EmptyObject = iouReportAction, ): string { - const reportActionMessage = reportAction?.message?.[0].html ?? ''; + const reportActionMessage = iouReportAction?.message?.[0].html ?? ''; if (isEmptyObject(report) || !report?.reportID) { // The iouReport is not found locally after SignIn because the OpenApp API won't return iouReports if they're settled @@ -2350,9 +2353,9 @@ function getReportPreviewMessage( return reportActionMessage; } - if (!isEmptyObject(reportAction) && !isIOUReport(report) && reportAction && ReportActionsUtils.isSplitBillAction(reportAction)) { + if (!isEmptyObject(iouReportAction) && !isIOUReport(report) && iouReportAction && ReportActionsUtils.isSplitBillAction(iouReportAction)) { // This covers group chats where the last action is a split bill action - const linkedTransaction = TransactionUtils.getLinkedTransaction(reportAction); + const linkedTransaction = TransactionUtils.getLinkedTransaction(iouReportAction); if (isEmptyObject(linkedTransaction)) { return reportActionMessage; } @@ -2387,8 +2390,8 @@ function getReportPreviewMessage( } let linkedTransaction; - if (!isEmptyObject(reportAction) && shouldConsiderScanningReceiptOrPendingRoute && reportAction && ReportActionsUtils.isMoneyRequestAction(reportAction)) { - linkedTransaction = TransactionUtils.getLinkedTransaction(reportAction); + if (!isEmptyObject(iouReportAction) && shouldConsiderScanningReceiptOrPendingRoute && iouReportAction && ReportActionsUtils.isMoneyRequestAction(iouReportAction)) { + linkedTransaction = TransactionUtils.getLinkedTransaction(iouReportAction); } if (!isEmptyObject(linkedTransaction) && TransactionUtils.hasReceipt(linkedTransaction) && TransactionUtils.isReceiptBeingScanned(linkedTransaction)) { @@ -2399,7 +2402,7 @@ function getReportPreviewMessage( return Localize.translateLocal('iou.routePending'); } - const originalMessage = reportAction?.originalMessage as IOUMessage | undefined; + const originalMessage = iouReportAction?.originalMessage as IOUMessage | undefined; // Show Paid preview message if it's settled or if the amount is paid & stuck at receivers end for only chat reports. if (isSettled(report.reportID) || (report.isWaitingOnBankAccount && isPreviewMessageForParentChatReport)) { @@ -2427,7 +2430,7 @@ function getReportPreviewMessage( return Localize.translateLocal('iou.waitingOnBankAccount', {submitterDisplayName}); } - const lastActorID = reportAction?.actorAccountID; + const lastActorID = iouReportAction?.actorAccountID; let amount = originalMessage?.amount; let currency = originalMessage?.currency ? originalMessage?.currency : report.currency; @@ -2436,8 +2439,8 @@ function getReportPreviewMessage( currency = TransactionUtils.getCurrency(linkedTransaction); } - if (isEmptyObject(linkedTransaction) && !isEmptyObject(reportAction)) { - linkedTransaction = TransactionUtils.getLinkedTransaction(reportAction); + if (isEmptyObject(linkedTransaction) && !isEmptyObject(iouReportAction)) { + linkedTransaction = TransactionUtils.getLinkedTransaction(iouReportAction); } let comment = !isEmptyObject(linkedTransaction) ? TransactionUtils.getDescription(linkedTransaction) : undefined; From 7ccda640391a63472ec31bc2903a56348645bad7 Mon Sep 17 00:00:00 2001 From: John Lee Date: Fri, 8 Mar 2024 12:43:46 -0500 Subject: [PATCH 063/175] Include credentials on fetch --- package-lock.json | 6 +++--- package.json | 2 +- src/libs/HttpUtils.ts | 4 +++- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index c416a788e7c7..88ec40988483 100644 --- a/package-lock.json +++ b/package-lock.json @@ -52,7 +52,7 @@ "date-fns-tz": "^2.0.0", "dom-serializer": "^0.2.2", "domhandler": "^4.3.0", - "expensify-common": "git+ssh://git@github.com/Expensify/expensify-common.git#8dd750aee6a5403365007861cc6b6e6e1fddb8ff", + "expensify-common": "github:Expensify/expensify-common#eb11f2543f0ca9fb55723a479ef12aabf904f0a8", "expo": "^50.0.3", "expo-av": "~13.10.4", "expo-image": "1.10.1", @@ -30751,8 +30751,8 @@ }, "node_modules/expensify-common": { "version": "1.0.0", - "resolved": "git+ssh://git@github.com/Expensify/expensify-common.git#8dd750aee6a5403365007861cc6b6e6e1fddb8ff", - "integrity": "sha512-hsP+sd3jc752y402gAoJbmk8eTkAIbWBhV2nXuAsRl86jt79qQvgkfDheG0TWmcYrO+7RApqkok0OfZJuyI5nA==", + "resolved": "git+ssh://git@github.com/Expensify/expensify-common.git#eb11f2543f0ca9fb55723a479ef12aabf904f0a8", + "integrity": "sha512-VVRY+LLC4/olVkOgKtU1fcdPJwPa5qSTZxXr49bBlBw+OWKg4DmDFxocHHyWWp8nfRmKkqPGwma7GF3D/Ofebg==", "license": "MIT", "dependencies": { "classnames": "2.5.0", diff --git a/package.json b/package.json index c028c884e243..7dfffe141130 100644 --- a/package.json +++ b/package.json @@ -101,7 +101,7 @@ "date-fns-tz": "^2.0.0", "dom-serializer": "^0.2.2", "domhandler": "^4.3.0", - "expensify-common": "git+ssh://git@github.com/Expensify/expensify-common.git#8dd750aee6a5403365007861cc6b6e6e1fddb8ff", + "expensify-common": "github:Expensify/expensify-common#eb11f2543f0ca9fb55723a479ef12aabf904f0a8", "expo": "^50.0.3", "expo-av": "~13.10.4", "expo-image": "1.10.1", diff --git a/src/libs/HttpUtils.ts b/src/libs/HttpUtils.ts index f52fefe02386..9c350ab05d81 100644 --- a/src/libs/HttpUtils.ts +++ b/src/libs/HttpUtils.ts @@ -39,7 +39,7 @@ const addSkewList: string[] = [SIDE_EFFECT_REQUEST_COMMANDS.OPEN_REPORT, SIDE_EF /** * Regex to get API command from the command */ -const APICommandRegex = /[?&]command=([^&]+)/; +const APICommandRegex = /\/api\/([^&?]+)\??.*/; /** * Send an HTTP request, and attempt to resolve the json response. @@ -52,6 +52,8 @@ function processHTTPRequest(url: string, method: RequestType = 'get', body: Form signal: canCancel ? cancellationController.signal : undefined, method, body, + // We want to include the cookie accountID that is returned form the API + credentials: 'include', }) .then((response) => { // We are calculating the skew to minimize the delay when posting the messages From 87f28e2a6a43b26c58c656b04de4873943bbc394 Mon Sep 17 00:00:00 2001 From: John Lee Date: Fri, 8 Mar 2024 12:48:29 -0500 Subject: [PATCH 064/175] Update packagE --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7dfffe141130..e437f5c5526d 100644 --- a/package.json +++ b/package.json @@ -101,7 +101,7 @@ "date-fns-tz": "^2.0.0", "dom-serializer": "^0.2.2", "domhandler": "^4.3.0", - "expensify-common": "github:Expensify/expensify-common#eb11f2543f0ca9fb55723a479ef12aabf904f0a8", + "expensify-common": "github:Expensify/expensify-common#7ce83cd75c7893dbea4b1517ff04b9589144eafe", "expo": "^50.0.3", "expo-av": "~13.10.4", "expo-image": "1.10.1", From 904316b9036ad3c7b87ae371d59354094af4a39a Mon Sep 17 00:00:00 2001 From: Krishna Gupta Date: Sat, 9 Mar 2024 12:55:58 +0530 Subject: [PATCH 065/175] fix: Room - Side panel does not close when clicking outside of panel. Signed-off-by: Krishna Gupta --- src/components/Modal/BaseModal.tsx | 4 ++++ src/components/Modal/types.ts | 3 +++ src/components/ValuePicker/ValueSelectorModal.tsx | 3 ++- src/components/ValuePicker/index.tsx | 2 ++ src/components/ValuePicker/types.ts | 3 +++ 5 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/components/Modal/BaseModal.tsx b/src/components/Modal/BaseModal.tsx index 2b8d25d5d639..514bcc421e09 100644 --- a/src/components/Modal/BaseModal.tsx +++ b/src/components/Modal/BaseModal.tsx @@ -41,6 +41,7 @@ function BaseModal( avoidKeyboard = false, children, shouldUseCustomBackdrop = false, + onBackdropPress, }: BaseModalProps, ref: React.ForwardedRef, ) { @@ -117,6 +118,9 @@ function BaseModal( return; } + if (onBackdropPress) { + onBackdropPress(); + } onClose(); }; diff --git a/src/components/Modal/types.ts b/src/components/Modal/types.ts index a0cdb737d448..cfa4a28c4d87 100644 --- a/src/components/Modal/types.ts +++ b/src/components/Modal/types.ts @@ -23,6 +23,9 @@ type BaseModalProps = Partial & { /** Callback method fired when the user requests to close the modal */ onClose: () => void; + /** Function to call when the user presses on the modal backdrop */ + onBackdropPress?: () => void; + /** State that determines whether to display the modal or not */ isVisible: boolean; diff --git a/src/components/ValuePicker/ValueSelectorModal.tsx b/src/components/ValuePicker/ValueSelectorModal.tsx index fad59d4e48e4..2891a452a0ea 100644 --- a/src/components/ValuePicker/ValueSelectorModal.tsx +++ b/src/components/ValuePicker/ValueSelectorModal.tsx @@ -8,7 +8,7 @@ import useThemeStyles from '@hooks/useThemeStyles'; import CONST from '@src/CONST'; import type {ValueSelectorModalProps} from './types'; -function ValueSelectorModal({items = [], selectedItem, label = '', isVisible, onClose, onItemSelected, shouldShowTooltips = true}: ValueSelectorModalProps) { +function ValueSelectorModal({items = [], selectedItem, label = '', isVisible, onClose, onItemSelected, shouldShowTooltips = true, onBackdropPress}: ValueSelectorModalProps) { const styles = useThemeStyles(); const sections = useMemo( @@ -24,6 +24,7 @@ function ValueSelectorModal({items = [], selectedItem, label = '', isVisible, on onModalHide={onClose} hideModalContentWhileAnimating useNativeDriver + onBackdropPress={onBackdropPress} > ); diff --git a/src/components/ValuePicker/types.ts b/src/components/ValuePicker/types.ts index c7df88bc7417..8e42f80097ac 100644 --- a/src/components/ValuePicker/types.ts +++ b/src/components/ValuePicker/types.ts @@ -30,6 +30,9 @@ type ValueSelectorModalProps = { /** Function to call when the user closes the modal */ onClose?: () => void; + /** Function to call when the user presses on the modal backdrop */ + onBackdropPress?: () => void; + /** Whether to show the toolip text */ shouldShowTooltips?: boolean; }; From f692d394f14d5ff3766e2d61a8693785a2835d7d Mon Sep 17 00:00:00 2001 From: Abdelrahman Khattab Date: Mon, 11 Mar 2024 04:02:10 +0200 Subject: [PATCH 066/175] Fix: Unable to save manually entered address after selecting address from list --- src/pages/iou/request/step/IOURequestStepWaypoint.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/iou/request/step/IOURequestStepWaypoint.tsx b/src/pages/iou/request/step/IOURequestStepWaypoint.tsx index 5a68c85546e6..c8232b9cdb7b 100644 --- a/src/pages/iou/request/step/IOURequestStepWaypoint.tsx +++ b/src/pages/iou/request/step/IOURequestStepWaypoint.tsx @@ -125,7 +125,7 @@ function IOURequestStepWaypoint({ if (isOffline && waypointValue) { const waypoint = { address: waypointValue, - name: values.name, + name: values.name ?? '', }; saveWaypoint(waypoint); } From 7ec68d59821269b3d4957de50f13f51dbe6c017e Mon Sep 17 00:00:00 2001 From: Jayesh Mangwani Date: Mon, 11 Mar 2024 21:39:08 +0530 Subject: [PATCH 067/175] fixed restricted-imports for ScrollView --- src/pages/EnablePayments/OnfidoPrivacy.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pages/EnablePayments/OnfidoPrivacy.tsx b/src/pages/EnablePayments/OnfidoPrivacy.tsx index 99117e3f1e99..cf6e6837df16 100644 --- a/src/pages/EnablePayments/OnfidoPrivacy.tsx +++ b/src/pages/EnablePayments/OnfidoPrivacy.tsx @@ -1,5 +1,6 @@ import React, {useRef} from 'react'; import {View} from 'react-native'; +// eslint-disable-next-line no-restricted-imports import type {ScrollView} from 'react-native'; import {withOnyx} from 'react-native-onyx'; import type {OnyxEntry} from 'react-native-onyx'; From b69454519c8c89ae718a71493d63f172f6d6e44e Mon Sep 17 00:00:00 2001 From: Michal Muzyk Date: Mon, 11 Mar 2024 17:15:14 +0100 Subject: [PATCH 068/175] feat: policy distance rates settings --- src/CONST.ts | 4 + src/ROUTES.ts | 4 + src/SCREENS.ts | 1 + src/languages/en.ts | 8 ++ src/languages/es.ts | 8 ++ ...olicyDistanceRatesDefaultCategoryParams.ts | 6 + .../SetPolicyDistanceRatesUnitParams.ts | 6 + src/libs/API/parameters/index.ts | 2 + src/libs/API/types.ts | 4 + .../AppNavigator/ModalStackNavigators.tsx | 1 + .../CENTRAL_PANE_TO_RHP_MAPPING.ts | 2 +- src/libs/Navigation/linkingConfig/config.ts | 3 + src/libs/Navigation/types.ts | 3 + src/libs/actions/Policy.ts | 122 ++++++++++++++++++ .../CategorySelectorModal.tsx | 82 ++++++++++++ .../distanceRates/CategorySelector/index.tsx | 73 +++++++++++ .../distanceRates/CategorySelector/types.ts | 8 ++ .../distanceRates/PolicyDistanceRatesPage.tsx | 2 +- .../PolicyDistanceRatesSettingsPage.tsx | 80 ++++++++++++ .../UnitSelector/UnitSelectorModal.tsx | 80 ++++++++++++ .../distanceRates/UnitSelector/index.tsx | 69 ++++++++++ .../distanceRates/UnitSelector/types.ts | 13 ++ 22 files changed, 579 insertions(+), 2 deletions(-) create mode 100644 src/libs/API/parameters/SetPolicyDistanceRatesDefaultCategoryParams.ts create mode 100644 src/libs/API/parameters/SetPolicyDistanceRatesUnitParams.ts create mode 100644 src/pages/workspace/distanceRates/CategorySelector/CategorySelectorModal.tsx create mode 100644 src/pages/workspace/distanceRates/CategorySelector/index.tsx create mode 100644 src/pages/workspace/distanceRates/CategorySelector/types.ts create mode 100644 src/pages/workspace/distanceRates/PolicyDistanceRatesSettingsPage.tsx create mode 100644 src/pages/workspace/distanceRates/UnitSelector/UnitSelectorModal.tsx create mode 100644 src/pages/workspace/distanceRates/UnitSelector/index.tsx create mode 100644 src/pages/workspace/distanceRates/UnitSelector/types.ts diff --git a/src/CONST.ts b/src/CONST.ts index ce2029c78713..0b1dcd7ec250 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -1416,6 +1416,10 @@ const CONST = { DISABLE: 'disable', ENABLE: 'enable', }, + UNITS: { + MI: 'Miles', + KM: 'Kilometers', + }, }, CUSTOM_UNITS: { diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 87be6247c27c..5ffb2f13d27e 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -581,6 +581,10 @@ const ROUTES = { route: 'workspace/:policyID/distance-rates/new', getRoute: (policyID: string) => `workspace/${policyID}/distance-rates/new` as const, }, + WORKSPACE_DISTANCE_RATES_SETTINGS: { + route: 'workspace/:policyID/distance-rates/settings', + getRoute: (policyID: string) => `workspace/${policyID}/distance-rates/settings` as const, + }, // Referral program promotion REFERRAL_DETAILS_MODAL: { diff --git a/src/SCREENS.ts b/src/SCREENS.ts index 387d874efcf8..b3860b7a0e89 100644 --- a/src/SCREENS.ts +++ b/src/SCREENS.ts @@ -231,6 +231,7 @@ const SCREENS = { MEMBER_DETAILS_ROLE_SELECTION: 'Workspace_Member_Details_Role_Selection', DISTANCE_RATES: 'Distance_Rates', CREATE_DISTANCE_RATE: 'Create_Distance_Rate', + DISTANCE_RATES_SETTINGS: 'Distance_Rates_Settings', }, EDIT_REQUEST: { diff --git a/src/languages/en.ts b/src/languages/en.ts index be2d0dc569fd..722e3d708024 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -1927,8 +1927,16 @@ export default { status: 'Status', enabled: 'Enabled', disabled: 'Disabled', + unit: 'Unit', + defaultCategory: 'Default category', errors: { createRateGenericFailureMessage: 'An error occurred while creating the distance rate, please try again.', + updateRateUnitGenericFailureMessage: 'An error occurred while updating the distance rate unit, please try again.', + updateRateDefaultCategoryGenericFailureMessage: 'An error occurred while updating the distance rate default category, please try again.', + }, + units: { + MI: 'Miles', + KM: 'Kilometers', }, }, editor: { diff --git a/src/languages/es.ts b/src/languages/es.ts index b85071197298..be71730f1cc4 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -1952,8 +1952,16 @@ export default { status: 'Estado', enabled: 'Activada', disabled: 'Desactivada', + unit: 'Unit', + defaultCategory: 'Default category', errors: { createRateGenericFailureMessage: 'An error occurred while creating the distance rate, please try again.', + updateRateUnitGenericFailureMessage: 'An error occurred while updating the distance rate unit, please try again.', + updateRateDefaultCategoryGenericFailureMessage: 'An error occurred while updating the distance rate default category, please try again.', + }, + units: { + MI: 'Millas', + KM: 'Kilómetros', }, }, editor: { diff --git a/src/libs/API/parameters/SetPolicyDistanceRatesDefaultCategoryParams.ts b/src/libs/API/parameters/SetPolicyDistanceRatesDefaultCategoryParams.ts new file mode 100644 index 000000000000..d2d11993a172 --- /dev/null +++ b/src/libs/API/parameters/SetPolicyDistanceRatesDefaultCategoryParams.ts @@ -0,0 +1,6 @@ +type SetPolicyDistanceRatesDefaultCategoryParams = { + policyID: string; + customUnit: string; +}; + +export default SetPolicyDistanceRatesDefaultCategoryParams; diff --git a/src/libs/API/parameters/SetPolicyDistanceRatesUnitParams.ts b/src/libs/API/parameters/SetPolicyDistanceRatesUnitParams.ts new file mode 100644 index 000000000000..c841f480d1bf --- /dev/null +++ b/src/libs/API/parameters/SetPolicyDistanceRatesUnitParams.ts @@ -0,0 +1,6 @@ +type SetPolicyDistanceRatesUnitParams = { + policyID: string; + customUnit: string; +}; + +export default SetPolicyDistanceRatesUnitParams; diff --git a/src/libs/API/parameters/index.ts b/src/libs/API/parameters/index.ts index 85f3d9d87f57..717d33eee8ee 100644 --- a/src/libs/API/parameters/index.ts +++ b/src/libs/API/parameters/index.ts @@ -161,3 +161,5 @@ export type {default as DeclineJoinRequestParams} from './DeclineJoinRequest'; export type {default as JoinPolicyInviteLinkParams} from './JoinPolicyInviteLink'; export type {default as OpenPolicyDistanceRatesPageParams} from './OpenPolicyDistanceRatesPageParams'; export type {default as CreatePolicyDistanceRateParams} from './CreatePolicyDistanceRateParams'; +export type {default as SetPolicyDistanceRatesUnitParams} from './SetPolicyDistanceRatesUnitParams'; +export type {default as SetPolicyDistanceRatesDefaultCategoryParams} from './SetPolicyDistanceRatesDefaultCategoryParams'; diff --git a/src/libs/API/types.ts b/src/libs/API/types.ts index 51cf2721878b..be2d8b450425 100644 --- a/src/libs/API/types.ts +++ b/src/libs/API/types.ts @@ -161,6 +161,8 @@ const WRITE_COMMANDS = { ACCEPT_JOIN_REQUEST: 'AcceptJoinRequest', DECLINE_JOIN_REQUEST: 'DeclineJoinRequest', CREATE_POLICY_DISTANCE_RATE: 'CreatePolicyDistanceRate', + SET_POLICY_DISTANCE_RATES_UNIT: 'SetPolicyDistanceRatesUnit', + SET_POLICY_DISTANCE_RATES_DEFAULT_CATEGORY: 'SetPolicyDistanceRatesDefaultCategory', } as const; type WriteCommand = ValueOf; @@ -320,6 +322,8 @@ type WriteCommandParameters = { [WRITE_COMMANDS.ACCEPT_JOIN_REQUEST]: Parameters.AcceptJoinRequestParams; [WRITE_COMMANDS.DECLINE_JOIN_REQUEST]: Parameters.DeclineJoinRequestParams; [WRITE_COMMANDS.CREATE_POLICY_DISTANCE_RATE]: Parameters.CreatePolicyDistanceRateParams; + [WRITE_COMMANDS.SET_POLICY_DISTANCE_RATES_UNIT]: Parameters.SetPolicyDistanceRatesUnitParams; + [WRITE_COMMANDS.SET_POLICY_DISTANCE_RATES_DEFAULT_CATEGORY]: Parameters.SetPolicyDistanceRatesDefaultCategoryParams; }; const READ_COMMANDS = { diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx index 7786e16e00ef..da51fa4d3433 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx @@ -255,6 +255,7 @@ const SettingsModalStackNavigator = createModalStackNavigator require('../../../pages/workspace/members/WorkspaceMemberDetailsRoleSelectionPage').default as React.ComponentType, [SCREENS.WORKSPACE.CATEGORY_CREATE]: () => require('../../../pages/workspace/categories/CreateCategoryPage').default as React.ComponentType, [SCREENS.WORKSPACE.CREATE_DISTANCE_RATE]: () => require('../../../pages/workspace/distanceRates/PolicyNewDistanceRatePage').default as React.ComponentType, + [SCREENS.WORKSPACE.DISTANCE_RATES_SETTINGS]: () => require('../../../pages/workspace/distanceRates/PolicyDistanceRatesSettingsPage').default as React.ComponentType, [SCREENS.REIMBURSEMENT_ACCOUNT]: () => require('../../../pages/ReimbursementAccount/ReimbursementAccountPage').default as React.ComponentType, [SCREENS.GET_ASSISTANCE]: () => require('../../../pages/GetAssistancePage').default as React.ComponentType, [SCREENS.SETTINGS.TWO_FACTOR_AUTH]: () => require('../../../pages/settings/Security/TwoFactorAuth/TwoFactorAuthPage').default as React.ComponentType, diff --git a/src/libs/Navigation/linkingConfig/CENTRAL_PANE_TO_RHP_MAPPING.ts b/src/libs/Navigation/linkingConfig/CENTRAL_PANE_TO_RHP_MAPPING.ts index 8c5a32182e99..954b2b5b7cef 100755 --- a/src/libs/Navigation/linkingConfig/CENTRAL_PANE_TO_RHP_MAPPING.ts +++ b/src/libs/Navigation/linkingConfig/CENTRAL_PANE_TO_RHP_MAPPING.ts @@ -7,7 +7,7 @@ const CENTRAL_PANE_TO_RHP_MAPPING: Partial> = [SCREENS.WORKSPACE.MEMBERS]: [SCREENS.WORKSPACE.INVITE, SCREENS.WORKSPACE.INVITE_MESSAGE, SCREENS.WORKSPACE.MEMBER_DETAILS, SCREENS.WORKSPACE.MEMBER_DETAILS_ROLE_SELECTION], [SCREENS.WORKSPACE.WORKFLOWS]: [SCREENS.WORKSPACE.WORKFLOWS_APPROVER, SCREENS.WORKSPACE.WORKFLOWS_AUTO_REPORTING_FREQUENCY, SCREENS.WORKSPACE.WORKFLOWS_AUTO_REPORTING_MONTHLY_OFFSET], [SCREENS.WORKSPACE.CATEGORIES]: [SCREENS.WORKSPACE.CATEGORY_CREATE, SCREENS.WORKSPACE.CATEGORY_SETTINGS, SCREENS.WORKSPACE.CATEGORIES_SETTINGS], - [SCREENS.WORKSPACE.DISTANCE_RATES]: [SCREENS.WORKSPACE.CREATE_DISTANCE_RATE], + [SCREENS.WORKSPACE.DISTANCE_RATES]: [SCREENS.WORKSPACE.CREATE_DISTANCE_RATE, SCREENS.WORKSPACE.DISTANCE_RATES_SETTINGS], }; export default CENTRAL_PANE_TO_RHP_MAPPING; diff --git a/src/libs/Navigation/linkingConfig/config.ts b/src/libs/Navigation/linkingConfig/config.ts index cc337c3b603f..7ada76628c82 100644 --- a/src/libs/Navigation/linkingConfig/config.ts +++ b/src/libs/Navigation/linkingConfig/config.ts @@ -297,6 +297,9 @@ const config: LinkingOptions['config'] = { [SCREENS.WORKSPACE.CREATE_DISTANCE_RATE]: { path: ROUTES.WORKSPACE_CREATE_DISTANCE_RATE.route, }, + [SCREENS.WORKSPACE.DISTANCE_RATES_SETTINGS]: { + path: ROUTES.WORKSPACE_DISTANCE_RATES_SETTINGS.route, + }, [SCREENS.REIMBURSEMENT_ACCOUNT]: { path: ROUTES.BANK_ACCOUNT_WITH_STEP_TO_OPEN.route, exact: true, diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index fc7ebc8f1b72..5ad59483bf38 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -224,6 +224,9 @@ type SettingsNavigatorParamList = { [SCREENS.WORKSPACE.CREATE_DISTANCE_RATE]: { policyID: string; }; + [SCREENS.WORKSPACE.DISTANCE_RATES_SETTINGS]: { + policyID: string; + }; [SCREENS.GET_ASSISTANCE]: { backTo: Routes; }; diff --git a/src/libs/actions/Policy.ts b/src/libs/actions/Policy.ts index e6fcbe9e1ba9..1311e2867a21 100644 --- a/src/libs/actions/Policy.ts +++ b/src/libs/actions/Policy.ts @@ -23,6 +23,8 @@ import type { OpenWorkspaceMembersPageParams, OpenWorkspaceParams, OpenWorkspaceReimburseViewParams, + SetPolicyDistanceRatesDefaultCategoryParams, + SetPolicyDistanceRatesUnitParams, SetWorkspaceApprovalModeParams, SetWorkspaceAutoReportingFrequencyParams, SetWorkspaceAutoReportingMonthlyOffsetParams, @@ -2858,6 +2860,124 @@ function clearCreateDistanceRateError(policyID: string, currentRates: Record; + + /** Whether the modal is visible */ + isVisible: boolean; + + /** Selected category */ + currentCategory: string; + + /** Function to call when the user selects a category */ + onCategorySelected: (value: CategoryItemType) => void; + + /** Function to call when the user closes the category selector modal */ + onClose: () => void; + + /** Label to display on field */ + label: string; +}; + +function CategorySelectorModal({policyCategories, isVisible, currentCategory, onCategorySelected, onClose, label}: CategorySelectorModalProps) { + const styles = useThemeStyles(); + + const categories = useMemo( + () => + Object.values(policyCategories ?? {}).map((value) => ({ + value: value.name, + text: value.name, + keyForList: value.name, + isSelected: value.name === currentCategory, + })), + [currentCategory, policyCategories], + ); + + return ( + + + + + + + ); +} + +CategorySelectorModal.displayName = 'CategorySelectorModal'; + +export default CategorySelectorModal; diff --git a/src/pages/workspace/distanceRates/CategorySelector/index.tsx b/src/pages/workspace/distanceRates/CategorySelector/index.tsx new file mode 100644 index 000000000000..f739e163a47f --- /dev/null +++ b/src/pages/workspace/distanceRates/CategorySelector/index.tsx @@ -0,0 +1,73 @@ +import React, {useState} from 'react'; +import type {StyleProp, ViewStyle} from 'react-native'; +import {View} from 'react-native'; +import type {OnyxEntry} from 'react-native-onyx'; +import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription'; +import useThemeStyles from '@hooks/useThemeStyles'; +import type * as OnyxTypes from '@src/types/onyx'; +import CategorySelectorModal from './CategorySelectorModal'; +import type CategoryItemType from './types'; + +type CategorySelectorProps = { + /** Collection of categories attached to a policy */ + policyCategories: OnyxEntry; + + /** Function to call when the user selects a category */ + setNewCategory: (value: CategoryItemType) => void; + + /** Currently selected category */ + defaultValue?: string; + + /** Label to display on field */ + label: string; + + /** Any additional styles to apply */ + wrapperStyle: StyleProp; +}; + +function CategorySelector({policyCategories, defaultValue = '', wrapperStyle, label, setNewCategory}: CategorySelectorProps) { + const styles = useThemeStyles(); + + const [isPickerVisible, setIsPickerVisible] = useState(false); + + const showPickerModal = () => { + setIsPickerVisible(true); + }; + + const hidePickerModal = () => { + setIsPickerVisible(false); + }; + + const updateCategoryInput = (categoryItem: CategoryItemType) => { + setNewCategory(categoryItem); + hidePickerModal(); + }; + + const title = defaultValue; + const descStyle = title.length === 0 ? styles.textNormal : null; + + return ( + + + + + ); +} + +CategorySelector.displayName = 'CategorySelector'; + +export default CategorySelector; diff --git a/src/pages/workspace/distanceRates/CategorySelector/types.ts b/src/pages/workspace/distanceRates/CategorySelector/types.ts new file mode 100644 index 000000000000..78e78afb4547 --- /dev/null +++ b/src/pages/workspace/distanceRates/CategorySelector/types.ts @@ -0,0 +1,8 @@ +type CategoryItemType = { + value: string; + text: string; + keyForList: string; + isSelected: boolean; +}; + +export default CategoryItemType; diff --git a/src/pages/workspace/distanceRates/PolicyDistanceRatesPage.tsx b/src/pages/workspace/distanceRates/PolicyDistanceRatesPage.tsx index b9e1ca47b8a8..8f70fa9c13db 100644 --- a/src/pages/workspace/distanceRates/PolicyDistanceRatesPage.tsx +++ b/src/pages/workspace/distanceRates/PolicyDistanceRatesPage.tsx @@ -113,7 +113,7 @@ function PolicyDistanceRatesPage({policy, route}: PolicyDistanceRatesPageProps) }; const openSettings = () => { - // Navigation.navigate(ROUTES.WORKSPACE_DISTANCE_RATES_SETTINGS.getRoute(policyID)); + Navigation.navigate(ROUTES.WORKSPACE_DISTANCE_RATES_SETTINGS.getRoute(policyID)); }; const editRate = () => { diff --git a/src/pages/workspace/distanceRates/PolicyDistanceRatesSettingsPage.tsx b/src/pages/workspace/distanceRates/PolicyDistanceRatesSettingsPage.tsx new file mode 100644 index 000000000000..47df30dfd271 --- /dev/null +++ b/src/pages/workspace/distanceRates/PolicyDistanceRatesSettingsPage.tsx @@ -0,0 +1,80 @@ +import type {StackScreenProps} from '@react-navigation/stack'; +import React from 'react'; +import type {OnyxEntry} from 'react-native-onyx'; +import {withOnyx} from 'react-native-onyx'; +import HeaderWithBackButton from '@components/HeaderWithBackButton'; +import ScreenWrapper from '@components/ScreenWrapper'; +import useLocalize from '@hooks/useLocalize'; +import useThemeStyles from '@hooks/useThemeStyles'; +import type {SettingsNavigatorParamList} from '@navigation/types'; +import * as Policy from '@userActions/Policy'; +import ONYXKEYS from '@src/ONYXKEYS'; +import type SCREENS from '@src/SCREENS'; +import type * as OnyxTypes from '@src/types/onyx'; +import CategorySelector from './CategorySelector'; +import type CategoryItemType from './CategorySelector/types'; +import UnitSelector from './UnitSelector'; +import type {UnitItemType} from './UnitSelector/types'; + +type PolicyDistanceRatesSettingsPageOnyxProps = { + /** Policy details */ + policy: OnyxEntry; + + /** Collection of categories attached to a policy */ + policyCategories: OnyxEntry; +}; + +type PolicyDistanceRatesSettingsPageProps = PolicyDistanceRatesSettingsPageOnyxProps & StackScreenProps; + +function PolicyDistanceRatesSettingsPage({policy, policyCategories, route}: PolicyDistanceRatesSettingsPageProps) { + const styles = useThemeStyles(); + const {translate} = useLocalize(); + + const policyID = route.params.policyID; + const customUnits = policy?.customUnits ?? {}; + const customUnit = customUnits[Object.keys(customUnits)[0]]; + const customUnitID = customUnit.customUnitID; + + const defaultCategory = customUnits[customUnitID].defaultCategory; + const defaultUnit = customUnits[customUnitID].attributes.unit.toUpperCase(); + + const setNewUnit = (unit: UnitItemType) => { + Policy.setPolicyDistanceRatesUnit(policyID, customUnit, {...customUnit, attributes: {unit: unit.value}}); + }; + + const setNewCategory = (category: CategoryItemType) => { + Policy.setPolicyDistanceRatesDefaultCategory(policyID, customUnit, {...customUnit, defaultCategory: category.value}); + }; + + return ( + + + + {policy?.areCategoriesEnabled && ( + + )} + + ); +} + +PolicyDistanceRatesSettingsPage.displayName = 'PolicyDistanceRatesSettingsPage'; + +export default withOnyx({ + policy: { + key: ({route}) => `${ONYXKEYS.COLLECTION.POLICY}${route.params.policyID}`, + }, + policyCategories: { + key: ({route}) => `${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${route.params.policyID}`, + }, +})(PolicyDistanceRatesSettingsPage); diff --git a/src/pages/workspace/distanceRates/UnitSelector/UnitSelectorModal.tsx b/src/pages/workspace/distanceRates/UnitSelector/UnitSelectorModal.tsx new file mode 100644 index 000000000000..cd4a7b926c4c --- /dev/null +++ b/src/pages/workspace/distanceRates/UnitSelector/UnitSelectorModal.tsx @@ -0,0 +1,80 @@ +import React, {useMemo} from 'react'; +import HeaderWithBackButton from '@components/HeaderWithBackButton'; +import Modal from '@components/Modal'; +import ScreenWrapper from '@components/ScreenWrapper'; +import SelectionList from '@components/SelectionList'; +import RadioListItem from '@components/SelectionList/RadioListItem'; +import useLocalize from '@hooks/useLocalize'; +import useThemeStyles from '@hooks/useThemeStyles'; +import CONST from '@src/CONST'; +import type {Unit} from '@src/types/onyx/Policy'; +import type {UnitItemType, UnitType} from './types'; + +type UnitSelectorModalProps = { + /** Whether the modal is visible */ + isVisible: boolean; + + /** Selected unit */ + currentUnit: string; + + /** Function to call when the user selects a unit */ + onUnitSelected: (value: UnitItemType) => void; + + /** Function to call when the user closes the unit selector modal */ + onClose: () => void; + + /** Label to display on field */ + label: string; +}; + +function UnitSelectorModal({isVisible, currentUnit, onUnitSelected, onClose, label}: UnitSelectorModalProps) { + const styles = useThemeStyles(); + const {translate} = useLocalize(); + + const units = useMemo( + () => + Object.keys(CONST.POLICY.UNITS).map((key) => ({ + value: key.toLowerCase() as Unit, + text: translate(`workspace.distanceRates.units.${key as UnitType}`), + keyForList: key, + isSelected: key === currentUnit, + })), + [currentUnit, translate], + ); + + return ( + + + + + + + ); +} + +UnitSelectorModal.displayName = 'UnitSelectorModal'; + +export default UnitSelectorModal; diff --git a/src/pages/workspace/distanceRates/UnitSelector/index.tsx b/src/pages/workspace/distanceRates/UnitSelector/index.tsx new file mode 100644 index 000000000000..8615f101fdda --- /dev/null +++ b/src/pages/workspace/distanceRates/UnitSelector/index.tsx @@ -0,0 +1,69 @@ +import React, {useState} from 'react'; +import type {StyleProp, ViewStyle} from 'react-native'; +import {View} from 'react-native'; +import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription'; +import useLocalize from '@hooks/useLocalize'; +import useThemeStyles from '@hooks/useThemeStyles'; +import type {UnitItemType, UnitType} from './types'; +import UnitSelectorModal from './UnitSelectorModal'; + +type UnitSelectorProps = { + /** Function to call when the user selects a unit */ + setNewUnit: (value: UnitItemType) => void; + + /** Currently selected unit */ + defaultValue: string; + + /** Label to display on field */ + label: string; + + /** Any additional styles to apply */ + wrapperStyle: StyleProp; +}; + +function UnitSelector({defaultValue = '', wrapperStyle, label, setNewUnit}: UnitSelectorProps) { + const styles = useThemeStyles(); + const {translate} = useLocalize(); + + const [isPickerVisible, setIsPickerVisible] = useState(false); + + const showPickerModal = () => { + setIsPickerVisible(true); + }; + + const hidePickerModal = () => { + setIsPickerVisible(false); + }; + + const updateUnitInput = (UnitItem: UnitItemType) => { + setNewUnit(UnitItem); + hidePickerModal(); + }; + + const title = defaultValue ? translate(`workspace.distanceRates.units.${defaultValue as UnitType}`) : ''; + const descStyle = title.length === 0 ? styles.textNormal : null; + + return ( + + + + + ); +} + +UnitSelector.displayName = 'UnitSelector'; + +export default UnitSelector; diff --git a/src/pages/workspace/distanceRates/UnitSelector/types.ts b/src/pages/workspace/distanceRates/UnitSelector/types.ts new file mode 100644 index 000000000000..98f2af3f48cf --- /dev/null +++ b/src/pages/workspace/distanceRates/UnitSelector/types.ts @@ -0,0 +1,13 @@ +import type CONST from '@src/CONST'; +import type {Unit} from '@src/types/onyx/Policy'; + +type UnitType = keyof typeof CONST.POLICY.UNITS; + +type UnitItemType = { + value: Unit; + text: string; + keyForList: string; + isSelected: boolean; +}; + +export type {UnitType, UnitItemType}; From dd2b727c2008b1fca537686aede278ed3b9607e8 Mon Sep 17 00:00:00 2001 From: rory Date: Mon, 11 Mar 2024 15:30:05 -0700 Subject: [PATCH 069/175] Improve InitialURLContext --- src/App.tsx | 8 ++--- src/components/InitialURLContextProvider.tsx | 33 ++++++++++++++++++++ src/libs/InitialUrlContext/index.ts | 7 ----- src/libs/Navigation/AppNavigator/index.tsx | 4 +-- src/pages/LogOutPreviousUserPage.tsx | 5 ++- 5 files changed, 41 insertions(+), 16 deletions(-) create mode 100644 src/components/InitialURLContextProvider.tsx delete mode 100644 src/libs/InitialUrlContext/index.ts diff --git a/src/App.tsx b/src/App.tsx index 0e247d5faa53..a2d353a026af 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -13,6 +13,7 @@ import CustomStatusBarAndBackground from './components/CustomStatusBarAndBackgro import CustomStatusBarAndBackgroundContextProvider from './components/CustomStatusBarAndBackground/CustomStatusBarAndBackgroundContextProvider'; import ErrorBoundary from './components/ErrorBoundary'; import HTMLEngineProvider from './components/HTMLEngineProvider'; +import InitialURLContextProvider from './components/InitialURLContextProvider'; import {LocaleContextProvider} from './components/LocaleContextProvider'; import OnyxProvider from './components/OnyxProvider'; import PopoverContextProvider from './components/PopoverProvider'; @@ -30,12 +31,11 @@ import {WindowDimensionsProvider} from './components/withWindowDimensions'; import Expensify from './Expensify'; import useDefaultDragAndDrop from './hooks/useDefaultDragAndDrop'; import OnyxUpdateManager from './libs/actions/OnyxUpdateManager'; -import InitialUrlContext from './libs/InitialUrlContext'; import {ReportAttachmentsProvider} from './pages/home/report/ReportAttachmentsContext'; import type {Route} from './ROUTES'; type AppProps = { - /** If we have an authToken this is true */ + /** URL passed to our top-level React Native component by HybridApp. Will always be undefined in "pure" NewDot builds. */ url?: Route; }; @@ -52,7 +52,7 @@ function App({url}: AppProps) { useDefaultDragAndDrop(); OnyxUpdateManager(); return ( - + - + ); } diff --git a/src/components/InitialURLContextProvider.tsx b/src/components/InitialURLContextProvider.tsx new file mode 100644 index 000000000000..a3df93844ca9 --- /dev/null +++ b/src/components/InitialURLContextProvider.tsx @@ -0,0 +1,33 @@ +import React, {createContext, useEffect, useState} from 'react'; +import type {ReactNode} from 'react'; +import {Linking} from 'react-native'; +import type {Route} from '@src/ROUTES'; + +/** Initial url that will be opened when NewDot is embedded into Hybrid App. */ +const InitialURLContext = createContext(undefined); + +type InitialURLContextProviderProps = { + /** URL passed to our top-level React Native component by HybridApp. Will always be undefined in "pure" NewDot builds. */ + url?: Route; + + /** Children passed to the context provider */ + children: ReactNode; +}; + +function InitialURLContextProvider({children, url}: InitialURLContextProviderProps) { + const [initialURL, setInitialURL] = useState(url); + useEffect(() => { + if (initialURL) { + return; + } + Linking.getInitialURL().then((initURL) => { + setInitialURL(initURL as Route); + }); + }, [initialURL]); + return {children}; +} + +InitialURLContextProvider.displayName = 'InitialURLContextProvider'; + +export default InitialURLContextProvider; +export {InitialURLContext}; diff --git a/src/libs/InitialUrlContext/index.ts b/src/libs/InitialUrlContext/index.ts deleted file mode 100644 index a87417fe4cc6..000000000000 --- a/src/libs/InitialUrlContext/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -import {createContext} from 'react'; -import type {Route} from '@src/ROUTES'; - -/** Initial url that will be opened when NewDot is embedded into Hybrid App. */ -const InitialUrlContext = createContext(undefined); - -export default InitialUrlContext; diff --git a/src/libs/Navigation/AppNavigator/index.tsx b/src/libs/Navigation/AppNavigator/index.tsx index 24f0f42c5d64..9729a2f812ce 100644 --- a/src/libs/Navigation/AppNavigator/index.tsx +++ b/src/libs/Navigation/AppNavigator/index.tsx @@ -1,6 +1,6 @@ import React, {useContext, useEffect} from 'react'; import {NativeModules} from 'react-native'; -import InitialUrlContext from '@libs/InitialUrlContext'; +import {InitialURLContext} from '@components/InitialURLContextProvider'; import Navigation from '@libs/Navigation/Navigation'; type AppNavigatorProps = { @@ -9,7 +9,7 @@ type AppNavigatorProps = { }; function AppNavigator({authenticated}: AppNavigatorProps) { - const initUrl = useContext(InitialUrlContext); + const initUrl = useContext(InitialURLContext); useEffect(() => { if (!NativeModules.HybridAppModule || !initUrl) { diff --git a/src/pages/LogOutPreviousUserPage.tsx b/src/pages/LogOutPreviousUserPage.tsx index 8679c1bcf4c3..08432a5fb964 100644 --- a/src/pages/LogOutPreviousUserPage.tsx +++ b/src/pages/LogOutPreviousUserPage.tsx @@ -4,7 +4,7 @@ import {Linking, NativeModules} from 'react-native'; import {withOnyx} from 'react-native-onyx'; import type {OnyxEntry} from 'react-native-onyx'; import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator'; -import InitialUrlContext from '@libs/InitialUrlContext'; +import {InitialURLContext} from '@components/InitialURLContextProvider'; import * as SessionUtils from '@libs/SessionUtils'; import Navigation from '@navigation/Navigation'; import type {AuthScreensParamList} from '@navigation/types'; @@ -29,7 +29,7 @@ type LogOutPreviousUserPageProps = LogOutPreviousUserPageOnyxProps & StackScreen // // This component should not do any other navigation as that handled in App.setUpPoliciesAndNavigate function LogOutPreviousUserPage({session, route, account}: LogOutPreviousUserPageProps) { - const initUrlFromOldApp = useContext(InitialUrlContext); + const initUrlFromOldApp = useContext(InitialURLContext); useEffect(() => { Linking.getInitialURL().then((url) => { const sessionEmail = session?.email; @@ -75,7 +75,6 @@ function LogOutPreviousUserPage({session, route, account}: LogOutPreviousUserPag } }); - // We only want to run this effect once on mount (when the page first loads after transitioning from OldDot) // eslint-disable-next-line react-hooks/exhaustive-deps }, []); From d485dd85f0374401e996807c025fb5560d3ab6c0 Mon Sep 17 00:00:00 2001 From: rory Date: Mon, 11 Mar 2024 15:33:21 -0700 Subject: [PATCH 070/175] fix TS types --- src/pages/LogOutPreviousUserPage.tsx | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/pages/LogOutPreviousUserPage.tsx b/src/pages/LogOutPreviousUserPage.tsx index 08432a5fb964..52f95b7c23a0 100644 --- a/src/pages/LogOutPreviousUserPage.tsx +++ b/src/pages/LogOutPreviousUserPage.tsx @@ -14,12 +14,14 @@ import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type {Route} from '@src/ROUTES'; import type SCREENS from '@src/SCREENS'; -import type {Account, Session} from '@src/types/onyx'; +import type {Session} from '@src/types/onyx'; type LogOutPreviousUserPageOnyxProps = { /** The data about the current session which will be set once the user is authenticated and we return to this component as an AuthScreen */ session: OnyxEntry; - account: OnyxEntry; + + /** Is the account loading? */ + isAccountLoading: boolean; }; type LogOutPreviousUserPageProps = LogOutPreviousUserPageOnyxProps & StackScreenProps; @@ -28,12 +30,12 @@ type LogOutPreviousUserPageProps = LogOutPreviousUserPageOnyxProps & StackScreen // out if the transition is for another user. // // This component should not do any other navigation as that handled in App.setUpPoliciesAndNavigate -function LogOutPreviousUserPage({session, route, account}: LogOutPreviousUserPageProps) { +function LogOutPreviousUserPage({session, route, isAccountLoading}: LogOutPreviousUserPageProps) { const initUrlFromOldApp = useContext(InitialURLContext); useEffect(() => { Linking.getInitialURL().then((url) => { const sessionEmail = session?.email; - const transitionURL = NativeModules.HybridAppModule ? `${CONST.DEEPLINK_BASE_URL}${initUrl}` : url; + const transitionURL = NativeModules.HybridAppModule ? `${CONST.DEEPLINK_BASE_URL}${initUrlFromOldApp}` : url; const isLoggingInAsNewUser = SessionUtils.isLoggingInAsNewUser(transitionURL ?? undefined, sessionEmail); const isSupportalLogin = route.params.authTokenType === CONST.AUTH_TOKEN_TYPES.SUPPORT; @@ -65,7 +67,7 @@ function LogOutPreviousUserPage({session, route, account}: LogOutPreviousUserPag // We don't want to navigate to the exitTo route when creating a new workspace from a deep link, // because we already handle creating the optimistic policy and navigating to it in App.setUpPoliciesAndNavigate, // which is already called when AuthScreens mounts. - if (exitTo && exitTo !== ROUTES.WORKSPACE_NEW && !account?.isLoading && !isLoggingInAsNewUser) { + if (exitTo && exitTo !== ROUTES.WORKSPACE_NEW && !isAccountLoading && !isLoggingInAsNewUser) { Navigation.isNavigationReady().then(() => { // remove this screen and navigate to exit route const exitUrl = NativeModules.HybridAppModule ? Navigation.parseHybridAppUrl(exitTo) : exitTo; @@ -87,7 +89,7 @@ LogOutPreviousUserPage.displayName = 'LogOutPreviousUserPage'; export default withOnyx({ isAccountLoading: { key: ONYXKEYS.ACCOUNT, - selector: (account) => account?.isLoading, + selector: (account) => account?.isLoading ?? false, }, session: { key: ONYXKEYS.SESSION, From 52f3877edf2b3aeeb36d048e323883363a68d94a Mon Sep 17 00:00:00 2001 From: rory Date: Mon, 11 Mar 2024 15:53:18 -0700 Subject: [PATCH 071/175] Remove call to Linking.getInitialURL --- src/pages/LogOutPreviousUserPage.tsx | 84 ++++++++++++++-------------- 1 file changed, 41 insertions(+), 43 deletions(-) diff --git a/src/pages/LogOutPreviousUserPage.tsx b/src/pages/LogOutPreviousUserPage.tsx index 52f95b7c23a0..e622424a6832 100644 --- a/src/pages/LogOutPreviousUserPage.tsx +++ b/src/pages/LogOutPreviousUserPage.tsx @@ -1,6 +1,6 @@ import type {StackScreenProps} from '@react-navigation/stack'; import React, {useContext, useEffect} from 'react'; -import {Linking, NativeModules} from 'react-native'; +import {NativeModules} from 'react-native'; import {withOnyx} from 'react-native-onyx'; import type {OnyxEntry} from 'react-native-onyx'; import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator'; @@ -31,55 +31,53 @@ type LogOutPreviousUserPageProps = LogOutPreviousUserPageOnyxProps & StackScreen // // This component should not do any other navigation as that handled in App.setUpPoliciesAndNavigate function LogOutPreviousUserPage({session, route, isAccountLoading}: LogOutPreviousUserPageProps) { - const initUrlFromOldApp = useContext(InitialURLContext); + const initialURL = useContext(InitialURLContext); useEffect(() => { - Linking.getInitialURL().then((url) => { - const sessionEmail = session?.email; - const transitionURL = NativeModules.HybridAppModule ? `${CONST.DEEPLINK_BASE_URL}${initUrlFromOldApp}` : url; - const isLoggingInAsNewUser = SessionUtils.isLoggingInAsNewUser(transitionURL ?? undefined, sessionEmail); - const isSupportalLogin = route.params.authTokenType === CONST.AUTH_TOKEN_TYPES.SUPPORT; + const sessionEmail = session?.email; + const transitionURL = NativeModules.HybridAppModule ? `${CONST.DEEPLINK_BASE_URL}${initialURL}` : initialURL; + const isLoggingInAsNewUser = SessionUtils.isLoggingInAsNewUser(transitionURL ?? undefined, sessionEmail); + const isSupportalLogin = route.params.authTokenType === CONST.AUTH_TOKEN_TYPES.SUPPORT; - if (isLoggingInAsNewUser) { - SessionActions.signOutAndRedirectToSignIn(false, isSupportalLogin); - } + if (isLoggingInAsNewUser) { + SessionActions.signOutAndRedirectToSignIn(false, isSupportalLogin); + } - if (isSupportalLogin) { - SessionActions.signInWithSupportAuthToken(route.params.shortLivedAuthToken ?? ''); - Navigation.isNavigationReady().then(() => { - // We must call goBack() to remove the /transition route from history - Navigation.goBack(); - Navigation.navigate(ROUTES.HOME); - }); - return; - } + if (isSupportalLogin) { + SessionActions.signInWithSupportAuthToken(route.params.shortLivedAuthToken ?? ''); + Navigation.isNavigationReady().then(() => { + // We must call goBack() to remove the /transition route from history + Navigation.goBack(); + Navigation.navigate(ROUTES.HOME); + }); + return; + } - // We need to signin and fetch a new authToken, if a user was already authenticated in NewDot, and was redirected to OldDot - // and their authToken stored in Onyx becomes invalid. - // This workflow is triggered while setting up VBBA. User is redirected from NewDot to OldDot to set up 2FA, and then redirected back to NewDot - // On Enabling 2FA, authToken stored in Onyx becomes expired and hence we need to fetch new authToken - const shouldForceLogin = route.params.shouldForceLogin === 'true'; - if (shouldForceLogin) { - const email = route.params.email ?? ''; - const shortLivedAuthToken = route.params.shortLivedAuthToken ?? ''; - SessionActions.signInWithShortLivedAuthToken(email, shortLivedAuthToken); - } - const exitTo = route.params.exitTo as Route | null; - // We don't want to navigate to the exitTo route when creating a new workspace from a deep link, - // because we already handle creating the optimistic policy and navigating to it in App.setUpPoliciesAndNavigate, - // which is already called when AuthScreens mounts. - if (exitTo && exitTo !== ROUTES.WORKSPACE_NEW && !isAccountLoading && !isLoggingInAsNewUser) { - Navigation.isNavigationReady().then(() => { - // remove this screen and navigate to exit route - const exitUrl = NativeModules.HybridAppModule ? Navigation.parseHybridAppUrl(exitTo) : exitTo; - Navigation.goBack(); - Navigation.navigate(exitUrl); - }); - } - }); + // We need to signin and fetch a new authToken, if a user was already authenticated in NewDot, and was redirected to OldDot + // and their authToken stored in Onyx becomes invalid. + // This workflow is triggered while setting up VBBA. User is redirected from NewDot to OldDot to set up 2FA, and then redirected back to NewDot + // On Enabling 2FA, authToken stored in Onyx becomes expired and hence we need to fetch new authToken + const shouldForceLogin = route.params.shouldForceLogin === 'true'; + if (shouldForceLogin) { + const email = route.params.email ?? ''; + const shortLivedAuthToken = route.params.shortLivedAuthToken ?? ''; + SessionActions.signInWithShortLivedAuthToken(email, shortLivedAuthToken); + } + const exitTo = route.params.exitTo as Route | null; + // We don't want to navigate to the exitTo route when creating a new workspace from a deep link, + // because we already handle creating the optimistic policy and navigating to it in App.setUpPoliciesAndNavigate, + // which is already called when AuthScreens mounts. + if (exitTo && exitTo !== ROUTES.WORKSPACE_NEW && !isAccountLoading && !isLoggingInAsNewUser) { + Navigation.isNavigationReady().then(() => { + // remove this screen and navigate to exit route + const exitUrl = NativeModules.HybridAppModule ? Navigation.parseHybridAppUrl(exitTo) : exitTo; + Navigation.goBack(); + Navigation.navigate(exitUrl); + }); + } // We only want to run this effect once on mount (when the page first loads after transitioning from OldDot) // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); + }, [initialURL]); return ; } From c5eab765a3179740daa1bf3f7e220f19fbdb6478 Mon Sep 17 00:00:00 2001 From: rory Date: Mon, 11 Mar 2024 15:54:41 -0700 Subject: [PATCH 072/175] Add missing return --- src/pages/LogOutPreviousUserPage.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pages/LogOutPreviousUserPage.tsx b/src/pages/LogOutPreviousUserPage.tsx index e622424a6832..f55b6014deef 100644 --- a/src/pages/LogOutPreviousUserPage.tsx +++ b/src/pages/LogOutPreviousUserPage.tsx @@ -40,6 +40,7 @@ function LogOutPreviousUserPage({session, route, isAccountLoading}: LogOutPrevio if (isLoggingInAsNewUser) { SessionActions.signOutAndRedirectToSignIn(false, isSupportalLogin); + return; } if (isSupportalLogin) { From bf9331918b12b25743dafb868550b2dbfffc1372 Mon Sep 17 00:00:00 2001 From: rory Date: Mon, 11 Mar 2024 15:55:52 -0700 Subject: [PATCH 073/175] Default initialURL to empty string --- src/pages/LogOutPreviousUserPage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/LogOutPreviousUserPage.tsx b/src/pages/LogOutPreviousUserPage.tsx index f55b6014deef..d1d51033c147 100644 --- a/src/pages/LogOutPreviousUserPage.tsx +++ b/src/pages/LogOutPreviousUserPage.tsx @@ -34,7 +34,7 @@ function LogOutPreviousUserPage({session, route, isAccountLoading}: LogOutPrevio const initialURL = useContext(InitialURLContext); useEffect(() => { const sessionEmail = session?.email; - const transitionURL = NativeModules.HybridAppModule ? `${CONST.DEEPLINK_BASE_URL}${initialURL}` : initialURL; + const transitionURL = NativeModules.HybridAppModule ? `${CONST.DEEPLINK_BASE_URL}${initialURL ?? ''}` : initialURL; const isLoggingInAsNewUser = SessionUtils.isLoggingInAsNewUser(transitionURL ?? undefined, sessionEmail); const isSupportalLogin = route.params.authTokenType === CONST.AUTH_TOKEN_TYPES.SUPPORT; From 2f7e85e47156c9da8d3e7a459bcfa56dc1c3d64d Mon Sep 17 00:00:00 2001 From: Jayesh Mangwani Date: Tue, 12 Mar 2024 12:50:46 +0530 Subject: [PATCH 074/175] revert package-lock.json file --- package-lock.json | 149 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 148 insertions(+), 1 deletion(-) diff --git a/package-lock.json b/package-lock.json index 5cf96414d5f1..112ae3fa8b94 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8045,6 +8045,153 @@ "integrity": "sha512-C9Br1BQqm6io6lvYHptlLcOHbzlaqxp9tS35P8Qj3pdiiYRTzU3KPvZ61rQ+ZnZ4FOQ6MwPsKsmB8+6WHkAY6Q==", "license": "MIT" }, + "node_modules/@onfido/active-video-capture": { + "version": "0.28.6", + "resolved": "https://registry.npmjs.org/@onfido/active-video-capture/-/active-video-capture-0.28.6.tgz", + "integrity": "sha512-RFUeKaOSjj/amPp6VzhVkq/7kIkutEnnttT9n5KDeD3Vx8a09KD3a/xvxdQppveHlDAYsdBP6LrJwSSpjXiprg==", + "dependencies": { + "@mediapipe/face_detection": "^0.4.1646425229", + "@mediapipe/face_mesh": "^0.4.1633559619", + "@onfido/castor": "^2.2.2", + "@onfido/castor-icons": "^2.12.0", + "@tensorflow-models/face-detection": "^1.0.1", + "@tensorflow-models/face-landmarks-detection": "^1.0.2", + "@tensorflow/tfjs-backend-wasm": "3.20.0", + "@tensorflow/tfjs-backend-webgl": "3.20.0", + "@tensorflow/tfjs-converter": "3.20.0", + "@tensorflow/tfjs-core": "3.20.0", + "preact": "10.11.3", + "react-webcam": "^7.2.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/@onfido/active-video-capture/node_modules/@tensorflow-models/face-landmarks-detection": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@tensorflow-models/face-landmarks-detection/-/face-landmarks-detection-1.0.5.tgz", + "integrity": "sha512-54XJPi8g29/MknJ33ZBrLsEzr9kw/dJtrJMMD3xrCrnRlfFQPIKQ5PI2Wml55Fz2p4U2hemzBB0/H+S94JddIQ==", + "dependencies": { + "rimraf": "^3.0.2" + }, + "peerDependencies": { + "@mediapipe/face_mesh": "~0.4.0", + "@tensorflow-models/face-detection": "~1.0.0", + "@tensorflow/tfjs-backend-webgl": "^3.12.0", + "@tensorflow/tfjs-converter": "^3.12.0", + "@tensorflow/tfjs-core": "^3.12.0" + } + }, + "node_modules/@onfido/active-video-capture/node_modules/@tensorflow/tfjs-backend-cpu": { + "version": "3.20.0", + "resolved": "https://registry.npmjs.org/@tensorflow/tfjs-backend-cpu/-/tfjs-backend-cpu-3.20.0.tgz", + "integrity": "sha512-gf075YaBLwSAAiUwa0D4GvYyUBhbJ1BVSivUNQmUfGKvIr2lIhF0qstBr033YTc3lhkbFSHEEPAHh/EfpqyjXQ==", + "dependencies": { + "@types/seedrandom": "^2.4.28", + "seedrandom": "^3.0.5" + }, + "engines": { + "yarn": ">= 1.3.2" + }, + "peerDependencies": { + "@tensorflow/tfjs-core": "3.20.0" + } + }, + "node_modules/@onfido/active-video-capture/node_modules/@tensorflow/tfjs-backend-wasm": { + "version": "3.20.0", + "resolved": "https://registry.npmjs.org/@tensorflow/tfjs-backend-wasm/-/tfjs-backend-wasm-3.20.0.tgz", + "integrity": "sha512-k+sDcrcPtGToLjKRffgtSqlcN4MC6g4hXWRarZfgvvyvFqpxVfVqrGYHGTirXdN47sKYhmcTSMvbM2quGaaQnA==", + "dependencies": { + "@tensorflow/tfjs-backend-cpu": "3.20.0", + "@types/emscripten": "~0.0.34" + }, + "peerDependencies": { + "@tensorflow/tfjs-core": "3.20.0" + } + }, + "node_modules/@onfido/active-video-capture/node_modules/@tensorflow/tfjs-backend-webgl": { + "version": "3.20.0", + "resolved": "https://registry.npmjs.org/@tensorflow/tfjs-backend-webgl/-/tfjs-backend-webgl-3.20.0.tgz", + "integrity": "sha512-SucbyQ08re3HvRgVfarRtKFIjNM4JvIAzcXmw4vaE/HrCtPEePkGO1VrmfQoN470EdUmGiwgqAjoyBvM2VOlVg==", + "dependencies": { + "@tensorflow/tfjs-backend-cpu": "3.20.0", + "@types/offscreencanvas": "~2019.3.0", + "@types/seedrandom": "^2.4.28", + "@types/webgl-ext": "0.0.30", + "@types/webgl2": "0.0.6", + "seedrandom": "^3.0.5" + }, + "engines": { + "yarn": ">= 1.3.2" + }, + "peerDependencies": { + "@tensorflow/tfjs-core": "3.20.0" + } + }, + "node_modules/@onfido/active-video-capture/node_modules/@tensorflow/tfjs-converter": { + "version": "3.20.0", + "resolved": "https://registry.npmjs.org/@tensorflow/tfjs-converter/-/tfjs-converter-3.20.0.tgz", + "integrity": "sha512-8EIYqtQwvSYw9GFNW2OFU8Qnl/FQF/kKAsQJoORYaZ419WJo+FIZWbAWDtCpJSAgkgoHH1jYWgV9H313cVmqxg==", + "peerDependencies": { + "@tensorflow/tfjs-core": "3.20.0" + } + }, + "node_modules/@onfido/active-video-capture/node_modules/@tensorflow/tfjs-core": { + "version": "3.20.0", + "resolved": "https://registry.npmjs.org/@tensorflow/tfjs-core/-/tfjs-core-3.20.0.tgz", + "integrity": "sha512-L16JyVA4a8jFJXFgB9/oYZxcGq/GfLypt5dMVTyedznARZZ9SiY/UMMbo3IKl9ZylG1dOVVTpjzV3EvBYfeJXw==", + "dependencies": { + "@types/long": "^4.0.1", + "@types/offscreencanvas": "~2019.3.0", + "@types/seedrandom": "^2.4.28", + "@types/webgl-ext": "0.0.30", + "@webgpu/types": "0.1.16", + "long": "4.0.0", + "node-fetch": "~2.6.1", + "seedrandom": "^3.0.5" + }, + "engines": { + "yarn": ">= 1.3.2" + } + }, + "node_modules/@onfido/active-video-capture/node_modules/@webgpu/types": { + "version": "0.1.16", + "resolved": "https://registry.npmjs.org/@webgpu/types/-/types-0.1.16.tgz", + "integrity": "sha512-9E61voMP4+Rze02jlTXud++Htpjyyk8vw5Hyw9FGRrmhHQg2GqbuOfwf5Klrb8vTxc2XWI3EfO7RUHMpxTj26A==" + }, + "node_modules/@onfido/castor": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@onfido/castor/-/castor-2.3.0.tgz", + "integrity": "sha512-FkydkjedS6b2g3SqgZMYnVRZvUs/MkaEuXXJWG9+LNc7DMFT1K8smOnNuHzkiM3cJhXL6yAADdKE0mg+ZIrucQ==", + "dependencies": { + "@onfido/castor-tokens": "^1.0.0-beta.6", + "csstype": "^3.1.1" + }, + "peerDependencies": { + "@onfido/castor-icons": ">=1.0.0" + } + }, + "node_modules/@onfido/castor-icons": { + "version": "2.22.0", + "resolved": "https://registry.npmjs.org/@onfido/castor-icons/-/castor-icons-2.22.0.tgz", + "integrity": "sha512-7OnCvu5xqVWcBLqovZyb99NP0oHw7sjkVYXZhi438i0U6Pgecrhu/14Gc/IN/kvgDxWj9qmiYdd0qdjNaVckrQ==", + "peerDependencies": { + "react": ">=17 || ^16.14 || ^15.7 || ^0.14.10" + } + }, + "node_modules/@onfido/castor-tokens": { + "version": "1.0.0-beta.6", + "resolved": "https://registry.npmjs.org/@onfido/castor-tokens/-/castor-tokens-1.0.0-beta.6.tgz", + "integrity": "sha512-MfwuSlNdM0Ay0cI3LLyqZGsHW0e1Y1R/0IdQKVU575PdWQx1Q/538aOZMo/a3/oSW0pMEgfOm+mNqPx057cvWA==" + }, + "node_modules/@onfido/opencv": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@onfido/opencv/-/opencv-2.1.1.tgz", + "integrity": "sha512-Bwo0YsZrrdm+p5hpNFZ7yrqNVWJxOUbQW9aWDEUtkDWUL+nX2RHIR6F4lBGVmbqnG24anadS/+nEvy80SwD3tQ==", + "dependencies": { + "mirada": "^0.0.15" + } + }, "node_modules/@onfido/react-native-sdk": { "version": "10.6.0", "resolved": "https://registry.npmjs.org/@onfido/react-native-sdk/-/react-native-sdk-10.6.0.tgz", @@ -52751,4 +52898,4 @@ } } } -} +} \ No newline at end of file From 990a4401198bea614446f2e2221c5228f340c76d Mon Sep 17 00:00:00 2001 From: Jayesh Mangwani Date: Tue, 12 Mar 2024 12:53:12 +0530 Subject: [PATCH 075/175] revert package-lock.json file --- package-lock.json | 149 +--------------------------------------------- 1 file changed, 1 insertion(+), 148 deletions(-) diff --git a/package-lock.json b/package-lock.json index 112ae3fa8b94..5cf96414d5f1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8045,153 +8045,6 @@ "integrity": "sha512-C9Br1BQqm6io6lvYHptlLcOHbzlaqxp9tS35P8Qj3pdiiYRTzU3KPvZ61rQ+ZnZ4FOQ6MwPsKsmB8+6WHkAY6Q==", "license": "MIT" }, - "node_modules/@onfido/active-video-capture": { - "version": "0.28.6", - "resolved": "https://registry.npmjs.org/@onfido/active-video-capture/-/active-video-capture-0.28.6.tgz", - "integrity": "sha512-RFUeKaOSjj/amPp6VzhVkq/7kIkutEnnttT9n5KDeD3Vx8a09KD3a/xvxdQppveHlDAYsdBP6LrJwSSpjXiprg==", - "dependencies": { - "@mediapipe/face_detection": "^0.4.1646425229", - "@mediapipe/face_mesh": "^0.4.1633559619", - "@onfido/castor": "^2.2.2", - "@onfido/castor-icons": "^2.12.0", - "@tensorflow-models/face-detection": "^1.0.1", - "@tensorflow-models/face-landmarks-detection": "^1.0.2", - "@tensorflow/tfjs-backend-wasm": "3.20.0", - "@tensorflow/tfjs-backend-webgl": "3.20.0", - "@tensorflow/tfjs-converter": "3.20.0", - "@tensorflow/tfjs-core": "3.20.0", - "preact": "10.11.3", - "react-webcam": "^7.2.0" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/@onfido/active-video-capture/node_modules/@tensorflow-models/face-landmarks-detection": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@tensorflow-models/face-landmarks-detection/-/face-landmarks-detection-1.0.5.tgz", - "integrity": "sha512-54XJPi8g29/MknJ33ZBrLsEzr9kw/dJtrJMMD3xrCrnRlfFQPIKQ5PI2Wml55Fz2p4U2hemzBB0/H+S94JddIQ==", - "dependencies": { - "rimraf": "^3.0.2" - }, - "peerDependencies": { - "@mediapipe/face_mesh": "~0.4.0", - "@tensorflow-models/face-detection": "~1.0.0", - "@tensorflow/tfjs-backend-webgl": "^3.12.0", - "@tensorflow/tfjs-converter": "^3.12.0", - "@tensorflow/tfjs-core": "^3.12.0" - } - }, - "node_modules/@onfido/active-video-capture/node_modules/@tensorflow/tfjs-backend-cpu": { - "version": "3.20.0", - "resolved": "https://registry.npmjs.org/@tensorflow/tfjs-backend-cpu/-/tfjs-backend-cpu-3.20.0.tgz", - "integrity": "sha512-gf075YaBLwSAAiUwa0D4GvYyUBhbJ1BVSivUNQmUfGKvIr2lIhF0qstBr033YTc3lhkbFSHEEPAHh/EfpqyjXQ==", - "dependencies": { - "@types/seedrandom": "^2.4.28", - "seedrandom": "^3.0.5" - }, - "engines": { - "yarn": ">= 1.3.2" - }, - "peerDependencies": { - "@tensorflow/tfjs-core": "3.20.0" - } - }, - "node_modules/@onfido/active-video-capture/node_modules/@tensorflow/tfjs-backend-wasm": { - "version": "3.20.0", - "resolved": "https://registry.npmjs.org/@tensorflow/tfjs-backend-wasm/-/tfjs-backend-wasm-3.20.0.tgz", - "integrity": "sha512-k+sDcrcPtGToLjKRffgtSqlcN4MC6g4hXWRarZfgvvyvFqpxVfVqrGYHGTirXdN47sKYhmcTSMvbM2quGaaQnA==", - "dependencies": { - "@tensorflow/tfjs-backend-cpu": "3.20.0", - "@types/emscripten": "~0.0.34" - }, - "peerDependencies": { - "@tensorflow/tfjs-core": "3.20.0" - } - }, - "node_modules/@onfido/active-video-capture/node_modules/@tensorflow/tfjs-backend-webgl": { - "version": "3.20.0", - "resolved": "https://registry.npmjs.org/@tensorflow/tfjs-backend-webgl/-/tfjs-backend-webgl-3.20.0.tgz", - "integrity": "sha512-SucbyQ08re3HvRgVfarRtKFIjNM4JvIAzcXmw4vaE/HrCtPEePkGO1VrmfQoN470EdUmGiwgqAjoyBvM2VOlVg==", - "dependencies": { - "@tensorflow/tfjs-backend-cpu": "3.20.0", - "@types/offscreencanvas": "~2019.3.0", - "@types/seedrandom": "^2.4.28", - "@types/webgl-ext": "0.0.30", - "@types/webgl2": "0.0.6", - "seedrandom": "^3.0.5" - }, - "engines": { - "yarn": ">= 1.3.2" - }, - "peerDependencies": { - "@tensorflow/tfjs-core": "3.20.0" - } - }, - "node_modules/@onfido/active-video-capture/node_modules/@tensorflow/tfjs-converter": { - "version": "3.20.0", - "resolved": "https://registry.npmjs.org/@tensorflow/tfjs-converter/-/tfjs-converter-3.20.0.tgz", - "integrity": "sha512-8EIYqtQwvSYw9GFNW2OFU8Qnl/FQF/kKAsQJoORYaZ419WJo+FIZWbAWDtCpJSAgkgoHH1jYWgV9H313cVmqxg==", - "peerDependencies": { - "@tensorflow/tfjs-core": "3.20.0" - } - }, - "node_modules/@onfido/active-video-capture/node_modules/@tensorflow/tfjs-core": { - "version": "3.20.0", - "resolved": "https://registry.npmjs.org/@tensorflow/tfjs-core/-/tfjs-core-3.20.0.tgz", - "integrity": "sha512-L16JyVA4a8jFJXFgB9/oYZxcGq/GfLypt5dMVTyedznARZZ9SiY/UMMbo3IKl9ZylG1dOVVTpjzV3EvBYfeJXw==", - "dependencies": { - "@types/long": "^4.0.1", - "@types/offscreencanvas": "~2019.3.0", - "@types/seedrandom": "^2.4.28", - "@types/webgl-ext": "0.0.30", - "@webgpu/types": "0.1.16", - "long": "4.0.0", - "node-fetch": "~2.6.1", - "seedrandom": "^3.0.5" - }, - "engines": { - "yarn": ">= 1.3.2" - } - }, - "node_modules/@onfido/active-video-capture/node_modules/@webgpu/types": { - "version": "0.1.16", - "resolved": "https://registry.npmjs.org/@webgpu/types/-/types-0.1.16.tgz", - "integrity": "sha512-9E61voMP4+Rze02jlTXud++Htpjyyk8vw5Hyw9FGRrmhHQg2GqbuOfwf5Klrb8vTxc2XWI3EfO7RUHMpxTj26A==" - }, - "node_modules/@onfido/castor": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@onfido/castor/-/castor-2.3.0.tgz", - "integrity": "sha512-FkydkjedS6b2g3SqgZMYnVRZvUs/MkaEuXXJWG9+LNc7DMFT1K8smOnNuHzkiM3cJhXL6yAADdKE0mg+ZIrucQ==", - "dependencies": { - "@onfido/castor-tokens": "^1.0.0-beta.6", - "csstype": "^3.1.1" - }, - "peerDependencies": { - "@onfido/castor-icons": ">=1.0.0" - } - }, - "node_modules/@onfido/castor-icons": { - "version": "2.22.0", - "resolved": "https://registry.npmjs.org/@onfido/castor-icons/-/castor-icons-2.22.0.tgz", - "integrity": "sha512-7OnCvu5xqVWcBLqovZyb99NP0oHw7sjkVYXZhi438i0U6Pgecrhu/14Gc/IN/kvgDxWj9qmiYdd0qdjNaVckrQ==", - "peerDependencies": { - "react": ">=17 || ^16.14 || ^15.7 || ^0.14.10" - } - }, - "node_modules/@onfido/castor-tokens": { - "version": "1.0.0-beta.6", - "resolved": "https://registry.npmjs.org/@onfido/castor-tokens/-/castor-tokens-1.0.0-beta.6.tgz", - "integrity": "sha512-MfwuSlNdM0Ay0cI3LLyqZGsHW0e1Y1R/0IdQKVU575PdWQx1Q/538aOZMo/a3/oSW0pMEgfOm+mNqPx057cvWA==" - }, - "node_modules/@onfido/opencv": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@onfido/opencv/-/opencv-2.1.1.tgz", - "integrity": "sha512-Bwo0YsZrrdm+p5hpNFZ7yrqNVWJxOUbQW9aWDEUtkDWUL+nX2RHIR6F4lBGVmbqnG24anadS/+nEvy80SwD3tQ==", - "dependencies": { - "mirada": "^0.0.15" - } - }, "node_modules/@onfido/react-native-sdk": { "version": "10.6.0", "resolved": "https://registry.npmjs.org/@onfido/react-native-sdk/-/react-native-sdk-10.6.0.tgz", @@ -52898,4 +52751,4 @@ } } } -} \ No newline at end of file +} From 4dd5b43dcd7fccd1ee4ee5e3e49327030af03c04 Mon Sep 17 00:00:00 2001 From: Jayesh Mangwani Date: Tue, 12 Mar 2024 12:57:33 +0530 Subject: [PATCH 076/175] revert package-lock.json file --- package-lock.json | 147 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 147 insertions(+) diff --git a/package-lock.json b/package-lock.json index 5cf96414d5f1..bc373abcd9b0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8045,6 +8045,153 @@ "integrity": "sha512-C9Br1BQqm6io6lvYHptlLcOHbzlaqxp9tS35P8Qj3pdiiYRTzU3KPvZ61rQ+ZnZ4FOQ6MwPsKsmB8+6WHkAY6Q==", "license": "MIT" }, + "node_modules/@onfido/active-video-capture": { + "version": "0.28.6", + "resolved": "https://registry.npmjs.org/@onfido/active-video-capture/-/active-video-capture-0.28.6.tgz", + "integrity": "sha512-RFUeKaOSjj/amPp6VzhVkq/7kIkutEnnttT9n5KDeD3Vx8a09KD3a/xvxdQppveHlDAYsdBP6LrJwSSpjXiprg==", + "dependencies": { + "@mediapipe/face_detection": "^0.4.1646425229", + "@mediapipe/face_mesh": "^0.4.1633559619", + "@onfido/castor": "^2.2.2", + "@onfido/castor-icons": "^2.12.0", + "@tensorflow-models/face-detection": "^1.0.1", + "@tensorflow-models/face-landmarks-detection": "^1.0.2", + "@tensorflow/tfjs-backend-wasm": "3.20.0", + "@tensorflow/tfjs-backend-webgl": "3.20.0", + "@tensorflow/tfjs-converter": "3.20.0", + "@tensorflow/tfjs-core": "3.20.0", + "preact": "10.11.3", + "react-webcam": "^7.2.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/@onfido/active-video-capture/node_modules/@tensorflow-models/face-landmarks-detection": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@tensorflow-models/face-landmarks-detection/-/face-landmarks-detection-1.0.5.tgz", + "integrity": "sha512-54XJPi8g29/MknJ33ZBrLsEzr9kw/dJtrJMMD3xrCrnRlfFQPIKQ5PI2Wml55Fz2p4U2hemzBB0/H+S94JddIQ==", + "dependencies": { + "rimraf": "^3.0.2" + }, + "peerDependencies": { + "@mediapipe/face_mesh": "~0.4.0", + "@tensorflow-models/face-detection": "~1.0.0", + "@tensorflow/tfjs-backend-webgl": "^3.12.0", + "@tensorflow/tfjs-converter": "^3.12.0", + "@tensorflow/tfjs-core": "^3.12.0" + } + }, + "node_modules/@onfido/active-video-capture/node_modules/@tensorflow/tfjs-backend-cpu": { + "version": "3.20.0", + "resolved": "https://registry.npmjs.org/@tensorflow/tfjs-backend-cpu/-/tfjs-backend-cpu-3.20.0.tgz", + "integrity": "sha512-gf075YaBLwSAAiUwa0D4GvYyUBhbJ1BVSivUNQmUfGKvIr2lIhF0qstBr033YTc3lhkbFSHEEPAHh/EfpqyjXQ==", + "dependencies": { + "@types/seedrandom": "^2.4.28", + "seedrandom": "^3.0.5" + }, + "engines": { + "yarn": ">= 1.3.2" + }, + "peerDependencies": { + "@tensorflow/tfjs-core": "3.20.0" + } + }, + "node_modules/@onfido/active-video-capture/node_modules/@tensorflow/tfjs-backend-wasm": { + "version": "3.20.0", + "resolved": "https://registry.npmjs.org/@tensorflow/tfjs-backend-wasm/-/tfjs-backend-wasm-3.20.0.tgz", + "integrity": "sha512-k+sDcrcPtGToLjKRffgtSqlcN4MC6g4hXWRarZfgvvyvFqpxVfVqrGYHGTirXdN47sKYhmcTSMvbM2quGaaQnA==", + "dependencies": { + "@tensorflow/tfjs-backend-cpu": "3.20.0", + "@types/emscripten": "~0.0.34" + }, + "peerDependencies": { + "@tensorflow/tfjs-core": "3.20.0" + } + }, + "node_modules/@onfido/active-video-capture/node_modules/@tensorflow/tfjs-backend-webgl": { + "version": "3.20.0", + "resolved": "https://registry.npmjs.org/@tensorflow/tfjs-backend-webgl/-/tfjs-backend-webgl-3.20.0.tgz", + "integrity": "sha512-SucbyQ08re3HvRgVfarRtKFIjNM4JvIAzcXmw4vaE/HrCtPEePkGO1VrmfQoN470EdUmGiwgqAjoyBvM2VOlVg==", + "dependencies": { + "@tensorflow/tfjs-backend-cpu": "3.20.0", + "@types/offscreencanvas": "~2019.3.0", + "@types/seedrandom": "^2.4.28", + "@types/webgl-ext": "0.0.30", + "@types/webgl2": "0.0.6", + "seedrandom": "^3.0.5" + }, + "engines": { + "yarn": ">= 1.3.2" + }, + "peerDependencies": { + "@tensorflow/tfjs-core": "3.20.0" + } + }, + "node_modules/@onfido/active-video-capture/node_modules/@tensorflow/tfjs-converter": { + "version": "3.20.0", + "resolved": "https://registry.npmjs.org/@tensorflow/tfjs-converter/-/tfjs-converter-3.20.0.tgz", + "integrity": "sha512-8EIYqtQwvSYw9GFNW2OFU8Qnl/FQF/kKAsQJoORYaZ419WJo+FIZWbAWDtCpJSAgkgoHH1jYWgV9H313cVmqxg==", + "peerDependencies": { + "@tensorflow/tfjs-core": "3.20.0" + } + }, + "node_modules/@onfido/active-video-capture/node_modules/@tensorflow/tfjs-core": { + "version": "3.20.0", + "resolved": "https://registry.npmjs.org/@tensorflow/tfjs-core/-/tfjs-core-3.20.0.tgz", + "integrity": "sha512-L16JyVA4a8jFJXFgB9/oYZxcGq/GfLypt5dMVTyedznARZZ9SiY/UMMbo3IKl9ZylG1dOVVTpjzV3EvBYfeJXw==", + "dependencies": { + "@types/long": "^4.0.1", + "@types/offscreencanvas": "~2019.3.0", + "@types/seedrandom": "^2.4.28", + "@types/webgl-ext": "0.0.30", + "@webgpu/types": "0.1.16", + "long": "4.0.0", + "node-fetch": "~2.6.1", + "seedrandom": "^3.0.5" + }, + "engines": { + "yarn": ">= 1.3.2" + } + }, + "node_modules/@onfido/active-video-capture/node_modules/@webgpu/types": { + "version": "0.1.16", + "resolved": "https://registry.npmjs.org/@webgpu/types/-/types-0.1.16.tgz", + "integrity": "sha512-9E61voMP4+Rze02jlTXud++Htpjyyk8vw5Hyw9FGRrmhHQg2GqbuOfwf5Klrb8vTxc2XWI3EfO7RUHMpxTj26A==" + }, + "node_modules/@onfido/castor": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@onfido/castor/-/castor-2.3.0.tgz", + "integrity": "sha512-FkydkjedS6b2g3SqgZMYnVRZvUs/MkaEuXXJWG9+LNc7DMFT1K8smOnNuHzkiM3cJhXL6yAADdKE0mg+ZIrucQ==", + "dependencies": { + "@onfido/castor-tokens": "^1.0.0-beta.6", + "csstype": "^3.1.1" + }, + "peerDependencies": { + "@onfido/castor-icons": ">=1.0.0" + } + }, + "node_modules/@onfido/castor-icons": { + "version": "2.22.0", + "resolved": "https://registry.npmjs.org/@onfido/castor-icons/-/castor-icons-2.22.0.tgz", + "integrity": "sha512-7OnCvu5xqVWcBLqovZyb99NP0oHw7sjkVYXZhi438i0U6Pgecrhu/14Gc/IN/kvgDxWj9qmiYdd0qdjNaVckrQ==", + "peerDependencies": { + "react": ">=17 || ^16.14 || ^15.7 || ^0.14.10" + } + }, + "node_modules/@onfido/castor-tokens": { + "version": "1.0.0-beta.6", + "resolved": "https://registry.npmjs.org/@onfido/castor-tokens/-/castor-tokens-1.0.0-beta.6.tgz", + "integrity": "sha512-MfwuSlNdM0Ay0cI3LLyqZGsHW0e1Y1R/0IdQKVU575PdWQx1Q/538aOZMo/a3/oSW0pMEgfOm+mNqPx057cvWA==" + }, + "node_modules/@onfido/opencv": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@onfido/opencv/-/opencv-2.1.1.tgz", + "integrity": "sha512-Bwo0YsZrrdm+p5hpNFZ7yrqNVWJxOUbQW9aWDEUtkDWUL+nX2RHIR6F4lBGVmbqnG24anadS/+nEvy80SwD3tQ==", + "dependencies": { + "mirada": "^0.0.15" + } + }, "node_modules/@onfido/react-native-sdk": { "version": "10.6.0", "resolved": "https://registry.npmjs.org/@onfido/react-native-sdk/-/react-native-sdk-10.6.0.tgz", From 5460b54f694ab2f1383d867e1200bb6e43230e82 Mon Sep 17 00:00:00 2001 From: BrtqKr Date: Tue, 12 Mar 2024 14:51:18 +0100 Subject: [PATCH 077/175] migrate workflow_tests/utils files --- tsconfig.json | 2 +- workflow_tests/utils/ExtendedAct.js | 44 ------ workflow_tests/utils/ExtendedAct.ts | 50 +++++++ .../utils/{JobMocker.js => JobMocker.ts} | 67 ++++++--- ...{preGenerateTest.js => preGenerateTest.ts} | 130 ++++++++++-------- workflow_tests/utils/{utils.js => utils.ts} | 82 +++++++---- 6 files changed, 230 insertions(+), 145 deletions(-) delete mode 100644 workflow_tests/utils/ExtendedAct.js create mode 100644 workflow_tests/utils/ExtendedAct.ts rename workflow_tests/utils/{JobMocker.js => JobMocker.ts} (58%) rename workflow_tests/utils/{preGenerateTest.js => preGenerateTest.ts} (70%) rename workflow_tests/utils/{utils.js => utils.ts} (66%) 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/utils/ExtendedAct.js b/workflow_tests/utils/ExtendedAct.js deleted file mode 100644 index 9b4ab1bebda2..000000000000 --- a/workflow_tests/utils/ExtendedAct.js +++ /dev/null @@ -1,44 +0,0 @@ -const kieActJs = require('@kie/act-js'); -const path = require('path'); -const _ = require('underscore'); -const JobMocker = require('./JobMocker'); - -class ExtendedAct extends kieActJs.Act { - async parseRunOpts(opts) { - const {cwd, actArguments, proxy} = await super.parseRunOpts(opts); - if (opts && opts.actor) { - actArguments.push('--actor', opts.actor); - } - return {cwd, actArguments, proxy}; - } - - async runEvent(event, opts) { - const {mockJobs, ...vanillaOpts} = opts; - if (mockJobs) { - await this.handleJobMocking((workflow) => workflow.events.includes(event), {mockJobs, workflowFile: opts.workflowFile, cwd: opts.cwd}); - } - return super.runEvent(event, vanillaOpts); - } - - async handleJobMocking(filter, opts) { - let workflowFiles; - if (opts.workflowFile) { - workflowFiles = [path.basename(opts.workflowFile)]; - } else if (this.workflowFile !== this.cwd) { - workflowFiles = [path.basename(this.workflowFile)]; - } else { - workflowFiles = _(_(await this.list(undefined, opts.cwd, opts.workflowFile)).filter(filter)).map((l) => l.workflowFile); - } - return Promise.all( - _(workflowFiles).map((workflowFile) => { - // eslint-disable-next-line es/no-nullish-coalescing-operators - const jobMocker = new JobMocker.JobMocker(workflowFile, opts.cwd ?? this.cwd); - return jobMocker.mock(opts.mockJobs); - }), - ); - } -} - -module.exports = { - ExtendedAct, -}; diff --git a/workflow_tests/utils/ExtendedAct.ts b/workflow_tests/utils/ExtendedAct.ts new file mode 100644 index 000000000000..f471292b1509 --- /dev/null +++ b/workflow_tests/utils/ExtendedAct.ts @@ -0,0 +1,50 @@ +/* eslint-disable @typescript-eslint/dot-notation */ +// This eslint-disable comment is here to allow accessing private properties in the Act class +import type {RunOpts, Workflow} from '@kie/act-js'; +import kieActJs from '@kie/act-js'; +import path from 'path'; +import {JobMocker} from './JobMocker'; +import type {MockJob} from './JobMocker'; + +type ExtendedActOpts = RunOpts & {actor?: string; workflowFile?: string; mockJobs?: Record}; + +// @ts-expect-error Override shouldn't be done on private methods - wait until the issue is resolved +class ExtendedAct extends kieActJs.Act { + async parseRunOpts(opts?: ExtendedActOpts) { + const {cwd, actArguments, proxy} = await super['parseRunOpts'](opts); + if (opts?.actor) { + actArguments.push('--actor', opts.actor); + } + return {cwd, actArguments, proxy}; + } + + async runEvent(event: string, opts?: ExtendedActOpts) { + const {mockJobs, ...vanillaOpts} = opts ?? {}; + + if (mockJobs) { + await this.handleJobMocking((workflow) => workflow.events.includes(event), {mockJobs, workflowFile: opts?.workflowFile, cwd: opts?.cwd}); + } + return super.runEvent(event, vanillaOpts); + } + + async handleJobMocking(filter: (workflow: Workflow) => boolean, opts?: ExtendedActOpts) { + let workflowFiles: string[]; + if (opts?.workflowFile) { + workflowFiles = [path.basename(opts.workflowFile)]; + } else if (this['workflowFile'] !== this['cwd']) { + workflowFiles = [path.basename(this['workflowFile'])]; + } else { + const availableWorkflows = await this.list(undefined, opts?.cwd, opts?.workflowFile); + workflowFiles = availableWorkflows.filter(filter).map((workflow: Workflow) => workflow.workflowFile); + } + return Promise.all( + workflowFiles.map((workflowFile) => { + const jobMocker = new JobMocker(workflowFile, opts?.cwd ?? this['cwd']); + return jobMocker.mock(opts?.mockJobs); + }), + ); + } +} + +// eslint-disable-next-line import/prefer-default-export +export {ExtendedAct}; diff --git a/workflow_tests/utils/JobMocker.js b/workflow_tests/utils/JobMocker.ts similarity index 58% rename from workflow_tests/utils/JobMocker.js rename to workflow_tests/utils/JobMocker.ts index a2682a657380..66e1e19e542b 100644 --- a/workflow_tests/utils/JobMocker.js +++ b/workflow_tests/utils/JobMocker.ts @@ -1,17 +1,48 @@ -const fs = require('fs'); -const path = require('path'); -const yaml = require('yaml'); -const _ = require('underscore'); +import type {PathOrFileDescriptor} from 'fs'; +import fs from 'fs'; +import path from 'path'; +import yaml from 'yaml'; + +// eslint-disable-next-line @typescript-eslint/naming-convention +type YamlMockJob = Omit & {'runs-on'?: string}; + +type YamlWorkflow = { + jobs: Record; +}; + +type MockJob = { + steps: MockJobStep[]; + uses?: string; // ? + secrets?: string[]; // ? + with?: string; // ? + outputs?: string[]; // ? + runsOn: string; // ? +}; + +type MockJobStep = { + id?: string; // ? + name: string; + run?: string; // ? + mockWith?: string; + with?: string; // ? + envs?: string[]; // ? + inputs?: string[]; +}; class JobMocker { - constructor(workflowFile, cwd) { + workflowFile: string; + + cwd: string; + + constructor(workflowFile: string, cwd: string) { this.workflowFile = workflowFile; this.cwd = cwd; } - async mock(mockJobs) { + mock(mockJobs: Record = {}) { const filePath = this.getWorkflowPath(); - const workflow = await this.readWorkflowFile(filePath); + const workflow = this.readWorkflowFile(filePath); + Object.entries(mockJobs).forEach(([jobId, mockJob]) => { const job = this.locateJob(workflow, jobId); if (job) { @@ -21,13 +52,13 @@ class JobMocker { if (job.secrets) { delete job.secrets; } - let jobWith; + let jobWith: string | undefined; if (job.with) { jobWith = job.with; delete job.with; } - job.steps = _(mockJob.steps).map((step) => { - const mockStep = { + job.steps = mockJob.steps.map((step) => { + const mockStep: MockJobStep = { name: step.name, run: step.mockWith, }; @@ -52,7 +83,7 @@ class JobMocker { return this.writeWorkflowFile(filePath, workflow); } - locateJob(workflow, jobId) { + locateJob(workflow: YamlWorkflow, jobId: string) { return workflow.jobs[jobId]; } @@ -69,15 +100,17 @@ class JobMocker { throw new Error(`Could not locate ${this.workflowFile}`); } - async readWorkflowFile(location) { - return yaml.parse(fs.readFileSync(location, 'utf8')); + readWorkflowFile(location: PathOrFileDescriptor) { + const test: YamlWorkflow = yaml.parse(fs.readFileSync(location, 'utf8')); + + return test; } - async writeWorkflowFile(location, data) { + writeWorkflowFile(location: PathOrFileDescriptor, data: YamlWorkflow) { return fs.writeFileSync(location, yaml.stringify(data), 'utf8'); } } -module.exports = { - JobMocker, -}; +// eslint-disable-next-line import/prefer-default-export +export {JobMocker}; +export type {MockJob, YamlWorkflow, YamlMockJob, MockJobStep}; diff --git a/workflow_tests/utils/preGenerateTest.js b/workflow_tests/utils/preGenerateTest.ts similarity index 70% rename from workflow_tests/utils/preGenerateTest.js rename to workflow_tests/utils/preGenerateTest.ts index df4a12f68dc6..485b7b30bb35 100644 --- a/workflow_tests/utils/preGenerateTest.js +++ b/workflow_tests/utils/preGenerateTest.ts @@ -1,9 +1,10 @@ /* eslint no-console: ["error", { allow: ["warn", "log"] }] */ -const path = require('path'); -const {exit} = require('process'); -const fs = require('fs'); -const yaml = require('yaml'); -const _ = require('underscore'); +import type {PathLike} from 'fs'; +import fs from 'fs'; +import path from 'path'; +import {exit} from 'process'; +import yaml from 'yaml'; +import type {MockJobStep, YamlMockJob, YamlWorkflow} from './JobMocker'; const workflowsDirectory = path.resolve(__dirname, '..', '..', '.github', 'workflows'); const workflowTestsDirectory = path.resolve(__dirname, '..'); @@ -12,16 +13,16 @@ const workflowTestAssertionsDirectory = path.join(workflowTestsDirectory, 'asser const workflowFilePattern = '\\w+\\.yml'; const workflowFileRegex = new RegExp(workflowFilePattern, 'g'); -const capitalize = (s) => (s && s.charAt(0).toUpperCase() + s.slice(1)) || ''; -const mockFileTemplate = (mockSteps, exports) => `const utils = require('../utils/utils'); +const capitalize = (s: string): string => (s && s.charAt(0).toUpperCase() + s.slice(1)) || ''; +const mockFileTemplate = (mockSteps: string, exports: string) => `const utils = require('../utils/utils'); ${mockSteps} ${exports} `; -const assertionFileTemplate = (jobAssertions, exports) => `const utils = require('../utils/utils'); +const assertionFileTemplate = (jobAssertions: string, exports: string) => `const utils = require('../utils/utils'); ${jobAssertions} ${exports} `; -const testFileTemplate = (workflowName) => `const path = require('path'); +const testFileTemplate = (workflowName: string) => `const path = require('path'); const kieMockGithub = require('@kie/mock-github'); const utils = require('./utils/utils'); const assertions = require('./assertions/${workflowName}Assertions'); @@ -95,35 +96,42 @@ describe('test workflow ${workflowName}', () => { }); }); `; -const mockStepTemplate = (stepMockName, step, jobId) => ` + +const mockStepTemplate = (stepMockName: string, step: MockJobStep, jobId: string | undefined) => ` const ${stepMockName} = utils.createMockStep( - '${step.name || ''}', - '${step.name || ''}', + '${step.name ?? ''}', + '${step.name ?? ''}', ${jobId ? `'${jobId.toUpperCase()}'` : 'null'}, ${step.inputs ? JSON.stringify(step.inputs).replaceAll('"', "'") : 'null'}, ${step.envs ? JSON.stringify(step.envs).replaceAll('"', "'") : 'null'}, // add outputs if needed );`; -const stepAssertionTemplate = (step_name, job_id, step_message, inputs, envs) => ` +const stepAssertionTemplate = (stepName: string, jobId: string, stepMessage: string, inputs: string[] = [], envs: string[] = []) => { + const inputsString = inputs.map((input) => `{key: '${input}', value: '[FILL_IN]'}`).join(','); + const envsString = envs.map((env) => `{key: '${env}', value: '[FILL_IN]'}`).join(','); + + return ` utils.createStepAssertion( - '${step_name}', + '${stepName}', true, null, - '${job_id}', - '${step_message}', - [${_(inputs).map((input) => `{key: '${input}', value: '[FILL_IN]'}`)}], - [${_(envs).map((env) => `{key: '${env}', value: '[FILL_IN]'}`)}], + '${jobId}', + '${stepMessage}', + [${inputsString}], + [${envsString}], ),`; -const jobMocksTemplate = (jobMocksName, stepMocks) => ` -const ${jobMocksName} = [${_(stepMocks).map( - (stepMock) => ` - ${stepMock}`, -)} -];`; -const jobAssertionTemplate = (jobAssertionName, stepAssertions) => ` +}; + +const jobMocksTemplate = (jobMocksName: string, stepMocks: string[]) => { + const stepMocksString = stepMocks.map((stepMock) => `${stepMock}`).join(','); + + return `const ${jobMocksName} = [${stepMocksString} + ];`; +}; + +const jobAssertionTemplate = (jobAssertionName: string, stepAssertionsContent: string) => ` const ${jobAssertionName} = (workflowResult, didExecute = true) => { - const steps = [${stepAssertions} - ]; + const steps = [\n${stepAssertionsContent}\n]; for (const expectedStep of steps) { if (didExecute) { @@ -133,80 +141,84 @@ const ${jobAssertionName} = (workflowResult, didExecute = true) => { } } };`; -const mocksExportsTemplate = (jobMocks) => ` -module.exports = { - ${_(jobMocks).map((jobMock) => `${jobMock}`)} -};`; -const assertionsExportsTemplate = (jobAssertions) => ` -module.exports = { - ${_(jobAssertions).map((jobAssertion) => `${jobAssertion}`)} -};`; -const checkArguments = (args) => { +const mocksExportsTemplate = (jobMocks: string[]) => { + const jobMocksString = jobMocks.map((jobMock) => ` ${jobMock}: ${jobMock}`).join(',\n'); + + return `module.exports = {\n${jobMocksString}\n};\n`; +}; + +const assertionsExportsTemplate = (jobAssertions: string[]) => { + const assertionsString = jobAssertions.map((assertion) => ` ${assertion}: ${assertion}`).join(',\n'); + + return `module.exports = {\n${assertionsString}\n};\n`; +}; + +const checkArguments = (args: string[]) => { if (args.length > 0 && args[0]) { return; } console.warn('Please provide workflow file name'); exit(1); }; -const checkWorkflowFileName = (fileName) => { +const checkWorkflowFileName = (fileName: string) => { if (workflowFileRegex.test(fileName)) { return; } console.warn(`Please provide a valid workflow file name ([workflow].yml) instead of ${fileName}`); exit(1); }; -const checkWorkflowFilePath = (filePath) => { +const checkWorkflowFilePath = (filePath: PathLike) => { if (fs.existsSync(filePath)) { return; } - console.warn(`Provided workflow file does not exist: ${filePath}`); + console.warn(`Provided workflow file does not exist: ${filePath.toString()}`); exit(1); }; -const checkIfTestFileExists = (testsDirectory, testFileName) => { +const checkIfTestFileExists = (testsDirectory: string, testFileName: string) => { if (!fs.existsSync(path.join(testsDirectory, testFileName))) { return; } console.warn(`The test file ${testFileName} already exists, exiting`); exit(1); }; -const checkIfMocksFileExists = (mocksDirectory, mocksFileName) => { +const checkIfMocksFileExists = (mocksDirectory: string, mocksFileName: string) => { if (!fs.existsSync(path.join(mocksDirectory, mocksFileName))) { return; } console.warn(`The mocks file ${mocksFileName} already exists, exiting`); exit(1); }; -const checkIfAssertionsFileExists = (assertionsDirectory, assertionsFileName) => { +const checkIfAssertionsFileExists = (assertionsDirectory: string, assertionsFileName: string) => { if (!fs.existsSync(path.join(assertionsDirectory, assertionsFileName))) { return; } console.warn(`The assertions file ${assertionsFileName} already exists, exiting`); exit(1); }; -const parseWorkflowFile = (workflow) => { - const workflowJobs = {}; +const parseWorkflowFile = (workflow: YamlWorkflow) => { + const workflowJobs: Record = {}; Object.entries(workflow.jobs).forEach(([jobId, job]) => { workflowJobs[jobId] = { steps: [], }; job.steps.forEach((step) => { const workflowStep = { - name: step.name || '', - inputs: _.keys(step.with || {}) || [], - envs: _.keys(step.env || {}) || [], + name: step.name || '', // ? + inputs: Object.keys(step.with ?? {}), + envs: step.envs ?? [], }; workflowJobs[jobId].steps.push(workflowStep); }); }); return workflowJobs; }; -const getMockFileContent = (workflowName, jobs) => { +const getMockFileContent = (workflowName: string, jobs: Record) => { let content = ''; - const jobMocks = []; + const jobMocks: string[] = []; Object.entries(jobs).forEach(([jobId, job]) => { let mockStepsContent = `\n// ${jobId.toLowerCase()}`; - const stepMocks = []; + const stepMocks: string[] = []; job.steps.forEach((step) => { const stepMockName = `${workflowName.toUpperCase()}__${jobId.toUpperCase()}__${step.name .replaceAll(' ', '_') @@ -215,7 +227,7 @@ const getMockFileContent = (workflowName, jobs) => { .replaceAll('#', '') .toUpperCase()}__STEP_MOCK`; stepMocks.push(stepMockName); - mockStepsContent += mockStepTemplate(stepMockName, step, jobId); + mockStepsContent += mockStepTemplate(stepMockName, step, jobId); // ? }); const jobMocksName = `${workflowName.toUpperCase()}__${jobId.toUpperCase()}__STEP_MOCKS`; jobMocks.push(jobMocksName); @@ -224,9 +236,9 @@ const getMockFileContent = (workflowName, jobs) => { }); return mockFileTemplate(content, mocksExportsTemplate(jobMocks)); }; -const getAssertionsFileContent = (workflowName, jobs) => { +const getAssertionsFileContent = (jobs: Record) => { let content = ''; - const jobAssertions = []; + const jobAssertions: string[] = []; Object.entries(jobs).forEach(([jobId, job]) => { let stepAssertionsContent = ''; job.steps.forEach((step) => { @@ -238,12 +250,12 @@ const getAssertionsFileContent = (workflowName, jobs) => { }); return assertionFileTemplate(content, assertionsExportsTemplate(jobAssertions)); }; -const getTestFileContent = (workflowName) => testFileTemplate(workflowName); +const getTestFileContent = (workflowName: string) => testFileTemplate(workflowName); -const call_args = process.argv.slice(2); -checkArguments(call_args); +const callArgs = process.argv.slice(2); +checkArguments(callArgs); -const workflowFileName = call_args[0]; +const workflowFileName = callArgs[0]; checkWorkflowFileName(workflowFileName); const workflowName = workflowFileName.slice(0, -4); @@ -268,13 +280,13 @@ console.log(`Creating mock file ${mockFilePath}`); fs.writeFileSync(mockFilePath, mockFileContent); console.log(`Mock file ${mockFilePath} created`); -const assertionsFileContent = getAssertionsFileContent(workflowName, workflowJobs); +const assertionsFileContent = getAssertionsFileContent(workflowJobs); const assertionsFilePath = path.join(workflowTestAssertionsDirectory, workflowTestAssertionsFileName); console.log(`Creating assertions file ${assertionsFilePath}`); fs.writeFileSync(assertionsFilePath, assertionsFileContent); console.log(`Assertions file ${assertionsFilePath} created`); -const testFileContent = getTestFileContent(workflowName, workflowJobs); +const testFileContent = getTestFileContent(workflowName); const testFilePath = path.join(workflowTestsDirectory, workflowTestFileName); console.log(`Creating test file ${testFilePath}`); fs.writeFileSync(testFilePath, testFileContent); diff --git a/workflow_tests/utils/utils.js b/workflow_tests/utils/utils.ts similarity index 66% rename from workflow_tests/utils/utils.js rename to workflow_tests/utils/utils.ts index 32e106cfb1de..36e6cccd87fa 100644 --- a/workflow_tests/utils/utils.js +++ b/workflow_tests/utils/utils.ts @@ -1,9 +1,23 @@ -const yaml = require('yaml'); -const fs = require('fs'); -const path = require('path'); +import fs from 'fs'; +import path from 'path'; +import yaml from 'yaml'; +import type {ExtendedAct} from './ExtendedAct'; +import type {MockJobStep} from './JobMocker'; + +type EventOptions = { + action: string; +}; -function setUpActParams(act, event = null, eventOptions = null, secrets = null, githubToken = null, envVars = null, inputs = null) { - let updated_act = act; +function setUpActParams( + act: ExtendedAct, + event = null, + eventOptions: EventOptions | null = null, + secrets: Record | null = null, + githubToken: string | null = null, + envVars: Record | null = null, + inputs: Record | null = null, +) { + let updatedAct = act; if (event && eventOptions) { // according to `Act` docs event data should be under the key with the event name (`[event]: eventOptions`), but @@ -13,39 +27,49 @@ function setUpActParams(act, event = null, eventOptions = null, secrets = null, [event]: eventOptions, ...eventOptions, }; - updated_act = updated_act.setEvent(eventData); + updatedAct = updatedAct.setEvent(eventData); } if (secrets) { Object.entries(secrets).forEach(([key, value]) => { - updated_act = updated_act.setSecret(key, value); + updatedAct = updatedAct.setSecret(key, value); }); } if (githubToken) { - updated_act = updated_act.setGithubToken(githubToken); + updatedAct = updatedAct.setGithubToken(githubToken); } if (envVars) { Object.entries(envVars).forEach(([key, value]) => { - updated_act = updated_act.setEnv(key, value); + updatedAct = updatedAct.setEnv(key, value); }); } if (inputs) { Object.entries(inputs).forEach(([key, value]) => { - updated_act = updated_act.setInput(key, value); + updatedAct = updatedAct.setInput(key, value); }); } - return updated_act; + return updatedAct; } -function createMockStep(name, message, job_id = null, inputs = null, in_envs = null, outputs = null, out_envs = null, isSuccessful = true, id = null) { +function createMockStep( + name: string, + message: string, + jobId: string | null = null, + inputs: string[] | null = null, + inEnvs: string[] | null = null, + outputs: Record | null = null, + outEnvs: Record | null = null, + isSuccessful = true, + id = null, +) { const mockStepName = name; let mockWithCommand = 'echo [MOCK]'; - if (job_id) { - mockWithCommand += ` [${job_id}]`; + if (jobId) { + mockWithCommand += ` [${jobId}]`; } mockWithCommand += ` ${message}`; if (inputs) { @@ -53,8 +77,8 @@ function createMockStep(name, message, job_id = null, inputs = null, in_envs = n mockWithCommand += `, ${input}="\${{ inputs.${input} && inputs.${input} || github.event.inputs.${input} }}"`; }); } - if (in_envs) { - in_envs.forEach((env) => { + if (inEnvs) { + inEnvs.forEach((env) => { mockWithCommand += `, ${env}="\${{ env.${env} }}"`; }); } @@ -63,15 +87,15 @@ function createMockStep(name, message, job_id = null, inputs = null, in_envs = n mockWithCommand += `\necho "${key}=${value}" >> "$GITHUB_OUTPUT"`; }); } - if (out_envs) { - Object.entries(out_envs).forEach(([key, value]) => { + if (outEnvs) { + Object.entries(outEnvs).forEach(([key, value]) => { mockWithCommand += `\necho "${key}=${value}" >> "$GITHUB_ENV"`; }); } if (!isSuccessful) { mockWithCommand += '\nexit 1'; } - const mockStep = { + const mockStep: MockJobStep = { name: mockStepName, mockWith: mockWithCommand, }; @@ -81,10 +105,19 @@ function createMockStep(name, message, job_id = null, inputs = null, in_envs = n return mockStep; } -function createStepAssertion(name, isSuccessful = true, expectedOutput = null, jobId = null, message = null, inputs = null, envs = null) { +function createStepAssertion( + name: string, + isSuccessful = true, + expectedOutput = null, + jobId: string | null = null, + message: string | null = null, + // Replace arrays with records + inputs: Array<{key: string; value: string}> | null = null, + envs: Array<{key: string; value: string}> | null = null, +) { const stepName = `Main ${name}`; const stepStatus = isSuccessful ? 0 : 1; - let stepOutput; + let stepOutput: string; if (expectedOutput !== undefined && expectedOutput !== null) { stepOutput = expectedOutput; } else { @@ -113,7 +146,7 @@ function createStepAssertion(name, isSuccessful = true, expectedOutput = null, j }; } -function setJobRunners(act, jobs, workflowPath) { +function setJobRunners(act: ExtendedAct, jobs: Record, workflowPath: string) { if (!act || !jobs || !workflowPath) { return act; } @@ -127,11 +160,12 @@ function setJobRunners(act, jobs, workflowPath) { return act; } -function deepCopy(originalObject) { +function deepCopy(originalObject: T): T { + // eslint-disable-next-line @typescript-eslint/no-unsafe-return return JSON.parse(JSON.stringify(originalObject)); } -function getLogFilePath(workflowName, testName) { +function getLogFilePath(workflowName: string, testName: string) { const logsDir = path.resolve(__dirname, '..', 'logs'); if (!fs.existsSync(logsDir)) { fs.mkdirSync(logsDir); From a8317715003ac1c12dec272cdc7818a5c7e6cc69 Mon Sep 17 00:00:00 2001 From: Abdelrahman Khattab Date: Tue, 12 Mar 2024 19:08:55 +0200 Subject: [PATCH 078/175] adding fallback values for the lat and lng --- .../iou/request/step/IOURequestStepWaypoint.tsx | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/pages/iou/request/step/IOURequestStepWaypoint.tsx b/src/pages/iou/request/step/IOURequestStepWaypoint.tsx index c8232b9cdb7b..96d355489f82 100644 --- a/src/pages/iou/request/step/IOURequestStepWaypoint.tsx +++ b/src/pages/iou/request/step/IOURequestStepWaypoint.tsx @@ -1,10 +1,10 @@ import {useNavigation} from '@react-navigation/native'; import React, {useMemo, useRef, useState} from 'react'; -import {View} from 'react-native'; import type {TextInput} from 'react-native'; +import {View} from 'react-native'; import type {Place} from 'react-native-google-places-autocomplete'; -import {withOnyx} from 'react-native-onyx'; import type {OnyxEntry} from 'react-native-onyx'; +import {withOnyx} from 'react-native-onyx'; import type {ValueOf} from 'type-fest'; import AddressSearch from '@components/AddressSearch'; import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView'; @@ -124,8 +124,10 @@ function IOURequestStepWaypoint({ // Therefore, we're going to save the waypoint as just the address, and the lat/long will be filled in on the backend if (isOffline && waypointValue) { const waypoint = { - address: waypointValue, + address: waypointValue ?? '', name: values.name ?? '', + lat: values.lat ?? 0, + lng: values.lng ?? 0, }; saveWaypoint(waypoint); } @@ -142,10 +144,10 @@ function IOURequestStepWaypoint({ const selectWaypoint = (values: Waypoint) => { const waypoint = { - lat: values.lat, - lng: values.lng, - address: values.address, - name: values.name, + lat: values.lat ?? 0, + lng: values.lng ?? 0, + address: values.address ?? '', + name: values.name ?? '', }; Transaction.saveWaypoint(transactionID, pageIndex, waypoint, action === CONST.IOU.ACTION.CREATE); From a669de520285b8c7da12f755d6037470be9202ba Mon Sep 17 00:00:00 2001 From: John Lee Date: Tue, 12 Mar 2024 14:47:23 -0400 Subject: [PATCH 079/175] Fix Ping endpoint --- src/libs/NetworkConnection.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/NetworkConnection.ts b/src/libs/NetworkConnection.ts index f5c391aad09c..1a51391e8684 100644 --- a/src/libs/NetworkConnection.ts +++ b/src/libs/NetworkConnection.ts @@ -81,7 +81,7 @@ function subscribeToNetInfo(): void { // By default, NetInfo uses `/` for `reachabilityUrl` // When App is served locally (or from Electron) this address is always reachable - even offline // Using the API url ensures reachability is tested over internet - reachabilityUrl: `${CONFIG.EXPENSIFY.DEFAULT_API_ROOT}api?command=Ping`, + reachabilityUrl: `${CONFIG.EXPENSIFY.DEFAULT_API_ROOT}api/Ping`, reachabilityMethod: 'GET', reachabilityTest: (response) => { if (!response.ok) { From 9c196a4468f8517d3432a944e5defdf09ba93f65 Mon Sep 17 00:00:00 2001 From: BrtqKr Date: Wed, 13 Mar 2024 08:44:42 +0100 Subject: [PATCH 080/175] cleanup --- package.json | 2 +- workflow_tests/utils/JobMocker.ts | 18 +++++++++--------- workflow_tests/utils/preGenerateTest.ts | 4 ++-- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/package.json b/package.json index 7dab1aeaa386..d8a35d7753b9 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "test:e2e:dev": "ts-node tests/e2e/testRunner.js --config ./config.dev.js", "gh-actions-unused-styles": "./.github/scripts/findUnusedKeys.sh", "workflow-test": "./workflow_tests/scripts/runWorkflowTests.sh", - "workflow-test:generate": "ts-node workflow_tests/utils/preGenerateTest.js", + "workflow-test:generate": "ts-node workflow_tests/utils/preGenerateTest.ts", "setup-https": "mkcert -install && mkcert -cert-file config/webpack/certificate.pem -key-file config/webpack/key.pem dev.new.expensify.com localhost 127.0.0.1", "e2e-test-runner-build": "ncc build tests/e2e/testRunner.js -o tests/e2e/dist/" }, diff --git a/workflow_tests/utils/JobMocker.ts b/workflow_tests/utils/JobMocker.ts index 66e1e19e542b..3bbdaa118e0c 100644 --- a/workflow_tests/utils/JobMocker.ts +++ b/workflow_tests/utils/JobMocker.ts @@ -12,20 +12,20 @@ type YamlWorkflow = { type MockJob = { steps: MockJobStep[]; - uses?: string; // ? - secrets?: string[]; // ? - with?: string; // ? - outputs?: string[]; // ? - runsOn: string; // ? + uses?: string; + secrets?: string[]; + with?: string; + outputs?: string[]; + runsOn: string; }; type MockJobStep = { - id?: string; // ? + id?: string; name: string; - run?: string; // ? + run?: string; mockWith?: string; - with?: string; // ? - envs?: string[]; // ? + with?: string; + envs?: string[]; inputs?: string[]; }; diff --git a/workflow_tests/utils/preGenerateTest.ts b/workflow_tests/utils/preGenerateTest.ts index 485b7b30bb35..1a8bdfd85ed5 100644 --- a/workflow_tests/utils/preGenerateTest.ts +++ b/workflow_tests/utils/preGenerateTest.ts @@ -204,7 +204,7 @@ const parseWorkflowFile = (workflow: YamlWorkflow) => { }; job.steps.forEach((step) => { const workflowStep = { - name: step.name || '', // ? + name: step.name, inputs: Object.keys(step.with ?? {}), envs: step.envs ?? [], }; @@ -227,7 +227,7 @@ const getMockFileContent = (workflowName: string, jobs: Record Date: Wed, 13 Mar 2024 14:58:32 +0700 Subject: [PATCH 081/175] fix: stop camera usage --- src/pages/iou/request/step/IOURequestStepScan/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/iou/request/step/IOURequestStepScan/index.js b/src/pages/iou/request/step/IOURequestStepScan/index.js index 09eb85348ef7..7b1a5936a4ef 100644 --- a/src/pages/iou/request/step/IOURequestStepScan/index.js +++ b/src/pages/iou/request/step/IOURequestStepScan/index.js @@ -91,6 +91,7 @@ function IOURequestStepScan({ } navigator.mediaDevices.getUserMedia({video: {facingMode: {exact: 'environment'}, zoom: {ideal: 1}}}).then((stream) => { + _.forEach(stream.getTracks(), (track) => track.stop()); // Only Safari 17+ supports zoom constraint if (Browser.isMobileSafari() && stream.getTracks().length > 0) { const deviceId = _.chain(stream.getTracks()) @@ -103,7 +104,6 @@ function IOURequestStepScan({ return; } } - _.forEach(stream.getTracks(), (track) => track.stop()); if (!navigator.mediaDevices.enumerateDevices) { setVideoConstraints({facingMode: {exact: 'environment'}}); return; From 8a489d3a70907d5c24f7021e8a47def7047dcc79 Mon Sep 17 00:00:00 2001 From: Michal Muzyk Date: Wed, 13 Mar 2024 12:54:38 +0100 Subject: [PATCH 082/175] fix: after conflicts resolve --- src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx | 2 +- .../linkingConfig/FULL_SCREEN_TO_RHP_MAPPING.ts | 2 +- src/libs/actions/Policy.ts | 8 -------- .../distanceRates/PolicyDistanceRatesSettingsPage.tsx | 2 +- 4 files changed, 3 insertions(+), 11 deletions(-) diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx index 293dd15440b9..42932a78bd0a 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx @@ -262,7 +262,7 @@ const SettingsModalStackNavigator = createModalStackNavigator require('../../../pages/workspace/members/WorkspaceMemberDetailsPage').default as React.ComponentType, [SCREENS.WORKSPACE.MEMBER_DETAILS_ROLE_SELECTION]: () => require('../../../pages/workspace/members/WorkspaceMemberDetailsRoleSelectionPage').default as React.ComponentType, [SCREENS.WORKSPACE.CATEGORY_CREATE]: () => require('../../../pages/workspace/categories/CreateCategoryPage').default as React.ComponentType, - [SCREENS.WORKSPACE.CREATE_DISTANCE_RATE]: () => require('../../../workspace/distanceRates/CreateDistanceRatePage').default as React.ComponentType, + [SCREENS.WORKSPACE.CREATE_DISTANCE_RATE]: () => require('../../../pages/workspace/distanceRates/CreateDistanceRatePage').default as React.ComponentType, [SCREENS.WORKSPACE.DISTANCE_RATES_SETTINGS]: () => require('../../../pages/workspace/distanceRates/PolicyDistanceRatesSettingsPage').default as React.ComponentType, [SCREENS.WORKSPACE.TAGS_SETTINGS]: () => require('../../../pages/workspace/tags/WorkspaceTagsSettingsPage').default as React.ComponentType, [SCREENS.WORKSPACE.TAGS_EDIT]: () => require('../../../pages/workspace/tags/WorkspaceEditTagsPage').default as React.ComponentType, diff --git a/src/libs/Navigation/linkingConfig/FULL_SCREEN_TO_RHP_MAPPING.ts b/src/libs/Navigation/linkingConfig/FULL_SCREEN_TO_RHP_MAPPING.ts index da56b98519d4..905c62e5f812 100755 --- a/src/libs/Navigation/linkingConfig/FULL_SCREEN_TO_RHP_MAPPING.ts +++ b/src/libs/Navigation/linkingConfig/FULL_SCREEN_TO_RHP_MAPPING.ts @@ -13,7 +13,7 @@ const FULL_SCREEN_TO_RHP_MAPPING: Partial> = { ], [SCREENS.WORKSPACE.TAGS]: [SCREENS.WORKSPACE.TAGS_SETTINGS, SCREENS.WORKSPACE.TAGS_EDIT, SCREENS.WORKSPACE.TAG_CREATE], [SCREENS.WORKSPACE.CATEGORIES]: [SCREENS.WORKSPACE.CATEGORY_CREATE, SCREENS.WORKSPACE.CATEGORY_SETTINGS, SCREENS.WORKSPACE.CATEGORIES_SETTINGS], - [SCREENS.WORKSPACE.DISTANCE_RATES]: [SCREENS.WORKSPACE.CREATE_DISTANCE_RATE], + [SCREENS.WORKSPACE.DISTANCE_RATES]: [SCREENS.WORKSPACE.CREATE_DISTANCE_RATE, SCREENS.WORKSPACE.DISTANCE_RATES_SETTINGS], }; export default FULL_SCREEN_TO_RHP_MAPPING; diff --git a/src/libs/actions/Policy.ts b/src/libs/actions/Policy.ts index cb03857c0507..22370983e4bb 100644 --- a/src/libs/actions/Policy.ts +++ b/src/libs/actions/Policy.ts @@ -3536,10 +3536,6 @@ function clearCreateDistanceRateError(policyID: string, currentRates: Record Date: Wed, 13 Mar 2024 13:15:43 +0100 Subject: [PATCH 083/175] config jest ts --- package-lock.json | 1460 ++++----------------------- package.json | 1 + workflow_tests/jest.config.js | 1 + workflow_tests/utils/ExtendedAct.ts | 2 +- workflow_tests/utils/utils.ts | 11 +- 5 files changed, 201 insertions(+), 1274 deletions(-) diff --git a/package-lock.json b/package-lock.json index 81686286bf1c..2986136f8a98 100644 --- a/package-lock.json +++ b/package-lock.json @@ -234,6 +234,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", @@ -5960,30 +5961,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", @@ -6099,30 +6076,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", @@ -6204,94 +6157,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", @@ -6306,94 +6171,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", @@ -6433,94 +6210,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", @@ -6535,94 +6224,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", @@ -6664,30 +6265,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", @@ -6823,100 +6400,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", @@ -6955,30 +6438,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", @@ -7061,19 +6520,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": { @@ -9440,6 +8899,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", @@ -9462,6 +8944,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", @@ -9478,6 +8975,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", @@ -9497,6 +9002,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", @@ -21227,18 +20743,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", @@ -25046,6 +24561,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", @@ -35690,30 +35217,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", @@ -35818,30 +35321,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", @@ -36004,30 +35483,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", @@ -36206,30 +35661,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", @@ -36325,30 +35756,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", @@ -36360,55 +35767,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", @@ -36462,15 +35820,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", @@ -36537,18 +35886,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", @@ -36626,94 +35963,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", @@ -36786,75 +36035,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", @@ -36891,17 +36071,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", @@ -37016,30 +36185,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", @@ -37117,94 +36262,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", @@ -37359,30 +36416,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", @@ -37524,30 +36557,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", @@ -37648,30 +36657,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", @@ -37762,30 +36747,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", @@ -37866,30 +36827,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", @@ -38210,30 +37147,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", @@ -38351,100 +37264,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", @@ -39226,6 +38045,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", @@ -45137,6 +43962,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", @@ -45159,6 +44007,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", @@ -45201,6 +44064,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", @@ -45255,6 +44126,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", @@ -50317,6 +49199,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 d8a35d7753b9..487e345e28dd 100644 --- a/package.json +++ b/package.json @@ -283,6 +283,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/workflow_tests/jest.config.js b/workflow_tests/jest.config.js index c8a4534764e3..cecdf8589d7f 100644 --- a/workflow_tests/jest.config.js +++ b/workflow_tests/jest.config.js @@ -2,6 +2,7 @@ module.exports = { verbose: true, transform: { '^.+\\.jsx?$': 'babel-jest', + '^.+\\.tsx?$': 'ts-jest', }, clearMocks: true, resetMocks: true, diff --git a/workflow_tests/utils/ExtendedAct.ts b/workflow_tests/utils/ExtendedAct.ts index f471292b1509..addd59be43c7 100644 --- a/workflow_tests/utils/ExtendedAct.ts +++ b/workflow_tests/utils/ExtendedAct.ts @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/dot-notation */ // This eslint-disable comment is here to allow accessing private properties in the Act class import type {RunOpts, Workflow} from '@kie/act-js'; -import kieActJs from '@kie/act-js'; +import * as kieActJs from '@kie/act-js'; import path from 'path'; import {JobMocker} from './JobMocker'; import type {MockJob} from './JobMocker'; diff --git a/workflow_tests/utils/utils.ts b/workflow_tests/utils/utils.ts index 36e6cccd87fa..d6db1ff8a92b 100644 --- a/workflow_tests/utils/utils.ts +++ b/workflow_tests/utils/utils.ts @@ -200,13 +200,4 @@ const FILES_TO_COPY_INTO_TEST_REPO = [ }, ]; -module.exports = { - setUpActParams, - createMockStep, - createStepAssertion, - setJobRunners, - deepCopy, - getLogFilePath, - FILES_TO_COPY_INTO_TEST_REPO, - removeMockRepoDir, -}; +export {setUpActParams, createMockStep, createStepAssertion, setJobRunners, deepCopy, getLogFilePath, FILES_TO_COPY_INTO_TEST_REPO, removeMockRepoDir}; From 3cf6a2a98fdb6ca38ac9dee063cda4a4d10d69f9 Mon Sep 17 00:00:00 2001 From: Michal Muzyk Date: Wed, 13 Mar 2024 13:16:03 +0100 Subject: [PATCH 084/175] fix: update error message --- src/libs/actions/Policy.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libs/actions/Policy.ts b/src/libs/actions/Policy.ts index 22370983e4bb..641dd06a97e8 100644 --- a/src/libs/actions/Policy.ts +++ b/src/libs/actions/Policy.ts @@ -3574,7 +3574,7 @@ function setPolicyDistanceRatesUnit(policyID: string, currentCustomUnit: CustomU customUnits: { [currentCustomUnit.customUnitID]: { ...currentCustomUnit, - errors: ErrorUtils.getMicroSecondOnyxError('workspace.distanceRates.errors.updateRateUnitGenericFailureMessage'), + errors: ErrorUtils.getMicroSecondOnyxError('common.genericErrorMessage'), pendingAction: null, }, }, @@ -3629,7 +3629,7 @@ function setPolicyDistanceRatesDefaultCategory(policyID: string, currentCustomUn customUnits: { [currentCustomUnit.customUnitID]: { ...currentCustomUnit, - errors: ErrorUtils.getMicroSecondOnyxError('workspace.distanceRates.errors.updateRateDefaultCategoryGenericFailureMessage'), + errors: ErrorUtils.getMicroSecondOnyxError('common.genericErrorMessage'), pendingAction: null, }, }, From 3e5fe1dcb929e909f93d72ed9edc2ff07619c17b Mon Sep 17 00:00:00 2001 From: BrtqKr Date: Wed, 13 Mar 2024 14:53:35 +0100 Subject: [PATCH 085/175] review fixes --- workflow_tests/utils/ExtendedAct.ts | 2 +- workflow_tests/utils/preGenerateTest.ts | 3 +-- workflow_tests/utils/utils.ts | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/workflow_tests/utils/ExtendedAct.ts b/workflow_tests/utils/ExtendedAct.ts index addd59be43c7..99b8551337b8 100644 --- a/workflow_tests/utils/ExtendedAct.ts +++ b/workflow_tests/utils/ExtendedAct.ts @@ -8,7 +8,7 @@ import type {MockJob} from './JobMocker'; type ExtendedActOpts = RunOpts & {actor?: string; workflowFile?: string; mockJobs?: Record}; -// @ts-expect-error Override shouldn't be done on private methods - wait until the issue is resolved +// @ts-expect-error Override shouldn't be done on private methods wait until https://github.com/kiegroup/act-js/issues/77 is resolved or try to create a params workaround class ExtendedAct extends kieActJs.Act { async parseRunOpts(opts?: ExtendedActOpts) { const {cwd, actArguments, proxy} = await super['parseRunOpts'](opts); diff --git a/workflow_tests/utils/preGenerateTest.ts b/workflow_tests/utils/preGenerateTest.ts index 1a8bdfd85ed5..1bc5a01975e7 100644 --- a/workflow_tests/utils/preGenerateTest.ts +++ b/workflow_tests/utils/preGenerateTest.ts @@ -125,8 +125,7 @@ const stepAssertionTemplate = (stepName: string, jobId: string, stepMessage: str const jobMocksTemplate = (jobMocksName: string, stepMocks: string[]) => { const stepMocksString = stepMocks.map((stepMock) => `${stepMock}`).join(','); - return `const ${jobMocksName} = [${stepMocksString} - ];`; + return `const ${jobMocksName} = [${stepMocksString}\n];`; }; const jobAssertionTemplate = (jobAssertionName: string, stepAssertionsContent: string) => ` diff --git a/workflow_tests/utils/utils.ts b/workflow_tests/utils/utils.ts index d6db1ff8a92b..7e477c6ab63d 100644 --- a/workflow_tests/utils/utils.ts +++ b/workflow_tests/utils/utils.ts @@ -160,7 +160,7 @@ function setJobRunners(act: ExtendedAct, jobs: Record, workflowP return act; } -function deepCopy(originalObject: T): T { +function deepCopy>(originalObject: TObject): TObject { // eslint-disable-next-line @typescript-eslint/no-unsafe-return return JSON.parse(JSON.stringify(originalObject)); } From f0719b2776b3e51ad089b758a7186f83130ef9bb Mon Sep 17 00:00:00 2001 From: BrtqKr Date: Wed, 13 Mar 2024 16:07:31 +0100 Subject: [PATCH 086/175] revert deepCopy signature --- workflow_tests/utils/utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/workflow_tests/utils/utils.ts b/workflow_tests/utils/utils.ts index 7e477c6ab63d..9583ec233e60 100644 --- a/workflow_tests/utils/utils.ts +++ b/workflow_tests/utils/utils.ts @@ -160,7 +160,7 @@ function setJobRunners(act: ExtendedAct, jobs: Record, workflowP return act; } -function deepCopy>(originalObject: TObject): TObject { +function deepCopy(originalObject: TObject): TObject { // eslint-disable-next-line @typescript-eslint/no-unsafe-return return JSON.parse(JSON.stringify(originalObject)); } From 9a9d55d09ff9b283ed9abb9947efcdd84164a62d Mon Sep 17 00:00:00 2001 From: Artem Makushov Date: Wed, 13 Mar 2024 17:21:44 +0100 Subject: [PATCH 087/175] initial edit page --- src/ONYXKEYS.ts | 6 +- src/ROUTES.ts | 4 + src/SCREENS.ts | 1 + src/languages/en.ts | 1 + src/languages/es.ts | 1 + .../API/parameters/RenamePolicyTagsParams.ts | 10 ++ src/libs/API/parameters/index.ts | 1 + src/libs/API/types.ts | 2 + .../AppNavigator/ModalStackNavigators.tsx | 1 + src/libs/Navigation/linkingConfig/config.ts | 6 + src/libs/Navigation/types.ts | 4 + src/libs/actions/Policy.ts | 71 +++++++++++ .../workspace/tags/WorkspaceCreateTagPage.tsx | 2 +- .../workspace/tags/WorkspaceEditTagPage.tsx | 114 ++++++++++++++++++ ...ceTagCreateForm.ts => WorkspaceTagForm.ts} | 4 +- src/types/form/index.ts | 2 +- 16 files changed, 223 insertions(+), 7 deletions(-) create mode 100644 src/libs/API/parameters/RenamePolicyTagsParams.ts create mode 100644 src/pages/workspace/tags/WorkspaceEditTagPage.tsx rename src/types/form/{WorkspaceTagCreateForm.ts => WorkspaceTagForm.ts} (78%) diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index 8c48cbad561f..5393519f693d 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -332,8 +332,8 @@ const ONYXKEYS = { WORKSPACE_SETTINGS_FORM: 'workspaceSettingsForm', WORKSPACE_CATEGORY_CREATE_FORM: 'workspaceCategoryCreate', WORKSPACE_CATEGORY_CREATE_FORM_DRAFT: 'workspaceCategoryCreateDraft', - WORKSPACE_TAG_CREATE_FORM: 'workspaceTagCreate', - WORKSPACE_TAG_CREATE_FORM_DRAFT: 'workspaceTagCreateDraft', + WORKSPACE_TAG_FORM: 'workspaceTagForm', + WORKSPACE_TAG_FORM_DRAFT: 'workspaceTagFormDraft', WORKSPACE_SETTINGS_FORM_DRAFT: 'workspaceSettingsFormDraft', WORKSPACE_DESCRIPTION_FORM: 'workspaceDescriptionForm', WORKSPACE_DESCRIPTION_FORM_DRAFT: 'workspaceDescriptionFormDraft', @@ -418,7 +418,7 @@ type OnyxFormValuesMapping = { [ONYXKEYS.FORMS.ADD_DEBIT_CARD_FORM]: FormTypes.AddDebitCardForm; [ONYXKEYS.FORMS.WORKSPACE_SETTINGS_FORM]: FormTypes.WorkspaceSettingsForm; [ONYXKEYS.FORMS.WORKSPACE_CATEGORY_CREATE_FORM]: FormTypes.WorkspaceCategoryCreateForm; - [ONYXKEYS.FORMS.WORKSPACE_TAG_CREATE_FORM]: FormTypes.WorkspaceTagCreateForm; + [ONYXKEYS.FORMS.WORKSPACE_TAG_FORM]: FormTypes.WorkspaceTagForm; [ONYXKEYS.FORMS.WORKSPACE_RATE_AND_UNIT_FORM]: FormTypes.WorkspaceRateAndUnitForm; [ONYXKEYS.FORMS.CLOSE_ACCOUNT_FORM]: FormTypes.CloseAccountForm; [ONYXKEYS.FORMS.PROFILE_SETTINGS_FORM]: FormTypes.ProfileSettingsForm; diff --git a/src/ROUTES.ts b/src/ROUTES.ts index ad2d9c10700b..9f014a47b4c0 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -585,6 +585,10 @@ const ROUTES = { route: 'settings/workspaces/:policyID/tags/edit', getRoute: (policyID: string) => `settings/workspaces/${policyID}/tags/edit` as const, }, + WORKSPACE_TAG_EDIT: { + route: 'workspace/:policyID/tags/:tagName/edit', + getRoute: (policyID: string, tagName: string) => `workspace/${policyID}/tags/${encodeURI(tagName)}/edit` as const, + }, WORKSPACE_TAXES: { route: 'settings/workspaces/:policyID/taxes', getRoute: (policyID: string) => `settings/workspaces/${policyID}/taxes` as const, diff --git a/src/SCREENS.ts b/src/SCREENS.ts index 6c742f08bfb7..db62371d4591 100644 --- a/src/SCREENS.ts +++ b/src/SCREENS.ts @@ -219,6 +219,7 @@ const SCREENS = { TAGS: 'Workspace_Tags', TAGS_SETTINGS: 'Tags_Settings', TAGS_EDIT: 'Tags_Edit', + TAG_EDIT: 'Tag_Edit', TAXES: 'Workspace_Taxes', TAG_CREATE: 'Tag_Create', CURRENCY: 'Workspace_Profile_Currency', diff --git a/src/languages/en.ts b/src/languages/en.ts index 6ec5983583fc..0054fd8326a4 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -1840,6 +1840,7 @@ export default { customTagName: 'Custom tag name', enableTag: 'Enable tag', addTag: 'Add tag', + editTag: 'Edit tag', subtitle: 'Tags add more detailed ways to classify costs.', emptyTags: { title: "You haven't created any tags", diff --git a/src/languages/es.ts b/src/languages/es.ts index c2eb6374affa..b7de31f792ed 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -1864,6 +1864,7 @@ export default { customTagName: 'Nombre de etiqueta personalizada', enableTag: 'Habilitar etiqueta', addTag: 'Añadir etiqueta', + editTag: 'Editar etiqueta', subtitle: 'Las etiquetas añaden formas más detalladas de clasificar los costos.', emptyTags: { title: 'No has creado ninguna etiqueta', diff --git a/src/libs/API/parameters/RenamePolicyTagsParams.ts b/src/libs/API/parameters/RenamePolicyTagsParams.ts new file mode 100644 index 000000000000..51686ade1b9e --- /dev/null +++ b/src/libs/API/parameters/RenamePolicyTagsParams.ts @@ -0,0 +1,10 @@ +type RenamePolicyTagsParams = { + policyID: string; + /** + * Stringified JSON object with type of following structure: + * {[oldName: string]: string;} where value is new tag name + */ + tags: string; +}; + +export default RenamePolicyTagsParams; diff --git a/src/libs/API/parameters/index.ts b/src/libs/API/parameters/index.ts index 25c336753203..09f69fe1f535 100644 --- a/src/libs/API/parameters/index.ts +++ b/src/libs/API/parameters/index.ts @@ -177,3 +177,4 @@ export type {default as OpenPolicyDistanceRatesPageParams} from './OpenPolicyDis export type {default as OpenPolicyTaxesPageParams} from './OpenPolicyTaxesPageParams'; export type {default as OpenPolicyMoreFeaturesPageParams} from './OpenPolicyMoreFeaturesPageParams'; export type {default as CreatePolicyTagsParams} from './CreatePolicyTagsParams'; +export type {default as RenamePolicyTagsParams} from './RenamePolicyTagsParams'; diff --git a/src/libs/API/types.ts b/src/libs/API/types.ts index 07f1ca09d7c5..f8f128c6d4e8 100644 --- a/src/libs/API/types.ts +++ b/src/libs/API/types.ts @@ -119,6 +119,7 @@ const WRITE_COMMANDS = { SET_WORKSPACE_CATEGORIES_ENABLED: 'SetWorkspaceCategoriesEnabled', CREATE_WORKSPACE_CATEGORIES: 'CreateWorkspaceCategories', CREATE_POLICY_TAG: 'CreatePolicyTag', + RENAME_POLICY_TAG: 'RenamePolicyTag', SET_WORKSPACE_REQUIRES_CATEGORY: 'SetWorkspaceRequiresCategory', DELETE_WORKSPACE_CATEGORIES: 'DeleteWorkspaceCategories', SET_POLICY_REQUIRES_TAG: 'SetPolicyRequiresTag', @@ -287,6 +288,7 @@ type WriteCommandParameters = { [WRITE_COMMANDS.SET_POLICY_REQUIRES_TAG]: Parameters.SetPolicyRequiresTag; [WRITE_COMMANDS.RENAME_POLICY_TAG_LIST]: Parameters.RenamePolicyTaglist; [WRITE_COMMANDS.CREATE_POLICY_TAG]: Parameters.CreatePolicyTagsParams; + [WRITE_COMMANDS.RENAME_POLICY_TAG]: Parameters.RenamePolicyTagsParams; [WRITE_COMMANDS.CREATE_TASK]: Parameters.CreateTaskParams; [WRITE_COMMANDS.CANCEL_TASK]: Parameters.CancelTaskParams; [WRITE_COMMANDS.EDIT_TASK_ASSIGNEE]: Parameters.EditTaskAssigneeParams; diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx index a4d7593cf750..f8ea306d1cef 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx @@ -266,6 +266,7 @@ const SettingsModalStackNavigator = createModalStackNavigator require('../../../pages/workspace/tags/WorkspaceTagsSettingsPage').default as React.ComponentType, [SCREENS.WORKSPACE.TAGS_EDIT]: () => require('../../../pages/workspace/tags/WorkspaceEditTagsPage').default as React.ComponentType, [SCREENS.WORKSPACE.TAG_CREATE]: () => require('../../../pages/workspace/tags/WorkspaceCreateTagPage').default as React.ComponentType, + [SCREENS.WORKSPACE.TAG_EDIT]: () => require('../../../pages/workspace/tags/WorkspaceEditTagPage').default as React.ComponentType, [SCREENS.REIMBURSEMENT_ACCOUNT]: () => require('../../../pages/ReimbursementAccount/ReimbursementAccountPage').default as React.ComponentType, [SCREENS.GET_ASSISTANCE]: () => require('../../../pages/GetAssistancePage').default as React.ComponentType, [SCREENS.SETTINGS.TWO_FACTOR_AUTH]: () => require('../../../pages/settings/Security/TwoFactorAuth/TwoFactorAuthPage').default as React.ComponentType, diff --git a/src/libs/Navigation/linkingConfig/config.ts b/src/libs/Navigation/linkingConfig/config.ts index 04bc53e7b542..aacc759c4bfd 100644 --- a/src/libs/Navigation/linkingConfig/config.ts +++ b/src/libs/Navigation/linkingConfig/config.ts @@ -292,6 +292,12 @@ const config: LinkingOptions['config'] = { [SCREENS.WORKSPACE.TAG_CREATE]: { path: ROUTES.WORKSPACE_TAG_CREATE.route, }, + [SCREENS.WORKSPACE.TAG_EDIT]: { + path: ROUTES.WORKSPACE_TAG_EDIT.route, + parse: { + tagName: (tagName: string) => decodeURI(tagName), + }, + }, [SCREENS.REIMBURSEMENT_ACCOUNT]: { path: ROUTES.BANK_ACCOUNT_WITH_STEP_TO_OPEN.route, exact: true, diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index da418625ff55..f58d45b76af8 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -185,6 +185,10 @@ type SettingsNavigatorParamList = { policyID: string; tagName: string; }; + [SCREENS.WORKSPACE.TAG_EDIT]: { + policyID: string; + tagName: string; + }; [SCREENS.WORKSPACE.MEMBER_DETAILS]: { policyID: string; accountID: string; diff --git a/src/libs/actions/Policy.ts b/src/libs/actions/Policy.ts index 2adcfd29e00d..a4aba7e1ad5b 100644 --- a/src/libs/actions/Policy.ts +++ b/src/libs/actions/Policy.ts @@ -2826,6 +2826,76 @@ function createPolicyTag(policyID: string, tagName: string) { API.write(WRITE_COMMANDS.CREATE_POLICY_TAG, parameters, onyxData); } +function renamePolicyTag(policyID: string, policyTag: {oldName: string; newName: string}) { + const tagListName = Object.keys(allPolicyTags?.[`${ONYXKEYS.COLLECTION.POLICY_TAGS}${policyID}`] ?? {})[0]; + const oldTag = allPolicyTags?.[`${ONYXKEYS.COLLECTION.POLICY_TAGS}${policyID}`]?.[policyTag.oldName] ?? {}; + const onyxData: OnyxData = { + optimisticData: [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.POLICY_TAGS}${policyID}`, + value: { + [tagListName]: { + tags: { + [policyTag.oldName]: null, + [policyTag.newName]: { + ...oldTag, + name: policyTag.newName, + pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE, + }, + }, + }, + }, + }, + ], + successData: [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.POLICY_TAGS}${policyID}`, + value: { + [tagListName]: { + tags: { + [policyTag.oldName]: null, + [policyTag.newName]: { + ...oldTag, + name: policyTag.newName, + errors: null, + pendingAction: null, + }, + }, + }, + }, + }, + ], + failureData: [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.POLICY_TAGS}${policyID}`, + value: { + [tagListName]: { + tags: { + [policyTag.newName]: null, + [policyTag.oldName]: { + ...oldTag, + name: policyTag.oldName, + errors: ErrorUtils.getMicroSecondOnyxError('workspace.categories.genericFailureMessage'), + pendingAction: null, + }, + }, + }, + }, + }, + ], + }; + + const parameters = { + policyID, + tags: JSON.stringify({[policyTag.oldName]: policyTag.newName}), + }; + + API.write(WRITE_COMMANDS.RENAME_POLICY_TAG, parameters, onyxData); +} + function setWorkspaceRequiresCategory(policyID: string, requiresCategory: boolean) { const onyxData: OnyxData = { optimisticData: [ @@ -3589,6 +3659,7 @@ export { openPolicyDistanceRatesPage, openPolicyMoreFeaturesPage, createPolicyTag, + renamePolicyTag, clearWorkspaceReimbursementErrors, deleteWorkspaceCategories, }; diff --git a/src/pages/workspace/tags/WorkspaceCreateTagPage.tsx b/src/pages/workspace/tags/WorkspaceCreateTagPage.tsx index 2df7621c17d3..dc2c17427651 100644 --- a/src/pages/workspace/tags/WorkspaceCreateTagPage.tsx +++ b/src/pages/workspace/tags/WorkspaceCreateTagPage.tsx @@ -23,7 +23,7 @@ import * as Policy from '@userActions/Policy'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type SCREENS from '@src/SCREENS'; -import INPUT_IDS from '@src/types/form/WorkspaceTagCreateForm'; +import INPUT_IDS from '@src/types/form/WorkspaceTagForm'; import type {PolicyTagList} from '@src/types/onyx'; type WorkspaceCreateTagPageOnyxProps = { diff --git a/src/pages/workspace/tags/WorkspaceEditTagPage.tsx b/src/pages/workspace/tags/WorkspaceEditTagPage.tsx new file mode 100644 index 000000000000..1ba3f88a3c68 --- /dev/null +++ b/src/pages/workspace/tags/WorkspaceEditTagPage.tsx @@ -0,0 +1,114 @@ +import type {StackScreenProps} from '@react-navigation/stack'; +import React, {useCallback} from 'react'; +import {Keyboard} from 'react-native'; +import {withOnyx} from 'react-native-onyx'; +import type {OnyxEntry} from 'react-native-onyx'; +import FormProvider from '@components/Form/FormProvider'; +import InputWrapper from '@components/Form/InputWrapper'; +import type {FormInputErrors, FormOnyxValues} from '@components/Form/types'; +import HeaderWithBackButton from '@components/HeaderWithBackButton'; +import ScreenWrapper from '@components/ScreenWrapper'; +import TextInput from '@components/TextInput'; +import useAutoFocusInput from '@hooks/useAutoFocusInput'; +import useLocalize from '@hooks/useLocalize'; +import useThemeStyles from '@hooks/useThemeStyles'; +import * as ErrorUtils from '@libs/ErrorUtils'; +import Navigation from '@libs/Navigation/Navigation'; +import * as PolicyUtils from '@libs/PolicyUtils'; +import * as ValidationUtils from '@libs/ValidationUtils'; +import type {SettingsNavigatorParamList} from '@navigation/types'; +import AdminPolicyAccessOrNotFoundWrapper from '@pages/workspace/AdminPolicyAccessOrNotFoundWrapper'; +import PaidPolicyAccessOrNotFoundWrapper from '@pages/workspace/PaidPolicyAccessOrNotFoundWrapper'; +import * as Policy from '@userActions/Policy'; +import CONST from '@src/CONST'; +import ONYXKEYS from '@src/ONYXKEYS'; +import ROUTES from '@src/ROUTES'; +import type SCREENS from '@src/SCREENS'; +import INPUT_IDS from '@src/types/form/WorkspaceTagForm'; +import type {PolicyTagList} from '@src/types/onyx'; + +type WorkspaceEditTagPageOnyxProps = { + /** All policy tags */ + policyTags: OnyxEntry; +}; + +type EditTagPageProps = WorkspaceEditTagPageOnyxProps & StackScreenProps; + +function EditTagPage({route, policyTags}: EditTagPageProps) { + const styles = useThemeStyles(); + const {translate} = useLocalize(); + const {inputCallbackRef} = useAutoFocusInput(); + + const validate = useCallback( + (values: FormOnyxValues) => { + const errors: FormInputErrors = {}; + const tagName = values.tagName.trim(); + const {tags} = PolicyUtils.getTagList(policyTags, 0); + + if (!ValidationUtils.isRequiredFulfilled(tagName)) { + errors.tagName = 'workspace.tags.tagRequiredError'; + } else if (tags?.[tagName]) { + errors.tagName = 'workspace.tags.existingTagError'; + } else if ([...tagName].length > CONST.TAG_NAME_LIMIT) { + // Uses the spread syntax to count the number of Unicode code points instead of the number of UTF-16 code units. + ErrorUtils.addErrorMessage(errors, 'tagName', ['common.error.characterLimitExceedCounter', {length: [...tagName].length, limit: CONST.TAG_NAME_LIMIT}]); + } + + return errors; + }, + [policyTags], + ); + + const editTag = useCallback( + (values: FormOnyxValues) => { + Policy.renamePolicyTag(route.params.policyID, {oldName: route.params.tagName, newName: values.tagName.trim()}); + Keyboard.dismiss(); + Navigation.goBack(ROUTES.WORKSPACE_TAGS.getRoute(route.params.policyID)); + }, + [route.params.policyID, route.params.tagName], + ); + + return ( + + + + + + + + + + + ); +} + +EditTagPage.displayName = 'EditTagPage'; + +export default withOnyx({ + policyTags: { + key: ({route}) => `${ONYXKEYS.COLLECTION.POLICY_TAGS}${route?.params?.policyID}`, + }, +})(EditTagPage); diff --git a/src/types/form/WorkspaceTagCreateForm.ts b/src/types/form/WorkspaceTagForm.ts similarity index 78% rename from src/types/form/WorkspaceTagCreateForm.ts rename to src/types/form/WorkspaceTagForm.ts index 9a9670d84ae8..a6cc4c6c37cd 100644 --- a/src/types/form/WorkspaceTagCreateForm.ts +++ b/src/types/form/WorkspaceTagForm.ts @@ -7,12 +7,12 @@ const INPUT_IDS = { type InputID = ValueOf; -type WorkspaceTagCreateForm = Form< +type WorkspaceTagForm = Form< InputID, { [INPUT_IDS.TAG_NAME]: string; } >; -export type {WorkspaceTagCreateForm}; +export type {WorkspaceTagForm}; export default INPUT_IDS; diff --git a/src/types/form/index.ts b/src/types/form/index.ts index 5a574de3db54..01c682e54e14 100644 --- a/src/types/form/index.ts +++ b/src/types/form/index.ts @@ -39,5 +39,5 @@ export type {WorkspaceSettingsForm} from './WorkspaceSettingsForm'; export type {ReportPhysicalCardForm} from './ReportPhysicalCardForm'; export type {WorkspaceDescriptionForm} from './WorkspaceDescriptionForm'; export type {PolicyTagNameForm} from './PolicyTagNameForm'; -export type {WorkspaceTagCreateForm} from './WorkspaceTagCreateForm'; +export type {WorkspaceTagForm} from './WorkspaceTagForm'; export type {default as Form} from './Form'; From 7155c3fda8730d8c23883b6a9d7fde8ac86988c6 Mon Sep 17 00:00:00 2001 From: Florent De Neve Date: Wed, 13 Mar 2024 12:59:32 -0400 Subject: [PATCH 088/175] Update tagSelection and categorySelection copies --- src/languages/en.ts | 4 ++-- src/pages/EditRequestTagPage.js | 2 +- src/pages/iou/request/step/IOURequestStepTag.js | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/languages/en.ts b/src/languages/en.ts index 6ec5983583fc..976bd0269b04 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -657,8 +657,8 @@ export default { `changed the distance to ${newDistanceToDisplay} (previously ${oldDistanceToDisplay}), which updated the amount to ${newAmountToDisplay} (previously ${oldAmountToDisplay})`, threadRequestReportName: ({formattedAmount, comment}: ThreadRequestReportNameParams) => `${formattedAmount} ${comment ? `for ${comment}` : 'request'}`, threadSentMoneyReportName: ({formattedAmount, comment}: ThreadSentMoneyReportNameParams) => `${formattedAmount} sent${comment ? ` for ${comment}` : ''}`, - tagSelection: ({tagName}: TagSelectionParams) => `Select a ${tagName} to add additional organization to your money.`, - categorySelection: 'Select a category to add additional organization to your money.', + tagSelection: 'Select a tag to better organize your spend.', + categorySelection: 'Select a category to better organize your spend.', error: { invalidCategoryLength: 'The length of the category chosen exceeds the maximum allowed (255). Please choose a different or shorten the category name first.', invalidAmount: 'Please enter a valid amount before continuing.', diff --git a/src/pages/EditRequestTagPage.js b/src/pages/EditRequestTagPage.js index 74643afa347f..b64cb925a213 100644 --- a/src/pages/EditRequestTagPage.js +++ b/src/pages/EditRequestTagPage.js @@ -49,7 +49,7 @@ function EditRequestTagPage({defaultTag, policyID, tagName, tagIndex, onSubmit}) title={tagName || translate('common.tag')} onBackButtonPress={Navigation.goBack} /> - {translate('iou.tagSelection', {tagName: tagName || translate('common.tag')})} + {translate('iou.tagSelection')} {({insets}) => ( <> - {translate('iou.tagSelection', {tagName: policyTagListName})} + {translate('iou.tagSelection')} Date: Wed, 13 Mar 2024 13:07:20 -0400 Subject: [PATCH 089/175] fix spanish too --- src/languages/es.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/languages/es.ts b/src/languages/es.ts index c2eb6374affa..3dea318760cd 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -652,7 +652,7 @@ export default { `cambió la distancia a ${newDistanceToDisplay} (previamente ${oldDistanceToDisplay}), lo que cambió el importe a ${newAmountToDisplay} (previamente ${oldAmountToDisplay})`, threadRequestReportName: ({formattedAmount, comment}: ThreadRequestReportNameParams) => `${comment ? `${formattedAmount} para ${comment}` : `Solicitud de ${formattedAmount}`}`, threadSentMoneyReportName: ({formattedAmount, comment}: ThreadSentMoneyReportNameParams) => `${formattedAmount} enviado${comment ? ` para ${comment}` : ''}`, - tagSelection: ({tagName}: TagSelectionParams) => `Seleccione una ${tagName} para organizar mejor tu dinero.`, + tagSelection: 'Selecciona un tag para organizar mejor tu dinero.', categorySelection: 'Seleccione una categoría para organizar mejor tu dinero.', error: { invalidCategoryLength: 'El largo de la categoría escogida excede el máximo permitido (255). Por favor, escoge otra categoría o acorta la categoría primero.', From 7f3a461a5dc1b7e3e54e675d6df5363eb1e57065 Mon Sep 17 00:00:00 2001 From: Florent De Neve Date: Wed, 13 Mar 2024 13:08:10 -0400 Subject: [PATCH 090/175] remove unused TagSelectionParams --- src/languages/en.ts | 1 - src/languages/es.ts | 1 - 2 files changed, 2 deletions(-) diff --git a/src/languages/en.ts b/src/languages/en.ts index 976bd0269b04..dabf6a61da2b 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -68,7 +68,6 @@ import type { SizeExceededParams, SplitAmountParams, StepCounterParams, - TagSelectionParams, TaskCreatedActionParams, TermsParams, ThreadRequestReportNameParams, diff --git a/src/languages/es.ts b/src/languages/es.ts index 3dea318760cd..58d3a203da10 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -67,7 +67,6 @@ import type { SizeExceededParams, SplitAmountParams, StepCounterParams, - TagSelectionParams, TaskCreatedActionParams, TermsParams, ThreadRequestReportNameParams, From 2cd0925db14e84dc4bd048d0e2d25b70592e617e Mon Sep 17 00:00:00 2001 From: Florent De Neve Date: Wed, 13 Mar 2024 13:08:59 -0400 Subject: [PATCH 091/175] Better spanish --- src/languages/es.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/languages/es.ts b/src/languages/es.ts index 58d3a203da10..7f4c8c4e051f 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -651,7 +651,7 @@ export default { `cambió la distancia a ${newDistanceToDisplay} (previamente ${oldDistanceToDisplay}), lo que cambió el importe a ${newAmountToDisplay} (previamente ${oldAmountToDisplay})`, threadRequestReportName: ({formattedAmount, comment}: ThreadRequestReportNameParams) => `${comment ? `${formattedAmount} para ${comment}` : `Solicitud de ${formattedAmount}`}`, threadSentMoneyReportName: ({formattedAmount, comment}: ThreadSentMoneyReportNameParams) => `${formattedAmount} enviado${comment ? ` para ${comment}` : ''}`, - tagSelection: 'Selecciona un tag para organizar mejor tu dinero.', + tagSelection: 'Selecciona una etiqueta para organizar mejor tu dinero.', categorySelection: 'Seleccione una categoría para organizar mejor tu dinero.', error: { invalidCategoryLength: 'El largo de la categoría escogida excede el máximo permitido (255). Por favor, escoge otra categoría o acorta la categoría primero.', From 3316b0a545072f93fa53350398d3e78178321b19 Mon Sep 17 00:00:00 2001 From: Florent De Neve Date: Wed, 13 Mar 2024 13:54:05 -0400 Subject: [PATCH 092/175] remove unused type --- src/languages/types.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/languages/types.ts b/src/languages/types.ts index 2d04bdc156c9..6c2460f76168 100644 --- a/src/languages/types.ts +++ b/src/languages/types.ts @@ -211,8 +211,6 @@ type UpdatedTheDistanceParams = {newDistanceToDisplay: string; oldDistanceToDisp type FormattedMaxLengthParams = {formattedMaxLength: string}; -type TagSelectionParams = {tagName: string}; - type WalletProgramParams = {walletProgram: string}; type ViolationsAutoReportedRejectedExpenseParams = {rejectedBy: string; rejectReason: string}; @@ -362,7 +360,6 @@ export type { SizeExceededParams, SplitAmountParams, StepCounterParams, - TagSelectionParams, TaskCreatedActionParams, TermsParams, ThreadRequestReportNameParams, From 588e599bb4e3d48675985ad5817d5fb639fbe044 Mon Sep 17 00:00:00 2001 From: John Lee Date: Wed, 13 Mar 2024 14:08:19 -0400 Subject: [PATCH 093/175] No more credentials include --- src/libs/HttpUtils.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/libs/HttpUtils.ts b/src/libs/HttpUtils.ts index 9c350ab05d81..842776d0c8dd 100644 --- a/src/libs/HttpUtils.ts +++ b/src/libs/HttpUtils.ts @@ -52,8 +52,6 @@ function processHTTPRequest(url: string, method: RequestType = 'get', body: Form signal: canCancel ? cancellationController.signal : undefined, method, body, - // We want to include the cookie accountID that is returned form the API - credentials: 'include', }) .then((response) => { // We are calculating the skew to minimize the delay when posting the messages From 3776262761d4d458c3702f4c658398b56a0839fc Mon Sep 17 00:00:00 2001 From: BrtqKr Date: Wed, 13 Mar 2024 21:20:10 +0100 Subject: [PATCH 094/175] fix StepIdentifier type --- workflow_tests/utils/utils.ts | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/workflow_tests/utils/utils.ts b/workflow_tests/utils/utils.ts index 9583ec233e60..76ab284f5bb9 100644 --- a/workflow_tests/utils/utils.ts +++ b/workflow_tests/utils/utils.ts @@ -1,16 +1,16 @@ +import type {StepIdentifier} from '@kie/act-js/build/src/step-mocker/step-mocker.types'; import fs from 'fs'; import path from 'path'; import yaml from 'yaml'; import type {ExtendedAct} from './ExtendedAct'; -import type {MockJobStep} from './JobMocker'; type EventOptions = { - action: string; + action?: string; }; function setUpActParams( act: ExtendedAct, - event = null, + event: string | null = null, eventOptions: EventOptions | null = null, secrets: Record | null = null, githubToken: string | null = null, @@ -65,7 +65,7 @@ function createMockStep( outEnvs: Record | null = null, isSuccessful = true, id = null, -) { +): StepIdentifier { const mockStepName = name; let mockWithCommand = 'echo [MOCK]'; if (jobId) { @@ -95,14 +95,16 @@ function createMockStep( if (!isSuccessful) { mockWithCommand += '\nexit 1'; } - const mockStep: MockJobStep = { + if (id) { + return { + id, + mockWith: mockWithCommand, + }; + } + return { name: mockStepName, mockWith: mockWithCommand, }; - if (id) { - mockStep.id = id; - } - return mockStep; } function createStepAssertion( @@ -111,7 +113,6 @@ function createStepAssertion( expectedOutput = null, jobId: string | null = null, message: string | null = null, - // Replace arrays with records inputs: Array<{key: string; value: string}> | null = null, envs: Array<{key: string; value: string}> | null = null, ) { @@ -165,7 +166,11 @@ function deepCopy(originalObject: TObject): TObject { return JSON.parse(JSON.stringify(originalObject)); } -function getLogFilePath(workflowName: string, testName: string) { +function getLogFilePath(workflowName: string, testName: string | undefined) { + if (!testName) { + throw new Error(); + } + const logsDir = path.resolve(__dirname, '..', 'logs'); if (!fs.existsSync(logsDir)) { fs.mkdirSync(logsDir); From 161c43d428f0784f430fb976daebb46b3af2e91f Mon Sep 17 00:00:00 2001 From: BrtqKr Date: Wed, 13 Mar 2024 22:04:05 +0100 Subject: [PATCH 095/175] adjust createMockStep --- workflow_tests/utils/utils.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/workflow_tests/utils/utils.ts b/workflow_tests/utils/utils.ts index 76ab284f5bb9..7fc57eed75ad 100644 --- a/workflow_tests/utils/utils.ts +++ b/workflow_tests/utils/utils.ts @@ -95,13 +95,15 @@ function createMockStep( if (!isSuccessful) { mockWithCommand += '\nexit 1'; } - if (id) { + if (!id) { return { - id, + name: mockStepName, mockWith: mockWithCommand, }; } + return { + id, name: mockStepName, mockWith: mockWithCommand, }; From de14e6669e44b818dd7001c11556936c9106dcd7 Mon Sep 17 00:00:00 2001 From: Michal Muzyk Date: Thu, 14 Mar 2024 12:07:36 +0100 Subject: [PATCH 096/175] fix: remove redundant error clearing --- src/libs/actions/Policy.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/libs/actions/Policy.ts b/src/libs/actions/Policy.ts index 9279874b1fc5..1d08ccf0c1d6 100644 --- a/src/libs/actions/Policy.ts +++ b/src/libs/actions/Policy.ts @@ -3620,7 +3620,6 @@ function setPolicyDistanceRatesUnit(policyID: string, currentCustomUnit: CustomU value: { customUnits: { [newCustomUnit.customUnitID]: { - errors: null, pendingAction: null, }, }, @@ -3675,7 +3674,6 @@ function setPolicyDistanceRatesDefaultCategory(policyID: string, currentCustomUn value: { customUnits: { [newCustomUnit.customUnitID]: { - errors: null, pendingAction: null, }, }, From 93589ed0571dd03ace0518bd2072b0b7a3cac95b Mon Sep 17 00:00:00 2001 From: Alberto Date: Thu, 14 Mar 2024 13:53:51 +0100 Subject: [PATCH 097/175] add constants --- src/CONST.ts | 15 +++++++++++++++ src/ONYXKEYS.ts | 3 +++ 2 files changed, 18 insertions(+) diff --git a/src/CONST.ts b/src/CONST.ts index fa44cda20720..69c2b502d84f 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -561,6 +561,21 @@ const CONST = { REPORT: 'report', PERSONAL_DETAIL: 'personalDetail', }, + + QUICK_ACTIONS: { + REQUEST_MANUAL: 'requestManual', + REQUEST_SCAN: 'requestScan', + REQUEST_DISTANCE: 'requestDistance', + SPLIT_MANUAL: 'splitManual', + SPLIT_SCAN: 'splitScan', + SPLIT_DISTANCE: 'splitDistance', + TRACK_MANUAL: 'trackManual', + TRACK_SCAN: 'trackScan', + TRACK_DISTANCE: 'trackDistance', + ASSIGN_TASK: 'assignTask', + SEND_MONEY: 'sendMoney', + }, + RECEIPT: { ICON_SIZE: 164, PERMISSION_GRANTED: 'granted', diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index 8c48cbad561f..b19499046661 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -131,6 +131,9 @@ const ONYXKEYS = { /** The NVP with the last distance rate used per policy */ NVP_LAST_SELECTED_DISTANCE_RATES: 'lastSelectedDistanceRates', + /** The NVP with the last action taken (for the Quick Action Button) */ + NVP_QUICK_ACTION_GLOBAL_CREATE: 'nvp_quickActionGlobalCreate', + /** Does this user have push notifications enabled for this device? */ PUSH_NOTIFICATIONS_ENABLED: 'pushNotificationsEnabled', From 9e05073ce95bb781e3a0a748baf8cbe8931849a6 Mon Sep 17 00:00:00 2001 From: Alberto Date: Thu, 14 Mar 2024 15:40:57 +0100 Subject: [PATCH 098/175] Add optimistic action for requests --- src/libs/actions/IOU.ts | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index af5c40836c74..411c4bf4f731 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -231,6 +231,14 @@ Onyx.connect({ }, }); +let quickAction: OnyxEntry = {}; +Onyx.connect({ + key: ONYXKEYS.NVP_QUICK_ACTION_GLOBAL_CREATE, + callback: (value) => { + quickAction = value; + }, +}); + /** * Initialize money request info * @param reportID to attach the transaction to @@ -462,6 +470,10 @@ function buildOnyxDataForMoneyRequest( const outstandingChildRequest = getOutstandingChildRequest(policy ?? {}, iouReport); const clearedPendingFields = Object.fromEntries(Object.keys(transaction.pendingFields ?? {}).map((key) => [key, null])); const optimisticData: OnyxUpdate[] = []; + let newQuickAction = isScanRequest ? CONST.QUICK_ACTIONS.REQUEST_SCAN : CONST.QUICK_ACTIONS.REQUEST_MANUAL; + if (TransactionUtils.isDistanceRequest(transaction)) { + newQuickAction = CONST.QUICK_ACTIONS.REQUEST_DISTANCE; + } if (chatReport) { optimisticData.push({ @@ -497,7 +509,17 @@ function buildOnyxDataForMoneyRequest( key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transaction.transactionID}`, value: transaction, }, - isNewChatReport + { + onyxMethod: Onyx.METHOD.SET, + key: ONYXKEYS.NVP_QUICK_ACTION_GLOBAL_CREATE, + value:{ + action: newQuickAction, + reportID: chatReport?.reportID, + isFirstQuickAction: isEmptyObject(quickAction); + }, + }, + + isNewChatReport ? { onyxMethod: Onyx.METHOD.SET, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport?.reportID}`, From c9f9224ed830ec19c49e077e8cbd7e7a1aeeb484 Mon Sep 17 00:00:00 2001 From: Alberto Date: Thu, 14 Mar 2024 15:45:27 +0100 Subject: [PATCH 099/175] Add onyx type --- src/types/onyx/QuickAction.ts | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 src/types/onyx/QuickAction.ts diff --git a/src/types/onyx/QuickAction.ts b/src/types/onyx/QuickAction.ts new file mode 100644 index 000000000000..d26482deb969 --- /dev/null +++ b/src/types/onyx/QuickAction.ts @@ -0,0 +1,18 @@ +import type {ValueOf} from 'type-fest'; +import type CONST from '@src/CONST'; + +type QuickAction = { + /** The action to take */ + action: ValueOf; + + /** ID of the report */ + reportID: string; + + /** ID of the target account for task actions */ + accountID?: number; + + /** True if it is the first quick action we store for this user */ + isFirstQuickAction?: boolean; +}; + +export default QuickAction; From fbc1d40dc1cdc31e0b934a9b09568af6de63801d Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Thu, 14 Mar 2024 09:09:43 -0600 Subject: [PATCH 100/175] sort tag list --- .../workspace/tags/WorkspaceTagsPage.tsx | 39 ++++++++++--------- 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/src/pages/workspace/tags/WorkspaceTagsPage.tsx b/src/pages/workspace/tags/WorkspaceTagsPage.tsx index 4ea8ba669b9b..de856df3e34f 100644 --- a/src/pages/workspace/tags/WorkspaceTagsPage.tsx +++ b/src/pages/workspace/tags/WorkspaceTagsPage.tsx @@ -18,6 +18,7 @@ import useNetwork from '@hooks/useNetwork'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import useWindowDimensions from '@hooks/useWindowDimensions'; +import localeCompare from '@libs/LocaleCompare'; import Navigation from '@libs/Navigation/Navigation'; import * as PolicyUtils from '@libs/PolicyUtils'; import type {WorkspacesCentralPaneNavigatorParamList} from '@navigation/types'; @@ -68,25 +69,27 @@ function WorkspaceTagsPage({policyTags, route}: WorkspaceTagsPageProps) { () => policyTagLists .map((policyTagList) => - Object.values(policyTagList.tags || []).map((value) => ({ - value: value.name, - text: value.name, - keyForList: value.name, - isSelected: !!selectedTags[value.name], - rightElement: ( - - - {value.enabled ? translate('workspace.common.enabled') : translate('workspace.common.disabled')} - - - + Object.values(policyTagList.tags || []) + .sort((a, b) => localeCompare(a.name, b.name)) + .map((value) => ({ + value: value.name, + text: value.name, + keyForList: value.name, + isSelected: !!selectedTags[value.name], + rightElement: ( + + + {value.enabled ? translate('workspace.common.enabled') : translate('workspace.common.disabled')} + + + + - - ), - })), + ), + })), ) .flat(), [policyTagLists, selectedTags, styles.alignSelfCenter, styles.flexRow, styles.label, styles.p1, styles.pl2, styles.textSupporting, theme.icon, translate], From 616922ae69c9993178dde03f56baf6b121248f8e Mon Sep 17 00:00:00 2001 From: John Lee Date: Thu, 14 Mar 2024 11:44:27 -0400 Subject: [PATCH 101/175] Update package --- package-lock.json | 1280 ++++++++++++++++++++------------------------- package.json | 25 +- 2 files changed, 582 insertions(+), 723 deletions(-) diff --git a/package-lock.json b/package-lock.json index bbe2ba76e621..dba282b0e96f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "new.expensify", - "version": "1.4.47-2", + "version": "1.4.52-0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "new.expensify", - "version": "1.4.47-2", + "version": "1.4.52-0", "hasInstallScript": true, "license": "MIT", "dependencies": { @@ -26,7 +26,7 @@ "@oguzhnatly/react-native-image-manipulator": "github:Expensify/react-native-image-manipulator#5cdae3d4455b03a04c57f50be3863e2fe6c92c52", "@onfido/react-native-sdk": "10.6.0", "@react-native-async-storage/async-storage": "1.21.0", - "@react-native-camera-roll/camera-roll": "5.4.0", + "@react-native-camera-roll/camera-roll": "7.4.0", "@react-native-clipboard/clipboard": "^1.13.2", "@react-native-community/geolocation": "^3.0.6", "@react-native-community/netinfo": "11.2.1", @@ -52,7 +52,7 @@ "date-fns-tz": "^2.0.0", "dom-serializer": "^0.2.2", "domhandler": "^4.3.0", - "expensify-common": "github:Expensify/expensify-common#7ce83cd75c7893dbea4b1517ff04b9589144eafe", + "expensify-common": "git+ssh://git@github.com/Expensify/expensify-common.git#615f4a8662cd1abea9fdeee4d04847197c5e36ae", "expo": "^50.0.3", "expo-av": "~13.10.4", "expo-image": "1.10.1", @@ -64,7 +64,7 @@ "lodash": "4.17.21", "lottie-react-native": "6.4.1", "mapbox-gl": "^2.15.0", - "onfido-sdk-ui": "13.6.1", + "onfido-sdk-ui": "14.15.0", "patch-package": "^8.0.0", "process": "^0.11.10", "prop-types": "^15.7.2", @@ -97,7 +97,7 @@ "react-native-linear-gradient": "^2.8.1", "react-native-localize": "^2.2.6", "react-native-modal": "^13.0.0", - "react-native-onyx": "2.0.10", + "react-native-onyx": "git+https://github.com/Expensify/react-native-onyx#cd778b55e419bf09ecf377b1e3ac013b7758434d", "react-native-pager-view": "6.2.2", "react-native-pdf": "6.7.3", "react-native-performance": "^5.1.0", @@ -106,10 +106,12 @@ "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-reanimated": "^3.7.1", + "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", + "react-native-share": "^10.0.2", "react-native-sound": "^0.11.2", "react-native-svg": "14.1.0", "react-native-tab-view": "^3.5.2", @@ -203,7 +205,7 @@ "diff-so-fancy": "^1.3.0", "dotenv": "^16.0.3", "electron": "^29.0.0", - "electron-builder": "24.6.4", + "electron-builder": "24.13.2", "eslint": "^7.6.0", "eslint-config-airbnb-typescript": "^17.1.0", "eslint-config-expensify": "^2.0.44", @@ -227,7 +229,6 @@ "prettier": "^2.8.8", "pusher-js-mock": "^0.3.3", "react-native-clean-project": "^4.0.0-alpha4.0", - "react-native-performance-flipper-reporter": "^2.0.0", "react-test-renderer": "18.2.0", "reassure": "^0.10.1", "setimmediate": "^1.0.5", @@ -3077,9 +3078,9 @@ } }, "node_modules/@electron/asar": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/@electron/asar/-/asar-3.2.5.tgz", - "integrity": "sha512-Ypahc2ElTj9YOrFvUHuoXv5Z/V1nPA5enlhmQapc578m/HZBHKTbqhoL5JZQjje2+/6Ti5AHh7Gj1/haeJa63Q==", + "version": "3.2.8", + "resolved": "https://registry.npmjs.org/@electron/asar/-/asar-3.2.8.tgz", + "integrity": "sha512-cmskk5M06ewHMZAplSiF4AlME3IrnnZhKnWbtwKVLRkdJkKyUVjMLhDIiPIx/+6zQWVlKX/LtmK9xDme7540Sg==", "dev": true, "dependencies": { "commander": "^5.0.0", @@ -3169,9 +3170,9 @@ } }, "node_modules/@electron/notarize": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@electron/notarize/-/notarize-2.1.0.tgz", - "integrity": "sha512-Q02xem1D0sg4v437xHgmBLxI2iz/fc0D4K7fiVWHa/AnW8o7D751xyKNXgziA6HrTOme9ul1JfWN5ark8WH1xA==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@electron/notarize/-/notarize-2.2.1.tgz", + "integrity": "sha512-aL+bFMIkpR0cmmj5Zgy0LMKEpgy43/hw5zadEArgmAMWWlKc5buwFvFT9G/o/YJkvXAJm5q3iuTuLaiaXW39sg==", "dev": true, "dependencies": { "debug": "^4.1.1", @@ -3230,9 +3231,9 @@ } }, "node_modules/@electron/universal": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@electron/universal/-/universal-1.4.1.tgz", - "integrity": "sha512-lE/U3UNw1YHuowNbTmKNs9UlS3En3cPgwM5MI+agIgr/B1hSze9NdOP0qn7boZaI9Lph8IDv3/24g9IxnJP7aQ==", + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@electron/universal/-/universal-1.5.1.tgz", + "integrity": "sha512-kbgXxyEauPJiQQUNG2VgUeyfQNFk6hBF11ISN2PNI6agUgPl55pv4eQmaqHzTAzchBvqZ2tQuRVaPStGf0mxGw==", "dev": true, "dependencies": { "@electron/asar": "^3.2.1", @@ -7713,16 +7714,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/@mediapipe/face_detection": { - "version": "0.4.1646425229", - "resolved": "https://registry.npmjs.org/@mediapipe/face_detection/-/face_detection-0.4.1646425229.tgz", - "integrity": "sha512-aeCN+fRAojv9ch3NXorP6r5tcGVLR3/gC1HmtqB0WEZBRXrdP6/3W/sGR0dHr1iT6ueiK95G9PVjbzFosf/hrg==" - }, - "node_modules/@mediapipe/face_mesh": { - "version": "0.4.1633559619", - "resolved": "https://registry.npmjs.org/@mediapipe/face_mesh/-/face_mesh-0.4.1633559619.tgz", - "integrity": "sha512-Vc8cdjxS5+O2gnjWH9KncYpUCVXT0h714KlWAsyqJvJbIgUJBqpppbIx8yWcAzBDxm/5cYSuBI5p5ySIPxzcEg==" - }, "node_modules/@mrmlnc/readdir-enhanced": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz", @@ -8054,153 +8045,6 @@ "integrity": "sha512-C9Br1BQqm6io6lvYHptlLcOHbzlaqxp9tS35P8Qj3pdiiYRTzU3KPvZ61rQ+ZnZ4FOQ6MwPsKsmB8+6WHkAY6Q==", "license": "MIT" }, - "node_modules/@onfido/active-video-capture": { - "version": "0.28.6", - "resolved": "https://registry.npmjs.org/@onfido/active-video-capture/-/active-video-capture-0.28.6.tgz", - "integrity": "sha512-RFUeKaOSjj/amPp6VzhVkq/7kIkutEnnttT9n5KDeD3Vx8a09KD3a/xvxdQppveHlDAYsdBP6LrJwSSpjXiprg==", - "dependencies": { - "@mediapipe/face_detection": "^0.4.1646425229", - "@mediapipe/face_mesh": "^0.4.1633559619", - "@onfido/castor": "^2.2.2", - "@onfido/castor-icons": "^2.12.0", - "@tensorflow-models/face-detection": "^1.0.1", - "@tensorflow-models/face-landmarks-detection": "^1.0.2", - "@tensorflow/tfjs-backend-wasm": "3.20.0", - "@tensorflow/tfjs-backend-webgl": "3.20.0", - "@tensorflow/tfjs-converter": "3.20.0", - "@tensorflow/tfjs-core": "3.20.0", - "preact": "10.11.3", - "react-webcam": "^7.2.0" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/@onfido/active-video-capture/node_modules/@tensorflow-models/face-landmarks-detection": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@tensorflow-models/face-landmarks-detection/-/face-landmarks-detection-1.0.5.tgz", - "integrity": "sha512-54XJPi8g29/MknJ33ZBrLsEzr9kw/dJtrJMMD3xrCrnRlfFQPIKQ5PI2Wml55Fz2p4U2hemzBB0/H+S94JddIQ==", - "dependencies": { - "rimraf": "^3.0.2" - }, - "peerDependencies": { - "@mediapipe/face_mesh": "~0.4.0", - "@tensorflow-models/face-detection": "~1.0.0", - "@tensorflow/tfjs-backend-webgl": "^3.12.0", - "@tensorflow/tfjs-converter": "^3.12.0", - "@tensorflow/tfjs-core": "^3.12.0" - } - }, - "node_modules/@onfido/active-video-capture/node_modules/@tensorflow/tfjs-backend-cpu": { - "version": "3.20.0", - "resolved": "https://registry.npmjs.org/@tensorflow/tfjs-backend-cpu/-/tfjs-backend-cpu-3.20.0.tgz", - "integrity": "sha512-gf075YaBLwSAAiUwa0D4GvYyUBhbJ1BVSivUNQmUfGKvIr2lIhF0qstBr033YTc3lhkbFSHEEPAHh/EfpqyjXQ==", - "dependencies": { - "@types/seedrandom": "^2.4.28", - "seedrandom": "^3.0.5" - }, - "engines": { - "yarn": ">= 1.3.2" - }, - "peerDependencies": { - "@tensorflow/tfjs-core": "3.20.0" - } - }, - "node_modules/@onfido/active-video-capture/node_modules/@tensorflow/tfjs-backend-wasm": { - "version": "3.20.0", - "resolved": "https://registry.npmjs.org/@tensorflow/tfjs-backend-wasm/-/tfjs-backend-wasm-3.20.0.tgz", - "integrity": "sha512-k+sDcrcPtGToLjKRffgtSqlcN4MC6g4hXWRarZfgvvyvFqpxVfVqrGYHGTirXdN47sKYhmcTSMvbM2quGaaQnA==", - "dependencies": { - "@tensorflow/tfjs-backend-cpu": "3.20.0", - "@types/emscripten": "~0.0.34" - }, - "peerDependencies": { - "@tensorflow/tfjs-core": "3.20.0" - } - }, - "node_modules/@onfido/active-video-capture/node_modules/@tensorflow/tfjs-backend-webgl": { - "version": "3.20.0", - "resolved": "https://registry.npmjs.org/@tensorflow/tfjs-backend-webgl/-/tfjs-backend-webgl-3.20.0.tgz", - "integrity": "sha512-SucbyQ08re3HvRgVfarRtKFIjNM4JvIAzcXmw4vaE/HrCtPEePkGO1VrmfQoN470EdUmGiwgqAjoyBvM2VOlVg==", - "dependencies": { - "@tensorflow/tfjs-backend-cpu": "3.20.0", - "@types/offscreencanvas": "~2019.3.0", - "@types/seedrandom": "^2.4.28", - "@types/webgl-ext": "0.0.30", - "@types/webgl2": "0.0.6", - "seedrandom": "^3.0.5" - }, - "engines": { - "yarn": ">= 1.3.2" - }, - "peerDependencies": { - "@tensorflow/tfjs-core": "3.20.0" - } - }, - "node_modules/@onfido/active-video-capture/node_modules/@tensorflow/tfjs-converter": { - "version": "3.20.0", - "resolved": "https://registry.npmjs.org/@tensorflow/tfjs-converter/-/tfjs-converter-3.20.0.tgz", - "integrity": "sha512-8EIYqtQwvSYw9GFNW2OFU8Qnl/FQF/kKAsQJoORYaZ419WJo+FIZWbAWDtCpJSAgkgoHH1jYWgV9H313cVmqxg==", - "peerDependencies": { - "@tensorflow/tfjs-core": "3.20.0" - } - }, - "node_modules/@onfido/active-video-capture/node_modules/@tensorflow/tfjs-core": { - "version": "3.20.0", - "resolved": "https://registry.npmjs.org/@tensorflow/tfjs-core/-/tfjs-core-3.20.0.tgz", - "integrity": "sha512-L16JyVA4a8jFJXFgB9/oYZxcGq/GfLypt5dMVTyedznARZZ9SiY/UMMbo3IKl9ZylG1dOVVTpjzV3EvBYfeJXw==", - "dependencies": { - "@types/long": "^4.0.1", - "@types/offscreencanvas": "~2019.3.0", - "@types/seedrandom": "^2.4.28", - "@types/webgl-ext": "0.0.30", - "@webgpu/types": "0.1.16", - "long": "4.0.0", - "node-fetch": "~2.6.1", - "seedrandom": "^3.0.5" - }, - "engines": { - "yarn": ">= 1.3.2" - } - }, - "node_modules/@onfido/active-video-capture/node_modules/@webgpu/types": { - "version": "0.1.16", - "resolved": "https://registry.npmjs.org/@webgpu/types/-/types-0.1.16.tgz", - "integrity": "sha512-9E61voMP4+Rze02jlTXud++Htpjyyk8vw5Hyw9FGRrmhHQg2GqbuOfwf5Klrb8vTxc2XWI3EfO7RUHMpxTj26A==" - }, - "node_modules/@onfido/castor": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@onfido/castor/-/castor-2.3.0.tgz", - "integrity": "sha512-FkydkjedS6b2g3SqgZMYnVRZvUs/MkaEuXXJWG9+LNc7DMFT1K8smOnNuHzkiM3cJhXL6yAADdKE0mg+ZIrucQ==", - "dependencies": { - "@onfido/castor-tokens": "^1.0.0-beta.6", - "csstype": "^3.1.1" - }, - "peerDependencies": { - "@onfido/castor-icons": ">=1.0.0" - } - }, - "node_modules/@onfido/castor-icons": { - "version": "2.22.0", - "resolved": "https://registry.npmjs.org/@onfido/castor-icons/-/castor-icons-2.22.0.tgz", - "integrity": "sha512-7OnCvu5xqVWcBLqovZyb99NP0oHw7sjkVYXZhi438i0U6Pgecrhu/14Gc/IN/kvgDxWj9qmiYdd0qdjNaVckrQ==", - "peerDependencies": { - "react": ">=17 || ^16.14 || ^15.7 || ^0.14.10" - } - }, - "node_modules/@onfido/castor-tokens": { - "version": "1.0.0-beta.6", - "resolved": "https://registry.npmjs.org/@onfido/castor-tokens/-/castor-tokens-1.0.0-beta.6.tgz", - "integrity": "sha512-MfwuSlNdM0Ay0cI3LLyqZGsHW0e1Y1R/0IdQKVU575PdWQx1Q/538aOZMo/a3/oSW0pMEgfOm+mNqPx057cvWA==" - }, - "node_modules/@onfido/opencv": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@onfido/opencv/-/opencv-2.1.1.tgz", - "integrity": "sha512-Bwo0YsZrrdm+p5hpNFZ7yrqNVWJxOUbQW9aWDEUtkDWUL+nX2RHIR6F4lBGVmbqnG24anadS/+nEvy80SwD3tQ==", - "dependencies": { - "mirada": "^0.0.15" - } - }, "node_modules/@onfido/react-native-sdk": { "version": "10.6.0", "resolved": "https://registry.npmjs.org/@onfido/react-native-sdk/-/react-native-sdk-10.6.0.tgz", @@ -8825,10 +8669,12 @@ } }, "node_modules/@react-native-camera-roll/camera-roll": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@react-native-camera-roll/camera-roll/-/camera-roll-5.4.0.tgz", - "integrity": "sha512-SMEhc+2hQWubwzxR6Zac0CmrJ2rdoHHBo0ibG2iNMsxR0dnU5AdRGnYF/tyK9i20/i7ZNxn+qsEJ69shpkd6gg==", - "license": "MIT", + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@react-native-camera-roll/camera-roll/-/camera-roll-7.4.0.tgz", + "integrity": "sha512-y0bVpMJLaFphYvMMx1BsqgMA0kXq9CKxKYNnt4ocUvwJj5Rp4TZ233rzJoDqz1oxd56Tz5f1g+yhYN5RImKl8Q==", + "engines": { + "node": ">= 18.17.0" + }, "peerDependencies": { "react-native": ">=0.59" } @@ -10485,78 +10331,6 @@ "join-component": "^1.1.0" } }, - "node_modules/@sentry/browser": { - "version": "7.11.1", - "license": "BSD-3-Clause", - "dependencies": { - "@sentry/core": "7.11.1", - "@sentry/types": "7.11.1", - "@sentry/utils": "7.11.1", - "tslib": "^1.9.3" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@sentry/browser/node_modules/tslib": { - "version": "1.14.1", - "license": "0BSD" - }, - "node_modules/@sentry/core": { - "version": "7.11.1", - "license": "BSD-3-Clause", - "dependencies": { - "@sentry/hub": "7.11.1", - "@sentry/types": "7.11.1", - "@sentry/utils": "7.11.1", - "tslib": "^1.9.3" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@sentry/core/node_modules/tslib": { - "version": "1.14.1", - "license": "0BSD" - }, - "node_modules/@sentry/hub": { - "version": "7.11.1", - "license": "BSD-3-Clause", - "dependencies": { - "@sentry/types": "7.11.1", - "@sentry/utils": "7.11.1", - "tslib": "^1.9.3" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@sentry/hub/node_modules/tslib": { - "version": "1.14.1", - "license": "0BSD" - }, - "node_modules/@sentry/types": { - "version": "7.11.1", - "license": "BSD-3-Clause", - "engines": { - "node": ">=8" - } - }, - "node_modules/@sentry/utils": { - "version": "7.11.1", - "license": "BSD-3-Clause", - "dependencies": { - "@sentry/types": "7.11.1", - "tslib": "^1.9.3" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@sentry/utils/node_modules/tslib": { - "version": "1.14.1", - "license": "0BSD" - }, "node_modules/@shopify/flash-list": { "version": "1.6.3", "resolved": "https://registry.npmjs.org/@shopify/flash-list/-/flash-list-1.6.3.tgz", @@ -10635,11 +10409,6 @@ "@sinonjs/commons": "^2.0.0" } }, - "node_modules/@socket.io/component-emitter": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz", - "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==" - }, "node_modules/@storybook/addon-a11y": { "version": "6.5.10", "dev": true, @@ -20003,88 +19772,6 @@ "node": ">=10" } }, - "node_modules/@tensorflow-models/face-detection": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@tensorflow-models/face-detection/-/face-detection-1.0.2.tgz", - "integrity": "sha512-anjSxy3MnZdTiVluOEQZeaFWM30IPswFM+SltX6wseXKja/AbrHYqamGNZKUylAs2JAyudq+xqTRPS+nA2ourg==", - "dependencies": { - "rimraf": "^3.0.2", - "tslib": "2.4.0" - }, - "peerDependencies": { - "@mediapipe/face_detection": "~0.4.0", - "@tensorflow/tfjs-backend-webgl": "^4.4.0", - "@tensorflow/tfjs-converter": "^4.4.0", - "@tensorflow/tfjs-core": "^4.4.0" - } - }, - "node_modules/@tensorflow/tfjs-backend-cpu": { - "version": "4.16.0", - "resolved": "https://registry.npmjs.org/@tensorflow/tfjs-backend-cpu/-/tfjs-backend-cpu-4.16.0.tgz", - "integrity": "sha512-bQFu7FTUgqgss1AwnqSwQ1f02IPrfLLc2lLn5pyyVrS6Ex7zA6Y4YkfktqoJSRE6LlRZv3vxSriUGE1avRe4qQ==", - "peer": true, - "dependencies": { - "@types/seedrandom": "^2.4.28", - "seedrandom": "^3.0.5" - }, - "engines": { - "yarn": ">= 1.3.2" - }, - "peerDependencies": { - "@tensorflow/tfjs-core": "4.16.0" - } - }, - "node_modules/@tensorflow/tfjs-backend-webgl": { - "version": "4.16.0", - "resolved": "https://registry.npmjs.org/@tensorflow/tfjs-backend-webgl/-/tfjs-backend-webgl-4.16.0.tgz", - "integrity": "sha512-cIGZWuY892iwTRokbDj3qsLi0AlpQn+U7rzB1mddhHrWr9kBXrrnAvIq0h2aiFzRFNePWUcsbgK+HmYG32kosg==", - "peer": true, - "dependencies": { - "@tensorflow/tfjs-backend-cpu": "4.16.0", - "@types/offscreencanvas": "~2019.3.0", - "@types/seedrandom": "^2.4.28", - "seedrandom": "^3.0.5" - }, - "engines": { - "yarn": ">= 1.3.2" - }, - "peerDependencies": { - "@tensorflow/tfjs-core": "4.16.0" - } - }, - "node_modules/@tensorflow/tfjs-converter": { - "version": "4.16.0", - "resolved": "https://registry.npmjs.org/@tensorflow/tfjs-converter/-/tfjs-converter-4.16.0.tgz", - "integrity": "sha512-gd8dHl9tqEPQOHZLAUza713nKr42rpvUXrtm7yUhk10THvJT6TXe9Q2AJKmni8J3vfR+ghsCh77F8D4RbShx1Q==", - "peer": true, - "peerDependencies": { - "@tensorflow/tfjs-core": "4.16.0" - } - }, - "node_modules/@tensorflow/tfjs-core": { - "version": "4.16.0", - "resolved": "https://registry.npmjs.org/@tensorflow/tfjs-core/-/tfjs-core-4.16.0.tgz", - "integrity": "sha512-MarAtO+Up6wA8pI9QDpQOwwJgb/imYMN++tsoaalyOEE9+B5HS4lQldxDJKXO8Frf4DyXf4FItJktEXaiPfRHw==", - "peer": true, - "dependencies": { - "@types/long": "^4.0.1", - "@types/offscreencanvas": "~2019.7.0", - "@types/seedrandom": "^2.4.28", - "@webgpu/types": "0.1.38", - "long": "4.0.0", - "node-fetch": "~2.6.1", - "seedrandom": "^3.0.5" - }, - "engines": { - "yarn": ">= 1.3.2" - } - }, - "node_modules/@tensorflow/tfjs-core/node_modules/@types/offscreencanvas": { - "version": "2019.7.3", - "resolved": "https://registry.npmjs.org/@types/offscreencanvas/-/offscreencanvas-2019.7.3.tgz", - "integrity": "sha512-ieXiYmgSRXUDeOntE1InxjWyvEelZGP63M+cGuquuRLuIKKT1osnkXjxev9B7d1nXSug5vpunx+gNlbVxMlC9A==", - "peer": true - }, "node_modules/@testing-library/jest-native": { "version": "5.4.1", "resolved": "https://registry.npmjs.org/@testing-library/jest-native/-/jest-native-5.4.1.tgz", @@ -20560,9 +20247,9 @@ } }, "node_modules/@types/debug": { - "version": "4.1.8", - "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.8.tgz", - "integrity": "sha512-/vPO1EPOs306Cvhwv7KfVfYvOJqA/S/AXjaHQiJboCZzcNDb+TIJFN9/2C9DZ//ijSKWioNyUxD792QmDJ+HKQ==", + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", + "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", "dev": true, "dependencies": { "@types/ms": "*" @@ -20574,11 +20261,6 @@ "integrity": "sha512-w5jZ0ee+HaPOaX25X2/2oGR/7rgAQSYII7X7pp0m9KgBfMP7uKfMfTvcpl5Dj+eDBbpxKGiqE+flqDr6XTd2RA==", "dev": true }, - "node_modules/@types/emscripten": { - "version": "0.0.34", - "resolved": "https://registry.npmjs.org/@types/emscripten/-/emscripten-0.0.34.tgz", - "integrity": "sha512-QSb9ojDincskc+uKMI0KXp8e1NALFINCrMlp8VGKGcTSxeEyRTTKyjWw75NYrCZHUsVEEEpr1tYHpbtaC++/sQ==" - }, "node_modules/@types/eslint": { "version": "8.4.6", "license": "MIT", @@ -20823,11 +20505,6 @@ "integrity": "sha512-Hwx9EUgdwf2GLarOjQp5ZH8ZmblzcbTBC2wtQWNKARBSxM9ezRIAUpeDTgoQRAFB0+8CNWXVA9+MaSOzOF3nPg==", "dev": true }, - "node_modules/@types/long": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz", - "integrity": "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==" - }, "node_modules/@types/mapbox-gl": { "version": "2.7.13", "resolved": "https://registry.npmjs.org/@types/mapbox-gl/-/mapbox-gl-2.7.13.tgz", @@ -20863,9 +20540,9 @@ "license": "MIT" }, "node_modules/@types/ms": { - "version": "0.7.31", - "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.31.tgz", - "integrity": "sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==", + "version": "0.7.34", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.34.tgz", + "integrity": "sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==", "dev": true }, "node_modules/@types/node": { @@ -20900,11 +20577,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@types/offscreencanvas": { - "version": "2019.3.0", - "resolved": "https://registry.npmjs.org/@types/offscreencanvas/-/offscreencanvas-2019.3.0.tgz", - "integrity": "sha512-esIJx9bQg+QYF0ra8GnvfianIY8qWB0GBx54PK5Eps6m+xTj86KLavHv6qDhzKcu5UUOgNfJ2pWaIIV7TRUd9Q==" - }, "node_modules/@types/parse-json": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", @@ -20920,9 +20592,9 @@ "license": "MIT" }, "node_modules/@types/plist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/plist/-/plist-3.0.3.tgz", - "integrity": "sha512-DXkBoKc7jwUR0p439icInmXXMJNhoImdpOrrgA5/nDFK7LVtcJ9MyQNKhJEKpEztnHGWnNWMWLOIR62By0Ln0A==", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/plist/-/plist-3.0.5.tgz", + "integrity": "sha512-E6OCaRmAe4WDmWNsL/9RMqdkkzDCY1etutkflWk4c+AcjDU07Pcz1fQwTX0TQz+Pxqn9i4L1TU3UFpjnrcDgxA==", "dev": true, "optional": true, "dependencies": { @@ -21062,11 +20734,6 @@ "version": "0.16.2", "license": "MIT" }, - "node_modules/@types/seedrandom": { - "version": "2.4.34", - "resolved": "https://registry.npmjs.org/@types/seedrandom/-/seedrandom-2.4.34.tgz", - "integrity": "sha512-ytDiArvrn/3Xk6/vtylys5tlY6eo7Ane0hvcx++TKo6RxQXuVfW0AF/oeWqAj9dN29SyhtawuXstgmPlwNcv/A==" - }, "node_modules/@types/semver": { "version": "7.5.4", "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.4.tgz", @@ -21160,22 +20827,12 @@ "license": "MIT" }, "node_modules/@types/verror": { - "version": "1.10.6", - "resolved": "https://registry.npmjs.org/@types/verror/-/verror-1.10.6.tgz", - "integrity": "sha512-NNm+gdePAX1VGvPcGZCDKQZKYSiAWigKhKaz5KF94hG6f2s8de9Ow5+7AbXoeKxL8gavZfk4UquSAygOF2duEQ==", + "version": "1.10.9", + "resolved": "https://registry.npmjs.org/@types/verror/-/verror-1.10.9.tgz", + "integrity": "sha512-MLx9Z+9lGzwEuW16ubGeNkpBDE84RpB/NyGgg6z2BTpWzKkGU451cAY3UkUzZEp72RHF585oJ3V8JVNqIplcAQ==", "dev": true, "optional": true }, - "node_modules/@types/webgl-ext": { - "version": "0.0.30", - "resolved": "https://registry.npmjs.org/@types/webgl-ext/-/webgl-ext-0.0.30.tgz", - "integrity": "sha512-LKVgNmBxN0BbljJrVUwkxwRYqzsAEPcZOe6S2T6ZaBDIrFp0qu4FNlpc5sM1tGbXUYFgdVQIoeLk1Y1UoblyEg==" - }, - "node_modules/@types/webgl2": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/@types/webgl2/-/webgl2-0.0.6.tgz", - "integrity": "sha512-50GQhDVTq/herLMiqSQkdtRu+d5q/cWHn4VvKJtrj4DJAjo1MNkWYa2MA41BaBO1q1HgsUjuQvEOk0QHvlnAaQ==" - }, "node_modules/@types/webpack": { "version": "4.41.32", "dev": true, @@ -22193,12 +21850,6 @@ "@xtuc/long": "4.2.2" } }, - "node_modules/@webgpu/types": { - "version": "0.1.38", - "resolved": "https://registry.npmjs.org/@webgpu/types/-/types-0.1.38.tgz", - "integrity": "sha512-7LrhVKz2PRh+DD7+S+PVaFd5HxaWQvoMqBbsV9fNJO1pjUs1P8bM2vQVNfk+3URTqbuTI7gkXi0rfsN0IadoBA==", - "peer": true - }, "node_modules/@webpack-cli/configtest": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.2.0.tgz", @@ -22278,9 +21929,9 @@ "license": "BSD-2-Clause" }, "node_modules/7zip-bin": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/7zip-bin/-/7zip-bin-5.1.1.tgz", - "integrity": "sha512-sAP4LldeWNz0lNzmTird3uWfFDWWTeg6V/MsmyyLR9X1idwKBWIgt/ZvinqQldJm3LecKEs1emkbquO6PCiLVQ==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/7zip-bin/-/7zip-bin-5.2.0.tgz", + "integrity": "sha512-ukTPVhqG4jNzMro2qA9HSCSSVJN3aN7tlb+hfqYCt3ER0yWroeA2VR38MNrOHLQ/cVj+DaIMad0kFCtWWowh/A==", "dev": true }, "node_modules/abab": { @@ -22752,26 +22403,25 @@ "dev": true }, "node_modules/app-builder-lib": { - "version": "24.6.4", - "resolved": "https://registry.npmjs.org/app-builder-lib/-/app-builder-lib-24.6.4.tgz", - "integrity": "sha512-m9931WXb83teb32N0rKg+ulbn6+Hl8NV5SUpVDOVz9MWOXfhV6AQtTdftf51zJJvCQnQugGtSqoLvgw6mdF/Rg==", + "version": "24.13.2", + "resolved": "https://registry.npmjs.org/app-builder-lib/-/app-builder-lib-24.13.2.tgz", + "integrity": "sha512-EPqgMIby/mwp140olwMoSHAreqjtu0m9IqfmGD8lWCeVvxvMoHqkWfqCF1sgaE5ISj7+nFb994RelR3As9VJJg==", "dev": true, "dependencies": { "@develar/schema-utils": "~2.6.5", - "@electron/notarize": "2.1.0", + "@electron/notarize": "2.2.1", "@electron/osx-sign": "1.0.5", - "@electron/universal": "1.4.1", + "@electron/universal": "1.5.1", "@malept/flatpak-bundler": "^0.4.0", "@types/fs-extra": "9.0.13", - "7zip-bin": "~5.1.1", "async-exit-hook": "^2.0.1", "bluebird-lst": "^1.0.9", - "builder-util": "24.5.0", - "builder-util-runtime": "9.2.1", + "builder-util": "24.13.1", + "builder-util-runtime": "9.2.4", "chromium-pickle-js": "^0.2.0", "debug": "^4.3.4", "ejs": "^3.1.8", - "electron-publish": "24.5.0", + "electron-publish": "24.13.1", "form-data": "^4.0.0", "fs-extra": "^10.1.0", "hosted-git-info": "^4.1.0", @@ -22788,6 +22438,10 @@ }, "engines": { "node": ">=14.0.0" + }, + "peerDependencies": { + "dmg-builder": "24.13.2", + "electron-builder-squirrel-windows": "24.13.2" } }, "node_modules/app-builder-lib/node_modules/argparse": { @@ -22880,6 +22534,62 @@ "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", "devOptional": true }, + "node_modules/archiver": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/archiver/-/archiver-5.3.2.tgz", + "integrity": "sha512-+25nxyyznAXF7Nef3y0EbBeqmGZgeN/BxHX29Rs39djAfaFalmQ89SE6CWyDCHzGL0yt/ycBtNOmGTW0FyGWNw==", + "dev": true, + "peer": true, + "dependencies": { + "archiver-utils": "^2.1.0", + "async": "^3.2.4", + "buffer-crc32": "^0.2.1", + "readable-stream": "^3.6.0", + "readdir-glob": "^1.1.2", + "tar-stream": "^2.2.0", + "zip-stream": "^4.1.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/archiver-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-2.1.0.tgz", + "integrity": "sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==", + "dev": true, + "peer": true, + "dependencies": { + "glob": "^7.1.4", + "graceful-fs": "^4.2.0", + "lazystream": "^1.0.0", + "lodash.defaults": "^4.2.0", + "lodash.difference": "^4.5.0", + "lodash.flatten": "^4.4.0", + "lodash.isplainobject": "^4.0.6", + "lodash.union": "^4.6.0", + "normalize-path": "^3.0.0", + "readable-stream": "^2.0.0" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/archiver/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "peer": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/are-docs-informative": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/are-docs-informative/-/are-docs-informative-0.0.2.tgz", @@ -24568,12 +24278,6 @@ "bluebird": "^3.5.5" } }, - "node_modules/blueimp-load-image": { - "version": "2.29.0", - "resolved": "https://registry.npmjs.org/blueimp-load-image/-/blueimp-load-image-2.29.0.tgz", - "integrity": "sha512-psm81GlZ0ffKxVT0QN9dvhpzXMv1KxgXSg8ars0XGAcEGsTwFT2IPo59HDXlw4Lo2oImdPzwrwkliZSiLLUpIw==", - "license": "MIT" - }, "node_modules/blueimp-md5": { "version": "2.19.0", "resolved": "https://registry.npmjs.org/blueimp-md5/-/blueimp-md5-2.19.0.tgz", @@ -25072,16 +24776,16 @@ "license": "MIT" }, "node_modules/builder-util": { - "version": "24.5.0", - "resolved": "https://registry.npmjs.org/builder-util/-/builder-util-24.5.0.tgz", - "integrity": "sha512-STnBmZN/M5vGcv01u/K8l+H+kplTaq4PAIn3yeuufUKSpcdro0DhJWxPI81k5XcNfC//bjM3+n9nr8F9uV4uAQ==", + "version": "24.13.1", + "resolved": "https://registry.npmjs.org/builder-util/-/builder-util-24.13.1.tgz", + "integrity": "sha512-NhbCSIntruNDTOVI9fdXz0dihaqX2YuE1D6zZMrwiErzH4ELZHE6mdiB40wEgZNprDia+FghRFgKoAqMZRRjSA==", "dev": true, "dependencies": { "@types/debug": "^4.1.6", - "7zip-bin": "~5.1.1", + "7zip-bin": "~5.2.0", "app-builder-bin": "4.0.0", "bluebird-lst": "^1.0.9", - "builder-util-runtime": "9.2.1", + "builder-util-runtime": "9.2.4", "chalk": "^4.1.2", "cross-spawn": "^7.0.3", "debug": "^4.3.4", @@ -25096,9 +24800,9 @@ } }, "node_modules/builder-util-runtime": { - "version": "9.2.1", - "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-9.2.1.tgz", - "integrity": "sha512-2rLv/uQD2x+dJ0J3xtsmI12AlRyk7p45TEbE/6o/fbb633e/S3pPgm+ct+JHsoY7r39dKHnGEFk/AASRFdnXmA==", + "version": "9.2.4", + "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-9.2.4.tgz", + "integrity": "sha512-upp+biKpN/XZMLim7aguUyW8s0FUpDvOtK6sbanMFDAMBzpHDqdhgVYm6zc9HJ6nWo7u2Lxk60i2M6Jd3aiNrA==", "dev": true, "dependencies": { "debug": "^4.3.4", @@ -26389,6 +26093,37 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/compress-commons": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-4.1.2.tgz", + "integrity": "sha512-D3uMHtGc/fcO1Gt1/L7i1e33VOvD4A9hfQLP+6ewd+BvG/gQ84Yh4oftEhAdjSMgBgwGL+jsppT7JYNpo6MHHg==", + "dev": true, + "peer": true, + "dependencies": { + "buffer-crc32": "^0.2.13", + "crc32-stream": "^4.0.2", + "normalize-path": "^3.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/compress-commons/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "peer": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/compressible": { "version": "2.0.18", "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", @@ -26494,26 +26229,96 @@ } }, "node_modules/config-file-ts": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/config-file-ts/-/config-file-ts-0.2.4.tgz", - "integrity": "sha512-cKSW0BfrSaAUnxpgvpXPLaaW/umg4bqg4k3GO1JqlRfpx+d5W0GDXznCMkWotJQek5Mmz1MJVChQnz3IVaeMZQ==", + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/config-file-ts/-/config-file-ts-0.2.6.tgz", + "integrity": "sha512-6boGVaglwblBgJqGyxm4+xCmEGcWgnWHSWHY5jad58awQhB6gftq0G8HbzU39YqCIYHMLAiL1yjwiZ36m/CL8w==", "dev": true, "dependencies": { - "glob": "^7.1.6", - "typescript": "^4.0.2" + "glob": "^10.3.10", + "typescript": "^5.3.3" + } + }, + "node_modules/config-file-ts/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" } }, - "node_modules/config-file-ts/node_modules/typescript": { - "version": "4.9.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", - "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "node_modules/config-file-ts/node_modules/foreground-child": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", + "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", "dev": true, + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/config-file-ts/node_modules/glob": { + "version": "10.3.10", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", + "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", + "dev": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + }, "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/config-file-ts/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/config-file-ts/node_modules/minipass": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", + "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/config-file-ts/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, "engines": { - "node": ">=4.2.0" + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/confusing-browser-globals": { @@ -27315,6 +27120,48 @@ "buffer": "^5.1.0" } }, + "node_modules/crc-32": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", + "dev": true, + "peer": true, + "bin": { + "crc32": "bin/crc32.njs" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/crc32-stream": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-4.0.3.tgz", + "integrity": "sha512-NT7w2JVU7DFroFdYkeq8cywxrgjPHWkdX1wjpRQXPX5Asews3tA+Ght6lddQO5Mkumffp3X7GEqku3epj2toIw==", + "dev": true, + "peer": true, + "dependencies": { + "crc-32": "^1.2.0", + "readable-stream": "^3.4.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/crc32-stream/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "peer": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/create-ecdh": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", @@ -28330,14 +28177,14 @@ } }, "node_modules/dmg-builder": { - "version": "24.6.4", - "resolved": "https://registry.npmjs.org/dmg-builder/-/dmg-builder-24.6.4.tgz", - "integrity": "sha512-BNcHRc9CWEuI9qt0E655bUBU/j/3wUCYBVKGu1kVpbN5lcUdEJJJeiO0NHK3dgKmra6LUUZlo+mWqc+OCbi0zw==", + "version": "24.13.2", + "resolved": "https://registry.npmjs.org/dmg-builder/-/dmg-builder-24.13.2.tgz", + "integrity": "sha512-PF/gAaoVkyfV/m/Av5BPUJ1xW0mRvNBEcMKw2KZI59uISYALkxwJCcU0rFt6dNFQxa8HK0YYB46MWhSzqKYq2A==", "dev": true, "dependencies": { - "app-builder-lib": "24.6.4", - "builder-util": "24.5.0", - "builder-util-runtime": "9.2.1", + "app-builder-lib": "24.13.2", + "builder-util": "24.13.1", + "builder-util-runtime": "9.2.4", "fs-extra": "^10.1.0", "iconv-lite": "^0.6.2", "js-yaml": "^4.1.0" @@ -28533,10 +28380,6 @@ "url": "https://github.com/fb55/domhandler?sponsor=1" } }, - "node_modules/dompurify": { - "version": "2.3.10", - "license": "(MPL-2.0 OR Apache-2.0)" - }, "node_modules/domutils": { "version": "2.8.0", "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", @@ -28664,16 +28507,16 @@ } }, "node_modules/electron-builder": { - "version": "24.6.4", - "resolved": "https://registry.npmjs.org/electron-builder/-/electron-builder-24.6.4.tgz", - "integrity": "sha512-uNWQoU7pE7qOaIQ6CJHpBi44RJFVG8OHRBIadUxrsDJVwLLo8Nma3K/EEtx5/UyWAQYdcK4nVPYKoRqBb20hbA==", + "version": "24.13.2", + "resolved": "https://registry.npmjs.org/electron-builder/-/electron-builder-24.13.2.tgz", + "integrity": "sha512-8G5fqkTwBsi7B9nOSBPtqu6v2TStPuyk/5xIJxEXwZqmFycp3CwnPQlb1MZsxjDHofma2LtJtuF0y09PwoG2xw==", "dev": true, "dependencies": { - "app-builder-lib": "24.6.4", - "builder-util": "24.5.0", - "builder-util-runtime": "9.2.1", + "app-builder-lib": "24.13.2", + "builder-util": "24.13.1", + "builder-util-runtime": "9.2.4", "chalk": "^4.1.2", - "dmg-builder": "24.6.4", + "dmg-builder": "24.13.2", "fs-extra": "^10.1.0", "is-ci": "^3.0.0", "lazy-val": "^1.0.5", @@ -28689,6 +28532,34 @@ "node": ">=14.0.0" } }, + "node_modules/electron-builder-squirrel-windows": { + "version": "24.13.2", + "resolved": "https://registry.npmjs.org/electron-builder-squirrel-windows/-/electron-builder-squirrel-windows-24.13.2.tgz", + "integrity": "sha512-ukiHmh+/eAKskPuobxDzdL5hHpgSY1gN8Sz4pGGG5qhuFmSvbHMj33RbMt/1nj8E9/wzapKhdear5+fBkyYqIw==", + "dev": true, + "peer": true, + "dependencies": { + "app-builder-lib": "24.13.2", + "archiver": "^5.3.1", + "builder-util": "24.13.1", + "fs-extra": "^10.1.0" + } + }, + "node_modules/electron-builder-squirrel-windows/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "peer": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/electron-builder/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -28831,14 +28702,14 @@ } }, "node_modules/electron-publish": { - "version": "24.5.0", - "resolved": "https://registry.npmjs.org/electron-publish/-/electron-publish-24.5.0.tgz", - "integrity": "sha512-zwo70suH15L15B4ZWNDoEg27HIYoPsGJUF7xevLJLSI7JUPC8l2yLBdLGwqueJ5XkDL7ucYyRZzxJVR8ElV9BA==", + "version": "24.13.1", + "resolved": "https://registry.npmjs.org/electron-publish/-/electron-publish-24.13.1.tgz", + "integrity": "sha512-2ZgdEqJ8e9D17Hwp5LEq5mLQPjqU3lv/IALvgp+4W8VeNhryfGhYEQC/PgDPMrnWUp+l60Ou5SJLsu+k4mhQ8A==", "dev": true, "dependencies": { "@types/fs-extra": "^9.0.11", - "builder-util": "24.5.0", - "builder-util-runtime": "9.2.1", + "builder-util": "24.13.1", + "builder-util-runtime": "9.2.4", "chalk": "^4.1.2", "fs-extra": "^10.1.0", "lazy-val": "^1.0.5", @@ -29027,46 +28898,6 @@ "objectorarray": "^1.0.5" } }, - "node_modules/engine.io-client": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.5.3.tgz", - "integrity": "sha512-9Z0qLB0NIisTRt1DZ/8U2k12RJn8yls/nXMZLn+/N8hANT3TcYjKFKcwbw5zFQiN4NTde3TSY9zb79e1ij6j9Q==", - "dependencies": { - "@socket.io/component-emitter": "~3.1.0", - "debug": "~4.3.1", - "engine.io-parser": "~5.2.1", - "ws": "~8.11.0", - "xmlhttprequest-ssl": "~2.0.0" - } - }, - "node_modules/engine.io-client/node_modules/ws": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", - "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/engine.io-parser": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.1.tgz", - "integrity": "sha512-9JktcM3u18nU9N2Lz3bWeBgxVgOKpw7yhRaoxQA3FUDZzzw+9WlA6p4G4u0RixNkg14fH7EfEc/RhpurtiROTQ==", - "engines": { - "node": ">=10.0.0" - } - }, "node_modules/enhanced-resolve": { "version": "5.15.0", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz", @@ -29107,12 +28938,6 @@ "url": "https://github.com/fb55/entities?sponsor=1" } }, - "node_modules/enumerate-devices": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/enumerate-devices/-/enumerate-devices-1.1.1.tgz", - "integrity": "sha512-8zDbrc7ocusTL1ZGmvgy0cTwdyCaM7sGZoYLRmnWJalLQzmftDtce+uDU91gafOTo9MCtgjSIxyMv/F4+Hcchw==", - "license": "MIT" - }, "node_modules/env-editor": { "version": "0.4.2", "resolved": "https://registry.npmjs.org/env-editor/-/env-editor-0.4.2.tgz", @@ -30509,12 +30334,6 @@ "node": ">=6" } }, - "node_modules/eventemitter2": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-2.2.2.tgz", - "integrity": "sha512-AmQ734LWUB9Iyk+2WIU3Z8iRhdL1XQihEE0iF/QC5Xp11zST0Z5tn5jRHa/PgIld2QIPSCys3CREqOQLUhNvkw==", - "license": "MIT" - }, "node_modules/eventemitter3": { "version": "4.0.7", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", @@ -30751,8 +30570,8 @@ }, "node_modules/expensify-common": { "version": "1.0.0", - "resolved": "git+ssh://git@github.com/Expensify/expensify-common.git#7ce83cd75c7893dbea4b1517ff04b9589144eafe", - "integrity": "sha512-bbYk0IZedc5njp+GS8Qu8EO91uG7pXgnXAoGrZg+chNdVWnpEWemXtnTNrnGxNjq5SuuRkcvQXlwMRKXPKFTjw==", + "resolved": "git+ssh://git@github.com/Expensify/expensify-common.git#615f4a8662cd1abea9fdeee4d04847197c5e36ae", + "integrity": "sha512-k/SmW3EBR+gxFkJP/59LJsmBKjnKR07XS30yk/GkQ0lIfyYkNmFJ0dWm/S/54ezFweezR7MDaQ3zGc45Mb/U5A==", "license": "MIT", "dependencies": { "classnames": "2.5.0", @@ -31591,14 +31410,6 @@ "url": "https://opencollective.com/ramda" } }, - "node_modules/file-type": { - "version": "12.4.2", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-12.4.2.tgz", - "integrity": "sha512-UssQP5ZgIOKelfsaB5CuGAL+Y+q7EmONuiwF3N5HAH0t27rvrttgi6Ra9k/+DVaY9UF6+ybxu5pOXLUdA8N7Vg==", - "engines": { - "node": ">=8" - } - }, "node_modules/file-uri-to-path": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", @@ -32210,6 +32021,13 @@ "readable-stream": "^2.0.0" } }, + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "dev": true, + "peer": true + }, "node_modules/fs-extra": { "version": "9.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", @@ -33167,19 +32985,6 @@ "node": ">= 8" } }, - "node_modules/history": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/history/-/history-4.5.1.tgz", - "integrity": "sha512-gfHeJeYeMzFtos61gdA1AloO0hGXPF2Yum+2FRdJvlylYQOz51OnT1zuwg9UYst1BRrONhcAh3Nmsg9iblgl6g==", - "license": "MIT", - "dependencies": { - "invariant": "^2.2.1", - "loose-envify": "^1.2.0", - "resolve-pathname": "^2.0.0", - "value-equal": "^0.2.0", - "warning": "^3.0.0" - } - }, "node_modules/hmac-drbg": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", @@ -35086,12 +34891,12 @@ "license": "MIT" }, "node_modules/isbinaryfile": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-5.0.0.tgz", - "integrity": "sha512-UDdnyGvMajJUWCkib7Cei/dvyJrrvo4FIrsvSFWdPpXSUorzXrDJ0S+X5Q4ZlasfPjca4yqCNNsjbCeiy8FFeg==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-5.0.2.tgz", + "integrity": "sha512-GvcjojwonMjWbTkfMpnVHVqXW/wKMYDfEpY94/8zy8HFMOqb/VL6oeONq9v87q4ttVlaTLnGXnJD4B5B1OTGIg==", "dev": true, "engines": { - "node": ">= 14.0.0" + "node": ">= 18.0.0" }, "funding": { "url": "https://github.com/sponsors/gjtorikian/" @@ -38248,13 +38053,6 @@ "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-3.7.5.tgz", "integrity": "sha512-3MEt5DTINKqfScXKfJFrRbxkrnk2AxPWGBL/ycjz4dK8iqiSJ06UxD8jh8xuh6p10TX4t2+7FsBYVxxQbMg+qA==" }, - "node_modules/js-cookie": { - "version": "3.0.1", - "license": "MIT", - "engines": { - "node": ">=12" - } - }, "node_modules/js-string-escape": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/js-string-escape/-/js-string-escape-1.0.1.tgz", @@ -38692,6 +38490,19 @@ "integrity": "sha512-0/BnGCCfyUMkBpeDgWihanIAF9JmZhHBgUhEqzvf+adhNGLoP6TaiI5oF8oyb3I45P+PcnrqihSf01M0l0G5+Q==", "dev": true }, + "node_modules/lazystream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz", + "integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==", + "dev": true, + "peer": true, + "dependencies": { + "readable-stream": "^2.0.5" + }, + "engines": { + "node": ">= 0.6.3" + } + }, "node_modules/lcid": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", @@ -38940,12 +38751,40 @@ "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", "license": "MIT" }, + "node_modules/lodash.defaults": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", + "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==", + "dev": true, + "peer": true + }, + "node_modules/lodash.difference": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz", + "integrity": "sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA==", + "dev": true, + "peer": true + }, + "node_modules/lodash.flatten": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", + "integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==", + "dev": true, + "peer": true + }, "node_modules/lodash.isequal": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==", "license": "MIT" }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "dev": true, + "peer": true + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -38965,6 +38804,13 @@ "dev": true, "license": "MIT" }, + "node_modules/lodash.union": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz", + "integrity": "sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==", + "dev": true, + "peer": true + }, "node_modules/lodash.uniq": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", @@ -39214,11 +39060,6 @@ "node": ">=6" } }, - "node_modules/long": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", - "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" - }, "node_modules/longest": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", @@ -40833,22 +40674,6 @@ "node": ">= 8" } }, - "node_modules/mirada": { - "version": "0.0.15", - "resolved": "https://registry.npmjs.org/mirada/-/mirada-0.0.15.tgz", - "integrity": "sha512-mbm4c+wjBVcmUzHRLv/TfOAq+iy03D24KwGxx8H+NSXkD5EOZV9zFWbVxTvZCc9XwR0FIUhryU/kQm12SMSQ3g==", - "dependencies": { - "buffer": "^5.4.3", - "cross-fetch": "^3.0.4", - "file-type": "^12.3.0", - "misc-utils-of-mine-generic": "^0.2.31" - } - }, - "node_modules/misc-utils-of-mine-generic": { - "version": "0.2.45", - "resolved": "https://registry.npmjs.org/misc-utils-of-mine-generic/-/misc-utils-of-mine-generic-0.2.45.tgz", - "integrity": "sha512-WsG2zYiui2cdEbHF2pXmJfnjHb4zL+cy+PaYcLgIpMju98hwX89VbjlvGIfamCfEodbQ0qjCEvD3ocgkCXfMOQ==" - }, "node_modules/mississippi": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz", @@ -41860,41 +41685,9 @@ } }, "node_modules/onfido-sdk-ui": { - "version": "13.6.1", - "resolved": "https://registry.npmjs.org/onfido-sdk-ui/-/onfido-sdk-ui-13.6.1.tgz", - "integrity": "sha512-EcFqTN9uaVINRUttSdt6ySUBlfg25dE9f2yxxXVUmrM9a4M1luv+aICej1zE3vRZPFEuFJ9mqJZQUTYo0YMFyg==", - "dependencies": { - "@onfido/active-video-capture": "^0.28.2", - "@onfido/opencv": "^2.0.0", - "@sentry/browser": "^7.2.0", - "blueimp-load-image": "~2.29.0", - "classnames": "~2.2.5", - "core-js": "^3.21.1", - "deepmerge": "^4.2.2", - "dompurify": "^2.2.6", - "enumerate-devices": "^1.1.1", - "eventemitter2": "~2.2.2", - "history": "~4.5.1", - "hoist-non-react-statics": "^3.3.2", - "js-cookie": "^3.0.1", - "pdfobject": "^2.2.7", - "preact": "10.11.3", - "redux": "^4.0.5", - "socket.io-client": "^4.2.0", - "supports-webp": "~1.0.3", - "uuid": "^8.3.2", - "visibilityjs": "~1.2.4", - "xstate": "^4.33.6" - }, - "bin": { - "migrate_locales": "scripts/migrate_locales.js" - } - }, - "node_modules/onfido-sdk-ui/node_modules/classnames": { - "version": "2.2.6", - "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.2.6.tgz", - "integrity": "sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q==", - "license": "MIT" + "version": "14.15.0", + "resolved": "https://registry.npmjs.org/onfido-sdk-ui/-/onfido-sdk-ui-14.15.0.tgz", + "integrity": "sha512-4Z+tnH6pQjK4SyazlzJq17NXO8AnhGcwEACbA3PVbAo90LBpGu1WAZ1r6VidlxFr/oPbu6sg/hisYvfXiqOtTg==" }, "node_modules/open": { "version": "8.4.2", @@ -42744,10 +42537,6 @@ "canvas": "^2.11.2" } }, - "node_modules/pdfobject": { - "version": "2.2.8", - "license": "MIT" - }, "node_modules/pend": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", @@ -43134,15 +42923,6 @@ "resolved": "https://registry.npmjs.org/potpack/-/potpack-2.0.0.tgz", "integrity": "sha512-Q+/tYsFU9r7xoOJ+y/ZTtdVQwTWfzjbiXBDMM/JKUux3+QPP02iUuIoeBQ+Ot6oEDlC+/PGjB/5A3K7KKb7hcw==" }, - "node_modules/preact": { - "version": "10.11.3", - "resolved": "https://registry.npmjs.org/preact/-/preact-10.11.3.tgz", - "integrity": "sha512-eY93IVpod/zG3uMF22Unl8h9KkrcKIRs2EGar8hwLZZDU1lkjph303V9HZBwufh2s736U6VXuhD109LYqPoffg==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/preact" - } - }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -44308,16 +44088,6 @@ "react-native-reanimated": ">=2.8.0" } }, - "node_modules/react-native-flipper": { - "version": "0.159.0", - "dev": true, - "license": "MIT", - "peer": true, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0", - "react-native": ">0.62.0" - } - }, "node_modules/react-native-fs": { "version": "2.20.0", "resolved": "https://registry.npmjs.org/react-native-fs/-/react-native-fs-2.20.0.tgz", @@ -44484,8 +44254,9 @@ }, "node_modules/react-native-onyx": { "version": "2.0.10", - "resolved": "https://registry.npmjs.org/react-native-onyx/-/react-native-onyx-2.0.10.tgz", - "integrity": "sha512-XHJdKBZnUyoRKrBgZlv/p6ehuFvqXqwqQlapmVwwIU40KQQes58gPy+8HnRndT3CdAeElVWZnw/BUMtiD/F3Xw==", + "resolved": "git+ssh://git@github.com/Expensify/react-native-onyx.git#cd778b55e419bf09ecf377b1e3ac013b7758434d", + "integrity": "sha512-0ky9ISCNhuch0onIkeu/XFhVHoLp7gFwg6Q5TZYt1Wfmu/48Z9fjJxKxw5PRLfNBtwDQZQWKYFAf/CIoBxnmZw==", + "license": "MIT", "dependencies": { "ascii-table": "0.0.9", "fast-equals": "^4.0.3", @@ -44549,17 +44320,6 @@ "react-native": "*" } }, - "node_modules/react-native-performance-flipper-reporter": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/react-native-performance-flipper-reporter/-/react-native-performance-flipper-reporter-2.0.0.tgz", - "integrity": "sha512-ccOgq99eK3OvrNNhpJDC4ydNk/1JGgWZPo2FLrPDLUHXAR4EcE9cUAtb46oGOpvHk5ZOb5aEDofc/CS9OEGcag==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "react-native-flipper": "*", - "react-native-performance": "*" - } - }, "node_modules/react-native-permissions": { "version": "3.9.3", "resolved": "https://registry.npmjs.org/react-native-permissions/-/react-native-permissions-3.9.3.tgz", @@ -44623,9 +44383,9 @@ } }, "node_modules/react-native-reanimated": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-3.7.1.tgz", - "integrity": "sha512-bapCxhnS58+GZynQmA/f5U8vRlmhXlI/WhYg0dqnNAGXHNIc+38ahRWcG8iK8e0R2v9M8Ky2ZWObEC6bmweofg==", + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-3.7.2.tgz", + "integrity": "sha512-3KpTmYEcmHhkZeTqgWtioqnljpd4TLxKHClvarYsA3UXU2Tv+O1gqlRhVhfHBZuiDngVu436gWkde9+/VQVMFQ==", "dependencies": { "@babel/plugin-transform-object-assign": "^7.16.7", "@babel/preset-typescript": "^7.16.7", @@ -44649,6 +44409,33 @@ "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", "license": "MIT" }, + "node_modules/react-native-release-profiler": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/react-native-release-profiler/-/react-native-release-profiler-0.1.6.tgz", + "integrity": "sha512-kSAPYjO3PDzV4xbjgj2NoiHtL7EaXmBira/WOcyz6S7mz1MVBoF0Bj74z5jAZo6BoBJRKqmQWI4ep+m0xvoF+g==", + "dependencies": { + "@react-native-community/cli": "^12.2.1", + "commander": "^11.1.0" + }, + "bin": { + "react-native-release-profiler": "lib/commonjs/cli.js" + }, + "engines": { + "node": ">= 18.0.0" + }, + "peerDependencies": { + "react": "*", + "react-native": "*" + } + }, + "node_modules/react-native-release-profiler/node_modules/commander": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", + "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", + "engines": { + "node": ">=16" + } + }, "node_modules/react-native-render-html": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/react-native-render-html/-/react-native-render-html-6.3.1.tgz", @@ -44718,6 +44505,14 @@ "react-native": "*" } }, + "node_modules/react-native-share": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/react-native-share/-/react-native-share-10.0.2.tgz", + "integrity": "sha512-EZs4MtsyauAI1zP8xXT1hIFB/pXOZJNDCKcgCpEfTZFXgCUzz8MDVbI1ocP2hA59XHRSkqAQdbJ0BFTpjxOBlg==", + "engines": { + "node": ">=16" + } + }, "node_modules/react-native-sound": { "version": "0.11.2", "resolved": "https://registry.npmjs.org/react-native-sound/-/react-native-sound-0.11.2.tgz", @@ -45959,6 +45754,39 @@ "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", "license": "MIT" }, + "node_modules/readdir-glob": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.3.tgz", + "integrity": "sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==", + "dev": true, + "peer": true, + "dependencies": { + "minimatch": "^5.1.0" + } + }, + "node_modules/readdir-glob/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "peer": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/readdir-glob/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "peer": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", @@ -46593,12 +46421,6 @@ "node": ">=8" } }, - "node_modules/resolve-pathname": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-2.2.0.tgz", - "integrity": "sha512-bAFz9ld18RzJfddgrO2e/0S2O81710++chRMUxHjXOYKF6jTAMrUNZrEZ1PvV0zlhfjidm08iRPdTLPno1FuRg==", - "license": "MIT" - }, "node_modules/resolve-protobuf-schema": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/resolve-protobuf-schema/-/resolve-protobuf-schema-2.1.0.tgz", @@ -46967,6 +46789,7 @@ "version": "3.0.5", "resolved": "https://registry.npmjs.org/seedrandom/-/seedrandom-3.0.5.tgz", "integrity": "sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg==", + "dev": true, "license": "MIT" }, "node_modules/select": { @@ -47865,32 +47688,6 @@ "node": ">=0.10.0" } }, - "node_modules/socket.io-client": { - "version": "4.7.4", - "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.7.4.tgz", - "integrity": "sha512-wh+OkeF0rAVCrABWQBaEjLfb7DVPotMbu0cgWgyR0v6eA4EoVnAwcIeIbcdTE3GT/H3kbdLl7OoH2+asoDRIIg==", - "dependencies": { - "@socket.io/component-emitter": "~3.1.0", - "debug": "~4.3.2", - "engine.io-client": "~6.5.2", - "socket.io-parser": "~4.2.4" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/socket.io-parser": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", - "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", - "dependencies": { - "@socket.io/component-emitter": "~3.1.0", - "debug": "~4.3.1" - }, - "engines": { - "node": ">=10.0.0" - } - }, "node_modules/sockjs": { "version": "0.3.24", "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", @@ -48951,12 +48748,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/supports-webp": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/supports-webp/-/supports-webp-1.0.7.tgz", - "integrity": "sha512-ZlqT+sCgZKcykOLrk8DYR4t3Em+nyVSHpiV3q7uzOutLwKIYU23n88KibCLw3FzM4NCQeRorvZ55AV/77lQyOQ==", - "license": "MIT" - }, "node_modules/svg-parser": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.4.tgz", @@ -49141,6 +48932,38 @@ "node": ">=10" } }, + "node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dev": true, + "peer": true, + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tar-stream/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "peer": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/tar/node_modules/minipass": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", @@ -49722,15 +49545,12 @@ "integrity": "sha512-ppJZNDuKGgxzkHihX8v9v9G5f+18gzaTfrukGrq6ueg0lmH4nqVnA2IPG0AEH3jKEk2GRJCUhDoqpoiw3PHLBA==" }, "node_modules/tmp": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", - "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz", + "integrity": "sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==", "dev": true, - "dependencies": { - "rimraf": "^3.0.0" - }, "engines": { - "node": ">=8.17.0" + "node": ">=14.14" } }, "node_modules/tmp-promise": { @@ -50270,9 +50090,9 @@ "license": "MIT" }, "node_modules/typescript": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.2.tgz", - "integrity": "sha512-6l+RyNy7oAHDfxC4FzSJcz9vnjTKxrLpDG5M2Vu4SHRVNg6xzqZp6LYSR9zjqQTu8DU/f5xwxUdADOkbrIX2gQ==", + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", + "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", "devOptional": true, "bin": { "tsc": "bin/tsc", @@ -51064,12 +50884,6 @@ "builtins": "^1.0.3" } }, - "node_modules/value-equal": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/value-equal/-/value-equal-0.2.1.tgz", - "integrity": "sha512-yRL36Xb2K/HmFT5Fe3M86S7mu4+a12/3l7uytUh6eNPPjP77ldPBvsAvmnWff39sXn55naRMZN8LZWRO8PWaeQ==", - "license": "MIT" - }, "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", @@ -51137,12 +50951,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/visibilityjs": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/visibilityjs/-/visibilityjs-1.2.8.tgz", - "integrity": "sha512-Y+aL3OUX88b+/VSmkmC2ApuLbf0grzbNLpCfIDSw3BzTU6PqcPsdgIOaw8b+eZoy+DdQqnVN3y/Evow9vQq9Ig==", - "license": "MIT" - }, "node_modules/vlq": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/vlq/-/vlq-1.0.1.tgz", @@ -51204,15 +51012,6 @@ "integrity": "sha512-VkQZJbO8zVImzYFteBXvBOZEl1qL175WH8VmZcxF2fZAoudNhNDvHi+doCaAEdU2l2vtcIwa2zn0QK5+I1HQ3Q==", "license": "MIT" }, - "node_modules/warning": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/warning/-/warning-3.0.0.tgz", - "integrity": "sha512-jMBt6pUrKn5I+OGgtQ4YZLdhIeJmObddh6CsibPxyQ5yPZm1XExSyzC1LCNX7BzhxWgiHmizBWJTHJIjMjTQYQ==", - "license": "BSD-3-Clause", - "dependencies": { - "loose-envify": "^1.0.0" - } - }, "node_modules/watchpack": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", @@ -52646,22 +52445,6 @@ "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", "license": "MIT" }, - "node_modules/xmlhttprequest-ssl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz", - "integrity": "sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/xstate": { - "version": "4.37.2", - "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/xstate" - } - }, "node_modules/xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", @@ -52874,6 +52657,79 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/zip-stream": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-4.1.1.tgz", + "integrity": "sha512-9qv4rlDiopXg4E69k+vMHjNN63YFMe9sZMrdlvKnCjlCRWeCBswPPMPUfx+ipsAWq1LXHe70RcbaHdJJpS6hyQ==", + "dev": true, + "peer": true, + "dependencies": { + "archiver-utils": "^3.0.4", + "compress-commons": "^4.1.2", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/zip-stream/node_modules/archiver-utils": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-3.0.4.tgz", + "integrity": "sha512-KVgf4XQVrTjhyWmx6cte4RxonPLR9onExufI1jhvw/MQ4BB6IsZD5gT8Lq+u/+pRkWna/6JoHpiQioaqFP5Rzw==", + "dev": true, + "peer": true, + "dependencies": { + "glob": "^7.2.3", + "graceful-fs": "^4.2.0", + "lazystream": "^1.0.0", + "lodash.defaults": "^4.2.0", + "lodash.difference": "^4.5.0", + "lodash.flatten": "^4.4.0", + "lodash.isplainobject": "^4.0.6", + "lodash.union": "^4.6.0", + "normalize-path": "^3.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/zip-stream/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "peer": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/zip-stream/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "peer": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/zod": { "version": "3.22.4", "resolved": "https://registry.npmjs.org/zod/-/zod-3.22.4.tgz", diff --git a/package.json b/package.json index e437f5c5526d..38b5f9ef3979 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "new.expensify", - "version": "1.4.47-2", + "version": "1.4.52-0", "author": "Expensify, Inc.", "homepage": "https://new.expensify.com", "description": "New Expensify is the next generation of Expensify: a reimagination of payments based atop a foundation of chat.", @@ -50,13 +50,15 @@ "analyze-packages": "ANALYZE_BUNDLE=true webpack --config config/webpack/webpack.common.js --env envFile=.env.production", "symbolicate:android": "npx metro-symbolicate android/app/build/generated/sourcemaps/react/release/index.android.bundle.map", "symbolicate:ios": "npx metro-symbolicate main.jsbundle.map", - "test:e2e": "ts-node tests/e2e/testRunner.js --config ./config.local.ts", - "test:e2e:dev": "ts-node tests/e2e/testRunner.js --config ./config.dev.js", + "symbolicate-release:ios": "scripts/release-profile.js --platform=ios", + "symbolicate-release:android": "scripts/release-profile.js --platform=android", + "test:e2e": "ts-node tests/e2e/testRunner.ts --config ./config.local.ts", + "test:e2e:dev": "ts-node tests/e2e/testRunner.ts --config ./config.dev.ts", "gh-actions-unused-styles": "./.github/scripts/findUnusedKeys.sh", "workflow-test": "./workflow_tests/scripts/runWorkflowTests.sh", "workflow-test:generate": "ts-node workflow_tests/utils/preGenerateTest.js", "setup-https": "mkcert -install && mkcert -cert-file config/webpack/certificate.pem -key-file config/webpack/key.pem dev.new.expensify.com localhost 127.0.0.1", - "e2e-test-runner-build": "ncc build tests/e2e/testRunner.js -o tests/e2e/dist/" + "e2e-test-runner-build": "ncc build tests/e2e/testRunner.ts -o tests/e2e/dist/" }, "dependencies": { "@dotlottie/react-player": "^1.6.3", @@ -75,7 +77,7 @@ "@oguzhnatly/react-native-image-manipulator": "github:Expensify/react-native-image-manipulator#5cdae3d4455b03a04c57f50be3863e2fe6c92c52", "@onfido/react-native-sdk": "10.6.0", "@react-native-async-storage/async-storage": "1.21.0", - "@react-native-camera-roll/camera-roll": "5.4.0", + "@react-native-camera-roll/camera-roll": "7.4.0", "@react-native-clipboard/clipboard": "^1.13.2", "@react-native-community/geolocation": "^3.0.6", "@react-native-community/netinfo": "11.2.1", @@ -101,7 +103,7 @@ "date-fns-tz": "^2.0.0", "dom-serializer": "^0.2.2", "domhandler": "^4.3.0", - "expensify-common": "github:Expensify/expensify-common#7ce83cd75c7893dbea4b1517ff04b9589144eafe", + "expensify-common": "git+ssh://git@github.com/Expensify/expensify-common.git#615f4a8662cd1abea9fdeee4d04847197c5e36ae", "expo": "^50.0.3", "expo-av": "~13.10.4", "expo-image": "1.10.1", @@ -113,7 +115,7 @@ "lodash": "4.17.21", "lottie-react-native": "6.4.1", "mapbox-gl": "^2.15.0", - "onfido-sdk-ui": "13.6.1", + "onfido-sdk-ui": "14.15.0", "patch-package": "^8.0.0", "process": "^0.11.10", "prop-types": "^15.7.2", @@ -146,7 +148,7 @@ "react-native-linear-gradient": "^2.8.1", "react-native-localize": "^2.2.6", "react-native-modal": "^13.0.0", - "react-native-onyx": "2.0.10", + "react-native-onyx": "git+https://github.com/Expensify/react-native-onyx#cd778b55e419bf09ecf377b1e3ac013b7758434d", "react-native-pager-view": "6.2.2", "react-native-pdf": "6.7.3", "react-native-performance": "^5.1.0", @@ -155,10 +157,12 @@ "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-reanimated": "^3.7.1", + "react-native-release-profiler": "^0.1.6", + "react-native-reanimated": "^3.7.2", "react-native-render-html": "6.3.1", "react-native-safe-area-context": "4.8.2", "react-native-screens": "3.29.0", + "react-native-share": "^10.0.2", "react-native-sound": "^0.11.2", "react-native-svg": "14.1.0", "react-native-tab-view": "^3.5.2", @@ -252,7 +256,7 @@ "diff-so-fancy": "^1.3.0", "dotenv": "^16.0.3", "electron": "^29.0.0", - "electron-builder": "24.6.4", + "electron-builder": "24.13.2", "eslint": "^7.6.0", "eslint-config-airbnb-typescript": "^17.1.0", "eslint-config-expensify": "^2.0.44", @@ -276,7 +280,6 @@ "prettier": "^2.8.8", "pusher-js-mock": "^0.3.3", "react-native-clean-project": "^4.0.0-alpha4.0", - "react-native-performance-flipper-reporter": "^2.0.0", "react-test-renderer": "18.2.0", "reassure": "^0.10.1", "setimmediate": "^1.0.5", From a0a861c6ec583e26a563e5495ea5155e5a829d34 Mon Sep 17 00:00:00 2001 From: Alberto Date: Thu, 14 Mar 2024 17:15:53 +0100 Subject: [PATCH 102/175] add split actions --- src/libs/actions/IOU.ts | 53 +++++++++++++++++++++++++++++++++-------- 1 file changed, 43 insertions(+), 10 deletions(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 411c4bf4f731..f89c44d9d0a4 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -465,6 +465,7 @@ function buildOnyxDataForMoneyRequest( policyTagList?: OnyxEntry, policyCategories?: OnyxEntry, optimisticNextStep?: OnyxTypes.ReportNextStep | null, + isOneOnOneSplit = false, ): [OnyxUpdate[], OnyxUpdate[], OnyxUpdate[]] { const isScanRequest = TransactionUtils.isScanRequest(transaction); const outstandingChildRequest = getOutstandingChildRequest(policy ?? {}, iouReport); @@ -509,16 +510,6 @@ function buildOnyxDataForMoneyRequest( key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transaction.transactionID}`, value: transaction, }, - { - onyxMethod: Onyx.METHOD.SET, - key: ONYXKEYS.NVP_QUICK_ACTION_GLOBAL_CREATE, - value:{ - action: newQuickAction, - reportID: chatReport?.reportID, - isFirstQuickAction: isEmptyObject(quickAction); - }, - }, - isNewChatReport ? { onyxMethod: Onyx.METHOD.SET, @@ -573,6 +564,19 @@ function buildOnyxDataForMoneyRequest( }, ); + if (!isOneOnOneSplit) { + console.log('bad'); + optimisticData.push({ + onyxMethod: Onyx.METHOD.SET, + key: ONYXKEYS.NVP_QUICK_ACTION_GLOBAL_CREATE, + value:{ + action: newQuickAction, + reportID: chatReport?.reportID, + isFirstQuickAction: isEmptyObject(quickAction), + }, + }); + } + if (optimisticPolicyRecentlyUsedCategories.length) { optimisticData.push({ onyxMethod: Onyx.METHOD.SET, @@ -1726,6 +1730,7 @@ function createSplitsAndOnyxData( }; } + console.log('here'); const optimisticData: OnyxUpdate[] = [ { // Use set for new reports because it doesn't exist yet, is faster, @@ -1734,6 +1739,15 @@ function createSplitsAndOnyxData( key: `${ONYXKEYS.COLLECTION.REPORT}${splitChatReport.reportID}`, value: splitChatReport, }, + { + onyxMethod: Onyx.METHOD.SET, + key: ONYXKEYS.NVP_QUICK_ACTION_GLOBAL_CREATE, + value:{ + action: TransactionUtils.isDistanceRequest(splitTransaction) ? CONST.QUICK_ACTIONS.SPLIT_DISTANCE : CONST.QUICK_ACTIONS.SPLIT_MANUAL, + reportID: splitChatReport.reportID, + isFirstQuickAction: isEmptyObject(quickAction), + }, + }, existingSplitChatReport ? { onyxMethod: Onyx.METHOD.MERGE, @@ -1965,6 +1979,11 @@ function createSplitsAndOnyxData( optimisticTransactionThread, optimisticCreatedActionForTransactionThread, shouldCreateNewOneOnOneIOUReport, + null, + null, + null, + null, + true, ); const individualSplit = { @@ -2189,6 +2208,15 @@ function startSplitBill( key: `${ONYXKEYS.COLLECTION.REPORT}${splitChatReport.reportID}`, value: splitChatReport, }, + { + onyxMethod: Onyx.METHOD.SET, + key: ONYXKEYS.NVP_QUICK_ACTION_GLOBAL_CREATE, + value:{ + action: CONST.QUICK_ACTIONS.SPLIT_SCAN, + reportID: splitChatReport.reportID, + isFirstQuickAction: isEmptyObject(quickAction), + }, + }, existingSplitChatReport ? { onyxMethod: Onyx.METHOD.MERGE, @@ -2564,6 +2592,11 @@ function completeSplitBill(chatReportID: string, reportAction: OnyxTypes.ReportA optimisticTransactionThread, optimisticCreatedActionForTransactionThread, shouldCreateNewOneOnOneIOUReport, + null, + null, + null, + null, + true, ); splits.push({ From 75d817c6778942117e2b18d6884ecd43b9c89626 Mon Sep 17 00:00:00 2001 From: John Lee Date: Thu, 14 Mar 2024 13:40:25 -0400 Subject: [PATCH 103/175] Fix Jest tests --- tests/unit/MiddlewareTest.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/unit/MiddlewareTest.js b/tests/unit/MiddlewareTest.js index 85148cdb40e0..6a9576511f38 100644 --- a/tests/unit/MiddlewareTest.js +++ b/tests/unit/MiddlewareTest.js @@ -49,9 +49,9 @@ describe('Middleware', () => { await waitForNetworkPromises(); expect(global.fetch).toHaveBeenCalledTimes(2); - expect(global.fetch).toHaveBeenLastCalledWith('https://www.expensify.com.dev/api?command=AddComment', expect.anything()); + expect(global.fetch).toHaveBeenLastCalledWith('https://www.expensify.com.dev/api/AddComment?', expect.anything()); TestHelper.assertFormDataMatchesObject(global.fetch.mock.calls[1][1].body, {reportID: '1234', reportActionID: '5678', reportComment: 'foo'}); - expect(global.fetch).toHaveBeenNthCalledWith(1, 'https://www.expensify.com.dev/api?command=OpenReport', expect.anything()); + expect(global.fetch).toHaveBeenNthCalledWith(1, 'https://www.expensify.com.dev/api/OpenReport?', expect.anything()); TestHelper.assertFormDataMatchesObject(global.fetch.mock.calls[0][1].body, {reportID: '1234'}); }); @@ -93,9 +93,9 @@ describe('Middleware', () => { await waitForNetworkPromises(); expect(global.fetch).toHaveBeenCalledTimes(2); - expect(global.fetch).toHaveBeenLastCalledWith('https://www.expensify.com.dev/api?command=AddComment', expect.anything()); + expect(global.fetch).toHaveBeenLastCalledWith('https://www.expensify.com.dev/api/AddComment?', expect.anything()); TestHelper.assertFormDataMatchesObject(global.fetch.mock.calls[1][1].body, {reportID: '5555', reportActionID: '5678', reportComment: 'foo'}); - expect(global.fetch).toHaveBeenNthCalledWith(1, 'https://www.expensify.com.dev/api?command=OpenReport', expect.anything()); + expect(global.fetch).toHaveBeenNthCalledWith(1, 'https://www.expensify.com.dev/api/OpenReport?', expect.anything()); TestHelper.assertFormDataMatchesObject(global.fetch.mock.calls[0][1].body, {reportID: '1234'}); }); }); From 59faf8b3e4e9790a2b982216af3b0c7066e68b5b Mon Sep 17 00:00:00 2001 From: John Lee Date: Thu, 14 Mar 2024 13:41:57 -0400 Subject: [PATCH 104/175] Fix documentation and last places --- README.md | 64 +++++++++---------- .../Navigation/AppNavigator/AuthScreens.tsx | 2 +- tests/ui/UnreadIndicatorsTest.tsx | 2 +- tests/utils/PusherHelper.ts | 2 +- web/proxy.js | 6 +- 5 files changed, 38 insertions(+), 38 deletions(-) diff --git a/README.md b/README.md index 400260393bc1..7019567c7acb 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ These instructions should get you set up ready to work on New Expensify 🙌 1. Install `nvm` then `node` & `npm`: `brew install nvm && nvm install` 2. Install `watchman`: `brew install watchman` 3. Install dependencies: `npm install` -4. Install `mkcert`: `brew install mkcert` followed by `npm run setup-https`. If you are not using macOS, follow the instructions [here](https://github.com/FiloSottile/mkcert?tab=readme-ov-file#installation). +4. Install `mkcert`: `brew install mkcert` followed by `npm run setup-https`. If you are not using macOS, follow the instructions [here](https://github.com/FiloSottile/mkcert?tab=readme-ov-file#installation). 5. Create a host entry in your local hosts file, `/etc/hosts` for dev.new.expensify.com pointing to localhost: ``` 127.0.0.1 dev.new.expensify.com @@ -86,7 +86,7 @@ If you want to run the app on an actual physical iOS device, please follow the i 1. If you are having issues with **_Getting Started_**, please reference [React Native's Documentation](https://reactnative.dev/docs/environment-setup) 2. If you are running into CORS errors like (in the browser dev console) ```sh - Access to fetch at 'https://www.expensify.com/api?command=BeginSignIn' from origin 'http://localhost:8080' has been blocked by CORS policy + Access to fetch at 'https://www.expensify.com/api/BeginSignIn' from origin 'http://localhost:8080' has been blocked by CORS policy ``` You probably have a misconfigured `.env` file - remove it (`rm .env`) and try again @@ -113,7 +113,7 @@ variables referenced here get updated since your local `.env` file is ignored. see [PERFORMANCE.md](contributingGuides/PERFORMANCE.md#performance-metrics-opt-in-on-local-release-builds) for more information - `ONYX_METRICS` (optional) - Set this to `true` to capture even more performance metrics and see them in Flipper see [React-Native-Onyx#benchmarks](https://github.com/Expensify/react-native-onyx#benchmarks) for more information -- `E2E_TESTING` (optional) - This needs to be set to `true` when running the e2e tests for performance regression testing. +- `E2E_TESTING` (optional) - This needs to be set to `true` when running the e2e tests for performance regression testing. This happens usually automatically, read [this](tests/e2e/README.md) for more information ---- @@ -127,7 +127,7 @@ You create this certificate by following the instructions in [`Configuring HTTPS #### Pre-requisite for Android flow 1. Open any emulator using Android Studio 2. Use `adb push "$(mkcert -CAROOT)/rootCA.pem" /storage/emulated/0/Download/` to push certificate to install in Download folder. -3. Install the certificate as CA certificate from the settings. On the Android emulator, this option can be found in Settings > Security > Encryption & Credentials > Install a certificate > CA certificate. +3. Install the certificate as CA certificate from the settings. On the Android emulator, this option can be found in Settings > Security > Encryption & Credentials > Install a certificate > CA certificate. 4. Close the emulator. Note - If you want to run app on `https://127.0.0.1:8082`, then just install the certificate and use `adb reverse tcp:8082 tcp:8082` on every startup. @@ -196,7 +196,7 @@ Often, performance issue debugging occurs in debug builds, which can introduce e ### Getting Started with Source Maps To accurately profile your application, generating source maps for Android and iOS is crucial. Here's how to enable them: -1. Enable source maps on Android +1. Enable source maps on Android Ensure the following is set in your app's `android/app/build.gradle` file. ```jsx @@ -205,13 +205,13 @@ Ensure the following is set in your app's `android/app/build.gradle` file. hermesFlagsRelease: ["-O", "-output-source-map"], // <-- here, plus whichever flag was required to set this away from default ] ``` - -2. Enable source maps on IOS + +2. Enable source maps on IOS Within Xcode head to the build phase - `Bundle React Native code and images`. - + ```jsx export SOURCEMAP_FILE="$(pwd)/../main.jsbundle.map" // <-- here; - + export NODE_BINARY=node ../node_modules/react-native/scripts/react-native-xcode.sh ``` @@ -221,8 +221,8 @@ Within Xcode head to the build phase - `Bundle React Native code and images`. ``` 7. Depending on the platform you are targeting, run your Android/iOS app in production mode. 8. Upon completion, the generated source map can be found at: - Android: `android/app/build/generated/sourcemaps/react/productionRelease/index.android.bundle.map` - IOS: `main.jsbundle.map` + Android: `android/app/build/generated/sourcemaps/react/productionRelease/index.android.bundle.map` + IOS: `main.jsbundle.map` ### Recording a Trace: 1. Ensure you have generated the source map as outlined above. @@ -253,7 +253,7 @@ Build info: 4. Use the following commands to symbolicate the trace for Android and iOS, respectively: Android: `npm run symbolicate-release:android` -IOS: `npm run symbolicate-release:ios` +IOS: `npm run symbolicate-release:ios` 5. A new file named `Profile_trace_for_-converted.json` will appear in your project's root folder. 6. Open this file in your tool of choice: - SpeedScope ([https://www.speedscope.app](https://www.speedscope.app/)) @@ -482,8 +482,8 @@ Updated rules for managing members across all types of chats in New Expensify. - Members can't leave or be removed from the #announce room - Admins can't leave or be removed from #admins - Domain members can't leave or be removed from their domain chat - - Report submitters can't leave or be removed from their reports - - Report managers can't leave or be removed from their reports + - Report submitters can't leave or be removed from their reports + - Report managers can't leave or be removed from their reports - Group owners cannot be removed from their groups - they need to transfer ownership first - **Excepting the above, admins can remove anyone. For example:** - Group admins can remove other group admins, as well as group members @@ -494,17 +494,17 @@ Updated rules for managing members across all types of chats in New Expensify. 1. ### DM | | Member - | :---: | :---: - | **Invite** | ❌ - | **Remove** | ❌ - | **Leave** | ❌ + | :---: | :---: + | **Invite** | ❌ + | **Remove** | ❌ + | **Leave** | ❌ | **Can be removed** | ❌ - DM always has two participants. None of the participant can leave or be removed from the DM. Also no additional member can be invited to the chat. 2. ### Workspace 1. #### Workspace | | Creator | Member(Employee/User) | Admin | Auditor? - | :---: | :---: | :---: | :---: | :---: + | :---: | :---: | :---: | :---: | :---: | **Invite** | ✅ | ❌ | ✅ | ❌ | **Remove** | ✅ | ❌ | ✅ | ❌ | **Leave** | ❌ | ✅ | ❌ | ✅ @@ -518,7 +518,7 @@ Updated rules for managing members across all types of chats in New Expensify. 2. #### Workspace #announce room | | Member(Employee/User) | Admin | Auditor? - | :---: | :---: | :---: | :---: + | :---: | :---: | :---: | :---: | **Invite** | ❌ | ❌ | ❌ | **Remove** | ❌ | ❌ | ❌ | **Leave** | ❌ | ❌ | ❌ @@ -528,14 +528,14 @@ Updated rules for managing members across all types of chats in New Expensify. 3. #### Workspace #admin room | | Admin | - | :---: | :---: - | **Invite** | ❌ - | **Remove** | ❌ - | **Leave** | ❌ + | :---: | :---: + | **Invite** | ❌ + | **Remove** | ❌ + | **Leave** | ❌ | **Can be removed** | ❌ - Admins can't leave or be removed from #admins - + 4. #### Workspace rooms | | Creator | Member | Guest(outside of the workspace) | :---: | :---: | :---: | :---: @@ -548,10 +548,10 @@ Updated rules for managing members across all types of chats in New Expensify. - Guests are not able to remove anyone from the room 4. #### Workspace chats - | | Admin | Member(default) | Member(invited) + | | Admin | Member(default) | Member(invited) | :---: | :---: | :---: | :---: | **Invite** | ✅ | ✅ | ❌ - | **Remove** | ✅ | ✅ | ❌ + | **Remove** | ✅ | ✅ | ❌ | **Leave** | ❌ | ❌ | ✅ | **Can be removed** | ❌ | ❌ | ✅ @@ -563,16 +563,16 @@ Updated rules for managing members across all types of chats in New Expensify. 3. ### Domain chat | | Member - | :---: | :---: - | **Remove** | ❌ - | **Leave** | ❌ - | **Can be removed** | ❌ + | :---: | :---: + | **Remove** | ❌ + | **Leave** | ❌ + | **Can be removed** | ❌ - Domain members can't leave or be removed from their domain chat 4. ### Reports | | Submitter | Manager - | :---: | :---: | :---: + | :---: | :---: | :---: | **Remove** | ❌ | ❌ | **Leave** | ❌ | ❌ | **Can be removed** | ❌ | ❌ diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.tsx b/src/libs/Navigation/AppNavigator/AuthScreens.tsx index 585713243d3f..5835558e5de4 100644 --- a/src/libs/Navigation/AppNavigator/AuthScreens.tsx +++ b/src/libs/Navigation/AppNavigator/AuthScreens.tsx @@ -181,7 +181,7 @@ function AuthScreens({session, lastOpenedPublicRoomID, initialLastUpdateIDApplie Pusher.init({ appKey: CONFIG.PUSHER.APP_KEY, cluster: CONFIG.PUSHER.CLUSTER, - authEndpoint: `${CONFIG.EXPENSIFY.DEFAULT_API_ROOT}api?command=AuthenticatePusher`, + authEndpoint: `${CONFIG.EXPENSIFY.DEFAULT_API_ROOT}api/AuthenticatePusher?`, }).then(() => { User.subscribeToUserEvents(); }); diff --git a/tests/ui/UnreadIndicatorsTest.tsx b/tests/ui/UnreadIndicatorsTest.tsx index cbfb0b66d493..61eb726686f2 100644 --- a/tests/ui/UnreadIndicatorsTest.tsx +++ b/tests/ui/UnreadIndicatorsTest.tsx @@ -131,7 +131,7 @@ beforeAll(() => { Pusher.init({ appKey: CONFIG.PUSHER.APP_KEY, cluster: CONFIG.PUSHER.CLUSTER, - authEndpoint: `${CONFIG.EXPENSIFY.DEFAULT_API_ROOT}api?command=AuthenticatePusher`, + authEndpoint: `${CONFIG.EXPENSIFY.DEFAULT_API_ROOT}api/AuthenticatePusher?`, }); }); diff --git a/tests/utils/PusherHelper.ts b/tests/utils/PusherHelper.ts index dcd144e77596..8726433c03ab 100644 --- a/tests/utils/PusherHelper.ts +++ b/tests/utils/PusherHelper.ts @@ -20,7 +20,7 @@ function setup() { Pusher.init({ appKey: CONFIG.PUSHER.APP_KEY, cluster: CONFIG.PUSHER.CLUSTER, - authEndpoint: `${CONFIG.EXPENSIFY.DEFAULT_API_ROOT}api?command=AuthenticatePusher`, + authEndpoint: `${CONFIG.EXPENSIFY.DEFAULT_API_ROOT}api/AuthenticatePusher?`, }); } diff --git a/web/proxy.js b/web/proxy.js index 0d82ae60b678..a86947bc2020 100644 --- a/web/proxy.js +++ b/web/proxy.js @@ -30,9 +30,9 @@ const server = http.createServer((request, response) => { * This is done because the staging api root is only intended for the proxy, * the actual server request must use the /api path. * For example, - * /api?command=OpenReport => request sent to production server - * /staging/api?command=OpenReport => request sent to staging server - * /staging-secure/api?command=OpenReport => request sent to secure staging server + * /api/OpenReport => request sent to production server + * /staging/api/OpenReport => request sent to staging server + * /staging-secure/api/OpenReport => request sent to secure staging server * /chat-attachments/46545... => request sent to production server * /receipts/w_... => request sent to production server * /staging/chat-attachments/46545... => request sent to staging server From 7270bf2612aafd8f69adc534b3f448aa737cf57f Mon Sep 17 00:00:00 2001 From: Alberto Date: Thu, 14 Mar 2024 22:00:03 +0100 Subject: [PATCH 105/175] add sendMoney --- src/libs/actions/IOU.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index f89c44d9d0a4..dbff8fb4895a 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -565,7 +565,6 @@ function buildOnyxDataForMoneyRequest( ); if (!isOneOnOneSplit) { - console.log('bad'); optimisticData.push({ onyxMethod: Onyx.METHOD.SET, key: ONYXKEYS.NVP_QUICK_ACTION_GLOBAL_CREATE, @@ -3329,6 +3328,15 @@ function getSendMoneyParams( lastVisibleActionCreated: reportPreviewAction.created, }, }; + const optimisticQuickActionData: OnyxUpdate = { + onyxMethod: Onyx.METHOD.SET, + key: ONYXKEYS.NVP_QUICK_ACTION_GLOBAL_CREATE, + value: { + action: CONST.QUICK_ACTIONS.SEND_MONEY, + reportID: chatReport.reportID, + isFirstQuickAction: isEmptyObject(quickAction), + }, + }; const optimisticIOUReportData: OnyxUpdate = { onyxMethod: Onyx.METHOD.SET, key: `${ONYXKEYS.COLLECTION.REPORT}${optimisticIOUReport.reportID}`, @@ -3495,6 +3503,7 @@ function getSendMoneyParams( const optimisticData: OnyxUpdate[] = [ optimisticChatReportData, + optimisticQuickActionData, optimisticIOUReportData, optimisticChatReportActionsData, optimisticIOUReportActionsData, From 9e0d5b9dc20dd6eb3453d7a494e05ff6ec37d300 Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Fri, 15 Mar 2024 14:55:45 +0800 Subject: [PATCH 106/175] add missing param --- src/libs/actions/Plaid.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libs/actions/Plaid.ts b/src/libs/actions/Plaid.ts index 78bc91618215..7f63b3920e01 100644 --- a/src/libs/actions/Plaid.ts +++ b/src/libs/actions/Plaid.ts @@ -11,10 +11,11 @@ import ONYXKEYS from '@src/ONYXKEYS'; */ function openPlaidBankLogin(allowDebit: boolean, bankAccountID: number) { // redirect_uri needs to be in kebab case convention because that's how it's passed to the backend - const {redirectURI} = getPlaidLinkTokenParameters(); + const {redirectURI, androidPackage} = getPlaidLinkTokenParameters(); const params: OpenPlaidBankLoginParams = { redirectURI, + androidPackage, allowDebit, bankAccountID, }; From fe113e752c2f848efcdb7a8217aa2cf1db482a82 Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Fri, 15 Mar 2024 14:55:52 +0800 Subject: [PATCH 107/175] update type --- src/libs/API/parameters/OpenPlaidBankLoginParams.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libs/API/parameters/OpenPlaidBankLoginParams.ts b/src/libs/API/parameters/OpenPlaidBankLoginParams.ts index f76e05423d03..c72154b0e9e7 100644 --- a/src/libs/API/parameters/OpenPlaidBankLoginParams.ts +++ b/src/libs/API/parameters/OpenPlaidBankLoginParams.ts @@ -1,5 +1,6 @@ type OpenPlaidBankLoginParams = { redirectURI: string | undefined; + androidPackage?: string, allowDebit: boolean; bankAccountID: number; }; From 9f27106786b6b12381ba9afdc9bc0e813c1e889c Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Fri, 15 Mar 2024 15:06:18 +0800 Subject: [PATCH 108/175] prettier --- src/libs/API/parameters/OpenPlaidBankLoginParams.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/API/parameters/OpenPlaidBankLoginParams.ts b/src/libs/API/parameters/OpenPlaidBankLoginParams.ts index c72154b0e9e7..d60596eeb08f 100644 --- a/src/libs/API/parameters/OpenPlaidBankLoginParams.ts +++ b/src/libs/API/parameters/OpenPlaidBankLoginParams.ts @@ -1,6 +1,6 @@ type OpenPlaidBankLoginParams = { redirectURI: string | undefined; - androidPackage?: string, + androidPackage?: string; allowDebit: boolean; bankAccountID: number; }; From 832b5237c106da2d4345fd8a76738bd9e461751a Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Fri, 15 Mar 2024 14:40:33 +0700 Subject: [PATCH 109/175] update correct policyName in optimistic data --- src/libs/actions/Policy.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libs/actions/Policy.ts b/src/libs/actions/Policy.ts index 6699f8756005..53ecf6299fe5 100644 --- a/src/libs/actions/Policy.ts +++ b/src/libs/actions/Policy.ts @@ -318,6 +318,7 @@ function deleteWorkspace(policyID: string, policyName: string) { statusNum: CONST.REPORT.STATUS_NUM.CLOSED, hasDraft: false, oldPolicyName: allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${policyID}`]?.name ?? '', + policyName: '', }, }); @@ -364,6 +365,7 @@ function deleteWorkspace(policyID: string, policyName: string) { statusNum, hasDraft, oldPolicyName, + policyName: report?.policyName, }, }); }); From 8f6416da627f78f32bd83c71f24928918629dbf3 Mon Sep 17 00:00:00 2001 From: Alberto Date: Fri, 15 Mar 2024 10:46:06 +0100 Subject: [PATCH 110/175] Add task --- src/libs/actions/Task.ts | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/libs/actions/Task.ts b/src/libs/actions/Task.ts index 48ab7cce9186..1a844a480c73 100644 --- a/src/libs/actions/Task.ts +++ b/src/libs/actions/Task.ts @@ -58,6 +58,14 @@ Onyx.connect({ callback: (value) => (allPersonalDetails = value), }); +let quickAction: OnyxEntry = {}; +Onyx.connect({ + key: ONYXKEYS.NVP_QUICK_ACTION_GLOBAL_CREATE, + callback: (value) => { + quickAction = value; + }, +}); + const allReportActions: OnyxCollection = {}; Onyx.connect({ key: ONYXKEYS.COLLECTION.REPORT_ACTIONS, @@ -219,6 +227,19 @@ function createTaskAndNavigate( }, ); + // FOR QUICK ACTION NVP + optimisticData.push( + { + onyxMethod: Onyx.METHOD.SET, + key: ONYXKEYS.NVP_QUICK_ACTION_GLOBAL_CREATE, + value:{ + action: CONST.QUICK_ACTIONS.ASSIGN_TASK, + reportID: parentReportID, + isFirstQuickAction: isEmptyObject(quickAction), + }, + }, + ); + // If needed, update optimistic data for parent report action of the parent report. const optimisticParentReportData = ReportUtils.getOptimisticDataForParentReportAction(parentReportID, currentTime, CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD); if (!isEmptyObject(optimisticParentReportData)) { From b1807ee35bdcd9d1936cc7fff452f3cdad500661 Mon Sep 17 00:00:00 2001 From: Alberto Date: Fri, 15 Mar 2024 10:54:24 +0100 Subject: [PATCH 111/175] add type and target account --- src/libs/actions/Task.ts | 1 + src/types/onyx/QuickAction.ts | 2 +- src/types/onyx/index.ts | 2 ++ 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/libs/actions/Task.ts b/src/libs/actions/Task.ts index 1a844a480c73..b8129d8c6766 100644 --- a/src/libs/actions/Task.ts +++ b/src/libs/actions/Task.ts @@ -236,6 +236,7 @@ function createTaskAndNavigate( action: CONST.QUICK_ACTIONS.ASSIGN_TASK, reportID: parentReportID, isFirstQuickAction: isEmptyObject(quickAction), + targetAccountID: assigneeAccountID, }, }, ); diff --git a/src/types/onyx/QuickAction.ts b/src/types/onyx/QuickAction.ts index d26482deb969..310c3d1a27ba 100644 --- a/src/types/onyx/QuickAction.ts +++ b/src/types/onyx/QuickAction.ts @@ -9,7 +9,7 @@ type QuickAction = { reportID: string; /** ID of the target account for task actions */ - accountID?: number; + targetAccountID?: number; /** True if it is the first quick action we store for this user */ isFirstQuickAction?: boolean; diff --git a/src/types/onyx/index.ts b/src/types/onyx/index.ts index e3118538258e..7d129d8e2cd9 100644 --- a/src/types/onyx/index.ts +++ b/src/types/onyx/index.ts @@ -43,6 +43,7 @@ import type {PolicyTag, PolicyTagList, PolicyTags} from './PolicyTag'; import type PreferredTheme from './PreferredTheme'; import type PriorityMode from './PriorityMode'; import type PrivatePersonalDetails from './PrivatePersonalDetails'; +import type QuickAction from './QuickAction'; import type RecentlyUsedCategories from './RecentlyUsedCategories'; import type RecentlyUsedReportFields from './RecentlyUsedReportFields'; import type RecentlyUsedTags from './RecentlyUsedTags'; @@ -119,6 +120,7 @@ export type { PreferredTheme, PriorityMode, PrivatePersonalDetails, + QuickAction, RecentWaypoint, RecentlyUsedCategories, RecentlyUsedTags, From 84d9bf48fb1c98af04818643c7f441fbbc64aea7 Mon Sep 17 00:00:00 2001 From: Alberto Date: Fri, 15 Mar 2024 12:05:03 +0100 Subject: [PATCH 112/175] fix distance splits --- src/libs/actions/IOU.ts | 9 ++++++--- src/pages/iou/request/step/IOURequestStepConfirmation.js | 2 ++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index dbff8fb4895a..26f63179416b 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -1674,6 +1674,7 @@ function createSplitsAndOnyxData( tag: string, existingSplitChatReportID = '', billable = false, + iouRequestType = CONST.IOU.REQUEST_TYPE.MANUAL, ): SplitsAndOnyxData { const currentUserEmailForIOUSplit = PhoneNumber.addSMSDomainIfPhoneNumber(currentUserLogin); const participantAccountIDs = participants.map((participant) => Number(participant.accountID)); @@ -1729,7 +1730,6 @@ function createSplitsAndOnyxData( }; } - console.log('here'); const optimisticData: OnyxUpdate[] = [ { // Use set for new reports because it doesn't exist yet, is faster, @@ -1742,7 +1742,7 @@ function createSplitsAndOnyxData( onyxMethod: Onyx.METHOD.SET, key: ONYXKEYS.NVP_QUICK_ACTION_GLOBAL_CREATE, value:{ - action: TransactionUtils.isDistanceRequest(splitTransaction) ? CONST.QUICK_ACTIONS.SPLIT_DISTANCE : CONST.QUICK_ACTIONS.SPLIT_MANUAL, + action: iouRequestType === CONST.IOU.REQUEST_TYPE.DISTANCE ? CONST.QUICK_ACTIONS.SPLIT_DISTANCE : CONST.QUICK_ACTIONS.SPLIT_MANUAL, reportID: splitChatReport.reportID, isFirstQuickAction: isEmptyObject(quickAction), }, @@ -2041,6 +2041,7 @@ function splitBill( tag: string, existingSplitChatReportID = '', billable = false, + iouRequestType = CONST.IOU.REQUEST_TYPE.MANUAL, ) { const currentCreated = DateUtils.enrichMoneyRequestTimestamp(created); const {splitData, splits, onyxData} = createSplitsAndOnyxData( @@ -2056,6 +2057,7 @@ function splitBill( tag, existingSplitChatReportID, billable, + iouRequestType, ); const parameters: SplitBillParams = { @@ -2097,9 +2099,10 @@ function splitBillAndOpenReport( category: string, tag: string, billable: boolean, + iouRequestType = CONST.IOU.REQUEST_TYPE.MANUAL, ) { const currentCreated = DateUtils.enrichMoneyRequestTimestamp(created); - const {splitData, splits, onyxData} = createSplitsAndOnyxData(participants, currentUserLogin, currentUserAccountID, amount, comment, currency, merchant, currentCreated, category, tag); + const {splitData, splits, onyxData} = createSplitsAndOnyxData(participants, currentUserLogin, currentUserAccountID, amount, comment, currency, merchant, currentCreated, category, tag, '', billable, iouRequestType); const parameters: SplitBillParams = { reportID: splitData.chatReportID, diff --git a/src/pages/iou/request/step/IOURequestStepConfirmation.js b/src/pages/iou/request/step/IOURequestStepConfirmation.js index 9904f64d6833..21ff06bf0c83 100644 --- a/src/pages/iou/request/step/IOURequestStepConfirmation.js +++ b/src/pages/iou/request/step/IOURequestStepConfirmation.js @@ -286,6 +286,7 @@ function IOURequestStepConfirmation({ transaction.tag, report.reportID, transaction.billable, + transaction.iouRequestType, ); return; } @@ -304,6 +305,7 @@ function IOURequestStepConfirmation({ transaction.category, transaction.tag, transaction.billable, + transaction.iouRequestType, ); return; } From 9bbbee651ec87714ce479250e927880a8d0671e0 Mon Sep 17 00:00:00 2001 From: Alberto Date: Fri, 15 Mar 2024 12:37:28 +0100 Subject: [PATCH 113/175] prettier --- src/libs/actions/IOU.ts | 24 +++++++++++++++++++----- src/libs/actions/Task.ts | 20 +++++++++----------- 2 files changed, 28 insertions(+), 16 deletions(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 26f63179416b..c397b6849b07 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -510,7 +510,7 @@ function buildOnyxDataForMoneyRequest( key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transaction.transactionID}`, value: transaction, }, - isNewChatReport + isNewChatReport ? { onyxMethod: Onyx.METHOD.SET, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport?.reportID}`, @@ -568,7 +568,7 @@ function buildOnyxDataForMoneyRequest( optimisticData.push({ onyxMethod: Onyx.METHOD.SET, key: ONYXKEYS.NVP_QUICK_ACTION_GLOBAL_CREATE, - value:{ + value: { action: newQuickAction, reportID: chatReport?.reportID, isFirstQuickAction: isEmptyObject(quickAction), @@ -1741,7 +1741,7 @@ function createSplitsAndOnyxData( { onyxMethod: Onyx.METHOD.SET, key: ONYXKEYS.NVP_QUICK_ACTION_GLOBAL_CREATE, - value:{ + value: { action: iouRequestType === CONST.IOU.REQUEST_TYPE.DISTANCE ? CONST.QUICK_ACTIONS.SPLIT_DISTANCE : CONST.QUICK_ACTIONS.SPLIT_MANUAL, reportID: splitChatReport.reportID, isFirstQuickAction: isEmptyObject(quickAction), @@ -2102,7 +2102,21 @@ function splitBillAndOpenReport( iouRequestType = CONST.IOU.REQUEST_TYPE.MANUAL, ) { const currentCreated = DateUtils.enrichMoneyRequestTimestamp(created); - const {splitData, splits, onyxData} = createSplitsAndOnyxData(participants, currentUserLogin, currentUserAccountID, amount, comment, currency, merchant, currentCreated, category, tag, '', billable, iouRequestType); + const {splitData, splits, onyxData} = createSplitsAndOnyxData( + participants, + currentUserLogin, + currentUserAccountID, + amount, + comment, + currency, + merchant, + currentCreated, + category, + tag, + '', + billable, + iouRequestType, + ); const parameters: SplitBillParams = { reportID: splitData.chatReportID, @@ -2213,7 +2227,7 @@ function startSplitBill( { onyxMethod: Onyx.METHOD.SET, key: ONYXKEYS.NVP_QUICK_ACTION_GLOBAL_CREATE, - value:{ + value: { action: CONST.QUICK_ACTIONS.SPLIT_SCAN, reportID: splitChatReport.reportID, isFirstQuickAction: isEmptyObject(quickAction), diff --git a/src/libs/actions/Task.ts b/src/libs/actions/Task.ts index b8129d8c6766..b097ddf05ca5 100644 --- a/src/libs/actions/Task.ts +++ b/src/libs/actions/Task.ts @@ -228,18 +228,16 @@ function createTaskAndNavigate( ); // FOR QUICK ACTION NVP - optimisticData.push( - { - onyxMethod: Onyx.METHOD.SET, - key: ONYXKEYS.NVP_QUICK_ACTION_GLOBAL_CREATE, - value:{ - action: CONST.QUICK_ACTIONS.ASSIGN_TASK, - reportID: parentReportID, - isFirstQuickAction: isEmptyObject(quickAction), - targetAccountID: assigneeAccountID, - }, + optimisticData.push({ + onyxMethod: Onyx.METHOD.SET, + key: ONYXKEYS.NVP_QUICK_ACTION_GLOBAL_CREATE, + value: { + action: CONST.QUICK_ACTIONS.ASSIGN_TASK, + reportID: parentReportID, + isFirstQuickAction: isEmptyObject(quickAction), + targetAccountID: assigneeAccountID, }, - ); + }); // If needed, update optimistic data for parent report action of the parent report. const optimisticParentReportData = ReportUtils.getOptimisticDataForParentReportAction(parentReportID, currentTime, CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD); From 65a783ba9978fd927b32cebdb8bd59e511621f8f Mon Sep 17 00:00:00 2001 From: Alberto Date: Fri, 15 Mar 2024 12:40:14 +0100 Subject: [PATCH 114/175] typescript --- src/ONYXKEYS.ts | 1 + src/types/onyx/QuickAction.ts | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index b19499046661..4fbe0ac1f3f1 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -590,6 +590,7 @@ type OnyxValuesMapping = { [ONYXKEYS.LOGS]: Record; [ONYXKEYS.SHOULD_STORE_LOGS]: boolean; [ONYXKEYS.CACHED_PDF_PATHS]: Record; + [ONYXKEYS.NVP_QUICK_ACTION_GLOBAL_CREATE]: OnyxTypes.QuickAction; }; type OnyxValues = OnyxValuesMapping & OnyxCollectionValuesMapping & OnyxFormValuesMapping & OnyxFormDraftValuesMapping; diff --git a/src/types/onyx/QuickAction.ts b/src/types/onyx/QuickAction.ts index 310c3d1a27ba..6cf1af929a5c 100644 --- a/src/types/onyx/QuickAction.ts +++ b/src/types/onyx/QuickAction.ts @@ -3,10 +3,10 @@ import type CONST from '@src/CONST'; type QuickAction = { /** The action to take */ - action: ValueOf; + action?: ValueOf; /** ID of the report */ - reportID: string; + reportID?: string; /** ID of the target account for task actions */ targetAccountID?: number; From 560f3cc404c52d5e992809abf0bcdaa20cc34e1a Mon Sep 17 00:00:00 2001 From: Alberto Date: Fri, 15 Mar 2024 12:46:08 +0100 Subject: [PATCH 115/175] more typescript --- src/libs/actions/IOU.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index c397b6849b07..8f03c36ec618 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -471,7 +471,7 @@ function buildOnyxDataForMoneyRequest( const outstandingChildRequest = getOutstandingChildRequest(policy ?? {}, iouReport); const clearedPendingFields = Object.fromEntries(Object.keys(transaction.pendingFields ?? {}).map((key) => [key, null])); const optimisticData: OnyxUpdate[] = []; - let newQuickAction = isScanRequest ? CONST.QUICK_ACTIONS.REQUEST_SCAN : CONST.QUICK_ACTIONS.REQUEST_MANUAL; + let newQuickAction: string = isScanRequest ? CONST.QUICK_ACTIONS.REQUEST_SCAN : CONST.QUICK_ACTIONS.REQUEST_MANUAL; if (TransactionUtils.isDistanceRequest(transaction)) { newQuickAction = CONST.QUICK_ACTIONS.REQUEST_DISTANCE; } From ffc9fa34965f66fc63fbd3dca47c4eafba901b2a Mon Sep 17 00:00:00 2001 From: Alberto Date: Fri, 15 Mar 2024 12:53:07 +0100 Subject: [PATCH 116/175] still fighting typescript --- src/libs/actions/IOU.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 8f03c36ec618..f1a4104f1850 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -471,7 +471,7 @@ function buildOnyxDataForMoneyRequest( const outstandingChildRequest = getOutstandingChildRequest(policy ?? {}, iouReport); const clearedPendingFields = Object.fromEntries(Object.keys(transaction.pendingFields ?? {}).map((key) => [key, null])); const optimisticData: OnyxUpdate[] = []; - let newQuickAction: string = isScanRequest ? CONST.QUICK_ACTIONS.REQUEST_SCAN : CONST.QUICK_ACTIONS.REQUEST_MANUAL; + let newQuickAction: ValueOf = isScanRequest ? CONST.QUICK_ACTIONS.REQUEST_SCAN : CONST.QUICK_ACTIONS.REQUEST_MANUAL; if (TransactionUtils.isDistanceRequest(transaction)) { newQuickAction = CONST.QUICK_ACTIONS.REQUEST_DISTANCE; } From 5604d9f0aefb379c0374ceb11d4469c35df6925b Mon Sep 17 00:00:00 2001 From: Alberto Date: Fri, 15 Mar 2024 13:08:01 +0100 Subject: [PATCH 117/175] typo --- src/libs/actions/IOU.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index f1a4104f1850..dac2a8216f8a 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -471,7 +471,7 @@ function buildOnyxDataForMoneyRequest( const outstandingChildRequest = getOutstandingChildRequest(policy ?? {}, iouReport); const clearedPendingFields = Object.fromEntries(Object.keys(transaction.pendingFields ?? {}).map((key) => [key, null])); const optimisticData: OnyxUpdate[] = []; - let newQuickAction: ValueOf = isScanRequest ? CONST.QUICK_ACTIONS.REQUEST_SCAN : CONST.QUICK_ACTIONS.REQUEST_MANUAL; + let newQuickAction: ValueOf = isScanRequest ? CONST.QUICK_ACTIONS.REQUEST_SCAN : CONST.QUICK_ACTIONS.REQUEST_MANUAL; if (TransactionUtils.isDistanceRequest(transaction)) { newQuickAction = CONST.QUICK_ACTIONS.REQUEST_DISTANCE; } From 1341932c91b756e3c580c4adc65e48d7c635b530 Mon Sep 17 00:00:00 2001 From: Alberto Date: Fri, 15 Mar 2024 13:13:42 +0100 Subject: [PATCH 118/175] hopefully last one --- src/libs/actions/IOU.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index dac2a8216f8a..37b1e5c00091 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -1674,7 +1674,7 @@ function createSplitsAndOnyxData( tag: string, existingSplitChatReportID = '', billable = false, - iouRequestType = CONST.IOU.REQUEST_TYPE.MANUAL, + iouRequestType: IOURequestType = CONST.IOU.REQUEST_TYPE.MANUAL, ): SplitsAndOnyxData { const currentUserEmailForIOUSplit = PhoneNumber.addSMSDomainIfPhoneNumber(currentUserLogin); const participantAccountIDs = participants.map((participant) => Number(participant.accountID)); @@ -2041,7 +2041,7 @@ function splitBill( tag: string, existingSplitChatReportID = '', billable = false, - iouRequestType = CONST.IOU.REQUEST_TYPE.MANUAL, + iouRequestType: IOURequestType = CONST.IOU.REQUEST_TYPE.MANUAL, ) { const currentCreated = DateUtils.enrichMoneyRequestTimestamp(created); const {splitData, splits, onyxData} = createSplitsAndOnyxData( @@ -2099,7 +2099,7 @@ function splitBillAndOpenReport( category: string, tag: string, billable: boolean, - iouRequestType = CONST.IOU.REQUEST_TYPE.MANUAL, + iouRequestType: IOURequestType = CONST.IOU.REQUEST_TYPE.MANUAL, ) { const currentCreated = DateUtils.enrichMoneyRequestTimestamp(created); const {splitData, splits, onyxData} = createSplitsAndOnyxData( From cc63c22102c26694487608dc9d36f9d94d35f00d Mon Sep 17 00:00:00 2001 From: Krishna Gupta Date: Fri, 15 Mar 2024 21:04:48 +0530 Subject: [PATCH 119/175] add suggested changes. Signed-off-by: Krishna Gupta --- src/components/Modal/BaseModal.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/Modal/BaseModal.tsx b/src/components/Modal/BaseModal.tsx index 514bcc421e09..4604e831a2ae 100644 --- a/src/components/Modal/BaseModal.tsx +++ b/src/components/Modal/BaseModal.tsx @@ -120,8 +120,9 @@ function BaseModal( if (onBackdropPress) { onBackdropPress(); + } else { + onClose(); } - onClose(); }; const handleDismissModal = () => { From 9327009a4e38e75b3a865aed93fe9c41f272333d Mon Sep 17 00:00:00 2001 From: BrtqKr Date: Fri, 15 Mar 2024 17:07:57 +0100 Subject: [PATCH 120/175] review fixes --- workflow_tests/utils/ExtendedAct.ts | 21 +++++++++++++----- workflow_tests/utils/JobMocker.ts | 12 +++++----- workflow_tests/utils/preGenerateTest.ts | 15 +++++++------ workflow_tests/utils/utils.ts | 29 +++++++++++++++---------- 4 files changed, 49 insertions(+), 28 deletions(-) diff --git a/workflow_tests/utils/ExtendedAct.ts b/workflow_tests/utils/ExtendedAct.ts index 99b8551337b8..81c2f0b981b2 100644 --- a/workflow_tests/utils/ExtendedAct.ts +++ b/workflow_tests/utils/ExtendedAct.ts @@ -4,31 +4,41 @@ import type {RunOpts, Workflow} from '@kie/act-js'; import * as kieActJs from '@kie/act-js'; import path from 'path'; import {JobMocker} from './JobMocker'; -import type {MockJob} from './JobMocker'; +import type {MockJobs} from './JobMocker'; -type ExtendedActOpts = RunOpts & {actor?: string; workflowFile?: string; mockJobs?: Record}; +type ExtendedActOpts = RunOpts & {actor?: string; workflowFile?: string; mockJobs?: MockJobs}; + +type ActOptions = { + cwd: string | undefined; + actArguments: string[]; + proxy: unknown; +}; // @ts-expect-error Override shouldn't be done on private methods wait until https://github.com/kiegroup/act-js/issues/77 is resolved or try to create a params workaround class ExtendedAct extends kieActJs.Act { - async parseRunOpts(opts?: ExtendedActOpts) { + async parseRunOpts(opts?: ExtendedActOpts): Promise { const {cwd, actArguments, proxy} = await super['parseRunOpts'](opts); + if (opts?.actor) { actArguments.push('--actor', opts.actor); } + return {cwd, actArguments, proxy}; } - async runEvent(event: string, opts?: ExtendedActOpts) { + async runEvent(event: string, opts?: ExtendedActOpts): Promise { const {mockJobs, ...vanillaOpts} = opts ?? {}; if (mockJobs) { await this.handleJobMocking((workflow) => workflow.events.includes(event), {mockJobs, workflowFile: opts?.workflowFile, cwd: opts?.cwd}); } + return super.runEvent(event, vanillaOpts); } - async handleJobMocking(filter: (workflow: Workflow) => boolean, opts?: ExtendedActOpts) { + async handleJobMocking(filter: (workflow: Workflow) => boolean, opts?: ExtendedActOpts): Promise { let workflowFiles: string[]; + if (opts?.workflowFile) { workflowFiles = [path.basename(opts.workflowFile)]; } else if (this['workflowFile'] !== this['cwd']) { @@ -37,6 +47,7 @@ class ExtendedAct extends kieActJs.Act { const availableWorkflows = await this.list(undefined, opts?.cwd, opts?.workflowFile); workflowFiles = availableWorkflows.filter(filter).map((workflow: Workflow) => workflow.workflowFile); } + return Promise.all( workflowFiles.map((workflowFile) => { const jobMocker = new JobMocker(workflowFile, opts?.cwd ?? this['cwd']); diff --git a/workflow_tests/utils/JobMocker.ts b/workflow_tests/utils/JobMocker.ts index 3bbdaa118e0c..84ab7fe66f41 100644 --- a/workflow_tests/utils/JobMocker.ts +++ b/workflow_tests/utils/JobMocker.ts @@ -19,6 +19,8 @@ type MockJob = { runsOn: string; }; +type MockJobs = Record; + type MockJobStep = { id?: string; name: string; @@ -39,7 +41,7 @@ class JobMocker { this.cwd = cwd; } - mock(mockJobs: Record = {}) { + mock(mockJobs: MockJobs = {}) { const filePath = this.getWorkflowPath(); const workflow = this.readWorkflowFile(filePath); @@ -83,11 +85,11 @@ class JobMocker { return this.writeWorkflowFile(filePath, workflow); } - locateJob(workflow: YamlWorkflow, jobId: string) { + locateJob(workflow: YamlWorkflow, jobId: string): YamlMockJob { return workflow.jobs[jobId]; } - getWorkflowPath() { + getWorkflowPath(): string { if (fs.existsSync(path.join(this.cwd, this.workflowFile))) { return path.join(this.cwd, this.workflowFile); } @@ -100,7 +102,7 @@ class JobMocker { throw new Error(`Could not locate ${this.workflowFile}`); } - readWorkflowFile(location: PathOrFileDescriptor) { + readWorkflowFile(location: PathOrFileDescriptor): YamlWorkflow { const test: YamlWorkflow = yaml.parse(fs.readFileSync(location, 'utf8')); return test; @@ -113,4 +115,4 @@ class JobMocker { // eslint-disable-next-line import/prefer-default-export export {JobMocker}; -export type {MockJob, YamlWorkflow, YamlMockJob, MockJobStep}; +export type {MockJob, MockJobs, YamlWorkflow, YamlMockJob, MockJobStep}; diff --git a/workflow_tests/utils/preGenerateTest.ts b/workflow_tests/utils/preGenerateTest.ts index 1bc5a01975e7..1f1826ea6b0d 100644 --- a/workflow_tests/utils/preGenerateTest.ts +++ b/workflow_tests/utils/preGenerateTest.ts @@ -106,7 +106,8 @@ const ${stepMockName} = utils.createMockStep( ${step.envs ? JSON.stringify(step.envs).replaceAll('"', "'") : 'null'}, // add outputs if needed );`; -const stepAssertionTemplate = (stepName: string, jobId: string, stepMessage: string, inputs: string[] = [], envs: string[] = []) => { + +const stepAssertionTemplate = (stepName: string, jobId: string, stepMessage: string, inputs: string[] = [], envs: string[] = []): string => { const inputsString = inputs.map((input) => `{key: '${input}', value: '[FILL_IN]'}`).join(','); const envsString = envs.map((env) => `{key: '${env}', value: '[FILL_IN]'}`).join(','); @@ -122,7 +123,7 @@ const stepAssertionTemplate = (stepName: string, jobId: string, stepMessage: str ),`; }; -const jobMocksTemplate = (jobMocksName: string, stepMocks: string[]) => { +const jobMocksTemplate = (jobMocksName: string, stepMocks: string[]): string => { const stepMocksString = stepMocks.map((stepMock) => `${stepMock}`).join(','); return `const ${jobMocksName} = [${stepMocksString}\n];`; @@ -141,13 +142,13 @@ const ${jobAssertionName} = (workflowResult, didExecute = true) => { } };`; -const mocksExportsTemplate = (jobMocks: string[]) => { +const mocksExportsTemplate = (jobMocks: string[]): string => { const jobMocksString = jobMocks.map((jobMock) => ` ${jobMock}: ${jobMock}`).join(',\n'); return `module.exports = {\n${jobMocksString}\n};\n`; }; -const assertionsExportsTemplate = (jobAssertions: string[]) => { +const assertionsExportsTemplate = (jobAssertions: string[]): string => { const assertionsString = jobAssertions.map((assertion) => ` ${assertion}: ${assertion}`).join(',\n'); return `module.exports = {\n${assertionsString}\n};\n`; @@ -212,7 +213,7 @@ const parseWorkflowFile = (workflow: YamlWorkflow) => { }); return workflowJobs; }; -const getMockFileContent = (workflowName: string, jobs: Record) => { +const getMockFileContent = (workflowName: string, jobs: Record): string => { let content = ''; const jobMocks: string[] = []; Object.entries(jobs).forEach(([jobId, job]) => { @@ -235,7 +236,7 @@ const getMockFileContent = (workflowName: string, jobs: Record) => { +const getAssertionsFileContent = (jobs: Record): string => { let content = ''; const jobAssertions: string[] = []; Object.entries(jobs).forEach(([jobId, job]) => { @@ -249,7 +250,7 @@ const getAssertionsFileContent = (jobs: Record) => { }); return assertionFileTemplate(content, assertionsExportsTemplate(jobAssertions)); }; -const getTestFileContent = (workflowName: string) => testFileTemplate(workflowName); +const getTestFileContent = (workflowName: string): string => testFileTemplate(workflowName); const callArgs = process.argv.slice(2); checkArguments(callArgs); diff --git a/workflow_tests/utils/utils.ts b/workflow_tests/utils/utils.ts index 7fc57eed75ad..71bb2194c9fe 100644 --- a/workflow_tests/utils/utils.ts +++ b/workflow_tests/utils/utils.ts @@ -8,6 +8,14 @@ type EventOptions = { action?: string; }; +type StepAssertionInputEntry = {key: string; value: string}; + +type StepAssertion = { + name: string; + status: number; + output: string; +}; + function setUpActParams( act: ExtendedAct, event: string | null = null, @@ -16,7 +24,7 @@ function setUpActParams( githubToken: string | null = null, envVars: Record | null = null, inputs: Record | null = null, -) { +): ExtendedAct { let updatedAct = act; if (event && eventOptions) { @@ -64,7 +72,7 @@ function createMockStep( outputs: Record | null = null, outEnvs: Record | null = null, isSuccessful = true, - id = null, + id: string | null = null, ): StepIdentifier { const mockStepName = name; let mockWithCommand = 'echo [MOCK]'; @@ -112,16 +120,16 @@ function createMockStep( function createStepAssertion( name: string, isSuccessful = true, - expectedOutput = null, + expectedOutput: string | null = null, jobId: string | null = null, message: string | null = null, - inputs: Array<{key: string; value: string}> | null = null, - envs: Array<{key: string; value: string}> | null = null, -) { + inputs: StepAssertionInputEntry[] | null = null, + envs: StepAssertionInputEntry[] | null = null, +): StepAssertion { const stepName = `Main ${name}`; const stepStatus = isSuccessful ? 0 : 1; let stepOutput: string; - if (expectedOutput !== undefined && expectedOutput !== null) { + if (expectedOutput !== null) { stepOutput = expectedOutput; } else { stepOutput = '[MOCK]'; @@ -149,7 +157,7 @@ function createStepAssertion( }; } -function setJobRunners(act: ExtendedAct, jobs: Record, workflowPath: string) { +function setJobRunners(act: ExtendedAct, jobs: Record, workflowPath: string): ExtendedAct { if (!act || !jobs || !workflowPath) { return act; } @@ -164,11 +172,10 @@ function setJobRunners(act: ExtendedAct, jobs: Record, workflowP } function deepCopy(originalObject: TObject): TObject { - // eslint-disable-next-line @typescript-eslint/no-unsafe-return - return JSON.parse(JSON.stringify(originalObject)); + return JSON.parse(JSON.stringify(originalObject)) as TObject; } -function getLogFilePath(workflowName: string, testName: string | undefined) { +function getLogFilePath(workflowName: string, testName: string | undefined): string { if (!testName) { throw new Error(); } From 863fbd3266e1c74c16364da8079a8f6b52e9ba78 Mon Sep 17 00:00:00 2001 From: Artem Makushov Date: Fri, 15 Mar 2024 17:52:39 +0100 Subject: [PATCH 121/175] fixes --- src/ROUTES.ts | 4 ++-- src/libs/Navigation/linkingConfig/config.ts | 2 +- src/libs/actions/Policy.ts | 5 +---- .../{WorkspaceEditTagPage.tsx => EditTagPage.tsx} | 14 +++++++------- 4 files changed, 11 insertions(+), 14 deletions(-) rename src/pages/workspace/tags/{WorkspaceEditTagPage.tsx => EditTagPage.tsx} (92%) diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 9f014a47b4c0..f41201dfea4b 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -586,8 +586,8 @@ const ROUTES = { getRoute: (policyID: string) => `settings/workspaces/${policyID}/tags/edit` as const, }, WORKSPACE_TAG_EDIT: { - route: 'workspace/:policyID/tags/:tagName/edit', - getRoute: (policyID: string, tagName: string) => `workspace/${policyID}/tags/${encodeURI(tagName)}/edit` as const, + route: 'workspace/:policyID/tag/:tagName/edit', + getRoute: (policyID: string, tagName: string) => `workspace/${policyID}/tag/${encodeURIComponent(tagName)}/edit` as const, }, WORKSPACE_TAXES: { route: 'settings/workspaces/:policyID/taxes', diff --git a/src/libs/Navigation/linkingConfig/config.ts b/src/libs/Navigation/linkingConfig/config.ts index aacc759c4bfd..38c7704ddf28 100644 --- a/src/libs/Navigation/linkingConfig/config.ts +++ b/src/libs/Navigation/linkingConfig/config.ts @@ -295,7 +295,7 @@ const config: LinkingOptions['config'] = { [SCREENS.WORKSPACE.TAG_EDIT]: { path: ROUTES.WORKSPACE_TAG_EDIT.route, parse: { - tagName: (tagName: string) => decodeURI(tagName), + tagName: (tagName: string) => decodeURIComponent(tagName), }, }, [SCREENS.REIMBURSEMENT_ACCOUNT]: { diff --git a/src/libs/actions/Policy.ts b/src/libs/actions/Policy.ts index a4aba7e1ad5b..7ddb4c7a8c12 100644 --- a/src/libs/actions/Policy.ts +++ b/src/libs/actions/Policy.ts @@ -2855,7 +2855,6 @@ function renamePolicyTag(policyID: string, policyTag: {oldName: string; newName: value: { [tagListName]: { tags: { - [policyTag.oldName]: null, [policyTag.newName]: { ...oldTag, name: policyTag.newName, @@ -2877,9 +2876,7 @@ function renamePolicyTag(policyID: string, policyTag: {oldName: string; newName: [policyTag.newName]: null, [policyTag.oldName]: { ...oldTag, - name: policyTag.oldName, - errors: ErrorUtils.getMicroSecondOnyxError('workspace.categories.genericFailureMessage'), - pendingAction: null, + errors: ErrorUtils.getMicroSecondOnyxError('workspace.tags.genericFailureMessage'), }, }, }, diff --git a/src/pages/workspace/tags/WorkspaceEditTagPage.tsx b/src/pages/workspace/tags/EditTagPage.tsx similarity index 92% rename from src/pages/workspace/tags/WorkspaceEditTagPage.tsx rename to src/pages/workspace/tags/EditTagPage.tsx index 1ba3f88a3c68..c32f089b53c1 100644 --- a/src/pages/workspace/tags/WorkspaceEditTagPage.tsx +++ b/src/pages/workspace/tags/EditTagPage.tsx @@ -27,12 +27,12 @@ import type SCREENS from '@src/SCREENS'; import INPUT_IDS from '@src/types/form/WorkspaceTagForm'; import type {PolicyTagList} from '@src/types/onyx'; -type WorkspaceEditTagPageOnyxProps = { +type EditTagPageOnyxProps = { /** All policy tags */ policyTags: OnyxEntry; }; -type EditTagPageProps = WorkspaceEditTagPageOnyxProps & StackScreenProps; +type EditTagPageProps = EditTagPageOnyxProps & StackScreenProps; function EditTagPage({route, policyTags}: EditTagPageProps) { const styles = useThemeStyles(); @@ -40,8 +40,8 @@ function EditTagPage({route, policyTags}: EditTagPageProps) { const {inputCallbackRef} = useAutoFocusInput(); const validate = useCallback( - (values: FormOnyxValues) => { - const errors: FormInputErrors = {}; + (values: FormOnyxValues) => { + const errors: FormInputErrors = {}; const tagName = values.tagName.trim(); const {tags} = PolicyUtils.getTagList(policyTags, 0); @@ -60,7 +60,7 @@ function EditTagPage({route, policyTags}: EditTagPageProps) { ); const editTag = useCallback( - (values: FormOnyxValues) => { + (values: FormOnyxValues) => { Policy.renamePolicyTag(route.params.policyID, {oldName: route.params.tagName, newName: values.tagName.trim()}); Keyboard.dismiss(); Navigation.goBack(ROUTES.WORKSPACE_TAGS.getRoute(route.params.policyID)); @@ -82,7 +82,7 @@ function EditTagPage({route, policyTags}: EditTagPageProps) { onBackButtonPress={Navigation.goBack} /> ({ +export default withOnyx({ policyTags: { key: ({route}) => `${ONYXKEYS.COLLECTION.POLICY_TAGS}${route?.params?.policyID}`, }, From 9e5aa9d873d3f0cd11d863d820fccbe3900b09fe Mon Sep 17 00:00:00 2001 From: Andrew Gable Date: Fri, 15 Mar 2024 13:58:18 -0600 Subject: [PATCH 122/175] Add required depdency to useEffect to fix transition --- src/pages/LogOutPreviousUserPage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/LogOutPreviousUserPage.tsx b/src/pages/LogOutPreviousUserPage.tsx index d1d51033c147..37402ea8b048 100644 --- a/src/pages/LogOutPreviousUserPage.tsx +++ b/src/pages/LogOutPreviousUserPage.tsx @@ -78,7 +78,7 @@ function LogOutPreviousUserPage({session, route, isAccountLoading}: LogOutPrevio // We only want to run this effect once on mount (when the page first loads after transitioning from OldDot) // eslint-disable-next-line react-hooks/exhaustive-deps - }, [initialURL]); + }, [initialURL, isAccountLoading]); return ; } From 7a527debfe7638cb0dc2391682f12a4ffaf37352 Mon Sep 17 00:00:00 2001 From: Krishna Gupta Date: Mon, 18 Mar 2024 02:31:18 +0530 Subject: [PATCH 123/175] fix: Web - LHN - This is the beginning of your chat message can be seen for Your space. Signed-off-by: Krishna Gupta --- src/libs/SidebarUtils.ts | 39 ++++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/src/libs/SidebarUtils.ts b/src/libs/SidebarUtils.ts index 7bf163416054..4b4d71cd5cdc 100644 --- a/src/libs/SidebarUtils.ts +++ b/src/libs/SidebarUtils.ts @@ -352,25 +352,26 @@ function getOptionData({ if (!lastMessageText) { // Here we get the beginning of chat history message and append the display name for each user, adding pronouns if there are any. // We also add a fullstop after the final name, the word "and" before the final name and commas between all previous names. - lastMessageText = - Localize.translate(preferredLocale, 'reportActionsView.beginningOfChatHistory') + - displayNamesWithTooltips - .map(({displayName, pronouns}, index) => { - const formattedText = !pronouns ? displayName : `${displayName} (${pronouns})`; - - if (index === displayNamesWithTooltips.length - 1) { - return `${formattedText}.`; - } - if (index === displayNamesWithTooltips.length - 2) { - return `${formattedText} ${Localize.translate(preferredLocale, 'common.and')}`; - } - if (index < displayNamesWithTooltips.length - 2) { - return `${formattedText},`; - } - - return ''; - }) - .join(' '); + lastMessageText = ReportUtils.isSelfDM(report) + ? Localize.translate(preferredLocale, 'reportActionsView.beginningOfChatHistorySelfDM') + : Localize.translate(preferredLocale, 'reportActionsView.beginningOfChatHistory') + + displayNamesWithTooltips + .map(({displayName, pronouns}, index) => { + const formattedText = !pronouns ? displayName : `${displayName} (${pronouns})`; + + if (index === displayNamesWithTooltips.length - 1) { + return `${formattedText}.`; + } + if (index === displayNamesWithTooltips.length - 2) { + return `${formattedText} ${Localize.translate(preferredLocale, 'common.and')}`; + } + if (index < displayNamesWithTooltips.length - 2) { + return `${formattedText},`; + } + + return ''; + }) + .join(' '); } result.alternateText = ReportUtils.isGroupChat(report) && lastActorDisplayName ? `${lastActorDisplayName}: ${lastMessageText}` : lastMessageText || formattedLogin; From b088355852b54216d05a8748d804239dd5eacf1c Mon Sep 17 00:00:00 2001 From: Michal Muzyk Date: Mon, 18 Mar 2024 11:37:43 +0100 Subject: [PATCH 124/175] fix: remove redundant prop --- .../workspace/distanceRates/UnitSelector/UnitSelectorModal.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pages/workspace/distanceRates/UnitSelector/UnitSelectorModal.tsx b/src/pages/workspace/distanceRates/UnitSelector/UnitSelectorModal.tsx index cd4a7b926c4c..ec5e99778d8a 100644 --- a/src/pages/workspace/distanceRates/UnitSelector/UnitSelectorModal.tsx +++ b/src/pages/workspace/distanceRates/UnitSelector/UnitSelectorModal.tsx @@ -68,7 +68,6 @@ function UnitSelectorModal({isVisible, currentUnit, onUnitSelected, onClose, lab initiallyFocusedOptionKey={currentUnit} onSelectRow={onUnitSelected} shouldStopPropagation - shouldUseDynamicMaxToRenderPerBatch /> From 6a666d3545ff6c89029cc33ba5c0f8db7ff67770 Mon Sep 17 00:00:00 2001 From: Michal Muzyk Date: Mon, 18 Mar 2024 13:39:07 +0100 Subject: [PATCH 125/175] fix: access wrapper --- .../PolicyDistanceRatesSettingsPage.tsx | 46 +++++++++++-------- 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/src/pages/workspace/distanceRates/PolicyDistanceRatesSettingsPage.tsx b/src/pages/workspace/distanceRates/PolicyDistanceRatesSettingsPage.tsx index a5546e7d389b..ecc982e32dec 100644 --- a/src/pages/workspace/distanceRates/PolicyDistanceRatesSettingsPage.tsx +++ b/src/pages/workspace/distanceRates/PolicyDistanceRatesSettingsPage.tsx @@ -7,6 +7,8 @@ import ScreenWrapper from '@components/ScreenWrapper'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import type {SettingsNavigatorParamList} from '@navigation/types'; +import AdminPolicyAccessOrNotFoundWrapper from '@pages/workspace/AdminPolicyAccessOrNotFoundWrapper'; +import PaidPolicyAccessOrNotFoundWrapper from '@pages/workspace/PaidPolicyAccessOrNotFoundWrapper'; import * as Policy from '@userActions/Policy'; import ONYXKEYS from '@src/ONYXKEYS'; import type SCREENS from '@src/SCREENS'; @@ -47,24 +49,32 @@ function PolicyDistanceRatesSettingsPage({policy, policyCategories, route}: Poli }; return ( - - - - {policy?.areCategoriesEnabled && ( - - )} - + + + + + + {policy?.areCategoriesEnabled && ( + + )} + + + ); } From 3a46b9a585dd07e56c0688fdc9d72b1b72d98226 Mon Sep 17 00:00:00 2001 From: Artem Makushov Date: Mon, 18 Mar 2024 15:13:46 +0100 Subject: [PATCH 126/175] Changes for tag edit to work --- src/libs/API/parameters/RenamePolicyTagsParams.ts | 7 ++----- src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx | 2 +- .../linkingConfig/FULL_SCREEN_TO_RHP_MAPPING.ts | 2 +- src/libs/actions/Policy.ts | 3 ++- src/pages/workspace/tags/EditTagPage.tsx | 8 +++++--- src/pages/workspace/tags/TagSettingsPage.tsx | 8 ++++++++ src/pages/workspace/tags/WorkspaceCreateTagPage.tsx | 8 ++++---- 7 files changed, 23 insertions(+), 15 deletions(-) diff --git a/src/libs/API/parameters/RenamePolicyTagsParams.ts b/src/libs/API/parameters/RenamePolicyTagsParams.ts index 51686ade1b9e..bcf38384cf2c 100644 --- a/src/libs/API/parameters/RenamePolicyTagsParams.ts +++ b/src/libs/API/parameters/RenamePolicyTagsParams.ts @@ -1,10 +1,7 @@ type RenamePolicyTagsParams = { policyID: string; - /** - * Stringified JSON object with type of following structure: - * {[oldName: string]: string;} where value is new tag name - */ - tags: string; + oldName: string; + newName: string; }; export default RenamePolicyTagsParams; diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx index 43021e112fe9..9523d041988d 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx @@ -268,7 +268,7 @@ const SettingsModalStackNavigator = createModalStackNavigator require('../../../pages/workspace/tags/TagSettingsPage').default as React.ComponentType, [SCREENS.WORKSPACE.TAGS_EDIT]: () => require('../../../pages/workspace/tags/WorkspaceEditTagsPage').default as React.ComponentType, [SCREENS.WORKSPACE.TAG_CREATE]: () => require('../../../pages/workspace/tags/WorkspaceCreateTagPage').default as React.ComponentType, - [SCREENS.WORKSPACE.TAG_EDIT]: () => require('../../../pages/workspace/tags/WorkspaceEditTagPage').default as React.ComponentType, + [SCREENS.WORKSPACE.TAG_EDIT]: () => require('../../../pages/workspace/tags/EditTagPage').default as React.ComponentType, [SCREENS.REIMBURSEMENT_ACCOUNT]: () => require('../../../pages/ReimbursementAccount/ReimbursementAccountPage').default as React.ComponentType, [SCREENS.GET_ASSISTANCE]: () => require('../../../pages/GetAssistancePage').default as React.ComponentType, [SCREENS.SETTINGS.TWO_FACTOR_AUTH]: () => require('../../../pages/settings/Security/TwoFactorAuth/TwoFactorAuthPage').default as React.ComponentType, diff --git a/src/libs/Navigation/linkingConfig/FULL_SCREEN_TO_RHP_MAPPING.ts b/src/libs/Navigation/linkingConfig/FULL_SCREEN_TO_RHP_MAPPING.ts index 8713cbbcf6ba..8d862439c736 100755 --- a/src/libs/Navigation/linkingConfig/FULL_SCREEN_TO_RHP_MAPPING.ts +++ b/src/libs/Navigation/linkingConfig/FULL_SCREEN_TO_RHP_MAPPING.ts @@ -11,7 +11,7 @@ const FULL_SCREEN_TO_RHP_MAPPING: Partial> = { SCREENS.WORKSPACE.WORKFLOWS_AUTO_REPORTING_MONTHLY_OFFSET, SCREENS.WORKSPACE.WORKFLOWS_PAYER, ], - [SCREENS.WORKSPACE.TAGS]: [SCREENS.WORKSPACE.TAGS_SETTINGS, SCREENS.WORKSPACE.TAGS_EDIT, SCREENS.WORKSPACE.TAG_CREATE, SCREENS.WORKSPACE.TAG_SETTINGS], + [SCREENS.WORKSPACE.TAGS]: [SCREENS.WORKSPACE.TAGS_SETTINGS, SCREENS.WORKSPACE.TAGS_EDIT, SCREENS.WORKSPACE.TAG_CREATE, SCREENS.WORKSPACE.TAG_SETTINGS, SCREENS.WORKSPACE.TAG_EDIT], [SCREENS.WORKSPACE.CATEGORIES]: [SCREENS.WORKSPACE.CATEGORY_CREATE, SCREENS.WORKSPACE.CATEGORY_SETTINGS, SCREENS.WORKSPACE.CATEGORIES_SETTINGS, SCREENS.WORKSPACE.CATEGORY_EDIT], [SCREENS.WORKSPACE.DISTANCE_RATES]: [SCREENS.WORKSPACE.CREATE_DISTANCE_RATE], }; diff --git a/src/libs/actions/Policy.ts b/src/libs/actions/Policy.ts index 2f83b54d73a2..1ddfac93676b 100644 --- a/src/libs/actions/Policy.ts +++ b/src/libs/actions/Policy.ts @@ -3079,7 +3079,8 @@ function renamePolicyTag(policyID: string, policyTag: {oldName: string; newName: const parameters = { policyID, - tags: JSON.stringify({[policyTag.oldName]: policyTag.newName}), + oldName: policyTag.oldName, + newName: policyTag.newName, }; API.write(WRITE_COMMANDS.RENAME_POLICY_TAG, parameters, onyxData); diff --git a/src/pages/workspace/tags/EditTagPage.tsx b/src/pages/workspace/tags/EditTagPage.tsx index c32f089b53c1..cfa60b5e8ff6 100644 --- a/src/pages/workspace/tags/EditTagPage.tsx +++ b/src/pages/workspace/tags/EditTagPage.tsx @@ -38,6 +38,7 @@ function EditTagPage({route, policyTags}: EditTagPageProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); const {inputCallbackRef} = useAutoFocusInput(); + const currentTagName = route.params.tagName; const validate = useCallback( (values: FormOnyxValues) => { @@ -61,11 +62,11 @@ function EditTagPage({route, policyTags}: EditTagPageProps) { const editTag = useCallback( (values: FormOnyxValues) => { - Policy.renamePolicyTag(route.params.policyID, {oldName: route.params.tagName, newName: values.tagName.trim()}); + Policy.renamePolicyTag(route.params.policyID, {oldName: currentTagName, newName: values.tagName.trim()}); Keyboard.dismiss(); - Navigation.goBack(ROUTES.WORKSPACE_TAGS.getRoute(route.params.policyID)); + Navigation.dismissModal(); }, - [route.params.policyID, route.params.tagName], + [route.params.policyID, currentTagName], ); return ( @@ -92,6 +93,7 @@ function EditTagPage({route, policyTags}: EditTagPageProps) { { + Navigation.navigate(ROUTES.WORKSPACE_TAG_EDIT.getRoute(route.params.policyID, currentPolicyTag.name)); + }; + return ( @@ -75,6 +81,8 @@ function TagSettingsPage({route, policyTags}: TagSettingsPageProps) { diff --git a/src/pages/workspace/tags/WorkspaceCreateTagPage.tsx b/src/pages/workspace/tags/WorkspaceCreateTagPage.tsx index dc2c17427651..04c0cf8038d0 100644 --- a/src/pages/workspace/tags/WorkspaceCreateTagPage.tsx +++ b/src/pages/workspace/tags/WorkspaceCreateTagPage.tsx @@ -39,8 +39,8 @@ function CreateTagPage({route, policyTags}: CreateTagPageProps) { const {inputCallbackRef} = useAutoFocusInput(); const validate = useCallback( - (values: FormOnyxValues) => { - const errors: FormInputErrors = {}; + (values: FormOnyxValues) => { + const errors: FormInputErrors = {}; const tagName = values.tagName.trim(); const {tags} = PolicyUtils.getTagList(policyTags, 0); @@ -59,7 +59,7 @@ function CreateTagPage({route, policyTags}: CreateTagPageProps) { ); const createTag = useCallback( - (values: FormOnyxValues) => { + (values: FormOnyxValues) => { Policy.createPolicyTag(route.params.policyID, values.tagName.trim()); Keyboard.dismiss(); Navigation.goBack(); @@ -81,7 +81,7 @@ function CreateTagPage({route, policyTags}: CreateTagPageProps) { onBackButtonPress={Navigation.goBack} /> Date: Mon, 18 Mar 2024 15:18:52 +0100 Subject: [PATCH 127/175] fix lint --- src/pages/workspace/tags/EditTagPage.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pages/workspace/tags/EditTagPage.tsx b/src/pages/workspace/tags/EditTagPage.tsx index cfa60b5e8ff6..4842fcb89fd8 100644 --- a/src/pages/workspace/tags/EditTagPage.tsx +++ b/src/pages/workspace/tags/EditTagPage.tsx @@ -22,7 +22,6 @@ import PaidPolicyAccessOrNotFoundWrapper from '@pages/workspace/PaidPolicyAccess import * as Policy from '@userActions/Policy'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; -import ROUTES from '@src/ROUTES'; import type SCREENS from '@src/SCREENS'; import INPUT_IDS from '@src/types/form/WorkspaceTagForm'; import type {PolicyTagList} from '@src/types/onyx'; From 7e175f65d4334f036ec36b083b6e181955b876a7 Mon Sep 17 00:00:00 2001 From: Michal Muzyk Date: Mon, 18 Mar 2024 16:16:52 +0100 Subject: [PATCH 128/175] fix: cr fixes --- src/ROUTES.ts | 4 ++-- src/languages/es.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 3c32f5f88087..6410b00743f1 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -614,8 +614,8 @@ const ROUTES = { getRoute: (policyID: string) => `settings/workspaces/${policyID}/distance-rates/new` as const, }, WORKSPACE_DISTANCE_RATES_SETTINGS: { - route: 'workspace/:policyID/distance-rates/settings', - getRoute: (policyID: string) => `workspace/${policyID}/distance-rates/settings` as const, + route: 'settings/workspace/:policyID/distance-rates/settings', + getRoute: (policyID: string) => `settings/workspace/${policyID}/distance-rates/settings` as const, }, // Referral program promotion REFERRAL_DETAILS_MODAL: { diff --git a/src/languages/es.ts b/src/languages/es.ts index dc0e68504cbd..8a4c28839291 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -2021,8 +2021,8 @@ export default { status: 'Estado', enabled: 'Activada', disabled: 'Desactivada', - unit: 'Unit', - defaultCategory: 'Default category', + unit: 'Unidad', + defaultCategory: 'Categoría predeterminada', units: { MI: 'Millas', KM: 'Kilómetros', From ec142def26746f010efda5f2d63821ee0ba99ce5 Mon Sep 17 00:00:00 2001 From: Nicolay Arefyeu Date: Mon, 18 Mar 2024 17:56:00 +0200 Subject: [PATCH 129/175] Add default description for Workspace --- src/languages/en.ts | 4 ++-- src/languages/es.ts | 4 ++-- src/libs/actions/Policy.ts | 2 +- src/pages/workspace/WorkspaceInviteMessagePage.tsx | 5 +++-- .../workspace/WorkspaceProfileDescriptionPage.tsx | 9 ++++++++- src/pages/workspace/WorkspaceProfilePage.tsx | 11 ++++++++++- 6 files changed, 26 insertions(+), 9 deletions(-) diff --git a/src/languages/en.ts b/src/languages/en.ts index a80889ef7857..0ca50e506740 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -1768,6 +1768,8 @@ export default { moreFeatures: 'More features', requested: 'Requested', distanceRates: 'Distance rates', + welcomeNote: ({workspaceName}: WelcomeNoteParams) => + `You have been invited to ${workspaceName || 'a workspace'}! Download the Expensify mobile app at use.expensify.com/download to start tracking your expenses.`, }, type: { free: 'Free', @@ -1977,8 +1979,6 @@ export default { personalMessagePrompt: 'Message', genericFailureMessage: 'An error occurred inviting the user to the workspace, please try again.', inviteNoMembersError: 'Please select at least one member to invite', - welcomeNote: ({workspaceName}: WelcomeNoteParams) => - `You have been invited to ${workspaceName || 'a workspace'}! Download the Expensify mobile app at use.expensify.com/download to start tracking your expenses.`, }, distanceRates: { oopsNotSoFast: 'Oops! Not so fast...', diff --git a/src/languages/es.ts b/src/languages/es.ts index 4660b57c9265..9cc94c125b5a 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -1792,6 +1792,8 @@ export default { moreFeatures: 'Más características', requested: 'Solicitado', distanceRates: 'Tasas de distancia', + welcomeNote: ({workspaceName}: WelcomeNoteParams) => + `¡Has sido invitado a ${workspaceName}! Descargue la aplicación móvil Expensify en use.expensify.com/download para comenzar a rastrear sus gastos.`, }, type: { free: 'Gratis', @@ -2002,8 +2004,6 @@ export default { personalMessagePrompt: 'Mensaje', inviteNoMembersError: 'Por favor, selecciona al menos un miembro a invitar', genericFailureMessage: 'Se produjo un error al invitar al usuario al espacio de trabajo. Vuelva a intentarlo..', - welcomeNote: ({workspaceName}: WelcomeNoteParams) => - `¡Has sido invitado a ${workspaceName}! Descargue la aplicación móvil Expensify en use.expensify.com/download para comenzar a rastrear sus gastos.`, }, distanceRates: { oopsNotSoFast: 'Ups! No tan rápido...', diff --git a/src/libs/actions/Policy.ts b/src/libs/actions/Policy.ts index 6c1b53e21436..1dde6500aeb6 100644 --- a/src/libs/actions/Policy.ts +++ b/src/libs/actions/Policy.ts @@ -2163,7 +2163,7 @@ function setWorkspaceInviteMembersDraft(policyID: string, invitedEmailsToAccount Onyx.set(`${ONYXKEYS.COLLECTION.WORKSPACE_INVITE_MEMBERS_DRAFT}${policyID}`, invitedEmailsToAccountIDs); } -function setWorkspaceInviteMessageDraft(policyID: string, message: string) { +function setWorkspaceInviteMessageDraft(policyID: string, message: string | null) { Onyx.set(`${ONYXKEYS.COLLECTION.WORKSPACE_INVITE_MESSAGE_DRAFT}${policyID}`, message); } diff --git a/src/pages/workspace/WorkspaceInviteMessagePage.tsx b/src/pages/workspace/WorkspaceInviteMessagePage.tsx index df1d3cd63011..b83d8f4b72d0 100644 --- a/src/pages/workspace/WorkspaceInviteMessagePage.tsx +++ b/src/pages/workspace/WorkspaceInviteMessagePage.tsx @@ -64,7 +64,7 @@ function WorkspaceInviteMessagePage({workspaceInviteMessageDraft, invitedEmailsT // workspaceInviteMessageDraft can be an empty string // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing workspaceInviteMessageDraft || - translate('workspace.inviteMessage.welcomeNote', { + translate('workspace.common.welcomeNote', { workspaceName: policy?.name ?? '', }); @@ -77,7 +77,7 @@ function WorkspaceInviteMessagePage({workspaceInviteMessageDraft, invitedEmailsT // eslint-disable-next-line react-hooks/exhaustive-deps }, []); - const debouncedSaveDraft = lodashDebounce((newDraft: string) => { + const debouncedSaveDraft = lodashDebounce((newDraft: string | null) => { Policy.setWorkspaceInviteMessageDraft(route.params.policyID, newDraft); }); @@ -85,6 +85,7 @@ function WorkspaceInviteMessagePage({workspaceInviteMessageDraft, invitedEmailsT Keyboard.dismiss(); // Please see https://github.com/Expensify/App/blob/main/README.md#Security for more details Policy.addMembersToWorkspace(invitedEmailsToAccountIDsDraft ?? {}, welcomeNote ?? '', route.params.policyID); + debouncedSaveDraft(null); SearchInputManager.searchInput = ''; // Pop the invite message page before navigating to the members page. Navigation.goBack(); diff --git a/src/pages/workspace/WorkspaceProfileDescriptionPage.tsx b/src/pages/workspace/WorkspaceProfileDescriptionPage.tsx index 46a83dd2b166..98c67f194811 100644 --- a/src/pages/workspace/WorkspaceProfileDescriptionPage.tsx +++ b/src/pages/workspace/WorkspaceProfileDescriptionPage.tsx @@ -26,7 +26,14 @@ const parser = new ExpensiMark(); function WorkspaceProfileDescriptionPage({policy}: Props) { const styles = useThemeStyles(); const {translate} = useLocalize(); - const [description, setDescription] = useState(() => parser.htmlToMarkdown(policy?.description ?? '')); + const [description, setDescription] = useState(() => + parser.htmlToMarkdown( + policy?.description ?? + translate('workspace.common.welcomeNote', { + workspaceName: policy?.name ?? '', + }), + ), + ); /** * @param {Object} values - form input values passed by the Form component diff --git a/src/pages/workspace/WorkspaceProfilePage.tsx b/src/pages/workspace/WorkspaceProfilePage.tsx index 59c66f0c06a7..22b84861c085 100644 --- a/src/pages/workspace/WorkspaceProfilePage.tsx +++ b/src/pages/workspace/WorkspaceProfilePage.tsx @@ -1,3 +1,4 @@ +import ExpensiMark from 'expensify-common/lib/ExpensiMark'; import React, {useCallback, useState} from 'react'; import type {ImageStyle, StyleProp} from 'react-native'; import {Image, StyleSheet, View} from 'react-native'; @@ -41,6 +42,8 @@ type WorkSpaceProfilePageOnyxProps = { type WorkSpaceProfilePageProps = WithPolicyProps & WorkSpaceProfilePageOnyxProps; +const parser = new ExpensiMark(); + function WorkspaceProfilePage({policy, currencyList = {}, route}: WorkSpaceProfilePageProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); @@ -58,7 +61,13 @@ function WorkspaceProfilePage({policy, currencyList = {}, route}: WorkSpaceProfi const onPressShare = useCallback(() => Navigation.navigate(ROUTES.WORKSPACE_PROFILE_SHARE.getRoute(policy?.id ?? '')), [policy?.id]); const policyName = policy?.name ?? ''; - const policyDescription = policy?.description ?? ''; + const policyDescription = + policy?.description ?? + parser.replace( + translate('workspace.common.welcomeNote', { + workspaceName: policy?.name ?? '', + }), + ); const readOnly = !PolicyUtils.isPolicyAdmin(policy); const imageStyle: StyleProp = isSmallScreenWidth ? [styles.mhv12, styles.mhn5, styles.mbn5] : [styles.mhv8, styles.mhn8, styles.mbn5]; From a635c748c6e2d745d485618f5b355fdb33ac70b2 Mon Sep 17 00:00:00 2001 From: Nicolay Arefyeu Date: Mon, 18 Mar 2024 18:24:51 +0200 Subject: [PATCH 130/175] update optional checks and add description from policy to invite flow --- src/pages/workspace/WorkspaceInviteMessagePage.tsx | 3 +++ src/pages/workspace/WorkspaceProfilePage.tsx | 4 +++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/pages/workspace/WorkspaceInviteMessagePage.tsx b/src/pages/workspace/WorkspaceInviteMessagePage.tsx index b83d8f4b72d0..09a6528867f0 100644 --- a/src/pages/workspace/WorkspaceInviteMessagePage.tsx +++ b/src/pages/workspace/WorkspaceInviteMessagePage.tsx @@ -64,6 +64,9 @@ function WorkspaceInviteMessagePage({workspaceInviteMessageDraft, invitedEmailsT // workspaceInviteMessageDraft can be an empty string // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing workspaceInviteMessageDraft || + // policy?.description can be an empty string + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing + policy?.description || translate('workspace.common.welcomeNote', { workspaceName: policy?.name ?? '', }); diff --git a/src/pages/workspace/WorkspaceProfilePage.tsx b/src/pages/workspace/WorkspaceProfilePage.tsx index 22b84861c085..d110a5752382 100644 --- a/src/pages/workspace/WorkspaceProfilePage.tsx +++ b/src/pages/workspace/WorkspaceProfilePage.tsx @@ -62,7 +62,9 @@ function WorkspaceProfilePage({policy, currencyList = {}, route}: WorkSpaceProfi const policyName = policy?.name ?? ''; const policyDescription = - policy?.description ?? + // policy?.description can be an empty string + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing + policy?.description || parser.replace( translate('workspace.common.welcomeNote', { workspaceName: policy?.name ?? '', From 295259e50f133e0eaf2a9baac0e3e68e2eaa0a03 Mon Sep 17 00:00:00 2001 From: Artem Makushov Date: Mon, 18 Mar 2024 17:31:17 +0100 Subject: [PATCH 131/175] fixes --- src/ROUTES.ts | 4 ++-- src/pages/workspace/tags/WorkspaceTagsPage.tsx | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 19aa75eec6d1..5eda71fb34d4 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -577,8 +577,8 @@ const ROUTES = { getRoute: (policyID: string) => `settings/workspaces/${policyID}/tags/edit` as const, }, WORKSPACE_TAG_EDIT: { - route: 'workspace/:policyID/tag/:tagName/edit', - getRoute: (policyID: string, tagName: string) => `workspace/${policyID}/tag/${encodeURIComponent(tagName)}/edit` as const, + route: 'settings/workspace/:policyID/tag/:tagName/edit', + getRoute: (policyID: string, tagName: string) => `settings/workspace/${policyID}/tag/${encodeURIComponent(tagName)}/edit` as const, }, WORKSPACE_TAG_SETTINGS: { route: 'settings/workspaces/:policyID/tag/:tagName', diff --git a/src/pages/workspace/tags/WorkspaceTagsPage.tsx b/src/pages/workspace/tags/WorkspaceTagsPage.tsx index 7cf42b17fe5e..02f8d57488d2 100644 --- a/src/pages/workspace/tags/WorkspaceTagsPage.tsx +++ b/src/pages/workspace/tags/WorkspaceTagsPage.tsx @@ -128,6 +128,7 @@ function WorkspaceTagsPage({policyTags, route}: WorkspaceTagsPageProps) { }; const navigateToTagSettings = (tag: PolicyOption) => { + setSelectedTags({}); Navigation.navigate(ROUTES.WORKSPACE_TAG_SETTINGS.getRoute(route.params.policyID, tag.keyForList)); }; From 11916b569b4648c8ea1013d94dbaee36de4f3e44 Mon Sep 17 00:00:00 2001 From: Nicolay Arefyeu Date: Mon, 18 Mar 2024 18:37:44 +0200 Subject: [PATCH 132/175] fix markdown --- src/pages/workspace/WorkspaceInviteMessagePage.tsx | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/pages/workspace/WorkspaceInviteMessagePage.tsx b/src/pages/workspace/WorkspaceInviteMessagePage.tsx index 09a6528867f0..a9d8860ae12a 100644 --- a/src/pages/workspace/WorkspaceInviteMessagePage.tsx +++ b/src/pages/workspace/WorkspaceInviteMessagePage.tsx @@ -1,4 +1,5 @@ import type {StackScreenProps} from '@react-navigation/stack'; +import ExpensiMark from 'expensify-common/lib/ExpensiMark'; import lodashDebounce from 'lodash/debounce'; import React, {useEffect, useState} from 'react'; import {Keyboard, View} from 'react-native'; @@ -52,6 +53,8 @@ type WorkspaceInviteMessagePageProps = WithPolicyAndFullscreenLoadingProps & WorkspaceInviteMessagePageOnyxProps & StackScreenProps; +const parser = new ExpensiMark(); + function WorkspaceInviteMessagePage({workspaceInviteMessageDraft, invitedEmailsToAccountIDsDraft, policy, route, allPersonalDetails}: WorkspaceInviteMessagePageProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); @@ -67,13 +70,15 @@ function WorkspaceInviteMessagePage({workspaceInviteMessageDraft, invitedEmailsT // policy?.description can be an empty string // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing policy?.description || - translate('workspace.common.welcomeNote', { - workspaceName: policy?.name ?? '', - }); + parser.replace( + translate('workspace.common.welcomeNote', { + workspaceName: policy?.name ?? '', + }), + ); useEffect(() => { if (!isEmptyObject(invitedEmailsToAccountIDsDraft)) { - setWelcomeNote(getDefaultWelcomeNote()); + setWelcomeNote(parser.htmlToMarkdown(getDefaultWelcomeNote())); return; } Navigation.goBack(ROUTES.WORKSPACE_INVITE.getRoute(route.params.policyID), true); From bb95af47b9e8a8247eb48821337ac091eb65e67a Mon Sep 17 00:00:00 2001 From: John Lee Date: Mon, 18 Mar 2024 12:59:31 -0400 Subject: [PATCH 133/175] Fix google places API issue --- src/components/AddressSearch/index.tsx | 2 +- src/libs/ApiUtils.ts | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/components/AddressSearch/index.tsx b/src/components/AddressSearch/index.tsx index a2e3f5d9948e..9901ff9243f9 100644 --- a/src/components/AddressSearch/index.tsx +++ b/src/components/AddressSearch/index.tsx @@ -369,7 +369,7 @@ function AddressSearch( query={query} requestUrl={{ useOnPlatform: 'all', - url: isOffline ? '' : ApiUtils.getCommandURL({command: 'Proxy_GooglePlaces&proxyUrl='}), + url: isOffline ? '' : ApiUtils.getCommandURL({command: 'Proxy_GooglePlaces?proxyUrl='}), }} textInputProps={{ InputComp: TextInput, diff --git a/src/libs/ApiUtils.ts b/src/libs/ApiUtils.ts index 78bcc000318c..0c8fa3f53915 100644 --- a/src/libs/ApiUtils.ts +++ b/src/libs/ApiUtils.ts @@ -52,7 +52,8 @@ function getApiRoot(request?: Request): string { * @param - the name of the API command */ function getCommandURL(request: Request): string { - return `${getApiRoot(request)}api/${request.command}?`; + // If request.command already contains ? then we don't need to append it + return `${getApiRoot(request)}api/${request.command}${request.command.includes('?') ? '' : '?'}`; } /** From 8a850c657767259fdc9725f518907c7fb19b4618 Mon Sep 17 00:00:00 2001 From: Artem Makushov Date: Mon, 18 Mar 2024 18:07:16 +0100 Subject: [PATCH 134/175] fixes --- src/libs/actions/Policy.ts | 2 -- src/pages/workspace/tags/EditTagPage.tsx | 3 --- 2 files changed, 5 deletions(-) diff --git a/src/libs/actions/Policy.ts b/src/libs/actions/Policy.ts index e1a543c88a72..af66aa8f1b89 100644 --- a/src/libs/actions/Policy.ts +++ b/src/libs/actions/Policy.ts @@ -3048,8 +3048,6 @@ function renamePolicyTag(policyID: string, policyTag: {oldName: string; newName: [tagListName]: { tags: { [policyTag.newName]: { - ...oldTag, - name: policyTag.newName, errors: null, pendingAction: null, }, diff --git a/src/pages/workspace/tags/EditTagPage.tsx b/src/pages/workspace/tags/EditTagPage.tsx index 4842fcb89fd8..bc89db4d3055 100644 --- a/src/pages/workspace/tags/EditTagPage.tsx +++ b/src/pages/workspace/tags/EditTagPage.tsx @@ -49,9 +49,6 @@ function EditTagPage({route, policyTags}: EditTagPageProps) { errors.tagName = 'workspace.tags.tagRequiredError'; } else if (tags?.[tagName]) { errors.tagName = 'workspace.tags.existingTagError'; - } else if ([...tagName].length > CONST.TAG_NAME_LIMIT) { - // Uses the spread syntax to count the number of Unicode code points instead of the number of UTF-16 code units. - ErrorUtils.addErrorMessage(errors, 'tagName', ['common.error.characterLimitExceedCounter', {length: [...tagName].length, limit: CONST.TAG_NAME_LIMIT}]); } return errors; From f042015061c098621784fbb538a8edb1c9de78ac Mon Sep 17 00:00:00 2001 From: Artem Makushov Date: Mon, 18 Mar 2024 19:15:35 +0100 Subject: [PATCH 135/175] fixes --- src/pages/workspace/tags/EditTagPage.tsx | 26 ++++++++---------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/src/pages/workspace/tags/EditTagPage.tsx b/src/pages/workspace/tags/EditTagPage.tsx index bc89db4d3055..4fc6e2d64559 100644 --- a/src/pages/workspace/tags/EditTagPage.tsx +++ b/src/pages/workspace/tags/EditTagPage.tsx @@ -12,7 +12,6 @@ import TextInput from '@components/TextInput'; import useAutoFocusInput from '@hooks/useAutoFocusInput'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; -import * as ErrorUtils from '@libs/ErrorUtils'; import Navigation from '@libs/Navigation/Navigation'; import * as PolicyUtils from '@libs/PolicyUtils'; import * as ValidationUtils from '@libs/ValidationUtils'; @@ -39,22 +38,15 @@ function EditTagPage({route, policyTags}: EditTagPageProps) { const {inputCallbackRef} = useAutoFocusInput(); const currentTagName = route.params.tagName; - const validate = useCallback( - (values: FormOnyxValues) => { - const errors: FormInputErrors = {}; - const tagName = values.tagName.trim(); - const {tags} = PolicyUtils.getTagList(policyTags, 0); - - if (!ValidationUtils.isRequiredFulfilled(tagName)) { - errors.tagName = 'workspace.tags.tagRequiredError'; - } else if (tags?.[tagName]) { - errors.tagName = 'workspace.tags.existingTagError'; - } + const validate = useCallback((values: FormOnyxValues) => { + const errors: FormInputErrors = {}; + const tagName = values.tagName.trim(); + if (!ValidationUtils.isRequiredFulfilled(tagName)) { + errors.tagName = 'workspace.tags.tagRequiredError'; + } - return errors; - }, - [policyTags], - ); + return errors; + }, []); const editTag = useCallback( (values: FormOnyxValues) => { @@ -75,7 +67,7 @@ function EditTagPage({route, policyTags}: EditTagPageProps) { shouldEnableMaxHeight > Date: Mon, 18 Mar 2024 19:54:53 +0100 Subject: [PATCH 136/175] reverted validation, ability to save oldTag --- src/pages/workspace/tags/EditTagPage.tsx | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/pages/workspace/tags/EditTagPage.tsx b/src/pages/workspace/tags/EditTagPage.tsx index 4fc6e2d64559..c22ba9154146 100644 --- a/src/pages/workspace/tags/EditTagPage.tsx +++ b/src/pages/workspace/tags/EditTagPage.tsx @@ -38,15 +38,21 @@ function EditTagPage({route, policyTags}: EditTagPageProps) { const {inputCallbackRef} = useAutoFocusInput(); const currentTagName = route.params.tagName; - const validate = useCallback((values: FormOnyxValues) => { - const errors: FormInputErrors = {}; - const tagName = values.tagName.trim(); - if (!ValidationUtils.isRequiredFulfilled(tagName)) { - errors.tagName = 'workspace.tags.tagRequiredError'; - } + const validate = useCallback( + (values: FormOnyxValues) => { + const errors: FormInputErrors = {}; + const tagName = values.tagName.trim(); + const {tags} = PolicyUtils.getTagList(policyTags, 0); + if (!ValidationUtils.isRequiredFulfilled(tagName)) { + errors.tagName = 'workspace.tags.tagRequiredError'; + } else if (tags?.[tagName] && currentTagName !== tagName) { + errors.tagName = 'workspace.tags.existingTagError'; + } - return errors; - }, []); + return errors; + }, + [currentTagName, policyTags], + ); const editTag = useCallback( (values: FormOnyxValues) => { From 16394aa50b8ffed2fb52dac81493ca0bed056f96 Mon Sep 17 00:00:00 2001 From: Ren Jones <153645623+ren-jones@users.noreply.github.com> Date: Mon, 18 Mar 2024 16:38:02 -0500 Subject: [PATCH 137/175] Create Add-expenses-in-bulk.md New article for adding expenses in bulk --- .../expenses/Add-expenses-in-bulk.md | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 docs/articles/expensify-classic/expenses/Add-expenses-in-bulk.md diff --git a/docs/articles/expensify-classic/expenses/Add-expenses-in-bulk.md b/docs/articles/expensify-classic/expenses/Add-expenses-in-bulk.md new file mode 100644 index 000000000000..6ee84e1ead15 --- /dev/null +++ b/docs/articles/expensify-classic/expenses/Add-expenses-in-bulk.md @@ -0,0 +1,44 @@ +--- +title: Add expenses in bulk +description: Add multiple expenses at one time +--- +
+ +You can upload bulk receipt images or add receipt details in bulk. + +# SmartScan receipt images in bulk + +{% include selector.html values="desktop, mobile" %} + +{% include option.html value="desktop" %} +1. Click the **Expenses** tab. +2. Drag and drop up to 10 images or PDF receipts at once from your computer’s files. You can drop them anywhere on the Expense page where you see a green plus icon next to your mouse cursor. +{% include end-option.html %} + +{% include option.html value="mobile" %} +1. Open the mobile app and tap the camera icon in the bottom right corner. +2. Tap the camera icon in the right corner to select the Rapid Fire mode. +3. Take a clear photo of each receipt. +4. When all receipts are captured, tap the X in the left corner to close the camera. +{% include end-option.html %} + +{% include end-selector.html %} + +# Manually add receipt details in bulk + +*Note: This process is currently not available from the mobile app and must be completed from the Expensify website.* + +1. Click the **Expenses** tab. +2. Click **New Expense** and select **Create Multiple**. +3. Enter the expense details for up to 10 expenses and click **Save**. + +# Upload personal expenses via CSV, XLS, etc. + +*Note: This process is currently not available from the mobile app and must be completed from the Expensify website.* + +1. Hover over Settings, then click **Account**. +2. Click the **Credit Card Import** tab. +3. Under Personal Cards, click **Import Transactions from File**. +4. Click **Upload** and select a .csv, .xls, .ofx, or a .qfx file. + +
From 8aaddf04213a2e73b82f7ef973adff1a60d766e2 Mon Sep 17 00:00:00 2001 From: Ren Jones <153645623+ren-jones@users.noreply.github.com> Date: Mon, 18 Mar 2024 16:41:59 -0500 Subject: [PATCH 138/175] Delete docs/articles/expensify-classic/expenses/expenses/Upload-Receipts.md This information is covered in the following two articles that I just pushed: https://github.com/Expensify/App/pull/38524 (Add an expense) https://github.com/Expensify/App/pull/38525 (Add expenses in bulk) --- .../expenses/expenses/Upload-Receipts.md | 38 ------------------- 1 file changed, 38 deletions(-) delete mode 100644 docs/articles/expensify-classic/expenses/expenses/Upload-Receipts.md diff --git a/docs/articles/expensify-classic/expenses/expenses/Upload-Receipts.md b/docs/articles/expensify-classic/expenses/expenses/Upload-Receipts.md deleted file mode 100644 index b0e3ee1b9ade..000000000000 --- a/docs/articles/expensify-classic/expenses/expenses/Upload-Receipts.md +++ /dev/null @@ -1,38 +0,0 @@ ---- -title: Upload-Receipts.md -description: This article shows you all the ways that you can upload your receipts to Expensify! ---- - - -# About -Need to get paid? Check out this guide to see all the ways that you can upload your receipts to Expensify - whether it’s by SmartScanning them by forwarding via email or manually by taking a picture of a receipt, we’ll cover it here! - -# How-to Upload Receipts -## SmartScan -The easiest way to upload your receipts to Expensify is to SmartScan them with Expensify’s mobile app or forward a receipt from your email inbox! - -When you SmartScan a receipt, we’ll read the Merchant, Date and Amount of the transaction, create an expense, and add it to your Expensify account automatically. The best practice is to take a picture of the receipt at the time of purchase or forward it to your Expensify account from the point of sale system. If you have a credit card connected and you upload a receipt that matches a card expense, the SmartScanned receipt will automatically merge with the imported card expense instead. - -## Email Receipts -To SmartScan a receipt on your mobile app, tap the green camera button, point and shoot! You can also forward your digital receipts (or photos of receipts) to receipts@expensify.com from the email address associated with your Expensify account, and they’ll be SmartScanned. This may take a few minutes because Expensify aims to have the most accurate OCR. - -## Manually Upload -To upload receipts on the web, simply navigate to the Expenses page and click on **New Expense**. Select **Scan Receipt** and choose the file you would like to upload, or drag-and-drop your image directly into the Expenses page, and that will start the SmartScanning process! - -{% include faq-begin.md %} -## How do you SmartScan multiple receipts? -You can utilize the Rapid Fire Mode to quickly SmartScan multiple receipts at once! - -To activate it, tap on the green camera button in the mobile app and then tap on the camera icon on the bottom right. When you see the little fire icon on the camera, Rapid Fire Mode has been activated - tap the camera icon again to disable Rapid Fire Mode. - -## How do you create an expense from an email address that is different from your Expensify login? -You can email a receipt from a different email address by adding it as a Secondary Login to your Expensify account - this ensures that any receipts sent from this email to receipts@expensify.com will be associated with your current Expensify account. - -Once that email address has been added as a Secondary Login, simply forward your receipt image or emails to receipts@expensify.com. - -## How do you crop or rotate a receipt image? -You can crop and rotate a receipt image on the web app, and you can only edit one expense at a time. - -Navigate to your Expenses page and locate the expense whose receipt image you'd like to edit, then click the expense to open the Edit screen. If there is an image file associated with the receipt, you will see the Rotate and Crop buttons. Alternatively, you can also navigate to your Reports page, click on a report, and locate the individual expense. - -{% include faq-end.md %} From bbc3cb4b5796d1e7154c705f60921db2c3b63889 Mon Sep 17 00:00:00 2001 From: Ren Jones <153645623+ren-jones@users.noreply.github.com> Date: Mon, 18 Mar 2024 16:56:27 -0500 Subject: [PATCH 139/175] Create Split-an-expense.md New article for splitting an expense --- .../expenses/Split-an-expense.md | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 docs/articles/expensify-classic/expenses/Split-an-expense.md diff --git a/docs/articles/expensify-classic/expenses/Split-an-expense.md b/docs/articles/expensify-classic/expenses/Split-an-expense.md new file mode 100644 index 000000000000..997d81ef0729 --- /dev/null +++ b/docs/articles/expensify-classic/expenses/Split-an-expense.md @@ -0,0 +1,49 @@ +--- +title: Split an expense +description: Divide expenses on a receipt into separate expenses +--- +
+ +You can break down a receipt into multiple expenses by splitting it. Each split expense is treated as an individual expense which can be categorized and tagged separately. The same receipt image will be attached to all of the split expenses. + +{% include info.html %} +Splitting an expense cannot be undone. +{% include end-info.html %} + +{% include selector.html values="desktop, mobile" %} + +{% include option.html value="desktop" %} +1. Click the **Expenses** tab. +2. Click the expense you want to split. +3. Scroll down and click **Split Expense** in the bottom left corner. +4. Use the buttons in the bottom left corner to select how to split the expenses. + - Add additional splits by clicking **Add Split**. + - Split the expense for multiple days by clicking **Split by Days**. This option is good for expenses like hotel stays. + - Split the expense evenly by clicking **Split Even**. This option also works if you add more than two splits. + +{% include info.html %} +Each split must have a value greater than $0.00 and all splits must add up to the total expense amount. +{% include end-info.html %} + +{% include end-option.html %} + +{% include option.html value="mobile" %} +1. Tap the **Expenses** tab. +2. Tap the expense you want to split. +3. Scroll down to the bottom and tap **More Options**. +4. Tap **Split**. +5. Tap each split to add the expense details including the total and category, then click **Save**. To add any additional splits, click **Add Split**. + +{% include info.html %} +Each split must have a value greater than $0.00 and all splits must add up to the total expense amount. +{% include end-info.html %} + +6. Once all splits have been added and adjusted, click **Save**. + +{% include end-option.html %} + +{% include end-selector.html %} + + + +
From 4c36d7678f10cd63fc258bf7d2bb9f592e4fdf75 Mon Sep 17 00:00:00 2001 From: Ren Jones <153645623+ren-jones@users.noreply.github.com> Date: Mon, 18 Mar 2024 17:04:43 -0500 Subject: [PATCH 140/175] Update and rename Merge-Expenses.md to Merge-expenses.md Rewrite for article --- .../expenses/expenses/Merge-Expenses.md | 65 ------------------- .../expenses/expenses/Merge-expenses.md | 57 ++++++++++++++++ 2 files changed, 57 insertions(+), 65 deletions(-) delete mode 100644 docs/articles/expensify-classic/expenses/expenses/Merge-Expenses.md create mode 100644 docs/articles/expensify-classic/expenses/expenses/Merge-expenses.md diff --git a/docs/articles/expensify-classic/expenses/expenses/Merge-Expenses.md b/docs/articles/expensify-classic/expenses/expenses/Merge-Expenses.md deleted file mode 100644 index a26146536e42..000000000000 --- a/docs/articles/expensify-classic/expenses/expenses/Merge-Expenses.md +++ /dev/null @@ -1,65 +0,0 @@ ---- -title: Merge Expenses -description: This article shows you all the ways that you can merge your expenses in Expensify! ---- - - -# About -The merge expense function helps combine two separate expenses into one. This is useful when the same expense has been accidentally entered more than once, or if you have a connected credit card and an imported expense didn’t automatically merge with a manual entry. - -# How-to merge expenses -It’s important to note that merging expenses doesn't add the two values together. Instead, merging them combines both expenses to create a single, consolidated expense. - -Keep in mind: -1. Merging expenses cannot be undone. -2. You can only merge two expenses at a time. -3. You can merge a cash expense with a credit card expense, or two cash expenses - but not two credit card expenses. -4. In order to merge, both expenses will need to be in a Personal or Draft status. - -# How to merge expenses on the web app -To merge two expenses from the Expenses page: -1. Sign into your Expensify account. -2. Navigate to the Expenses page on the left-hand navigation. -3. Click the checkboxes next to the two expenses you wish to merge. -4. Click **Merge**. -5. You'll be able to choose which aspect of each of the two expenses you would like to be used on the resulting expense, such as the receipt image, card, merchant, category, and more. - -To merge two expenses from the Reports page: -1. Sign into your Expensify account. -2. Navigate to the Reports page on the left-hand navigation. -3. Click the Report that contains the expenses that you wish to merge. -4. Click on the **Details** tab, then the Pencil icon. -5. Select the two expenses that you wish to merge. -6. You'll be able to choose which aspect of each of the two expenses you would like to be used on the resulting expense, such as the receipt image, card, merchant, category, and more. - -# How to merge expenses on the Expensify mobile app -On the mobile app, merging is prompted when you see the message _"Potential duplicate expense detected"_. Simply tap **Resolve Now** to take a closer look, then hit **Merge Expense**, and you're done! - -If the expenses exist on two different reports, you will be asked which report you'd like the newly created single expense to be reported onto. - -{% include faq-begin.md %} - -## Can you merge expenses across different reports? - -You cannot merge expenses across different reports. Expenses will only merge if they are on the same report. If you have expenses across different reports that you wish to merge, you’ll need to move both expenses onto the same report (and ensure they are in the Draft status) in order to merge them. - -## Can you merge expenses across different accounts? - -You cannot merge expenses across two separate accounts. You will need to choose one submitter and transfer the expense information to that user's account in order to merge the expense. - -## Can you merge expenses with different currencies? - -Yes, you can merge expenses with different currencies. The conversion amount will be based on the daily exchange rate for the date of the transaction, as long as the converted rates are within +/- 5%. If the currencies are the same, then the amounts must be an exact match to merge. - -## Can Expensify automatically merge a cash expense with a credit card expense? - -Yes, Expensify can merge a cash expense with a credit card expense. A receipt will need to be SmartScanned via the app or forwarded to [receipts@expensify.com](mailto:receipts@expensify.com) in order to merge with a card expense. Note that the SmartScan must be fully completed and not stopped or edited, otherwise the two won’t merge. - -## It doesn’t look like my cash and card expenses merged properly. What are some troubleshooting tips? -First, check the expense types - you can only merge a SmartScanned receipt (which will initially show with a cash icon) with a card transaction imported from a bank or via CSV. - -If the card expense in your Expensify account is older than the receipt you're trying to merge it with, they won't merge, and if the receipt is dated more than 7 days prior to the card expense, then they also will not merge. - -If you have any expenses that are more than 90 days old from the date they were incurred (not the date they were imported to Expensify), Expensify will not automatically merge them. This safeguard helps prevent the merging of very old expenses that might not align with recent transactions or receipts. - -Lastly, transactions imported with the Expensify API (via the Expense Importer) will not automatically merge with SmartScanned transactions. diff --git a/docs/articles/expensify-classic/expenses/expenses/Merge-expenses.md b/docs/articles/expensify-classic/expenses/expenses/Merge-expenses.md new file mode 100644 index 000000000000..8b1f573a64b4 --- /dev/null +++ b/docs/articles/expensify-classic/expenses/expenses/Merge-expenses.md @@ -0,0 +1,57 @@ +--- +title: Merge expenses +description: Combine two expenses into one +--- + +Combine two separate expenses by merging them into one single, consolidated expense. + +{% include info.html %} +Merging expenses cannot be undone, and you cannot merge two credit card expenses. +{% include end-info.html %} + +{% include selector.html values="desktop, mobile" %} + +{% include option.html value="desktop" %} +To merge expenses from the Expenses tab, + +1. Click the **Expenses** tab. +2. Select the checkbox next to the two expenses you wish to merge. +3. Click **Merge**. +4. Choose which details to use from each of the expenses, such as the receipt image, card, merchant, category, etc. + +To merge expenses from the Reports tab, + +1. Click the **Reports** tab. +2. Click the Report that contains the expenses that you wish to merge. +3. Click the **Details** tab, then the Edit icon. +4. Select the two expenses that you wish to merge. +5. You’ll be able to choose which details to use from each of the two expenses, such as the receipt image, card, merchant, category, etc. +{% include end-option.html %} + +{% include option.html value="mobile" %} +On the mobile app, you’ll be notified of duplicate expenses and can click **Resolve Now** to review them. To merge the two expenses into one expense, tap **Merge Expense**. + +If the expenses exist on two different reports, you will be asked which report you’d like the newly created single expense to be reported onto. +{% include end-option.html %} + +{% include end-selector.html %} + +# FAQs + +**Why can’t I merge expenses that are on my submitted report?** +You cannot merge expenses that are on reports that have already been submitted. + +**Can I merge expenses that are under different accounts?** +No, you cannot merge expenses across two separate accounts. + +**Can you merge expenses with different currencies?** +Yes, you can merge expenses with different currencies. The conversion amount will be based on the daily exchange rate for the date of the transaction, as long as the converted rates are within +/- 5%. If the currencies are the same, then the amounts must be an exact match to merge. + +**Can Expensify automatically merge a cash expense with a credit card expense?** +Yes, Expensify merges a cash expense with a credit card expense if the receipt is SmartScanned or forwarded to receipts@expensify.com. However, these expenses will not merge if: +- The card expense added to your Expensify account is older than the receipt you’re trying to merge it with +- The receipt is dated older than 7 days of the card expense date +- Either expense date (the date the Expense was incurred, not the date it was added into Expensify) is older than 90 days +- The transaction was imported with the Expensify API + +However, if a receipt does not automatically merge with the card entry, you can complete this process manually. From 7262520417930c9fdb8dd730fe29a910e6aeefb8 Mon Sep 17 00:00:00 2001 From: Vit Horacek Date: Mon, 18 Mar 2024 22:56:09 +0000 Subject: [PATCH 141/175] Remove the usage of isApprovalModeEnabled --- src/libs/actions/Policy.ts | 17 ++++++++++------- .../workflows/WorkspaceWorkflowsPage.tsx | 4 ++-- src/types/onyx/Policy.ts | 3 --- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/libs/actions/Policy.ts b/src/libs/actions/Policy.ts index dbbb94b82a1a..dd3fabfcc656 100644 --- a/src/libs/actions/Policy.ts +++ b/src/libs/actions/Policy.ts @@ -451,7 +451,7 @@ function setWorkspaceAutoReporting(policyID: string, enabled: boolean, frequency enabled, }, autoReportingFrequency: frequency, - pendingFields: {isAutoApprovalEnabled: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE}, + pendingFields: {autoReporting: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE}, }, }, ]; @@ -466,7 +466,7 @@ function setWorkspaceAutoReporting(policyID: string, enabled: boolean, frequency enabled: policy.harvesting?.enabled ?? null, }, autoReportingFrequency: policy.autoReportingFrequency ?? null, - pendingFields: {isAutoApprovalEnabled: null, harvesting: null}, + pendingFields: {autoReporting: null}, }, }, ]; @@ -476,7 +476,7 @@ function setWorkspaceAutoReporting(policyID: string, enabled: boolean, frequency onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, value: { - pendingFields: {isAutoApprovalEnabled: null, harvesting: null}, + pendingFields: {autoReporting: null}, }, }, ]; @@ -566,13 +566,11 @@ function setWorkspaceAutoReportingMonthlyOffset(policyID: string, autoReportingO } function setWorkspaceApprovalMode(policyID: string, approver: string, approvalMode: ValueOf) { - const isAutoApprovalEnabled = approvalMode === CONST.POLICY.APPROVAL_MODE.BASIC; const policy = ReportUtils.getPolicy(policyID); const value = { approver, approvalMode, - isAutoApprovalEnabled, }; const optimisticData: OnyxUpdate[] = [ @@ -593,7 +591,6 @@ function setWorkspaceApprovalMode(policyID: string, approver: string, approvalMo value: { approver: policy.approver ?? null, approvalMode: policy.approvalMode ?? null, - isAutoApprovalEnabled: policy.isAutoApprovalEnabled ?? null, pendingFields: {approvalMode: null}, }, }, @@ -609,7 +606,13 @@ function setWorkspaceApprovalMode(policyID: string, approver: string, approvalMo }, ]; - const params: SetWorkspaceApprovalModeParams = {policyID, value: JSON.stringify(value)}; + const params: SetWorkspaceApprovalModeParams = { + policyID, + value: JSON.stringify({ + ...value, + isAutoApprovalEnabled: approvalMode === CONST.POLICY.APPROVAL_MODE.BASIC, + }), + }; API.write(WRITE_COMMANDS.SET_WORKSPACE_APPROVAL_MODE, params, {optimisticData, failureData, successData}); } diff --git a/src/pages/workspace/workflows/WorkspaceWorkflowsPage.tsx b/src/pages/workspace/workflows/WorkspaceWorkflowsPage.tsx index c6ace2b0856e..af91eeb3aef6 100644 --- a/src/pages/workspace/workflows/WorkspaceWorkflowsPage.tsx +++ b/src/pages/workspace/workflows/WorkspaceWorkflowsPage.tsx @@ -111,7 +111,7 @@ function WorkspaceWorkflowsPage({policy, betas, route, reimbursementAccount, ses /> ), isActive: (policy?.harvesting?.enabled && policy.autoReportingFrequency !== CONST.POLICY.AUTO_REPORTING_FREQUENCIES.INSTANT) ?? false, - pendingAction: policy?.pendingFields?.isAutoApprovalEnabled, + pendingAction: policy?.pendingFields?.autoReporting, }, ] : []), @@ -134,7 +134,7 @@ function WorkspaceWorkflowsPage({policy, betas, route, reimbursementAccount, ses hoverAndPressStyle={[styles.mr0, styles.br2]} /> ), - isActive: policy?.isAutoApprovalEnabled ?? false, + isActive: policy?.approvalMode === CONST.POLICY.APPROVAL_MODE.BASIC, pendingAction: policy?.pendingFields?.approvalMode, }, { diff --git a/src/types/onyx/Policy.ts b/src/types/onyx/Policy.ts index 84ac101a7d7a..e8e17bbdff4b 100644 --- a/src/types/onyx/Policy.ts +++ b/src/types/onyx/Policy.ts @@ -292,9 +292,6 @@ type Policy = OnyxCommon.OnyxValueWithOfflineFeedback< /** The approval mode set up on this policy */ approvalMode?: ValueOf; - /** Whether the auto approval is enabled */ - isAutoApprovalEnabled?: boolean; - /** Whether transactions should be billable by default */ defaultBillable?: boolean; From e9ab69ce9102d5be47b4ee37539a41ff5af6483c Mon Sep 17 00:00:00 2001 From: Vit Horacek Date: Mon, 18 Mar 2024 23:41:44 +0000 Subject: [PATCH 142/175] Make sure the autoApproval is off for Collect --- src/libs/actions/Policy.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libs/actions/Policy.ts b/src/libs/actions/Policy.ts index dd3fabfcc656..8df84965b08c 100644 --- a/src/libs/actions/Policy.ts +++ b/src/libs/actions/Policy.ts @@ -610,7 +610,8 @@ function setWorkspaceApprovalMode(policyID: string, approver: string, approvalMo policyID, value: JSON.stringify({ ...value, - isAutoApprovalEnabled: approvalMode === CONST.POLICY.APPROVAL_MODE.BASIC, + // This property should now be set to false for all Collect policies + isAutoApprovalEnabled: false, }), }; API.write(WRITE_COMMANDS.SET_WORKSPACE_APPROVAL_MODE, params, {optimisticData, failureData, successData}); From 44621799ca4f2ff50ec1a3a7c19dd2f89e3434ae Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Mon, 18 Mar 2024 17:44:09 -0600 Subject: [PATCH 143/175] fix style --- src/pages/workspace/tags/WorkspaceTagsPage.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/workspace/tags/WorkspaceTagsPage.tsx b/src/pages/workspace/tags/WorkspaceTagsPage.tsx index 1e55422db95c..42cd6d612bcb 100644 --- a/src/pages/workspace/tags/WorkspaceTagsPage.tsx +++ b/src/pages/workspace/tags/WorkspaceTagsPage.tsx @@ -98,8 +98,8 @@ function WorkspaceTagsPage({policyTags, route}: WorkspaceTagsPageProps) { ), })), - ) - .flat(), + ) + .flat(), [policyTagLists, selectedTags, styles.alignSelfCenter, styles.flexRow, styles.label, styles.p1, styles.pl2, styles.textSupporting, theme.icon, translate], ); From 5753a7c4ed073b6dfafe6fc7c5af31d81392c896 Mon Sep 17 00:00:00 2001 From: Vit Horacek Date: Mon, 18 Mar 2024 23:49:20 +0000 Subject: [PATCH 144/175] Add top padding to the taxes and tags settings page description --- src/pages/workspace/tags/WorkspaceTagsPage.tsx | 2 +- src/pages/workspace/taxes/WorkspaceTaxesPage.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/workspace/tags/WorkspaceTagsPage.tsx b/src/pages/workspace/tags/WorkspaceTagsPage.tsx index 7cf42b17fe5e..4fa84b5c4977 100644 --- a/src/pages/workspace/tags/WorkspaceTagsPage.tsx +++ b/src/pages/workspace/tags/WorkspaceTagsPage.tsx @@ -172,7 +172,7 @@ function WorkspaceTagsPage({policyTags, route}: WorkspaceTagsPageProps) { {!isSmallScreenWidth && headerButtons}
{isSmallScreenWidth && {headerButtons}} - + {translate('workspace.tags.subtitle')} {isLoading && ( diff --git a/src/pages/workspace/taxes/WorkspaceTaxesPage.tsx b/src/pages/workspace/taxes/WorkspaceTaxesPage.tsx index d0724f4592ba..8eb730c0134f 100644 --- a/src/pages/workspace/taxes/WorkspaceTaxesPage.tsx +++ b/src/pages/workspace/taxes/WorkspaceTaxesPage.tsx @@ -168,7 +168,7 @@ function WorkspaceTaxesPage({policy, route}: WorkspaceTaxesPageProps) { {isSmallScreenWidth && {headerButtons}} - + {translate('workspace.taxes.subtitle')} {isLoading && ( From 2563af31a0f094c09673a8ec23f0b8c6ca20cb88 Mon Sep 17 00:00:00 2001 From: situchan Date: Tue, 19 Mar 2024 13:00:39 +0600 Subject: [PATCH 145/175] fix concierge avatar not showing in preview --- src/components/Image/index.tsx | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/components/Image/index.tsx b/src/components/Image/index.tsx index 6884966fb81a..f4e5bf4834e0 100644 --- a/src/components/Image/index.tsx +++ b/src/components/Image/index.tsx @@ -11,14 +11,19 @@ function Image({source: propsSource, isAuthTokenRequired = false, session, ...fo * to the source. */ const source = useMemo(() => { - const authToken = session?.encryptedAuthToken ?? null; - if (isAuthTokenRequired && typeof propsSource === 'object' && 'uri' in propsSource && authToken) { - return { - ...propsSource, - headers: { - [CONST.CHAT_ATTACHMENT_TOKEN_KEY]: authToken, - }, - }; + if (typeof propsSource === 'object' && 'uri' in propsSource) { + if (typeof propsSource.uri === 'number') { + return propsSource.uri; + } + const authToken = session?.encryptedAuthToken ?? null; + if (isAuthTokenRequired && authToken) { + return { + ...propsSource, + headers: { + [CONST.CHAT_ATTACHMENT_TOKEN_KEY]: authToken, + }, + }; + } } return propsSource; // The session prop is not required, as it causes the image to reload whenever the session changes. For more information, please refer to issue #26034. From fd0f68e55aa0f4680e8ab99236faabd5150985ed Mon Sep 17 00:00:00 2001 From: dragnoir Date: Tue, 19 Mar 2024 10:13:13 +0100 Subject: [PATCH 146/175] Fix: form button not disabled when error --- src/components/MoneyRequestConfirmationList.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/MoneyRequestConfirmationList.tsx b/src/components/MoneyRequestConfirmationList.tsx index 6b562525258d..e953b1c23ad0 100755 --- a/src/components/MoneyRequestConfirmationList.tsx +++ b/src/components/MoneyRequestConfirmationList.tsx @@ -527,7 +527,7 @@ function MoneyRequestConfirmationList({ } const shouldShowSettlementButton = iouType === CONST.IOU.TYPE.SEND; - const shouldDisableButton = selectedParticipants.length === 0 || shouldDisplayMerchantError; + const shouldDisableButton = selectedParticipants.length === 0; const button = shouldShowSettlementButton ? ( Date: Tue, 19 Mar 2024 10:54:56 +0100 Subject: [PATCH 147/175] Remove style from ScreenWrapper in WorkspaceInitialPage --- src/pages/workspace/WorkspaceInitialPage.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pages/workspace/WorkspaceInitialPage.tsx b/src/pages/workspace/WorkspaceInitialPage.tsx index 9a56a2da0314..0d3bb027b8e6 100644 --- a/src/pages/workspace/WorkspaceInitialPage.tsx +++ b/src/pages/workspace/WorkspaceInitialPage.tsx @@ -249,7 +249,6 @@ function WorkspaceInitialPage({policyDraft, policy: policyProp, policyMembers, r Date: Tue, 19 Mar 2024 11:04:13 +0100 Subject: [PATCH 148/175] npm run lint --- src/components/MoneyRequestConfirmationList.tsx | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/src/components/MoneyRequestConfirmationList.tsx b/src/components/MoneyRequestConfirmationList.tsx index e953b1c23ad0..2e8f80175b56 100755 --- a/src/components/MoneyRequestConfirmationList.tsx +++ b/src/components/MoneyRequestConfirmationList.tsx @@ -575,20 +575,7 @@ function MoneyRequestConfirmationList({ {button} ); - }, [ - isReadOnly, - iouType, - bankAccountRoute, - iouCurrencyCode, - policyID, - selectedParticipants.length, - shouldDisplayMerchantError, - confirm, - splitOrRequestOptions, - formError, - styles.ph1, - styles.mb2, - ]); + }, [isReadOnly, iouType, bankAccountRoute, iouCurrencyCode, policyID, selectedParticipants.length, confirm, splitOrRequestOptions, formError, styles.ph1, styles.mb2]); const {image: receiptImage, thumbnail: receiptThumbnail} = receiptPath && receiptFilename ? ReceiptUtils.getThumbnailAndImageURIs(transaction, receiptPath, receiptFilename) : ({} as ReceiptUtils.ThumbnailAndImageURI); From 30739acd78133422c694651bf54a931e69d89578 Mon Sep 17 00:00:00 2001 From: Nicolay Arefyeu Date: Tue, 19 Mar 2024 12:15:14 +0200 Subject: [PATCH 149/175] update optional checks --- src/pages/workspace/WorkspaceProfileDescriptionPage.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/pages/workspace/WorkspaceProfileDescriptionPage.tsx b/src/pages/workspace/WorkspaceProfileDescriptionPage.tsx index 98c67f194811..f31ebfc85dcc 100644 --- a/src/pages/workspace/WorkspaceProfileDescriptionPage.tsx +++ b/src/pages/workspace/WorkspaceProfileDescriptionPage.tsx @@ -28,7 +28,9 @@ function WorkspaceProfileDescriptionPage({policy}: Props) { const {translate} = useLocalize(); const [description, setDescription] = useState(() => parser.htmlToMarkdown( - policy?.description ?? + // policy?.description can be an empty string + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing + policy?.description || translate('workspace.common.welcomeNote', { workspaceName: policy?.name ?? '', }), From 0df3315f1d93f3f9fb1dc76bb7f00d1705b52947 Mon Sep 17 00:00:00 2001 From: BrtqKr Date: Tue, 19 Mar 2024 11:31:09 +0100 Subject: [PATCH 150/175] review fixes --- workflow_tests/authorChecklist.test.js | 14 +++---- workflow_tests/cherryPick.test.js | 16 ++++---- workflow_tests/cla.test.js | 12 +++--- workflow_tests/createNewVersion.test.js | 12 +++--- workflow_tests/deploy.test.js | 10 ++--- workflow_tests/deployBlocker.test.js | 8 ++-- workflow_tests/failureNotifier.test.js | 4 +- workflow_tests/finishReleaseCycle.test.js | 10 ++--- workflow_tests/lint.test.js | 12 +++--- workflow_tests/lockDeploys.test.js | 20 +++++----- workflow_tests/platformDeploy.test.js | 8 ++-- workflow_tests/preDeploy.test.js | 24 +++++------ workflow_tests/reviewerChecklist.test.js | 6 +-- workflow_tests/test.test.js | 14 +++---- workflow_tests/testBuild.test.js | 42 ++++++++++---------- workflow_tests/utils/ExtendedAct.ts | 33 +++++++-------- workflow_tests/utils/JobMocker.ts | 5 +-- workflow_tests/utils/preGenerateTest.ts | 4 +- workflow_tests/utils/utils.ts | 2 +- workflow_tests/validateGithubActions.test.js | 6 +-- workflow_tests/verifyPodfile.test.js | 10 ++--- workflow_tests/verifySignedCommits.test.js | 6 +-- 22 files changed, 137 insertions(+), 141 deletions(-) diff --git a/workflow_tests/authorChecklist.test.js b/workflow_tests/authorChecklist.test.js index 831e7f695ba4..536ef929ca02 100644 --- a/workflow_tests/authorChecklist.test.js +++ b/workflow_tests/authorChecklist.test.js @@ -3,7 +3,7 @@ const kieMockGithub = require('@kie/mock-github'); const utils = require('./utils/utils'); const assertions = require('./assertions/authorChecklistAssertions'); const mocks = require('./mocks/authorChecklistMocks'); -const eAct = require('./utils/ExtendedAct'); +const ExtendedAct = require('./utils/ExtendedAct').default; jest.setTimeout(90 * 1000); let mockGithub; @@ -49,7 +49,7 @@ describe('test workflow authorChecklist', () => { it('executes workflow', async () => { const repoPath = mockGithub.repo.getPath('testAuthorChecklistWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'authorChecklist.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams(act, event, eventOptions, {}, githubToken); const testMockSteps = { checklist: mocks.AUTHORCHECKLIST__CHECKLIST__STEP_MOCKS, @@ -68,7 +68,7 @@ describe('test workflow authorChecklist', () => { it('does not execute workflow', async () => { const repoPath = mockGithub.repo.getPath('testAuthorChecklistWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'authorChecklist.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams(act, event, eventOptions, {}, githubToken); const testMockSteps = { checklist: mocks.AUTHORCHECKLIST__CHECKLIST__STEP_MOCKS, @@ -93,7 +93,7 @@ describe('test workflow authorChecklist', () => { it('executes workflow', async () => { const repoPath = mockGithub.repo.getPath('testAuthorChecklistWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'authorChecklist.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams(act, event, eventOptions, {}, githubToken); const testMockSteps = { checklist: mocks.AUTHORCHECKLIST__CHECKLIST__STEP_MOCKS, @@ -112,7 +112,7 @@ describe('test workflow authorChecklist', () => { it('does not execute workflow', async () => { const repoPath = mockGithub.repo.getPath('testAuthorChecklistWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'authorChecklist.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams(act, event, eventOptions, {}, githubToken); const testMockSteps = { checklist: mocks.AUTHORCHECKLIST__CHECKLIST__STEP_MOCKS, @@ -137,7 +137,7 @@ describe('test workflow authorChecklist', () => { it('executes workflow', async () => { const repoPath = mockGithub.repo.getPath('testAuthorChecklistWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'authorChecklist.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams(act, event, eventOptions, {}, githubToken); const testMockSteps = { checklist: mocks.AUTHORCHECKLIST__CHECKLIST__STEP_MOCKS, @@ -156,7 +156,7 @@ describe('test workflow authorChecklist', () => { it('does not execute workflow', async () => { const repoPath = mockGithub.repo.getPath('testAuthorChecklistWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'authorChecklist.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams(act, event, eventOptions, {}, githubToken); const testMockSteps = { checklist: mocks.AUTHORCHECKLIST__CHECKLIST__STEP_MOCKS, diff --git a/workflow_tests/cherryPick.test.js b/workflow_tests/cherryPick.test.js index 592170a7c64e..beae7f03b3ef 100644 --- a/workflow_tests/cherryPick.test.js +++ b/workflow_tests/cherryPick.test.js @@ -3,7 +3,7 @@ const kieMockGithub = require('@kie/mock-github'); const utils = require('./utils/utils'); const assertions = require('./assertions/cherryPickAssertions'); const mocks = require('./mocks/cherryPickMocks'); -const eAct = require('./utils/ExtendedAct'); +const ExtendedAct = require('./utils/ExtendedAct').default; jest.setTimeout(90 * 1000); let mockGithub; @@ -45,7 +45,7 @@ describe('test workflow cherryPick', () => { it('workflow ends after validate job', async () => { const repoPath = mockGithub.repo.getPath('testCherryPickWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'cherryPick.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams( act, event, @@ -95,7 +95,7 @@ describe('test workflow cherryPick', () => { it('behaviour is the same as with actor being the deployer', async () => { const repoPath = mockGithub.repo.getPath('testCherryPickWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'cherryPick.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); const testMockSteps = { validateActor: mocks.CHERRYPICK__VALIDATEACTOR__FALSE__STEP_MOCKS, cherryPick: mocks.getCherryPickMockSteps(versionsMatch, mergeConflicts), @@ -147,7 +147,7 @@ describe('test workflow cherryPick', () => { it('workflow executes, PR approved and merged automatically', async () => { const repoPath = mockGithub.repo.getPath('testCherryPickWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'cherryPick.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); const testMockSteps = { validateActor: mocks.CHERRYPICK__VALIDATEACTOR__TRUE__STEP_MOCKS, }; @@ -195,7 +195,7 @@ describe('test workflow cherryPick', () => { it('workflow executes, PR auto-assigned and commented, approved and merged automatically', async () => { const repoPath = mockGithub.repo.getPath('testCherryPickWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'cherryPick.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); const testMockSteps = { validateActor: mocks.CHERRYPICK__VALIDATEACTOR__TRUE__STEP_MOCKS, }; @@ -246,7 +246,7 @@ describe('test workflow cherryPick', () => { it('workflow executes, PR auto-assigned and commented, not merged automatically', async () => { const repoPath = mockGithub.repo.getPath('testCherryPickWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'cherryPick.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); const testMockSteps = { validateActor: mocks.CHERRYPICK__VALIDATEACTOR__TRUE__STEP_MOCKS, }; @@ -294,7 +294,7 @@ describe('test workflow cherryPick', () => { it('workflow executes, PR auto-assigned and commented, not merged automatically', async () => { const repoPath = mockGithub.repo.getPath('testCherryPickWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'cherryPick.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); const testMockSteps = { validateActor: mocks.CHERRYPICK__VALIDATEACTOR__TRUE__STEP_MOCKS, }; @@ -345,7 +345,7 @@ describe('test workflow cherryPick', () => { it('workflow does not execute', async () => { const repoPath = mockGithub.repo.getPath('testCherryPickWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'cherryPick.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams( act, event, diff --git a/workflow_tests/cla.test.js b/workflow_tests/cla.test.js index 301aa7587f53..cf1dfd00ca4a 100644 --- a/workflow_tests/cla.test.js +++ b/workflow_tests/cla.test.js @@ -3,7 +3,7 @@ const kieMockGithub = require('@kie/mock-github'); const utils = require('./utils/utils'); const assertions = require('./assertions/claAssertions'); const mocks = require('./mocks/claMocks'); -const eAct = require('./utils/ExtendedAct'); +const ExtendedAct = require('./utils/ExtendedAct').default; jest.setTimeout(90 * 1000); let mockGithub; @@ -62,7 +62,7 @@ describe('test workflow cla', () => { it('workflow executes, CLA assistant step not run', async () => { const repoPath = mockGithub.repo.getPath('testClaWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'cla.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams(act, event, eventData, secrets, githubToken); const testMockSteps = { CLA: mocks.CLA__CLA__NO_MATCHES__STEP_MOCKS, @@ -93,7 +93,7 @@ describe('test workflow cla', () => { it('workflow executes, CLA assistant step run', async () => { const repoPath = mockGithub.repo.getPath('testClaWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'cla.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams(act, event, eventData, secrets, githubToken); const testMockSteps = { CLA: mocks.CLA__CLA__CHECK_MATCH__STEP_MOCKS, @@ -124,7 +124,7 @@ describe('test workflow cla', () => { it('workflow executes, CLA assistant step run', async () => { const repoPath = mockGithub.repo.getPath('testClaWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'cla.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams(act, event, eventData, secrets, githubToken); const testMockSteps = { CLA: mocks.CLA__CLA__RECHECK_MATCH__STEP_MOCKS, @@ -154,7 +154,7 @@ describe('test workflow cla', () => { it('workflow executes, CLA assistant step still run', async () => { const repoPath = mockGithub.repo.getPath('testClaWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'cla.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams(act, event, eventData, secrets, githubToken); const testMockSteps = { CLA: mocks.CLA__CLA__NO_MATCHES__STEP_MOCKS, @@ -178,7 +178,7 @@ describe('test workflow cla', () => { }; const repoPath = mockGithub.repo.getPath('testClaWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'cla.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams(act, event, eventData, secrets, githubToken); const testMockSteps = { CLA: mocks.CLA__CLA__NO_MATCHES__STEP_MOCKS, diff --git a/workflow_tests/createNewVersion.test.js b/workflow_tests/createNewVersion.test.js index dca1afbd9a41..08ac63ba9948 100644 --- a/workflow_tests/createNewVersion.test.js +++ b/workflow_tests/createNewVersion.test.js @@ -3,7 +3,7 @@ const kieMockGithub = require('@kie/mock-github'); const utils = require('./utils/utils'); const assertions = require('./assertions/createNewVersionAssertions'); const mocks = require('./mocks/createNewVersionMocks'); -const eAct = require('./utils/ExtendedAct'); +const ExtendedAct = require('./utils/ExtendedAct').default; jest.setTimeout(90 * 1000); // 90 sec let mockGithub; @@ -58,7 +58,7 @@ describe('test workflow createNewVersion', () => { it('executes full workflow', async () => { const repoPath = mockGithub.repo.getPath('testCreateNewVersionWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'createNewVersion.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams(act, event, {}, secrets, githubToken, {}, inputs); act = utils.setJobRunners(act, {createNewVersion: 'ubuntu-latest'}, workflowPath); const testMockSteps = { @@ -81,7 +81,7 @@ describe('test workflow createNewVersion', () => { it('executes full workflow', async () => { const repoPath = mockGithub.repo.getPath('testCreateNewVersionWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'createNewVersion.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams(act, event, {}, secrets, githubToken, {}, inputs); act = utils.setJobRunners(act, {createNewVersion: 'ubuntu-latest'}, workflowPath); const testMockSteps = { @@ -104,7 +104,7 @@ describe('test workflow createNewVersion', () => { it('stops after validation', async () => { const repoPath = mockGithub.repo.getPath('testCreateNewVersionWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'createNewVersion.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams(act, event, {}, secrets, githubToken, {}, inputs); act = utils.setJobRunners(act, {createNewVersion: 'ubuntu-latest'}, workflowPath); const testMockSteps = { @@ -126,7 +126,7 @@ describe('test workflow createNewVersion', () => { it('announces failure on Slack', async () => { const repoPath = mockGithub.repo.getPath('testCreateNewVersionWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'createNewVersion.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams(act, event, {}, secrets, githubToken, {}, inputs); act = utils.setJobRunners(act, {createNewVersion: 'ubuntu-latest'}, workflowPath); const testMockSteps = { @@ -148,7 +148,7 @@ describe('test workflow createNewVersion', () => { it('chooses source branch depending on the SEMVER_LEVEL', async () => { const repoPath = mockGithub.repo.getPath('testCreateNewVersionWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'createNewVersion.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams(act, event, {}, secrets, githubToken, {}, {SEMVER_LEVEL: 'MAJOR'}); act = utils.setJobRunners(act, {createNewVersion: 'ubuntu-latest'}, workflowPath); const testMockSteps = { diff --git a/workflow_tests/deploy.test.js b/workflow_tests/deploy.test.js index b15a167d4702..cf5b658d3ffb 100644 --- a/workflow_tests/deploy.test.js +++ b/workflow_tests/deploy.test.js @@ -3,7 +3,7 @@ const kieMockGithub = require('@kie/mock-github'); const utils = require('./utils/utils'); const assertions = require('./assertions/deployAssertions'); const mocks = require('./mocks/deployMocks'); -const eAct = require('./utils/ExtendedAct'); +const ExtendedAct = require('./utils/ExtendedAct').default; jest.setTimeout(90 * 1000); let mockGithub; @@ -50,7 +50,7 @@ describe('test workflow deploy', () => { it('to main - nothing triggered', async () => { const repoPath = mockGithub.repo.getPath('testDeployWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'deploy.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams( act, 'push', @@ -77,7 +77,7 @@ describe('test workflow deploy', () => { it('to staging - deployStaging triggered', async () => { const repoPath = mockGithub.repo.getPath('testDeployWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'deploy.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams( act, 'push', @@ -104,7 +104,7 @@ describe('test workflow deploy', () => { it('to production - deployProduction triggered', async () => { const repoPath = mockGithub.repo.getPath('testDeployWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'deploy.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams( act, 'push', @@ -132,7 +132,7 @@ describe('test workflow deploy', () => { it('different event than push - workflow does not execute', async () => { const repoPath = mockGithub.repo.getPath('testDeployWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'deploy.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); const testMockSteps = { deployStaging: mocks.DEPLOY_STAGING_STEP_MOCKS, deployProduction: mocks.DEPLOY_PRODUCTION_STEP_MOCKS, diff --git a/workflow_tests/deployBlocker.test.js b/workflow_tests/deployBlocker.test.js index 2fee3d01915a..42c4f9e741f7 100644 --- a/workflow_tests/deployBlocker.test.js +++ b/workflow_tests/deployBlocker.test.js @@ -3,7 +3,7 @@ const kieMockGithub = require('@kie/mock-github'); const utils = require('./utils/utils'); const assertions = require('./assertions/deployBlockerAssertions'); const mocks = require('./mocks/deployBlockerMocks'); -const eAct = require('./utils/ExtendedAct'); +const ExtendedAct = require('./utils/ExtendedAct').default; jest.setTimeout(90 * 1000); let mockGithub; @@ -66,7 +66,7 @@ describe('test workflow deployBlocker', () => { it('runs the workflow and announces success on Slack', async () => { const repoPath = mockGithub.repo.getPath('testDeployBlockerWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'deployBlocker.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams(act, event, testEventOptions, secrets, githubToken, {}, {}); const testMockSteps = { deployBlocker: mocks.DEPLOYBLOCKER__DEPLOYBLOCKER__STEP_MOCKS, @@ -92,7 +92,7 @@ describe('test workflow deployBlocker', () => { it('announces failure on Slack', async () => { const repoPath = mockGithub.repo.getPath('testDeployBlockerWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'deployBlocker.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams(act, event, testEventOptions, secrets, githubToken, {}, {}); const testMockSteps = { deployBlocker: utils.deepCopy(mocks.DEPLOYBLOCKER__DEPLOYBLOCKER__STEP_MOCKS), @@ -132,7 +132,7 @@ describe('test workflow deployBlocker', () => { it('does not run workflow', async () => { const repoPath = mockGithub.repo.getPath('testDeployBlockerWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'deployBlocker.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams(act, event, testEventOptions, secrets, githubToken, {}, {}); const testMockSteps = { deployBlocker: mocks.DEPLOYBLOCKER__DEPLOYBLOCKER__STEP_MOCKS, diff --git a/workflow_tests/failureNotifier.test.js b/workflow_tests/failureNotifier.test.js index 655d5ed64d83..d521c6cde00e 100644 --- a/workflow_tests/failureNotifier.test.js +++ b/workflow_tests/failureNotifier.test.js @@ -2,7 +2,7 @@ const path = require('path'); const kieMockGithub = require('@kie/mock-github'); const assertions = require('./assertions/failureNotifierAssertions'); const mocks = require('./mocks/failureNotifierMocks'); -const eAct = require('./utils/ExtendedAct'); +const ExtendedAct = require('./utils/ExtendedAct').default; jest.setTimeout(90 * 1000); let mockGithub; @@ -36,7 +36,7 @@ describe('test workflow failureNotifier', () => { it('runs the notify failure when main fails', async () => { const repoPath = mockGithub.repo.getPath('testFailureNotifierWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'failureNotifier.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); const event = 'workflow_run'; act = act.setEvent({ workflow_run: { diff --git a/workflow_tests/finishReleaseCycle.test.js b/workflow_tests/finishReleaseCycle.test.js index 26b4d2f60afc..20ab66471d91 100644 --- a/workflow_tests/finishReleaseCycle.test.js +++ b/workflow_tests/finishReleaseCycle.test.js @@ -3,7 +3,7 @@ const kieMockGithub = require('@kie/mock-github'); const utils = require('./utils/utils'); const assertions = require('./assertions/finishReleaseCycleAssertions'); const mocks = require('./mocks/finishReleaseCycleMocks'); -const eAct = require('./utils/ExtendedAct'); +const ExtendedAct = require('./utils/ExtendedAct').default; jest.setTimeout(90 * 1000); let mockGithub; @@ -52,7 +52,7 @@ describe('test workflow finishReleaseCycle', () => { it('production updated, new version created', async () => { const repoPath = mockGithub.repo.getPath('testFinishReleaseCycleWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'finishReleaseCycle.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams( act, 'issues', @@ -98,7 +98,7 @@ describe('test workflow finishReleaseCycle', () => { it('production not updated, new version not created, issue reopened', async () => { const repoPath = mockGithub.repo.getPath('testFinishReleaseCycleWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'finishReleaseCycle.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams( act, 'issues', @@ -145,7 +145,7 @@ describe('test workflow finishReleaseCycle', () => { it('production not updated, new version not created, issue reopened', async () => { const repoPath = mockGithub.repo.getPath('testFinishReleaseCycleWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'finishReleaseCycle.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams( act, 'issues', @@ -192,7 +192,7 @@ describe('test workflow finishReleaseCycle', () => { it('validate job not run', async () => { const repoPath = mockGithub.repo.getPath('testFinishReleaseCycleWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'finishReleaseCycle.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams( act, 'issues', diff --git a/workflow_tests/lint.test.js b/workflow_tests/lint.test.js index bc51f31b657c..b13b4c1c3564 100644 --- a/workflow_tests/lint.test.js +++ b/workflow_tests/lint.test.js @@ -3,7 +3,7 @@ const kieMockGithub = require('@kie/mock-github'); const utils = require('./utils/utils'); const assertions = require('./assertions/lintAssertions'); const mocks = require('./mocks/lintMocks'); -const eAct = require('./utils/ExtendedAct'); +const ExtendedAct = require('./utils/ExtendedAct').default; jest.setTimeout(90 * 1000); let mockGithub; @@ -49,7 +49,7 @@ describe('test workflow lint', () => { it('runs the lint', async () => { const repoPath = mockGithub.repo.getPath('testLintWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'lint.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams(act, event, eventOptions, {}, githubToken); const testMockSteps = { lint: mocks.LINT__LINT__STEP_MOCKS, @@ -68,7 +68,7 @@ describe('test workflow lint', () => { it('runs the lint', async () => { const repoPath = mockGithub.repo.getPath('testLintWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'lint.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams(act, event, eventOptions, {}, githubToken); const testMockSteps = { lint: mocks.LINT__LINT__STEP_MOCKS, @@ -93,7 +93,7 @@ describe('test workflow lint', () => { it('runs the lint', async () => { const repoPath = mockGithub.repo.getPath('testLintWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'lint.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams(act, event, eventOptions, {}, githubToken); const testMockSteps = { lint: mocks.LINT__LINT__STEP_MOCKS, @@ -112,7 +112,7 @@ describe('test workflow lint', () => { it('does not run the lint', async () => { const repoPath = mockGithub.repo.getPath('testLintWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'lint.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams(act, event, eventOptions, {}, githubToken); const testMockSteps = { lint: mocks.LINT__LINT__STEP_MOCKS, @@ -135,7 +135,7 @@ describe('test workflow lint', () => { it('runs the lint', async () => { const repoPath = mockGithub.repo.getPath('testLintWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'lint.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams(act, event, eventOptions, {}, githubToken); const testMockSteps = { lint: mocks.LINT__LINT__STEP_MOCKS, diff --git a/workflow_tests/lockDeploys.test.js b/workflow_tests/lockDeploys.test.js index a57ed8847fd3..68c78653413c 100644 --- a/workflow_tests/lockDeploys.test.js +++ b/workflow_tests/lockDeploys.test.js @@ -3,7 +3,7 @@ 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'); +const ExtendedAct = require('./utils/ExtendedAct').default; jest.setTimeout(90 * 1000); let mockGithub; @@ -45,7 +45,7 @@ describe('test workflow lockDeploys', () => { it('job triggered, comment left in StagingDeployCash', async () => { const repoPath = mockGithub.repo.getPath('testLockDeploysWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'lockDeploys.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams( act, 'issues', @@ -87,7 +87,7 @@ 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 workflowPath = path.join(repoPath, '.github', 'workflows', 'lockDeploys.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams( act, 'issues', @@ -141,7 +141,7 @@ describe('test workflow lockDeploys', () => { it('job not triggered, comment not left in StagingDeployCash', async () => { const repoPath = mockGithub.repo.getPath('testLockDeploysWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'lockDeploys.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams( act, 'issues', @@ -187,7 +187,7 @@ describe('test workflow lockDeploys', () => { it('job not triggered, comment not left in StagingDeployCash', async () => { const repoPath = mockGithub.repo.getPath('testLockDeploysWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'lockDeploys.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams( act, 'issues', @@ -231,7 +231,7 @@ describe('test workflow lockDeploys', () => { it('job not triggered, comment not left in StagingDeployCash', async () => { const repoPath = mockGithub.repo.getPath('testLockDeploysWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'lockDeploys.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams( act, 'issues', @@ -279,7 +279,7 @@ describe('test workflow lockDeploys', () => { it('job not triggered, comment not left in StagingDeployCash', async () => { const repoPath = mockGithub.repo.getPath('testLockDeploysWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'lockDeploys.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams( act, 'issues', @@ -323,7 +323,7 @@ describe('test workflow lockDeploys', () => { it('job not triggered, comment not left in StagingDeployCash', async () => { const repoPath = mockGithub.repo.getPath('testLockDeploysWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'lockDeploys.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams( act, 'issues', @@ -369,7 +369,7 @@ describe('test workflow lockDeploys', () => { it('job not triggered, comment not left in StagingDeployCash', async () => { const repoPath = mockGithub.repo.getPath('testLockDeploysWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'lockDeploys.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams( act, 'issues', @@ -413,7 +413,7 @@ describe('test workflow lockDeploys', () => { it('job not triggered, comment not left in StagingDeployCash', async () => { const repoPath = mockGithub.repo.getPath('testLockDeploysWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'lockDeploys.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams( act, 'issues', diff --git a/workflow_tests/platformDeploy.test.js b/workflow_tests/platformDeploy.test.js index 6bcd5ff5b896..2215ce7f4d83 100644 --- a/workflow_tests/platformDeploy.test.js +++ b/workflow_tests/platformDeploy.test.js @@ -3,7 +3,7 @@ const kieMockGithub = require('@kie/mock-github'); const utils = require('./utils/utils'); const assertions = require('./assertions/platformDeployAssertions'); const mocks = require('./mocks/platformDeployMocks'); -const eAct = require('./utils/ExtendedAct'); +const ExtendedAct = require('./utils/ExtendedAct').default; jest.setTimeout(90 * 1000); let mockGithub; @@ -44,7 +44,7 @@ describe('test workflow platformDeploy', () => { it('as team member - platform deploy executes on staging', async () => { const repoPath = mockGithub.repo.getPath('testPlatformDeployWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'platformDeploy.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams( act, 'push', @@ -126,7 +126,7 @@ describe('test workflow platformDeploy', () => { it('as OSBotify - platform deploy executes on staging', async () => { const repoPath = mockGithub.repo.getPath('testPlatformDeployWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'platformDeploy.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams( act, 'push', @@ -208,7 +208,7 @@ describe('test workflow platformDeploy', () => { it('as outsider - platform deploy does not execute', async () => { const repoPath = mockGithub.repo.getPath('testPlatformDeployWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'platformDeploy.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams( act, 'push', diff --git a/workflow_tests/preDeploy.test.js b/workflow_tests/preDeploy.test.js index 0d5b126b4430..eef80b904a91 100644 --- a/workflow_tests/preDeploy.test.js +++ b/workflow_tests/preDeploy.test.js @@ -3,7 +3,7 @@ const kieMockGithub = require('@kie/mock-github'); const utils = require('./utils/utils'); const assertions = require('./assertions/preDeployAssertions'); const mocks = require('./mocks/preDeployMocks'); -const eAct = require('./utils/ExtendedAct'); +const ExtendedAct = require('./utils/ExtendedAct').default; jest.setTimeout(90 * 1000); let mockGithub; @@ -47,7 +47,7 @@ describe('test workflow preDeploy', () => { const workflowPath = path.join(repoPath, '.github', 'workflows', 'preDeploy.yml'); // instantiate Act in the context of the test repo and given workflow file - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); // set run parameters act = utils.setUpActParams( @@ -119,7 +119,7 @@ describe('test workflow preDeploy', () => { it('different event than push - workflow does not execute', async () => { const repoPath = mockGithub.repo.getPath('testPreDeployWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'preDeploy.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); const testMockSteps = { confirmPassingBuild: mocks.CONFIRM_PASSING_BUILD_JOB_MOCK_STEPS, chooseDeployActions: mocks.CHOOSE_DEPLOY_ACTIONS_JOB_MOCK_STEPS__STAGING_UNLOCKED, @@ -212,7 +212,7 @@ describe('test workflow preDeploy', () => { it('typecheck job failed - workflow exits', async () => { const repoPath = mockGithub.repo.getPath('testPreDeployWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'preDeploy.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams( act, 'push', @@ -285,7 +285,7 @@ describe('test workflow preDeploy', () => { it('lint job failed - workflow exits', async () => { const repoPath = mockGithub.repo.getPath('testPreDeployWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'preDeploy.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams( act, 'push', @@ -356,7 +356,7 @@ describe('test workflow preDeploy', () => { it('test job failed - workflow exits', async () => { const repoPath = mockGithub.repo.getPath('testPreDeployWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'preDeploy.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams( act, 'push', @@ -427,7 +427,7 @@ describe('test workflow preDeploy', () => { it('lint and test job succeed - workflow continues', async () => { const repoPath = mockGithub.repo.getPath('testPreDeployWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'preDeploy.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams( act, 'push', @@ -493,7 +493,7 @@ describe('test workflow preDeploy', () => { it('not automated PR - deploy skipped and comment left', async () => { const repoPath = mockGithub.repo.getPath('testPreDeployWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'preDeploy.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams(act, 'push', {ref: 'refs/heads/main'}, {OS_BOTIFY_TOKEN: 'dummy_token', SLACK_WEBHOOK: 'dummy_slack_webhook'}, 'dummy_github_token'); const testMockSteps = { confirmPassingBuild: mocks.CONFIRM_PASSING_BUILD_JOB_MOCK_STEPS, @@ -547,7 +547,7 @@ describe('test workflow preDeploy', () => { it('automated PR - deploy skipped, but no comment left', async () => { const repoPath = mockGithub.repo.getPath('testPreDeployWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'preDeploy.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams(act, 'push', {ref: 'refs/heads/main'}, {OS_BOTIFY_TOKEN: 'dummy_token', SLACK_WEBHOOK: 'dummy_slack_webhook'}, 'dummy_github_token'); const testMockSteps = { confirmPassingBuild: mocks.CONFIRM_PASSING_BUILD_JOB_MOCK_STEPS, @@ -603,7 +603,7 @@ describe('test workflow preDeploy', () => { it('not automated PR - proceed with deploy', async () => { const repoPath = mockGithub.repo.getPath('testPreDeployWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'preDeploy.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams( act, 'push', @@ -667,7 +667,7 @@ describe('test workflow preDeploy', () => { it('automated PR - deploy skipped, but no comment left', async () => { const repoPath = mockGithub.repo.getPath('testPreDeployWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'preDeploy.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams( act, 'push', @@ -731,7 +731,7 @@ describe('test workflow preDeploy', () => { it('one of updateStaging steps failed - failure announced in Slack', async () => { const repoPath = mockGithub.repo.getPath('testPreDeployWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'preDeploy.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams( act, 'push', diff --git a/workflow_tests/reviewerChecklist.test.js b/workflow_tests/reviewerChecklist.test.js index 9903c3eb4b8d..0c719a04a987 100644 --- a/workflow_tests/reviewerChecklist.test.js +++ b/workflow_tests/reviewerChecklist.test.js @@ -3,7 +3,7 @@ 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'); +const ExtendedAct = require('./utils/ExtendedAct').default; jest.setTimeout(90 * 1000); let mockGithub; @@ -46,7 +46,7 @@ describe('test workflow reviewerChecklist', () => { 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); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams(act, event, eventOptions, {}, githubToken); const testMockSteps = { checklist: mocks.REVIEWERCHECKLIST__CHECKLIST__STEP_MOCKS, @@ -65,7 +65,7 @@ describe('test workflow reviewerChecklist', () => { it('does not run 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); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams(act, event, eventOptions, {}, githubToken); const testMockSteps = { checklist: mocks.REVIEWERCHECKLIST__CHECKLIST__STEP_MOCKS, diff --git a/workflow_tests/test.test.js b/workflow_tests/test.test.js index 6efe8d260928..1ad8a1b48e4b 100644 --- a/workflow_tests/test.test.js +++ b/workflow_tests/test.test.js @@ -3,7 +3,7 @@ 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'); +const ExtendedAct = require('./utils/ExtendedAct').default; jest.setTimeout(90 * 1000); let mockGithub; @@ -51,7 +51,7 @@ describe('test workflow test', () => { it('runs all tests', async () => { const repoPath = mockGithub.repo.getPath('testTestWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'test.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams(act, event, eventOptions, {}, githubToken); const testMockSteps = { jest: mocks.TEST__JEST__STEP_MOCKS, @@ -71,7 +71,7 @@ describe('test workflow test', () => { it('does not run tests', async () => { const repoPath = mockGithub.repo.getPath('testTestWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'test.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams(act, event, eventOptions, {}, githubToken); const testMockSteps = { jest: mocks.TEST__JEST__STEP_MOCKS, @@ -98,7 +98,7 @@ describe('test workflow test', () => { it('runs all tests', async () => { const repoPath = mockGithub.repo.getPath('testTestWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'test.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams(act, event, eventOptions, {}, githubToken); const testMockSteps = { jest: mocks.TEST__JEST__STEP_MOCKS, @@ -118,7 +118,7 @@ describe('test workflow test', () => { it('does not run tests', async () => { const repoPath = mockGithub.repo.getPath('testTestWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'test.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams(act, event, eventOptions, {}, githubToken); const testMockSteps = { jest: mocks.TEST__JEST__STEP_MOCKS, @@ -143,7 +143,7 @@ describe('test workflow test', () => { it('runs all tests', async () => { const repoPath = mockGithub.repo.getPath('testTestWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'test.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams(act, event, eventOptions, {}, githubToken); const testMockSteps = { jest: mocks.TEST__JEST__STEP_MOCKS, @@ -163,7 +163,7 @@ describe('test workflow test', () => { it('runs all tests normally', async () => { const repoPath = mockGithub.repo.getPath('testTestWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'test.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams(act, event, eventOptions, {}, githubToken); const testMockSteps = { jest: mocks.TEST__JEST__STEP_MOCKS, diff --git a/workflow_tests/testBuild.test.js b/workflow_tests/testBuild.test.js index 371759607ed5..7e93b0a9ac9f 100644 --- a/workflow_tests/testBuild.test.js +++ b/workflow_tests/testBuild.test.js @@ -3,7 +3,7 @@ const kieMockGithub = require('@kie/mock-github'); const utils = require('./utils/utils'); const assertions = require('./assertions/testBuildAssertions'); const mocks = require('./mocks/testBuildMocks'); -const eAct = require('./utils/ExtendedAct'); +const ExtendedAct = require('./utils/ExtendedAct').default; jest.setTimeout(90 * 1000); let mockGithub; @@ -62,7 +62,7 @@ describe('test workflow testBuild', () => { it('executes workflow', async () => { const repoPath = mockGithub.repo.getPath('testTestBuildWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'testBuild.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams(act, event, {}, secrets, githubToken, {}, inputs); act = utils.setJobRunners(act, {iOS: 'ubuntu-latest', desktop: 'ubuntu-latest', web: 'ubuntu-latest', android: 'ubuntu-latest'}, workflowPath); const testMockSteps = { @@ -93,7 +93,7 @@ describe('test workflow testBuild', () => { it('stops the workflow after validation', async () => { const repoPath = mockGithub.repo.getPath('testTestBuildWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'testBuild.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams(act, event, {}, secrets, githubToken, {}, inputs); act = utils.setJobRunners(act, {iOS: 'ubuntu-latest', desktop: 'ubuntu-latest', web: 'ubuntu-latest', android: 'ubuntu-latest'}, workflowPath); const testMockSteps = { @@ -125,7 +125,7 @@ describe('test workflow testBuild', () => { it('stops the workflow after validation', async () => { const repoPath = mockGithub.repo.getPath('testTestBuildWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'testBuild.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams(act, event, {}, secrets, githubToken, {}, inputs); act = utils.setJobRunners(act, {iOS: 'ubuntu-latest', desktop: 'ubuntu-latest', web: 'ubuntu-latest', android: 'ubuntu-latest'}, workflowPath); const testMockSteps = { @@ -157,7 +157,7 @@ describe('test workflow testBuild', () => { it('stops the workflow after validation', async () => { const repoPath = mockGithub.repo.getPath('testTestBuildWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'testBuild.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams(act, event, {}, secrets, githubToken, {}, inputs); act = utils.setJobRunners(act, {iOS: 'ubuntu-latest', desktop: 'ubuntu-latest', web: 'ubuntu-latest', android: 'ubuntu-latest'}, workflowPath); const testMockSteps = { @@ -189,7 +189,7 @@ describe('test workflow testBuild', () => { it('executes workflow, failure reflected', async () => { const repoPath = mockGithub.repo.getPath('testTestBuildWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'testBuild.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams(act, event, {}, secrets, githubToken, {}, inputs); act = utils.setJobRunners(act, {iOS: 'ubuntu-latest', desktop: 'ubuntu-latest', web: 'ubuntu-latest', android: 'ubuntu-latest'}, workflowPath); const testMockSteps = { @@ -222,7 +222,7 @@ describe('test workflow testBuild', () => { it('executes workflow, failure reflected', async () => { const repoPath = mockGithub.repo.getPath('testTestBuildWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'testBuild.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams(act, event, {}, secrets, githubToken, {}, inputs); act = utils.setJobRunners(act, {iOS: 'ubuntu-latest', desktop: 'ubuntu-latest', web: 'ubuntu-latest', android: 'ubuntu-latest'}, workflowPath); const testMockSteps = { @@ -255,7 +255,7 @@ describe('test workflow testBuild', () => { it('executes workflow, failure reflected', async () => { const repoPath = mockGithub.repo.getPath('testTestBuildWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'testBuild.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams(act, event, {}, secrets, githubToken, {}, inputs); act = utils.setJobRunners(act, {iOS: 'ubuntu-latest', desktop: 'ubuntu-latest', web: 'ubuntu-latest', android: 'ubuntu-latest'}, workflowPath); const testMockSteps = { @@ -297,7 +297,7 @@ describe('test workflow testBuild', () => { it('executes workflow, failure reflected', async () => { const repoPath = mockGithub.repo.getPath('testTestBuildWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'testBuild.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams(act, event, {}, secrets, githubToken, {}, inputs); act = utils.setJobRunners(act, {iOS: 'ubuntu-latest', desktop: 'ubuntu-latest', web: 'ubuntu-latest', android: 'ubuntu-latest'}, workflowPath); const testMockSteps = { @@ -350,7 +350,7 @@ describe('test workflow testBuild', () => { it('executes workflow, without getBranchRef', async () => { const repoPath = mockGithub.repo.getPath('testTestBuildWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'testBuild.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams(act, event, eventOptions, secrets, githubToken, {}); act = utils.setJobRunners(act, {iOS: 'ubuntu-latest', desktop: 'ubuntu-latest', web: 'ubuntu-latest', android: 'ubuntu-latest'}, workflowPath); const testMockSteps = { @@ -381,7 +381,7 @@ describe('test workflow testBuild', () => { it('stops the workflow after validation', async () => { const repoPath = mockGithub.repo.getPath('testTestBuildWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'testBuild.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams(act, event, eventOptions, secrets, githubToken, {}); act = utils.setJobRunners(act, {iOS: 'ubuntu-latest', desktop: 'ubuntu-latest', web: 'ubuntu-latest', android: 'ubuntu-latest'}, workflowPath); const testMockSteps = { @@ -413,7 +413,7 @@ describe('test workflow testBuild', () => { it('stops the workflow after validation', async () => { const repoPath = mockGithub.repo.getPath('testTestBuildWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'testBuild.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams(act, event, eventOptions, secrets, githubToken, {}); act = utils.setJobRunners(act, {iOS: 'ubuntu-latest', desktop: 'ubuntu-latest', web: 'ubuntu-latest', android: 'ubuntu-latest'}, workflowPath); const testMockSteps = { @@ -445,7 +445,7 @@ describe('test workflow testBuild', () => { it('stops the workflow after validation', async () => { const repoPath = mockGithub.repo.getPath('testTestBuildWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'testBuild.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams(act, event, eventOptions, secrets, githubToken, {}); act = utils.setJobRunners(act, {iOS: 'ubuntu-latest', desktop: 'ubuntu-latest', web: 'ubuntu-latest', android: 'ubuntu-latest'}, workflowPath); const testMockSteps = { @@ -488,7 +488,7 @@ describe('test workflow testBuild', () => { it('executes workflow, without getBranchRef', async () => { const repoPath = mockGithub.repo.getPath('testTestBuildWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'testBuild.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams(act, event, eventOptions, secrets, githubToken, {}); act = utils.setJobRunners(act, {iOS: 'ubuntu-latest', desktop: 'ubuntu-latest', web: 'ubuntu-latest', android: 'ubuntu-latest'}, workflowPath); const testMockSteps = { @@ -519,7 +519,7 @@ describe('test workflow testBuild', () => { it('stops the workflow after validation', async () => { const repoPath = mockGithub.repo.getPath('testTestBuildWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'testBuild.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams(act, event, eventOptions, secrets, githubToken, {}); act = utils.setJobRunners(act, {iOS: 'ubuntu-latest', desktop: 'ubuntu-latest', web: 'ubuntu-latest', android: 'ubuntu-latest'}, workflowPath); const testMockSteps = { @@ -551,7 +551,7 @@ describe('test workflow testBuild', () => { it('stops the workflow after validation', async () => { const repoPath = mockGithub.repo.getPath('testTestBuildWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'testBuild.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams(act, event, eventOptions, secrets, githubToken, {}); act = utils.setJobRunners(act, {iOS: 'ubuntu-latest', desktop: 'ubuntu-latest', web: 'ubuntu-latest', android: 'ubuntu-latest'}, workflowPath); const testMockSteps = { @@ -583,7 +583,7 @@ describe('test workflow testBuild', () => { it('stops the workflow after validation', async () => { const repoPath = mockGithub.repo.getPath('testTestBuildWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'testBuild.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams(act, event, eventOptions, secrets, githubToken, {}); act = utils.setJobRunners(act, {iOS: 'ubuntu-latest', desktop: 'ubuntu-latest', web: 'ubuntu-latest', android: 'ubuntu-latest'}, workflowPath); const testMockSteps = { @@ -626,7 +626,7 @@ describe('test workflow testBuild', () => { it('executes workflow, withuout getBranchRef', async () => { const repoPath = mockGithub.repo.getPath('testTestBuildWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'testBuild.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams(act, event, eventOptions, secrets, githubToken, {}); act = utils.setJobRunners(act, {iOS: 'ubuntu-latest', desktop: 'ubuntu-latest', web: 'ubuntu-latest', android: 'ubuntu-latest'}, workflowPath); const testMockSteps = { @@ -657,7 +657,7 @@ describe('test workflow testBuild', () => { it('stops the workflow after validation', async () => { const repoPath = mockGithub.repo.getPath('testTestBuildWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'testBuild.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams(act, event, eventOptions, secrets, githubToken, {}); act = utils.setJobRunners(act, {iOS: 'ubuntu-latest', desktop: 'ubuntu-latest', web: 'ubuntu-latest', android: 'ubuntu-latest'}, workflowPath); const testMockSteps = { @@ -689,7 +689,7 @@ describe('test workflow testBuild', () => { it('stops the workflow after validation', async () => { const repoPath = mockGithub.repo.getPath('testTestBuildWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'testBuild.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams(act, event, eventOptions, secrets, githubToken, {}); act = utils.setJobRunners(act, {iOS: 'ubuntu-latest', desktop: 'ubuntu-latest', web: 'ubuntu-latest', android: 'ubuntu-latest'}, workflowPath); const testMockSteps = { @@ -721,7 +721,7 @@ describe('test workflow testBuild', () => { it('stops the workflow after validation', async () => { const repoPath = mockGithub.repo.getPath('testTestBuildWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'testBuild.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams(act, event, eventOptions, secrets, githubToken, {}); act = utils.setJobRunners(act, {iOS: 'ubuntu-latest', desktop: 'ubuntu-latest', web: 'ubuntu-latest', android: 'ubuntu-latest'}, workflowPath); const testMockSteps = { diff --git a/workflow_tests/utils/ExtendedAct.ts b/workflow_tests/utils/ExtendedAct.ts index 81c2f0b981b2..b0f4d7e159e4 100644 --- a/workflow_tests/utils/ExtendedAct.ts +++ b/workflow_tests/utils/ExtendedAct.ts @@ -1,21 +1,21 @@ /* eslint-disable @typescript-eslint/dot-notation */ // This eslint-disable comment is here to allow accessing private properties in the Act class -import type {RunOpts, Workflow} from '@kie/act-js'; -import * as kieActJs from '@kie/act-js'; +import type {RunOpts, Step, Workflow} from '@kie/act-js'; +import {Act} from '@kie/act-js'; import path from 'path'; -import {JobMocker} from './JobMocker'; +import JobMocker from './JobMocker'; import type {MockJobs} from './JobMocker'; type ExtendedActOpts = RunOpts & {actor?: string; workflowFile?: string; mockJobs?: MockJobs}; type ActOptions = { - cwd: string | undefined; + cwd: string; actArguments: string[]; proxy: unknown; }; // @ts-expect-error Override shouldn't be done on private methods wait until https://github.com/kiegroup/act-js/issues/77 is resolved or try to create a params workaround -class ExtendedAct extends kieActJs.Act { +class ExtendedAct extends Act { async parseRunOpts(opts?: ExtendedActOpts): Promise { const {cwd, actArguments, proxy} = await super['parseRunOpts'](opts); @@ -26,36 +26,33 @@ class ExtendedAct extends kieActJs.Act { return {cwd, actArguments, proxy}; } - async runEvent(event: string, opts?: ExtendedActOpts): Promise { + async runEvent(event: string, opts?: ExtendedActOpts): Promise { const {mockJobs, ...vanillaOpts} = opts ?? {}; if (mockJobs) { - await this.handleJobMocking((workflow) => workflow.events.includes(event), {mockJobs, workflowFile: opts?.workflowFile, cwd: opts?.cwd}); + await this.handleJobMocking((workflow) => workflow.events.includes(event), {mockJobs, workflowFile: vanillaOpts.workflowFile, cwd: vanillaOpts.cwd}); } return super.runEvent(event, vanillaOpts); } - async handleJobMocking(filter: (workflow: Workflow) => boolean, opts?: ExtendedActOpts): Promise { + async handleJobMocking(filter: (workflow: Workflow) => boolean, opts: ExtendedActOpts): Promise { let workflowFiles: string[]; - if (opts?.workflowFile) { + if (opts.workflowFile) { workflowFiles = [path.basename(opts.workflowFile)]; } else if (this['workflowFile'] !== this['cwd']) { workflowFiles = [path.basename(this['workflowFile'])]; } else { - const availableWorkflows = await this.list(undefined, opts?.cwd, opts?.workflowFile); + const availableWorkflows = await this.list(undefined, opts.cwd, opts.workflowFile); workflowFiles = availableWorkflows.filter(filter).map((workflow: Workflow) => workflow.workflowFile); } - return Promise.all( - workflowFiles.map((workflowFile) => { - const jobMocker = new JobMocker(workflowFile, opts?.cwd ?? this['cwd']); - return jobMocker.mock(opts?.mockJobs); - }), - ); + return workflowFiles.map((workflowFile) => { + const jobMocker = new JobMocker(workflowFile, opts.cwd ?? this['cwd']); + return jobMocker.mock(opts.mockJobs); + }); } } -// eslint-disable-next-line import/prefer-default-export -export {ExtendedAct}; +export default ExtendedAct; diff --git a/workflow_tests/utils/JobMocker.ts b/workflow_tests/utils/JobMocker.ts index 84ab7fe66f41..b6dc99771dd2 100644 --- a/workflow_tests/utils/JobMocker.ts +++ b/workflow_tests/utils/JobMocker.ts @@ -16,7 +16,7 @@ type MockJob = { secrets?: string[]; with?: string; outputs?: string[]; - runsOn: string; + runsOn?: string; }; type MockJobs = Record; @@ -113,6 +113,5 @@ class JobMocker { } } -// eslint-disable-next-line import/prefer-default-export -export {JobMocker}; +export default JobMocker; export type {MockJob, MockJobs, YamlWorkflow, YamlMockJob, MockJobStep}; diff --git a/workflow_tests/utils/preGenerateTest.ts b/workflow_tests/utils/preGenerateTest.ts index 1f1826ea6b0d..7698e618432d 100644 --- a/workflow_tests/utils/preGenerateTest.ts +++ b/workflow_tests/utils/preGenerateTest.ts @@ -27,7 +27,7 @@ const kieMockGithub = require('@kie/mock-github'); const utils = require('./utils/utils'); const assertions = require('./assertions/${workflowName}Assertions'); const mocks = require('./mocks/${workflowName}Mocks'); -const eAct = require('./utils/ExtendedAct'); +const ExtendedAct = require('./utils/ExtendedAct').default; jest.setTimeout(90 * 1000); let mockGithub; @@ -74,7 +74,7 @@ describe('test workflow ${workflowName}', () => { it('test stub', async () => { const repoPath = mockGithub.repo.getPath('test${capitalize(workflowName)}WorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', '${workflowName}.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams( act, '[EVENT]', diff --git a/workflow_tests/utils/utils.ts b/workflow_tests/utils/utils.ts index 71bb2194c9fe..dcc04aee02de 100644 --- a/workflow_tests/utils/utils.ts +++ b/workflow_tests/utils/utils.ts @@ -2,7 +2,7 @@ import type {StepIdentifier} from '@kie/act-js/build/src/step-mocker/step-mocker import fs from 'fs'; import path from 'path'; import yaml from 'yaml'; -import type {ExtendedAct} from './ExtendedAct'; +import type ExtendedAct from './ExtendedAct'; type EventOptions = { action?: string; diff --git a/workflow_tests/validateGithubActions.test.js b/workflow_tests/validateGithubActions.test.js index dfa5e9362ce7..5a18d4b0efff 100644 --- a/workflow_tests/validateGithubActions.test.js +++ b/workflow_tests/validateGithubActions.test.js @@ -3,7 +3,7 @@ const kieMockGithub = require('@kie/mock-github'); const utils = require('./utils/utils'); const assertions = require('./assertions/validateGithubActionsAssertions'); const mocks = require('./mocks/validateGithubActionsMocks'); -const eAct = require('./utils/ExtendedAct'); +const ExtendedAct = require('./utils/ExtendedAct').default; jest.setTimeout(90 * 1000); let mockGithub; @@ -49,7 +49,7 @@ describe('test workflow validateGithubActions', () => { it('executes verification', async () => { const repoPath = mockGithub.repo.getPath('testValidateGithubActionsWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'validateGithubActions.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams(act, event, eventOptions, {}, githubToken); const testMockSteps = { verify: mocks.VALIDATEGITHUBACTIONS__VERIFY__STEP_MOCKS, @@ -72,7 +72,7 @@ describe('test workflow validateGithubActions', () => { it('executes verification', async () => { const repoPath = mockGithub.repo.getPath('testValidateGithubActionsWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'validateGithubActions.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams(act, event, eventOptions, {}, githubToken); const testMockSteps = { verify: mocks.VALIDATEGITHUBACTIONS__VERIFY__STEP_MOCKS, diff --git a/workflow_tests/verifyPodfile.test.js b/workflow_tests/verifyPodfile.test.js index de062af2a2c2..e90ef8daadd3 100644 --- a/workflow_tests/verifyPodfile.test.js +++ b/workflow_tests/verifyPodfile.test.js @@ -3,7 +3,7 @@ const kieMockGithub = require('@kie/mock-github'); const utils = require('./utils/utils'); const assertions = require('./assertions/verifyPodfileAssertions'); const mocks = require('./mocks/verifyPodfileMocks'); -const eAct = require('./utils/ExtendedAct'); +const ExtendedAct = require('./utils/ExtendedAct').default; jest.setTimeout(90 * 1000); let mockGithub; @@ -50,7 +50,7 @@ describe('test workflow verifyPodfile', () => { it('executes workflow', async () => { const repoPath = mockGithub.repo.getPath('testVerifyPodfileWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'verifyPodfile.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams(act, event, eventOptions, {}, githubToken); act = utils.setJobRunners(act, {verify: 'ubuntu-latest'}, workflowPath); const testMockSteps = { @@ -69,7 +69,7 @@ describe('test workflow verifyPodfile', () => { it('does not execute workflow', async () => { const repoPath = mockGithub.repo.getPath('testVerifyPodfileWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'verifyPodfile.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams(act, event, eventOptions, {}, githubToken); act = utils.setJobRunners(act, {verify: 'ubuntu-latest'}, workflowPath); const testMockSteps = { @@ -94,7 +94,7 @@ describe('test workflow verifyPodfile', () => { it('executes workflow', async () => { const repoPath = mockGithub.repo.getPath('testVerifyPodfileWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'verifyPodfile.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams(act, event, eventOptions, {}, githubToken); act = utils.setJobRunners(act, {verify: 'ubuntu-latest'}, workflowPath); const testMockSteps = { @@ -113,7 +113,7 @@ describe('test workflow verifyPodfile', () => { it('does not execute workflow', async () => { const repoPath = mockGithub.repo.getPath('testVerifyPodfileWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'verifyPodfile.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams(act, event, eventOptions, {}, githubToken); act = utils.setJobRunners(act, {verify: 'ubuntu-latest'}, workflowPath); const testMockSteps = { diff --git a/workflow_tests/verifySignedCommits.test.js b/workflow_tests/verifySignedCommits.test.js index 911208e91f4a..de4df3093715 100644 --- a/workflow_tests/verifySignedCommits.test.js +++ b/workflow_tests/verifySignedCommits.test.js @@ -3,7 +3,7 @@ const kieMockGithub = require('@kie/mock-github'); const utils = require('./utils/utils'); const assertions = require('./assertions/verifySignedCommitsAssertions'); const mocks = require('./mocks/verifySignedCommitsMocks'); -const eAct = require('./utils/ExtendedAct'); +const ExtendedAct = require('./utils/ExtendedAct').default; jest.setTimeout(90 * 1000); let mockGithub; @@ -49,7 +49,7 @@ describe('test workflow verifySignedCommits', () => { it('test stub', async () => { const repoPath = mockGithub.repo.getPath('testVerifySignedCommitsWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'verifySignedCommits.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams(act, event, eventOptions, {}, githubToken); const testMockSteps = { verifySignedCommits: mocks.VERIFYSIGNEDCOMMITS__VERIFYSIGNEDCOMMITS__STEP_MOCKS, @@ -72,7 +72,7 @@ describe('test workflow verifySignedCommits', () => { it('test stub', async () => { const repoPath = mockGithub.repo.getPath('testVerifySignedCommitsWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'verifySignedCommits.yml'); - let act = new eAct.ExtendedAct(repoPath, workflowPath); + let act = new ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams(act, event, eventOptions, {}, githubToken); const testMockSteps = { verifySignedCommits: mocks.VERIFYSIGNEDCOMMITS__VERIFYSIGNEDCOMMITS__STEP_MOCKS, From cecb40febfb2755774b752f1e952c96d052b63b7 Mon Sep 17 00:00:00 2001 From: Adam Grzybowski Date: Tue, 19 Mar 2024 11:31:14 +0100 Subject: [PATCH 151/175] add shouldSkipDeepLinkNavigation for web --- src/libs/shouldSkipDeepLinkNavigation/index.web.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 src/libs/shouldSkipDeepLinkNavigation/index.web.ts diff --git a/src/libs/shouldSkipDeepLinkNavigation/index.web.ts b/src/libs/shouldSkipDeepLinkNavigation/index.web.ts new file mode 100644 index 000000000000..0a2d7f533e74 --- /dev/null +++ b/src/libs/shouldSkipDeepLinkNavigation/index.web.ts @@ -0,0 +1,12 @@ +import ROUTES from '@src/ROUTES'; + +export default function shouldSkipDeepLinkNavigation(route: string) { + // When deep-linking to desktop app with `transition` route we don't want to call navigate + // on the route because it will display an infinite loading indicator. + // See issue: https://github.com/Expensify/App/issues/33149 + if (route.includes(ROUTES.TRANSITION_BETWEEN_APPS)) { + return true; + } + + return false; +} From af2c1b83006718a94a779651731955f53061d715 Mon Sep 17 00:00:00 2001 From: Artem Makushov Date: Tue, 19 Mar 2024 12:51:35 +0100 Subject: [PATCH 152/175] fixed decode bug --- src/ROUTES.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 5eda71fb34d4..82be3886d2c2 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -578,11 +578,11 @@ const ROUTES = { }, WORKSPACE_TAG_EDIT: { route: 'settings/workspace/:policyID/tag/:tagName/edit', - getRoute: (policyID: string, tagName: string) => `settings/workspace/${policyID}/tag/${encodeURIComponent(tagName)}/edit` as const, + getRoute: (policyID: string, tagName: string) => `settings/workspace/${policyID}/tag/${decodeURIComponent(tagName)}/edit` as const, }, WORKSPACE_TAG_SETTINGS: { route: 'settings/workspaces/:policyID/tag/:tagName', - getRoute: (policyID: string, tagName: string) => `settings/workspaces/${policyID}/tag/${encodeURIComponent(tagName)}` as const, + getRoute: (policyID: string, tagName: string) => `settings/workspaces/${policyID}/tag/${decodeURIComponent(tagName)}` as const, }, WORKSPACE_TAXES: { route: 'settings/workspaces/:policyID/taxes', From cea3a906f367b9a93d9fdd742aed2151b30c75c3 Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Tue, 19 Mar 2024 20:02:23 +0800 Subject: [PATCH 153/175] fix workspace list page status bar style --- src/styles/theme/themes/light.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/styles/theme/themes/light.ts b/src/styles/theme/themes/light.ts index 7fb04a2dad77..671bb36847c9 100644 --- a/src/styles/theme/themes/light.ts +++ b/src/styles/theme/themes/light.ts @@ -113,7 +113,7 @@ const lightTheme = { }, [SCREENS.SETTINGS.WORKSPACES]: { backgroundColor: colors.productLight100, - statusBarStyle: CONST.STATUS_BAR_STYLE.LIGHT_CONTENT, + statusBarStyle: CONST.STATUS_BAR_STYLE.DARK_CONTENT, }, [SCREENS.SETTINGS.WALLET.ROOT]: { backgroundColor: colors.productLight100, From 748898371f1c45e56e6bf29485a94e3f89383f32 Mon Sep 17 00:00:00 2001 From: Adam Grzybowski Date: Tue, 19 Mar 2024 13:08:43 +0100 Subject: [PATCH 154/175] add shouldSkipDeepLinkNavigation for all platforms --- ...ex.desktop.ts => shouldSkipDeepLinkNavigation.ts} | 0 src/libs/shouldSkipDeepLinkNavigation/index.ts | 5 ----- src/libs/shouldSkipDeepLinkNavigation/index.web.ts | 12 ------------ 3 files changed, 17 deletions(-) rename src/libs/{shouldSkipDeepLinkNavigation/index.desktop.ts => shouldSkipDeepLinkNavigation.ts} (100%) delete mode 100644 src/libs/shouldSkipDeepLinkNavigation/index.ts delete mode 100644 src/libs/shouldSkipDeepLinkNavigation/index.web.ts diff --git a/src/libs/shouldSkipDeepLinkNavigation/index.desktop.ts b/src/libs/shouldSkipDeepLinkNavigation.ts similarity index 100% rename from src/libs/shouldSkipDeepLinkNavigation/index.desktop.ts rename to src/libs/shouldSkipDeepLinkNavigation.ts diff --git a/src/libs/shouldSkipDeepLinkNavigation/index.ts b/src/libs/shouldSkipDeepLinkNavigation/index.ts deleted file mode 100644 index 8a2d8035507f..000000000000 --- a/src/libs/shouldSkipDeepLinkNavigation/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -// eslint-disable-next-line @typescript-eslint/no-unused-vars -export default function shouldSkipDeepLinkNavigation(route: string) { - // no-op for all other platforms - return false; -} diff --git a/src/libs/shouldSkipDeepLinkNavigation/index.web.ts b/src/libs/shouldSkipDeepLinkNavigation/index.web.ts deleted file mode 100644 index 0a2d7f533e74..000000000000 --- a/src/libs/shouldSkipDeepLinkNavigation/index.web.ts +++ /dev/null @@ -1,12 +0,0 @@ -import ROUTES from '@src/ROUTES'; - -export default function shouldSkipDeepLinkNavigation(route: string) { - // When deep-linking to desktop app with `transition` route we don't want to call navigate - // on the route because it will display an infinite loading indicator. - // See issue: https://github.com/Expensify/App/issues/33149 - if (route.includes(ROUTES.TRANSITION_BETWEEN_APPS)) { - return true; - } - - return false; -} From 55ca7493b68159df4f4a05871e2bfe1699915087 Mon Sep 17 00:00:00 2001 From: Michal Muzyk Date: Tue, 19 Mar 2024 14:44:52 +0100 Subject: [PATCH 155/175] fix: more cr fixes --- src/CONST.ts | 4 -- src/components/UnitPicker.tsx | 56 +++++++++++++++++++ src/languages/en.ts | 4 -- src/languages/es.ts | 4 -- .../CategorySelectorModal.tsx | 39 ++++--------- .../distanceRates/CategorySelector/index.tsx | 16 +++--- .../distanceRates/CategorySelector/types.ts | 8 --- .../PolicyDistanceRatesSettingsPage.tsx | 20 +++---- .../UnitSelector/UnitSelectorModal.tsx | 31 +++------- .../distanceRates/UnitSelector/index.tsx | 29 ++++++---- .../distanceRates/UnitSelector/types.ts | 13 ----- .../WorkspaceRateAndUnitPage/UnitPage.tsx | 46 +++------------ 12 files changed, 112 insertions(+), 158 deletions(-) create mode 100644 src/components/UnitPicker.tsx delete mode 100644 src/pages/workspace/distanceRates/CategorySelector/types.ts delete mode 100644 src/pages/workspace/distanceRates/UnitSelector/types.ts diff --git a/src/CONST.ts b/src/CONST.ts index 28a72dd6e00e..aac314ca926f 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -1459,10 +1459,6 @@ const CONST = { DISABLE: 'disable', ENABLE: 'enable', }, - UNITS: { - MI: 'Miles', - KM: 'Kilometers', - }, }, CUSTOM_UNITS: { diff --git a/src/components/UnitPicker.tsx b/src/components/UnitPicker.tsx new file mode 100644 index 000000000000..04620a4b72f1 --- /dev/null +++ b/src/components/UnitPicker.tsx @@ -0,0 +1,56 @@ +import Str from 'expensify-common/lib/str'; +import React, {useMemo} from 'react'; +import useLocalize from '@hooks/useLocalize'; +import CONST from '@src/CONST'; +import type {Unit} from '@src/types/onyx/Policy'; +import SelectionList from './SelectionList'; +import RadioListItem from './SelectionList/RadioListItem'; + +type UnitItemType = { + value: Unit; + text: string; + keyForList: string; + isSelected: boolean; +}; + +type UnitPickerProps = { + defaultValue: Unit; + onOptionSelected: (unit: UnitItemType) => void; +}; + +function UnitPicker({defaultValue, onOptionSelected}: UnitPickerProps) { + const {translate} = useLocalize(); + const unitItems = useMemo( + () => ({ + [CONST.CUSTOM_UNITS.DISTANCE_UNIT_KILOMETERS]: translate('common.kilometers'), + [CONST.CUSTOM_UNITS.DISTANCE_UNIT_MILES]: translate('common.miles'), + }), + [translate], + ); + + const unitOptions = useMemo(() => { + const arr: UnitItemType[] = []; + Object.entries(unitItems).forEach(([unit, label]) => { + arr.push({ + value: unit as Unit, + text: Str.recapitalize(label), + keyForList: unit, + isSelected: defaultValue === unit, + }); + }); + return arr; + }, [defaultValue, unitItems]); + + return ( + unit.isSelected)?.keyForList} + /> + ); +} + +export default UnitPicker; + +export type {UnitItemType}; diff --git a/src/languages/en.ts b/src/languages/en.ts index bcfd95426e3c..a3280f4b64ef 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -2005,10 +2005,6 @@ export default { disabled: 'Disabled', unit: 'Unit', defaultCategory: 'Default category', - units: { - MI: 'Miles', - KM: 'Kilometers', - }, }, editor: { descriptionInputLabel: 'Description', diff --git a/src/languages/es.ts b/src/languages/es.ts index 656e754f28a2..6fb7779b4bcc 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -2030,10 +2030,6 @@ export default { disabled: 'Desactivada', unit: 'Unidad', defaultCategory: 'Categoría predeterminada', - units: { - MI: 'Millas', - KM: 'Kilómetros', - }, }, editor: { nameInputLabel: 'Nombre', diff --git a/src/pages/workspace/distanceRates/CategorySelector/CategorySelectorModal.tsx b/src/pages/workspace/distanceRates/CategorySelector/CategorySelectorModal.tsx index d6e0129d039b..b48456ecce79 100644 --- a/src/pages/workspace/distanceRates/CategorySelector/CategorySelectorModal.tsx +++ b/src/pages/workspace/distanceRates/CategorySelector/CategorySelectorModal.tsx @@ -1,18 +1,15 @@ -import React, {useMemo} from 'react'; -import type {OnyxEntry} from 'react-native-onyx'; +import React from 'react'; +import CategoryPicker from '@components/CategoryPicker'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import Modal from '@components/Modal'; import ScreenWrapper from '@components/ScreenWrapper'; -import SelectionList from '@components/SelectionList'; -import RadioListItem from '@components/SelectionList/RadioListItem'; +import type {ListItem} from '@components/SelectionList/types'; import useThemeStyles from '@hooks/useThemeStyles'; import CONST from '@src/CONST'; -import type * as OnyxTypes from '@src/types/onyx'; -import type CategoryItemType from './types'; type CategorySelectorModalProps = { - /** Collection of categories attached to a policy */ - policyCategories: OnyxEntry; + /** The ID of the associated policy */ + policyID: string; /** Whether the modal is visible */ isVisible: boolean; @@ -21,7 +18,7 @@ type CategorySelectorModalProps = { currentCategory: string; /** Function to call when the user selects a category */ - onCategorySelected: (value: CategoryItemType) => void; + onCategorySelected: (value: ListItem) => void; /** Function to call when the user closes the category selector modal */ onClose: () => void; @@ -30,20 +27,9 @@ type CategorySelectorModalProps = { label: string; }; -function CategorySelectorModal({policyCategories, isVisible, currentCategory, onCategorySelected, onClose, label}: CategorySelectorModalProps) { +function CategorySelectorModal({policyID, isVisible, currentCategory, onCategorySelected, onClose, label}: CategorySelectorModalProps) { const styles = useThemeStyles(); - const categories = useMemo( - () => - Object.values(policyCategories ?? {}).map((value) => ({ - value: value.name, - text: value.name, - keyForList: value.name, - isSelected: value.name === currentCategory, - })), - [currentCategory, policyCategories], - ); - return ( - diff --git a/src/pages/workspace/distanceRates/CategorySelector/index.tsx b/src/pages/workspace/distanceRates/CategorySelector/index.tsx index f739e163a47f..f7a1ba49d91e 100644 --- a/src/pages/workspace/distanceRates/CategorySelector/index.tsx +++ b/src/pages/workspace/distanceRates/CategorySelector/index.tsx @@ -1,19 +1,17 @@ import React, {useState} from 'react'; import type {StyleProp, ViewStyle} from 'react-native'; import {View} from 'react-native'; -import type {OnyxEntry} from 'react-native-onyx'; import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription'; +import type {ListItem} from '@components/SelectionList/types'; import useThemeStyles from '@hooks/useThemeStyles'; -import type * as OnyxTypes from '@src/types/onyx'; import CategorySelectorModal from './CategorySelectorModal'; -import type CategoryItemType from './types'; type CategorySelectorProps = { - /** Collection of categories attached to a policy */ - policyCategories: OnyxEntry; + /** The ID of the associated policy */ + policyID: string; /** Function to call when the user selects a category */ - setNewCategory: (value: CategoryItemType) => void; + setNewCategory: (value: ListItem) => void; /** Currently selected category */ defaultValue?: string; @@ -25,7 +23,7 @@ type CategorySelectorProps = { wrapperStyle: StyleProp; }; -function CategorySelector({policyCategories, defaultValue = '', wrapperStyle, label, setNewCategory}: CategorySelectorProps) { +function CategorySelector({defaultValue = '', wrapperStyle, label, setNewCategory, policyID}: CategorySelectorProps) { const styles = useThemeStyles(); const [isPickerVisible, setIsPickerVisible] = useState(false); @@ -38,7 +36,7 @@ function CategorySelector({policyCategories, defaultValue = '', wrapperStyle, la setIsPickerVisible(false); }; - const updateCategoryInput = (categoryItem: CategoryItemType) => { + const updateCategoryInput = (categoryItem: ListItem) => { setNewCategory(categoryItem); hidePickerModal(); }; @@ -57,7 +55,7 @@ function CategorySelector({policyCategories, defaultValue = '', wrapperStyle, la wrapperStyle={wrapperStyle} /> ; - - /** Collection of categories attached to a policy */ - policyCategories: OnyxEntry; }; type PolicyDistanceRatesSettingsPageProps = PolicyDistanceRatesSettingsPageOnyxProps & StackScreenProps; -function PolicyDistanceRatesSettingsPage({policy, policyCategories, route}: PolicyDistanceRatesSettingsPageProps) { +function PolicyDistanceRatesSettingsPage({policy, route}: PolicyDistanceRatesSettingsPageProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); @@ -38,14 +35,14 @@ function PolicyDistanceRatesSettingsPage({policy, policyCategories, route}: Poli const customUnitID = customUnit?.customUnitID ?? ''; const defaultCategory = customUnits[customUnitID].defaultCategory; - const defaultUnit = customUnits[customUnitID].attributes.unit.toUpperCase(); + const defaultUnit = customUnits[customUnitID].attributes.unit; const setNewUnit = (unit: UnitItemType) => { Policy.setPolicyDistanceRatesUnit(policyID, customUnit, {...customUnit, attributes: {unit: unit.value}}); }; - const setNewCategory = (category: CategoryItemType) => { - Policy.setPolicyDistanceRatesDefaultCategory(policyID, customUnit, {...customUnit, defaultCategory: category.value}); + const setNewCategory = (category: ListItem) => { + Policy.setPolicyDistanceRatesDefaultCategory(policyID, customUnit, {...customUnit, defaultCategory: category.text}); }; return ( @@ -65,7 +62,7 @@ function PolicyDistanceRatesSettingsPage({policy, policyCategories, route}: Poli /> {policy?.areCategoriesEnabled && ( `${ONYXKEYS.COLLECTION.POLICY}${route.params.policyID}`, }, - policyCategories: { - key: ({route}) => `${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${route.params.policyID}`, - }, })(PolicyDistanceRatesSettingsPage); diff --git a/src/pages/workspace/distanceRates/UnitSelector/UnitSelectorModal.tsx b/src/pages/workspace/distanceRates/UnitSelector/UnitSelectorModal.tsx index ec5e99778d8a..5a9f5e7c6ea1 100644 --- a/src/pages/workspace/distanceRates/UnitSelector/UnitSelectorModal.tsx +++ b/src/pages/workspace/distanceRates/UnitSelector/UnitSelectorModal.tsx @@ -1,21 +1,19 @@ -import React, {useMemo} from 'react'; +import React from 'react'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import Modal from '@components/Modal'; import ScreenWrapper from '@components/ScreenWrapper'; -import SelectionList from '@components/SelectionList'; -import RadioListItem from '@components/SelectionList/RadioListItem'; -import useLocalize from '@hooks/useLocalize'; +import type {UnitItemType} from '@components/UnitPicker'; +import UnitPicker from '@components/UnitPicker'; import useThemeStyles from '@hooks/useThemeStyles'; import CONST from '@src/CONST'; import type {Unit} from '@src/types/onyx/Policy'; -import type {UnitItemType, UnitType} from './types'; type UnitSelectorModalProps = { /** Whether the modal is visible */ isVisible: boolean; /** Selected unit */ - currentUnit: string; + currentUnit: Unit; /** Function to call when the user selects a unit */ onUnitSelected: (value: UnitItemType) => void; @@ -29,18 +27,6 @@ type UnitSelectorModalProps = { function UnitSelectorModal({isVisible, currentUnit, onUnitSelected, onClose, label}: UnitSelectorModalProps) { const styles = useThemeStyles(); - const {translate} = useLocalize(); - - const units = useMemo( - () => - Object.keys(CONST.POLICY.UNITS).map((key) => ({ - value: key.toLowerCase() as Unit, - text: translate(`workspace.distanceRates.units.${key as UnitType}`), - keyForList: key, - isSelected: key === currentUnit, - })), - [currentUnit, translate], - ); return ( - diff --git a/src/pages/workspace/distanceRates/UnitSelector/index.tsx b/src/pages/workspace/distanceRates/UnitSelector/index.tsx index 8615f101fdda..41ad28d2d644 100644 --- a/src/pages/workspace/distanceRates/UnitSelector/index.tsx +++ b/src/pages/workspace/distanceRates/UnitSelector/index.tsx @@ -1,10 +1,12 @@ -import React, {useState} from 'react'; +import Str from 'expensify-common/lib/str'; +import React, {useMemo, useState} from 'react'; import type {StyleProp, ViewStyle} from 'react-native'; import {View} from 'react-native'; import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription'; +import type {UnitItemType} from '@components/UnitPicker'; import useLocalize from '@hooks/useLocalize'; -import useThemeStyles from '@hooks/useThemeStyles'; -import type {UnitItemType, UnitType} from './types'; +import CONST from '@src/CONST'; +import type {Unit} from '@src/types/onyx/Policy'; import UnitSelectorModal from './UnitSelectorModal'; type UnitSelectorProps = { @@ -12,7 +14,7 @@ type UnitSelectorProps = { setNewUnit: (value: UnitItemType) => void; /** Currently selected unit */ - defaultValue: string; + defaultValue: Unit; /** Label to display on field */ label: string; @@ -21,8 +23,7 @@ type UnitSelectorProps = { wrapperStyle: StyleProp; }; -function UnitSelector({defaultValue = '', wrapperStyle, label, setNewUnit}: UnitSelectorProps) { - const styles = useThemeStyles(); +function UnitSelector({defaultValue, wrapperStyle, label, setNewUnit}: UnitSelectorProps) { const {translate} = useLocalize(); const [isPickerVisible, setIsPickerVisible] = useState(false); @@ -35,21 +36,25 @@ function UnitSelector({defaultValue = '', wrapperStyle, label, setNewUnit}: Unit setIsPickerVisible(false); }; - const updateUnitInput = (UnitItem: UnitItemType) => { - setNewUnit(UnitItem); + const updateUnitInput = (unit: UnitItemType) => { + setNewUnit(unit); hidePickerModal(); }; - const title = defaultValue ? translate(`workspace.distanceRates.units.${defaultValue as UnitType}`) : ''; - const descStyle = title.length === 0 ? styles.textNormal : null; + const unitTranslations = useMemo( + () => ({ + [CONST.CUSTOM_UNITS.DISTANCE_UNIT_KILOMETERS]: translate('common.kilometers'), + [CONST.CUSTOM_UNITS.DISTANCE_UNIT_MILES]: translate('common.miles'), + }), + [translate], + ); return ( diff --git a/src/pages/workspace/distanceRates/UnitSelector/types.ts b/src/pages/workspace/distanceRates/UnitSelector/types.ts deleted file mode 100644 index 98f2af3f48cf..000000000000 --- a/src/pages/workspace/distanceRates/UnitSelector/types.ts +++ /dev/null @@ -1,13 +0,0 @@ -import type CONST from '@src/CONST'; -import type {Unit} from '@src/types/onyx/Policy'; - -type UnitType = keyof typeof CONST.POLICY.UNITS; - -type UnitItemType = { - value: Unit; - text: string; - keyForList: string; - isSelected: boolean; -}; - -export type {UnitType, UnitItemType}; diff --git a/src/pages/workspace/reimburse/WorkspaceRateAndUnitPage/UnitPage.tsx b/src/pages/workspace/reimburse/WorkspaceRateAndUnitPage/UnitPage.tsx index 3bd5a9e01bab..36efc239fe69 100644 --- a/src/pages/workspace/reimburse/WorkspaceRateAndUnitPage/UnitPage.tsx +++ b/src/pages/workspace/reimburse/WorkspaceRateAndUnitPage/UnitPage.tsx @@ -1,9 +1,9 @@ import React, {useEffect, useMemo} from 'react'; import {withOnyx} from 'react-native-onyx'; import type {OnyxEntry} from 'react-native-onyx'; -import SelectionList from '@components/SelectionList'; -import RadioListItem from '@components/SelectionList/RadioListItem'; import Text from '@components/Text'; +import type {UnitItemType} from '@components/UnitPicker'; +import UnitPicker from '@components/UnitPicker'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import compose from '@libs/compose'; @@ -16,14 +16,6 @@ import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type {WorkspaceRateAndUnit} from '@src/types/onyx'; -import type {Unit} from '@src/types/onyx/Policy'; - -type OptionRow = { - value: Unit; - text: string; - keyForList: string; - isSelected: boolean; -}; type WorkspaceUnitPageBaseProps = WithPolicyProps; @@ -35,13 +27,6 @@ type WorkspaceUnitPageProps = WorkspaceUnitPageBaseProps & WorkspaceRateAndUnitO function WorkspaceUnitPage(props: WorkspaceUnitPageProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); - const unitItems = useMemo( - () => ({ - [CONST.CUSTOM_UNITS.DISTANCE_UNIT_KILOMETERS]: translate('workspace.reimburse.kilometers'), - [CONST.CUSTOM_UNITS.DISTANCE_UNIT_MILES]: translate('workspace.reimburse.miles'), - }), - [translate], - ); useEffect(() => { if (props.workspaceRateAndUnit?.policyID === props.policy?.id) { @@ -51,8 +36,8 @@ function WorkspaceUnitPage(props: WorkspaceUnitPageProps) { // eslint-disable-next-line react-hooks/exhaustive-deps }, []); - const updateUnit = (unit: Unit) => { - Policy.setUnitForReimburseView(unit); + const updateUnit = (unit: UnitItemType) => { + Policy.setUnitForReimburseView(unit.value); Navigation.navigate(ROUTES.WORKSPACE_RATE_AND_UNIT.getRoute(props.policy?.id ?? '')); }; @@ -61,20 +46,6 @@ function WorkspaceUnitPage(props: WorkspaceUnitPageProps) { return defaultDistanceCustomUnit?.attributes.unit ?? CONST.CUSTOM_UNITS.DISTANCE_UNIT_MILES; }, [props.policy?.customUnits]); - const unitOptions = useMemo(() => { - const arr: OptionRow[] = []; - Object.entries(unitItems).forEach(([unit, label]) => { - arr.push({ - value: unit as Unit, - text: label, - keyForList: unit, - // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - isSelected: (props.workspaceRateAndUnit?.unit || defaultValue) === unit, - }); - }); - return arr; - }, [defaultValue, props.workspaceRateAndUnit?.unit, unitItems]); - return ( ( <> {translate('workspace.reimburse.trackDistanceChooseUnit')} - - updateUnit(unit.value)} - initiallyFocusedOptionKey={unitOptions.find((unit) => unit.isSelected)?.keyForList} + )} From af86fafa7339329a0b48f6598482d0a222053894 Mon Sep 17 00:00:00 2001 From: Georgia Monahan Date: Tue, 19 Mar 2024 14:14:21 +0000 Subject: [PATCH 156/175] update card data returned to app --- src/types/onyx/Card.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/types/onyx/Card.ts b/src/types/onyx/Card.ts index 68acd88aa120..7d407d698501 100644 --- a/src/types/onyx/Card.ts +++ b/src/types/onyx/Card.ts @@ -11,6 +11,9 @@ type Card = { maskedPan?: string; // do not reference, removing as part of Expensify/App#27943 lastFourPAN?: string; cardName: string; + cardTitle: string; // used only for virtual limit cards + limitType: string; + isAdminIssuedVirtualCard: boolean; isVirtual: boolean; fraud: ValueOf; cardholderFirstName: string; From 56958516d2a5d088964cd185c7a77334619be07b Mon Sep 17 00:00:00 2001 From: Michal Muzyk Date: Tue, 19 Mar 2024 15:20:44 +0100 Subject: [PATCH 157/175] fix: added util to get unit translation --- src/components/UnitPicker.tsx | 26 +++++++------------ src/languages/en.ts | 2 -- src/languages/es.ts | 2 -- src/libs/WorkspacesSettingsUtils.ts | 16 ++++++++++++ .../distanceRates/UnitSelector/index.tsx | 14 +++------- .../WorkspaceRateAndUnitPage/InitialPage.tsx | 15 ++++------- 6 files changed, 35 insertions(+), 40 deletions(-) diff --git a/src/components/UnitPicker.tsx b/src/components/UnitPicker.tsx index 04620a4b72f1..a9202a348e4d 100644 --- a/src/components/UnitPicker.tsx +++ b/src/components/UnitPicker.tsx @@ -1,6 +1,7 @@ import Str from 'expensify-common/lib/str'; import React, {useMemo} from 'react'; import useLocalize from '@hooks/useLocalize'; +import {getUnitTranslationKey} from '@libs/WorkspacesSettingsUtils'; import CONST from '@src/CONST'; import type {Unit} from '@src/types/onyx/Policy'; import SelectionList from './SelectionList'; @@ -18,28 +19,21 @@ type UnitPickerProps = { onOptionSelected: (unit: UnitItemType) => void; }; +const units = [CONST.CUSTOM_UNITS.DISTANCE_UNIT_KILOMETERS, CONST.CUSTOM_UNITS.DISTANCE_UNIT_MILES]; + function UnitPicker({defaultValue, onOptionSelected}: UnitPickerProps) { const {translate} = useLocalize(); - const unitItems = useMemo( - () => ({ - [CONST.CUSTOM_UNITS.DISTANCE_UNIT_KILOMETERS]: translate('common.kilometers'), - [CONST.CUSTOM_UNITS.DISTANCE_UNIT_MILES]: translate('common.miles'), - }), - [translate], - ); - const unitOptions = useMemo(() => { - const arr: UnitItemType[] = []; - Object.entries(unitItems).forEach(([unit, label]) => { - arr.push({ + const unitOptions = useMemo( + () => + units.map((unit) => ({ value: unit as Unit, - text: Str.recapitalize(label), + text: Str.recapitalize(translate(getUnitTranslationKey(unit))), keyForList: unit, isSelected: defaultValue === unit, - }); - }); - return arr; - }, [defaultValue, unitItems]); + })), + [defaultValue, translate], + ); return ( { return workspacesUnreadStatuses; } +/** + * @param unit Unit + * @returns translation key for the unit + */ +function getUnitTranslationKey(unit: Unit): TranslationPaths { + const unitTranslationKeysStrategy: Record = { + [CONST.CUSTOM_UNITS.DISTANCE_UNIT_KILOMETERS]: 'common.kilometers', + [CONST.CUSTOM_UNITS.DISTANCE_UNIT_MILES]: 'common.miles', + }; + + return unitTranslationKeysStrategy[unit]; +} + export { getBrickRoadForPolicy, getWorkspacesBrickRoads, @@ -204,5 +219,6 @@ export { checkIfWorkspaceSettingsTabHasRBR, hasWorkspaceSettingsRBR, getChatTabBrickRoad, + getUnitTranslationKey, }; export type {BrickRoad}; diff --git a/src/pages/workspace/distanceRates/UnitSelector/index.tsx b/src/pages/workspace/distanceRates/UnitSelector/index.tsx index 41ad28d2d644..e6511e7d6418 100644 --- a/src/pages/workspace/distanceRates/UnitSelector/index.tsx +++ b/src/pages/workspace/distanceRates/UnitSelector/index.tsx @@ -1,11 +1,11 @@ import Str from 'expensify-common/lib/str'; -import React, {useMemo, useState} from 'react'; +import React, {useState} from 'react'; import type {StyleProp, ViewStyle} from 'react-native'; import {View} from 'react-native'; import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription'; import type {UnitItemType} from '@components/UnitPicker'; import useLocalize from '@hooks/useLocalize'; -import CONST from '@src/CONST'; +import {getUnitTranslationKey} from '@libs/WorkspacesSettingsUtils'; import type {Unit} from '@src/types/onyx/Policy'; import UnitSelectorModal from './UnitSelectorModal'; @@ -41,19 +41,13 @@ function UnitSelector({defaultValue, wrapperStyle, label, setNewUnit}: UnitSelec hidePickerModal(); }; - const unitTranslations = useMemo( - () => ({ - [CONST.CUSTOM_UNITS.DISTANCE_UNIT_KILOMETERS]: translate('common.kilometers'), - [CONST.CUSTOM_UNITS.DISTANCE_UNIT_MILES]: translate('common.miles'), - }), - [translate], - ); + const title = Str.recapitalize(translate(getUnitTranslationKey(defaultValue))); return ( ({ - [CONST.CUSTOM_UNITS.DISTANCE_UNIT_KILOMETERS]: translate('workspace.reimburse.kilometers'), - [CONST.CUSTOM_UNITS.DISTANCE_UNIT_MILES]: translate('workspace.reimburse.miles'), - }), - [translate], - ); - const saveUnitAndRate = (newUnit: Unit, newRate: string) => { const distanceCustomUnit = Object.values(props.policy?.customUnits ?? {}).find((unit) => unit.name === CONST.CUSTOM_UNITS.NAME_DISTANCE); if (!distanceCustomUnit) { @@ -93,6 +87,7 @@ function WorkspaceRateAndUnitPage(props: WorkspaceRateAndUnitPageProps) { const unitValue = props.workspaceRateAndUnit?.unit ?? distanceCustomUnit?.attributes.unit ?? CONST.CUSTOM_UNITS.DISTANCE_UNIT_MILES; const rateValue = props.workspaceRateAndUnit?.rate ?? distanceCustomRate?.rate?.toString() ?? ''; + const unitTitle = Str.recapitalize(translate(getUnitTranslationKey(unitValue))); const submit = () => { saveUnitAndRate(unitValue, rateValue); @@ -131,7 +126,7 @@ function WorkspaceRateAndUnitPage(props: WorkspaceRateAndUnitPageProps) { /> Navigation.navigate(ROUTES.WORKSPACE_RATE_AND_UNIT_UNIT.getRoute(props.policy?.id ?? ''))} shouldShowRightIcon /> From 82f12926e5132ed0b0af46657f2489d9065b69a6 Mon Sep 17 00:00:00 2001 From: gijoe0295 Date: Tue, 19 Mar 2024 21:23:39 +0700 Subject: [PATCH 158/175] fix: parent category not show selected state --- src/libs/OptionsListUtils.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/libs/OptionsListUtils.ts b/src/libs/OptionsListUtils.ts index ff55343fa762..d6a79c903746 100644 --- a/src/libs/OptionsListUtils.ts +++ b/src/libs/OptionsListUtils.ts @@ -1013,8 +1013,8 @@ function getCategoryListSections( } const selectedOptionNames = selectedOptions.map((selectedOption) => selectedOption.name); - const enabledWithoutSelectedCategories = sortedCategories.filter((category) => category.enabled && !selectedOptionNames.includes(category.name)); - const numberOfVisibleCategories = enabledWithoutSelectedCategories.length + selectedOptions.length; + const filteredCategories = enabledCategories.filter((category) => !selectedOptionNames.includes(category.name)); + const numberOfVisibleCategories = filteredCategories.length + selectedOptionNames.length; if (numberOfVisibleCategories < CONST.CATEGORY_LIST_THRESHOLD) { categorySections.push({ @@ -1022,7 +1022,7 @@ function getCategoryListSections( title: '', shouldShow: false, indexOffset, - data: getCategoryOptionTree(enabledWithoutSelectedCategories), + data: getCategoryOptionTree(filteredCategories, false, selectedOptionNames), }); return categorySections; @@ -1049,8 +1049,6 @@ function getCategoryListSections( indexOffset += filteredRecentlyUsedCategories.length; } - const filteredCategories = enabledCategories.filter((category) => !selectedOptionNames.includes(category.name)); - categorySections.push({ // "All" section when items amount more than the threshold title: Localize.translateLocal('common.all'), From fa54fc57137d0695f5e65f375659a77c08987216 Mon Sep 17 00:00:00 2001 From: Jayesh Mangwani Date: Tue, 19 Mar 2024 19:54:38 +0530 Subject: [PATCH 159/175] fix @ts-expect-error warning --- src/pages/EnablePayments/OnfidoStep.tsx | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/pages/EnablePayments/OnfidoStep.tsx b/src/pages/EnablePayments/OnfidoStep.tsx index 46c6e1c8e6ed..06ad9ca3a922 100644 --- a/src/pages/EnablePayments/OnfidoStep.tsx +++ b/src/pages/EnablePayments/OnfidoStep.tsx @@ -3,8 +3,8 @@ import {withOnyx} from 'react-native-onyx'; import type {OnyxEntry} from 'react-native-onyx'; import FullPageOfflineBlockingView from '@components/BlockingViews/FullPageOfflineBlockingView'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; -// @ts-expect-error TODO: Remove this once Onfido (https://github.com/Expensify/App/issues/25136) is migrated to TypeScript. import Onfido from '@components/Onfido'; +import type {OnfidoData} from '@components/Onfido/types'; import useLocalize from '@hooks/useLocalize'; import Growl from '@libs/Growl'; import Navigation from '@libs/Navigation/Navigation'; @@ -45,8 +45,7 @@ function OnfidoStep({walletOnfidoData = DEFAULT_WALLET_ONFIDO_DATA}: OnfidoStepP }, [translate]); const verifyIdentity = useCallback( - // @ts-expect-error TODO: Remove this once Onfido (https://github.com/Expensify/App/issues/25136) is migrated to TypeScript. - (data) => { + (data: OnfidoData) => { BankAccounts.verifyIdentity({ onfidoData: JSON.stringify({ ...data, @@ -64,7 +63,7 @@ function OnfidoStep({walletOnfidoData = DEFAULT_WALLET_ONFIDO_DATA}: OnfidoStepP onBackButtonPress={goToPreviousStep} /> - {shouldShowOnfido ? ( + {shouldShowOnfido && walletOnfidoData?.sdkToken ? ( Date: Tue, 19 Mar 2024 16:43:56 +0200 Subject: [PATCH 160/175] use markdown for default --- src/pages/workspace/WorkspaceProfileDescriptionPage.tsx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/pages/workspace/WorkspaceProfileDescriptionPage.tsx b/src/pages/workspace/WorkspaceProfileDescriptionPage.tsx index f31ebfc85dcc..bd8ec5b03f05 100644 --- a/src/pages/workspace/WorkspaceProfileDescriptionPage.tsx +++ b/src/pages/workspace/WorkspaceProfileDescriptionPage.tsx @@ -31,9 +31,11 @@ function WorkspaceProfileDescriptionPage({policy}: Props) { // policy?.description can be an empty string // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing policy?.description || - translate('workspace.common.welcomeNote', { - workspaceName: policy?.name ?? '', - }), + parser.replace( + translate('workspace.common.welcomeNote', { + workspaceName: policy?.name ?? '', + }), + ), ), ); From b95b8dff83de2584440b95de2b3fe3bf9f01edee Mon Sep 17 00:00:00 2001 From: Jayesh Mangwani Date: Tue, 19 Mar 2024 20:22:28 +0530 Subject: [PATCH 161/175] added a empty string instead doublechecking walletOnfidoData.sdkToken --- src/pages/EnablePayments/OnfidoStep.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/EnablePayments/OnfidoStep.tsx b/src/pages/EnablePayments/OnfidoStep.tsx index 06ad9ca3a922..f5a600cc8548 100644 --- a/src/pages/EnablePayments/OnfidoStep.tsx +++ b/src/pages/EnablePayments/OnfidoStep.tsx @@ -63,9 +63,9 @@ function OnfidoStep({walletOnfidoData = DEFAULT_WALLET_ONFIDO_DATA}: OnfidoStepP onBackButtonPress={goToPreviousStep} /> - {shouldShowOnfido && walletOnfidoData?.sdkToken ? ( + {shouldShowOnfido ? ( Date: Tue, 19 Mar 2024 15:11:42 +0000 Subject: [PATCH 162/175] specify the limit types --- src/CONST.ts | 5 +++++ src/types/onyx/Card.ts | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/CONST.ts b/src/CONST.ts index 132b49c16ef7..ced44f211f0e 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -1527,6 +1527,11 @@ const CONST = { STATE_SUSPENDED: 7, }, ACTIVE_STATES: cardActiveStates, + LIMIT_TYPES: { + SMART: "smart", + MONTHLY: "monthly", + FIXED: "fixed", + } }, AVATAR_ROW_SIZE: { DEFAULT: 4, diff --git a/src/types/onyx/Card.ts b/src/types/onyx/Card.ts index 7d407d698501..53415690705a 100644 --- a/src/types/onyx/Card.ts +++ b/src/types/onyx/Card.ts @@ -12,7 +12,7 @@ type Card = { lastFourPAN?: string; cardName: string; cardTitle: string; // used only for virtual limit cards - limitType: string; + limitType: ValueOf; isAdminIssuedVirtualCard: boolean; isVirtual: boolean; fraud: ValueOf; From 02e9db25fd990c1a1144ab489d5068c523ff1bda Mon Sep 17 00:00:00 2001 From: Georgia Monahan Date: Tue, 19 Mar 2024 15:16:34 +0000 Subject: [PATCH 163/175] prettier --- src/CONST.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/CONST.ts b/src/CONST.ts index 2f63f7c7fb92..360f8ad4348a 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -1532,10 +1532,10 @@ const CONST = { }, ACTIVE_STATES: cardActiveStates, LIMIT_TYPES: { - SMART: "smart", - MONTHLY: "monthly", - FIXED: "fixed", - } + SMART: 'smart', + MONTHLY: 'monthly', + FIXED: 'fixed', + }, }, AVATAR_ROW_SIZE: { DEFAULT: 4, From 24682f5a183ece27aedb296753c52f0acf66b4ad Mon Sep 17 00:00:00 2001 From: Artem Makushov Date: Tue, 19 Mar 2024 16:23:00 +0100 Subject: [PATCH 164/175] fixing decoding and encoding --- src/ROUTES.ts | 4 ++-- src/libs/Navigation/linkingConfig/config.ts | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 82be3886d2c2..5eda71fb34d4 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -578,11 +578,11 @@ const ROUTES = { }, WORKSPACE_TAG_EDIT: { route: 'settings/workspace/:policyID/tag/:tagName/edit', - getRoute: (policyID: string, tagName: string) => `settings/workspace/${policyID}/tag/${decodeURIComponent(tagName)}/edit` as const, + getRoute: (policyID: string, tagName: string) => `settings/workspace/${policyID}/tag/${encodeURIComponent(tagName)}/edit` as const, }, WORKSPACE_TAG_SETTINGS: { route: 'settings/workspaces/:policyID/tag/:tagName', - getRoute: (policyID: string, tagName: string) => `settings/workspaces/${policyID}/tag/${decodeURIComponent(tagName)}` as const, + getRoute: (policyID: string, tagName: string) => `settings/workspaces/${policyID}/tag/${encodeURIComponent(tagName)}` as const, }, WORKSPACE_TAXES: { route: 'settings/workspaces/:policyID/taxes', diff --git a/src/libs/Navigation/linkingConfig/config.ts b/src/libs/Navigation/linkingConfig/config.ts index 2f515c5f090a..053975e83f46 100644 --- a/src/libs/Navigation/linkingConfig/config.ts +++ b/src/libs/Navigation/linkingConfig/config.ts @@ -303,6 +303,9 @@ const config: LinkingOptions['config'] = { }, [SCREENS.WORKSPACE.TAG_EDIT]: { path: ROUTES.WORKSPACE_TAG_EDIT.route, + parse: { + tagName: (tagName: string) => decodeURIComponent(tagName), + }, }, [SCREENS.WORKSPACE.TAG_SETTINGS]: { path: ROUTES.WORKSPACE_TAG_SETTINGS.route, From 152853a482578cf82e5ba42717a1621a4e4c275a Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Tue, 19 Mar 2024 09:29:51 -0600 Subject: [PATCH 165/175] use correct api command --- src/libs/API/types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/API/types.ts b/src/libs/API/types.ts index 132fbc60b967..6cb9da922001 100644 --- a/src/libs/API/types.ts +++ b/src/libs/API/types.ts @@ -126,7 +126,7 @@ const WRITE_COMMANDS = { DELETE_WORKSPACE_CATEGORIES: 'DeleteWorkspaceCategories', SET_POLICY_REQUIRES_TAG: 'SetPolicyRequiresTag', RENAME_POLICY_TAG_LIST: 'RenamePolicyTaglist', - DELETE_POLICY_TAGS: 'Policy_IndependentTaglist_Tags_Remove', + DELETE_POLICY_TAGS: 'DeletePolicyTags', CREATE_TASK: 'CreateTask', CANCEL_TASK: 'CancelTask', EDIT_TASK_ASSIGNEE: 'EditTaskAssignee', From 996d67d7dd5677c00c40c3936239284b45a73d26 Mon Sep 17 00:00:00 2001 From: Nicolay Arefyeu Date: Tue, 19 Mar 2024 17:37:13 +0200 Subject: [PATCH 166/175] Fix custom button for Continue Bank Account setup --- src/pages/ReimbursementAccount/ContinueBankAccountSetup.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/pages/ReimbursementAccount/ContinueBankAccountSetup.js b/src/pages/ReimbursementAccount/ContinueBankAccountSetup.js index 5d5fa080ff92..6ce8356e7273 100644 --- a/src/pages/ReimbursementAccount/ContinueBankAccountSetup.js +++ b/src/pages/ReimbursementAccount/ContinueBankAccountSetup.js @@ -65,12 +65,13 @@ function ContinueBankAccountSetup(props) { > {props.translate('workspace.bankAccount.youreAlmostDone')}