From f091ba12e14d9104bc4db858ac332b54fd21c502 Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Wed, 19 Jul 2023 15:41:51 -1000 Subject: [PATCH 001/237] Refactor HeaderGap --- src/components/HeaderGap/index.desktop.js | 11 ++++++----- src/components/HeaderGap/index.js | 11 +++++------ 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/components/HeaderGap/index.desktop.js b/src/components/HeaderGap/index.desktop.js index 10974aa9f5ee..2c6e81da8818 100644 --- a/src/components/HeaderGap/index.desktop.js +++ b/src/components/HeaderGap/index.desktop.js @@ -1,9 +1,10 @@ -import React, {PureComponent} from 'react'; +import React from 'react'; import {View} from 'react-native'; import styles from '../../styles/styles'; -export default class HeaderGap extends PureComponent { - render() { - return ; - } +function HeaderGap() { + return ; } + +HeaderGap.displayName = 'HeaderGap'; +export default HeaderGap; diff --git a/src/components/HeaderGap/index.js b/src/components/HeaderGap/index.js index ca81056d5f7a..35e6bf92fb5d 100644 --- a/src/components/HeaderGap/index.js +++ b/src/components/HeaderGap/index.js @@ -1,7 +1,6 @@ -import {PureComponent} from 'react'; - -export default class HeaderGap extends PureComponent { - render() { - return null; - } +function HeaderGap() { + return null; } + +HeaderGap.displayName = 'HeaderGap'; +export default HeaderGap; From 4986bbf0cc7ce192efaec95824f1bd505a2d9aff Mon Sep 17 00:00:00 2001 From: tienifr Date: Thu, 7 Sep 2023 19:38:53 +0700 Subject: [PATCH 002/237] fix: 26762 --- src/libs/actions/Task.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libs/actions/Task.js b/src/libs/actions/Task.js index 6227686b3f45..3f29730cbc30 100644 --- a/src/libs/actions/Task.js +++ b/src/libs/actions/Task.js @@ -529,6 +529,7 @@ function editTaskAssigneeAndNavigate(report, ownerAccountID, assigneeEmail, assi reportName, managerID: assigneeAccountID || report.managerID, managerEmail: assigneeEmail || report.managerEmail, + notificationPreference: [assigneeAccountID, ownerAccountID].includes(currentUserAccountID) ? CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS : CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN, }, }, ]; From fda078116081fe005cda01c9148ab205478c1f7a Mon Sep 17 00:00:00 2001 From: tienifr Date: Wed, 20 Sep 2023 18:03:05 +0700 Subject: [PATCH 003/237] fix lint --- src/libs/actions/Task.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libs/actions/Task.js b/src/libs/actions/Task.js index 1ed1d35449f8..50f524809202 100644 --- a/src/libs/actions/Task.js +++ b/src/libs/actions/Task.js @@ -520,7 +520,9 @@ function editTaskAssigneeAndNavigate(report, ownerAccountID, assigneeEmail, assi reportName, managerID: assigneeAccountID || report.managerID, managerEmail: assigneeEmail || report.managerEmail, - notificationPreference: [assigneeAccountID, ownerAccountID].includes(currentUserAccountID) ? CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS : CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN, + notificationPreference: [assigneeAccountID, ownerAccountID].includes(currentUserAccountID) + ? CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS + : CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN, }, }, ]; From c59b47d41d31d93751ec6c32f0f90f46b77b4c19 Mon Sep 17 00:00:00 2001 From: keisyrzk Date: Thu, 28 Sep 2023 14:59:58 +0200 Subject: [PATCH 004/237] updated to function componenet --- ios/Podfile.lock | 6 +- src/components/AvatarWithImagePicker.js | 289 ++++++++++-------------- 2 files changed, 123 insertions(+), 172 deletions(-) diff --git a/ios/Podfile.lock b/ios/Podfile.lock index ba53d939e46c..747efb5f2fa7 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -783,7 +783,7 @@ PODS: - React-Core - RNReactNativeHapticFeedback (1.14.0): - React-Core - - RNReanimated (3.5.4): + - RNReanimated (3.4.0): - DoubleConversion - FBLazyVector - glog @@ -1298,7 +1298,7 @@ SPEC CHECKSUMS: rnmapbox-maps: 6f638ec002aa6e906a6f766d69cd45f968d98e64 RNPermissions: dcdb7b99796bbeda6975a6e79ad519c41b251b1c RNReactNativeHapticFeedback: 1e3efeca9628ff9876ee7cdd9edec1b336913f8c - RNReanimated: ab2e96c6d5591c3dfbb38a464f54c8d17fb34a87 + RNReanimated: 020859659f64be2d30849a1fe88c821a7c3e0cbf RNScreens: d037903436160a4b039d32606668350d2a808806 RNSVG: ed492aaf3af9ca01bc945f7a149d76d62e73ec82 SDWebImage: a7f831e1a65eb5e285e3fb046a23fcfbf08e696d @@ -1311,4 +1311,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: 2daf34c870819a933f3fefe426801d54b2ff2a14 -COCOAPODS: 1.12.1 +COCOAPODS: 1.13.0 diff --git a/src/components/AvatarWithImagePicker.js b/src/components/AvatarWithImagePicker.js index a44d1841bbb6..4459ad892877 100644 --- a/src/components/AvatarWithImagePicker.js +++ b/src/components/AvatarWithImagePicker.js @@ -1,6 +1,6 @@ import _ from 'underscore'; -import React from 'react'; -import {View} from 'react-native'; +import React, { useState, useRef, useEffect } from 'react'; +import { View } from 'react-native'; import PropTypes from 'prop-types'; import lodashGet from 'lodash/get'; import Avatar from './Avatar'; @@ -116,166 +116,118 @@ const defaultProps = { originalFileName: '', }; -class AvatarWithImagePicker extends React.Component { - constructor(props) { - super(props); - this.animation = new SpinningIndicatorAnimation(); - this.setError = this.setError.bind(this); - this.isValidSize = this.isValidSize.bind(this); - this.showAvatarCropModal = this.showAvatarCropModal.bind(this); - this.hideAvatarCropModal = this.hideAvatarCropModal.bind(this); - this.state = { - isMenuVisible: false, - validationError: null, - phraseParam: {}, - isAvatarCropModalOpen: false, - imageName: '', - imageUri: '', - imageType: '', +function AvatarWithImagePicker(props) { + const animation = new SpinningIndicatorAnimation(); + const [isMenuVisible, setIsMenuVisible] = useState(false); + const [validationError, setValidationError] = useState(null); + const [phraseParam, setPhraseParam] = useState({}); + const [isAvatarCropModalOpen, setIsAvatarCropModalOpen] = useState(false); + const [imageName, setImageName] = useState(''); + const [imageUri, setImageUri] = useState(''); + const [imageType, setImageType] = useState(''); + const anchorRef = useRef(); + + useEffect(() => { + if (props.isUploading) { + animation.start(); + } + + return () => { + animation.stop(); }; - this.anchorRef = React.createRef(); - } + }, [props.isUploading]); - componentDidMount() { - if (!this.props.isUploading) { - return; + useEffect(() => { + if (!props.isFocused) { + setError(null, {}); } + }, [props.isFocused]); - this.animation.start(); - } + const setError = (error, phraseParam) => { + setValidationError(error); + setPhraseParam(phraseParam); + }; - componentDidUpdate(prevProps) { - if (!prevProps.isFocused && this.props.isFocused) { - this.setError(null, {}); - } - if (!prevProps.isUploading && this.props.isUploading) { - this.animation.start(); - } else if (prevProps.isUploading && !this.props.isUploading) { - this.animation.stop(); - } - } - - componentWillUnmount() { - this.animation.stop(); - } - - /** - * @param {String} error - * @param {Object} phraseParam - */ - setError(error, phraseParam) { - this.setState({validationError: error, phraseParam}); - } - - /** - * Check if the attachment extension is allowed. - * - * @param {Object} image - * @returns {Boolean} - */ - isValidExtension(image) { - const {fileExtension} = FileUtils.splitExtensionFromFileName(lodashGet(image, 'name', '')); + const isValidExtension = (image) => { + const { fileExtension } = FileUtils.splitExtensionFromFileName(lodashGet(image, 'name', '')); return _.contains(CONST.AVATAR_ALLOWED_EXTENSIONS, fileExtension.toLowerCase()); - } - - /** - * Check if the attachment size is less than allowed size. - * - * @param {Object} image - * @returns {Boolean} - */ - isValidSize(image) { + }; + + const isValidSize = (image) => { return image && lodashGet(image, 'size', 0) < CONST.AVATAR_MAX_ATTACHMENT_SIZE; - } - - /** - * Check if the attachment resolution matches constraints. - * - * @param {Object} image - * @returns {Promise} - */ - isValidResolution(image) { - return getImageResolution(image).then( - (resolution) => - resolution.height >= CONST.AVATAR_MIN_HEIGHT_PX && - resolution.width >= CONST.AVATAR_MIN_WIDTH_PX && - resolution.height <= CONST.AVATAR_MAX_HEIGHT_PX && - resolution.width <= CONST.AVATAR_MAX_WIDTH_PX, - ); - } - - /** - * Validates if an image has a valid resolution and opens an avatar crop modal - * - * @param {Object} image - */ - showAvatarCropModal(image) { - if (!this.isValidExtension(image)) { - this.setError('avatarWithImagePicker.notAllowedExtension', {allowedExtensions: CONST.AVATAR_ALLOWED_EXTENSIONS}); + }; + + const isValidResolution = async (image) => { + const resolution = await getImageResolution(image); + return resolution.height >= CONST.AVATAR_MIN_HEIGHT_PX && + resolution.width >= CONST.AVATAR_MIN_WIDTH_PX && + resolution.height <= CONST.AVATAR_MAX_HEIGHT_PX && + resolution.width <= CONST.AVATAR_MAX_WIDTH_PX; + }; + + const showAvatarCropModal = async (image) => { + if (!isValidExtension(image)) { + setError('avatarWithImagePicker.notAllowedExtension', { allowedExtensions: CONST.AVATAR_ALLOWED_EXTENSIONS }); return; } - if (!this.isValidSize(image)) { - this.setError('avatarWithImagePicker.sizeExceeded', {maxUploadSizeInMB: CONST.AVATAR_MAX_ATTACHMENT_SIZE / (1024 * 1024)}); + if (!isValidSize(image)) { + setError('avatarWithImagePicker.sizeExceeded', { maxUploadSizeInMB: CONST.AVATAR_MAX_ATTACHMENT_SIZE / (1024 * 1024) }); return; } - this.isValidResolution(image).then((isValidResolution) => { - if (!isValidResolution) { - this.setError('avatarWithImagePicker.resolutionConstraints', { - minHeightInPx: CONST.AVATAR_MIN_HEIGHT_PX, - minWidthInPx: CONST.AVATAR_MIN_WIDTH_PX, - maxHeightInPx: CONST.AVATAR_MAX_HEIGHT_PX, - maxWidthInPx: CONST.AVATAR_MAX_WIDTH_PX, - }); - return; - } - - this.setState({ - isAvatarCropModalOpen: true, - validationError: null, - phraseParam: {}, - isMenuVisible: false, - imageUri: image.uri, - imageName: image.name, - imageType: image.type, + const isValidRes = await isValidResolution(image); + if (!isValidRes) { + setError('avatarWithImagePicker.resolutionConstraints', { + minHeightInPx: CONST.AVATAR_MIN_HEIGHT_PX, + minWidthInPx: CONST.AVATAR_MIN_WIDTH_PX, + maxHeightInPx: CONST.AVATAR_MAX_HEIGHT_PX, + maxWidthInPx: CONST.AVATAR_MAX_WIDTH_PX, }); - }); - } - - hideAvatarCropModal() { - this.setState({isAvatarCropModalOpen: false}); - } - - render() { - const DefaultAvatar = this.props.DefaultAvatar; - const additionalStyles = _.isArray(this.props.style) ? this.props.style : [this.props.style]; + return; + } - return ( - - + setIsAvatarCropModalOpen(true); + setValidationError(null); + setPhraseParam({}); + setIsMenuVisible(false); + setImageUri(image.uri); + setImageName(image.name); + setImageType(image.type); + }; + + const hideAvatarCropModal = () => { + setIsAvatarCropModalOpen(false); + }; + + const DefaultAvatar = props.DefaultAvatar; + const additionalStyles = _.isArray(props.style) ? props.style : [props.style]; + + return ( + + - + this.setState((prev) => ({isMenuVisible: !prev.isMenuVisible}))} + onPress={() => setIsMenuVisible(prev => !prev)} accessibilityRole={CONST.ACCESSIBILITY_ROLE.IMAGEBUTTON} - accessibilityLabel={this.props.translate('avatarWithImagePicker.editImage')} - disabled={this.state.isAvatarCropModalOpen} - ref={this.anchorRef} + accessibilityLabel={props.translate('avatarWithImagePicker.editImage')} + disabled={isAvatarCropModalOpen} + ref={anchorRef} > - {this.props.source ? ( + {props.source ? ( ) : ( @@ -293,10 +245,10 @@ class AvatarWithImagePicker extends React.Component { {({show}) => ( @@ -304,55 +256,55 @@ class AvatarWithImagePicker extends React.Component { const menuItems = [ { icon: Expensicons.Upload, - text: this.props.translate('avatarWithImagePicker.uploadPhoto'), + text: props.translate('avatarWithImagePicker.uploadPhoto'), onSelected: () => { if (Browser.isSafari()) { return; } openPicker({ - onPicked: this.showAvatarCropModal, + onPicked: showAvatarCropModal, }); }, }, ]; // If current avatar isn't a default avatar, allow Remove Photo option - if (!this.props.isUsingDefaultAvatar) { + if (!props.isUsingDefaultAvatar) { menuItems.push({ icon: Expensicons.Trashcan, - text: this.props.translate('avatarWithImagePicker.removePhoto'), + text: props.translate('avatarWithImagePicker.removePhoto'), onSelected: () => { - this.setError(null, {}); - this.props.onImageRemoved(); + setError(null, {}); + props.onImageRemoved(); }, }); menuItems.push({ icon: Expensicons.Eye, - text: this.props.translate('avatarWithImagePicker.viewPhoto'), + text: props.translate('avatarWithImagePicker.viewPhoto'), onSelected: () => show(), }); } return ( this.setState({isMenuVisible: false})} + isVisible={isMenuVisible} + onClose={() => setIsMenuVisible(false)} onItemSelected={(item, index) => { - this.setState({isMenuVisible: false}); + setIsMenuVisible(false); // In order for the file picker to open dynamically, the click // function must be called from within a event handler that was initiated // by the user on Safari. if (index === 0 && Browser.isSafari()) { openPicker({ - onPicked: this.showAvatarCropModal, + onPicked: showAvatarCropModal, }); } }} menuItems={menuItems} - anchorPosition={this.props.anchorPosition} + anchorPosition={props.anchorPosition} withoutOverlay - anchorRef={this.anchorRef} - anchorAlignment={this.props.anchorAlignment} + anchorRef={anchorRef} + anchorAlignment={props.anchorAlignment} /> ); }} @@ -360,25 +312,24 @@ class AvatarWithImagePicker extends React.Component { )} - {this.state.validationError && ( + {validationError && ( )} - - ); - } + + ); } AvatarWithImagePicker.propTypes = propTypes; From 0989000c8dc4736b0c21237bf13940f7ed33fc40 Mon Sep 17 00:00:00 2001 From: Kacper Falat Date: Fri, 29 Sep 2023 10:33:40 +0200 Subject: [PATCH 005/237] Migrated fileDownload lib to TypeScript. --- .../{FileUtils.js => FileUtils.ts} | 86 ++++++++----------- ...mentDetails.js => getAttachmentDetails.ts} | 10 +-- ...native.js => getImageResolution.native.ts} | 9 +- ...ageResolution.js => getImageResolution.ts} | 13 +-- .../{index.android.js => index.android.ts} | 33 ++++--- .../{index.ios.js => index.ios.ts} | 53 ++++++------ src/libs/fileDownload/{index.js => index.ts} | 13 ++- src/libs/fileDownload/types.ts | 9 ++ src/types/global.d.ts | 11 +++ 9 files changed, 118 insertions(+), 119 deletions(-) rename src/libs/fileDownload/{FileUtils.js => FileUtils.ts} (70%) rename src/libs/fileDownload/{getAttachmentDetails.js => getAttachmentDetails.ts} (90%) rename src/libs/fileDownload/{getImageResolution.native.js => getImageResolution.native.ts} (59%) rename src/libs/fileDownload/{getImageResolution.js => getImageResolution.ts} (79%) rename src/libs/fileDownload/{index.android.js => index.android.ts} (82%) rename src/libs/fileDownload/{index.ios.js => index.ios.ts} (72%) rename src/libs/fileDownload/{index.js => index.ts} (85%) create mode 100644 src/libs/fileDownload/types.ts diff --git a/src/libs/fileDownload/FileUtils.js b/src/libs/fileDownload/FileUtils.ts similarity index 70% rename from src/libs/fileDownload/FileUtils.js rename to src/libs/fileDownload/FileUtils.ts index cee2b8877ef6..bb24d398273e 100644 --- a/src/libs/fileDownload/FileUtils.js +++ b/src/libs/fileDownload/FileUtils.ts @@ -2,6 +2,7 @@ import {Alert, Linking, Platform} from 'react-native'; import CONST from '../../CONST'; import * as Localize from '../Localize'; import DateUtils from '../DateUtils'; +import {ReadFileAsync, SplitExtensionFromFileName} from './types'; /** * Show alert on successful attachment download @@ -43,49 +44,45 @@ function showPermissionErrorAlert() { }, { text: Localize.translateLocal('common.settings'), - onPress: () => Linking.openSettings(), + onPress: () => { + Linking.openSettings(); + }, }, ]); } /** * Generate a random file name with timestamp and file extension - * @param {String} url - * @returns {String} */ -function getAttachmentName(url) { +function getAttachmentName(url: string): string { if (!url) { return ''; } - return `${DateUtils.getDBTime()}.${url.split(/[#?]/)[0].split('.').pop().trim()}`; + return `${DateUtils.getDBTime()}.${url.split(/[#?]/)[0].split('.').pop()?.trim()}`; } -/** - * @param {String} fileName - * @returns {Boolean} - */ -function isImage(fileName) { +function isImage(fileName: string): boolean { return CONST.FILE_TYPE_REGEX.IMAGE.test(fileName); } -/** - * @param {String} fileName - * @returns {Boolean} - */ -function isVideo(fileName) { +function isVideo(fileName: string): boolean { return CONST.FILE_TYPE_REGEX.VIDEO.test(fileName); } /** * Returns file type based on the uri - * @param {String} fileUrl - * @returns {String} */ -function getFileType(fileUrl) { +function getFileType(fileUrl: string): string | undefined { if (!fileUrl) { return; } - const fileName = fileUrl.split('/').pop().split('?')[0].split('#')[0]; + + const fileName = fileUrl.split('/').pop()?.split('?')[0].split('#')[0]; + + if (!fileName) { + return; + } + if (isImage(fileName)) { return CONST.ATTACHMENT_FILE_TYPE.IMAGE; } @@ -97,32 +94,22 @@ function getFileType(fileUrl) { /** * Returns the filename split into fileName and fileExtension - * - * @param {String} fullFileName - * @returns {Object} */ -function splitExtensionFromFileName(fullFileName) { +const splitExtensionFromFileName: SplitExtensionFromFileName = (fullFileName: string) => { const fileName = fullFileName.trim(); const splitFileName = fileName.split('.'); const fileExtension = splitFileName.length > 1 ? splitFileName.pop() : ''; - return {fileName: splitFileName.join('.'), fileExtension}; -} + return {fileName: splitFileName.join('.'), fileExtension: fileExtension ?? ''}; +}; /** * Returns the filename replacing special characters with underscore - * - * @param {String} fileName - * @returns {String} */ -function cleanFileName(fileName) { +function cleanFileName(fileName: string): string { return fileName.replace(/[^a-zA-Z0-9\-._]/g, '_'); } -/** - * @param {String} fileName - * @returns {String} - */ -function appendTimeToFileName(fileName) { +function appendTimeToFileName(fileName: string): string { const file = splitExtensionFromFileName(fileName); let newFileName = `${file.fileName}-${DateUtils.getDBTime()}`; // Replace illegal characters before trying to download the attachment. @@ -135,18 +122,13 @@ function appendTimeToFileName(fileName) { /** * Reads a locally uploaded file - * - * @param {String} path - the blob url of the locally uplodaded file - * @param {String} fileName - * @returns {Promise} */ -const readFileAsync = (path, fileName) => +const readFileAsync: ReadFileAsync = (path, fileName) => new Promise((resolve) => { if (!path) { resolve(); } - - return fetch(path) + fetch(path) .then((res) => { // For some reason, fetch is "Unable to read uploaded file" // on Android even though the blob is returned, so we'll ignore @@ -154,15 +136,19 @@ const readFileAsync = (path, fileName) => if (!res.ok && Platform.OS !== 'android') { throw Error(res.statusText); } - return res.blob(); - }) - .then((blob) => { - const file = new File([blob], cleanFileName(fileName)); - file.source = path; - // For some reason, the File object on iOS does not have a uri property - // so images aren't uploaded correctly to the backend - file.uri = path; - resolve(file); + res.blob() + .then((blob) => { + const file = new File([blob], cleanFileName(fileName)); + file.source = path; + // For some reason, the File object on iOS does not have a uri property + // so images aren't uploaded correctly to the backend + file.uri = path; + resolve(file); + }) + .catch((e) => { + console.debug('[FileUtils] Could not read uploaded file', e); + resolve(); + }); }) .catch((e) => { console.debug('[FileUtils] Could not read uploaded file', e); diff --git a/src/libs/fileDownload/getAttachmentDetails.js b/src/libs/fileDownload/getAttachmentDetails.ts similarity index 90% rename from src/libs/fileDownload/getAttachmentDetails.js rename to src/libs/fileDownload/getAttachmentDetails.ts index 72cbad115681..2795c0d39497 100644 --- a/src/libs/fileDownload/getAttachmentDetails.js +++ b/src/libs/fileDownload/getAttachmentDetails.ts @@ -3,10 +3,8 @@ import tryResolveUrlFromApiRoot from '../tryResolveUrlFromApiRoot'; /** * Extract the thumbnail URL, source URL and the original filename from the HTML. - * @param {String} html - * @returns {Object} */ -export default function getAttachmentDetails(html) { +export default function getAttachmentDetails(html: string): unknown { // Files can be rendered either as anchor tag or as an image so based on that we have to form regex. const IS_IMAGE_TAG = //i.test(html); const PREVIEW_SOURCE_REGEX = new RegExp(`${CONST.ATTACHMENT_PREVIEW_ATTRIBUTE}*=*"(.+?)"`, 'i'); @@ -21,10 +19,10 @@ export default function getAttachmentDetails(html) { } // Files created/uploaded/hosted by App should resolve from API ROOT. Other URLs aren't modified - const sourceURL = tryResolveUrlFromApiRoot(html.match(SOURCE_REGEX)[1]); - const imageURL = IS_IMAGE_TAG && tryResolveUrlFromApiRoot(html.match(PREVIEW_SOURCE_REGEX)[1]); + const sourceURL = tryResolveUrlFromApiRoot(html.match(SOURCE_REGEX)?.[1] ?? ''); + const imageURL = IS_IMAGE_TAG && tryResolveUrlFromApiRoot(html.match(PREVIEW_SOURCE_REGEX)?.[1] ?? ''); const previewSourceURL = IS_IMAGE_TAG ? imageURL : sourceURL; - const originalFileName = html.match(ORIGINAL_FILENAME_REGEX)[1]; + const originalFileName = html.match(ORIGINAL_FILENAME_REGEX)?.[1] ?? null; // Update the image URL so the images can be accessed depending on the config environment return { diff --git a/src/libs/fileDownload/getImageResolution.native.js b/src/libs/fileDownload/getImageResolution.native.ts similarity index 59% rename from src/libs/fileDownload/getImageResolution.native.js rename to src/libs/fileDownload/getImageResolution.native.ts index f291886f4665..6ec08826344d 100644 --- a/src/libs/fileDownload/getImageResolution.native.js +++ b/src/libs/fileDownload/getImageResolution.native.ts @@ -1,14 +1,13 @@ +import {Asset} from 'react-native-image-picker'; +import {GetImageResolution} from './types'; + /** * Get image resolution * Image object is returned as a result of a user selecting image using the react-native-image-picker * Image already has width and height properties coming from library so we just need to return them on native * Opposite to web where we need to create a new Image object and get dimensions from it * - * @param {*} file Picked file blob - * @returns {Promise} */ -function getImageResolution(file) { - return Promise.resolve({width: file.width, height: file.height}); -} +const getImageResolution: GetImageResolution = (file: Asset | File) => Promise.resolve({width: (file as Asset).width ?? 0, height: (file as Asset).height ?? 0}); export default getImageResolution; diff --git a/src/libs/fileDownload/getImageResolution.js b/src/libs/fileDownload/getImageResolution.ts similarity index 79% rename from src/libs/fileDownload/getImageResolution.js rename to src/libs/fileDownload/getImageResolution.ts index 2f9a6d4fbdb4..44718710a3fb 100644 --- a/src/libs/fileDownload/getImageResolution.js +++ b/src/libs/fileDownload/getImageResolution.ts @@ -1,3 +1,6 @@ +import {Asset} from 'react-native-image-picker'; +import {GetImageResolution} from './types'; + /** * Get image resolution * File object is returned as a result of a user selecting image using the @@ -7,10 +10,8 @@ * new Image() is used specifically for performance reasons, opposed to using FileReader (5ms vs +100ms) * because FileReader is slow and causes a noticeable delay in the UI when selecting an image. * - * @param {*} file Picked file blob - * @returns {Promise} */ -function getImageResolution(file) { +const getImageResolution: GetImageResolution = (file: File | Asset) => { if (!(file instanceof File)) { return Promise.reject(new Error('Object is not an instance of File')); } @@ -20,14 +21,14 @@ function getImageResolution(file) { const objectUrl = URL.createObjectURL(file); image.onload = function () { resolve({ - width: this.naturalWidth, - height: this.naturalHeight, + width: image.naturalWidth, + height: image.naturalHeight, }); URL.revokeObjectURL(objectUrl); }; image.onerror = reject; image.src = objectUrl; }); -} +}; export default getImageResolution; diff --git a/src/libs/fileDownload/index.android.js b/src/libs/fileDownload/index.android.ts similarity index 82% rename from src/libs/fileDownload/index.android.js rename to src/libs/fileDownload/index.android.ts index c3528b579f67..67d0664ae8d4 100644 --- a/src/libs/fileDownload/index.android.js +++ b/src/libs/fileDownload/index.android.ts @@ -1,15 +1,15 @@ import {PermissionsAndroid, Platform} from 'react-native'; -import RNFetchBlob from 'react-native-blob-util'; +import RNFetchBlob, {FetchBlobResponse, StatefulPromise} from 'react-native-blob-util'; import * as FileUtils from './FileUtils'; +import {FileDownload} from './types'; /** * Android permission check to store images - * @returns {Promise} */ -function hasAndroidPermission() { +function hasAndroidPermission(): Promise { // On Android API Level 33 and above, these permissions do nothing and always return 'never_ask_again' // More info here: https://stackoverflow.com/a/74296799 - if (Platform.Version >= 33) { + if ((Platform.Version as number) >= 33) { return Promise.resolve(true); } @@ -31,11 +31,8 @@ function hasAndroidPermission() { /** * Handling the download - * @param {String} url - * @param {String} fileName - * @returns {Promise} */ -function handleDownload(url, fileName) { +function handleDownload(url: string, fileName: string): Promise { return new Promise((resolve) => { const dirs = RNFetchBlob.fs.dirs; @@ -46,7 +43,7 @@ function handleDownload(url, fileName) { const isLocalFile = url.startsWith('file://'); let attachmentPath = isLocalFile ? url : undefined; - let fetchedAttachment = Promise.resolve(); + let fetchedAttachment: Promise | StatefulPromise = Promise.resolve(); if (!isLocalFile) { // Fetching the attachment @@ -69,7 +66,7 @@ function handleDownload(url, fileName) { } if (!isLocalFile) { - attachmentPath = attachment.path(); + attachmentPath = (attachment as FetchBlobResponse).path(); } return RNFetchBlob.MediaCollection.copyToMediaStore( @@ -79,11 +76,13 @@ function handleDownload(url, fileName) { mimeType: null, }, 'Download', - attachmentPath, + attachmentPath ?? '', ); }) .then(() => { - RNFetchBlob.fs.unlink(attachmentPath); + if (attachmentPath) { + RNFetchBlob.fs.unlink(attachmentPath); + } FileUtils.showSuccessAlert(); }) .catch(() => { @@ -95,12 +94,9 @@ function handleDownload(url, fileName) { /** * Checks permission and downloads the file for Android - * @param {String} url - * @param {String} fileName - * @returns {Promise} */ -export default function fileDownload(url, fileName) { - return new Promise((resolve) => { +const fileDownload: FileDownload = (url, fileName) => + new Promise((resolve) => { hasAndroidPermission() .then((hasPermission) => { if (hasPermission) { @@ -113,4 +109,5 @@ export default function fileDownload(url, fileName) { }) .finally(() => resolve()); }); -} + +export default fileDownload; diff --git a/src/libs/fileDownload/index.ios.js b/src/libs/fileDownload/index.ios.ts similarity index 72% rename from src/libs/fileDownload/index.ios.js rename to src/libs/fileDownload/index.ios.ts index 95d92f1e3103..1073a5e24f4b 100644 --- a/src/libs/fileDownload/index.ios.js +++ b/src/libs/fileDownload/index.ios.ts @@ -1,23 +1,20 @@ import RNFetchBlob from 'react-native-blob-util'; import {CameraRoll} from '@react-native-camera-roll/camera-roll'; -import lodashGet from 'lodash/get'; import * as FileUtils from './FileUtils'; import CONST from '../../CONST'; +import {FileDownload} from './types'; /** * Downloads the file to Documents section in iOS - * @param {String} fileUrl - * @param {String} fileName - * @returns {Promise} */ -function downloadFile(fileUrl, fileName) { +function downloadFile(fileUrl: string, fileName: string) { const dirs = RNFetchBlob.fs.dirs; // The iOS files will download to documents directory const path = dirs.DocumentDir; // Fetching the attachment - const fetchedAttachment = RNFetchBlob.config({ + return RNFetchBlob.config({ fileCache: true, path: `${path}/${fileName}`, addAndroidDownloads: { @@ -26,60 +23,61 @@ function downloadFile(fileUrl, fileName) { path: `${path}/Expensify/${fileName}`, }, }).fetch('GET', fileUrl); - return fetchedAttachment; } /** * Download the image to photo lib in iOS - * @param {String} fileUrl - * @param {String} fileName - * @returns {String} URI */ -function downloadImage(fileUrl) { +function downloadImage(fileUrl: string) { return CameraRoll.save(fileUrl); } /** * Download the video to photo lib in iOS - * @param {String} fileUrl - * @param {String} fileName - * @returns {String} URI */ -function downloadVideo(fileUrl, fileName) { +function downloadVideo(fileUrl: string, fileName: string): Promise { return new Promise((resolve, reject) => { - let documentPathUri = null; - let cameraRollUri = null; + let documentPathUri: string | null = null; + let cameraRollUri: string | null = null; // Because CameraRoll doesn't allow direct downloads of video with remote URIs, we first download as documents, then copy to photo lib and unlink the original file. downloadFile(fileUrl, fileName) .then((attachment) => { - documentPathUri = lodashGet(attachment, 'data'); + documentPathUri = attachment.data; + if (!documentPathUri) { + throw new Error('Error downloading video'); + } return CameraRoll.save(documentPathUri); }) .then((attachment) => { cameraRollUri = attachment; + if (!documentPathUri) { + throw new Error('Error downloading video'); + } return RNFetchBlob.fs.unlink(documentPathUri); }) - .then(() => resolve(cameraRollUri)) + .then(() => { + if (!cameraRollUri) { + throw new Error('Error downloading video'); + } + resolve(cameraRollUri); + }) .catch((err) => reject(err)); }); } /** * Download the file based on type(image, video, other file types)for iOS - * @param {String} fileUrl - * @param {String} fileName - * @returns {Promise} */ -export default function fileDownload(fileUrl, fileName) { - return new Promise((resolve) => { - let fileDownloadPromise = null; +const fileDownload: FileDownload = (fileUrl, fileName) => + new Promise((resolve) => { + let fileDownloadPromise; const fileType = FileUtils.getFileType(fileUrl); const attachmentName = FileUtils.appendTimeToFileName(fileName) || FileUtils.getAttachmentName(fileUrl); switch (fileType) { case CONST.ATTACHMENT_FILE_TYPE.IMAGE: - fileDownloadPromise = downloadImage(fileUrl, attachmentName); + fileDownloadPromise = downloadImage(fileUrl); break; case CONST.ATTACHMENT_FILE_TYPE.VIDEO: fileDownloadPromise = downloadVideo(fileUrl, attachmentName); @@ -108,4 +106,5 @@ export default function fileDownload(fileUrl, fileName) { }) .finally(() => resolve()); }); -} + +export default fileDownload; diff --git a/src/libs/fileDownload/index.js b/src/libs/fileDownload/index.ts similarity index 85% rename from src/libs/fileDownload/index.js rename to src/libs/fileDownload/index.ts index a775576eb365..a42c104b9d84 100644 --- a/src/libs/fileDownload/index.js +++ b/src/libs/fileDownload/index.ts @@ -1,14 +1,12 @@ import * as FileUtils from './FileUtils'; import * as Link from '../actions/Link'; +import {FileDownload} from './types'; /** * Downloading attachment in web, desktop - * @param {String} url - * @param {String} fileName - * @returns {Promise} */ -export default function fileDownload(url, fileName) { - return new Promise((resolve) => { +const fileDownload: FileDownload = (url: string, fileName: string) => + new Promise((resolve) => { fetch(url) .then((response) => response.blob()) .then((blob) => { @@ -34,7 +32,7 @@ export default function fileDownload(url, fileName) { // Clean up and remove the link URL.revokeObjectURL(link.href); - link.parentNode.removeChild(link); + link.parentNode?.removeChild(link); return resolve(); }) .catch(() => { @@ -43,4 +41,5 @@ export default function fileDownload(url, fileName) { return resolve(); }); }); -} + +export default fileDownload; diff --git a/src/libs/fileDownload/types.ts b/src/libs/fileDownload/types.ts new file mode 100644 index 000000000000..5ce8f121f952 --- /dev/null +++ b/src/libs/fileDownload/types.ts @@ -0,0 +1,9 @@ +import {Asset} from 'react-native-image-picker'; + +type FileDownload = (url: string, fileName: string) => Promise; +type GetImageResolution = (url: File | Asset) => Promise<{width: number; height: number}>; + +type SplitExtensionFromFileName = (fileName: string) => {fileName: string; fileExtension: string}; +type ReadFileAsync = (path: string, fileName: string) => Promise; + +export type {SplitExtensionFromFileName, ReadFileAsync, FileDownload, GetImageResolution}; diff --git a/src/types/global.d.ts b/src/types/global.d.ts index 1910b5a994b8..d88fc2e1f5b6 100644 --- a/src/types/global.d.ts +++ b/src/types/global.d.ts @@ -16,4 +16,15 @@ declare module '*.svg' { export default content; } +declare global { + // eslint-disable-next-line @typescript-eslint/consistent-type-definitions + interface File { + source?: string; + + uri?: string; + } +} + +export {}; + declare module 'react-native-device-info/jest/react-native-device-info-mock'; From 025660b995d8752d1f5bf0acc8e4427a27a0bdc4 Mon Sep 17 00:00:00 2001 From: Kacper Falat Date: Fri, 29 Sep 2023 12:24:37 +0200 Subject: [PATCH 006/237] Changes after review. --- src/libs/cropOrRotateImage/index.ts | 8 +++----- src/libs/cropOrRotateImage/types.ts | 8 ++------ src/libs/fileDownload/FileUtils.ts | 8 ++------ src/libs/fileDownload/getAttachmentDetails.ts | 9 ++++++--- .../fileDownload/getImageResolution.native.ts | 4 ++-- src/libs/fileDownload/getImageResolution.ts | 2 +- src/libs/fileDownload/index.android.ts | 6 +++--- src/libs/fileDownload/index.ios.ts | 2 +- src/libs/fileDownload/index.ts | 2 +- src/libs/fileDownload/types.ts | 17 ++++++++++++++--- src/types/global.d.ts | 9 --------- 11 files changed, 35 insertions(+), 40 deletions(-) diff --git a/src/libs/cropOrRotateImage/index.ts b/src/libs/cropOrRotateImage/index.ts index 6b222c9759b5..a1f237ff8e5c 100644 --- a/src/libs/cropOrRotateImage/index.ts +++ b/src/libs/cropOrRotateImage/index.ts @@ -1,4 +1,4 @@ -import {CropOptions, CropOrRotateImage, CropOrRotateImageOptions, FileWithUri} from './types'; +import {CropOptions, CropOrRotateImage, CropOrRotateImageOptions} from './types'; type SizeFromAngle = { width: number; @@ -71,15 +71,13 @@ function cropCanvas(canvas: HTMLCanvasElement, options: CropOptions) { return result; } -function convertCanvasToFile(canvas: HTMLCanvasElement, options: CropOrRotateImageOptions): Promise { +function convertCanvasToFile(canvas: HTMLCanvasElement, options: CropOrRotateImageOptions): Promise { return new Promise((resolve) => { canvas.toBlob((blob) => { if (!blob) { return; } - const file = new File([blob], options.name || 'fileName.jpeg', {type: options.type || 'image/jpeg'}) as FileWithUri; - file.uri = URL.createObjectURL(file); - resolve(file); + resolve(new File([blob], options.name || 'fileName.jpeg', {type: options.type || 'image/jpeg'})); }); }); } diff --git a/src/libs/cropOrRotateImage/types.ts b/src/libs/cropOrRotateImage/types.ts index 6abbdab49ea5..3b814686de29 100644 --- a/src/libs/cropOrRotateImage/types.ts +++ b/src/libs/cropOrRotateImage/types.ts @@ -18,12 +18,8 @@ type Action = { rotate?: number; }; -type FileWithUri = File & { - uri: string; -}; - type CustomRNImageManipulatorResult = RNImageManipulatorResult & {size: number; type: string; name: string}; -type CropOrRotateImage = (uri: string, actions: Action[], options: CropOrRotateImageOptions) => Promise; +type CropOrRotateImage = (uri: string, actions: Action[], options: CropOrRotateImageOptions) => Promise; -export type {CropOrRotateImage, CropOptions, Action, FileWithUri, CropOrRotateImageOptions}; +export type {CropOrRotateImage, CropOptions, Action, CropOrRotateImageOptions}; diff --git a/src/libs/fileDownload/FileUtils.ts b/src/libs/fileDownload/FileUtils.ts index bb24d398273e..b779b202b279 100644 --- a/src/libs/fileDownload/FileUtils.ts +++ b/src/libs/fileDownload/FileUtils.ts @@ -2,7 +2,7 @@ import {Alert, Linking, Platform} from 'react-native'; import CONST from '../../CONST'; import * as Localize from '../Localize'; import DateUtils from '../DateUtils'; -import {ReadFileAsync, SplitExtensionFromFileName} from './types'; +import type {ReadFileAsync, SplitExtensionFromFileName} from './types'; /** * Show alert on successful attachment download @@ -95,7 +95,7 @@ function getFileType(fileUrl: string): string | undefined { /** * Returns the filename split into fileName and fileExtension */ -const splitExtensionFromFileName: SplitExtensionFromFileName = (fullFileName: string) => { +const splitExtensionFromFileName: SplitExtensionFromFileName = (fullFileName) => { const fileName = fullFileName.trim(); const splitFileName = fileName.split('.'); const fileExtension = splitFileName.length > 1 ? splitFileName.pop() : ''; @@ -139,10 +139,6 @@ const readFileAsync: ReadFileAsync = (path, fileName) => res.blob() .then((blob) => { const file = new File([blob], cleanFileName(fileName)); - file.source = path; - // For some reason, the File object on iOS does not have a uri property - // so images aren't uploaded correctly to the backend - file.uri = path; resolve(file); }) .catch((e) => { diff --git a/src/libs/fileDownload/getAttachmentDetails.ts b/src/libs/fileDownload/getAttachmentDetails.ts index 2795c0d39497..4c42ea4dc2aa 100644 --- a/src/libs/fileDownload/getAttachmentDetails.ts +++ b/src/libs/fileDownload/getAttachmentDetails.ts @@ -1,10 +1,11 @@ import CONST from '../../CONST'; import tryResolveUrlFromApiRoot from '../tryResolveUrlFromApiRoot'; +import type {GetAttachmentDetails} from './types'; /** * Extract the thumbnail URL, source URL and the original filename from the HTML. */ -export default function getAttachmentDetails(html: string): unknown { +const getAttachmentDetails: GetAttachmentDetails = (html: string) => { // Files can be rendered either as anchor tag or as an image so based on that we have to form regex. const IS_IMAGE_TAG = //i.test(html); const PREVIEW_SOURCE_REGEX = new RegExp(`${CONST.ATTACHMENT_PREVIEW_ATTRIBUTE}*=*"(.+?)"`, 'i'); @@ -20,7 +21,7 @@ export default function getAttachmentDetails(html: string): unknown { // Files created/uploaded/hosted by App should resolve from API ROOT. Other URLs aren't modified const sourceURL = tryResolveUrlFromApiRoot(html.match(SOURCE_REGEX)?.[1] ?? ''); - const imageURL = IS_IMAGE_TAG && tryResolveUrlFromApiRoot(html.match(PREVIEW_SOURCE_REGEX)?.[1] ?? ''); + const imageURL = IS_IMAGE_TAG ? tryResolveUrlFromApiRoot(html.match(PREVIEW_SOURCE_REGEX)?.[1] ?? '') : null; const previewSourceURL = IS_IMAGE_TAG ? imageURL : sourceURL; const originalFileName = html.match(ORIGINAL_FILENAME_REGEX)?.[1] ?? null; @@ -30,4 +31,6 @@ export default function getAttachmentDetails(html: string): unknown { sourceURL, originalFileName, }; -} +}; + +export default getAttachmentDetails; diff --git a/src/libs/fileDownload/getImageResolution.native.ts b/src/libs/fileDownload/getImageResolution.native.ts index 6ec08826344d..3bdff78a93ed 100644 --- a/src/libs/fileDownload/getImageResolution.native.ts +++ b/src/libs/fileDownload/getImageResolution.native.ts @@ -1,5 +1,5 @@ import {Asset} from 'react-native-image-picker'; -import {GetImageResolution} from './types'; +import type {GetImageResolution} from './types'; /** * Get image resolution @@ -8,6 +8,6 @@ import {GetImageResolution} from './types'; * Opposite to web where we need to create a new Image object and get dimensions from it * */ -const getImageResolution: GetImageResolution = (file: Asset | File) => Promise.resolve({width: (file as Asset).width ?? 0, height: (file as Asset).height ?? 0}); +const getImageResolution: GetImageResolution = (file: Asset) => Promise.resolve({width: file.width ?? 0, height: file.height ?? 0}); export default getImageResolution; diff --git a/src/libs/fileDownload/getImageResolution.ts b/src/libs/fileDownload/getImageResolution.ts index 44718710a3fb..1fcd72da9010 100644 --- a/src/libs/fileDownload/getImageResolution.ts +++ b/src/libs/fileDownload/getImageResolution.ts @@ -1,5 +1,5 @@ import {Asset} from 'react-native-image-picker'; -import {GetImageResolution} from './types'; +import type {GetImageResolution} from './types'; /** * Get image resolution diff --git a/src/libs/fileDownload/index.android.ts b/src/libs/fileDownload/index.android.ts index 67d0664ae8d4..014e3309df33 100644 --- a/src/libs/fileDownload/index.android.ts +++ b/src/libs/fileDownload/index.android.ts @@ -1,7 +1,7 @@ import {PermissionsAndroid, Platform} from 'react-native'; -import RNFetchBlob, {FetchBlobResponse, StatefulPromise} from 'react-native-blob-util'; +import RNFetchBlob, {FetchBlobResponse} from 'react-native-blob-util'; import * as FileUtils from './FileUtils'; -import {FileDownload} from './types'; +import type {FileDownload} from './types'; /** * Android permission check to store images @@ -43,7 +43,7 @@ function handleDownload(url: string, fileName: string): Promise { const isLocalFile = url.startsWith('file://'); let attachmentPath = isLocalFile ? url : undefined; - let fetchedAttachment: Promise | StatefulPromise = Promise.resolve(); + let fetchedAttachment: Promise = Promise.resolve(); if (!isLocalFile) { // Fetching the attachment diff --git a/src/libs/fileDownload/index.ios.ts b/src/libs/fileDownload/index.ios.ts index 1073a5e24f4b..b7a59512ff5b 100644 --- a/src/libs/fileDownload/index.ios.ts +++ b/src/libs/fileDownload/index.ios.ts @@ -2,7 +2,7 @@ import RNFetchBlob from 'react-native-blob-util'; import {CameraRoll} from '@react-native-camera-roll/camera-roll'; import * as FileUtils from './FileUtils'; import CONST from '../../CONST'; -import {FileDownload} from './types'; +import type {FileDownload} from './types'; /** * Downloads the file to Documents section in iOS diff --git a/src/libs/fileDownload/index.ts b/src/libs/fileDownload/index.ts index a42c104b9d84..b0f01ca99d03 100644 --- a/src/libs/fileDownload/index.ts +++ b/src/libs/fileDownload/index.ts @@ -1,6 +1,6 @@ import * as FileUtils from './FileUtils'; import * as Link from '../actions/Link'; -import {FileDownload} from './types'; +import type {FileDownload} from './types'; /** * Downloading attachment in web, desktop diff --git a/src/libs/fileDownload/types.ts b/src/libs/fileDownload/types.ts index 5ce8f121f952..d5b0600ab06a 100644 --- a/src/libs/fileDownload/types.ts +++ b/src/libs/fileDownload/types.ts @@ -1,9 +1,20 @@ import {Asset} from 'react-native-image-picker'; type FileDownload = (url: string, fileName: string) => Promise; -type GetImageResolution = (url: File | Asset) => Promise<{width: number; height: number}>; -type SplitExtensionFromFileName = (fileName: string) => {fileName: string; fileExtension: string}; +type ImageResolution = {width: number; height: number}; +type GetImageResolution = (url: File | Asset) => Promise; + +type ExtensionAndFileName = {fileName: string; fileExtension: string}; +type SplitExtensionFromFileName = (fileName: string) => ExtensionAndFileName; + type ReadFileAsync = (path: string, fileName: string) => Promise; -export type {SplitExtensionFromFileName, ReadFileAsync, FileDownload, GetImageResolution}; +type AttachmentDetails = { + previewSourceURL: null | string; + sourceURL: null | string; + originalFileName: null | string; +}; +type GetAttachmentDetails = (html: string) => AttachmentDetails; + +export type {SplitExtensionFromFileName, GetAttachmentDetails, ReadFileAsync, FileDownload, GetImageResolution}; diff --git a/src/types/global.d.ts b/src/types/global.d.ts index d88fc2e1f5b6..ee2a565b8439 100644 --- a/src/types/global.d.ts +++ b/src/types/global.d.ts @@ -16,15 +16,6 @@ declare module '*.svg' { export default content; } -declare global { - // eslint-disable-next-line @typescript-eslint/consistent-type-definitions - interface File { - source?: string; - - uri?: string; - } -} - export {}; declare module 'react-native-device-info/jest/react-native-device-info-mock'; From 0d1add8602c9f1a7dae2ce5614f31e25eaa47470 Mon Sep 17 00:00:00 2001 From: Kacper Falat Date: Fri, 29 Sep 2023 16:53:04 +0200 Subject: [PATCH 007/237] Implemented requested changes. --- src/libs/fileDownload/FileUtils.ts | 1 + src/libs/fileDownload/getImageResolution.ts | 4 ++-- src/types/global.d.ts | 2 -- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/libs/fileDownload/FileUtils.ts b/src/libs/fileDownload/FileUtils.ts index b779b202b279..45eaa53e4365 100644 --- a/src/libs/fileDownload/FileUtils.ts +++ b/src/libs/fileDownload/FileUtils.ts @@ -122,6 +122,7 @@ function appendTimeToFileName(fileName: string): string { /** * Reads a locally uploaded file + * @param path - the blob url of the locally uploaded file */ const readFileAsync: ReadFileAsync = (path, fileName) => new Promise((resolve) => { diff --git a/src/libs/fileDownload/getImageResolution.ts b/src/libs/fileDownload/getImageResolution.ts index 1fcd72da9010..a3707cc73574 100644 --- a/src/libs/fileDownload/getImageResolution.ts +++ b/src/libs/fileDownload/getImageResolution.ts @@ -21,8 +21,8 @@ const getImageResolution: GetImageResolution = (file: File | Asset) => { const objectUrl = URL.createObjectURL(file); image.onload = function () { resolve({ - width: image.naturalWidth, - height: image.naturalHeight, + width: (this as HTMLImageElement).naturalWidth, + height: (this as HTMLImageElement).naturalHeight, }); URL.revokeObjectURL(objectUrl); }; diff --git a/src/types/global.d.ts b/src/types/global.d.ts index ee2a565b8439..1910b5a994b8 100644 --- a/src/types/global.d.ts +++ b/src/types/global.d.ts @@ -16,6 +16,4 @@ declare module '*.svg' { export default content; } -export {}; - declare module 'react-native-device-info/jest/react-native-device-info-mock'; From f5eda23d37ae64a9bf8aa1bddff1f7222a22d121 Mon Sep 17 00:00:00 2001 From: Kacper Falat Date: Tue, 3 Oct 2023 09:26:22 +0200 Subject: [PATCH 008/237] Reverted index.ts --- src/libs/cropOrRotateImage/index.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/libs/cropOrRotateImage/index.ts b/src/libs/cropOrRotateImage/index.ts index a1f237ff8e5c..6b222c9759b5 100644 --- a/src/libs/cropOrRotateImage/index.ts +++ b/src/libs/cropOrRotateImage/index.ts @@ -1,4 +1,4 @@ -import {CropOptions, CropOrRotateImage, CropOrRotateImageOptions} from './types'; +import {CropOptions, CropOrRotateImage, CropOrRotateImageOptions, FileWithUri} from './types'; type SizeFromAngle = { width: number; @@ -71,13 +71,15 @@ function cropCanvas(canvas: HTMLCanvasElement, options: CropOptions) { return result; } -function convertCanvasToFile(canvas: HTMLCanvasElement, options: CropOrRotateImageOptions): Promise { +function convertCanvasToFile(canvas: HTMLCanvasElement, options: CropOrRotateImageOptions): Promise { return new Promise((resolve) => { canvas.toBlob((blob) => { if (!blob) { return; } - resolve(new File([blob], options.name || 'fileName.jpeg', {type: options.type || 'image/jpeg'})); + const file = new File([blob], options.name || 'fileName.jpeg', {type: options.type || 'image/jpeg'}) as FileWithUri; + file.uri = URL.createObjectURL(file); + resolve(file); }); }); } From c12cbb11886012ca369b544447bbe629428957a7 Mon Sep 17 00:00:00 2001 From: Kacper Falat Date: Tue, 3 Oct 2023 09:26:25 +0200 Subject: [PATCH 009/237] Reverted types.ts --- src/libs/cropOrRotateImage/types.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/libs/cropOrRotateImage/types.ts b/src/libs/cropOrRotateImage/types.ts index 3b814686de29..6abbdab49ea5 100644 --- a/src/libs/cropOrRotateImage/types.ts +++ b/src/libs/cropOrRotateImage/types.ts @@ -18,8 +18,12 @@ type Action = { rotate?: number; }; +type FileWithUri = File & { + uri: string; +}; + type CustomRNImageManipulatorResult = RNImageManipulatorResult & {size: number; type: string; name: string}; -type CropOrRotateImage = (uri: string, actions: Action[], options: CropOrRotateImageOptions) => Promise; +type CropOrRotateImage = (uri: string, actions: Action[], options: CropOrRotateImageOptions) => Promise; -export type {CropOrRotateImage, CropOptions, Action, CropOrRotateImageOptions}; +export type {CropOrRotateImage, CropOptions, Action, FileWithUri, CropOrRotateImageOptions}; From b221a7e7d33184d1ebd8c3c932084ecb05ab9e2b Mon Sep 17 00:00:00 2001 From: Kacper Falat Date: Tue, 3 Oct 2023 09:53:55 +0200 Subject: [PATCH 010/237] Solved conflicts and issues with types. --- src/libs/cropOrRotateImage/index.ts | 6 +++--- src/libs/cropOrRotateImage/types.ts | 8 ++------ src/libs/fileDownload/FileUtils.ts | 4 ++++ src/types/global.d.ts | 11 +++++++++++ 4 files changed, 20 insertions(+), 9 deletions(-) diff --git a/src/libs/cropOrRotateImage/index.ts b/src/libs/cropOrRotateImage/index.ts index 6b222c9759b5..a66ddbb40b00 100644 --- a/src/libs/cropOrRotateImage/index.ts +++ b/src/libs/cropOrRotateImage/index.ts @@ -1,4 +1,4 @@ -import {CropOptions, CropOrRotateImage, CropOrRotateImageOptions, FileWithUri} from './types'; +import {CropOptions, CropOrRotateImage, CropOrRotateImageOptions} from './types'; type SizeFromAngle = { width: number; @@ -71,13 +71,13 @@ function cropCanvas(canvas: HTMLCanvasElement, options: CropOptions) { return result; } -function convertCanvasToFile(canvas: HTMLCanvasElement, options: CropOrRotateImageOptions): Promise { +function convertCanvasToFile(canvas: HTMLCanvasElement, options: CropOrRotateImageOptions): Promise { return new Promise((resolve) => { canvas.toBlob((blob) => { if (!blob) { return; } - const file = new File([blob], options.name || 'fileName.jpeg', {type: options.type || 'image/jpeg'}) as FileWithUri; + const file = new File([blob], options.name || 'fileName.jpeg', {type: options.type || 'image/jpeg'}); file.uri = URL.createObjectURL(file); resolve(file); }); diff --git a/src/libs/cropOrRotateImage/types.ts b/src/libs/cropOrRotateImage/types.ts index 6abbdab49ea5..3b814686de29 100644 --- a/src/libs/cropOrRotateImage/types.ts +++ b/src/libs/cropOrRotateImage/types.ts @@ -18,12 +18,8 @@ type Action = { rotate?: number; }; -type FileWithUri = File & { - uri: string; -}; - type CustomRNImageManipulatorResult = RNImageManipulatorResult & {size: number; type: string; name: string}; -type CropOrRotateImage = (uri: string, actions: Action[], options: CropOrRotateImageOptions) => Promise; +type CropOrRotateImage = (uri: string, actions: Action[], options: CropOrRotateImageOptions) => Promise; -export type {CropOrRotateImage, CropOptions, Action, FileWithUri, CropOrRotateImageOptions}; +export type {CropOrRotateImage, CropOptions, Action, CropOrRotateImageOptions}; diff --git a/src/libs/fileDownload/FileUtils.ts b/src/libs/fileDownload/FileUtils.ts index 45eaa53e4365..fdb60efe4edd 100644 --- a/src/libs/fileDownload/FileUtils.ts +++ b/src/libs/fileDownload/FileUtils.ts @@ -140,6 +140,10 @@ const readFileAsync: ReadFileAsync = (path, fileName) => res.blob() .then((blob) => { const file = new File([blob], cleanFileName(fileName)); + file.source = path; + // For some reason, the File object on iOS does not have a uri property + // so images aren't uploaded correctly to the backend + file.uri = path; resolve(file); }) .catch((e) => { diff --git a/src/types/global.d.ts b/src/types/global.d.ts index 1910b5a994b8..d88fc2e1f5b6 100644 --- a/src/types/global.d.ts +++ b/src/types/global.d.ts @@ -16,4 +16,15 @@ declare module '*.svg' { export default content; } +declare global { + // eslint-disable-next-line @typescript-eslint/consistent-type-definitions + interface File { + source?: string; + + uri?: string; + } +} + +export {}; + declare module 'react-native-device-info/jest/react-native-device-info-mock'; From 424a856baa954875f82fa321ff40fa7a9002b82d Mon Sep 17 00:00:00 2001 From: Kacper Falat Date: Tue, 3 Oct 2023 10:25:13 +0200 Subject: [PATCH 011/237] Migrated HttpUtils.js lib to TypeScript. --- src/components/Alert/index.js | 2 +- src/libs/{HttpUtils.js => HttpUtils.ts} | 69 ++++++++++++------------- src/types/onyx/Response.ts | 8 +++ 3 files changed, 41 insertions(+), 38 deletions(-) rename src/libs/{HttpUtils.js => HttpUtils.ts} (67%) diff --git a/src/components/Alert/index.js b/src/components/Alert/index.js index dc3a722c2331..3fc90433f13e 100644 --- a/src/components/Alert/index.js +++ b/src/components/Alert/index.js @@ -5,7 +5,7 @@ import _ from 'underscore'; * * @param {String} title The title of the alert * @param {String} description The description of the alert - * @param {Object[]} options An array of objects with `style` and `onPress` properties + * @param {Object[]} [options] An array of objects with `style` and `onPress` properties */ export default (title, description, options) => { const result = _.filter(window.confirm([title, description], Boolean)).join('\n'); diff --git a/src/libs/HttpUtils.js b/src/libs/HttpUtils.ts similarity index 67% rename from src/libs/HttpUtils.js rename to src/libs/HttpUtils.ts index 5a8185a03038..ad902385495f 100644 --- a/src/libs/HttpUtils.js +++ b/src/libs/HttpUtils.ts @@ -1,10 +1,13 @@ import Onyx from 'react-native-onyx'; -import _ from 'underscore'; import CONST from '../CONST'; import ONYXKEYS from '../ONYXKEYS'; import HttpsError from './Errors/HttpsError'; import * as ApiUtils from './ApiUtils'; import alert from '../components/Alert'; +import type Response from '../types/onyx/Response'; + +type ProcessHttpRequest = (url: string, method: string, body: FormData | null, canCancel: boolean) => Promise; +type Xhr = (command: string, data: Record, type: string, shouldUseSecure: boolean) => Promise; let shouldFailAllRequests = false; let shouldForceOffline = false; @@ -25,15 +28,9 @@ let cancellationController = new AbortController(); /** * Send an HTTP request, and attempt to resolve the json response. * If there is a network error, we'll set the application offline. - * - * @param {String} url - * @param {String} [method] - * @param {Object} [body] - * @param {Boolean} [canCancel] - * @returns {Promise} */ -function processHTTPRequest(url, method = 'get', body = null, canCancel = true) { - return fetch(url, { +const processHTTPRequest: ProcessHttpRequest = (url, method = 'get', body = null, canCancel = true) => + fetch(url, { // We hook requests to the same Controller signal, so we can cancel them all at once signal: canCancel ? cancellationController.signal : undefined, method, @@ -49,40 +46,40 @@ function processHTTPRequest(url, method = 'get', body = null, canCancel = true) if (!response.ok) { // Expensify site is down or there was an internal server error, or something temporary like a Bad Gateway, or unknown error occurred - const serviceInterruptedStatuses = [ + const serviceInterruptedStatuses: number[] = [ CONST.HTTP_STATUS.INTERNAL_SERVER_ERROR, CONST.HTTP_STATUS.BAD_GATEWAY, CONST.HTTP_STATUS.GATEWAY_TIMEOUT, CONST.HTTP_STATUS.UNKNOWN_ERROR, ]; - if (_.contains(serviceInterruptedStatuses, response.status)) { + if (serviceInterruptedStatuses.includes(response.status)) { throw new HttpsError({ message: CONST.ERROR.EXPENSIFY_SERVICE_INTERRUPTED, - status: response.status, + status: response.status.toString(), title: 'Issue connecting to Expensify site', }); } else if (response.status === CONST.HTTP_STATUS.TOO_MANY_REQUESTS) { throw new HttpsError({ message: CONST.ERROR.THROTTLED, - status: response.status, + status: response.status.toString(), title: 'API request throttled', }); } throw new HttpsError({ message: response.statusText, - status: response.status, + status: response.status.toString(), }); } return response.json(); }) - .then((response) => { + .then((response: Response) => { // Some retried requests will result in a "Unique Constraints Violation" error from the server, which just means the record already exists if (response.jsonCode === CONST.JSON_CODE.BAD_REQUEST && response.message === CONST.ERROR_TITLE.DUPLICATE_RECORD) { throw new HttpsError({ message: CONST.ERROR.DUPLICATE_RECORD, - status: CONST.JSON_CODE.BAD_REQUEST, + status: CONST.JSON_CODE.BAD_REQUEST.toString(), title: CONST.ERROR_TITLE.DUPLICATE_RECORD, }); } @@ -91,44 +88,42 @@ function processHTTPRequest(url, method = 'get', body = null, canCancel = true) if (response.jsonCode === CONST.JSON_CODE.EXP_ERROR && response.title === CONST.ERROR_TITLE.SOCKET && response.type === CONST.ERROR_TYPE.SOCKET) { throw new HttpsError({ message: CONST.ERROR.EXPENSIFY_SERVICE_INTERRUPTED, - status: CONST.JSON_CODE.EXP_ERROR, + status: CONST.JSON_CODE.EXP_ERROR.toString(), title: CONST.ERROR_TITLE.SOCKET, }); } if (response.jsonCode === CONST.JSON_CODE.MANY_WRITES_ERROR) { - const {phpCommandName, authWriteCommands} = response.data; - // eslint-disable-next-line max-len - const message = `The API call (${phpCommandName}) did more Auth write requests than allowed. Count ${authWriteCommands.length}, commands: ${authWriteCommands.join( - ', ', - )}. Check the APIWriteCommands class in Web-Expensify`; - alert('Too many auth writes', message); + if (response.data) { + const {phpCommandName, authWriteCommands} = response.data; + // eslint-disable-next-line max-len + const message = `The API call (${phpCommandName}) did more Auth write requests than allowed. Count ${authWriteCommands.length}, commands: ${authWriteCommands.join( + ', ', + )}. Check the APIWriteCommands class in Web-Expensify`; + alert('Too many auth writes', message); + } } return response; }); -} /** * Makes XHR request - * @param {String} command the name of the API command - * @param {Object} data parameters for the API command - * @param {String} type HTTP request type (get/post) - * @param {Boolean} shouldUseSecure should we use the secure server - * @returns {Promise} + * @param command the name of the API command + * @param data parameters for the API command + * @param type HTTP request type (get/post) + * @param shouldUseSecure should we use the secure server */ -function xhr(command, data, type = CONST.NETWORK.METHOD.POST, shouldUseSecure = false) { +const xhr: Xhr = (command, data, type = CONST.NETWORK.METHOD.POST, shouldUseSecure = false) => { const formData = new FormData(); - _.each(data, (val, key) => { - // Do not send undefined request parameters to our API. They will be processed as strings of 'undefined'. - if (_.isUndefined(val)) { + Object.keys(data).forEach((key) => { + if (data[key] === undefined) { return; } - - formData.append(key, val); + formData.append(key, data[key]); }); const url = ApiUtils.getCommandURL({shouldUseSecure, command}); - return processHTTPRequest(url, type, formData, data.canCancel); -} + return processHTTPRequest(url, type, formData, Boolean(data.canCancel)); +}; function cancelPendingRequests() { cancellationController.abort(); diff --git a/src/types/onyx/Response.ts b/src/types/onyx/Response.ts index 255ac6d9bae4..263f1f37d886 100644 --- a/src/types/onyx/Response.ts +++ b/src/types/onyx/Response.ts @@ -1,5 +1,10 @@ import {OnyxUpdate} from 'react-native-onyx'; +type Data = { + phpCommandName: string; + authWriteCommands: string[]; +}; + type Response = { previousUpdateID?: number | string; lastUpdateID?: number | string; @@ -7,6 +12,9 @@ type Response = { onyxData?: OnyxUpdate[]; requestID?: string; message?: string; + title?: string; + data?: Data; + type?: string; }; export default Response; From 453eeedae5b2ff00209ff911331e6c698871ad18 Mon Sep 17 00:00:00 2001 From: keisyrzk Date: Tue, 3 Oct 2023 11:37:16 +0200 Subject: [PATCH 012/237] updates --- src/components/AvatarWithImagePicker.js | 93 +++++++++++++++---------- 1 file changed, 58 insertions(+), 35 deletions(-) diff --git a/src/components/AvatarWithImagePicker.js b/src/components/AvatarWithImagePicker.js index 4459ad892877..f20c4f4cfb55 100644 --- a/src/components/AvatarWithImagePicker.js +++ b/src/components/AvatarWithImagePicker.js @@ -1,6 +1,6 @@ import _ from 'underscore'; -import React, { useState, useRef, useEffect } from 'react'; -import { View } from 'react-native'; +import React, {useState, useRef, useEffect} from 'react'; +import {View} from 'react-native'; import PropTypes from 'prop-types'; import lodashGet from 'lodash/get'; import Avatar from './Avatar'; @@ -116,8 +116,31 @@ const defaultProps = { originalFileName: '', }; -function AvatarWithImagePicker(props) { - const animation = new SpinningIndicatorAnimation(); +function AvatarWithImagePicker({ + isUploading, + isFocused, + DefaultAvatar, + style, + pendingAction, + errors, + errorRowStyles, + onErrorClose, + translate, + source, + fallbackIcon, + size, + type, + headerTitle, + previewSource, + originalFileName, + isUsingDefaultAvatar, + onImageRemoved, + anchorPosition, + anchorAlignment, + onImageSelected, + editorMaskImage }) { + + const animation = useRef(new SpinningIndicatorAnimation()).current; const [isMenuVisible, setIsMenuVisible] = useState(false); const [validationError, setValidationError] = useState(null); const [phraseParam, setPhraseParam] = useState({}); @@ -128,20 +151,21 @@ function AvatarWithImagePicker(props) { const anchorRef = useRef(); useEffect(() => { - if (props.isUploading) { + if (isUploading) { animation.start(); } return () => { animation.stop(); }; - }, [props.isUploading]); + }, [isUploading]); useEffect(() => { - if (!props.isFocused) { + // check if the component is no longer focused, then reset the error. + if (!isFocused) { setError(null, {}); } - }, [props.isFocused]); + }, [isFocused]); const setError = (error, phraseParam) => { setValidationError(error); @@ -199,35 +223,34 @@ function AvatarWithImagePicker(props) { setIsAvatarCropModalOpen(false); }; - const DefaultAvatar = props.DefaultAvatar; - const additionalStyles = _.isArray(props.style) ? props.style : [props.style]; + const additionalStyles = _.isArray(style) ? style : [style]; return ( - + setIsMenuVisible(prev => !prev)} accessibilityRole={CONST.ACCESSIBILITY_ROLE.IMAGEBUTTON} - accessibilityLabel={props.translate('avatarWithImagePicker.editImage')} + accessibilityLabel={translate('avatarWithImagePicker.editImage')} disabled={isAvatarCropModalOpen} ref={anchorRef} > - {props.source ? ( + {source ? ( ) : ( @@ -245,10 +268,10 @@ function AvatarWithImagePicker(props) { {({show}) => ( @@ -256,7 +279,7 @@ function AvatarWithImagePicker(props) { const menuItems = [ { icon: Expensicons.Upload, - text: props.translate('avatarWithImagePicker.uploadPhoto'), + text: translate('avatarWithImagePicker.uploadPhoto'), onSelected: () => { if (Browser.isSafari()) { return; @@ -269,19 +292,19 @@ function AvatarWithImagePicker(props) { ]; // If current avatar isn't a default avatar, allow Remove Photo option - if (!props.isUsingDefaultAvatar) { + if (!isUsingDefaultAvatar) { menuItems.push({ icon: Expensicons.Trashcan, - text: props.translate('avatarWithImagePicker.removePhoto'), + text: translate('avatarWithImagePicker.removePhoto'), onSelected: () => { setError(null, {}); - props.onImageRemoved(); + onImageRemoved(); }, }); menuItems.push({ icon: Expensicons.Eye, - text: props.translate('avatarWithImagePicker.viewPhoto'), + text: translate('avatarWithImagePicker.viewPhoto'), onSelected: () => show(), }); } @@ -301,10 +324,10 @@ function AvatarWithImagePicker(props) { } }} menuItems={menuItems} - anchorPosition={props.anchorPosition} + anchorPosition={anchorPosition} withoutOverlay anchorRef={anchorRef} - anchorAlignment={props.anchorAlignment} + anchorAlignment={anchorAlignment} /> ); }} @@ -315,18 +338,18 @@ function AvatarWithImagePicker(props) { {validationError && ( )} ); From 1b2a6e24df4a6623c2d4c23f738ba65be11890d6 Mon Sep 17 00:00:00 2001 From: keisyrzk Date: Tue, 3 Oct 2023 11:54:44 +0200 Subject: [PATCH 013/237] comments --- src/components/AvatarWithImagePicker.js | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/components/AvatarWithImagePicker.js b/src/components/AvatarWithImagePicker.js index f20c4f4cfb55..7a0156cb89ee 100644 --- a/src/components/AvatarWithImagePicker.js +++ b/src/components/AvatarWithImagePicker.js @@ -172,15 +172,33 @@ function AvatarWithImagePicker({ setPhraseParam(phraseParam); }; + /** + * Check if the attachment extension is allowed. + * + * @param {Object} image + * @returns {Boolean} + */ const isValidExtension = (image) => { const { fileExtension } = FileUtils.splitExtensionFromFileName(lodashGet(image, 'name', '')); return _.contains(CONST.AVATAR_ALLOWED_EXTENSIONS, fileExtension.toLowerCase()); }; + /** + * Check if the attachment size is less than allowed size. + * + * @param {Object} image + * @returns {Boolean} + */ const isValidSize = (image) => { return image && lodashGet(image, 'size', 0) < CONST.AVATAR_MAX_ATTACHMENT_SIZE; }; + /** + * Check if the attachment resolution matches constraints. + * + * @param {Object} image + * @returns {Promise} + */ const isValidResolution = async (image) => { const resolution = await getImageResolution(image); return resolution.height >= CONST.AVATAR_MIN_HEIGHT_PX && @@ -189,6 +207,11 @@ function AvatarWithImagePicker({ resolution.width <= CONST.AVATAR_MAX_WIDTH_PX; }; + /** + * Validates if an image has a valid resolution and opens an avatar crop modal + * + * @param {Object} image + */ const showAvatarCropModal = async (image) => { if (!isValidExtension(image)) { setError('avatarWithImagePicker.notAllowedExtension', { allowedExtensions: CONST.AVATAR_ALLOWED_EXTENSIONS }); From 1b9523e690ec0208cde6dfe4a976db9ee39a2098 Mon Sep 17 00:00:00 2001 From: Kacper Falat Date: Tue, 3 Oct 2023 14:14:06 +0200 Subject: [PATCH 014/237] Requested changes. --- src/libs/HttpUtils.ts | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/libs/HttpUtils.ts b/src/libs/HttpUtils.ts index ad902385495f..5199ee6e6e6e 100644 --- a/src/libs/HttpUtils.ts +++ b/src/libs/HttpUtils.ts @@ -6,11 +6,9 @@ import * as ApiUtils from './ApiUtils'; import alert from '../components/Alert'; import type Response from '../types/onyx/Response'; -type ProcessHttpRequest = (url: string, method: string, body: FormData | null, canCancel: boolean) => Promise; -type Xhr = (command: string, data: Record, type: string, shouldUseSecure: boolean) => Promise; - let shouldFailAllRequests = false; let shouldForceOffline = false; + Onyx.connect({ key: ONYXKEYS.NETWORK, callback: (network) => { @@ -29,8 +27,8 @@ let cancellationController = new AbortController(); * Send an HTTP request, and attempt to resolve the json response. * If there is a network error, we'll set the application offline. */ -const processHTTPRequest: ProcessHttpRequest = (url, method = 'get', body = null, canCancel = true) => - fetch(url, { +function processHTTPRequest(url: string, method = 'get', body: FormData | null = null, canCancel = true): Promise { + return fetch(url, { // We hook requests to the same Controller signal, so we can cancel them all at once signal: canCancel ? cancellationController.signal : undefined, method, @@ -104,6 +102,7 @@ const processHTTPRequest: ProcessHttpRequest = (url, method = 'get', body = null } return response; }); +} /** * Makes XHR request @@ -112,10 +111,10 @@ const processHTTPRequest: ProcessHttpRequest = (url, method = 'get', body = null * @param type HTTP request type (get/post) * @param shouldUseSecure should we use the secure server */ -const xhr: Xhr = (command, data, type = CONST.NETWORK.METHOD.POST, shouldUseSecure = false) => { +function xhr(command: string, data: Record, type: string = CONST.NETWORK.METHOD.POST, shouldUseSecure = false): Promise { const formData = new FormData(); Object.keys(data).forEach((key) => { - if (data[key] === undefined) { + if (!data[key]) { return; } formData.append(key, data[key]); @@ -123,7 +122,7 @@ const xhr: Xhr = (command, data, type = CONST.NETWORK.METHOD.POST, shouldUseSecu const url = ApiUtils.getCommandURL({shouldUseSecure, command}); return processHTTPRequest(url, type, formData, Boolean(data.canCancel)); -}; +} function cancelPendingRequests() { cancellationController.abort(); From 559c7ae8e087c5d4661cba4a771f7161a198e3f6 Mon Sep 17 00:00:00 2001 From: keisyrzk Date: Tue, 3 Oct 2023 14:29:22 +0200 Subject: [PATCH 015/237] pr updates --- src/components/AvatarWithImagePicker.js | 114 +++++++++++++++--------- 1 file changed, 70 insertions(+), 44 deletions(-) diff --git a/src/components/AvatarWithImagePicker.js b/src/components/AvatarWithImagePicker.js index 7a0156cb89ee..55767268162c 100644 --- a/src/components/AvatarWithImagePicker.js +++ b/src/components/AvatarWithImagePicker.js @@ -12,7 +12,7 @@ import themeColors from '../styles/themes/default'; import AttachmentPicker from './AttachmentPicker'; import AvatarCropModal from './AvatarCropModal/AvatarCropModal'; import OfflineWithFeedback from './OfflineWithFeedback'; -import withLocalize, {withLocalizePropTypes} from './withLocalize'; +import useLocalize from '../hooks/useLocalize'; import variables from '../styles/variables'; import CONST from '../CONST'; import SpinningIndicatorAnimation from '../styles/animation/SpinningIndicatorAnimation'; @@ -91,7 +91,6 @@ const propTypes = { /** File name of the avatar */ originalFileName: PropTypes.string, - ...withLocalizePropTypes, ...withNavigationFocusPropTypes, }; @@ -114,6 +113,7 @@ const defaultProps = { headerTitle: '', previewSource: '', originalFileName: '', + displayName: `AvatarWithImagePicker`, }; function AvatarWithImagePicker({ @@ -125,7 +125,6 @@ function AvatarWithImagePicker({ errors, errorRowStyles, onErrorClose, - translate, source, fallbackIcon, size, @@ -142,13 +141,18 @@ function AvatarWithImagePicker({ const animation = useRef(new SpinningIndicatorAnimation()).current; const [isMenuVisible, setIsMenuVisible] = useState(false); - const [validationError, setValidationError] = useState(null); - const [phraseParam, setPhraseParam] = useState({}); + const [errorData, setErrorData] = useState({ + validationError: null, + phraseParam: {}, + }); const [isAvatarCropModalOpen, setIsAvatarCropModalOpen] = useState(false); - const [imageName, setImageName] = useState(''); - const [imageUri, setImageUri] = useState(''); - const [imageType, setImageType] = useState(''); + const [imageData, setImageData] = useState({ + uri: '', + name: '', + type: '' + }); const anchorRef = useRef(); + const {translate} = useLocalize(); useEffect(() => { if (isUploading) { @@ -167,9 +171,15 @@ function AvatarWithImagePicker({ } }, [isFocused]); + /** + * @param {String} error + * @param {Object} phraseParam + */ const setError = (error, phraseParam) => { - setValidationError(error); - setPhraseParam(phraseParam); + setErrorData({ + validationError: error, + phraseParam: phraseParam, + }); }; /** @@ -212,35 +222,51 @@ function AvatarWithImagePicker({ * * @param {Object} image */ - const showAvatarCropModal = async (image) => { - if (!isValidExtension(image)) { - setError('avatarWithImagePicker.notAllowedExtension', { allowedExtensions: CONST.AVATAR_ALLOWED_EXTENSIONS }); - return; - } - if (!isValidSize(image)) { - setError('avatarWithImagePicker.sizeExceeded', { maxUploadSizeInMB: CONST.AVATAR_MAX_ATTACHMENT_SIZE / (1024 * 1024) }); - return; - } - - const isValidRes = await isValidResolution(image); - if (!isValidRes) { - setError('avatarWithImagePicker.resolutionConstraints', { - minHeightInPx: CONST.AVATAR_MIN_HEIGHT_PX, - minWidthInPx: CONST.AVATAR_MIN_WIDTH_PX, - maxHeightInPx: CONST.AVATAR_MAX_HEIGHT_PX, - maxWidthInPx: CONST.AVATAR_MAX_WIDTH_PX, + function showAvatarCropModal(image) { + const handleResolutionValidation = (isValidRes) => { + if (!isValidRes) { + setError('avatarWithImagePicker.resolutionConstraints', { + minHeightInPx: CONST.AVATAR_MIN_HEIGHT_PX, + minWidthInPx: CONST.AVATAR_MIN_WIDTH_PX, + maxHeightInPx: CONST.AVATAR_MAX_HEIGHT_PX, + maxWidthInPx: CONST.AVATAR_MAX_WIDTH_PX, + }); + return; + } + + setIsAvatarCropModalOpen(true); + setError(null, {}); + setIsMenuVisible(false); + setImageData({ + uri: image.uri, + name: image.name, + type: image.type }); - return; - } - - setIsAvatarCropModalOpen(true); - setValidationError(null); - setPhraseParam({}); - setIsMenuVisible(false); - setImageUri(image.uri); - setImageName(image.name); - setImageType(image.type); - }; + }; + + return new Promise((resolve, reject) => { + if (!isValidExtension(image)) { + setError('avatarWithImagePicker.notAllowedExtension', { + allowedExtensions: CONST.AVATAR_ALLOWED_EXTENSIONS + }); + reject(new Error('Invalid extension')); + } + + if (!isValidSize(image)) { + setError('avatarWithImagePicker.sizeExceeded', { + maxUploadSizeInMB: CONST.AVATAR_MAX_ATTACHMENT_SIZE / (1024 * 1024) + }); + reject(new Error('Invalid size')); + } + + resolve(image); + }) + .then(isValidResolution) + .then(handleResolutionValidation) + .catch(err => { + console.error("Error in showAvatarCropModal:", err); + }); + } const hideAvatarCropModal = () => { setIsAvatarCropModalOpen(false); @@ -358,10 +384,10 @@ function AvatarWithImagePicker({ )} - {validationError && ( + {errorData.validationError && ( )} @@ -369,9 +395,9 @@ function AvatarWithImagePicker({ onClose={hideAvatarCropModal} isVisible={isAvatarCropModalOpen} onSave={onImageSelected} - imageUri={imageUri} - imageName={imageName} - imageType={imageType} + imageUri={imageData.uri} + imageName={imageData.name} + imageType={imageData.type} maskImage={editorMaskImage} /> @@ -381,4 +407,4 @@ function AvatarWithImagePicker({ AvatarWithImagePicker.propTypes = propTypes; AvatarWithImagePicker.defaultProps = defaultProps; -export default compose(withLocalize, withNavigationFocus)(AvatarWithImagePicker); +export default withNavigationFocus(AvatarWithImagePicker); \ No newline at end of file From d1bf47c67a2787b8e2ac1d29be584638a74b8223 Mon Sep 17 00:00:00 2001 From: keisyrzk Date: Thu, 5 Oct 2023 06:37:50 +0200 Subject: [PATCH 016/237] remove podfile.lock --- ios/Podfile.lock | 1314 ---------------------------------------------- 1 file changed, 1314 deletions(-) delete mode 100644 ios/Podfile.lock diff --git a/ios/Podfile.lock b/ios/Podfile.lock deleted file mode 100644 index 747efb5f2fa7..000000000000 --- a/ios/Podfile.lock +++ /dev/null @@ -1,1314 +0,0 @@ -PODS: - - Airship (16.11.3): - - Airship/Automation (= 16.11.3) - - Airship/Basement (= 16.11.3) - - Airship/Core (= 16.11.3) - - Airship/ExtendedActions (= 16.11.3) - - Airship/MessageCenter (= 16.11.3) - - Airship/Automation (16.11.3): - - Airship/Core - - Airship/Basement (16.11.3) - - Airship/Core (16.11.3): - - Airship/Basement - - Airship/ExtendedActions (16.11.3): - - Airship/Core - - Airship/MessageCenter (16.11.3): - - Airship/Core - - Airship/PreferenceCenter (16.11.3): - - Airship/Core - - AirshipFrameworkProxy (2.0.8): - - Airship (= 16.11.3) - - Airship/MessageCenter (= 16.11.3) - - Airship/PreferenceCenter (= 16.11.3) - - AppAuth (1.6.2): - - AppAuth/Core (= 1.6.2) - - AppAuth/ExternalUserAgent (= 1.6.2) - - AppAuth/Core (1.6.2) - - AppAuth/ExternalUserAgent (1.6.2): - - AppAuth/Core - - boost (1.76.0) - - BVLinearGradient (2.8.1): - - React-Core - - CocoaAsyncSocket (7.6.5) - - DoubleConversion (1.1.6) - - FBLazyVector (0.72.4) - - FBReactNativeSpec (0.72.4): - - RCT-Folly (= 2021.07.22.00) - - RCTRequired (= 0.72.4) - - RCTTypeSafety (= 0.72.4) - - React-Core (= 0.72.4) - - React-jsi (= 0.72.4) - - ReactCommon/turbomodule/core (= 0.72.4) - - Firebase/Analytics (8.8.0): - - Firebase/Core - - Firebase/Core (8.8.0): - - Firebase/CoreOnly - - FirebaseAnalytics (~> 8.8.0) - - Firebase/CoreOnly (8.8.0): - - FirebaseCore (= 8.8.0) - - Firebase/Crashlytics (8.8.0): - - Firebase/CoreOnly - - FirebaseCrashlytics (~> 8.8.0) - - Firebase/Performance (8.8.0): - - Firebase/CoreOnly - - FirebasePerformance (~> 8.8.0) - - FirebaseABTesting (8.15.0): - - FirebaseCore (~> 8.0) - - FirebaseAnalytics (8.8.0): - - FirebaseAnalytics/AdIdSupport (= 8.8.0) - - FirebaseCore (~> 8.0) - - FirebaseInstallations (~> 8.0) - - GoogleUtilities/AppDelegateSwizzler (~> 7.4) - - GoogleUtilities/MethodSwizzler (~> 7.4) - - GoogleUtilities/Network (~> 7.4) - - "GoogleUtilities/NSData+zlib (~> 7.4)" - - nanopb (~> 2.30908.0) - - FirebaseAnalytics/AdIdSupport (8.8.0): - - FirebaseCore (~> 8.0) - - FirebaseInstallations (~> 8.0) - - GoogleAppMeasurement (= 8.8.0) - - GoogleUtilities/AppDelegateSwizzler (~> 7.4) - - GoogleUtilities/MethodSwizzler (~> 7.4) - - GoogleUtilities/Network (~> 7.4) - - "GoogleUtilities/NSData+zlib (~> 7.4)" - - nanopb (~> 2.30908.0) - - FirebaseCore (8.8.0): - - FirebaseCoreDiagnostics (~> 8.0) - - GoogleUtilities/Environment (~> 7.4) - - GoogleUtilities/Logger (~> 7.4) - - FirebaseCoreDiagnostics (8.15.0): - - GoogleDataTransport (~> 9.1) - - GoogleUtilities/Environment (~> 7.7) - - GoogleUtilities/Logger (~> 7.7) - - nanopb (~> 2.30908.0) - - FirebaseCrashlytics (8.8.0): - - FirebaseCore (~> 8.0) - - FirebaseInstallations (~> 8.0) - - GoogleDataTransport (~> 9.0) - - GoogleUtilities/Environment (~> 7.4) - - nanopb (~> 2.30908.0) - - PromisesObjC (< 3.0, >= 1.2) - - FirebaseInstallations (8.15.0): - - FirebaseCore (~> 8.0) - - GoogleUtilities/Environment (~> 7.7) - - GoogleUtilities/UserDefaults (~> 7.7) - - PromisesObjC (< 3.0, >= 1.2) - - FirebasePerformance (8.8.0): - - FirebaseCore (~> 8.0) - - FirebaseInstallations (~> 8.0) - - FirebaseRemoteConfig (~> 8.0) - - GoogleDataTransport (~> 9.0) - - GoogleUtilities/Environment (~> 7.4) - - GoogleUtilities/ISASwizzler (~> 7.4) - - GoogleUtilities/MethodSwizzler (~> 7.4) - - nanopb (~> 2.30908.0) - - FirebaseRemoteConfig (8.15.0): - - FirebaseABTesting (~> 8.0) - - FirebaseCore (~> 8.0) - - FirebaseInstallations (~> 8.0) - - GoogleUtilities/Environment (~> 7.7) - - "GoogleUtilities/NSData+zlib (~> 7.7)" - - Flipper (0.182.0): - - Flipper-Folly (~> 2.6) - - Flipper-Boost-iOSX (1.76.0.1.11) - - Flipper-DoubleConversion (3.2.0.1) - - Flipper-Fmt (7.1.7) - - Flipper-Folly (2.6.10): - - Flipper-Boost-iOSX - - Flipper-DoubleConversion - - Flipper-Fmt (= 7.1.7) - - Flipper-Glog - - libevent (~> 2.1.12) - - OpenSSL-Universal (= 1.1.1100) - - Flipper-Glog (0.5.0.5) - - Flipper-PeerTalk (0.0.4) - - FlipperKit (0.182.0): - - FlipperKit/Core (= 0.182.0) - - FlipperKit/Core (0.182.0): - - Flipper (~> 0.182.0) - - FlipperKit/CppBridge - - FlipperKit/FBCxxFollyDynamicConvert - - FlipperKit/FBDefines - - FlipperKit/FKPortForwarding - - SocketRocket (~> 0.6.0) - - FlipperKit/CppBridge (0.182.0): - - Flipper (~> 0.182.0) - - FlipperKit/FBCxxFollyDynamicConvert (0.182.0): - - Flipper-Folly (~> 2.6) - - FlipperKit/FBDefines (0.182.0) - - FlipperKit/FKPortForwarding (0.182.0): - - CocoaAsyncSocket (~> 7.6) - - Flipper-PeerTalk (~> 0.0.4) - - FlipperKit/FlipperKitHighlightOverlay (0.182.0) - - FlipperKit/FlipperKitLayoutHelpers (0.182.0): - - FlipperKit/Core - - FlipperKit/FlipperKitHighlightOverlay - - FlipperKit/FlipperKitLayoutTextSearchable - - FlipperKit/FlipperKitLayoutIOSDescriptors (0.182.0): - - FlipperKit/Core - - FlipperKit/FlipperKitHighlightOverlay - - FlipperKit/FlipperKitLayoutHelpers - - YogaKit (~> 1.18) - - FlipperKit/FlipperKitLayoutPlugin (0.182.0): - - FlipperKit/Core - - FlipperKit/FlipperKitHighlightOverlay - - FlipperKit/FlipperKitLayoutHelpers - - FlipperKit/FlipperKitLayoutIOSDescriptors - - FlipperKit/FlipperKitLayoutTextSearchable - - YogaKit (~> 1.18) - - FlipperKit/FlipperKitLayoutTextSearchable (0.182.0) - - FlipperKit/FlipperKitNetworkPlugin (0.182.0): - - FlipperKit/Core - - FlipperKit/FlipperKitReactPlugin (0.182.0): - - FlipperKit/Core - - FlipperKit/FlipperKitUserDefaultsPlugin (0.182.0): - - FlipperKit/Core - - FlipperKit/SKIOSNetworkPlugin (0.182.0): - - FlipperKit/Core - - FlipperKit/FlipperKitNetworkPlugin - - fmt (6.2.1) - - glog (0.3.5) - - GoogleAppMeasurement (8.8.0): - - GoogleAppMeasurement/AdIdSupport (= 8.8.0) - - GoogleUtilities/AppDelegateSwizzler (~> 7.4) - - GoogleUtilities/MethodSwizzler (~> 7.4) - - GoogleUtilities/Network (~> 7.4) - - "GoogleUtilities/NSData+zlib (~> 7.4)" - - nanopb (~> 2.30908.0) - - GoogleAppMeasurement/AdIdSupport (8.8.0): - - GoogleAppMeasurement/WithoutAdIdSupport (= 8.8.0) - - GoogleUtilities/AppDelegateSwizzler (~> 7.4) - - GoogleUtilities/MethodSwizzler (~> 7.4) - - GoogleUtilities/Network (~> 7.4) - - "GoogleUtilities/NSData+zlib (~> 7.4)" - - nanopb (~> 2.30908.0) - - GoogleAppMeasurement/WithoutAdIdSupport (8.8.0): - - GoogleUtilities/AppDelegateSwizzler (~> 7.4) - - GoogleUtilities/MethodSwizzler (~> 7.4) - - GoogleUtilities/Network (~> 7.4) - - "GoogleUtilities/NSData+zlib (~> 7.4)" - - nanopb (~> 2.30908.0) - - GoogleDataTransport (9.2.3): - - GoogleUtilities/Environment (~> 7.7) - - nanopb (< 2.30910.0, >= 2.30908.0) - - PromisesObjC (< 3.0, >= 1.2) - - GoogleSignIn (7.0.0): - - AppAuth (~> 1.5) - - GTMAppAuth (< 3.0, >= 1.3) - - GTMSessionFetcher/Core (< 4.0, >= 1.1) - - GoogleUtilities/AppDelegateSwizzler (7.11.1): - - GoogleUtilities/Environment - - GoogleUtilities/Logger - - GoogleUtilities/Network - - GoogleUtilities/Environment (7.11.1): - - PromisesObjC (< 3.0, >= 1.2) - - GoogleUtilities/ISASwizzler (7.11.1) - - GoogleUtilities/Logger (7.11.1): - - GoogleUtilities/Environment - - GoogleUtilities/MethodSwizzler (7.11.1): - - GoogleUtilities/Logger - - GoogleUtilities/Network (7.11.1): - - GoogleUtilities/Logger - - "GoogleUtilities/NSData+zlib" - - GoogleUtilities/Reachability - - "GoogleUtilities/NSData+zlib (7.11.1)" - - GoogleUtilities/Reachability (7.11.1): - - GoogleUtilities/Logger - - GoogleUtilities/UserDefaults (7.11.1): - - GoogleUtilities/Logger - - GTMAppAuth (2.0.0): - - AppAuth/Core (~> 1.6) - - GTMSessionFetcher/Core (< 4.0, >= 1.5) - - GTMSessionFetcher/Core (3.1.1) - - hermes-engine (0.72.4): - - hermes-engine/Pre-built (= 0.72.4) - - hermes-engine/Pre-built (0.72.4) - - libevent (2.1.12) - - libwebp (1.2.4): - - libwebp/demux (= 1.2.4) - - libwebp/mux (= 1.2.4) - - libwebp/webp (= 1.2.4) - - libwebp/demux (1.2.4): - - libwebp/webp - - libwebp/mux (1.2.4): - - libwebp/demux - - libwebp/webp (1.2.4) - - lottie-ios (3.4.4) - - lottie-react-native (5.1.6): - - lottie-ios (~> 3.4.0) - - React-Core - - MapboxCommon (23.6.0) - - MapboxCoreMaps (10.14.0): - - MapboxCommon (~> 23.6) - - MapboxMaps (10.14.0): - - MapboxCommon (= 23.6.0) - - MapboxCoreMaps (= 10.14.0) - - MapboxMobileEvents (= 1.0.10) - - Turf (~> 2.0) - - MapboxMobileEvents (1.0.10) - - nanopb (2.30908.0): - - nanopb/decode (= 2.30908.0) - - nanopb/encode (= 2.30908.0) - - nanopb/decode (2.30908.0) - - nanopb/encode (2.30908.0) - - Onfido (27.4.0) - - onfido-react-native-sdk (7.4.0): - - Onfido (= 27.4.0) - - React - - OpenSSL-Universal (1.1.1100) - - Permission-Camera (3.6.1): - - RNPermissions - - Permission-LocationAccuracy (3.6.1): - - RNPermissions - - Permission-LocationAlways (3.6.1): - - RNPermissions - - Permission-LocationWhenInUse (3.6.1): - - RNPermissions - - Plaid (4.1.0) - - PromisesObjC (2.2.0) - - RCT-Folly (2021.07.22.00): - - boost - - DoubleConversion - - fmt (~> 6.2.1) - - glog - - RCT-Folly/Default (= 2021.07.22.00) - - RCT-Folly/Default (2021.07.22.00): - - boost - - DoubleConversion - - fmt (~> 6.2.1) - - glog - - RCT-Folly/Futures (2021.07.22.00): - - boost - - DoubleConversion - - fmt (~> 6.2.1) - - glog - - libevent - - RCTRequired (0.72.4) - - RCTTypeSafety (0.72.4): - - FBLazyVector (= 0.72.4) - - RCTRequired (= 0.72.4) - - React-Core (= 0.72.4) - - React (0.72.4): - - React-Core (= 0.72.4) - - React-Core/DevSupport (= 0.72.4) - - React-Core/RCTWebSocket (= 0.72.4) - - React-RCTActionSheet (= 0.72.4) - - React-RCTAnimation (= 0.72.4) - - React-RCTBlob (= 0.72.4) - - React-RCTImage (= 0.72.4) - - React-RCTLinking (= 0.72.4) - - React-RCTNetwork (= 0.72.4) - - React-RCTSettings (= 0.72.4) - - React-RCTText (= 0.72.4) - - React-RCTVibration (= 0.72.4) - - React-callinvoker (0.72.4) - - React-Codegen (0.72.4): - - DoubleConversion - - FBReactNativeSpec - - glog - - hermes-engine - - RCT-Folly - - RCTRequired - - RCTTypeSafety - - React-Core - - React-jsi - - React-jsiexecutor - - React-NativeModulesApple - - React-rncore - - ReactCommon/turbomodule/bridging - - ReactCommon/turbomodule/core - - React-Core (0.72.4): - - glog - - hermes-engine - - RCT-Folly (= 2021.07.22.00) - - React-Core/Default (= 0.72.4) - - React-cxxreact - - React-hermes - - React-jsi - - React-jsiexecutor - - React-perflogger - - React-runtimeexecutor - - React-utils - - SocketRocket (= 0.6.1) - - Yoga - - React-Core/CoreModulesHeaders (0.72.4): - - glog - - hermes-engine - - RCT-Folly (= 2021.07.22.00) - - React-Core/Default - - React-cxxreact - - React-hermes - - React-jsi - - React-jsiexecutor - - React-perflogger - - React-runtimeexecutor - - React-utils - - SocketRocket (= 0.6.1) - - Yoga - - React-Core/Default (0.72.4): - - glog - - hermes-engine - - RCT-Folly (= 2021.07.22.00) - - React-cxxreact - - React-hermes - - React-jsi - - React-jsiexecutor - - React-perflogger - - React-runtimeexecutor - - React-utils - - SocketRocket (= 0.6.1) - - Yoga - - React-Core/DevSupport (0.72.4): - - glog - - hermes-engine - - RCT-Folly (= 2021.07.22.00) - - React-Core/Default (= 0.72.4) - - React-Core/RCTWebSocket (= 0.72.4) - - React-cxxreact - - React-hermes - - React-jsi - - React-jsiexecutor - - React-jsinspector (= 0.72.4) - - React-perflogger - - React-runtimeexecutor - - React-utils - - SocketRocket (= 0.6.1) - - Yoga - - React-Core/RCTActionSheetHeaders (0.72.4): - - glog - - hermes-engine - - RCT-Folly (= 2021.07.22.00) - - React-Core/Default - - React-cxxreact - - React-hermes - - React-jsi - - React-jsiexecutor - - React-perflogger - - React-runtimeexecutor - - React-utils - - SocketRocket (= 0.6.1) - - Yoga - - React-Core/RCTAnimationHeaders (0.72.4): - - glog - - hermes-engine - - RCT-Folly (= 2021.07.22.00) - - React-Core/Default - - React-cxxreact - - React-hermes - - React-jsi - - React-jsiexecutor - - React-perflogger - - React-runtimeexecutor - - React-utils - - SocketRocket (= 0.6.1) - - Yoga - - React-Core/RCTBlobHeaders (0.72.4): - - glog - - hermes-engine - - RCT-Folly (= 2021.07.22.00) - - React-Core/Default - - React-cxxreact - - React-hermes - - React-jsi - - React-jsiexecutor - - React-perflogger - - React-runtimeexecutor - - React-utils - - SocketRocket (= 0.6.1) - - Yoga - - React-Core/RCTImageHeaders (0.72.4): - - glog - - hermes-engine - - RCT-Folly (= 2021.07.22.00) - - React-Core/Default - - React-cxxreact - - React-hermes - - React-jsi - - React-jsiexecutor - - React-perflogger - - React-runtimeexecutor - - React-utils - - SocketRocket (= 0.6.1) - - Yoga - - React-Core/RCTLinkingHeaders (0.72.4): - - glog - - hermes-engine - - RCT-Folly (= 2021.07.22.00) - - React-Core/Default - - React-cxxreact - - React-hermes - - React-jsi - - React-jsiexecutor - - React-perflogger - - React-runtimeexecutor - - React-utils - - SocketRocket (= 0.6.1) - - Yoga - - React-Core/RCTNetworkHeaders (0.72.4): - - glog - - hermes-engine - - RCT-Folly (= 2021.07.22.00) - - React-Core/Default - - React-cxxreact - - React-hermes - - React-jsi - - React-jsiexecutor - - React-perflogger - - React-runtimeexecutor - - React-utils - - SocketRocket (= 0.6.1) - - Yoga - - React-Core/RCTSettingsHeaders (0.72.4): - - glog - - hermes-engine - - RCT-Folly (= 2021.07.22.00) - - React-Core/Default - - React-cxxreact - - React-hermes - - React-jsi - - React-jsiexecutor - - React-perflogger - - React-runtimeexecutor - - React-utils - - SocketRocket (= 0.6.1) - - Yoga - - React-Core/RCTTextHeaders (0.72.4): - - glog - - hermes-engine - - RCT-Folly (= 2021.07.22.00) - - React-Core/Default - - React-cxxreact - - React-hermes - - React-jsi - - React-jsiexecutor - - React-perflogger - - React-runtimeexecutor - - React-utils - - SocketRocket (= 0.6.1) - - Yoga - - React-Core/RCTVibrationHeaders (0.72.4): - - glog - - hermes-engine - - RCT-Folly (= 2021.07.22.00) - - React-Core/Default - - React-cxxreact - - React-hermes - - React-jsi - - React-jsiexecutor - - React-perflogger - - React-runtimeexecutor - - React-utils - - SocketRocket (= 0.6.1) - - Yoga - - React-Core/RCTWebSocket (0.72.4): - - glog - - hermes-engine - - RCT-Folly (= 2021.07.22.00) - - React-Core/Default (= 0.72.4) - - React-cxxreact - - React-hermes - - React-jsi - - React-jsiexecutor - - React-perflogger - - React-runtimeexecutor - - React-utils - - SocketRocket (= 0.6.1) - - Yoga - - React-CoreModules (0.72.4): - - RCT-Folly (= 2021.07.22.00) - - RCTTypeSafety (= 0.72.4) - - React-Codegen (= 0.72.4) - - React-Core/CoreModulesHeaders (= 0.72.4) - - React-jsi (= 0.72.4) - - React-RCTBlob - - React-RCTImage (= 0.72.4) - - ReactCommon/turbomodule/core (= 0.72.4) - - SocketRocket (= 0.6.1) - - React-cxxreact (0.72.4): - - boost (= 1.76.0) - - DoubleConversion - - glog - - hermes-engine - - RCT-Folly (= 2021.07.22.00) - - React-callinvoker (= 0.72.4) - - React-debug (= 0.72.4) - - React-jsi (= 0.72.4) - - React-jsinspector (= 0.72.4) - - React-logger (= 0.72.4) - - React-perflogger (= 0.72.4) - - React-runtimeexecutor (= 0.72.4) - - React-debug (0.72.4) - - React-hermes (0.72.4): - - DoubleConversion - - glog - - hermes-engine - - RCT-Folly (= 2021.07.22.00) - - RCT-Folly/Futures (= 2021.07.22.00) - - React-cxxreact (= 0.72.4) - - React-jsi - - React-jsiexecutor (= 0.72.4) - - React-jsinspector (= 0.72.4) - - React-perflogger (= 0.72.4) - - React-jsi (0.72.4): - - boost (= 1.76.0) - - DoubleConversion - - glog - - hermes-engine - - RCT-Folly (= 2021.07.22.00) - - React-jsiexecutor (0.72.4): - - DoubleConversion - - glog - - hermes-engine - - RCT-Folly (= 2021.07.22.00) - - React-cxxreact (= 0.72.4) - - React-jsi (= 0.72.4) - - React-perflogger (= 0.72.4) - - React-jsinspector (0.72.4) - - React-logger (0.72.4): - - glog - - react-native-airship (15.2.6): - - AirshipFrameworkProxy (= 2.0.8) - - React-Core - - react-native-blob-util (0.17.3): - - React-Core - - react-native-cameraroll (5.4.0): - - React-Core - - react-native-config (1.4.6): - - react-native-config/App (= 1.4.6) - - react-native-config/App (1.4.6): - - React-Core - - react-native-document-picker (8.1.1): - - React-Core - - react-native-flipper (0.159.0): - - React-Core - - react-native-image-manipulator (1.0.5): - - React - - react-native-image-picker (5.1.0): - - React-Core - - react-native-key-command (1.0.1): - - React-Core - - react-native-netinfo (9.3.10): - - React-Core - - react-native-pager-view (6.2.0): - - React-Core - - react-native-pdf (6.7.1): - - React-Core - - react-native-performance (5.1.0): - - React-Core - - react-native-plaid-link-sdk (10.0.0): - - Plaid (~> 4.1.0) - - React-Core - - react-native-quick-sqlite (8.0.0-beta.2): - - React - - React-callinvoker - - React-Core - - react-native-render-html (6.3.1): - - React-Core - - react-native-safe-area-context (4.4.1): - - RCT-Folly - - RCTRequired - - RCTTypeSafety - - React-Core - - ReactCommon/turbomodule/core - - react-native-view-shot (3.6.0): - - React-Core - - react-native-webview (11.23.0): - - React-Core - - React-NativeModulesApple (0.72.4): - - hermes-engine - - React-callinvoker - - React-Core - - React-cxxreact - - React-jsi - - React-runtimeexecutor - - ReactCommon/turbomodule/bridging - - ReactCommon/turbomodule/core - - React-perflogger (0.72.4) - - React-RCTActionSheet (0.72.4): - - React-Core/RCTActionSheetHeaders (= 0.72.4) - - React-RCTAnimation (0.72.4): - - RCT-Folly (= 2021.07.22.00) - - RCTTypeSafety (= 0.72.4) - - React-Codegen (= 0.72.4) - - React-Core/RCTAnimationHeaders (= 0.72.4) - - React-jsi (= 0.72.4) - - ReactCommon/turbomodule/core (= 0.72.4) - - React-RCTAppDelegate (0.72.4): - - RCT-Folly - - RCTRequired - - RCTTypeSafety - - React-Core - - React-CoreModules - - React-hermes - - React-NativeModulesApple - - React-RCTImage - - React-RCTNetwork - - React-runtimescheduler - - ReactCommon/turbomodule/core - - React-RCTBlob (0.72.4): - - hermes-engine - - RCT-Folly (= 2021.07.22.00) - - React-Codegen (= 0.72.4) - - React-Core/RCTBlobHeaders (= 0.72.4) - - React-Core/RCTWebSocket (= 0.72.4) - - React-jsi (= 0.72.4) - - React-RCTNetwork (= 0.72.4) - - ReactCommon/turbomodule/core (= 0.72.4) - - React-RCTImage (0.72.4): - - RCT-Folly (= 2021.07.22.00) - - RCTTypeSafety (= 0.72.4) - - React-Codegen (= 0.72.4) - - React-Core/RCTImageHeaders (= 0.72.4) - - React-jsi (= 0.72.4) - - React-RCTNetwork (= 0.72.4) - - ReactCommon/turbomodule/core (= 0.72.4) - - React-RCTLinking (0.72.4): - - React-Codegen (= 0.72.4) - - React-Core/RCTLinkingHeaders (= 0.72.4) - - React-jsi (= 0.72.4) - - ReactCommon/turbomodule/core (= 0.72.4) - - React-RCTNetwork (0.72.4): - - RCT-Folly (= 2021.07.22.00) - - RCTTypeSafety (= 0.72.4) - - React-Codegen (= 0.72.4) - - React-Core/RCTNetworkHeaders (= 0.72.4) - - React-jsi (= 0.72.4) - - ReactCommon/turbomodule/core (= 0.72.4) - - React-RCTSettings (0.72.4): - - RCT-Folly (= 2021.07.22.00) - - RCTTypeSafety (= 0.72.4) - - React-Codegen (= 0.72.4) - - React-Core/RCTSettingsHeaders (= 0.72.4) - - React-jsi (= 0.72.4) - - ReactCommon/turbomodule/core (= 0.72.4) - - React-RCTText (0.72.4): - - React-Core/RCTTextHeaders (= 0.72.4) - - React-RCTVibration (0.72.4): - - RCT-Folly (= 2021.07.22.00) - - React-Codegen (= 0.72.4) - - React-Core/RCTVibrationHeaders (= 0.72.4) - - React-jsi (= 0.72.4) - - ReactCommon/turbomodule/core (= 0.72.4) - - React-rncore (0.72.4) - - React-runtimeexecutor (0.72.4): - - React-jsi (= 0.72.4) - - React-runtimescheduler (0.72.4): - - glog - - hermes-engine - - RCT-Folly (= 2021.07.22.00) - - React-callinvoker - - React-debug - - React-jsi - - React-runtimeexecutor - - React-utils (0.72.4): - - glog - - RCT-Folly (= 2021.07.22.00) - - React-debug - - ReactCommon/turbomodule/bridging (0.72.4): - - DoubleConversion - - glog - - hermes-engine - - RCT-Folly (= 2021.07.22.00) - - React-callinvoker (= 0.72.4) - - React-cxxreact (= 0.72.4) - - React-jsi (= 0.72.4) - - React-logger (= 0.72.4) - - React-perflogger (= 0.72.4) - - ReactCommon/turbomodule/core (0.72.4): - - DoubleConversion - - glog - - hermes-engine - - RCT-Folly (= 2021.07.22.00) - - React-callinvoker (= 0.72.4) - - React-cxxreact (= 0.72.4) - - React-jsi (= 0.72.4) - - React-logger (= 0.72.4) - - React-perflogger (= 0.72.4) - - RNAppleAuthentication (2.2.2): - - React-Core - - RNCAsyncStorage (1.17.11): - - React-Core - - RNCClipboard (1.5.1): - - React-Core - - RNCPicker (2.4.4): - - React-Core - - RNDateTimePicker (3.5.2): - - React-Core - - RNDeviceInfo (10.3.0): - - React-Core - - RNDevMenu (4.1.1): - - React-Core - - React-Core/DevSupport - - React-RCTNetwork - - RNFastImage (8.6.3): - - React-Core - - SDWebImage (~> 5.11.1) - - SDWebImageWebPCoder (~> 0.8.4) - - RNFBAnalytics (12.9.3): - - Firebase/Analytics (= 8.8.0) - - React-Core - - RNFBApp - - RNFBApp (12.9.3): - - Firebase/CoreOnly (= 8.8.0) - - React-Core - - RNFBCrashlytics (12.9.3): - - Firebase/Crashlytics (= 8.8.0) - - React-Core - - RNFBApp - - RNFBPerf (12.9.3): - - Firebase/Performance (= 8.8.0) - - React-Core - - RNFBApp - - RNFS (2.20.0): - - React-Core - - RNGestureHandler (2.12.0): - - React-Core - - RNGoogleSignin (10.0.1): - - GoogleSignIn (~> 7.0) - - React-Core - - RNLocalize (2.2.6): - - React-Core - - rnmapbox-maps (10.0.11): - - MapboxMaps (~> 10.14.0) - - React - - React-Core - - rnmapbox-maps/DynamicLibrary (= 10.0.11) - - Turf - - rnmapbox-maps/DynamicLibrary (10.0.11): - - MapboxMaps (~> 10.14.0) - - React - - React-Core - - Turf - - RNPermissions (3.6.1): - - React-Core - - RNReactNativeHapticFeedback (1.14.0): - - React-Core - - RNReanimated (3.4.0): - - DoubleConversion - - FBLazyVector - - glog - - hermes-engine - - RCT-Folly - - RCTRequired - - RCTTypeSafety - - React-callinvoker - - React-Core - - React-Core/DevSupport - - React-Core/RCTWebSocket - - React-CoreModules - - React-cxxreact - - React-hermes - - React-jsi - - React-jsiexecutor - - React-jsinspector - - React-RCTActionSheet - - React-RCTAnimation - - React-RCTAppDelegate - - React-RCTBlob - - React-RCTImage - - React-RCTLinking - - React-RCTNetwork - - React-RCTSettings - - React-RCTText - - ReactCommon/turbomodule/core - - Yoga - - RNScreens (3.21.0): - - React-Core - - React-RCTImage - - RNSVG (13.13.0): - - React-Core - - SDWebImage (5.11.1): - - SDWebImage/Core (= 5.11.1) - - SDWebImage/Core (5.11.1) - - SDWebImageWebPCoder (0.8.5): - - libwebp (~> 1.0) - - SDWebImage/Core (~> 5.10) - - SocketRocket (0.6.1) - - Turf (2.6.1) - - VisionCamera (2.15.4): - - React - - React-callinvoker - - React-Core - - Yoga (1.14.0) - - YogaKit (1.18.1): - - Yoga (~> 1.14) - -DEPENDENCIES: - - boost (from `../node_modules/react-native/third-party-podspecs/boost.podspec`) - - BVLinearGradient (from `../node_modules/react-native-linear-gradient`) - - DoubleConversion (from `../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec`) - - FBLazyVector (from `../node_modules/react-native/Libraries/FBLazyVector`) - - FBReactNativeSpec (from `../node_modules/react-native/React/FBReactNativeSpec`) - - Flipper (= 0.182.0) - - Flipper-Boost-iOSX (= 1.76.0.1.11) - - Flipper-DoubleConversion (= 3.2.0.1) - - Flipper-Fmt (= 7.1.7) - - Flipper-Folly (= 2.6.10) - - Flipper-Glog (= 0.5.0.5) - - Flipper-PeerTalk (= 0.0.4) - - FlipperKit (= 0.182.0) - - FlipperKit/Core (= 0.182.0) - - FlipperKit/CppBridge (= 0.182.0) - - FlipperKit/FBCxxFollyDynamicConvert (= 0.182.0) - - FlipperKit/FBDefines (= 0.182.0) - - FlipperKit/FKPortForwarding (= 0.182.0) - - FlipperKit/FlipperKitHighlightOverlay (= 0.182.0) - - FlipperKit/FlipperKitLayoutPlugin (= 0.182.0) - - FlipperKit/FlipperKitLayoutTextSearchable (= 0.182.0) - - FlipperKit/FlipperKitNetworkPlugin (= 0.182.0) - - FlipperKit/FlipperKitReactPlugin (= 0.182.0) - - FlipperKit/FlipperKitUserDefaultsPlugin (= 0.182.0) - - FlipperKit/SKIOSNetworkPlugin (= 0.182.0) - - glog (from `../node_modules/react-native/third-party-podspecs/glog.podspec`) - - hermes-engine (from `../node_modules/react-native/sdks/hermes-engine/hermes-engine.podspec`) - - libevent (~> 2.1.12) - - lottie-react-native (from `../node_modules/lottie-react-native`) - - "onfido-react-native-sdk (from `../node_modules/@onfido/react-native-sdk`)" - - OpenSSL-Universal (= 1.1.1100) - - Permission-Camera (from `../node_modules/react-native-permissions/ios/Camera`) - - Permission-LocationAccuracy (from `../node_modules/react-native-permissions/ios/LocationAccuracy`) - - Permission-LocationAlways (from `../node_modules/react-native-permissions/ios/LocationAlways`) - - Permission-LocationWhenInUse (from `../node_modules/react-native-permissions/ios/LocationWhenInUse`) - - RCT-Folly (from `../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec`) - - RCTRequired (from `../node_modules/react-native/Libraries/RCTRequired`) - - RCTTypeSafety (from `../node_modules/react-native/Libraries/TypeSafety`) - - React (from `../node_modules/react-native/`) - - React-callinvoker (from `../node_modules/react-native/ReactCommon/callinvoker`) - - React-Codegen (from `build/generated/ios`) - - React-Core (from `../node_modules/react-native/`) - - React-Core/DevSupport (from `../node_modules/react-native/`) - - React-Core/RCTWebSocket (from `../node_modules/react-native/`) - - React-CoreModules (from `../node_modules/react-native/React/CoreModules`) - - React-cxxreact (from `../node_modules/react-native/ReactCommon/cxxreact`) - - React-debug (from `../node_modules/react-native/ReactCommon/react/debug`) - - React-hermes (from `../node_modules/react-native/ReactCommon/hermes`) - - React-jsi (from `../node_modules/react-native/ReactCommon/jsi`) - - React-jsiexecutor (from `../node_modules/react-native/ReactCommon/jsiexecutor`) - - React-jsinspector (from `../node_modules/react-native/ReactCommon/jsinspector`) - - React-logger (from `../node_modules/react-native/ReactCommon/logger`) - - "react-native-airship (from `../node_modules/@ua/react-native-airship`)" - - react-native-blob-util (from `../node_modules/react-native-blob-util`) - - "react-native-cameraroll (from `../node_modules/@react-native-camera-roll/camera-roll`)" - - react-native-config (from `../node_modules/react-native-config`) - - react-native-document-picker (from `../node_modules/react-native-document-picker`) - - react-native-flipper (from `../node_modules/react-native-flipper`) - - "react-native-image-manipulator (from `../node_modules/@oguzhnatly/react-native-image-manipulator`)" - - react-native-image-picker (from `../node_modules/react-native-image-picker`) - - react-native-key-command (from `../node_modules/react-native-key-command`) - - "react-native-netinfo (from `../node_modules/@react-native-community/netinfo`)" - - react-native-pager-view (from `../node_modules/react-native-pager-view`) - - react-native-pdf (from `../node_modules/react-native-pdf`) - - react-native-performance (from `../node_modules/react-native-performance`) - - react-native-plaid-link-sdk (from `../node_modules/react-native-plaid-link-sdk`) - - react-native-quick-sqlite (from `../node_modules/react-native-quick-sqlite`) - - react-native-render-html (from `../node_modules/react-native-render-html`) - - react-native-safe-area-context (from `../node_modules/react-native-safe-area-context`) - - react-native-view-shot (from `../node_modules/react-native-view-shot`) - - react-native-webview (from `../node_modules/react-native-webview`) - - React-NativeModulesApple (from `../node_modules/react-native/ReactCommon/react/nativemodule/core/platform/ios`) - - React-perflogger (from `../node_modules/react-native/ReactCommon/reactperflogger`) - - React-RCTActionSheet (from `../node_modules/react-native/Libraries/ActionSheetIOS`) - - React-RCTAnimation (from `../node_modules/react-native/Libraries/NativeAnimation`) - - React-RCTAppDelegate (from `../node_modules/react-native/Libraries/AppDelegate`) - - React-RCTBlob (from `../node_modules/react-native/Libraries/Blob`) - - React-RCTImage (from `../node_modules/react-native/Libraries/Image`) - - React-RCTLinking (from `../node_modules/react-native/Libraries/LinkingIOS`) - - React-RCTNetwork (from `../node_modules/react-native/Libraries/Network`) - - React-RCTSettings (from `../node_modules/react-native/Libraries/Settings`) - - React-RCTText (from `../node_modules/react-native/Libraries/Text`) - - React-RCTVibration (from `../node_modules/react-native/Libraries/Vibration`) - - React-rncore (from `../node_modules/react-native/ReactCommon`) - - React-runtimeexecutor (from `../node_modules/react-native/ReactCommon/runtimeexecutor`) - - React-runtimescheduler (from `../node_modules/react-native/ReactCommon/react/renderer/runtimescheduler`) - - React-utils (from `../node_modules/react-native/ReactCommon/react/utils`) - - ReactCommon/turbomodule/core (from `../node_modules/react-native/ReactCommon`) - - "RNAppleAuthentication (from `../node_modules/@invertase/react-native-apple-authentication`)" - - "RNCAsyncStorage (from `../node_modules/@react-native-async-storage/async-storage`)" - - "RNCClipboard (from `../node_modules/@react-native-community/clipboard`)" - - "RNCPicker (from `../node_modules/@react-native-picker/picker`)" - - "RNDateTimePicker (from `../node_modules/@react-native-community/datetimepicker`)" - - RNDeviceInfo (from `../node_modules/react-native-device-info`) - - RNDevMenu (from `../node_modules/react-native-dev-menu`) - - RNFastImage (from `../node_modules/react-native-fast-image`) - - "RNFBAnalytics (from `../node_modules/@react-native-firebase/analytics`)" - - "RNFBApp (from `../node_modules/@react-native-firebase/app`)" - - "RNFBCrashlytics (from `../node_modules/@react-native-firebase/crashlytics`)" - - "RNFBPerf (from `../node_modules/@react-native-firebase/perf`)" - - RNFS (from `../node_modules/react-native-fs`) - - RNGestureHandler (from `../node_modules/react-native-gesture-handler`) - - "RNGoogleSignin (from `../node_modules/@react-native-google-signin/google-signin`)" - - RNLocalize (from `../node_modules/react-native-localize`) - - "rnmapbox-maps (from `../node_modules/@rnmapbox/maps`)" - - RNPermissions (from `../node_modules/react-native-permissions`) - - RNReactNativeHapticFeedback (from `../node_modules/react-native-haptic-feedback`) - - RNReanimated (from `../node_modules/react-native-reanimated`) - - RNScreens (from `../node_modules/react-native-screens`) - - RNSVG (from `../node_modules/react-native-svg`) - - VisionCamera (from `../node_modules/react-native-vision-camera`) - - Yoga (from `../node_modules/react-native/ReactCommon/yoga`) - -SPEC REPOS: - trunk: - - Airship - - AirshipFrameworkProxy - - AppAuth - - CocoaAsyncSocket - - Firebase - - FirebaseABTesting - - FirebaseAnalytics - - FirebaseCore - - FirebaseCoreDiagnostics - - FirebaseCrashlytics - - FirebaseInstallations - - FirebasePerformance - - FirebaseRemoteConfig - - Flipper - - Flipper-Boost-iOSX - - Flipper-DoubleConversion - - Flipper-Fmt - - Flipper-Folly - - Flipper-Glog - - Flipper-PeerTalk - - FlipperKit - - fmt - - GoogleAppMeasurement - - GoogleDataTransport - - GoogleSignIn - - GoogleUtilities - - GTMAppAuth - - GTMSessionFetcher - - libevent - - libwebp - - lottie-ios - - MapboxCommon - - MapboxCoreMaps - - MapboxMaps - - MapboxMobileEvents - - nanopb - - Onfido - - OpenSSL-Universal - - Plaid - - PromisesObjC - - SDWebImage - - SDWebImageWebPCoder - - SocketRocket - - Turf - - YogaKit - -EXTERNAL SOURCES: - boost: - :podspec: "../node_modules/react-native/third-party-podspecs/boost.podspec" - BVLinearGradient: - :path: "../node_modules/react-native-linear-gradient" - DoubleConversion: - :podspec: "../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec" - FBLazyVector: - :path: "../node_modules/react-native/Libraries/FBLazyVector" - FBReactNativeSpec: - :path: "../node_modules/react-native/React/FBReactNativeSpec" - glog: - :podspec: "../node_modules/react-native/third-party-podspecs/glog.podspec" - hermes-engine: - :podspec: "../node_modules/react-native/sdks/hermes-engine/hermes-engine.podspec" - :tag: hermes-2023-08-07-RNv0.72.4-813b2def12bc9df02654b3e3653ae4a68d0572e0 - lottie-react-native: - :path: "../node_modules/lottie-react-native" - onfido-react-native-sdk: - :path: "../node_modules/@onfido/react-native-sdk" - Permission-Camera: - :path: "../node_modules/react-native-permissions/ios/Camera" - Permission-LocationAccuracy: - :path: "../node_modules/react-native-permissions/ios/LocationAccuracy" - Permission-LocationAlways: - :path: "../node_modules/react-native-permissions/ios/LocationAlways" - Permission-LocationWhenInUse: - :path: "../node_modules/react-native-permissions/ios/LocationWhenInUse" - RCT-Folly: - :podspec: "../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec" - RCTRequired: - :path: "../node_modules/react-native/Libraries/RCTRequired" - RCTTypeSafety: - :path: "../node_modules/react-native/Libraries/TypeSafety" - React: - :path: "../node_modules/react-native/" - React-callinvoker: - :path: "../node_modules/react-native/ReactCommon/callinvoker" - React-Codegen: - :path: build/generated/ios - React-Core: - :path: "../node_modules/react-native/" - React-CoreModules: - :path: "../node_modules/react-native/React/CoreModules" - React-cxxreact: - :path: "../node_modules/react-native/ReactCommon/cxxreact" - React-debug: - :path: "../node_modules/react-native/ReactCommon/react/debug" - React-hermes: - :path: "../node_modules/react-native/ReactCommon/hermes" - React-jsi: - :path: "../node_modules/react-native/ReactCommon/jsi" - React-jsiexecutor: - :path: "../node_modules/react-native/ReactCommon/jsiexecutor" - React-jsinspector: - :path: "../node_modules/react-native/ReactCommon/jsinspector" - React-logger: - :path: "../node_modules/react-native/ReactCommon/logger" - react-native-airship: - :path: "../node_modules/@ua/react-native-airship" - react-native-blob-util: - :path: "../node_modules/react-native-blob-util" - react-native-cameraroll: - :path: "../node_modules/@react-native-camera-roll/camera-roll" - react-native-config: - :path: "../node_modules/react-native-config" - react-native-document-picker: - :path: "../node_modules/react-native-document-picker" - react-native-flipper: - :path: "../node_modules/react-native-flipper" - react-native-image-manipulator: - :path: "../node_modules/@oguzhnatly/react-native-image-manipulator" - react-native-image-picker: - :path: "../node_modules/react-native-image-picker" - react-native-key-command: - :path: "../node_modules/react-native-key-command" - react-native-netinfo: - :path: "../node_modules/@react-native-community/netinfo" - react-native-pager-view: - :path: "../node_modules/react-native-pager-view" - react-native-pdf: - :path: "../node_modules/react-native-pdf" - react-native-performance: - :path: "../node_modules/react-native-performance" - react-native-plaid-link-sdk: - :path: "../node_modules/react-native-plaid-link-sdk" - react-native-quick-sqlite: - :path: "../node_modules/react-native-quick-sqlite" - react-native-render-html: - :path: "../node_modules/react-native-render-html" - react-native-safe-area-context: - :path: "../node_modules/react-native-safe-area-context" - react-native-view-shot: - :path: "../node_modules/react-native-view-shot" - react-native-webview: - :path: "../node_modules/react-native-webview" - React-NativeModulesApple: - :path: "../node_modules/react-native/ReactCommon/react/nativemodule/core/platform/ios" - React-perflogger: - :path: "../node_modules/react-native/ReactCommon/reactperflogger" - React-RCTActionSheet: - :path: "../node_modules/react-native/Libraries/ActionSheetIOS" - React-RCTAnimation: - :path: "../node_modules/react-native/Libraries/NativeAnimation" - React-RCTAppDelegate: - :path: "../node_modules/react-native/Libraries/AppDelegate" - React-RCTBlob: - :path: "../node_modules/react-native/Libraries/Blob" - React-RCTImage: - :path: "../node_modules/react-native/Libraries/Image" - React-RCTLinking: - :path: "../node_modules/react-native/Libraries/LinkingIOS" - React-RCTNetwork: - :path: "../node_modules/react-native/Libraries/Network" - React-RCTSettings: - :path: "../node_modules/react-native/Libraries/Settings" - React-RCTText: - :path: "../node_modules/react-native/Libraries/Text" - React-RCTVibration: - :path: "../node_modules/react-native/Libraries/Vibration" - React-rncore: - :path: "../node_modules/react-native/ReactCommon" - React-runtimeexecutor: - :path: "../node_modules/react-native/ReactCommon/runtimeexecutor" - React-runtimescheduler: - :path: "../node_modules/react-native/ReactCommon/react/renderer/runtimescheduler" - React-utils: - :path: "../node_modules/react-native/ReactCommon/react/utils" - ReactCommon: - :path: "../node_modules/react-native/ReactCommon" - RNAppleAuthentication: - :path: "../node_modules/@invertase/react-native-apple-authentication" - RNCAsyncStorage: - :path: "../node_modules/@react-native-async-storage/async-storage" - RNCClipboard: - :path: "../node_modules/@react-native-community/clipboard" - RNCPicker: - :path: "../node_modules/@react-native-picker/picker" - RNDateTimePicker: - :path: "../node_modules/@react-native-community/datetimepicker" - RNDeviceInfo: - :path: "../node_modules/react-native-device-info" - RNDevMenu: - :path: "../node_modules/react-native-dev-menu" - RNFastImage: - :path: "../node_modules/react-native-fast-image" - RNFBAnalytics: - :path: "../node_modules/@react-native-firebase/analytics" - RNFBApp: - :path: "../node_modules/@react-native-firebase/app" - RNFBCrashlytics: - :path: "../node_modules/@react-native-firebase/crashlytics" - RNFBPerf: - :path: "../node_modules/@react-native-firebase/perf" - RNFS: - :path: "../node_modules/react-native-fs" - RNGestureHandler: - :path: "../node_modules/react-native-gesture-handler" - RNGoogleSignin: - :path: "../node_modules/@react-native-google-signin/google-signin" - RNLocalize: - :path: "../node_modules/react-native-localize" - rnmapbox-maps: - :path: "../node_modules/@rnmapbox/maps" - RNPermissions: - :path: "../node_modules/react-native-permissions" - RNReactNativeHapticFeedback: - :path: "../node_modules/react-native-haptic-feedback" - RNReanimated: - :path: "../node_modules/react-native-reanimated" - RNScreens: - :path: "../node_modules/react-native-screens" - RNSVG: - :path: "../node_modules/react-native-svg" - VisionCamera: - :path: "../node_modules/react-native-vision-camera" - Yoga: - :path: "../node_modules/react-native/ReactCommon/yoga" - -SPEC CHECKSUMS: - Airship: c70eed50e429f97f5adb285423c7291fb7a032ae - AirshipFrameworkProxy: 7bc4130c668c6c98e2d4c60fe4c9eb61a999be99 - AppAuth: 3bb1d1cd9340bd09f5ed189fb00b1cc28e1e8570 - boost: 57d2868c099736d80fcd648bf211b4431e51a558 - BVLinearGradient: 421743791a59d259aec53f4c58793aad031da2ca - CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99 - DoubleConversion: 5189b271737e1565bdce30deb4a08d647e3f5f54 - FBLazyVector: 5d4a3b7f411219a45a6d952f77d2c0a6c9989da5 - FBReactNativeSpec: 3fc2d478e1c4b08276f9dd9128f80ec6d5d85c1f - Firebase: 629510f1a9ddb235f3a7c5c8ceb23ba887f0f814 - FirebaseABTesting: 10cbce8db9985ae2e3847ea44e9947dd18f94e10 - FirebaseAnalytics: 5506ea8b867d8423485a84b4cd612d279f7b0b8a - FirebaseCore: 98b29e3828f0a53651c363937a7f7d92a19f1ba2 - FirebaseCoreDiagnostics: 92e07a649aeb66352b319d43bdd2ee3942af84cb - FirebaseCrashlytics: 3660c045c8e45cc4276110562a0ef44cf43c8157 - FirebaseInstallations: 40bd9054049b2eae9a2c38ef1c3dd213df3605cd - FirebasePerformance: 0c01a7a496657d7cea86d40c0b1725259d164c6c - FirebaseRemoteConfig: 2d6e2cfdb49af79535c8af8a80a4a5009038ec2b - Flipper: 6edb735e6c3e332975d1b17956bcc584eccf5818 - Flipper-Boost-iOSX: fd1e2b8cbef7e662a122412d7ac5f5bea715403c - Flipper-DoubleConversion: 2dc99b02f658daf147069aad9dbd29d8feb06d30 - Flipper-Fmt: 60cbdd92fc254826e61d669a5d87ef7015396a9b - Flipper-Folly: 584845625005ff068a6ebf41f857f468decd26b3 - Flipper-Glog: 70c50ce58ddaf67dc35180db05f191692570f446 - Flipper-PeerTalk: 116d8f857dc6ef55c7a5a75ea3ceaafe878aadc9 - FlipperKit: 2efad7007d6745a3f95e4034d547be637f89d3f6 - fmt: ff9d55029c625d3757ed641535fd4a75fedc7ce9 - glog: 04b94705f318337d7ead9e6d17c019bd9b1f6b1b - GoogleAppMeasurement: 5ba1164e3c844ba84272555e916d0a6d3d977e91 - GoogleDataTransport: f0308f5905a745f94fb91fea9c6cbaf3831cb1bd - GoogleSignIn: b232380cf495a429b8095d3178a8d5855b42e842 - GoogleUtilities: 9aa0ad5a7bc171f8bae016300bfcfa3fb8425749 - GTMAppAuth: 99fb010047ba3973b7026e45393f51f27ab965ae - GTMSessionFetcher: e8647203b65cee28c5f73d0f473d096653945e72 - hermes-engine: 81191603c4eaa01f5e4ae5737a9efcf64756c7b2 - libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913 - libwebp: f62cb61d0a484ba548448a4bd52aabf150ff6eef - lottie-ios: 8f97d3271e155c2d688875c29cd3c74908aef5f8 - lottie-react-native: 8f9d4be452e23f6e5ca0fdc11669dc99ab52be81 - MapboxCommon: 4a0251dd470ee37e7fadda8e285c01921a5e1eb0 - MapboxCoreMaps: eb07203bbb0b1509395db5ab89cd3ad6c2e3c04c - MapboxMaps: af50ec61a7eb3b032c3f7962c6bd671d93d2a209 - MapboxMobileEvents: de50b3a4de180dd129c326e09cd12c8adaaa46d6 - nanopb: a0ba3315591a9ae0a16a309ee504766e90db0c96 - Onfido: e36f284b865adcf99d9c905590a64ac09d4a576b - onfido-react-native-sdk: 4ecde1a97435dcff9f00a878e3f8d1eb14fabbdc - OpenSSL-Universal: ebc357f1e6bc71fa463ccb2fe676756aff50e88c - Permission-Camera: bf6791b17c7f614b6826019fcfdcc286d3a107f6 - Permission-LocationAccuracy: 76df17de5c6b8bc2eee34e61ee92cdd7a864c73d - Permission-LocationAlways: 8d99b025c9f73c696e0cdb367e42525f2e9a26f2 - Permission-LocationWhenInUse: 3ba99e45c852763f730eabecec2870c2382b7bd4 - Plaid: 7d340abeadb46c7aa1a91f896c5b22395a31fcf2 - PromisesObjC: 09985d6d70fbe7878040aa746d78236e6946d2ef - RCT-Folly: 424b8c9a7a0b9ab2886ffe9c3b041ef628fd4fb1 - RCTRequired: c0569ecc035894e4a68baecb30fe6a7ea6e399f9 - RCTTypeSafety: e90354072c21236e0bcf1699011e39acd25fea2f - React: a1be3c6dc0a6e949ccd3e659781aa47bbae1868f - React-callinvoker: 1020b33f6cb1a1824f9ca2a86609fbce2a73c6ed - React-Codegen: a0a26badf098d4a779acda922caf74f6ecabed28 - React-Core: 52075b80f10c26f62219d7b5d13d7d8089f027b3 - React-CoreModules: 21abab85d7ad9038ce2b1c33d39e3baaf7dc9244 - React-cxxreact: 4ad1cc861e32fb533dad6ff7a4ea25680fa1c994 - React-debug: 17366a3d5c5d2f5fc04f09101a4af38cb42b54ae - React-hermes: 37377d0a56aa0cf55c65248271866ce3268cde3f - React-jsi: 6de8b0ccc6b765b58e4eee9ee38049dbeaf5c221 - React-jsiexecutor: c7f826e40fa9cab5d37cab6130b1af237332b594 - React-jsinspector: aaed4cf551c4a1c98092436518c2d267b13a673f - React-logger: da1ebe05ae06eb6db4b162202faeafac4b435e77 - react-native-airship: 5d19f4ba303481cf4101ff9dee9249ef6a8a6b64 - react-native-blob-util: 99f4d79189252f597fe0d810c57a3733b1b1dea6 - react-native-cameraroll: 8ffb0af7a5e5de225fd667610e2979fc1f0c2151 - react-native-config: 7cd105e71d903104e8919261480858940a6b9c0e - react-native-document-picker: f68191637788994baed5f57d12994aa32cf8bf88 - react-native-flipper: dc5290261fbeeb2faec1bdc57ae6dd8d562e1de4 - react-native-image-manipulator: c48f64221cfcd46e9eec53619c4c0374f3328a56 - react-native-image-picker: c33d4e79f0a14a2b66e5065e14946ae63749660b - react-native-key-command: c2645ec01eb1fa664606c09480c05cb4220ef67b - react-native-netinfo: ccbe1085dffd16592791d550189772e13bf479e2 - react-native-pager-view: 0ccb8bf60e2ebd38b1f3669fa3650ecce81db2df - react-native-pdf: 7c0e91ada997bac8bac3bb5bea5b6b81f5a3caae - react-native-performance: cef2b618d47b277fb5c3280b81a3aad1e72f2886 - react-native-plaid-link-sdk: 9eb0f71dad94b3bdde649c7a384cba93024af46c - react-native-quick-sqlite: bcc7a7a250a40222f18913a97cd356bf82d0a6c4 - react-native-render-html: 96c979fe7452a0a41559685d2f83b12b93edac8c - react-native-safe-area-context: 99b24a0c5acd0d5dcac2b1a7f18c49ea317be99a - react-native-view-shot: 705f999ac2a24e4e6c909c0ca65c732ed33ca2ff - react-native-webview: e771bc375f789ebfa02a26939a57dbc6fa897336 - React-NativeModulesApple: edb5ace14f73f4969df6e7b1f3e41bef0012740f - React-perflogger: 496a1a3dc6737f964107cb3ddae7f9e265ddda58 - React-RCTActionSheet: 02904b932b50e680f4e26e7a686b33ebf7ef3c00 - React-RCTAnimation: 88feaf0a85648fb8fd497ce749829774910276d6 - React-RCTAppDelegate: 5792ac0f0feccb584765fdd7aa81ea320c4d9b0b - React-RCTBlob: 0dbc9e2a13d241b37d46b53e54630cbad1f0e141 - React-RCTImage: b111645ab901f8e59fc68fbe31f5731bdbeef087 - React-RCTLinking: 3d719727b4c098aad3588aa3559361ee0579f5de - React-RCTNetwork: b44d3580be05d74556ba4efbf53570f17e38f734 - React-RCTSettings: c0c54b330442c29874cd4dae6e94190dc11a6f6f - React-RCTText: 9b9f5589d9b649d7246c3f336e116496df28cfe6 - React-RCTVibration: 691c67f3beaf1d084ceed5eb5c1dddd9afa8591e - React-rncore: 142268f6c92e296dc079aadda3fade778562f9e4 - React-runtimeexecutor: d465ba0c47ef3ed8281143f59605cacc2244d5c7 - React-runtimescheduler: 4941cc1b3cf08b792fbf666342c9fc95f1969035 - React-utils: b79f2411931f9d3ea5781404dcbb2fa8a837e13a - ReactCommon: 4b2bdcb50a3543e1c2b2849ad44533686610826d - RNAppleAuthentication: 0571c08da8c327ae2afc0261b48b4a515b0286a6 - RNCAsyncStorage: 8616bd5a58af409453ea4e1b246521bb76578d60 - RNCClipboard: 41d8d918092ae8e676f18adada19104fa3e68495 - RNCPicker: 0b65be85fe7954fbb2062ef079e3d1cde252d888 - RNDateTimePicker: 7658208086d86d09e1627b5c34ba0cf237c60140 - RNDeviceInfo: 4701f0bf2a06b34654745053db0ce4cb0c53ada7 - RNDevMenu: 72807568fe4188bd4c40ce32675d82434b43c45d - RNFastImage: 5c9c9fed9c076e521b3f509fe79e790418a544e8 - RNFBAnalytics: f76bfa164ac235b00505deb9fc1776634056898c - RNFBApp: 729c0666395b1953198dc4a1ec6deb8fbe1c302e - RNFBCrashlytics: 2061ca863e8e2fa1aae9b12477d7dfa8e88ca0f9 - RNFBPerf: 389914cda4000fe0d996a752532a591132cbf3f9 - RNFS: 4ac0f0ea233904cb798630b3c077808c06931688 - RNGestureHandler: dec4645026e7401a0899f2846d864403478ff6a5 - RNGoogleSignin: ccaa4a81582cf713eea562c5dd9dc1961a715fd0 - RNLocalize: d4b8af4e442d4bcca54e68fc687a2129b4d71a81 - rnmapbox-maps: 6f638ec002aa6e906a6f766d69cd45f968d98e64 - RNPermissions: dcdb7b99796bbeda6975a6e79ad519c41b251b1c - RNReactNativeHapticFeedback: 1e3efeca9628ff9876ee7cdd9edec1b336913f8c - RNReanimated: 020859659f64be2d30849a1fe88c821a7c3e0cbf - RNScreens: d037903436160a4b039d32606668350d2a808806 - RNSVG: ed492aaf3af9ca01bc945f7a149d76d62e73ec82 - SDWebImage: a7f831e1a65eb5e285e3fb046a23fcfbf08e696d - SDWebImageWebPCoder: 908b83b6adda48effe7667cd2b7f78c897e5111d - SocketRocket: f32cd54efbe0f095c4d7594881e52619cfe80b17 - Turf: 469ce2c3d22e5e8e4818d5a3b254699a5c89efa4 - VisionCamera: d3ec8883417a6a4a0e3a6ba37d81d22db7611601 - Yoga: 3efc43e0d48686ce2e8c60f99d4e6bd349aff981 - YogaKit: f782866e155069a2cca2517aafea43200b01fd5a - -PODFILE CHECKSUM: 2daf34c870819a933f3fefe426801d54b2ff2a14 - -COCOAPODS: 1.13.0 From ed26edbc45a9c3dc0f36f9b9b328abf9b6f2c433 Mon Sep 17 00:00:00 2001 From: keisyrzk Date: Thu, 5 Oct 2023 06:58:11 +0200 Subject: [PATCH 017/237] updates pr --- src/components/AvatarWithImagePicker.js | 125 +++++++++++++----------- 1 file changed, 70 insertions(+), 55 deletions(-) diff --git a/src/components/AvatarWithImagePicker.js b/src/components/AvatarWithImagePicker.js index 55767268162c..156c08254a95 100644 --- a/src/components/AvatarWithImagePicker.js +++ b/src/components/AvatarWithImagePicker.js @@ -274,6 +274,42 @@ function AvatarWithImagePicker({ const additionalStyles = _.isArray(style) ? style : [style]; + /** + * Create menu items list for avatar menu + * + * @param {Function} openPicker + * @returns {Array} + */ + const createMenuItems = (openPicker) => { + const menuItems = [ + { + icon: Expensicons.Upload, + text: translate('avatarWithImagePicker.uploadPhoto'), + onSelected: () => { + if (Browser.isSafari()) { + return; + } + openPicker({ + onPicked: showAvatarCropModal, + }); + }, + }, + ]; + + // If current avatar isn't a default avatar, allow Remove Photo option + if (!isUsingDefaultAvatar) { + menuItems.push({ + icon: Expensicons.Trashcan, + text: translate('avatarWithImagePicker.removePhoto'), + onSelected: () => { + setError(null, {}); + onImageRemoved(); + }, + }); + } + return menuItems; + }; + return ( @@ -323,64 +359,43 @@ function AvatarWithImagePicker({ fallbackSource={fallbackIcon} > {({show}) => ( - - {({openPicker}) => { - const menuItems = [ - { - icon: Expensicons.Upload, - text: translate('avatarWithImagePicker.uploadPhoto'), - onSelected: () => { - if (Browser.isSafari()) { - return; - } + + {({openPicker}) => { + const menuItems = createMenuItems(openPicker); + + // If the current avatar isn't a default avatar, allow the "View Photo" option + if (!isUsingDefaultAvatar) { + menuItems.push({ + icon: Expensicons.Eye, + text: translate('avatarWithImagePicker.viewPhoto'), + onSelected: show, + }); + } + + return ( + setIsMenuVisible(false)} + onItemSelected={(item, index) => { + setIsMenuVisible(false); + // In order for the file picker to open dynamically, the click + // function must be called from within an event handler that was initiated + // by the user on Safari. + if (index === 0 && Browser.isSafari()) { openPicker({ onPicked: showAvatarCropModal, }); - }, - }, - ]; - - // If current avatar isn't a default avatar, allow Remove Photo option - if (!isUsingDefaultAvatar) { - menuItems.push({ - icon: Expensicons.Trashcan, - text: translate('avatarWithImagePicker.removePhoto'), - onSelected: () => { - setError(null, {}); - onImageRemoved(); - }, - }); - - menuItems.push({ - icon: Expensicons.Eye, - text: translate('avatarWithImagePicker.viewPhoto'), - onSelected: () => show(), - }); - } - return ( - setIsMenuVisible(false)} - onItemSelected={(item, index) => { - setIsMenuVisible(false); - // In order for the file picker to open dynamically, the click - // function must be called from within a event handler that was initiated - // by the user on Safari. - if (index === 0 && Browser.isSafari()) { - openPicker({ - onPicked: showAvatarCropModal, - }); - } - }} - menuItems={menuItems} - anchorPosition={anchorPosition} - withoutOverlay - anchorRef={anchorRef} - anchorAlignment={anchorAlignment} - /> - ); - }} - + } + }} + menuItems={menuItems} + anchorPosition={anchorPosition} + withoutOverlay + anchorRef={anchorRef} + anchorAlignment={anchorAlignment} + /> + ); + }} + )} From 23645f8d4ed53e075f01715831cd80f161e09c98 Mon Sep 17 00:00:00 2001 From: keisyrzk Date: Thu, 5 Oct 2023 09:40:31 +0200 Subject: [PATCH 018/237] restore podfile.lock --- ios/Podfile.lock | 1314 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1314 insertions(+) create mode 100644 ios/Podfile.lock diff --git a/ios/Podfile.lock b/ios/Podfile.lock new file mode 100644 index 000000000000..51b9f6af0e21 --- /dev/null +++ b/ios/Podfile.lock @@ -0,0 +1,1314 @@ +PODS: + - Airship (16.11.3): + - Airship/Automation (= 16.11.3) + - Airship/Basement (= 16.11.3) + - Airship/Core (= 16.11.3) + - Airship/ExtendedActions (= 16.11.3) + - Airship/MessageCenter (= 16.11.3) + - Airship/Automation (16.11.3): + - Airship/Core + - Airship/Basement (16.11.3) + - Airship/Core (16.11.3): + - Airship/Basement + - Airship/ExtendedActions (16.11.3): + - Airship/Core + - Airship/MessageCenter (16.11.3): + - Airship/Core + - Airship/PreferenceCenter (16.11.3): + - Airship/Core + - AirshipFrameworkProxy (2.0.8): + - Airship (= 16.11.3) + - Airship/MessageCenter (= 16.11.3) + - Airship/PreferenceCenter (= 16.11.3) + - AppAuth (1.6.2): + - AppAuth/Core (= 1.6.2) + - AppAuth/ExternalUserAgent (= 1.6.2) + - AppAuth/Core (1.6.2) + - AppAuth/ExternalUserAgent (1.6.2): + - AppAuth/Core + - boost (1.76.0) + - BVLinearGradient (2.8.1): + - React-Core + - CocoaAsyncSocket (7.6.5) + - DoubleConversion (1.1.6) + - FBLazyVector (0.72.4) + - FBReactNativeSpec (0.72.4): + - RCT-Folly (= 2021.07.22.00) + - RCTRequired (= 0.72.4) + - RCTTypeSafety (= 0.72.4) + - React-Core (= 0.72.4) + - React-jsi (= 0.72.4) + - ReactCommon/turbomodule/core (= 0.72.4) + - Firebase/Analytics (8.8.0): + - Firebase/Core + - Firebase/Core (8.8.0): + - Firebase/CoreOnly + - FirebaseAnalytics (~> 8.8.0) + - Firebase/CoreOnly (8.8.0): + - FirebaseCore (= 8.8.0) + - Firebase/Crashlytics (8.8.0): + - Firebase/CoreOnly + - FirebaseCrashlytics (~> 8.8.0) + - Firebase/Performance (8.8.0): + - Firebase/CoreOnly + - FirebasePerformance (~> 8.8.0) + - FirebaseABTesting (8.15.0): + - FirebaseCore (~> 8.0) + - FirebaseAnalytics (8.8.0): + - FirebaseAnalytics/AdIdSupport (= 8.8.0) + - FirebaseCore (~> 8.0) + - FirebaseInstallations (~> 8.0) + - GoogleUtilities/AppDelegateSwizzler (~> 7.4) + - GoogleUtilities/MethodSwizzler (~> 7.4) + - GoogleUtilities/Network (~> 7.4) + - "GoogleUtilities/NSData+zlib (~> 7.4)" + - nanopb (~> 2.30908.0) + - FirebaseAnalytics/AdIdSupport (8.8.0): + - FirebaseCore (~> 8.0) + - FirebaseInstallations (~> 8.0) + - GoogleAppMeasurement (= 8.8.0) + - GoogleUtilities/AppDelegateSwizzler (~> 7.4) + - GoogleUtilities/MethodSwizzler (~> 7.4) + - GoogleUtilities/Network (~> 7.4) + - "GoogleUtilities/NSData+zlib (~> 7.4)" + - nanopb (~> 2.30908.0) + - FirebaseCore (8.8.0): + - FirebaseCoreDiagnostics (~> 8.0) + - GoogleUtilities/Environment (~> 7.4) + - GoogleUtilities/Logger (~> 7.4) + - FirebaseCoreDiagnostics (8.15.0): + - GoogleDataTransport (~> 9.1) + - GoogleUtilities/Environment (~> 7.7) + - GoogleUtilities/Logger (~> 7.7) + - nanopb (~> 2.30908.0) + - FirebaseCrashlytics (8.8.0): + - FirebaseCore (~> 8.0) + - FirebaseInstallations (~> 8.0) + - GoogleDataTransport (~> 9.0) + - GoogleUtilities/Environment (~> 7.4) + - nanopb (~> 2.30908.0) + - PromisesObjC (< 3.0, >= 1.2) + - FirebaseInstallations (8.15.0): + - FirebaseCore (~> 8.0) + - GoogleUtilities/Environment (~> 7.7) + - GoogleUtilities/UserDefaults (~> 7.7) + - PromisesObjC (< 3.0, >= 1.2) + - FirebasePerformance (8.8.0): + - FirebaseCore (~> 8.0) + - FirebaseInstallations (~> 8.0) + - FirebaseRemoteConfig (~> 8.0) + - GoogleDataTransport (~> 9.0) + - GoogleUtilities/Environment (~> 7.4) + - GoogleUtilities/ISASwizzler (~> 7.4) + - GoogleUtilities/MethodSwizzler (~> 7.4) + - nanopb (~> 2.30908.0) + - FirebaseRemoteConfig (8.15.0): + - FirebaseABTesting (~> 8.0) + - FirebaseCore (~> 8.0) + - FirebaseInstallations (~> 8.0) + - GoogleUtilities/Environment (~> 7.7) + - "GoogleUtilities/NSData+zlib (~> 7.7)" + - Flipper (0.182.0): + - Flipper-Folly (~> 2.6) + - Flipper-Boost-iOSX (1.76.0.1.11) + - Flipper-DoubleConversion (3.2.0.1) + - Flipper-Fmt (7.1.7) + - Flipper-Folly (2.6.10): + - Flipper-Boost-iOSX + - Flipper-DoubleConversion + - Flipper-Fmt (= 7.1.7) + - Flipper-Glog + - libevent (~> 2.1.12) + - OpenSSL-Universal (= 1.1.1100) + - Flipper-Glog (0.5.0.5) + - Flipper-PeerTalk (0.0.4) + - FlipperKit (0.182.0): + - FlipperKit/Core (= 0.182.0) + - FlipperKit/Core (0.182.0): + - Flipper (~> 0.182.0) + - FlipperKit/CppBridge + - FlipperKit/FBCxxFollyDynamicConvert + - FlipperKit/FBDefines + - FlipperKit/FKPortForwarding + - SocketRocket (~> 0.6.0) + - FlipperKit/CppBridge (0.182.0): + - Flipper (~> 0.182.0) + - FlipperKit/FBCxxFollyDynamicConvert (0.182.0): + - Flipper-Folly (~> 2.6) + - FlipperKit/FBDefines (0.182.0) + - FlipperKit/FKPortForwarding (0.182.0): + - CocoaAsyncSocket (~> 7.6) + - Flipper-PeerTalk (~> 0.0.4) + - FlipperKit/FlipperKitHighlightOverlay (0.182.0) + - FlipperKit/FlipperKitLayoutHelpers (0.182.0): + - FlipperKit/Core + - FlipperKit/FlipperKitHighlightOverlay + - FlipperKit/FlipperKitLayoutTextSearchable + - FlipperKit/FlipperKitLayoutIOSDescriptors (0.182.0): + - FlipperKit/Core + - FlipperKit/FlipperKitHighlightOverlay + - FlipperKit/FlipperKitLayoutHelpers + - YogaKit (~> 1.18) + - FlipperKit/FlipperKitLayoutPlugin (0.182.0): + - FlipperKit/Core + - FlipperKit/FlipperKitHighlightOverlay + - FlipperKit/FlipperKitLayoutHelpers + - FlipperKit/FlipperKitLayoutIOSDescriptors + - FlipperKit/FlipperKitLayoutTextSearchable + - YogaKit (~> 1.18) + - FlipperKit/FlipperKitLayoutTextSearchable (0.182.0) + - FlipperKit/FlipperKitNetworkPlugin (0.182.0): + - FlipperKit/Core + - FlipperKit/FlipperKitReactPlugin (0.182.0): + - FlipperKit/Core + - FlipperKit/FlipperKitUserDefaultsPlugin (0.182.0): + - FlipperKit/Core + - FlipperKit/SKIOSNetworkPlugin (0.182.0): + - FlipperKit/Core + - FlipperKit/FlipperKitNetworkPlugin + - fmt (6.2.1) + - glog (0.3.5) + - GoogleAppMeasurement (8.8.0): + - GoogleAppMeasurement/AdIdSupport (= 8.8.0) + - GoogleUtilities/AppDelegateSwizzler (~> 7.4) + - GoogleUtilities/MethodSwizzler (~> 7.4) + - GoogleUtilities/Network (~> 7.4) + - "GoogleUtilities/NSData+zlib (~> 7.4)" + - nanopb (~> 2.30908.0) + - GoogleAppMeasurement/AdIdSupport (8.8.0): + - GoogleAppMeasurement/WithoutAdIdSupport (= 8.8.0) + - GoogleUtilities/AppDelegateSwizzler (~> 7.4) + - GoogleUtilities/MethodSwizzler (~> 7.4) + - GoogleUtilities/Network (~> 7.4) + - "GoogleUtilities/NSData+zlib (~> 7.4)" + - nanopb (~> 2.30908.0) + - GoogleAppMeasurement/WithoutAdIdSupport (8.8.0): + - GoogleUtilities/AppDelegateSwizzler (~> 7.4) + - GoogleUtilities/MethodSwizzler (~> 7.4) + - GoogleUtilities/Network (~> 7.4) + - "GoogleUtilities/NSData+zlib (~> 7.4)" + - nanopb (~> 2.30908.0) + - GoogleDataTransport (9.2.3): + - GoogleUtilities/Environment (~> 7.7) + - nanopb (< 2.30910.0, >= 2.30908.0) + - PromisesObjC (< 3.0, >= 1.2) + - GoogleSignIn (7.0.0): + - AppAuth (~> 1.5) + - GTMAppAuth (< 3.0, >= 1.3) + - GTMSessionFetcher/Core (< 4.0, >= 1.1) + - GoogleUtilities/AppDelegateSwizzler (7.11.1): + - GoogleUtilities/Environment + - GoogleUtilities/Logger + - GoogleUtilities/Network + - GoogleUtilities/Environment (7.11.1): + - PromisesObjC (< 3.0, >= 1.2) + - GoogleUtilities/ISASwizzler (7.11.1) + - GoogleUtilities/Logger (7.11.1): + - GoogleUtilities/Environment + - GoogleUtilities/MethodSwizzler (7.11.1): + - GoogleUtilities/Logger + - GoogleUtilities/Network (7.11.1): + - GoogleUtilities/Logger + - "GoogleUtilities/NSData+zlib" + - GoogleUtilities/Reachability + - "GoogleUtilities/NSData+zlib (7.11.1)" + - GoogleUtilities/Reachability (7.11.1): + - GoogleUtilities/Logger + - GoogleUtilities/UserDefaults (7.11.1): + - GoogleUtilities/Logger + - GTMAppAuth (2.0.0): + - AppAuth/Core (~> 1.6) + - GTMSessionFetcher/Core (< 4.0, >= 1.5) + - GTMSessionFetcher/Core (3.1.1) + - hermes-engine (0.72.4): + - hermes-engine/Pre-built (= 0.72.4) + - hermes-engine/Pre-built (0.72.4) + - libevent (2.1.12) + - libwebp (1.2.4): + - libwebp/demux (= 1.2.4) + - libwebp/mux (= 1.2.4) + - libwebp/webp (= 1.2.4) + - libwebp/demux (1.2.4): + - libwebp/webp + - libwebp/mux (1.2.4): + - libwebp/demux + - libwebp/webp (1.2.4) + - lottie-ios (3.4.4) + - lottie-react-native (5.1.6): + - lottie-ios (~> 3.4.0) + - React-Core + - MapboxCommon (23.6.0) + - MapboxCoreMaps (10.14.0): + - MapboxCommon (~> 23.6) + - MapboxMaps (10.14.0): + - MapboxCommon (= 23.6.0) + - MapboxCoreMaps (= 10.14.0) + - MapboxMobileEvents (= 1.0.10) + - Turf (~> 2.0) + - MapboxMobileEvents (1.0.10) + - nanopb (2.30908.0): + - nanopb/decode (= 2.30908.0) + - nanopb/encode (= 2.30908.0) + - nanopb/decode (2.30908.0) + - nanopb/encode (2.30908.0) + - Onfido (27.4.0) + - onfido-react-native-sdk (7.4.0): + - Onfido (= 27.4.0) + - React + - OpenSSL-Universal (1.1.1100) + - Permission-Camera (3.6.1): + - RNPermissions + - Permission-LocationAccuracy (3.6.1): + - RNPermissions + - Permission-LocationAlways (3.6.1): + - RNPermissions + - Permission-LocationWhenInUse (3.6.1): + - RNPermissions + - Plaid (4.1.0) + - PromisesObjC (2.2.0) + - RCT-Folly (2021.07.22.00): + - boost + - DoubleConversion + - fmt (~> 6.2.1) + - glog + - RCT-Folly/Default (= 2021.07.22.00) + - RCT-Folly/Default (2021.07.22.00): + - boost + - DoubleConversion + - fmt (~> 6.2.1) + - glog + - RCT-Folly/Futures (2021.07.22.00): + - boost + - DoubleConversion + - fmt (~> 6.2.1) + - glog + - libevent + - RCTRequired (0.72.4) + - RCTTypeSafety (0.72.4): + - FBLazyVector (= 0.72.4) + - RCTRequired (= 0.72.4) + - React-Core (= 0.72.4) + - React (0.72.4): + - React-Core (= 0.72.4) + - React-Core/DevSupport (= 0.72.4) + - React-Core/RCTWebSocket (= 0.72.4) + - React-RCTActionSheet (= 0.72.4) + - React-RCTAnimation (= 0.72.4) + - React-RCTBlob (= 0.72.4) + - React-RCTImage (= 0.72.4) + - React-RCTLinking (= 0.72.4) + - React-RCTNetwork (= 0.72.4) + - React-RCTSettings (= 0.72.4) + - React-RCTText (= 0.72.4) + - React-RCTVibration (= 0.72.4) + - React-callinvoker (0.72.4) + - React-Codegen (0.72.4): + - DoubleConversion + - FBReactNativeSpec + - glog + - hermes-engine + - RCT-Folly + - RCTRequired + - RCTTypeSafety + - React-Core + - React-jsi + - React-jsiexecutor + - React-NativeModulesApple + - React-rncore + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - React-Core (0.72.4): + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-Core/Default (= 0.72.4) + - React-cxxreact + - React-hermes + - React-jsi + - React-jsiexecutor + - React-perflogger + - React-runtimeexecutor + - React-utils + - SocketRocket (= 0.6.1) + - Yoga + - React-Core/CoreModulesHeaders (0.72.4): + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-Core/Default + - React-cxxreact + - React-hermes + - React-jsi + - React-jsiexecutor + - React-perflogger + - React-runtimeexecutor + - React-utils + - SocketRocket (= 0.6.1) + - Yoga + - React-Core/Default (0.72.4): + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-cxxreact + - React-hermes + - React-jsi + - React-jsiexecutor + - React-perflogger + - React-runtimeexecutor + - React-utils + - SocketRocket (= 0.6.1) + - Yoga + - React-Core/DevSupport (0.72.4): + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-Core/Default (= 0.72.4) + - React-Core/RCTWebSocket (= 0.72.4) + - React-cxxreact + - React-hermes + - React-jsi + - React-jsiexecutor + - React-jsinspector (= 0.72.4) + - React-perflogger + - React-runtimeexecutor + - React-utils + - SocketRocket (= 0.6.1) + - Yoga + - React-Core/RCTActionSheetHeaders (0.72.4): + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-Core/Default + - React-cxxreact + - React-hermes + - React-jsi + - React-jsiexecutor + - React-perflogger + - React-runtimeexecutor + - React-utils + - SocketRocket (= 0.6.1) + - Yoga + - React-Core/RCTAnimationHeaders (0.72.4): + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-Core/Default + - React-cxxreact + - React-hermes + - React-jsi + - React-jsiexecutor + - React-perflogger + - React-runtimeexecutor + - React-utils + - SocketRocket (= 0.6.1) + - Yoga + - React-Core/RCTBlobHeaders (0.72.4): + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-Core/Default + - React-cxxreact + - React-hermes + - React-jsi + - React-jsiexecutor + - React-perflogger + - React-runtimeexecutor + - React-utils + - SocketRocket (= 0.6.1) + - Yoga + - React-Core/RCTImageHeaders (0.72.4): + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-Core/Default + - React-cxxreact + - React-hermes + - React-jsi + - React-jsiexecutor + - React-perflogger + - React-runtimeexecutor + - React-utils + - SocketRocket (= 0.6.1) + - Yoga + - React-Core/RCTLinkingHeaders (0.72.4): + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-Core/Default + - React-cxxreact + - React-hermes + - React-jsi + - React-jsiexecutor + - React-perflogger + - React-runtimeexecutor + - React-utils + - SocketRocket (= 0.6.1) + - Yoga + - React-Core/RCTNetworkHeaders (0.72.4): + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-Core/Default + - React-cxxreact + - React-hermes + - React-jsi + - React-jsiexecutor + - React-perflogger + - React-runtimeexecutor + - React-utils + - SocketRocket (= 0.6.1) + - Yoga + - React-Core/RCTSettingsHeaders (0.72.4): + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-Core/Default + - React-cxxreact + - React-hermes + - React-jsi + - React-jsiexecutor + - React-perflogger + - React-runtimeexecutor + - React-utils + - SocketRocket (= 0.6.1) + - Yoga + - React-Core/RCTTextHeaders (0.72.4): + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-Core/Default + - React-cxxreact + - React-hermes + - React-jsi + - React-jsiexecutor + - React-perflogger + - React-runtimeexecutor + - React-utils + - SocketRocket (= 0.6.1) + - Yoga + - React-Core/RCTVibrationHeaders (0.72.4): + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-Core/Default + - React-cxxreact + - React-hermes + - React-jsi + - React-jsiexecutor + - React-perflogger + - React-runtimeexecutor + - React-utils + - SocketRocket (= 0.6.1) + - Yoga + - React-Core/RCTWebSocket (0.72.4): + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-Core/Default (= 0.72.4) + - React-cxxreact + - React-hermes + - React-jsi + - React-jsiexecutor + - React-perflogger + - React-runtimeexecutor + - React-utils + - SocketRocket (= 0.6.1) + - Yoga + - React-CoreModules (0.72.4): + - RCT-Folly (= 2021.07.22.00) + - RCTTypeSafety (= 0.72.4) + - React-Codegen (= 0.72.4) + - React-Core/CoreModulesHeaders (= 0.72.4) + - React-jsi (= 0.72.4) + - React-RCTBlob + - React-RCTImage (= 0.72.4) + - ReactCommon/turbomodule/core (= 0.72.4) + - SocketRocket (= 0.6.1) + - React-cxxreact (0.72.4): + - boost (= 1.76.0) + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-callinvoker (= 0.72.4) + - React-debug (= 0.72.4) + - React-jsi (= 0.72.4) + - React-jsinspector (= 0.72.4) + - React-logger (= 0.72.4) + - React-perflogger (= 0.72.4) + - React-runtimeexecutor (= 0.72.4) + - React-debug (0.72.4) + - React-hermes (0.72.4): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - RCT-Folly/Futures (= 2021.07.22.00) + - React-cxxreact (= 0.72.4) + - React-jsi + - React-jsiexecutor (= 0.72.4) + - React-jsinspector (= 0.72.4) + - React-perflogger (= 0.72.4) + - React-jsi (0.72.4): + - boost (= 1.76.0) + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-jsiexecutor (0.72.4): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-cxxreact (= 0.72.4) + - React-jsi (= 0.72.4) + - React-perflogger (= 0.72.4) + - React-jsinspector (0.72.4) + - React-logger (0.72.4): + - glog + - react-native-airship (15.2.6): + - AirshipFrameworkProxy (= 2.0.8) + - React-Core + - react-native-blob-util (0.17.3): + - React-Core + - react-native-cameraroll (5.4.0): + - React-Core + - react-native-config (1.4.6): + - react-native-config/App (= 1.4.6) + - react-native-config/App (1.4.6): + - React-Core + - react-native-document-picker (8.1.1): + - React-Core + - react-native-flipper (0.159.0): + - React-Core + - react-native-image-manipulator (1.0.5): + - React + - react-native-image-picker (5.1.0): + - React-Core + - react-native-key-command (1.0.1): + - React-Core + - react-native-netinfo (9.3.10): + - React-Core + - react-native-pager-view (6.2.0): + - React-Core + - react-native-pdf (6.7.1): + - React-Core + - react-native-performance (5.1.0): + - React-Core + - react-native-plaid-link-sdk (10.0.0): + - Plaid (~> 4.1.0) + - React-Core + - react-native-quick-sqlite (8.0.0-beta.2): + - React + - React-callinvoker + - React-Core + - react-native-render-html (6.3.1): + - React-Core + - react-native-safe-area-context (4.4.1): + - RCT-Folly + - RCTRequired + - RCTTypeSafety + - React-Core + - ReactCommon/turbomodule/core + - react-native-view-shot (3.6.0): + - React-Core + - react-native-webview (11.23.0): + - React-Core + - React-NativeModulesApple (0.72.4): + - hermes-engine + - React-callinvoker + - React-Core + - React-cxxreact + - React-jsi + - React-runtimeexecutor + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - React-perflogger (0.72.4) + - React-RCTActionSheet (0.72.4): + - React-Core/RCTActionSheetHeaders (= 0.72.4) + - React-RCTAnimation (0.72.4): + - RCT-Folly (= 2021.07.22.00) + - RCTTypeSafety (= 0.72.4) + - React-Codegen (= 0.72.4) + - React-Core/RCTAnimationHeaders (= 0.72.4) + - React-jsi (= 0.72.4) + - ReactCommon/turbomodule/core (= 0.72.4) + - React-RCTAppDelegate (0.72.4): + - RCT-Folly + - RCTRequired + - RCTTypeSafety + - React-Core + - React-CoreModules + - React-hermes + - React-NativeModulesApple + - React-RCTImage + - React-RCTNetwork + - React-runtimescheduler + - ReactCommon/turbomodule/core + - React-RCTBlob (0.72.4): + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-Codegen (= 0.72.4) + - React-Core/RCTBlobHeaders (= 0.72.4) + - React-Core/RCTWebSocket (= 0.72.4) + - React-jsi (= 0.72.4) + - React-RCTNetwork (= 0.72.4) + - ReactCommon/turbomodule/core (= 0.72.4) + - React-RCTImage (0.72.4): + - RCT-Folly (= 2021.07.22.00) + - RCTTypeSafety (= 0.72.4) + - React-Codegen (= 0.72.4) + - React-Core/RCTImageHeaders (= 0.72.4) + - React-jsi (= 0.72.4) + - React-RCTNetwork (= 0.72.4) + - ReactCommon/turbomodule/core (= 0.72.4) + - React-RCTLinking (0.72.4): + - React-Codegen (= 0.72.4) + - React-Core/RCTLinkingHeaders (= 0.72.4) + - React-jsi (= 0.72.4) + - ReactCommon/turbomodule/core (= 0.72.4) + - React-RCTNetwork (0.72.4): + - RCT-Folly (= 2021.07.22.00) + - RCTTypeSafety (= 0.72.4) + - React-Codegen (= 0.72.4) + - React-Core/RCTNetworkHeaders (= 0.72.4) + - React-jsi (= 0.72.4) + - ReactCommon/turbomodule/core (= 0.72.4) + - React-RCTSettings (0.72.4): + - RCT-Folly (= 2021.07.22.00) + - RCTTypeSafety (= 0.72.4) + - React-Codegen (= 0.72.4) + - React-Core/RCTSettingsHeaders (= 0.72.4) + - React-jsi (= 0.72.4) + - ReactCommon/turbomodule/core (= 0.72.4) + - React-RCTText (0.72.4): + - React-Core/RCTTextHeaders (= 0.72.4) + - React-RCTVibration (0.72.4): + - RCT-Folly (= 2021.07.22.00) + - React-Codegen (= 0.72.4) + - React-Core/RCTVibrationHeaders (= 0.72.4) + - React-jsi (= 0.72.4) + - ReactCommon/turbomodule/core (= 0.72.4) + - React-rncore (0.72.4) + - React-runtimeexecutor (0.72.4): + - React-jsi (= 0.72.4) + - React-runtimescheduler (0.72.4): + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-callinvoker + - React-debug + - React-jsi + - React-runtimeexecutor + - React-utils (0.72.4): + - glog + - RCT-Folly (= 2021.07.22.00) + - React-debug + - ReactCommon/turbomodule/bridging (0.72.4): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-callinvoker (= 0.72.4) + - React-cxxreact (= 0.72.4) + - React-jsi (= 0.72.4) + - React-logger (= 0.72.4) + - React-perflogger (= 0.72.4) + - ReactCommon/turbomodule/core (0.72.4): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-callinvoker (= 0.72.4) + - React-cxxreact (= 0.72.4) + - React-jsi (= 0.72.4) + - React-logger (= 0.72.4) + - React-perflogger (= 0.72.4) + - RNAppleAuthentication (2.2.2): + - React-Core + - RNCAsyncStorage (1.17.11): + - React-Core + - RNCClipboard (1.5.1): + - React-Core + - RNCPicker (2.4.4): + - React-Core + - RNDateTimePicker (3.5.2): + - React-Core + - RNDeviceInfo (10.3.0): + - React-Core + - RNDevMenu (4.1.1): + - React-Core + - React-Core/DevSupport + - React-RCTNetwork + - RNFastImage (8.6.3): + - React-Core + - SDWebImage (~> 5.11.1) + - SDWebImageWebPCoder (~> 0.8.4) + - RNFBAnalytics (12.9.3): + - Firebase/Analytics (= 8.8.0) + - React-Core + - RNFBApp + - RNFBApp (12.9.3): + - Firebase/CoreOnly (= 8.8.0) + - React-Core + - RNFBCrashlytics (12.9.3): + - Firebase/Crashlytics (= 8.8.0) + - React-Core + - RNFBApp + - RNFBPerf (12.9.3): + - Firebase/Performance (= 8.8.0) + - React-Core + - RNFBApp + - RNFS (2.20.0): + - React-Core + - RNGestureHandler (2.12.0): + - React-Core + - RNGoogleSignin (10.0.1): + - GoogleSignIn (~> 7.0) + - React-Core + - RNLocalize (2.2.6): + - React-Core + - rnmapbox-maps (10.0.11): + - MapboxMaps (~> 10.14.0) + - React + - React-Core + - rnmapbox-maps/DynamicLibrary (= 10.0.11) + - Turf + - rnmapbox-maps/DynamicLibrary (10.0.11): + - MapboxMaps (~> 10.14.0) + - React + - React-Core + - Turf + - RNPermissions (3.6.1): + - React-Core + - RNReactNativeHapticFeedback (1.14.0): + - React-Core + - RNReanimated (3.4.0): + - DoubleConversion + - FBLazyVector + - glog + - hermes-engine + - RCT-Folly + - RCTRequired + - RCTTypeSafety + - React-callinvoker + - React-Core + - React-Core/DevSupport + - React-Core/RCTWebSocket + - React-CoreModules + - React-cxxreact + - React-hermes + - React-jsi + - React-jsiexecutor + - React-jsinspector + - React-RCTActionSheet + - React-RCTAnimation + - React-RCTAppDelegate + - React-RCTBlob + - React-RCTImage + - React-RCTLinking + - React-RCTNetwork + - React-RCTSettings + - React-RCTText + - ReactCommon/turbomodule/core + - Yoga + - RNScreens (3.21.0): + - React-Core + - React-RCTImage + - RNSVG (13.13.0): + - React-Core + - SDWebImage (5.11.1): + - SDWebImage/Core (= 5.11.1) + - SDWebImage/Core (5.11.1) + - SDWebImageWebPCoder (0.8.5): + - libwebp (~> 1.0) + - SDWebImage/Core (~> 5.10) + - SocketRocket (0.6.1) + - Turf (2.6.1) + - VisionCamera (2.15.4): + - React + - React-callinvoker + - React-Core + - Yoga (1.14.0) + - YogaKit (1.18.1): + - Yoga (~> 1.14) + +DEPENDENCIES: + - boost (from `../node_modules/react-native/third-party-podspecs/boost.podspec`) + - BVLinearGradient (from `../node_modules/react-native-linear-gradient`) + - DoubleConversion (from `../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec`) + - FBLazyVector (from `../node_modules/react-native/Libraries/FBLazyVector`) + - FBReactNativeSpec (from `../node_modules/react-native/React/FBReactNativeSpec`) + - Flipper (= 0.182.0) + - Flipper-Boost-iOSX (= 1.76.0.1.11) + - Flipper-DoubleConversion (= 3.2.0.1) + - Flipper-Fmt (= 7.1.7) + - Flipper-Folly (= 2.6.10) + - Flipper-Glog (= 0.5.0.5) + - Flipper-PeerTalk (= 0.0.4) + - FlipperKit (= 0.182.0) + - FlipperKit/Core (= 0.182.0) + - FlipperKit/CppBridge (= 0.182.0) + - FlipperKit/FBCxxFollyDynamicConvert (= 0.182.0) + - FlipperKit/FBDefines (= 0.182.0) + - FlipperKit/FKPortForwarding (= 0.182.0) + - FlipperKit/FlipperKitHighlightOverlay (= 0.182.0) + - FlipperKit/FlipperKitLayoutPlugin (= 0.182.0) + - FlipperKit/FlipperKitLayoutTextSearchable (= 0.182.0) + - FlipperKit/FlipperKitNetworkPlugin (= 0.182.0) + - FlipperKit/FlipperKitReactPlugin (= 0.182.0) + - FlipperKit/FlipperKitUserDefaultsPlugin (= 0.182.0) + - FlipperKit/SKIOSNetworkPlugin (= 0.182.0) + - glog (from `../node_modules/react-native/third-party-podspecs/glog.podspec`) + - hermes-engine (from `../node_modules/react-native/sdks/hermes-engine/hermes-engine.podspec`) + - libevent (~> 2.1.12) + - lottie-react-native (from `../node_modules/lottie-react-native`) + - "onfido-react-native-sdk (from `../node_modules/@onfido/react-native-sdk`)" + - OpenSSL-Universal (= 1.1.1100) + - Permission-Camera (from `../node_modules/react-native-permissions/ios/Camera`) + - Permission-LocationAccuracy (from `../node_modules/react-native-permissions/ios/LocationAccuracy`) + - Permission-LocationAlways (from `../node_modules/react-native-permissions/ios/LocationAlways`) + - Permission-LocationWhenInUse (from `../node_modules/react-native-permissions/ios/LocationWhenInUse`) + - RCT-Folly (from `../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec`) + - RCTRequired (from `../node_modules/react-native/Libraries/RCTRequired`) + - RCTTypeSafety (from `../node_modules/react-native/Libraries/TypeSafety`) + - React (from `../node_modules/react-native/`) + - React-callinvoker (from `../node_modules/react-native/ReactCommon/callinvoker`) + - React-Codegen (from `build/generated/ios`) + - React-Core (from `../node_modules/react-native/`) + - React-Core/DevSupport (from `../node_modules/react-native/`) + - React-Core/RCTWebSocket (from `../node_modules/react-native/`) + - React-CoreModules (from `../node_modules/react-native/React/CoreModules`) + - React-cxxreact (from `../node_modules/react-native/ReactCommon/cxxreact`) + - React-debug (from `../node_modules/react-native/ReactCommon/react/debug`) + - React-hermes (from `../node_modules/react-native/ReactCommon/hermes`) + - React-jsi (from `../node_modules/react-native/ReactCommon/jsi`) + - React-jsiexecutor (from `../node_modules/react-native/ReactCommon/jsiexecutor`) + - React-jsinspector (from `../node_modules/react-native/ReactCommon/jsinspector`) + - React-logger (from `../node_modules/react-native/ReactCommon/logger`) + - "react-native-airship (from `../node_modules/@ua/react-native-airship`)" + - react-native-blob-util (from `../node_modules/react-native-blob-util`) + - "react-native-cameraroll (from `../node_modules/@react-native-camera-roll/camera-roll`)" + - react-native-config (from `../node_modules/react-native-config`) + - react-native-document-picker (from `../node_modules/react-native-document-picker`) + - react-native-flipper (from `../node_modules/react-native-flipper`) + - "react-native-image-manipulator (from `../node_modules/@oguzhnatly/react-native-image-manipulator`)" + - react-native-image-picker (from `../node_modules/react-native-image-picker`) + - react-native-key-command (from `../node_modules/react-native-key-command`) + - "react-native-netinfo (from `../node_modules/@react-native-community/netinfo`)" + - react-native-pager-view (from `../node_modules/react-native-pager-view`) + - react-native-pdf (from `../node_modules/react-native-pdf`) + - react-native-performance (from `../node_modules/react-native-performance`) + - react-native-plaid-link-sdk (from `../node_modules/react-native-plaid-link-sdk`) + - react-native-quick-sqlite (from `../node_modules/react-native-quick-sqlite`) + - react-native-render-html (from `../node_modules/react-native-render-html`) + - react-native-safe-area-context (from `../node_modules/react-native-safe-area-context`) + - react-native-view-shot (from `../node_modules/react-native-view-shot`) + - react-native-webview (from `../node_modules/react-native-webview`) + - React-NativeModulesApple (from `../node_modules/react-native/ReactCommon/react/nativemodule/core/platform/ios`) + - React-perflogger (from `../node_modules/react-native/ReactCommon/reactperflogger`) + - React-RCTActionSheet (from `../node_modules/react-native/Libraries/ActionSheetIOS`) + - React-RCTAnimation (from `../node_modules/react-native/Libraries/NativeAnimation`) + - React-RCTAppDelegate (from `../node_modules/react-native/Libraries/AppDelegate`) + - React-RCTBlob (from `../node_modules/react-native/Libraries/Blob`) + - React-RCTImage (from `../node_modules/react-native/Libraries/Image`) + - React-RCTLinking (from `../node_modules/react-native/Libraries/LinkingIOS`) + - React-RCTNetwork (from `../node_modules/react-native/Libraries/Network`) + - React-RCTSettings (from `../node_modules/react-native/Libraries/Settings`) + - React-RCTText (from `../node_modules/react-native/Libraries/Text`) + - React-RCTVibration (from `../node_modules/react-native/Libraries/Vibration`) + - React-rncore (from `../node_modules/react-native/ReactCommon`) + - React-runtimeexecutor (from `../node_modules/react-native/ReactCommon/runtimeexecutor`) + - React-runtimescheduler (from `../node_modules/react-native/ReactCommon/react/renderer/runtimescheduler`) + - React-utils (from `../node_modules/react-native/ReactCommon/react/utils`) + - ReactCommon/turbomodule/core (from `../node_modules/react-native/ReactCommon`) + - "RNAppleAuthentication (from `../node_modules/@invertase/react-native-apple-authentication`)" + - "RNCAsyncStorage (from `../node_modules/@react-native-async-storage/async-storage`)" + - "RNCClipboard (from `../node_modules/@react-native-community/clipboard`)" + - "RNCPicker (from `../node_modules/@react-native-picker/picker`)" + - "RNDateTimePicker (from `../node_modules/@react-native-community/datetimepicker`)" + - RNDeviceInfo (from `../node_modules/react-native-device-info`) + - RNDevMenu (from `../node_modules/react-native-dev-menu`) + - RNFastImage (from `../node_modules/react-native-fast-image`) + - "RNFBAnalytics (from `../node_modules/@react-native-firebase/analytics`)" + - "RNFBApp (from `../node_modules/@react-native-firebase/app`)" + - "RNFBCrashlytics (from `../node_modules/@react-native-firebase/crashlytics`)" + - "RNFBPerf (from `../node_modules/@react-native-firebase/perf`)" + - RNFS (from `../node_modules/react-native-fs`) + - RNGestureHandler (from `../node_modules/react-native-gesture-handler`) + - "RNGoogleSignin (from `../node_modules/@react-native-google-signin/google-signin`)" + - RNLocalize (from `../node_modules/react-native-localize`) + - "rnmapbox-maps (from `../node_modules/@rnmapbox/maps`)" + - RNPermissions (from `../node_modules/react-native-permissions`) + - RNReactNativeHapticFeedback (from `../node_modules/react-native-haptic-feedback`) + - RNReanimated (from `../node_modules/react-native-reanimated`) + - RNScreens (from `../node_modules/react-native-screens`) + - RNSVG (from `../node_modules/react-native-svg`) + - VisionCamera (from `../node_modules/react-native-vision-camera`) + - Yoga (from `../node_modules/react-native/ReactCommon/yoga`) + +SPEC REPOS: + trunk: + - Airship + - AirshipFrameworkProxy + - AppAuth + - CocoaAsyncSocket + - Firebase + - FirebaseABTesting + - FirebaseAnalytics + - FirebaseCore + - FirebaseCoreDiagnostics + - FirebaseCrashlytics + - FirebaseInstallations + - FirebasePerformance + - FirebaseRemoteConfig + - Flipper + - Flipper-Boost-iOSX + - Flipper-DoubleConversion + - Flipper-Fmt + - Flipper-Folly + - Flipper-Glog + - Flipper-PeerTalk + - FlipperKit + - fmt + - GoogleAppMeasurement + - GoogleDataTransport + - GoogleSignIn + - GoogleUtilities + - GTMAppAuth + - GTMSessionFetcher + - libevent + - libwebp + - lottie-ios + - MapboxCommon + - MapboxCoreMaps + - MapboxMaps + - MapboxMobileEvents + - nanopb + - Onfido + - OpenSSL-Universal + - Plaid + - PromisesObjC + - SDWebImage + - SDWebImageWebPCoder + - SocketRocket + - Turf + - YogaKit + +EXTERNAL SOURCES: + boost: + :podspec: "../node_modules/react-native/third-party-podspecs/boost.podspec" + BVLinearGradient: + :path: "../node_modules/react-native-linear-gradient" + DoubleConversion: + :podspec: "../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec" + FBLazyVector: + :path: "../node_modules/react-native/Libraries/FBLazyVector" + FBReactNativeSpec: + :path: "../node_modules/react-native/React/FBReactNativeSpec" + glog: + :podspec: "../node_modules/react-native/third-party-podspecs/glog.podspec" + hermes-engine: + :podspec: "../node_modules/react-native/sdks/hermes-engine/hermes-engine.podspec" + :tag: hermes-2023-08-07-RNv0.72.4-813b2def12bc9df02654b3e3653ae4a68d0572e0 + lottie-react-native: + :path: "../node_modules/lottie-react-native" + onfido-react-native-sdk: + :path: "../node_modules/@onfido/react-native-sdk" + Permission-Camera: + :path: "../node_modules/react-native-permissions/ios/Camera" + Permission-LocationAccuracy: + :path: "../node_modules/react-native-permissions/ios/LocationAccuracy" + Permission-LocationAlways: + :path: "../node_modules/react-native-permissions/ios/LocationAlways" + Permission-LocationWhenInUse: + :path: "../node_modules/react-native-permissions/ios/LocationWhenInUse" + RCT-Folly: + :podspec: "../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec" + RCTRequired: + :path: "../node_modules/react-native/Libraries/RCTRequired" + RCTTypeSafety: + :path: "../node_modules/react-native/Libraries/TypeSafety" + React: + :path: "../node_modules/react-native/" + React-callinvoker: + :path: "../node_modules/react-native/ReactCommon/callinvoker" + React-Codegen: + :path: build/generated/ios + React-Core: + :path: "../node_modules/react-native/" + React-CoreModules: + :path: "../node_modules/react-native/React/CoreModules" + React-cxxreact: + :path: "../node_modules/react-native/ReactCommon/cxxreact" + React-debug: + :path: "../node_modules/react-native/ReactCommon/react/debug" + React-hermes: + :path: "../node_modules/react-native/ReactCommon/hermes" + React-jsi: + :path: "../node_modules/react-native/ReactCommon/jsi" + React-jsiexecutor: + :path: "../node_modules/react-native/ReactCommon/jsiexecutor" + React-jsinspector: + :path: "../node_modules/react-native/ReactCommon/jsinspector" + React-logger: + :path: "../node_modules/react-native/ReactCommon/logger" + react-native-airship: + :path: "../node_modules/@ua/react-native-airship" + react-native-blob-util: + :path: "../node_modules/react-native-blob-util" + react-native-cameraroll: + :path: "../node_modules/@react-native-camera-roll/camera-roll" + react-native-config: + :path: "../node_modules/react-native-config" + react-native-document-picker: + :path: "../node_modules/react-native-document-picker" + react-native-flipper: + :path: "../node_modules/react-native-flipper" + react-native-image-manipulator: + :path: "../node_modules/@oguzhnatly/react-native-image-manipulator" + react-native-image-picker: + :path: "../node_modules/react-native-image-picker" + react-native-key-command: + :path: "../node_modules/react-native-key-command" + react-native-netinfo: + :path: "../node_modules/@react-native-community/netinfo" + react-native-pager-view: + :path: "../node_modules/react-native-pager-view" + react-native-pdf: + :path: "../node_modules/react-native-pdf" + react-native-performance: + :path: "../node_modules/react-native-performance" + react-native-plaid-link-sdk: + :path: "../node_modules/react-native-plaid-link-sdk" + react-native-quick-sqlite: + :path: "../node_modules/react-native-quick-sqlite" + react-native-render-html: + :path: "../node_modules/react-native-render-html" + react-native-safe-area-context: + :path: "../node_modules/react-native-safe-area-context" + react-native-view-shot: + :path: "../node_modules/react-native-view-shot" + react-native-webview: + :path: "../node_modules/react-native-webview" + React-NativeModulesApple: + :path: "../node_modules/react-native/ReactCommon/react/nativemodule/core/platform/ios" + React-perflogger: + :path: "../node_modules/react-native/ReactCommon/reactperflogger" + React-RCTActionSheet: + :path: "../node_modules/react-native/Libraries/ActionSheetIOS" + React-RCTAnimation: + :path: "../node_modules/react-native/Libraries/NativeAnimation" + React-RCTAppDelegate: + :path: "../node_modules/react-native/Libraries/AppDelegate" + React-RCTBlob: + :path: "../node_modules/react-native/Libraries/Blob" + React-RCTImage: + :path: "../node_modules/react-native/Libraries/Image" + React-RCTLinking: + :path: "../node_modules/react-native/Libraries/LinkingIOS" + React-RCTNetwork: + :path: "../node_modules/react-native/Libraries/Network" + React-RCTSettings: + :path: "../node_modules/react-native/Libraries/Settings" + React-RCTText: + :path: "../node_modules/react-native/Libraries/Text" + React-RCTVibration: + :path: "../node_modules/react-native/Libraries/Vibration" + React-rncore: + :path: "../node_modules/react-native/ReactCommon" + React-runtimeexecutor: + :path: "../node_modules/react-native/ReactCommon/runtimeexecutor" + React-runtimescheduler: + :path: "../node_modules/react-native/ReactCommon/react/renderer/runtimescheduler" + React-utils: + :path: "../node_modules/react-native/ReactCommon/react/utils" + ReactCommon: + :path: "../node_modules/react-native/ReactCommon" + RNAppleAuthentication: + :path: "../node_modules/@invertase/react-native-apple-authentication" + RNCAsyncStorage: + :path: "../node_modules/@react-native-async-storage/async-storage" + RNCClipboard: + :path: "../node_modules/@react-native-community/clipboard" + RNCPicker: + :path: "../node_modules/@react-native-picker/picker" + RNDateTimePicker: + :path: "../node_modules/@react-native-community/datetimepicker" + RNDeviceInfo: + :path: "../node_modules/react-native-device-info" + RNDevMenu: + :path: "../node_modules/react-native-dev-menu" + RNFastImage: + :path: "../node_modules/react-native-fast-image" + RNFBAnalytics: + :path: "../node_modules/@react-native-firebase/analytics" + RNFBApp: + :path: "../node_modules/@react-native-firebase/app" + RNFBCrashlytics: + :path: "../node_modules/@react-native-firebase/crashlytics" + RNFBPerf: + :path: "../node_modules/@react-native-firebase/perf" + RNFS: + :path: "../node_modules/react-native-fs" + RNGestureHandler: + :path: "../node_modules/react-native-gesture-handler" + RNGoogleSignin: + :path: "../node_modules/@react-native-google-signin/google-signin" + RNLocalize: + :path: "../node_modules/react-native-localize" + rnmapbox-maps: + :path: "../node_modules/@rnmapbox/maps" + RNPermissions: + :path: "../node_modules/react-native-permissions" + RNReactNativeHapticFeedback: + :path: "../node_modules/react-native-haptic-feedback" + RNReanimated: + :path: "../node_modules/react-native-reanimated" + RNScreens: + :path: "../node_modules/react-native-screens" + RNSVG: + :path: "../node_modules/react-native-svg" + VisionCamera: + :path: "../node_modules/react-native-vision-camera" + Yoga: + :path: "../node_modules/react-native/ReactCommon/yoga" + +SPEC CHECKSUMS: + Airship: c70eed50e429f97f5adb285423c7291fb7a032ae + AirshipFrameworkProxy: 7bc4130c668c6c98e2d4c60fe4c9eb61a999be99 + AppAuth: 3bb1d1cd9340bd09f5ed189fb00b1cc28e1e8570 + boost: 57d2868c099736d80fcd648bf211b4431e51a558 + BVLinearGradient: 421743791a59d259aec53f4c58793aad031da2ca + CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99 + DoubleConversion: 5189b271737e1565bdce30deb4a08d647e3f5f54 + FBLazyVector: 5d4a3b7f411219a45a6d952f77d2c0a6c9989da5 + FBReactNativeSpec: 3fc2d478e1c4b08276f9dd9128f80ec6d5d85c1f + Firebase: 629510f1a9ddb235f3a7c5c8ceb23ba887f0f814 + FirebaseABTesting: 10cbce8db9985ae2e3847ea44e9947dd18f94e10 + FirebaseAnalytics: 5506ea8b867d8423485a84b4cd612d279f7b0b8a + FirebaseCore: 98b29e3828f0a53651c363937a7f7d92a19f1ba2 + FirebaseCoreDiagnostics: 92e07a649aeb66352b319d43bdd2ee3942af84cb + FirebaseCrashlytics: 3660c045c8e45cc4276110562a0ef44cf43c8157 + FirebaseInstallations: 40bd9054049b2eae9a2c38ef1c3dd213df3605cd + FirebasePerformance: 0c01a7a496657d7cea86d40c0b1725259d164c6c + FirebaseRemoteConfig: 2d6e2cfdb49af79535c8af8a80a4a5009038ec2b + Flipper: 6edb735e6c3e332975d1b17956bcc584eccf5818 + Flipper-Boost-iOSX: fd1e2b8cbef7e662a122412d7ac5f5bea715403c + Flipper-DoubleConversion: 2dc99b02f658daf147069aad9dbd29d8feb06d30 + Flipper-Fmt: 60cbdd92fc254826e61d669a5d87ef7015396a9b + Flipper-Folly: 584845625005ff068a6ebf41f857f468decd26b3 + Flipper-Glog: 70c50ce58ddaf67dc35180db05f191692570f446 + Flipper-PeerTalk: 116d8f857dc6ef55c7a5a75ea3ceaafe878aadc9 + FlipperKit: 2efad7007d6745a3f95e4034d547be637f89d3f6 + fmt: ff9d55029c625d3757ed641535fd4a75fedc7ce9 + glog: 04b94705f318337d7ead9e6d17c019bd9b1f6b1b + GoogleAppMeasurement: 5ba1164e3c844ba84272555e916d0a6d3d977e91 + GoogleDataTransport: f0308f5905a745f94fb91fea9c6cbaf3831cb1bd + GoogleSignIn: b232380cf495a429b8095d3178a8d5855b42e842 + GoogleUtilities: 9aa0ad5a7bc171f8bae016300bfcfa3fb8425749 + GTMAppAuth: 99fb010047ba3973b7026e45393f51f27ab965ae + GTMSessionFetcher: e8647203b65cee28c5f73d0f473d096653945e72 + hermes-engine: 81191603c4eaa01f5e4ae5737a9efcf64756c7b2 + libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913 + libwebp: f62cb61d0a484ba548448a4bd52aabf150ff6eef + lottie-ios: 8f97d3271e155c2d688875c29cd3c74908aef5f8 + lottie-react-native: 8f9d4be452e23f6e5ca0fdc11669dc99ab52be81 + MapboxCommon: 4a0251dd470ee37e7fadda8e285c01921a5e1eb0 + MapboxCoreMaps: eb07203bbb0b1509395db5ab89cd3ad6c2e3c04c + MapboxMaps: af50ec61a7eb3b032c3f7962c6bd671d93d2a209 + MapboxMobileEvents: de50b3a4de180dd129c326e09cd12c8adaaa46d6 + nanopb: a0ba3315591a9ae0a16a309ee504766e90db0c96 + Onfido: e36f284b865adcf99d9c905590a64ac09d4a576b + onfido-react-native-sdk: 4ecde1a97435dcff9f00a878e3f8d1eb14fabbdc + OpenSSL-Universal: ebc357f1e6bc71fa463ccb2fe676756aff50e88c + Permission-Camera: bf6791b17c7f614b6826019fcfdcc286d3a107f6 + Permission-LocationAccuracy: 76df17de5c6b8bc2eee34e61ee92cdd7a864c73d + Permission-LocationAlways: 8d99b025c9f73c696e0cdb367e42525f2e9a26f2 + Permission-LocationWhenInUse: 3ba99e45c852763f730eabecec2870c2382b7bd4 + Plaid: 7d340abeadb46c7aa1a91f896c5b22395a31fcf2 + PromisesObjC: 09985d6d70fbe7878040aa746d78236e6946d2ef + RCT-Folly: 424b8c9a7a0b9ab2886ffe9c3b041ef628fd4fb1 + RCTRequired: c0569ecc035894e4a68baecb30fe6a7ea6e399f9 + RCTTypeSafety: e90354072c21236e0bcf1699011e39acd25fea2f + React: a1be3c6dc0a6e949ccd3e659781aa47bbae1868f + React-callinvoker: 1020b33f6cb1a1824f9ca2a86609fbce2a73c6ed + React-Codegen: a0a26badf098d4a779acda922caf74f6ecabed28 + React-Core: 52075b80f10c26f62219d7b5d13d7d8089f027b3 + React-CoreModules: 21abab85d7ad9038ce2b1c33d39e3baaf7dc9244 + React-cxxreact: 4ad1cc861e32fb533dad6ff7a4ea25680fa1c994 + React-debug: 17366a3d5c5d2f5fc04f09101a4af38cb42b54ae + React-hermes: 37377d0a56aa0cf55c65248271866ce3268cde3f + React-jsi: 6de8b0ccc6b765b58e4eee9ee38049dbeaf5c221 + React-jsiexecutor: c7f826e40fa9cab5d37cab6130b1af237332b594 + React-jsinspector: aaed4cf551c4a1c98092436518c2d267b13a673f + React-logger: da1ebe05ae06eb6db4b162202faeafac4b435e77 + react-native-airship: 5d19f4ba303481cf4101ff9dee9249ef6a8a6b64 + react-native-blob-util: 99f4d79189252f597fe0d810c57a3733b1b1dea6 + react-native-cameraroll: 8ffb0af7a5e5de225fd667610e2979fc1f0c2151 + react-native-config: 7cd105e71d903104e8919261480858940a6b9c0e + react-native-document-picker: f68191637788994baed5f57d12994aa32cf8bf88 + react-native-flipper: dc5290261fbeeb2faec1bdc57ae6dd8d562e1de4 + react-native-image-manipulator: c48f64221cfcd46e9eec53619c4c0374f3328a56 + react-native-image-picker: c33d4e79f0a14a2b66e5065e14946ae63749660b + react-native-key-command: c2645ec01eb1fa664606c09480c05cb4220ef67b + react-native-netinfo: ccbe1085dffd16592791d550189772e13bf479e2 + react-native-pager-view: 0ccb8bf60e2ebd38b1f3669fa3650ecce81db2df + react-native-pdf: 7c0e91ada997bac8bac3bb5bea5b6b81f5a3caae + react-native-performance: cef2b618d47b277fb5c3280b81a3aad1e72f2886 + react-native-plaid-link-sdk: 9eb0f71dad94b3bdde649c7a384cba93024af46c + react-native-quick-sqlite: bcc7a7a250a40222f18913a97cd356bf82d0a6c4 + react-native-render-html: 96c979fe7452a0a41559685d2f83b12b93edac8c + react-native-safe-area-context: 99b24a0c5acd0d5dcac2b1a7f18c49ea317be99a + react-native-view-shot: 705f999ac2a24e4e6c909c0ca65c732ed33ca2ff + react-native-webview: e771bc375f789ebfa02a26939a57dbc6fa897336 + React-NativeModulesApple: edb5ace14f73f4969df6e7b1f3e41bef0012740f + React-perflogger: 496a1a3dc6737f964107cb3ddae7f9e265ddda58 + React-RCTActionSheet: 02904b932b50e680f4e26e7a686b33ebf7ef3c00 + React-RCTAnimation: 88feaf0a85648fb8fd497ce749829774910276d6 + React-RCTAppDelegate: 5792ac0f0feccb584765fdd7aa81ea320c4d9b0b + React-RCTBlob: 0dbc9e2a13d241b37d46b53e54630cbad1f0e141 + React-RCTImage: b111645ab901f8e59fc68fbe31f5731bdbeef087 + React-RCTLinking: 3d719727b4c098aad3588aa3559361ee0579f5de + React-RCTNetwork: b44d3580be05d74556ba4efbf53570f17e38f734 + React-RCTSettings: c0c54b330442c29874cd4dae6e94190dc11a6f6f + React-RCTText: 9b9f5589d9b649d7246c3f336e116496df28cfe6 + React-RCTVibration: 691c67f3beaf1d084ceed5eb5c1dddd9afa8591e + React-rncore: 142268f6c92e296dc079aadda3fade778562f9e4 + React-runtimeexecutor: d465ba0c47ef3ed8281143f59605cacc2244d5c7 + React-runtimescheduler: 4941cc1b3cf08b792fbf666342c9fc95f1969035 + React-utils: b79f2411931f9d3ea5781404dcbb2fa8a837e13a + ReactCommon: 4b2bdcb50a3543e1c2b2849ad44533686610826d + RNAppleAuthentication: 0571c08da8c327ae2afc0261b48b4a515b0286a6 + RNCAsyncStorage: 8616bd5a58af409453ea4e1b246521bb76578d60 + RNCClipboard: 41d8d918092ae8e676f18adada19104fa3e68495 + RNCPicker: 0b65be85fe7954fbb2062ef079e3d1cde252d888 + RNDateTimePicker: 7658208086d86d09e1627b5c34ba0cf237c60140 + RNDeviceInfo: 4701f0bf2a06b34654745053db0ce4cb0c53ada7 + RNDevMenu: 72807568fe4188bd4c40ce32675d82434b43c45d + RNFastImage: 5c9c9fed9c076e521b3f509fe79e790418a544e8 + RNFBAnalytics: f76bfa164ac235b00505deb9fc1776634056898c + RNFBApp: 729c0666395b1953198dc4a1ec6deb8fbe1c302e + RNFBCrashlytics: 2061ca863e8e2fa1aae9b12477d7dfa8e88ca0f9 + RNFBPerf: 389914cda4000fe0d996a752532a591132cbf3f9 + RNFS: 4ac0f0ea233904cb798630b3c077808c06931688 + RNGestureHandler: dec4645026e7401a0899f2846d864403478ff6a5 + RNGoogleSignin: ccaa4a81582cf713eea562c5dd9dc1961a715fd0 + RNLocalize: d4b8af4e442d4bcca54e68fc687a2129b4d71a81 + rnmapbox-maps: 6f638ec002aa6e906a6f766d69cd45f968d98e64 + RNPermissions: dcdb7b99796bbeda6975a6e79ad519c41b251b1c + RNReactNativeHapticFeedback: 1e3efeca9628ff9876ee7cdd9edec1b336913f8c + RNReanimated: 020859659f64be2d30849a1fe88c821a7c3e0cbf + RNScreens: d037903436160a4b039d32606668350d2a808806 + RNSVG: ed492aaf3af9ca01bc945f7a149d76d62e73ec82 + SDWebImage: a7f831e1a65eb5e285e3fb046a23fcfbf08e696d + SDWebImageWebPCoder: 908b83b6adda48effe7667cd2b7f78c897e5111d + SocketRocket: f32cd54efbe0f095c4d7594881e52619cfe80b17 + Turf: 469ce2c3d22e5e8e4818d5a3b254699a5c89efa4 + VisionCamera: d3ec8883417a6a4a0e3a6ba37d81d22db7611601 + Yoga: 3efc43e0d48686ce2e8c60f99d4e6bd349aff981 + YogaKit: f782866e155069a2cca2517aafea43200b01fd5a + +PODFILE CHECKSUM: 2daf34c870819a933f3fefe426801d54b2ff2a14 + +COCOAPODS: 1.12.1 From 39bd03a80919b9411113987b3219803ee27cb2da Mon Sep 17 00:00:00 2001 From: keisyrzk Date: Thu, 5 Oct 2023 09:44:32 +0200 Subject: [PATCH 019/237] podfile.lock update content --- ios/Podfile.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 51b9f6af0e21..f157e8d0558a 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -783,7 +783,7 @@ PODS: - React-Core - RNReactNativeHapticFeedback (1.14.0): - React-Core - - RNReanimated (3.4.0): + - RNReanimated (3.5.4): - DoubleConversion - FBLazyVector - glog @@ -1298,7 +1298,7 @@ SPEC CHECKSUMS: rnmapbox-maps: 6f638ec002aa6e906a6f766d69cd45f968d98e64 RNPermissions: dcdb7b99796bbeda6975a6e79ad519c41b251b1c RNReactNativeHapticFeedback: 1e3efeca9628ff9876ee7cdd9edec1b336913f8c - RNReanimated: 020859659f64be2d30849a1fe88c821a7c3e0cbf + RNReanimated: ab2e96c6d5591c3dfbb38a464f54c8d17fb34a87 RNScreens: d037903436160a4b039d32606668350d2a808806 RNSVG: ed492aaf3af9ca01bc945f7a149d76d62e73ec82 SDWebImage: a7f831e1a65eb5e285e3fb046a23fcfbf08e696d @@ -1311,4 +1311,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: 2daf34c870819a933f3fefe426801d54b2ff2a14 -COCOAPODS: 1.12.1 +COCOAPODS: 1.12.1 \ No newline at end of file From c9cb983370a591f5c141edbca2a1c78850697c75 Mon Sep 17 00:00:00 2001 From: keisyrzk Date: Thu, 5 Oct 2023 11:00:39 +0200 Subject: [PATCH 020/237] podfile.lock empty space missing --- ios/Podfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ios/Podfile.lock b/ios/Podfile.lock index f157e8d0558a..ba53d939e46c 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -1311,4 +1311,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: 2daf34c870819a933f3fefe426801d54b2ff2a14 -COCOAPODS: 1.12.1 \ No newline at end of file +COCOAPODS: 1.12.1 From 5bc5c7684049d05889882e44af6f27f8d9444133 Mon Sep 17 00:00:00 2001 From: keisyrzk Date: Fri, 6 Oct 2023 07:09:14 +0200 Subject: [PATCH 021/237] Update src/components/AvatarWithImagePicker.js Co-authored-by: Eugene Voloshchak --- src/components/AvatarWithImagePicker.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/AvatarWithImagePicker.js b/src/components/AvatarWithImagePicker.js index 156c08254a95..c7523cdef942 100644 --- a/src/components/AvatarWithImagePicker.js +++ b/src/components/AvatarWithImagePicker.js @@ -137,7 +137,8 @@ function AvatarWithImagePicker({ anchorPosition, anchorAlignment, onImageSelected, - editorMaskImage }) { + editorMaskImage, +}) { const animation = useRef(new SpinningIndicatorAnimation()).current; const [isMenuVisible, setIsMenuVisible] = useState(false); From 06cd120a850b3c88eba752c02d513234dda00570 Mon Sep 17 00:00:00 2001 From: keisyrzk Date: Fri, 6 Oct 2023 07:17:06 +0200 Subject: [PATCH 022/237] pr updates --- src/components/AvatarWithImagePicker.js | 68 ++++++++++++------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/src/components/AvatarWithImagePicker.js b/src/components/AvatarWithImagePicker.js index c7523cdef942..8360e323d4ce 100644 --- a/src/components/AvatarWithImagePicker.js +++ b/src/components/AvatarWithImagePicker.js @@ -275,45 +275,45 @@ function AvatarWithImagePicker({ const additionalStyles = _.isArray(style) ? style : [style]; - /** + /** * Create menu items list for avatar menu * * @param {Function} openPicker * @returns {Array} */ - const createMenuItems = (openPicker) => { - const menuItems = [ - { - icon: Expensicons.Upload, - text: translate('avatarWithImagePicker.uploadPhoto'), - onSelected: () => { - if (Browser.isSafari()) { - return; - } - openPicker({ - onPicked: showAvatarCropModal, - }); - }, - }, - ]; + const createMenuItems = (openPicker) => { + const menuItems = [ + { + icon: Expensicons.Upload, + text: translate('avatarWithImagePicker.uploadPhoto'), + onSelected: () => { + if (Browser.isSafari()) { + return; + } + openPicker({ + onPicked: showAvatarCropModal, + }); + }, + }, + ]; - // If current avatar isn't a default avatar, allow Remove Photo option - if (!isUsingDefaultAvatar) { - menuItems.push({ - icon: Expensicons.Trashcan, - text: translate('avatarWithImagePicker.removePhoto'), - onSelected: () => { - setError(null, {}); - onImageRemoved(); - }, - }); - } - return menuItems; - }; + // If current avatar isn't a default avatar, allow Remove Photo option + if (!isUsingDefaultAvatar) { + menuItems.push({ + icon: Expensicons.Trashcan, + text: translate('avatarWithImagePicker.removePhoto'), + onSelected: () => { + setError(null, {}); + onImageRemoved(); + }, + }); + } + return menuItems; + }; return ( - + - {({show}) => ( - - {({openPicker}) => { + {({show}) => ( + + {({openPicker}) => { const menuItems = createMenuItems(openPicker); // If the current avatar isn't a default avatar, allow the "View Photo" option @@ -423,4 +423,4 @@ function AvatarWithImagePicker({ AvatarWithImagePicker.propTypes = propTypes; AvatarWithImagePicker.defaultProps = defaultProps; -export default withNavigationFocus(AvatarWithImagePicker); \ No newline at end of file +export default withNavigationFocus(AvatarWithImagePicker); From 9159c3e9bba07b57462c3cad06d3b3817fe89215 Mon Sep 17 00:00:00 2001 From: keisyrzk Date: Fri, 6 Oct 2023 12:23:12 +0200 Subject: [PATCH 023/237] updates --- ios/Podfile.lock | 2 +- src/components/AvatarWithImagePicker.js | 58 +++++++------------------ 2 files changed, 17 insertions(+), 43 deletions(-) diff --git a/ios/Podfile.lock b/ios/Podfile.lock index ba53d939e46c..f157e8d0558a 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -1311,4 +1311,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: 2daf34c870819a933f3fefe426801d54b2ff2a14 -COCOAPODS: 1.12.1 +COCOAPODS: 1.12.1 \ No newline at end of file diff --git a/src/components/AvatarWithImagePicker.js b/src/components/AvatarWithImagePicker.js index 8360e323d4ce..bf14e9afb770 100644 --- a/src/components/AvatarWithImagePicker.js +++ b/src/components/AvatarWithImagePicker.js @@ -15,7 +15,6 @@ import OfflineWithFeedback from './OfflineWithFeedback'; import useLocalize from '../hooks/useLocalize'; import variables from '../styles/variables'; import CONST from '../CONST'; -import SpinningIndicatorAnimation from '../styles/animation/SpinningIndicatorAnimation'; import Tooltip from './Tooltip'; import stylePropTypes from '../styles/stylePropTypes'; import * as FileUtils from '../libs/fileDownload/FileUtils'; @@ -113,7 +112,6 @@ const defaultProps = { headerTitle: '', previewSource: '', originalFileName: '', - displayName: `AvatarWithImagePicker`, }; function AvatarWithImagePicker({ @@ -140,7 +138,6 @@ function AvatarWithImagePicker({ editorMaskImage, }) { - const animation = useRef(new SpinningIndicatorAnimation()).current; const [isMenuVisible, setIsMenuVisible] = useState(false); const [errorData, setErrorData] = useState({ validationError: null, @@ -155,16 +152,6 @@ function AvatarWithImagePicker({ const anchorRef = useRef(); const {translate} = useLocalize(); - useEffect(() => { - if (isUploading) { - animation.start(); - } - - return () => { - animation.stop(); - }; - }, [isUploading]); - useEffect(() => { // check if the component is no longer focused, then reset the error. if (!isFocused) { @@ -190,7 +177,7 @@ function AvatarWithImagePicker({ * @returns {Boolean} */ const isValidExtension = (image) => { - const { fileExtension } = FileUtils.splitExtensionFromFileName(lodashGet(image, 'name', '')); + const {fileExtension} = FileUtils.splitExtensionFromFileName(lodashGet(image, 'name', '')); return _.contains(CONST.AVATAR_ALLOWED_EXTENSIONS, fileExtension.toLowerCase()); }; @@ -223,9 +210,18 @@ function AvatarWithImagePicker({ * * @param {Object} image */ - function showAvatarCropModal(image) { - const handleResolutionValidation = (isValidRes) => { - if (!isValidRes) { + const showAvatarCropModal = (image) => { + if (!isValidExtension(image)) { + setError('avatarWithImagePicker.notAllowedExtension', {allowedExtensions: CONST.AVATAR_ALLOWED_EXTENSIONS}); + return; + } + if (!isValidSize(image)) { + setError('avatarWithImagePicker.sizeExceeded', {maxUploadSizeInMB: CONST.AVATAR_MAX_ATTACHMENT_SIZE / (1024 * 1024)}); + return; + } + + isValidResolution(image).then((isValid) => { + if (!isValid) { setError('avatarWithImagePicker.resolutionConstraints', { minHeightInPx: CONST.AVATAR_MIN_HEIGHT_PX, minWidthInPx: CONST.AVATAR_MIN_WIDTH_PX, @@ -234,7 +230,7 @@ function AvatarWithImagePicker({ }); return; } - + setIsAvatarCropModalOpen(true); setError(null, {}); setIsMenuVisible(false); @@ -243,31 +239,8 @@ function AvatarWithImagePicker({ name: image.name, type: image.type }); - }; - - return new Promise((resolve, reject) => { - if (!isValidExtension(image)) { - setError('avatarWithImagePicker.notAllowedExtension', { - allowedExtensions: CONST.AVATAR_ALLOWED_EXTENSIONS - }); - reject(new Error('Invalid extension')); - } - - if (!isValidSize(image)) { - setError('avatarWithImagePicker.sizeExceeded', { - maxUploadSizeInMB: CONST.AVATAR_MAX_ATTACHMENT_SIZE / (1024 * 1024) - }); - reject(new Error('Invalid size')); - } - - resolve(image); - }) - .then(isValidResolution) - .then(handleResolutionValidation) - .catch(err => { - console.error("Error in showAvatarCropModal:", err); }); - } + }; const hideAvatarCropModal = () => { setIsAvatarCropModalOpen(false); @@ -422,5 +395,6 @@ function AvatarWithImagePicker({ AvatarWithImagePicker.propTypes = propTypes; AvatarWithImagePicker.defaultProps = defaultProps; +AvatarWithImagePicker.displayName = 'AvatarWithImagePicker'; export default withNavigationFocus(AvatarWithImagePicker); From f2427743df8ed7d74fd2db1b32514d53a774f7e9 Mon Sep 17 00:00:00 2001 From: keisyrzk Date: Mon, 9 Oct 2023 09:57:36 +0200 Subject: [PATCH 024/237] lint updates --- src/components/AvatarWithImagePicker.js | 261 ++++++++++++------------ 1 file changed, 131 insertions(+), 130 deletions(-) diff --git a/src/components/AvatarWithImagePicker.js b/src/components/AvatarWithImagePicker.js index bf14e9afb770..743bf93acadf 100644 --- a/src/components/AvatarWithImagePicker.js +++ b/src/components/AvatarWithImagePicker.js @@ -1,6 +1,6 @@ import _ from 'underscore'; -import React, {useState, useRef, useEffect} from 'react'; -import {View} from 'react-native'; +import React, { useState, useRef, useEffect } from 'react'; +import { View } from 'react-native'; import PropTypes from 'prop-types'; import lodashGet from 'lodash/get'; import Avatar from './Avatar'; @@ -23,8 +23,7 @@ import PressableWithoutFeedback from './Pressable/PressableWithoutFeedback'; import AttachmentModal from './AttachmentModal'; import DotIndicatorMessage from './DotIndicatorMessage'; import * as Browser from '../libs/Browser'; -import withNavigationFocus, {withNavigationFocusPropTypes} from './withNavigationFocus'; -import compose from '../libs/compose'; +import withNavigationFocus, { withNavigationFocusPropTypes } from './withNavigationFocus'; const propTypes = { /** Avatar source to display */ @@ -95,10 +94,10 @@ const propTypes = { const defaultProps = { source: '', - onImageSelected: () => {}, - onImageRemoved: () => {}, + onImageSelected: () => { }, + onImageRemoved: () => { }, style: [], - DefaultAvatar: () => {}, + DefaultAvatar: () => { }, isUsingDefaultAvatar: false, isUploading: false, size: CONST.AVATAR_SIZE.DEFAULT, @@ -106,7 +105,7 @@ const defaultProps = { type: CONST.ICON_TYPE_AVATAR, editorMaskImage: undefined, errorRowStyles: [], - onErrorClose: () => {}, + onErrorClose: () => { }, pendingAction: null, errors: null, headerTitle: '', @@ -114,35 +113,33 @@ const defaultProps = { originalFileName: '', }; -function AvatarWithImagePicker({ - isUploading, - isFocused, - DefaultAvatar, - style, - pendingAction, - errors, - errorRowStyles, - onErrorClose, - source, - fallbackIcon, - size, - type, - headerTitle, - previewSource, - originalFileName, - isUsingDefaultAvatar, - onImageRemoved, - anchorPosition, - anchorAlignment, - onImageSelected, +function AvatarWithImagePicker({ + isFocused, + DefaultAvatar, + style, + pendingAction, + errors, + errorRowStyles, + onErrorClose, + source, + fallbackIcon, + size, + type, + headerTitle, + previewSource, + originalFileName, + isUsingDefaultAvatar, + onImageRemoved, + anchorPosition, + anchorAlignment, + onImageSelected, editorMaskImage, }) { - const [isMenuVisible, setIsMenuVisible] = useState(false); const [errorData, setErrorData] = useState({ validationError: null, phraseParam: {}, - }); + }); const [isAvatarCropModalOpen, setIsAvatarCropModalOpen] = useState(false); const [imageData, setImageData] = useState({ uri: '', @@ -150,13 +147,16 @@ function AvatarWithImagePicker({ type: '' }); const anchorRef = useRef(); - const {translate} = useLocalize(); - + const { translate } = useLocalize(); + useEffect(() => { - // check if the component is no longer focused, then reset the error. - if (!isFocused) { - setError(null, {}); + // If the component is still focused, don't proceed further. + if (isFocused) { + return; } + + // Reset the error if the component is no longer focused. + setError(null, {}); }, [isFocused]); /** @@ -166,7 +166,7 @@ function AvatarWithImagePicker({ const setError = (error, phraseParam) => { setErrorData({ validationError: error, - phraseParam: phraseParam, + phraseParam, }); }; @@ -177,19 +177,17 @@ function AvatarWithImagePicker({ * @returns {Boolean} */ const isValidExtension = (image) => { - const {fileExtension} = FileUtils.splitExtensionFromFileName(lodashGet(image, 'name', '')); + const { fileExtension } = FileUtils.splitExtensionFromFileName(lodashGet(image, 'name', '')); return _.contains(CONST.AVATAR_ALLOWED_EXTENSIONS, fileExtension.toLowerCase()); }; - /** - * Check if the attachment size is less than allowed size. - * - * @param {Object} image - * @returns {Boolean} - */ - const isValidSize = (image) => { - return image && lodashGet(image, 'size', 0) < CONST.AVATAR_MAX_ATTACHMENT_SIZE; - }; + /** + * Check if the attachment size is less than allowed size. + * + * @param {Object} image + * @returns {Boolean} + */ + const isValidSize = (image) => image && lodashGet(image, 'size', 0) < CONST.AVATAR_MAX_ATTACHMENT_SIZE; /** * Check if the attachment resolution matches constraints. @@ -197,13 +195,16 @@ function AvatarWithImagePicker({ * @param {Object} image * @returns {Promise} */ - const isValidResolution = async (image) => { - const resolution = await getImageResolution(image); - return resolution.height >= CONST.AVATAR_MIN_HEIGHT_PX && - resolution.width >= CONST.AVATAR_MIN_WIDTH_PX && - resolution.height <= CONST.AVATAR_MAX_HEIGHT_PX && - resolution.width <= CONST.AVATAR_MAX_WIDTH_PX; + const isValidResolution = (image) => { + return getImageResolution(image) + .then(({ height, width }) => + height >= CONST.AVATAR_MIN_HEIGHT_PX && + width >= CONST.AVATAR_MIN_WIDTH_PX && + height <= CONST.AVATAR_MAX_HEIGHT_PX && + width <= CONST.AVATAR_MAX_WIDTH_PX + ); }; + /** * Validates if an image has a valid resolution and opens an avatar crop modal @@ -212,11 +213,11 @@ function AvatarWithImagePicker({ */ const showAvatarCropModal = (image) => { if (!isValidExtension(image)) { - setError('avatarWithImagePicker.notAllowedExtension', {allowedExtensions: CONST.AVATAR_ALLOWED_EXTENSIONS}); + setError('avatarWithImagePicker.notAllowedExtension', { allowedExtensions: CONST.AVATAR_ALLOWED_EXTENSIONS }); return; } if (!isValidSize(image)) { - setError('avatarWithImagePicker.sizeExceeded', {maxUploadSizeInMB: CONST.AVATAR_MAX_ATTACHMENT_SIZE / (1024 * 1024)}); + setError('avatarWithImagePicker.sizeExceeded', { maxUploadSizeInMB: CONST.AVATAR_MAX_ATTACHMENT_SIZE / (1024 * 1024) }); return; } @@ -262,14 +263,14 @@ function AvatarWithImagePicker({ onSelected: () => { if (Browser.isSafari()) { return; - } + } openPicker({ onPicked: showAvatarCropModal, - }); - }, - }, + }); + }, + }, ]; - + // If current avatar isn't a default avatar, allow Remove Photo option if (!isUsingDefaultAvatar) { menuItems.push({ @@ -278,65 +279,65 @@ function AvatarWithImagePicker({ onSelected: () => { setError(null, {}); onImageRemoved(); - }, - }); + }, + }); } return menuItems; - }; - + }; + return ( - - - setIsMenuVisible(prev => !prev)} - accessibilityRole={CONST.ACCESSIBILITY_ROLE.IMAGEBUTTON} - accessibilityLabel={translate('avatarWithImagePicker.editImage')} - disabled={isAvatarCropModalOpen} - ref={anchorRef} - > - - {source ? ( - - ) : ( - - )} - - - + + setIsMenuVisible(prev => !prev)} + accessibilityRole={CONST.ACCESSIBILITY_ROLE.IMAGEBUTTON} + accessibilityLabel={translate('avatarWithImagePicker.editImage')} + disabled={isAvatarCropModalOpen} + ref={anchorRef} + > + + {source ? ( + - - - - - - {({show}) => ( + ) : ( + + )} + + + + + + + + + {({ show }) => ( - {({openPicker}) => { + {({ openPicker }) => { const menuItems = createMenuItems(openPicker); - + // If the current avatar isn't a default avatar, allow the "View Photo" option if (!isUsingDefaultAvatar) { menuItems.push({ @@ -345,7 +346,7 @@ function AvatarWithImagePicker({ onSelected: show, }); } - + return ( - )} - - - {errorData.validationError && ( - - )} - + + {errorData.validationError && ( + + )} + ); } From 379c274a9e72d40f834f32a72ea1d665ab570e91 Mon Sep 17 00:00:00 2001 From: keisyrzk Date: Tue, 10 Oct 2023 08:40:03 +0200 Subject: [PATCH 025/237] pr empty sapces fix --- src/components/AvatarWithImagePicker.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/components/AvatarWithImagePicker.js b/src/components/AvatarWithImagePicker.js index 743bf93acadf..93c90008d34c 100644 --- a/src/components/AvatarWithImagePicker.js +++ b/src/components/AvatarWithImagePicker.js @@ -1,6 +1,6 @@ import _ from 'underscore'; -import React, { useState, useRef, useEffect } from 'react'; -import { View } from 'react-native'; +import React, {useState, useRef, useEffect} from 'react'; +import {View} from 'react-native'; import PropTypes from 'prop-types'; import lodashGet from 'lodash/get'; import Avatar from './Avatar'; @@ -23,7 +23,7 @@ import PressableWithoutFeedback from './Pressable/PressableWithoutFeedback'; import AttachmentModal from './AttachmentModal'; import DotIndicatorMessage from './DotIndicatorMessage'; import * as Browser from '../libs/Browser'; -import withNavigationFocus, { withNavigationFocusPropTypes } from './withNavigationFocus'; +import withNavigationFocus, {withNavigationFocusPropTypes} from './withNavigationFocus'; const propTypes = { /** Avatar source to display */ @@ -94,10 +94,10 @@ const propTypes = { const defaultProps = { source: '', - onImageSelected: () => { }, - onImageRemoved: () => { }, + onImageSelected: () => {}, + onImageRemoved: () => {}, style: [], - DefaultAvatar: () => { }, + DefaultAvatar: () => {}, isUsingDefaultAvatar: false, isUploading: false, size: CONST.AVATAR_SIZE.DEFAULT, @@ -105,7 +105,7 @@ const defaultProps = { type: CONST.ICON_TYPE_AVATAR, editorMaskImage: undefined, errorRowStyles: [], - onErrorClose: () => { }, + onErrorClose: () => {}, pendingAction: null, errors: null, headerTitle: '', @@ -147,7 +147,7 @@ function AvatarWithImagePicker({ type: '' }); const anchorRef = useRef(); - const { translate } = useLocalize(); + const {translate} = useLocalize(); useEffect(() => { // If the component is still focused, don't proceed further. From 09b694380c6cec4f03a21b3bc5621aab32e15667 Mon Sep 17 00:00:00 2001 From: keisyrzk Date: Tue, 10 Oct 2023 14:27:06 +0200 Subject: [PATCH 026/237] lint fix --- src/components/AvatarWithImagePicker.js | 45 +++++++++++-------------- 1 file changed, 19 insertions(+), 26 deletions(-) diff --git a/src/components/AvatarWithImagePicker.js b/src/components/AvatarWithImagePicker.js index 93c90008d34c..01522a09fe75 100644 --- a/src/components/AvatarWithImagePicker.js +++ b/src/components/AvatarWithImagePicker.js @@ -52,9 +52,6 @@ const propTypes = { left: PropTypes.number, }).isRequired, - /** Flag to see if image is being uploaded */ - isUploading: PropTypes.bool, - /** Size of Indicator */ size: PropTypes.oneOf([CONST.AVATAR_SIZE.LARGE, CONST.AVATAR_SIZE.DEFAULT]), @@ -99,7 +96,6 @@ const defaultProps = { style: [], DefaultAvatar: () => {}, isUsingDefaultAvatar: false, - isUploading: false, size: CONST.AVATAR_SIZE.DEFAULT, fallbackIcon: Expensicons.FallbackAvatar, type: CONST.ICON_TYPE_AVATAR, @@ -148,9 +144,19 @@ function AvatarWithImagePicker({ }); const anchorRef = useRef(); const {translate} = useLocalize(); + + /** + * @param {String} error + * @param {Object} phraseParam + */ + const setError = (error, phraseParam) => { + setErrorData({ + validationError: error, + phraseParam, + }); + }; useEffect(() => { - // If the component is still focused, don't proceed further. if (isFocused) { return; } @@ -159,17 +165,6 @@ function AvatarWithImagePicker({ setError(null, {}); }, [isFocused]); - /** - * @param {String} error - * @param {Object} phraseParam - */ - const setError = (error, phraseParam) => { - setErrorData({ - validationError: error, - phraseParam, - }); - }; - /** * Check if the attachment extension is allowed. * @@ -195,16 +190,14 @@ function AvatarWithImagePicker({ * @param {Object} image * @returns {Promise} */ - const isValidResolution = (image) => { - return getImageResolution(image) - .then(({ height, width }) => - height >= CONST.AVATAR_MIN_HEIGHT_PX && - width >= CONST.AVATAR_MIN_WIDTH_PX && - height <= CONST.AVATAR_MAX_HEIGHT_PX && - width <= CONST.AVATAR_MAX_WIDTH_PX - ); - }; - + const isValidResolution = (image) => + getImageResolution(image) + .then(({ height, width }) => + height >= CONST.AVATAR_MIN_HEIGHT_PX && + width >= CONST.AVATAR_MIN_WIDTH_PX && + height <= CONST.AVATAR_MAX_HEIGHT_PX && + width <= CONST.AVATAR_MAX_WIDTH_PX + ); /** * Validates if an image has a valid resolution and opens an avatar crop modal From 2ad7c4df4f7420e66acacd550da508f31713de56 Mon Sep 17 00:00:00 2001 From: keisyrzk Date: Thu, 12 Oct 2023 08:14:32 +0200 Subject: [PATCH 027/237] remove SpinningIndicatorAnimation file --- .../animation/SpinningIndicatorAnimation.js | 89 ------------------- 1 file changed, 89 deletions(-) delete mode 100644 src/styles/animation/SpinningIndicatorAnimation.js diff --git a/src/styles/animation/SpinningIndicatorAnimation.js b/src/styles/animation/SpinningIndicatorAnimation.js deleted file mode 100644 index 29044f0d127a..000000000000 --- a/src/styles/animation/SpinningIndicatorAnimation.js +++ /dev/null @@ -1,89 +0,0 @@ -import {Animated, Easing} from 'react-native'; -import useNativeDriver from '../../libs/useNativeDriver'; - -class SpinningIndicatorAnimation { - constructor() { - this.rotate = new Animated.Value(0); - this.scale = new Animated.Value(1); - this.startRotation = this.startRotation.bind(this); - this.start = this.start.bind(this); - this.stop = this.stop.bind(this); - this.getSyncingStyles = this.getSyncingStyles.bind(this); - } - - /** - * Rotation animation for indicator in a loop - * - * @memberof AvatarWithImagePicker - */ - startRotation() { - this.rotate.setValue(0); - Animated.loop( - Animated.timing(this.rotate, { - toValue: 1, - duration: 2000, - easing: Easing.linear, - isInteraction: false, - - // Animated.loop does not work with `useNativeDriver: true` on Web - useNativeDriver, - }), - ).start(); - } - - /** - * Start Animation for Indicator - * - * @memberof AvatarWithImagePicker - */ - start() { - this.startRotation(); - Animated.spring(this.scale, { - toValue: 1.666, - tension: 1, - isInteraction: false, - useNativeDriver, - }).start(); - } - - /** - * Stop Animation for Indicator - * - * @memberof AvatarWithImagePicker - */ - stop() { - Animated.spring(this.scale, { - toValue: 1, - tension: 1, - isInteraction: false, - useNativeDriver, - }).start(() => { - this.rotate.resetAnimation(); - this.scale.resetAnimation(); - this.rotate.setValue(0); - }); - } - - /** - * Get Indicator Styles while animating - * - * @returns {Object} - */ - getSyncingStyles() { - return { - transform: [ - { - rotate: this.rotate.interpolate({ - inputRange: [0, 1], - outputRange: ['0deg', '-360deg'], - }), - }, - { - scale: this.scale, - }, - ], - }; - } -} - -export default SpinningIndicatorAnimation; From 1c5ea6b610317d019b682113bb3ac0aa784c16ab Mon Sep 17 00:00:00 2001 From: Al Garces Date: Thu, 12 Oct 2023 17:11:28 -0700 Subject: [PATCH 028/237] Update Close-Account.md Updating the Close Account resource to the help site --- .../account-settings/Close-Account.md | 123 +++++++++++++++++- 1 file changed, 120 insertions(+), 3 deletions(-) diff --git a/docs/articles/expensify-classic/account-settings/Close-Account.md b/docs/articles/expensify-classic/account-settings/Close-Account.md index 5e18490fc357..7efa8e9ec255 100644 --- a/docs/articles/expensify-classic/account-settings/Close-Account.md +++ b/docs/articles/expensify-classic/account-settings/Close-Account.md @@ -1,5 +1,122 @@ --- -title: Close Account +title: Close-Account.md description: Close Account ---- -## Resource Coming Soon! +--- +# Overview + +Here is a walk through of how to close an Expensify account through the website or mobile app. + +# How to close your account +On the Web: + +1. Go to **Settings** in the left hand menu. Click **Account**. +2. Click “Close Account” +3. Follow the prompts to verify your email or phone number. +4. Your account will be closed, and all data will be deleted.* + +![Insert alt text for accessibility here](https://help.expensify.com/assets/images/image-name.png){:width="100%"} + +On the Mobile App: + +Open the app and tap the three horizontal lines in the upper left corner. +Select Settings from the menu. +Look for the "Close Account" option in the "Others" section. (If you don’t see this option, you have a Domain Controlled account and will need to ask your Domain Admin to delete your account.) +Complete the verification process using your email or phone number. +Your account will be closed, and all data will be deleted.* + +![Insert alt text for accessibility here](https://help.expensify.com/assets/images/image-name.png){:width="100%"} + +These instructions may vary depending on the specific device you are using, so be sure to follow the steps as they appear on your screen. + +*Note: Transactions shared with other accounts will still be visible to those accounts. (Example: A report submitted to your company and reimbursed will not be deleted from your company’s account.) Additionally, we are required to retain certain records of transactions in compliance with laws in various jurisdictions. + +# How to reopen your account + +If your Expensify account is closed and not associated with a verified domain, you can reopen it with the following steps: + +1. Visit [expensify.com](https://www.expensify.com/). +2. Attempt to sign in using your email address or phone number associated with the closed account. +3. After entering your user name, you will see the following prompt: [Insert Image 3] +4. Click on **Reopen Account**. +5. A magic link will be sent to your email address. +6. Access your email and click on the magic link. This link will take you to Expensify and reopen your account. +7. Follow the prompts to create a new password associated with your account. +8. Your account is now reopened. Any previously approved expense data will still be visible in the account. + +Note: Reports submitted and closed on an Individual workspace will not be retained since they have not been approved or shared with anyone else in Expensify. + +That's it! Your account is successfully reopened, and you can access your historical data that was shared with other accounts. Remember to recreate any workspaces and adjust settings if needed. + +# How to Reopen a Domain-controlled account +Once an account has been **Closed** by a Domain Admin, it can be reopened by any Domain Admin on that domain. + +The Domain Admin will simply need to invite the previously closed account in the same manner that new accounts are invited to the Domain. The user will receive a magic link to their email account which they can use to Reopen the account. + +# How to retain a free account to keep historical expenses +If you no longer need a group workspace or have a more advanced workspace than necessary in Expensify, and you want to downgrade while retaining your historical data, here's what you should do: + +1. If you're part of a group worksapce, request the Workspace Admin to remove you, or if you own the workspace, delete it to downgrade to a free version. +2. Once you've removed or been removed from a workspace, start using your free Expensify account. Your submitted expenses will still be saved, allowing you to access the historical data. +3. Domain Admins in the company will still retain access to approved and reimbursed expenses. +4. To keep your data, avoid closing your account. Account closures are irreversible and will result in the deletion of all your unapproved data. + +# Deep Dive + +## I’m unable to close my account + +If you're encountering an error message while trying to close your Expensify account, it's important to pinpoint the specific error. Encountering an error when trying to close your account is typically only experienced if the account has been an admin on a company’s Expensify workspace. (Especially if the account was involved in responsibilities like reimbursing employees or exporting expense reports.) + +In order to avoid users accidentally creating issues for their company, Expensify prevents account closure if you still have any individual responsibilities related to a Workspace within the platform. To successfully close your account, you need to ensure that your worksapce no longer relies on your account to operate. + +Here are the reasons why you might encounter an error when trying to close your Expensify account, along with the actions required to address each of these issues: + +- **Account Under a Validated Domain**: If your account is associated with a validated domain, only a Domain Admin can close it. You can find this option in your Domain Admin's settings under Settings > Domains > Domain Members. Afterward, if you have a secondary personal login, you can delete it by following the instructions mentioned above. +- **Sole Domain Admin for Your Company**: If you are the only Domain Admin for your company's domain, you must appoint another Domain Admin before you can close your account. This is to avoid accidentally prohibiting your entire company from using Expensify. You can do this by going to Settings > Domains > [Domain Name] > Domain Admins and making the necessary changes, or you can reset the entire domain. +- **Workspace Billing Owner with an Annual Subscription**: If you are the Workspace Billing Owner with an Annual Subscription, you need to downgrade from the Annual subscription before closing the account. Alternatively, you can have another user take over billing for your workspaces. +- **Ownership of a Company Workspace or Outstanding Balance**: If you own a company workspace or there is an outstanding balance owed to Expensify, you must take one of the following actions before closing your account: + + - Make the payment for the outstanding balance. + - Have another user take over billing for the workspace. + - Request a refund for your initial bill. + - Delete the workspace. + +- **Preferred Exporter for Your Workspace Integration**: If you are the "Preferred Exporter" for a workspace Integration, you must update the Preferred Exporter before closing your account. You can do this by navigating to **Settings** > **Workspaces** > **Group** > [Workspace name] > **Connections** > **Configure** and selecting any Workspace Admin from the dropdown menu as the Preferred Exporter. +- **Verified Business Account with Outstanding Balance or Locked Status**: If you have a Verified Business Account with an outstanding balance or if the account is locked, you should wait for all payments to settle or unlock the account. To settle the amount owed, go to **Settings** > **Account** > **Payments** > **Bank Accounts** and take the necessary steps. + +## Validate the account to close it + +Sometimes, you may find yourself with an Expensify account that you don't need. This could be due to various reasons like a company inviting you for reimbursement, a vendor inviting you to pay, or a mistaken sign-up. + +In such cases, you have two options: + +**Option 1**: Retain the Account for Future Use +You can keep the Expensify account just in case you need it later. + +**Option 2**: Close the Account + +Start by verifying your email or phone number + +Before closing the account, you need to verify that you have access to the email or phone number associated with it. This ensures that only you can close the account. + +Here's how to do it: + +1. Go to[ www.expensify.com](http://www.expensify.com/). +2. Enter your email address or phone number (whichever is associated with the unwanted account). +3. Click the **Resend Link** button. +4. Check your Home Page for the most recent email with the subject line "Please validate your Expensify login." Click the link provided in the email to validate your email address. + - If it's an account linked to a phone number, tap the link sent to your phone. +5. After clicking the validation link, you'll be directed to an Expensify Home Page. +6. Navigate to **Settings** > **Account** > **Account Details** > **Close Account**. +7. Click the **Close My Account** button. + - Re-enter the email address or phone number of the account when prompted. + - Check the box that says, "I understand all of my unsubmitted expense data will be deleted." + - Click the **Close My Account** button. + +By following these steps, you can easily verify your email or phone number and close an unwanted Expensify account. + +# FAQ + +## What should I do if I'm not directed to my account when clicking the validate option from my phone or email? +It's possible your browser has blocked this, either because of some existing cache or extension. In this case, you should follow the Reset Password flow to reset the password and manually gain access with the new password, along with your email address. +## Why don't I see the Close Account option? +It's possible your account is on a managed company domain. In this case, only the admins from that company can close it. From 4fa79fd5a73bb49cada0ef7b2c7d2232454ca758 Mon Sep 17 00:00:00 2001 From: Alberto Date: Tue, 17 Oct 2023 14:01:38 +0200 Subject: [PATCH 029/237] Add error message --- src/components/StatePicker/StateSelectorModal.js | 2 +- src/languages/en.ts | 2 ++ src/languages/types.ts | 3 +++ src/libs/actions/IOU.js | 4 ++-- 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/components/StatePicker/StateSelectorModal.js b/src/components/StatePicker/StateSelectorModal.js index 378dcc4ebc8b..30379c72c4a0 100644 --- a/src/components/StatePicker/StateSelectorModal.js +++ b/src/components/StatePicker/StateSelectorModal.js @@ -10,7 +10,7 @@ import useLocalize from '../../hooks/useLocalize'; import ScreenWrapper from '../ScreenWrapper'; import styles from '../../styles/styles'; import searchCountryOptions from '../../libs/searchCountryOptions'; -import StringUtils from '../../libs/StringUtils'; +import * as StringUtils from '../../libs/StringUtils'; const propTypes = { /** Whether the modal is visible */ diff --git a/src/languages/en.ts b/src/languages/en.ts index f69f9ea4bedd..edbac8d1dc61 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -74,6 +74,7 @@ import type { FormattedMaxLengthParams, RequestedAmountMessageParams, TagSelectionParams, + ReceiptCreateFailureMessageParams, TranslationBase, WalletProgramParams, } from './types'; @@ -567,6 +568,7 @@ export default { invalidSplit: 'Split amounts do not equal total amount', other: 'Unexpected error, please try again later', genericCreateFailureMessage: 'Unexpected error requesting money, please try again later', + receiptCreateFailureMessage: ({receiptUrl}: ReceiptCreateFailureMessageParams) => `The receipt didn't upload. Save the file or dismiss this error and lose it.`, genericDeleteFailureMessage: 'Unexpected error deleting the money request, please try again later', genericEditFailureMessage: 'Unexpected error editing the money request, please try again later', genericSmartscanFailureMessage: 'Transaction is missing fields', diff --git a/src/languages/types.ts b/src/languages/types.ts index 3ee504ccddd7..193f226899d6 100644 --- a/src/languages/types.ts +++ b/src/languages/types.ts @@ -198,6 +198,8 @@ type FormattedMaxLengthParams = {formattedMaxLength: string}; type TagSelectionParams = {tagName: string}; +type ReceiptCreateFailureMessageParams = {tagName: string}; + type WalletProgramParams = {walletProgram: string}; /* Translation Object types */ @@ -313,6 +315,7 @@ export type { RemovedTheRequestParams, FormattedMaxLengthParams, TagSelectionParams, + ReceiptCreateFailureMessageParams, SetTheDistanceParams, UpdatedTheDistanceParams, WalletProgramParams, diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index d5676672dd33..de6fdccd7b4e 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -349,12 +349,12 @@ function buildOnyxDataForMoneyRequest( errors: ErrorUtils.getMicroSecondOnyxError('iou.error.genericCreateFailureMessage'), }, [iouAction.reportActionID]: { - errors: ErrorUtils.getMicroSecondOnyxError(null), + errors: transaction.receipt ? ErrorUtils.getMicroSecondOnyxError(Localize.translateLocal('iou.error.receiptCreateFailureMessage', {receiptUrl: transaction.receipt.source})) : ErrorUtils.getMicroSecondOnyxError(null), }, } : { [iouAction.reportActionID]: { - errors: ErrorUtils.getMicroSecondOnyxError('iou.error.genericCreateFailureMessage'), + errors: transaction.receipt ? ErrorUtils.getMicroSecondOnyxError(Localize.translateLocal('iou.error.receiptCreateFailureMessage', {receiptUrl: transaction.receipt.source})) : ErrorUtils.getMicroSecondOnyxError('iou.error.genericCreateFailureMessage'), }, }), }, From 418f5d7246330c1db21db885e7c849eeb546f165 Mon Sep 17 00:00:00 2001 From: Alberto Date: Tue, 17 Oct 2023 14:02:27 +0200 Subject: [PATCH 030/237] handle htmL --- src/components/DotIndicatorMessage.js | 5 ++++- src/libs/StringUtils.ts | 15 ++++++++++++++- .../PersonalDetails/CountrySelectionPage.js | 2 +- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/components/DotIndicatorMessage.js b/src/components/DotIndicatorMessage.js index b3528b43dc75..f5d2bbbd5b1e 100644 --- a/src/components/DotIndicatorMessage.js +++ b/src/components/DotIndicatorMessage.js @@ -8,6 +8,9 @@ import * as Expensicons from './Icon/Expensicons'; import themeColors from '../styles/themes/default'; import Text from './Text'; import * as Localize from '../libs/Localize'; +import {hasHTML} from "../libs/StringUtils"; +import RenderHTML from "./RenderHTML"; +import * as StringUtils from "../libs/StringUtils"; const propTypes = { /** @@ -66,7 +69,7 @@ function DotIndicatorMessage(props) { key={i} style={styles.offlineFeedback.text} > - {message} + {StringUtils.hasHTML(message) ? : message} ))} diff --git a/src/libs/StringUtils.ts b/src/libs/StringUtils.ts index 8ef23bb0751b..b7021010aa05 100644 --- a/src/libs/StringUtils.ts +++ b/src/libs/StringUtils.ts @@ -10,4 +10,17 @@ function sanitizeString(str: string): string { return _.deburr(str).toLowerCase().replaceAll(CONST.REGEX.NON_ALPHABETIC_AND_NON_LATIN_CHARS, ''); } -export default {sanitizeString}; +/** + * Very simple function to identify if a string contains HTML elements. WARNING: Things like '' will return true + * @param str - The string to check. + * @returns True if it contains html elements + */ +function hasHTML(str: string): boolean { + const regex = new RegExp('/<\\/?[a-z][\\s\\S]*>/', 'i'); + return regex.test(str) +} + +export { + sanitizeString, + hasHTML, +}; diff --git a/src/pages/settings/Profile/PersonalDetails/CountrySelectionPage.js b/src/pages/settings/Profile/PersonalDetails/CountrySelectionPage.js index 741974776df1..ef19ba6aad9d 100644 --- a/src/pages/settings/Profile/PersonalDetails/CountrySelectionPage.js +++ b/src/pages/settings/Profile/PersonalDetails/CountrySelectionPage.js @@ -7,7 +7,7 @@ import ScreenWrapper from '../../../../components/ScreenWrapper'; import HeaderWithBackButton from '../../../../components/HeaderWithBackButton'; import SelectionList from '../../../../components/SelectionList'; import searchCountryOptions from '../../../../libs/searchCountryOptions'; -import StringUtils from '../../../../libs/StringUtils'; +import * as StringUtils from '../../../../libs/StringUtils'; import CONST from '../../../../CONST'; import useLocalize from '../../../../hooks/useLocalize'; From ccda700add1f128ac8c882507f532d8ea56058fa Mon Sep 17 00:00:00 2001 From: Alberto Date: Tue, 17 Oct 2023 14:12:11 +0200 Subject: [PATCH 031/237] fix regex --- src/libs/StringUtils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/StringUtils.ts b/src/libs/StringUtils.ts index b7021010aa05..ae0df0e563d3 100644 --- a/src/libs/StringUtils.ts +++ b/src/libs/StringUtils.ts @@ -16,7 +16,7 @@ function sanitizeString(str: string): string { * @returns True if it contains html elements */ function hasHTML(str: string): boolean { - const regex = new RegExp('/<\\/?[a-z][\\s\\S]*>/', 'i'); + const regex = new RegExp('', 'i'); return regex.test(str) } From ee3fbdb2f6903a8bf8b426a9cf340a8145829c83 Mon Sep 17 00:00:00 2001 From: Alberto Date: Tue, 17 Oct 2023 14:12:48 +0200 Subject: [PATCH 032/237] style --- src/components/DotIndicatorMessage.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/components/DotIndicatorMessage.js b/src/components/DotIndicatorMessage.js index f5d2bbbd5b1e..3ed660865cc9 100644 --- a/src/components/DotIndicatorMessage.js +++ b/src/components/DotIndicatorMessage.js @@ -8,9 +8,8 @@ import * as Expensicons from './Icon/Expensicons'; import themeColors from '../styles/themes/default'; import Text from './Text'; import * as Localize from '../libs/Localize'; -import {hasHTML} from "../libs/StringUtils"; -import RenderHTML from "./RenderHTML"; -import * as StringUtils from "../libs/StringUtils"; +import RenderHTML from './RenderHTML'; +import * as StringUtils from '../libs/StringUtils'; const propTypes = { /** From 6cb7230ef7cd786c2e716b0b68d97ff01699d574 Mon Sep 17 00:00:00 2001 From: Alberto Date: Tue, 17 Oct 2023 17:00:23 +0200 Subject: [PATCH 033/237] use object for error --- src/CONST.ts | 1 + src/components/DotIndicatorMessage.js | 20 ++++++++++++++++++-- src/libs/actions/IOU.js | 2 +- 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/CONST.ts b/src/CONST.ts index 55fd7faa5a6a..2651fb057a92 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -1118,6 +1118,7 @@ const CONST = { DOCX: 'docx', SVG: 'svg', }, + RECEIPT_ERROR: 'receiptError', }, GROWL: { diff --git a/src/components/DotIndicatorMessage.js b/src/components/DotIndicatorMessage.js index 3ed660865cc9..e74974846141 100644 --- a/src/components/DotIndicatorMessage.js +++ b/src/components/DotIndicatorMessage.js @@ -10,6 +10,7 @@ import Text from './Text'; import * as Localize from '../libs/Localize'; import RenderHTML from './RenderHTML'; import * as StringUtils from '../libs/StringUtils'; +import CONST from '../CONST'; const propTypes = { /** @@ -39,6 +40,13 @@ function DotIndicatorMessage(props) { return null; } + function isReceiptError (message) { + if (_.isString(message)) { + return false; + } + return _.get(message, 'error', '') === CONST.IOU.RECEIPT_ERROR; + } + // To ensure messages are presented in order we are sort of destroying the data we are given // and rebuilding as an array so we can render the messages in order. We don't really care about // the microtime timestamps anyways so isn't the end of the world that we sort of lose them here. @@ -64,13 +72,21 @@ function DotIndicatorMessage(props) { {_.map(sortedMessages, (message, i) => ( + isReceiptError(message) ? ( + + bla + + ) : ( - {StringUtils.hasHTML(message) ? : message} + {message} - ))} + )))} ); diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index de6fdccd7b4e..60b5b1f1fad6 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -354,7 +354,7 @@ function buildOnyxDataForMoneyRequest( } : { [iouAction.reportActionID]: { - errors: transaction.receipt ? ErrorUtils.getMicroSecondOnyxError(Localize.translateLocal('iou.error.receiptCreateFailureMessage', {receiptUrl: transaction.receipt.source})) : ErrorUtils.getMicroSecondOnyxError('iou.error.genericCreateFailureMessage'), + errors: transaction.receipt ? {[DateUtils.getMicroseconds()]: {error: CONST.IOU.RECEIPT_ERROR, source: transaction.receipt.source, filename: transaction.filename}} : ErrorUtils.getMicroSecondOnyxError('iou.error.genericCreateFailureMessage'), }, }), }, From 874985736bd4b2343b0d0d667c2c03010bcc82a9 Mon Sep 17 00:00:00 2001 From: Alberto Date: Tue, 17 Oct 2023 17:23:20 +0200 Subject: [PATCH 034/237] Use new approach --- src/components/DotIndicatorMessage.js | 38 ++++++++++++++++++++------- src/languages/en.ts | 4 ++- 2 files changed, 31 insertions(+), 11 deletions(-) diff --git a/src/components/DotIndicatorMessage.js b/src/components/DotIndicatorMessage.js index e74974846141..4486d439a05f 100644 --- a/src/components/DotIndicatorMessage.js +++ b/src/components/DotIndicatorMessage.js @@ -1,16 +1,17 @@ import React from 'react'; import _ from 'underscore'; import PropTypes from 'prop-types'; -import {View} from 'react-native'; +import {Keyboard, View} from 'react-native'; import styles from '../styles/styles'; import Icon from './Icon'; import * as Expensicons from './Icon/Expensicons'; import themeColors from '../styles/themes/default'; import Text from './Text'; import * as Localize from '../libs/Localize'; -import RenderHTML from './RenderHTML'; -import * as StringUtils from '../libs/StringUtils'; import CONST from '../CONST'; +import PressableWithoutFeedback from './Pressable/PressableWithoutFeedback'; +import addEncryptedAuthTokenToURL from "../libs/addEncryptedAuthTokenToURL"; +import fileDownload from '../libs/fileDownload'; const propTypes = { /** @@ -40,12 +41,19 @@ function DotIndicatorMessage(props) { return null; } - function isReceiptError (message) { + const isReceiptError = (message) => { if (_.isString(message)) { return false; } return _.get(message, 'error', '') === CONST.IOU.RECEIPT_ERROR; - } + }; + + /** + * Download the failed receipt. + */ + const downloadReceipt = (source, filename) => { + fileDownload(source, filename); + }; // To ensure messages are presented in order we are sort of destroying the data we are given // and rebuilding as an array so we can render the messages in order. We don't really care about @@ -73,12 +81,22 @@ function DotIndicatorMessage(props) { {_.map(sortedMessages, (message, i) => ( isReceiptError(message) ? ( - { + downloadReceipt(message.source, message.filename) + }} > - bla - + + {Localize.translateLocal('iou.error.receiptFailureMessage')} + {Localize.translateLocal('iou.error.saveFileMessage')} + {Localize.translateLocal('iou.error.loseFileMessage')} + + ) : ( `The receipt didn't upload. Save the file or dismiss this error and lose it.`, + receiptFailureMessage: 'The receipt didn\'t upload. ', + saveFileMessage: 'Save the file ', + loseFileMessage: 'or dismiss this error and lose it', genericDeleteFailureMessage: 'Unexpected error deleting the money request, please try again later', genericEditFailureMessage: 'Unexpected error editing the money request, please try again later', genericSmartscanFailureMessage: 'Transaction is missing fields', From 52f5e509b699ebaf1235e32f9f8988defe497738 Mon Sep 17 00:00:00 2001 From: Alberto Date: Tue, 17 Oct 2023 17:59:10 +0200 Subject: [PATCH 035/237] use function --- src/components/DotIndicatorMessage.js | 1 - src/languages/en.ts | 1 - src/languages/types.ts | 3 --- src/libs/ErrorUtils.ts | 10 +++++++++- src/libs/actions/IOU.js | 4 ++-- 5 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/components/DotIndicatorMessage.js b/src/components/DotIndicatorMessage.js index 4486d439a05f..afb59114cc6d 100644 --- a/src/components/DotIndicatorMessage.js +++ b/src/components/DotIndicatorMessage.js @@ -10,7 +10,6 @@ import Text from './Text'; import * as Localize from '../libs/Localize'; import CONST from '../CONST'; import PressableWithoutFeedback from './Pressable/PressableWithoutFeedback'; -import addEncryptedAuthTokenToURL from "../libs/addEncryptedAuthTokenToURL"; import fileDownload from '../libs/fileDownload'; const propTypes = { diff --git a/src/languages/en.ts b/src/languages/en.ts index 9dfeddcc2f36..d4c5e300708d 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -74,7 +74,6 @@ import type { FormattedMaxLengthParams, RequestedAmountMessageParams, TagSelectionParams, - ReceiptCreateFailureMessageParams, TranslationBase, WalletProgramParams, } from './types'; diff --git a/src/languages/types.ts b/src/languages/types.ts index 193f226899d6..3ee504ccddd7 100644 --- a/src/languages/types.ts +++ b/src/languages/types.ts @@ -198,8 +198,6 @@ type FormattedMaxLengthParams = {formattedMaxLength: string}; type TagSelectionParams = {tagName: string}; -type ReceiptCreateFailureMessageParams = {tagName: string}; - type WalletProgramParams = {walletProgram: string}; /* Translation Object types */ @@ -315,7 +313,6 @@ export type { RemovedTheRequestParams, FormattedMaxLengthParams, TagSelectionParams, - ReceiptCreateFailureMessageParams, SetTheDistanceParams, UpdatedTheDistanceParams, WalletProgramParams, diff --git a/src/libs/ErrorUtils.ts b/src/libs/ErrorUtils.ts index bf4fc0d810a4..4be126830500 100644 --- a/src/libs/ErrorUtils.ts +++ b/src/libs/ErrorUtils.ts @@ -42,6 +42,14 @@ function getMicroSecondOnyxError(error: string): Record { return {[DateUtils.getMicroseconds()]: error}; } +/** + * Method used to get an error object with microsecond as the key and am object as the value. + * @param error - error key or message to be saved + */ +function getMicroSecondOnyxErrorObject(error: Record): Record> { + return {[DateUtils.getMicroseconds()]: error}; +} + type OnyxDataWithErrors = { errors?: Errors; }; @@ -111,4 +119,4 @@ function addErrorMessage(errors: ErrorsList, inputID?: string, message?: string) } } -export {getAuthenticateErrorMessage, getMicroSecondOnyxError, getLatestErrorMessage, getLatestErrorField, getEarliestErrorField, addErrorMessage}; +export {getAuthenticateErrorMessage, getMicroSecondOnyxError, getMicroSecondOnyxErrorObject, getLatestErrorMessage, getLatestErrorField, getEarliestErrorField, addErrorMessage}; diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index 60b5b1f1fad6..a6e028b6e7ea 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -349,12 +349,12 @@ function buildOnyxDataForMoneyRequest( errors: ErrorUtils.getMicroSecondOnyxError('iou.error.genericCreateFailureMessage'), }, [iouAction.reportActionID]: { - errors: transaction.receipt ? ErrorUtils.getMicroSecondOnyxError(Localize.translateLocal('iou.error.receiptCreateFailureMessage', {receiptUrl: transaction.receipt.source})) : ErrorUtils.getMicroSecondOnyxError(null), + errors: transaction.receipt ? ErrorUtils.getMicroSecondOnyxErrorObject({error: CONST.IOU.RECEIPT_ERROR, source: transaction.receipt.source, filename: transaction.filename}) : ErrorUtils.getMicroSecondOnyxError(null), }, } : { [iouAction.reportActionID]: { - errors: transaction.receipt ? {[DateUtils.getMicroseconds()]: {error: CONST.IOU.RECEIPT_ERROR, source: transaction.receipt.source, filename: transaction.filename}} : ErrorUtils.getMicroSecondOnyxError('iou.error.genericCreateFailureMessage'), + errors: transaction.receipt ? ErrorUtils.getMicroSecondOnyxErrorObject({error: CONST.IOU.RECEIPT_ERROR, source: transaction.receipt.source, filename: transaction.filename}) : ErrorUtils.getMicroSecondOnyxError('iou.error.genericCreateFailureMessage'), }, }), }, From d97beb33efe4d1febd628b3a6baaa8c65666e19b Mon Sep 17 00:00:00 2001 From: Alberto Date: Tue, 17 Oct 2023 18:00:30 +0200 Subject: [PATCH 036/237] remove unneeded helper function --- src/components/StatePicker/StateSelectorModal.js | 2 +- src/libs/StringUtils.ts | 15 +-------------- .../PersonalDetails/CountrySelectionPage.js | 2 +- 3 files changed, 3 insertions(+), 16 deletions(-) diff --git a/src/components/StatePicker/StateSelectorModal.js b/src/components/StatePicker/StateSelectorModal.js index 30379c72c4a0..378dcc4ebc8b 100644 --- a/src/components/StatePicker/StateSelectorModal.js +++ b/src/components/StatePicker/StateSelectorModal.js @@ -10,7 +10,7 @@ import useLocalize from '../../hooks/useLocalize'; import ScreenWrapper from '../ScreenWrapper'; import styles from '../../styles/styles'; import searchCountryOptions from '../../libs/searchCountryOptions'; -import * as StringUtils from '../../libs/StringUtils'; +import StringUtils from '../../libs/StringUtils'; const propTypes = { /** Whether the modal is visible */ diff --git a/src/libs/StringUtils.ts b/src/libs/StringUtils.ts index ae0df0e563d3..8ef23bb0751b 100644 --- a/src/libs/StringUtils.ts +++ b/src/libs/StringUtils.ts @@ -10,17 +10,4 @@ function sanitizeString(str: string): string { return _.deburr(str).toLowerCase().replaceAll(CONST.REGEX.NON_ALPHABETIC_AND_NON_LATIN_CHARS, ''); } -/** - * Very simple function to identify if a string contains HTML elements. WARNING: Things like '' will return true - * @param str - The string to check. - * @returns True if it contains html elements - */ -function hasHTML(str: string): boolean { - const regex = new RegExp('', 'i'); - return regex.test(str) -} - -export { - sanitizeString, - hasHTML, -}; +export default {sanitizeString}; diff --git a/src/pages/settings/Profile/PersonalDetails/CountrySelectionPage.js b/src/pages/settings/Profile/PersonalDetails/CountrySelectionPage.js index ef19ba6aad9d..741974776df1 100644 --- a/src/pages/settings/Profile/PersonalDetails/CountrySelectionPage.js +++ b/src/pages/settings/Profile/PersonalDetails/CountrySelectionPage.js @@ -7,7 +7,7 @@ import ScreenWrapper from '../../../../components/ScreenWrapper'; import HeaderWithBackButton from '../../../../components/HeaderWithBackButton'; import SelectionList from '../../../../components/SelectionList'; import searchCountryOptions from '../../../../libs/searchCountryOptions'; -import * as StringUtils from '../../../../libs/StringUtils'; +import StringUtils from '../../../../libs/StringUtils'; import CONST from '../../../../CONST'; import useLocalize from '../../../../hooks/useLocalize'; From ca1443a94469d02637aac37375c74e208973a8ac Mon Sep 17 00:00:00 2001 From: Alberto Date: Tue, 17 Oct 2023 18:06:51 +0200 Subject: [PATCH 037/237] spanish --- src/languages/es.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/languages/es.ts b/src/languages/es.ts index 83e09b2a62c0..913056364970 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -561,6 +561,9 @@ export default { invalidSplit: 'La suma de las partes no equivale al monto total', other: 'Error inesperado, por favor inténtalo más tarde', genericCreateFailureMessage: 'Error inesperado solicitando dinero, Por favor, inténtalo más tarde', + receiptFailureMessage: 'El recibo no se subió. ', + saveFileMessage: 'Guarda el archivo ', + loseFileMessage: 'o descarta este error y piérdelo', genericDeleteFailureMessage: 'Error inesperado eliminando la solicitud de dinero. Por favor, inténtalo más tarde', genericEditFailureMessage: 'Error inesperado al guardar la solicitud de dinero. Por favor, inténtalo más tarde', genericSmartscanFailureMessage: 'La transacción tiene campos vacíos', From 0c559d1a9affc62563acda575a22cb8e6a8185c4 Mon Sep 17 00:00:00 2001 From: Alberto Date: Wed, 18 Oct 2023 13:10:37 +0200 Subject: [PATCH 038/237] lint --- src/components/DotIndicatorMessage.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/components/DotIndicatorMessage.js b/src/components/DotIndicatorMessage.js index afb59114cc6d..2b1e4ceac97f 100644 --- a/src/components/DotIndicatorMessage.js +++ b/src/components/DotIndicatorMessage.js @@ -1,7 +1,7 @@ import React from 'react'; import _ from 'underscore'; import PropTypes from 'prop-types'; -import {Keyboard, View} from 'react-native'; +import {View} from 'react-native'; import styles from '../styles/styles'; import Icon from './Icon'; import * as Expensicons from './Icon/Expensicons'; @@ -49,6 +49,9 @@ function DotIndicatorMessage(props) { /** * Download the failed receipt. + * + * @param {String} source + * @param {String} filename */ const downloadReceipt = (source, filename) => { fileDownload(source, filename); From 08d8e8667d4e24e83ff50eed7ee0b1e42372ac79 Mon Sep 17 00:00:00 2001 From: Alberto Date: Wed, 18 Oct 2023 13:25:59 +0200 Subject: [PATCH 039/237] prettier --- src/components/DotIndicatorMessage.js | 19 ++++++++++--------- src/languages/en.ts | 2 +- src/libs/actions/IOU.js | 8 ++++++-- 3 files changed, 17 insertions(+), 12 deletions(-) diff --git a/src/components/DotIndicatorMessage.js b/src/components/DotIndicatorMessage.js index 2b1e4ceac97f..2683e24e6e8e 100644 --- a/src/components/DotIndicatorMessage.js +++ b/src/components/DotIndicatorMessage.js @@ -81,12 +81,12 @@ function DotIndicatorMessage(props) { /> - {_.map(sortedMessages, (message, i) => ( + {_.map(sortedMessages, (message, i) => isReceiptError(message) ? ( { - downloadReceipt(message.source, message.filename) + downloadReceipt(message.source, message.filename); }} > ) : ( - - {message} - - )))} + + {message} + + ), + )} ); diff --git a/src/languages/en.ts b/src/languages/en.ts index d4c5e300708d..57d5eaf11e82 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -567,7 +567,7 @@ export default { invalidSplit: 'Split amounts do not equal total amount', other: 'Unexpected error, please try again later', genericCreateFailureMessage: 'Unexpected error requesting money, please try again later', - receiptFailureMessage: 'The receipt didn\'t upload. ', + receiptFailureMessage: "The receipt didn't upload. ", saveFileMessage: 'Save the file ', loseFileMessage: 'or dismiss this error and lose it', genericDeleteFailureMessage: 'Unexpected error deleting the money request, please try again later', diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index a6e028b6e7ea..2d19366e657a 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -349,12 +349,16 @@ function buildOnyxDataForMoneyRequest( errors: ErrorUtils.getMicroSecondOnyxError('iou.error.genericCreateFailureMessage'), }, [iouAction.reportActionID]: { - errors: transaction.receipt ? ErrorUtils.getMicroSecondOnyxErrorObject({error: CONST.IOU.RECEIPT_ERROR, source: transaction.receipt.source, filename: transaction.filename}) : ErrorUtils.getMicroSecondOnyxError(null), + errors: transaction.receipt + ? ErrorUtils.getMicroSecondOnyxErrorObject({error: CONST.IOU.RECEIPT_ERROR, source: transaction.receipt.source, filename: transaction.filename}) + : ErrorUtils.getMicroSecondOnyxError(null), }, } : { [iouAction.reportActionID]: { - errors: transaction.receipt ? ErrorUtils.getMicroSecondOnyxErrorObject({error: CONST.IOU.RECEIPT_ERROR, source: transaction.receipt.source, filename: transaction.filename}) : ErrorUtils.getMicroSecondOnyxError('iou.error.genericCreateFailureMessage'), + errors: transaction.receipt + ? ErrorUtils.getMicroSecondOnyxErrorObject({error: CONST.IOU.RECEIPT_ERROR, source: transaction.receipt.source, filename: transaction.filename}) + : ErrorUtils.getMicroSecondOnyxError('iou.error.genericCreateFailureMessage'), }, }), }, From 040c5edcb4326211493d100e88203699dd271be4 Mon Sep 17 00:00:00 2001 From: Alberto Date: Wed, 18 Oct 2023 16:48:05 +0200 Subject: [PATCH 040/237] allow multiple lines --- src/components/DotIndicatorMessage.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/DotIndicatorMessage.js b/src/components/DotIndicatorMessage.js index 2683e24e6e8e..ef838fb0ed4a 100644 --- a/src/components/DotIndicatorMessage.js +++ b/src/components/DotIndicatorMessage.js @@ -92,7 +92,6 @@ function DotIndicatorMessage(props) { {Localize.translateLocal('iou.error.receiptFailureMessage')} {Localize.translateLocal('iou.error.saveFileMessage')} From 17a1c43ba0dab4f7d41e7256bb6b8942cf7e215f Mon Sep 17 00:00:00 2001 From: Alberto Date: Thu, 19 Oct 2023 12:04:11 +0200 Subject: [PATCH 041/237] add split flow --- src/libs/actions/IOU.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index 2256b72e3851..c9bcf60e88ac 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -1413,7 +1413,7 @@ function startSplitBill(participants, currentUserLogin, currentUserAccountID, co key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${splitChatReport.reportID}`, value: { [splitIOUReportAction.reportActionID]: { - errors: ErrorUtils.getMicroSecondOnyxError('iou.error.genericCreateFailureMessage'), + errors: receipt ? ErrorUtils.getMicroSecondOnyxErrorObject({error: CONST.IOU.RECEIPT_ERROR, source, filename}) : ErrorUtils.getMicroSecondOnyxError('iou.error.genericCreateFailureMessage'), }, }, }); @@ -1436,7 +1436,7 @@ function startSplitBill(participants, currentUserLogin, currentUserAccountID, co errors: ErrorUtils.getMicroSecondOnyxError('report.genericCreateReportFailureMessage'), }, [splitIOUReportAction.reportActionID]: { - errors: ErrorUtils.getMicroSecondOnyxError('iou.error.genericCreateFailureMessage'), + errors: receipt ? ErrorUtils.getMicroSecondOnyxErrorObject({error: CONST.IOU.RECEIPT_ERROR, source, filename}) : ErrorUtils.getMicroSecondOnyxError('iou.error.genericCreateFailureMessage'), }, }, }, From 1d95f4613ca3567efc635e1b0c3c308c8015cc1d Mon Sep 17 00:00:00 2001 From: Alberto Date: Thu, 19 Oct 2023 12:36:17 +0200 Subject: [PATCH 042/237] use isEmpty --- src/libs/actions/IOU.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index c9bcf60e88ac..a223ce212d70 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -359,16 +359,16 @@ function buildOnyxDataForMoneyRequest( errors: ErrorUtils.getMicroSecondOnyxError('iou.error.genericCreateFailureMessage'), }, [iouAction.reportActionID]: { - errors: transaction.receipt - ? ErrorUtils.getMicroSecondOnyxErrorObject({error: CONST.IOU.RECEIPT_ERROR, source: transaction.receipt.source, filename: transaction.filename}) - : ErrorUtils.getMicroSecondOnyxError(null), + errors: _.isEmpty(transaction.receipt) + ? ErrorUtils.getMicroSecondOnyxError(null) + : ErrorUtils.getMicroSecondOnyxErrorObject({error: CONST.IOU.RECEIPT_ERROR, source: transaction.receipt.source, filename: transaction.filename}), }, } : { [iouAction.reportActionID]: { - errors: transaction.receipt - ? ErrorUtils.getMicroSecondOnyxErrorObject({error: CONST.IOU.RECEIPT_ERROR, source: transaction.receipt.source, filename: transaction.filename}) - : ErrorUtils.getMicroSecondOnyxError('iou.error.genericCreateFailureMessage'), + errors: !_.isEmpty(transaction.receipt) + ? ErrorUtils.getMicroSecondOnyxError('iou.error.genericCreateFailureMessage') + : ErrorUtils.getMicroSecondOnyxErrorObject({error: CONST.IOU.RECEIPT_ERROR, source: transaction.receipt.source, filename: transaction.filename}), }, }), }, @@ -1413,7 +1413,7 @@ function startSplitBill(participants, currentUserLogin, currentUserAccountID, co key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${splitChatReport.reportID}`, value: { [splitIOUReportAction.reportActionID]: { - errors: receipt ? ErrorUtils.getMicroSecondOnyxErrorObject({error: CONST.IOU.RECEIPT_ERROR, source, filename}) : ErrorUtils.getMicroSecondOnyxError('iou.error.genericCreateFailureMessage'), + errors: _.isEmpty(receipt) ? ErrorUtils.getMicroSecondOnyxError('iou.error.genericCreateFailureMessage') : ErrorUtils.getMicroSecondOnyxErrorObject({error: CONST.IOU.RECEIPT_ERROR, source, filename}), }, }, }); @@ -1436,7 +1436,7 @@ function startSplitBill(participants, currentUserLogin, currentUserAccountID, co errors: ErrorUtils.getMicroSecondOnyxError('report.genericCreateReportFailureMessage'), }, [splitIOUReportAction.reportActionID]: { - errors: receipt ? ErrorUtils.getMicroSecondOnyxErrorObject({error: CONST.IOU.RECEIPT_ERROR, source, filename}) : ErrorUtils.getMicroSecondOnyxError('iou.error.genericCreateFailureMessage'), + errors: _.isEmpty(receipt) ? ErrorUtils.getMicroSecondOnyxError('iou.error.genericCreateFailureMessage') : ErrorUtils.getMicroSecondOnyxErrorObject({error: CONST.IOU.RECEIPT_ERROR, source, filename}), }, }, }, From 0d010f9ede36a4c616d160fbbe98d4f2f7e90463 Mon Sep 17 00:00:00 2001 From: Alberto Date: Thu, 19 Oct 2023 12:47:24 +0200 Subject: [PATCH 043/237] use empty for split --- src/libs/actions/IOU.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index a223ce212d70..554e52f7383f 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -1413,7 +1413,9 @@ function startSplitBill(participants, currentUserLogin, currentUserAccountID, co key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${splitChatReport.reportID}`, value: { [splitIOUReportAction.reportActionID]: { - errors: _.isEmpty(receipt) ? ErrorUtils.getMicroSecondOnyxError('iou.error.genericCreateFailureMessage') : ErrorUtils.getMicroSecondOnyxErrorObject({error: CONST.IOU.RECEIPT_ERROR, source, filename}), + errors: _.isEmpty(receipt) + ? ErrorUtils.getMicroSecondOnyxError('iou.error.genericCreateFailureMessage') + : ErrorUtils.getMicroSecondOnyxErrorObject({error: CONST.IOU.RECEIPT_ERROR, source, filename}), }, }, }); @@ -1436,7 +1438,9 @@ function startSplitBill(participants, currentUserLogin, currentUserAccountID, co errors: ErrorUtils.getMicroSecondOnyxError('report.genericCreateReportFailureMessage'), }, [splitIOUReportAction.reportActionID]: { - errors: _.isEmpty(receipt) ? ErrorUtils.getMicroSecondOnyxError('iou.error.genericCreateFailureMessage') : ErrorUtils.getMicroSecondOnyxErrorObject({error: CONST.IOU.RECEIPT_ERROR, source, filename}), + errors: _.isEmpty(receipt) + ? ErrorUtils.getMicroSecondOnyxError('iou.error.genericCreateFailureMessage') + : ErrorUtils.getMicroSecondOnyxErrorObject({error: CONST.IOU.RECEIPT_ERROR, source, filename}), }, }, }, From 8f961ac7430dab15850570a523ea474b70dcfaed Mon Sep 17 00:00:00 2001 From: Vit Horacek Date: Sat, 21 Oct 2023 00:00:14 +0100 Subject: [PATCH 044/237] Add a new button to the payment methods popover --- src/CONST.ts | 1 + src/components/AddPaymentMethodMenu.js | 31 +++++++++++++++++++++++++- src/components/KYCWall/BaseKYCWall.js | 1 + src/languages/en.ts | 2 ++ src/languages/es.ts | 2 ++ src/libs/ReportActionsUtils.ts | 21 +++++++++++++++++ 6 files changed, 57 insertions(+), 1 deletion(-) diff --git a/src/CONST.ts b/src/CONST.ts index 048c2dee5bab..dd6df949c3fa 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -1101,6 +1101,7 @@ const CONST = { PAYMENT_METHODS: { DEBIT_CARD: 'debitCard', BANK_ACCOUNT: 'bankAccount', + BUSINESS_BANK_ACCOUNT: 'businessBankAccount', }, PAYMENT_METHOD_ID_KEYS: { diff --git a/src/components/AddPaymentMethodMenu.js b/src/components/AddPaymentMethodMenu.js index 2c3af95a3fad..7ced56b5b63a 100644 --- a/src/components/AddPaymentMethodMenu.js +++ b/src/components/AddPaymentMethodMenu.js @@ -2,6 +2,7 @@ import _ from 'underscore'; import React from 'react'; import PropTypes from 'prop-types'; import {withOnyx} from 'react-native-onyx'; +import lodashGet from 'lodash/get'; import * as Expensicons from './Icon/Expensicons'; import withLocalize, {withLocalizePropTypes} from './withLocalize'; import compose from '../libs/compose'; @@ -11,6 +12,9 @@ import withWindowDimensions from './withWindowDimensions'; import Permissions from '../libs/Permissions'; import PopoverMenu from './PopoverMenu'; import refPropTypes from './refPropTypes'; +import iouReportPropTypes from '../pages/iouReportPropTypes'; +import * as ReportUtils from '../libs/ReportUtils'; +import * as ReportActionsUtils from '../libs/ReportActionsUtils'; const propTypes = { /** Should the component be visible? */ @@ -19,6 +23,9 @@ const propTypes = { /** Callback to execute when the component closes. */ onClose: PropTypes.func.isRequired, + /** The IOU/Expense report we are paying */ + iouReport: iouReportPropTypes, + /** Anchor position for the AddPaymentMenu. */ anchorPosition: PropTypes.shape({ horizontal: PropTypes.number, @@ -37,10 +44,17 @@ const propTypes = { /** Popover anchor ref */ anchorRef: refPropTypes, + /** Session info for the currently logged in user. */ + session: PropTypes.shape({ + /** Currently logged in user accountID */ + accountID: PropTypes.number, + }), + ...withLocalizePropTypes, }; const defaultProps = { + iouReport: {}, anchorPosition: {}, anchorAlignment: { horizontal: CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL.LEFT, @@ -48,6 +62,9 @@ const defaultProps = { }, betas: [], anchorRef: () => {}, + session: { + accountID: 0, + }, }; function AddPaymentMethodMenu(props) { @@ -61,12 +78,21 @@ function AddPaymentMethodMenu(props) { onItemSelected={props.onClose} menuItems={[ { - text: props.translate('common.bankAccount'), + text: props.translate('common.personalBankAccount'), icon: Expensicons.Bank, onSelected: () => { props.onItemSelected(CONST.PAYMENT_METHODS.BANK_ACCOUNT); }, }, + ...(ReportUtils.isIOUReport(this.props.iouReport) && ReportActionsUtils.hasRequestFromPayer(lodashGet(this.props.iouReport, "reportID", 0), this.props.session.accountID) + ? [ + { + text: props.translate('common.businessBankAccount'), + icon: Expensicons.Workspace, + onSelected: () => props.onItemSelected(CONST.PAYMENT_METHODS.BUSINESS_BANK_ACCOUNT), + }, + ] + : []), ...(Permissions.canUseWallet(props.betas) ? [ { @@ -93,5 +119,8 @@ export default compose( betas: { key: ONYXKEYS.BETAS, }, + session: { + key: ONYXKEYS.SESSION, + }, }), )(AddPaymentMethodMenu); diff --git a/src/components/KYCWall/BaseKYCWall.js b/src/components/KYCWall/BaseKYCWall.js index ccee8bc4e6a0..969cbfc20dcd 100644 --- a/src/components/KYCWall/BaseKYCWall.js +++ b/src/components/KYCWall/BaseKYCWall.js @@ -164,6 +164,7 @@ class KYCWall extends React.Component { <> this.setState({shouldShowAddPaymentMenu: false})} anchorRef={this.anchorRef} anchorPosition={{ diff --git a/src/languages/en.ts b/src/languages/en.ts index 11637846130a..0a97a47cd770 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -214,6 +214,8 @@ export default { more: 'More', debitCard: 'Debit card', bankAccount: 'Bank account', + personalBankAccount: 'Personal bank account', + businessBankAccount: 'Business bank account', join: 'Join', joinThread: 'Join thread', decline: 'Decline', diff --git a/src/languages/es.ts b/src/languages/es.ts index e4a5c37241f2..8df14012ac9a 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -204,6 +204,8 @@ export default { more: 'Más', debitCard: 'Tarjeta de débito', bankAccount: 'Cuenta bancaria', + personalBankAccount: 'Personal bank account', + businessBankAccount: 'Business bank account', join: 'Unirse', joinThread: 'Unirse al hilo', decline: 'Rechazar', diff --git a/src/libs/ReportActionsUtils.ts b/src/libs/ReportActionsUtils.ts index c795e5d1c3b1..5a763bbea895 100644 --- a/src/libs/ReportActionsUtils.ts +++ b/src/libs/ReportActionsUtils.ts @@ -605,6 +605,26 @@ function isNotifiableReportAction(reportAction: OnyxEntry): boolea return actions.includes(reportAction.actionName); } +/** + * Helper method to determine if the provided accountID has made a request on the specified report. + * + * @param reportID + * @param currentAccountID + * @returns + */ +function hasRequestFromPayer(reportID: string, currentAccountID: number): boolean { + if (!reportID) { + return false; + } + + const reportActions = Object.values(getAllReportActions(reportID)); + if (reportActions.length === 0) { + return false; + } + + return reportActions.some((action) => action.actionName === CONST.REPORT.ACTIONS.TYPE.IOU && action.actorAccountID === currentAccountID); +} + export { extractLinksFromMessageHtml, getAllReportActions, @@ -644,4 +664,5 @@ export { isWhisperAction, shouldReportActionBeVisible, shouldReportActionBeVisibleAsLastAction, + hasRequestFromPayer, }; From 6c8bd199c0c73c752c58bd616fbeaaa5e500fb6b Mon Sep 17 00:00:00 2001 From: Vit Horacek Date: Sat, 21 Oct 2023 01:07:15 +0100 Subject: [PATCH 045/237] Add the business bank account option --- src/components/KYCWall/BaseKYCWall.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/components/KYCWall/BaseKYCWall.js b/src/components/KYCWall/BaseKYCWall.js index 969cbfc20dcd..a9814cac7492 100644 --- a/src/components/KYCWall/BaseKYCWall.js +++ b/src/components/KYCWall/BaseKYCWall.js @@ -97,6 +97,8 @@ class KYCWall extends React.Component { Navigation.navigate(this.props.addBankAccountRoute); } else if (paymentMethod === CONST.PAYMENT_METHODS.DEBIT_CARD) { Navigation.navigate(this.props.addDebitCardRoute); + } else if (paymentMethod === CONST.PAYMENT_METHODS.BUSINESS_BANK_ACCOUNT) { + // Start the Bottom up flow } } From 1a46590703a67280313606cac66002fc750219cd Mon Sep 17 00:00:00 2001 From: Vit Horacek Date: Sun, 22 Oct 2023 21:23:54 +0100 Subject: [PATCH 046/237] Work on the Bottom Up flow command --- src/CONST.ts | 4 +- src/components/KYCWall/BaseKYCWall.js | 3 +- src/libs/actions/Policy.js | 262 ++++++++++++++++++++++++++ 3 files changed, 266 insertions(+), 3 deletions(-) diff --git a/src/CONST.ts b/src/CONST.ts index dd6df949c3fa..d1db6431eecb 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -1190,8 +1190,8 @@ const CONST = { TYPE: { FREE: 'free', PERSONAL: 'personal', - CORPORATE: 'corporate', - TEAM: 'team', + CORPORATE: 'corporate', // aka Control + TEAM: 'team', // aka Collect }, ROLE: { ADMIN: 'admin', diff --git a/src/components/KYCWall/BaseKYCWall.js b/src/components/KYCWall/BaseKYCWall.js index a9814cac7492..e7f4b6ac1b31 100644 --- a/src/components/KYCWall/BaseKYCWall.js +++ b/src/components/KYCWall/BaseKYCWall.js @@ -9,6 +9,7 @@ import AddPaymentMethodMenu from '../AddPaymentMethodMenu'; import getClickedTargetLocation from '../../libs/getClickedTargetLocation'; import * as PaymentUtils from '../../libs/PaymentUtils'; import * as PaymentMethods from '../../libs/actions/PaymentMethods'; +import * as Policy from '../../libs/actions/Policy'; import ONYXKEYS from '../../ONYXKEYS'; import Log from '../../libs/Log'; import {propTypes, defaultProps} from './kycWallPropTypes'; @@ -98,7 +99,7 @@ class KYCWall extends React.Component { } else if (paymentMethod === CONST.PAYMENT_METHODS.DEBIT_CARD) { Navigation.navigate(this.props.addDebitCardRoute); } else if (paymentMethod === CONST.PAYMENT_METHODS.BUSINESS_BANK_ACCOUNT) { - // Start the Bottom up flow + Policy.startCollectFlow(this.props.iouReport); } } diff --git a/src/libs/actions/Policy.js b/src/libs/actions/Policy.js index 89324dd35485..02b56a079dbe 100644 --- a/src/libs/actions/Policy.js +++ b/src/libs/actions/Policy.js @@ -1289,6 +1289,267 @@ function buildOptimisticPolicyRecentlyUsedCategories(policyID, category) { return lodashUnion([category], policyRecentlyUsedCategories); } + +function startCollectBottomUpFlow(iouReport, firstName, lastName) { + + // This flow only works for IOU reports + if (!ReportUtils.isIOUReport(iouReport)) { + return; + } + + // Generate new vairbales for the policy + const policyID = generatePolicyID() + const workspaceName = generateDefaultWorkspaceName(sessionEmail); + const employeeAccountID = iouReport.ownerAccountID; + const employeeEmail = iouReport.ownerEmail; + const {customUnits, customUnitID, customUnitRateID} = buildOptimisticCustomUnits(); + + const { + announceChatReportID, + announceChatData, + announceReportActionData, + announceCreatedReportActionID, + adminsChatReportID, + adminsChatData, + adminsReportActionData, + adminsCreatedReportActionID, + expenseChatReportID: workspaceChatReportID, + expenseChatData: workspaceChatData, + expenseReportActionData: workspaceChatReportActionData, + expenseCreatedReportActionID: workspaceChatCreatedReportActionID, + } = ReportUtils.buildOptimisticWorkspaceChats(policyID, workspaceName); + + // Create the workspace chat for the employee + const employeeWorkspaceChat = createPolicyExpenseChats(policyID, {[employeeEmail]: employeeAccountID}); + + const optimisticData = [ + { + onyxMethod: Onyx.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, + value: { + id: policyID, + type: CONST.POLICY.TYPE.TEAM, // We are creating a collect policy in this case + name: workspaceName, + role: CONST.POLICY.ROLE.ADMIN, + owner: sessionEmail, + isPolicyExpenseChatEnabled: true, + outputCurrency: lodashGet(allPersonalDetails, [sessionAccountID, 'localCurrencyCode'], CONST.CURRENCY.USD), + pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, + customUnits, + }, + }, + { + onyxMethod: Onyx.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.POLICY_MEMBERS}${policyID}`, + value: { + [sessionAccountID]: { + role: CONST.POLICY.ROLE.ADMIN, + errors: {}, + }, + [employeeAccountID]: { + role: CONST.POLICY.ROLE.USER, + errors: {}, + }, + }, + }, + { + onyxMethod: Onyx.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.REPORT}${announceChatReportID}`, + value: { + pendingFields: { + addWorkspaceRoom: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, + }, + ...announceChatData, + }, + }, + { + onyxMethod: Onyx.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${announceChatReportID}`, + value: announceReportActionData, + }, + { + onyxMethod: Onyx.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.REPORT}${adminsChatReportID}`, + value: { + pendingFields: { + addWorkspaceRoom: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, + }, + ...adminsChatData, + }, + }, + { + onyxMethod: Onyx.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${adminsChatReportID}`, + value: adminsReportActionData, + }, + { + onyxMethod: Onyx.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.REPORT}${workspaceChatReportID}`, + value: { + pendingFields: { + addWorkspaceRoom: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, + }, + ...workspaceChatData, + }, + }, + { + onyxMethod: Onyx.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${workspaceChatReportID}`, + value: workspaceChatReportActionData, + }, + { + onyxMethod: Onyx.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.POLICY_DRAFTS}${policyID}`, + value: null, + }, + { + onyxMethod: Onyx.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.POLICY_MEMBERS_DRAFTS}${policyID}`, + value: null, + }, + ...employeeWorkspaceChat.onyxOptimisticData, + ]; + + const successData = [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, + value: {pendingAction: null}, + }, + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${announceChatReportID}`, + value: { + pendingFields: { + addWorkspaceRoom: null, + }, + pendingAction: null, + }, + }, + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${announceChatReportID}`, + value: { + [_.keys(announceChatData)[0]]: { + pendingAction: null, + }, + }, + }, + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${adminsChatReportID}`, + value: { + pendingFields: { + addWorkspaceRoom: null, + }, + pendingAction: null, + }, + }, + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${adminsChatReportID}`, + value: { + [_.keys(adminsChatData)[0]]: { + pendingAction: null, + }, + }, + }, + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${workspaceChatReportID}`, + value: { + pendingFields: { + addWorkspaceRoom: null, + }, + pendingAction: null, + }, + }, + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${workspaceChatReportID}`, + value: { + [_.keys(workspaceChatData)[0]]: { + pendingAction: null, + }, + }, + }, + ...employeeWorkspaceChat.onyxSuccessData + ]; + const failureData = [ + { + onyxMethod: Onyx.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.POLICY_MEMBERS}${policyID}`, + value: null, + }, + { + onyxMethod: Onyx.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.REPORT}${announceChatReportID}`, + value: null, + }, + { + onyxMethod: Onyx.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${announceChatReportID}`, + value: null, + }, + { + onyxMethod: Onyx.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.REPORT}${adminsChatReportID}`, + value: null, + }, + { + onyxMethod: Onyx.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${adminsChatReportID}`, + value: null, + }, + { + onyxMethod: Onyx.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.REPORT}${workspaceChatReportID}`, + value: null, + }, + { + onyxMethod: Onyx.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${workspaceChatReportID}`, + value: null, + }, + ]; + + // Next we need to convert the IOU report to Expense report and clean up the DM chat + // Get the 1on1 chat where the request was originally made + const chatReportID = iouReport.chatReportID; ReportUtils.getReport(iouReport.chatReportID); + const reportPreviewID = iouReport.parentReportActionID; + + + const membersData = [{ + accountID: employeeAccountID, + email: employeeEmail, + workspaceChatReportID: employeeWorkspaceChat.reportCreationData[employeeEmail].reportID, + workspaceChatCreatedReportActionID: employeeWorkspaceChat.reportCreationData[employeeEmail].reportActionID, + }]; + + API.write( + 'BottomUpCollectFlow', + { + policyID, + announceChatReportID, + adminsChatReportID, + expenseChatReportID: workspaceChatReportID, + ownerEmail: sessionEmail, + makeMeAdmin: false, + policyName: workspaceName, + type: CONST.POLICY.TYPE.TEAM, + announceCreatedReportActionID, + adminsCreatedReportActionID, + expenseCreatedReportActionID: workspaceChatCreatedReportActionID, + customUnitID, + customUnitRateID, + iouReportID: iouReport.reportID, + membersData: JSON.stringify(membersData), + }, + {optimisticData, successData, failureData}, + ); + // Navigation.dismissModal(CONST.TEACHERS_UNITE.PUBLIC_ROOM_ID); +} + export { removeMembers, addMembersToWorkspace, @@ -1320,4 +1581,5 @@ export { openDraftWorkspaceRequest, buildOptimisticPolicyRecentlyUsedCategories, createDraftInitialWorkspace, + startCollectBottomUpFlow, }; From a8e5213f4ee6ab96e395ef08b908cb2a0efb7235 Mon Sep 17 00:00:00 2001 From: keisyrzk Date: Mon, 23 Oct 2023 13:10:48 +0200 Subject: [PATCH 047/237] prettier --- src/components/AvatarWithImagePicker.js | 50 ++++++++++++------------- 1 file changed, 23 insertions(+), 27 deletions(-) diff --git a/src/components/AvatarWithImagePicker.js b/src/components/AvatarWithImagePicker.js index 01522a09fe75..dea7404937de 100644 --- a/src/components/AvatarWithImagePicker.js +++ b/src/components/AvatarWithImagePicker.js @@ -140,27 +140,27 @@ function AvatarWithImagePicker({ const [imageData, setImageData] = useState({ uri: '', name: '', - type: '' + type: '', }); const anchorRef = useRef(); const {translate} = useLocalize(); - /** + /** * @param {String} error * @param {Object} phraseParam */ - const setError = (error, phraseParam) => { + const setError = (error, phraseParam) => { setErrorData({ - validationError: error, - phraseParam, + validationError: error, + phraseParam, }); }; - + useEffect(() => { if (isFocused) { return; } - + // Reset the error if the component is no longer focused. setError(null, {}); }, [isFocused]); @@ -172,16 +172,16 @@ function AvatarWithImagePicker({ * @returns {Boolean} */ const isValidExtension = (image) => { - const { fileExtension } = FileUtils.splitExtensionFromFileName(lodashGet(image, 'name', '')); + const {fileExtension} = FileUtils.splitExtensionFromFileName(lodashGet(image, 'name', '')); return _.contains(CONST.AVATAR_ALLOWED_EXTENSIONS, fileExtension.toLowerCase()); }; /** - * Check if the attachment size is less than allowed size. - * - * @param {Object} image - * @returns {Boolean} - */ + * Check if the attachment size is less than allowed size. + * + * @param {Object} image + * @returns {Boolean} + */ const isValidSize = (image) => image && lodashGet(image, 'size', 0) < CONST.AVATAR_MAX_ATTACHMENT_SIZE; /** @@ -190,13 +190,9 @@ function AvatarWithImagePicker({ * @param {Object} image * @returns {Promise} */ - const isValidResolution = (image) => - getImageResolution(image) - .then(({ height, width }) => - height >= CONST.AVATAR_MIN_HEIGHT_PX && - width >= CONST.AVATAR_MIN_WIDTH_PX && - height <= CONST.AVATAR_MAX_HEIGHT_PX && - width <= CONST.AVATAR_MAX_WIDTH_PX + const isValidResolution = (image) => + getImageResolution(image).then( + ({height, width}) => height >= CONST.AVATAR_MIN_HEIGHT_PX && width >= CONST.AVATAR_MIN_WIDTH_PX && height <= CONST.AVATAR_MAX_HEIGHT_PX && width <= CONST.AVATAR_MAX_WIDTH_PX, ); /** @@ -206,11 +202,11 @@ function AvatarWithImagePicker({ */ const showAvatarCropModal = (image) => { if (!isValidExtension(image)) { - setError('avatarWithImagePicker.notAllowedExtension', { allowedExtensions: CONST.AVATAR_ALLOWED_EXTENSIONS }); + setError('avatarWithImagePicker.notAllowedExtension', {allowedExtensions: CONST.AVATAR_ALLOWED_EXTENSIONS}); return; } if (!isValidSize(image)) { - setError('avatarWithImagePicker.sizeExceeded', { maxUploadSizeInMB: CONST.AVATAR_MAX_ATTACHMENT_SIZE / (1024 * 1024) }); + setError('avatarWithImagePicker.sizeExceeded', {maxUploadSizeInMB: CONST.AVATAR_MAX_ATTACHMENT_SIZE / (1024 * 1024)}); return; } @@ -231,7 +227,7 @@ function AvatarWithImagePicker({ setImageData({ uri: image.uri, name: image.name, - type: image.type + type: image.type, }); }); }; @@ -289,7 +285,7 @@ function AvatarWithImagePicker({ > setIsMenuVisible(prev => !prev)} + onPress={() => setIsMenuVisible((prev) => !prev)} accessibilityRole={CONST.ACCESSIBILITY_ROLE.IMAGEBUTTON} accessibilityLabel={translate('avatarWithImagePicker.editImage')} disabled={isAvatarCropModalOpen} @@ -326,9 +322,9 @@ function AvatarWithImagePicker({ originalFileName={originalFileName} fallbackSource={fallbackIcon} > - {({ show }) => ( + {({show}) => ( - {({ openPicker }) => { + {({openPicker}) => { const menuItems = createMenuItems(openPicker); // If the current avatar isn't a default avatar, allow the "View Photo" option @@ -370,7 +366,7 @@ function AvatarWithImagePicker({ {errorData.validationError && ( )} From 458716e4f9138d1936816016d71d6dd5f8bf43bd Mon Sep 17 00:00:00 2001 From: keisyrzk Date: Mon, 23 Oct 2023 13:40:45 +0200 Subject: [PATCH 048/237] restore podfile.lock from main --- ios/Podfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ios/Podfile.lock b/ios/Podfile.lock index f41c2880563b..cb120bca2b88 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -1293,4 +1293,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: ff769666b7221c15936ebc5576a8c8e467dc6879 -COCOAPODS: 1.12.1 \ No newline at end of file +COCOAPODS: 1.12.1 From fa911fd0d07e7020057fda60b4f39110b06b4606 Mon Sep 17 00:00:00 2001 From: Al Garces Date: Mon, 23 Oct 2023 11:22:24 -0700 Subject: [PATCH 049/237] Update docs/articles/expensify-classic/account-settings/Close-Account.md Co-authored-by: Rushat Gabhane --- .../expensify-classic/account-settings/Close-Account.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/articles/expensify-classic/account-settings/Close-Account.md b/docs/articles/expensify-classic/account-settings/Close-Account.md index 7efa8e9ec255..615f75823fc7 100644 --- a/docs/articles/expensify-classic/account-settings/Close-Account.md +++ b/docs/articles/expensify-classic/account-settings/Close-Account.md @@ -1,5 +1,5 @@ --- -title: Close-Account.md +title: Close Account description: Close Account --- # Overview From a9d6bfa83aeddc12d55039b42c5ed1925ef6c179 Mon Sep 17 00:00:00 2001 From: Al Garces Date: Mon, 23 Oct 2023 11:22:37 -0700 Subject: [PATCH 050/237] Update docs/articles/expensify-classic/account-settings/Close-Account.md Co-authored-by: Rushat Gabhane --- .../expensify-classic/account-settings/Close-Account.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/articles/expensify-classic/account-settings/Close-Account.md b/docs/articles/expensify-classic/account-settings/Close-Account.md index 615f75823fc7..b3e1a5161b16 100644 --- a/docs/articles/expensify-classic/account-settings/Close-Account.md +++ b/docs/articles/expensify-classic/account-settings/Close-Account.md @@ -100,7 +100,7 @@ Before closing the account, you need to verify that you have access to the email Here's how to do it: -1. Go to[ www.expensify.com](http://www.expensify.com/). +1. Go to [www.expensify.com](http://www.expensify.com/). 2. Enter your email address or phone number (whichever is associated with the unwanted account). 3. Click the **Resend Link** button. 4. Check your Home Page for the most recent email with the subject line "Please validate your Expensify login." Click the link provided in the email to validate your email address. From 0482e5dd8edafcf18fb8748a57841b07a13c512a Mon Sep 17 00:00:00 2001 From: Al Garces Date: Mon, 23 Oct 2023 11:22:51 -0700 Subject: [PATCH 051/237] Update docs/articles/expensify-classic/account-settings/Close-Account.md Co-authored-by: Rushat Gabhane --- .../articles/expensify-classic/account-settings/Close-Account.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/articles/expensify-classic/account-settings/Close-Account.md b/docs/articles/expensify-classic/account-settings/Close-Account.md index b3e1a5161b16..0ea4f1bb287d 100644 --- a/docs/articles/expensify-classic/account-settings/Close-Account.md +++ b/docs/articles/expensify-classic/account-settings/Close-Account.md @@ -118,5 +118,6 @@ By following these steps, you can easily verify your email or phone number and c ## What should I do if I'm not directed to my account when clicking the validate option from my phone or email? It's possible your browser has blocked this, either because of some existing cache or extension. In this case, you should follow the Reset Password flow to reset the password and manually gain access with the new password, along with your email address. + ## Why don't I see the Close Account option? It's possible your account is on a managed company domain. In this case, only the admins from that company can close it. From 62d3bdaae6e93e74bb0f94d624e04a2d5c592e65 Mon Sep 17 00:00:00 2001 From: Kacper Falat Date: Tue, 24 Oct 2023 13:23:34 +0200 Subject: [PATCH 052/237] Solved conflicts. --- src/libs/fileDownload/FileUtils.ts | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/libs/fileDownload/FileUtils.ts b/src/libs/fileDownload/FileUtils.ts index 24481f8ede65..410db484d470 100644 --- a/src/libs/fileDownload/FileUtils.ts +++ b/src/libs/fileDownload/FileUtils.ts @@ -65,7 +65,7 @@ function showCameraPermissionsAlert() { }, { text: Localize.translateLocal('common.settings'), - onPress: () => Linking.openSettings(), + onPress: () => { Linking.openSettings() } }, ], {cancelable: false}, @@ -144,6 +144,7 @@ function appendTimeToFileName(fileName: string): string { /** * Reads a locally uploaded file * @param path - the blob url of the locally uploaded file + * @param fileName - name of the file to read */ const readFileAsync: ReadFileAsync = (path, fileName) => new Promise((resolve) => { @@ -182,16 +183,16 @@ const readFileAsync: ReadFileAsync = (path, fileName) => * Converts a base64 encoded image string to a File instance. * Adds a `uri` property to the File instance for accessing the blob as a URI. * - * @param {string} base64 - The base64 encoded image string. - * @param {string} filename - Desired filename for the File instance. - * @returns {File} The File instance created from the base64 string with an additional `uri` property. + * @param base64 - The base64 encoded image string. + * @param filename - Desired filename for the File instance. + * @returns The File instance created from the base64 string with an additional `uri` property. * * @example * const base64Image = "data:image/png;base64,..."; // your base64 encoded image * const imageFile = base64ToFile(base64Image, "example.png"); * console.log(imageFile.uri); // Blob URI */ -function base64ToFile(base64, filename) { +function base64ToFile(base64: string, filename: string): File { // Decode the base64 string const byteString = atob(base64.split(',')[1]); From b2c7be4ced3c28e32594d9905c158f56d2b7f3dc Mon Sep 17 00:00:00 2001 From: Kacper Falat Date: Tue, 24 Oct 2023 20:20:43 +0200 Subject: [PATCH 053/237] Fixed linter issue. --- src/libs/fileDownload/FileUtils.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libs/fileDownload/FileUtils.ts b/src/libs/fileDownload/FileUtils.ts index 410db484d470..1ed75c893ece 100644 --- a/src/libs/fileDownload/FileUtils.ts +++ b/src/libs/fileDownload/FileUtils.ts @@ -65,7 +65,9 @@ function showCameraPermissionsAlert() { }, { text: Localize.translateLocal('common.settings'), - onPress: () => { Linking.openSettings() } + onPress: () => { + Linking.openSettings(); + }, }, ], {cancelable: false}, From 183d38383dcde6c6009493ccf0dce1ce208475fc Mon Sep 17 00:00:00 2001 From: keisyrzk Date: Wed, 25 Oct 2023 13:36:55 +0200 Subject: [PATCH 054/237] pr comments --- src/components/AvatarWithImagePicker.js | 57 +++++++------------- src/pages/workspace/WorkspaceSettingsPage.js | 1 - 2 files changed, 18 insertions(+), 40 deletions(-) diff --git a/src/components/AvatarWithImagePicker.js b/src/components/AvatarWithImagePicker.js index 2876dede626d..ce0f2849e58d 100644 --- a/src/components/AvatarWithImagePicker.js +++ b/src/components/AvatarWithImagePicker.js @@ -92,47 +92,27 @@ const propTypes = { ...withNavigationFocusPropTypes, }; -const defaultProps = { - source: '', - onImageSelected: () => {}, - onImageRemoved: () => {}, - style: [], - DefaultAvatar: () => {}, - isUsingDefaultAvatar: false, - size: CONST.AVATAR_SIZE.DEFAULT, - fallbackIcon: Expensicons.FallbackAvatar, - type: CONST.ICON_TYPE_AVATAR, - editorMaskImage: undefined, - errorRowStyles: [], - onErrorClose: () => {}, - pendingAction: null, - errors: null, - headerTitle: '', - previewSource: '', - originalFileName: '', -}; - function AvatarWithImagePicker({ isFocused, - DefaultAvatar, - style, - pendingAction, - errors, - errorRowStyles, - onErrorClose, - source, - fallbackIcon, - size, - type, - headerTitle, - previewSource, - originalFileName, - isUsingDefaultAvatar, - onImageRemoved, + DefaultAvatar = () => {}, + style = [], + pendingAction = null, + errors = null, + errorRowStyles = [], + onErrorClose = () => {}, + source = '', + fallbackIcon = Expensicons.FallbackAvatar, + size = CONST.AVATAR_SIZE.DEFAULT, + type = CONST.ICON_TYPE_AVATAR, + headerTitle = '', + previewSource = '', + originalFileName = '', + isUsingDefaultAvatar = false, + onImageRemoved = () => {}, anchorPosition, anchorAlignment, - onImageSelected, - editorMaskImage, + onImageSelected = () => {}, + editorMaskImage = undefined }) { const [isMenuVisible, setIsMenuVisible] = useState(false); const [errorData, setErrorData] = useState({ @@ -278,7 +258,7 @@ function AvatarWithImagePicker({ }; return ( - + ( From 796940ffb6d1a37a841363acc2da848d21cdbb5a Mon Sep 17 00:00:00 2001 From: keisyrzk Date: Wed, 25 Oct 2023 14:26:40 +0200 Subject: [PATCH 055/237] updates - linter and PR comments --- src/components/AvatarWithImagePicker.js | 57 ++++++++++++++++--------- 1 file changed, 38 insertions(+), 19 deletions(-) diff --git a/src/components/AvatarWithImagePicker.js b/src/components/AvatarWithImagePicker.js index ce0f2849e58d..006337fc8999 100644 --- a/src/components/AvatarWithImagePicker.js +++ b/src/components/AvatarWithImagePicker.js @@ -92,27 +92,47 @@ const propTypes = { ...withNavigationFocusPropTypes, }; +const defaultProps = { + source: '', + onImageSelected: () => {}, + onImageRemoved: () => {}, + style: [], + DefaultAvatar: () => {}, + isUsingDefaultAvatar: false, + size: CONST.AVATAR_SIZE.DEFAULT, + fallbackIcon: Expensicons.FallbackAvatar, + type: CONST.ICON_TYPE_AVATAR, + editorMaskImage: undefined, + errorRowStyles: [], + onErrorClose: () => {}, + pendingAction: null, + errors: null, + headerTitle: '', + previewSource: '', + originalFileName: '', +}; + function AvatarWithImagePicker({ isFocused, - DefaultAvatar = () => {}, - style = [], - pendingAction = null, - errors = null, - errorRowStyles = [], - onErrorClose = () => {}, - source = '', - fallbackIcon = Expensicons.FallbackAvatar, - size = CONST.AVATAR_SIZE.DEFAULT, - type = CONST.ICON_TYPE_AVATAR, - headerTitle = '', - previewSource = '', - originalFileName = '', - isUsingDefaultAvatar = false, - onImageRemoved = () => {}, + DefaultAvatar, + style, + pendingAction, + errors, + errorRowStyles, + onErrorClose, + source, + fallbackIcon, + size, + type, + headerTitle, + previewSource, + originalFileName, + isUsingDefaultAvatar, + onImageRemoved, anchorPosition, anchorAlignment, - onImageSelected = () => {}, - editorMaskImage = undefined + onImageSelected, + editorMaskImage, }) { const [isMenuVisible, setIsMenuVisible] = useState(false); const [errorData, setErrorData] = useState({ @@ -219,8 +239,6 @@ function AvatarWithImagePicker({ setIsAvatarCropModalOpen(false); }; - const additionalStyles = _.isArray(style) ? style : [style]; - /** * Create menu items list for avatar menu * @@ -367,6 +385,7 @@ function AvatarWithImagePicker({ } AvatarWithImagePicker.propTypes = propTypes; +AvatarWithImagePicker.defaultProps = defaultProps; AvatarWithImagePicker.displayName = 'AvatarWithImagePicker'; export default withNavigationFocus(AvatarWithImagePicker); From 9e3c22fa673212f07bfac44fe02c6e43d890e402 Mon Sep 17 00:00:00 2001 From: Kacper Falat Date: Thu, 26 Oct 2023 13:48:32 +0200 Subject: [PATCH 056/237] Fixed ts issues. --- src/types/global.d.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/types/global.d.ts b/src/types/global.d.ts index d88fc2e1f5b6..7b53c4b01524 100644 --- a/src/types/global.d.ts +++ b/src/types/global.d.ts @@ -25,6 +25,4 @@ declare global { } } -export {}; - declare module 'react-native-device-info/jest/react-native-device-info-mock'; From f4485ca4ea0515682d94224adddcb75dbfbbeb4e Mon Sep 17 00:00:00 2001 From: Kacper Falat Date: Thu, 26 Oct 2023 13:55:14 +0200 Subject: [PATCH 057/237] Fixed ts issues. --- src/types/global.d.ts | 9 --------- src/types/modules/pusher.d.ts | 7 +++++++ 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/types/global.d.ts b/src/types/global.d.ts index 7b53c4b01524..1910b5a994b8 100644 --- a/src/types/global.d.ts +++ b/src/types/global.d.ts @@ -16,13 +16,4 @@ declare module '*.svg' { export default content; } -declare global { - // eslint-disable-next-line @typescript-eslint/consistent-type-definitions - interface File { - source?: string; - - uri?: string; - } -} - declare module 'react-native-device-info/jest/react-native-device-info-mock'; diff --git a/src/types/modules/pusher.d.ts b/src/types/modules/pusher.d.ts index b54a0508c309..fb7bbaa97f79 100644 --- a/src/types/modules/pusher.d.ts +++ b/src/types/modules/pusher.d.ts @@ -5,4 +5,11 @@ declare global { interface Window { getPusherInstance: () => Pusher | null; } + + // eslint-disable-next-line @typescript-eslint/consistent-type-definitions + interface File { + source?: string; + + uri?: string; + } } From 10e65433c158dd5701f72c7f24a7b699ac1ddaf3 Mon Sep 17 00:00:00 2001 From: keisyrzk Date: Fri, 27 Oct 2023 06:46:29 +0200 Subject: [PATCH 058/237] updates PR --- src/components/AvatarWithImagePicker.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/components/AvatarWithImagePicker.js b/src/components/AvatarWithImagePicker.js index 006337fc8999..4e85bba8ce9c 100644 --- a/src/components/AvatarWithImagePicker.js +++ b/src/components/AvatarWithImagePicker.js @@ -1,6 +1,6 @@ import _ from 'underscore'; import React, {useState, useRef, useEffect} from 'react'; -import {View} from 'react-native'; +import {View, StyleSheet} from 'react-native'; import PropTypes from 'prop-types'; import lodashGet from 'lodash/get'; import Avatar from './Avatar'; @@ -86,9 +86,6 @@ const propTypes = { /** File name of the avatar */ originalFileName: PropTypes.string, - /** Whether navigation is focused */ - isFocused: PropTypes.bool.isRequired, - ...withNavigationFocusPropTypes, }; From 6be9864c80d1a4837069964c7a08057ab73c9a2e Mon Sep 17 00:00:00 2001 From: keisyrzk Date: Fri, 27 Oct 2023 13:40:03 +0200 Subject: [PATCH 059/237] keep isFocused --- src/components/AvatarWithImagePicker.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/components/AvatarWithImagePicker.js b/src/components/AvatarWithImagePicker.js index 4e85bba8ce9c..0ef696072efd 100644 --- a/src/components/AvatarWithImagePicker.js +++ b/src/components/AvatarWithImagePicker.js @@ -23,7 +23,7 @@ import PressableWithoutFeedback from './Pressable/PressableWithoutFeedback'; import AttachmentModal from './AttachmentModal'; import DotIndicatorMessage from './DotIndicatorMessage'; import * as Browser from '../libs/Browser'; -import withNavigationFocus, {withNavigationFocusPropTypes} from './withNavigationFocus'; +import withNavigationFocus from './withNavigationFocus'; const propTypes = { /** Avatar source to display */ @@ -86,7 +86,8 @@ const propTypes = { /** File name of the avatar */ originalFileName: PropTypes.string, - ...withNavigationFocusPropTypes, + /** Whether navigation is focused */ + isFocused: PropTypes.bool.isRequired, }; const defaultProps = { From 02871ac9d817b17ca21a4e8bf1cbd4f38469403f Mon Sep 17 00:00:00 2001 From: cdOut <88325488+cdOut@users.noreply.github.com> Date: Fri, 27 Oct 2023 18:17:30 +0200 Subject: [PATCH 060/237] Add FormProvider to BankAccountManualStep --- .../BankAccountManualStep.js | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/pages/ReimbursementAccount/BankAccountManualStep.js b/src/pages/ReimbursementAccount/BankAccountManualStep.js index 9d0b0c1f5bed..dd46bd3d22c0 100644 --- a/src/pages/ReimbursementAccount/BankAccountManualStep.js +++ b/src/pages/ReimbursementAccount/BankAccountManualStep.js @@ -15,10 +15,11 @@ import {withLocalizePropTypes} from '../../components/withLocalize'; import * as ValidationUtils from '../../libs/ValidationUtils'; import ONYXKEYS from '../../ONYXKEYS'; import exampleCheckImage from './exampleCheckImage'; -import Form from '../../components/Form'; import shouldDelayFocus from '../../libs/shouldDelayFocus'; import ScreenWrapper from '../../components/ScreenWrapper'; import StepPropTypes from './StepPropTypes'; +import FormProvider from '../../components/Form/FormProvider'; +import InputWrapper from '../../components/Form/InputWrapper'; const propTypes = { ..._.omit(StepPropTypes, _.keys(withLocalizePropTypes)), @@ -84,7 +85,7 @@ function BankAccountManualStep(props) { guidesCallTaskID={CONST.GUIDES_CALL_TASK_IDS.WORKSPACE_BANK_ACCOUNT} onBackButtonPress={props.onBackButtonPress} /> -
- - - - + ); } From e44331715595fa03d6f443350ba99973fb9aa65a Mon Sep 17 00:00:00 2001 From: tienifr Date: Sat, 28 Oct 2023 16:13:07 +0700 Subject: [PATCH 061/237] fix: 30465 --- src/components/TagPicker/index.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/components/TagPicker/index.js b/src/components/TagPicker/index.js index 05eca664bd0f..ea29305c16b9 100644 --- a/src/components/TagPicker/index.js +++ b/src/components/TagPicker/index.js @@ -17,7 +17,8 @@ function TagPicker({selectedTag, tag, policyTags, policyRecentlyUsedTags, onSubm const policyRecentlyUsedTagsList = lodashGet(policyRecentlyUsedTags, tag, []); const policyTagList = PolicyUtils.getTagList(policyTags, tag); - const policyTagsCount = _.size(_.filter(policyTagList, (policyTag) => policyTag.enabled)); + const enabledTags = _.filter(policyTagList, (policyTag) => policyTag.enabled); + const policyTagsCount = _.size(enabledTags); const isTagsCountBelowThreshold = policyTagsCount < CONST.TAG_LIST_THRESHOLD; const shouldShowTextInput = !isTagsCountBelowThreshold; @@ -38,14 +39,14 @@ function TagPicker({selectedTag, tag, policyTags, policyRecentlyUsedTags, onSubm const initialFocusedIndex = useMemo(() => { if (isTagsCountBelowThreshold && selectedOptions.length > 0) { - return _.chain(policyTagList) + return _.chain(enabledTags) .values() .findIndex((policyTag) => policyTag.name === selectedOptions[0].name, true) .value(); } return 0; - }, [policyTagList, selectedOptions, isTagsCountBelowThreshold]); + }, [enabledTags, selectedOptions, isTagsCountBelowThreshold]); const sections = useMemo( () => From 66b2c82a9390a98123e513119e12643f1a9100cb Mon Sep 17 00:00:00 2001 From: tienifr Date: Sun, 29 Oct 2023 18:15:02 +0700 Subject: [PATCH 062/237] fix: 29378 Distance - Search is open in background on distance image preview --- src/components/Modal/BaseModal.js | 8 +++++--- src/libs/actions/Modal.ts | 34 +++++++++++++++++++------------ 2 files changed, 26 insertions(+), 16 deletions(-) diff --git a/src/components/Modal/BaseModal.js b/src/components/Modal/BaseModal.js index 6ed3b16c676d..b3e5b26b64ed 100644 --- a/src/components/Modal/BaseModal.js +++ b/src/components/Modal/BaseModal.js @@ -59,6 +59,8 @@ function BaseModal({ const isVisibleRef = useRef(isVisible); const wasVisible = usePrevious(isVisible); + const onCloseKey = useRef(Modal.getAvailableKey()); + /** * Hides modal * @param {Boolean} [callHideCallback=true] Should we call the onModalHide callback @@ -84,10 +86,10 @@ function BaseModal({ if (isVisible) { Modal.willAlertModalBecomeVisible(true); // To handle closing any modal already visible when this modal is mounted, i.e. PopoverReportActionContextMenu - Modal.setCloseModal(onClose); + Modal.setCloseModal(onCloseKey.current, onClose); } else if (wasVisible && !isVisible) { Modal.willAlertModalBecomeVisible(false); - Modal.setCloseModal(null); + Modal.setCloseModal(onCloseKey.current, null); } }, [isVisible, wasVisible, onClose]); @@ -100,7 +102,7 @@ function BaseModal({ hideModal(true); Modal.willAlertModalBecomeVisible(false); // To prevent closing any modal already unmounted when this modal still remains as visible state - Modal.setCloseModal(null); + Modal.setCloseModal(onCloseKey.current, null); }, // eslint-disable-next-line react-hooks/exhaustive-deps [], diff --git a/src/libs/actions/Modal.ts b/src/libs/actions/Modal.ts index 5114d5c1f42f..431142adfb20 100644 --- a/src/libs/actions/Modal.ts +++ b/src/libs/actions/Modal.ts @@ -1,30 +1,38 @@ import Onyx from 'react-native-onyx'; import ONYXKEYS from '@src/ONYXKEYS'; -let closeModal: (isNavigating: boolean) => void; +const closeModals: Record void)> = {}; +let count = 0; + +// let closeModal: (isNavigating: boolean) => void; let onModalClose: null | (() => void); +/** + * Get the available key that we can store the onClose callback into it + */ +function getAvailableKey() { + return count++; +} + /** * Allows other parts of the app to call modal close function */ -function setCloseModal(onClose: () => void) { - closeModal = onClose; +function setCloseModal(key: number, onClose: () => void) { + closeModals[key] = onClose; } /** * Close modal in other parts of the app */ function close(onModalCloseCallback: () => void, isNavigating = true) { - if (!closeModal) { - // If modal is already closed, no need to wait for modal close. So immediately call callback. - if (onModalCloseCallback) { - onModalCloseCallback(); - } - onModalClose = null; - return; - } onModalClose = onModalCloseCallback; - closeModal(isNavigating); + const reversalOnCloses = Object.values(closeModals).reverse(); + reversalOnCloses.forEach((onClose) => { + if (typeof onClose !== 'function') { + return; + } + onClose(isNavigating); + }); } function onModalDidClose() { @@ -50,4 +58,4 @@ function willAlertModalBecomeVisible(isVisible: boolean) { Onyx.merge(ONYXKEYS.MODAL, {willAlertModalBecomeVisible: isVisible}); } -export {setCloseModal, close, onModalDidClose, setModalVisibility, willAlertModalBecomeVisible}; +export {setCloseModal, close, onModalDidClose, setModalVisibility, willAlertModalBecomeVisible, getAvailableKey}; From f5d3c0ed3d06f556a9be7ea9ae377654c9196956 Mon Sep 17 00:00:00 2001 From: keisyrzk Date: Mon, 30 Oct 2023 07:39:05 +0100 Subject: [PATCH 063/237] merge lint issues --- src/components/AvatarWithImagePicker.js | 37 +++++++++++++------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/src/components/AvatarWithImagePicker.js b/src/components/AvatarWithImagePicker.js index cf3a53c2e329..e45d624766f7 100644 --- a/src/components/AvatarWithImagePicker.js +++ b/src/components/AvatarWithImagePicker.js @@ -1,37 +1,28 @@ import _ from 'underscore'; import React, {useState, useRef, useEffect} from 'react'; import {View, StyleSheet} from 'react-native'; +import * as Browser from '@libs/Browser'; import PropTypes from 'prop-types'; import lodashGet from 'lodash/get'; +import styles from '@styles/styles'; +import themeColors from '@styles/themes/default'; +import useLocalize from '@hooks/useLocalize'; +import variables from '@styles/variables'; +import CONST from '@src/CONST'; +import stylePropTypes from '@styles/stylePropTypes'; +import * as FileUtils from '@libs/fileDownload/FileUtils'; +import getImageResolution from '@libs/fileDownload/getImageResolution'; import Avatar from './Avatar'; import Icon from './Icon'; import PopoverMenu from './PopoverMenu'; import * as Expensicons from './Icon/Expensicons'; -import styles from '../styles/styles'; -import themeColors from '../styles/themes/default'; import AttachmentPicker from './AttachmentPicker'; import AvatarCropModal from './AvatarCropModal/AvatarCropModal'; import OfflineWithFeedback from './OfflineWithFeedback'; -import useLocalize from '../hooks/useLocalize'; -import variables from '../styles/variables'; -import CONST from '../CONST'; import Tooltip from './Tooltip'; -import stylePropTypes from '../styles/stylePropTypes'; -import * as FileUtils from '../libs/fileDownload/FileUtils'; -import getImageResolution from '../libs/fileDownload/getImageResolution'; import PressableWithoutFeedback from './Pressable/PressableWithoutFeedback'; -import * as Browser from '@libs/Browser'; import AttachmentModal from './AttachmentModal'; -import AttachmentPicker from './AttachmentPicker'; -import Avatar from './Avatar'; -import AvatarCropModal from './AvatarCropModal/AvatarCropModal'; import DotIndicatorMessage from './DotIndicatorMessage'; -import Icon from './Icon'; -import * as Expensicons from './Icon/Expensicons'; -import OfflineWithFeedback from './OfflineWithFeedback'; -import PopoverMenu from './PopoverMenu'; -import PressableWithoutFeedback from './Pressable/PressableWithoutFeedback'; -import Tooltip from './Tooltip/PopoverAnchorTooltip'; import withNavigationFocus from './withNavigationFocus'; const propTypes = { @@ -97,6 +88,12 @@ const propTypes = { /** Whether navigation is focused */ isFocused: PropTypes.bool.isRequired, + + /** Where the popover should be positioned relative to the anchor points. */ + anchorAlignment: PropTypes.shape({ + horizontal: PropTypes.oneOf(_.values(CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL)), + vertical: PropTypes.oneOf(_.values(CONST.MODAL.ANCHOR_ORIGIN_VERTICAL)), + }), }; const defaultProps = { @@ -117,6 +114,10 @@ const defaultProps = { headerTitle: '', previewSource: '', originalFileName: '', + anchorAlignment: { + horizontal: CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL.LEFT, + vertical: CONST.MODAL.ANCHOR_ORIGIN_VERTICAL.TOP, + }, }; function AvatarWithImagePicker({ From 42e4ba3fcf441b58dff9e254121af0787da03316 Mon Sep 17 00:00:00 2001 From: Alberto Date: Mon, 30 Oct 2023 12:10:04 +0100 Subject: [PATCH 064/237] import update --- src/components/DotIndicatorMessage.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/DotIndicatorMessage.js b/src/components/DotIndicatorMessage.js index bfd572bc50b3..e02635f35973 100644 --- a/src/components/DotIndicatorMessage.js +++ b/src/components/DotIndicatorMessage.js @@ -9,9 +9,9 @@ import themeColors from '@styles/themes/default'; import Icon from './Icon'; import * as Expensicons from './Icon/Expensicons'; import Text from './Text'; -import CONST from '../CONST'; +import CONST from '@src/CONST'; import PressableWithoutFeedback from './Pressable/PressableWithoutFeedback'; -import fileDownload from '../libs/fileDownload'; +import fileDownload from '@libs/fileDownload'; const propTypes = { /** From 8b0382b5805d11020cea62925a4cceace0521c6b Mon Sep 17 00:00:00 2001 From: Alberto Date: Mon, 30 Oct 2023 12:18:51 +0100 Subject: [PATCH 065/237] reorder --- src/components/DotIndicatorMessage.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/DotIndicatorMessage.js b/src/components/DotIndicatorMessage.js index e02635f35973..fa8c7bd67c97 100644 --- a/src/components/DotIndicatorMessage.js +++ b/src/components/DotIndicatorMessage.js @@ -3,15 +3,15 @@ import React from 'react'; import {View} from 'react-native'; import _ from 'underscore'; import * as Localize from '@libs/Localize'; +import fileDownload from '@libs/fileDownload'; import stylePropTypes from '@styles/stylePropTypes'; import styles from '@styles/styles'; import themeColors from '@styles/themes/default'; +import CONST from '@src/CONST'; import Icon from './Icon'; import * as Expensicons from './Icon/Expensicons'; import Text from './Text'; -import CONST from '@src/CONST'; import PressableWithoutFeedback from './Pressable/PressableWithoutFeedback'; -import fileDownload from '@libs/fileDownload'; const propTypes = { /** From f8ce4eb16ff1c6dee199ffc7c002ac62da6a12ed Mon Sep 17 00:00:00 2001 From: Alberto Date: Mon, 30 Oct 2023 12:44:12 +0100 Subject: [PATCH 066/237] prettier --- src/components/DotIndicatorMessage.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/DotIndicatorMessage.js b/src/components/DotIndicatorMessage.js index fa8c7bd67c97..31b96899ef56 100644 --- a/src/components/DotIndicatorMessage.js +++ b/src/components/DotIndicatorMessage.js @@ -2,16 +2,16 @@ import PropTypes from 'prop-types'; import React from 'react'; import {View} from 'react-native'; import _ from 'underscore'; -import * as Localize from '@libs/Localize'; import fileDownload from '@libs/fileDownload'; +import * as Localize from '@libs/Localize'; import stylePropTypes from '@styles/stylePropTypes'; import styles from '@styles/styles'; import themeColors from '@styles/themes/default'; import CONST from '@src/CONST'; import Icon from './Icon'; import * as Expensicons from './Icon/Expensicons'; -import Text from './Text'; import PressableWithoutFeedback from './Pressable/PressableWithoutFeedback'; +import Text from './Text'; const propTypes = { /** From 241793718d6f274ea70e229b915bee5e4961946c Mon Sep 17 00:00:00 2001 From: cdOut <88325488+cdOut@users.noreply.github.com> Date: Mon, 30 Oct 2023 13:18:37 +0100 Subject: [PATCH 067/237] fix CheckboxWithLabel forwardedRef typing --- src/components/CheckboxWithLabel.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/CheckboxWithLabel.js b/src/components/CheckboxWithLabel.js index 4bffadecb733..f18ec346dfa2 100644 --- a/src/components/CheckboxWithLabel.js +++ b/src/components/CheckboxWithLabel.js @@ -7,6 +7,7 @@ import variables from '@styles/variables'; import Checkbox from './Checkbox'; import FormHelpMessage from './FormHelpMessage'; import PressableWithFeedback from './Pressable/PressableWithFeedback'; +import refPropTypes from './refPropTypes'; import Text from './Text'; /** @@ -54,7 +55,7 @@ const propTypes = { defaultValue: PropTypes.bool, /** React ref being forwarded to the Checkbox input */ - forwardedRef: PropTypes.func, + forwardedRef: refPropTypes, /** The ID used to uniquely identify the input in a Form */ /* eslint-disable-next-line react/no-unused-prop-types */ From 1370aea6bd1c22b39192650e308cf647e6e28ce7 Mon Sep 17 00:00:00 2001 From: keisyrzk Date: Tue, 31 Oct 2023 06:18:22 +0100 Subject: [PATCH 068/237] linter prettier fix --- src/components/AvatarWithImagePicker.js | 30 ++++++++++++------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/components/AvatarWithImagePicker.js b/src/components/AvatarWithImagePicker.js index e45d624766f7..209a6d45abbc 100644 --- a/src/components/AvatarWithImagePicker.js +++ b/src/components/AvatarWithImagePicker.js @@ -1,28 +1,28 @@ +import lodashGet from 'lodash/get'; +import PropTypes from 'prop-types'; +import React, {useEffect, useRef, useState} from 'react'; +import {StyleSheet, View} from 'react-native'; import _ from 'underscore'; -import React, {useState, useRef, useEffect} from 'react'; -import {View, StyleSheet} from 'react-native'; +import useLocalize from '@hooks/useLocalize'; import * as Browser from '@libs/Browser'; -import PropTypes from 'prop-types'; -import lodashGet from 'lodash/get'; +import * as FileUtils from '@libs/fileDownload/FileUtils'; +import getImageResolution from '@libs/fileDownload/getImageResolution'; +import stylePropTypes from '@styles/stylePropTypes'; import styles from '@styles/styles'; import themeColors from '@styles/themes/default'; -import useLocalize from '@hooks/useLocalize'; import variables from '@styles/variables'; import CONST from '@src/CONST'; -import stylePropTypes from '@styles/stylePropTypes'; -import * as FileUtils from '@libs/fileDownload/FileUtils'; -import getImageResolution from '@libs/fileDownload/getImageResolution'; +import AttachmentModal from './AttachmentModal'; +import AttachmentPicker from './AttachmentPicker'; import Avatar from './Avatar'; +import AvatarCropModal from './AvatarCropModal/AvatarCropModal'; +import DotIndicatorMessage from './DotIndicatorMessage'; import Icon from './Icon'; -import PopoverMenu from './PopoverMenu'; import * as Expensicons from './Icon/Expensicons'; -import AttachmentPicker from './AttachmentPicker'; -import AvatarCropModal from './AvatarCropModal/AvatarCropModal'; import OfflineWithFeedback from './OfflineWithFeedback'; -import Tooltip from './Tooltip'; +import PopoverMenu from './PopoverMenu'; import PressableWithoutFeedback from './Pressable/PressableWithoutFeedback'; -import AttachmentModal from './AttachmentModal'; -import DotIndicatorMessage from './DotIndicatorMessage'; +import Tooltip from './Tooltip'; import withNavigationFocus from './withNavigationFocus'; const propTypes = { @@ -115,7 +115,7 @@ const defaultProps = { previewSource: '', originalFileName: '', anchorAlignment: { - horizontal: CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL.LEFT, + horizontal: CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL.LEFT, vertical: CONST.MODAL.ANCHOR_ORIGIN_VERTICAL.TOP, }, }; From c0b0f61150e8476ee233ff7b8939ce6293841d95 Mon Sep 17 00:00:00 2001 From: Kacper Falat Date: Tue, 31 Oct 2023 11:11:29 +0100 Subject: [PATCH 069/237] Prettier & linter applied after merge. --- src/libs/fileDownload/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/fileDownload/index.ts b/src/libs/fileDownload/index.ts index 927088ce4c0b..b6d5103314a1 100644 --- a/src/libs/fileDownload/index.ts +++ b/src/libs/fileDownload/index.ts @@ -1,5 +1,5 @@ -import * as FileUtils from './FileUtils'; import * as Link from '@userActions/Link'; +import * as FileUtils from './FileUtils'; import type {FileDownload} from './types'; /** From a342b162be83e198420409ae57f393ceabb44230 Mon Sep 17 00:00:00 2001 From: tienifr Date: Wed, 1 Nov 2023 16:34:42 +0700 Subject: [PATCH 070/237] refactor --- src/components/PopoverWithoutOverlay/index.js | 8 +++++--- src/libs/actions/Modal.ts | 16 ++++++++-------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/components/PopoverWithoutOverlay/index.js b/src/components/PopoverWithoutOverlay/index.js index 43156cd11827..243543231ef3 100644 --- a/src/components/PopoverWithoutOverlay/index.js +++ b/src/components/PopoverWithoutOverlay/index.js @@ -1,4 +1,4 @@ -import React from 'react'; +import React, {useRef} from 'react'; import {View} from 'react-native'; import {SafeAreaInsetsContext} from 'react-native-safe-area-context'; import {defaultProps, propTypes} from '@components/Popover/popoverPropTypes'; @@ -11,6 +11,8 @@ import * as Modal from '@userActions/Modal'; function Popover(props) { const {onOpen, close} = React.useContext(PopoverContext); + const onCloseKey = useRef(Modal.getAvailableKey()); + const {modalStyle, modalContainerStyle, shouldAddTopSafeAreaMargin, shouldAddBottomSafeAreaMargin, shouldAddTopSafeAreaPadding, shouldAddBottomSafeAreaPadding} = getModalStyles( 'popover', { @@ -30,8 +32,8 @@ function Popover(props) { ref: props.withoutOverlayRef, close: props.onClose, anchorRef: props.anchorRef, - onCloseCallback: () => Modal.setCloseModal(null), - onOpenCallback: () => Modal.setCloseModal(() => props.onClose(props.anchorRef)), + onCloseCallback: () => Modal.setCloseModal(onCloseKey, null), + onOpenCallback: () => Modal.setCloseModal(onCloseKey, () => props.onClose(props.anchorRef)), }); } else { props.onModalHide(); diff --git a/src/libs/actions/Modal.ts b/src/libs/actions/Modal.ts index 431142adfb20..b466423d537b 100644 --- a/src/libs/actions/Modal.ts +++ b/src/libs/actions/Modal.ts @@ -4,7 +4,6 @@ import ONYXKEYS from '@src/ONYXKEYS'; const closeModals: Record void)> = {}; let count = 0; -// let closeModal: (isNavigating: boolean) => void; let onModalClose: null | (() => void); /** @@ -26,13 +25,14 @@ function setCloseModal(key: number, onClose: () => void) { */ function close(onModalCloseCallback: () => void, isNavigating = true) { onModalClose = onModalCloseCallback; - const reversalOnCloses = Object.values(closeModals).reverse(); - reversalOnCloses.forEach((onClose) => { - if (typeof onClose !== 'function') { - return; - } - onClose(isNavigating); - }); + Object.values(closeModals) + .reverse() + .forEach((onClose) => { + if (typeof onClose !== 'function') { + return; + } + onClose(isNavigating); + }); } function onModalDidClose() { From b1b83496b5473ef4a813da9c0a4f00155755d30b Mon Sep 17 00:00:00 2001 From: Vit Horacek Date: Wed, 1 Nov 2023 17:06:51 +0000 Subject: [PATCH 071/237] Fix merge conflict --- src/components/AddPaymentMethodMenu.js | 2 +- src/libs/actions/Policy.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/AddPaymentMethodMenu.js b/src/components/AddPaymentMethodMenu.js index a0b839e736de..813e27e3b821 100644 --- a/src/components/AddPaymentMethodMenu.js +++ b/src/components/AddPaymentMethodMenu.js @@ -84,7 +84,7 @@ function AddPaymentMethodMenu(props) { props.onItemSelected(CONST.PAYMENT_METHODS.BANK_ACCOUNT); }, }, - ...(ReportUtils.isIOUReport(this.props.iouReport) && ReportActionsUtils.hasRequestFromPayer(lodashGet(this.props.iouReport, 'reportID', 0), this.props.session.accountID) + ...(ReportUtils.isIOUReport(props.iouReport) && ReportActionsUtils.hasRequestFromPayer(lodashGet(props.iouReport, 'reportID', 0), props.session.accountID) ? [ { text: props.translate('common.businessBankAccount'), diff --git a/src/libs/actions/Policy.js b/src/libs/actions/Policy.js index 0187af2c76a8..06b8970794d2 100644 --- a/src/libs/actions/Policy.js +++ b/src/libs/actions/Policy.js @@ -1598,7 +1598,7 @@ function startCollectBottomUpFlow(iouReport, firstName, lastName) { ]; API.write( - 'BottomUpCollectFlow', + 'CreateWorkspaceFromIOUPayment', { policyID, announceChatReportID, From c814adedbb12d5d2d5be64d8d8ec4b0aa412ce45 Mon Sep 17 00:00:00 2001 From: Vit Horacek Date: Thu, 2 Nov 2023 16:32:42 +0000 Subject: [PATCH 072/237] Fix issues in the flow --- src/components/AddPaymentMethodMenu.js | 4 +-- src/components/KYCWall/BaseKYCWall.js | 1 + src/components/MoneyReportHeader.js | 2 -- .../MoneyRequestConfirmationList.js | 1 - .../ReportActionItem/ReportPreview.js | 1 - src/components/SettlementButton.js | 32 ++----------------- 6 files changed, 5 insertions(+), 36 deletions(-) diff --git a/src/components/AddPaymentMethodMenu.js b/src/components/AddPaymentMethodMenu.js index 813e27e3b821..186cab115a39 100644 --- a/src/components/AddPaymentMethodMenu.js +++ b/src/components/AddPaymentMethodMenu.js @@ -84,11 +84,11 @@ function AddPaymentMethodMenu(props) { props.onItemSelected(CONST.PAYMENT_METHODS.BANK_ACCOUNT); }, }, - ...(ReportUtils.isIOUReport(props.iouReport) && ReportActionsUtils.hasRequestFromPayer(lodashGet(props.iouReport, 'reportID', 0), props.session.accountID) + ...(ReportUtils.isIOUReport(props.iouReport) && !ReportActionsUtils.hasRequestFromPayer(lodashGet(props.iouReport, 'reportID', 0), props.session.accountID) ? [ { text: props.translate('common.businessBankAccount'), - icon: Expensicons.Workspace, + icon: Expensicons.Building, onSelected: () => props.onItemSelected(CONST.PAYMENT_METHODS.BUSINESS_BANK_ACCOUNT), }, ] diff --git a/src/components/KYCWall/BaseKYCWall.js b/src/components/KYCWall/BaseKYCWall.js index 6093aae43d35..034f62466979 100644 --- a/src/components/KYCWall/BaseKYCWall.js +++ b/src/components/KYCWall/BaseKYCWall.js @@ -10,6 +10,7 @@ import Navigation from '@libs/Navigation/Navigation'; import * as PaymentUtils from '@libs/PaymentUtils'; import * as ReportUtils from '@libs/ReportUtils'; import * as PaymentMethods from '@userActions/PaymentMethods'; +import * as Policy from '@userActions/Policy'; import * as Wallet from '@userActions/Wallet'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; diff --git a/src/components/MoneyReportHeader.js b/src/components/MoneyReportHeader.js index a8fb5390ebb6..b3f0c52d5cdc 100644 --- a/src/components/MoneyReportHeader.js +++ b/src/components/MoneyReportHeader.js @@ -118,7 +118,6 @@ function MoneyReportHeader({session, personalDetails, policy, chatReport, nextSt onPress={(paymentType) => IOU.payMoneyRequest(paymentType, chatReport, moneyRequestReport)} enablePaymentsRoute={ROUTES.ENABLE_PAYMENTS} addBankAccountRoute={bankAccountRoute} - shouldShowPaymentOptions style={[styles.pv2]} formattedAmount={formattedAmount} /> @@ -163,7 +162,6 @@ function MoneyReportHeader({session, personalDetails, policy, chatReport, nextSt onPress={(paymentType) => IOU.payMoneyRequest(paymentType, chatReport, moneyRequestReport)} enablePaymentsRoute={ROUTES.ENABLE_PAYMENTS} addBankAccountRoute={bankAccountRoute} - shouldShowPaymentOptions formattedAmount={formattedAmount} />
diff --git a/src/components/MoneyRequestConfirmationList.js b/src/components/MoneyRequestConfirmationList.js index da1e03bd28e8..a8b4f95cae69 100755 --- a/src/components/MoneyRequestConfirmationList.js +++ b/src/components/MoneyRequestConfirmationList.js @@ -512,7 +512,6 @@ function MoneyRequestConfirmationList(props) { addDebitCardRoute={ROUTES.IOU_SEND_ADD_DEBIT_CARD} currency={props.iouCurrencyCode} policyID={props.policyID} - shouldShowPaymentOptions buttonSize={CONST.DROPDOWN_BUTTON_SIZE.LARGE} kycWallAnchorAlignment={{ horizontal: CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL.LEFT, diff --git a/src/components/ReportActionItem/ReportPreview.js b/src/components/ReportActionItem/ReportPreview.js index 00a4526b382f..b90b509fdefb 100644 --- a/src/components/ReportActionItem/ReportPreview.js +++ b/src/components/ReportActionItem/ReportPreview.js @@ -245,7 +245,6 @@ function ReportPreview(props) { onPress={(paymentType) => IOU.payMoneyRequest(paymentType, props.chatReport, props.iouReport)} enablePaymentsRoute={ROUTES.ENABLE_PAYMENTS} addBankAccountRoute={bankAccountRoute} - shouldShowPaymentOptions style={[styles.mt3]} kycWallAnchorAlignment={{ horizontal: CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL.LEFT, diff --git a/src/components/SettlementButton.js b/src/components/SettlementButton.js index d2030eac8d7d..53b85b5e0f05 100644 --- a/src/components/SettlementButton.js +++ b/src/components/SettlementButton.js @@ -40,9 +40,6 @@ const propTypes = { /** The route to redirect if user does not have a payment method setup */ enablePaymentsRoute: PropTypes.string.isRequired, - /** Should we show the payment options? */ - shouldShowPaymentOptions: PropTypes.bool, - /** The last payment method used per policy */ nvp_lastPaymentMethod: PropTypes.objectOf(PropTypes.string), @@ -97,7 +94,6 @@ const defaultProps = { betas: CONST.EMPTY_ARRAY, iouReport: CONST.EMPTY_OBJECT, nvp_lastPaymentMethod: CONST.EMPTY_OBJECT, - shouldShowPaymentOptions: false, style: [], policyID: '', formattedAmount: '', @@ -130,7 +126,6 @@ function SettlementButton({ onPress, pressOnEnter, policyID, - shouldShowPaymentOptions, style, }) { const {translate} = useLocalize(); @@ -165,33 +160,10 @@ function SettlementButton({ // To achieve the one tap pay experience we need to choose the correct payment type as default, // if user already paid for some request or expense, let's use the last payment method or use default. let paymentMethod = nvp_lastPaymentMethod[policyID] || ''; - if (!shouldShowPaymentOptions) { - if (!paymentMethod) { - // In case the user hasn't paid a request yet, let's default to VBBA payment type in case of expense reports - if (isExpenseReport) { - paymentMethod = CONST.IOU.PAYMENT_TYPE.VBBA; - } else if (canUseWallet) { - // If they have Wallet set up, use that payment method as default - paymentMethod = CONST.IOU.PAYMENT_TYPE.EXPENSIFY; - } else { - paymentMethod = CONST.IOU.PAYMENT_TYPE.ELSEWHERE; - } - } - - // In case of the settlement button in the report preview component, we do not show payment options and the label for Wallet and ACH type is simply "Pay". - return [ - { - ...paymentMethods[paymentMethod], - text: paymentMethod === CONST.IOU.PAYMENT_TYPE.ELSEWHERE ? translate('iou.payElsewhere') : translate('iou.pay'), - }, - ]; - } if (canUseWallet) { buttonOptions.push(paymentMethods[CONST.IOU.PAYMENT_TYPE.EXPENSIFY]); } - if (isExpenseReport) { - buttonOptions.push(paymentMethods[CONST.IOU.PAYMENT_TYPE.VBBA]); - } + buttonOptions.push(paymentMethods[CONST.IOU.PAYMENT_TYPE.VBBA]); buttonOptions.push(paymentMethods[CONST.IOU.PAYMENT_TYPE.ELSEWHERE]); // Put the preferred payment method to the front of the array so its shown as default @@ -199,7 +171,7 @@ function SettlementButton({ return _.sortBy(buttonOptions, (method) => (method.value === paymentMethod ? 0 : 1)); } return buttonOptions; - }, [betas, currency, formattedAmount, iouReport, nvp_lastPaymentMethod, policyID, shouldShowPaymentOptions, translate]); + }, [betas, currency, formattedAmount, iouReport, nvp_lastPaymentMethod, policyID, translate]); const selectPaymentType = (event, iouPaymentType, triggerKYCFlow) => { if (iouPaymentType === CONST.IOU.PAYMENT_TYPE.EXPENSIFY || iouPaymentType === CONST.IOU.PAYMENT_TYPE.VBBA) { From cfe141bd6af6755d84cb1fc677bb7346372e9a48 Mon Sep 17 00:00:00 2001 From: Vit Horacek Date: Thu, 2 Nov 2023 16:33:19 +0000 Subject: [PATCH 073/237] Update the personal bank account const name --- src/CONST.ts | 2 +- src/components/AddPaymentMethodMenu.js | 2 +- src/components/KYCWall/BaseKYCWall.js | 4 ++-- src/libs/PaymentUtils.ts | 2 +- src/libs/actions/PaymentMethods.ts | 10 +++++----- .../Wallet/ChooseTransferAccountPage.js | 4 ++-- src/pages/settings/Wallet/PaymentMethodList.js | 6 +++--- .../settings/Wallet/TransferBalancePage.js | 6 +++--- .../settings/Wallet/WalletPage/WalletPage.js | 18 +++++++++--------- .../settings/Wallet/walletTransferPropTypes.js | 2 +- src/types/onyx/BankAccount.ts | 2 +- src/types/onyx/WalletTransfer.ts | 2 +- 12 files changed, 30 insertions(+), 30 deletions(-) diff --git a/src/CONST.ts b/src/CONST.ts index e270f0066139..cb12a2a5f746 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -1111,7 +1111,7 @@ const CONST = { PAYMENT_METHODS: { DEBIT_CARD: 'debitCard', - BANK_ACCOUNT: 'bankAccount', + PERSONAL_BANK_ACCOUNT: 'bankAccount', BUSINESS_BANK_ACCOUNT: 'businessBankAccount', }, diff --git a/src/components/AddPaymentMethodMenu.js b/src/components/AddPaymentMethodMenu.js index 186cab115a39..f6ed7e8254a0 100644 --- a/src/components/AddPaymentMethodMenu.js +++ b/src/components/AddPaymentMethodMenu.js @@ -81,7 +81,7 @@ function AddPaymentMethodMenu(props) { text: props.translate('common.personalBankAccount'), icon: Expensicons.Bank, onSelected: () => { - props.onItemSelected(CONST.PAYMENT_METHODS.BANK_ACCOUNT); + props.onItemSelected(CONST.PAYMENT_METHODS.PERSONAL_BANK_ACCOUNT); }, }, ...(ReportUtils.isIOUReport(props.iouReport) && !ReportActionsUtils.hasRequestFromPayer(lodashGet(props.iouReport, 'reportID', 0), props.session.accountID) diff --git a/src/components/KYCWall/BaseKYCWall.js b/src/components/KYCWall/BaseKYCWall.js index 034f62466979..92df53353cf6 100644 --- a/src/components/KYCWall/BaseKYCWall.js +++ b/src/components/KYCWall/BaseKYCWall.js @@ -94,7 +94,7 @@ class KYCWall extends React.Component { */ selectPaymentMethod(paymentMethod) { this.props.onSelectPaymentMethod(paymentMethod); - if (paymentMethod === CONST.PAYMENT_METHODS.BANK_ACCOUNT) { + if (paymentMethod === CONST.PAYMENT_METHODS.PERSONAL_BANK_ACCOUNT) { Navigation.navigate(this.props.addBankAccountRoute); } else if (paymentMethod === CONST.PAYMENT_METHODS.DEBIT_CARD) { Navigation.navigate(this.props.addDebitCardRoute); @@ -138,7 +138,7 @@ class KYCWall extends React.Component { ) { Log.info('[KYC Wallet] User does not have valid payment method'); if (!this.props.shouldIncludeDebitCard) { - this.selectPaymentMethod(CONST.PAYMENT_METHODS.BANK_ACCOUNT); + this.selectPaymentMethod(CONST.PAYMENT_METHODS.PERSONAL_BANK_ACCOUNT); return; } const clickedElementLocation = getClickedTargetLocation(targetElement); diff --git a/src/libs/PaymentUtils.ts b/src/libs/PaymentUtils.ts index b37db2584394..5bd70fee4d83 100644 --- a/src/libs/PaymentUtils.ts +++ b/src/libs/PaymentUtils.ts @@ -26,7 +26,7 @@ function hasExpensifyPaymentMethod(fundList: Record, bankAccountLi function getPaymentMethodDescription(accountType: AccountType, account: BankAccount['accountData'] | Fund['accountData']): string { if (account) { - if (accountType === CONST.PAYMENT_METHODS.BANK_ACCOUNT && 'accountNumber' in account) { + if (accountType === CONST.PAYMENT_METHODS.PERSONAL_BANK_ACCOUNT && 'accountNumber' in account) { return `${Localize.translateLocal('paymentMethodList.accountLastFour')} ${account.accountNumber?.slice(-4)}`; } if (accountType === CONST.PAYMENT_METHODS.DEBIT_CARD && 'cardNumber' in account) { diff --git a/src/libs/actions/PaymentMethods.ts b/src/libs/actions/PaymentMethods.ts index bcc5d8142470..bc2ce95c8a43 100644 --- a/src/libs/actions/PaymentMethods.ts +++ b/src/libs/actions/PaymentMethods.ts @@ -81,7 +81,7 @@ function getMakeDefaultPaymentOnyxData( key: ONYXKEYS.USER_WALLET, value: { walletLinkedAccountID: bankAccountID || fundID, - walletLinkedAccountType: bankAccountID ? CONST.PAYMENT_METHODS.BANK_ACCOUNT : CONST.PAYMENT_METHODS.DEBIT_CARD, + walletLinkedAccountType: bankAccountID ? CONST.PAYMENT_METHODS.PERSONAL_BANK_ACCOUNT : CONST.PAYMENT_METHODS.DEBIT_CARD, // Only clear the error if this is optimistic data. If this is failure data, we do not want to clear the error that came from the server. errors: null, }, @@ -91,7 +91,7 @@ function getMakeDefaultPaymentOnyxData( key: ONYXKEYS.USER_WALLET, value: { walletLinkedAccountID: bankAccountID || fundID, - walletLinkedAccountType: bankAccountID ? CONST.PAYMENT_METHODS.BANK_ACCOUNT : CONST.PAYMENT_METHODS.DEBIT_CARD, + walletLinkedAccountType: bankAccountID ? CONST.PAYMENT_METHODS.PERSONAL_BANK_ACCOUNT : CONST.PAYMENT_METHODS.DEBIT_CARD, }, }, ]; @@ -99,7 +99,7 @@ function getMakeDefaultPaymentOnyxData( if (previousPaymentMethod?.methodID) { onyxData.push({ onyxMethod: Onyx.METHOD.MERGE, - key: previousPaymentMethod.accountType === CONST.PAYMENT_METHODS.BANK_ACCOUNT ? ONYXKEYS.BANK_ACCOUNT_LIST : ONYXKEYS.FUND_LIST, + key: previousPaymentMethod.accountType === CONST.PAYMENT_METHODS.PERSONAL_BANK_ACCOUNT ? ONYXKEYS.BANK_ACCOUNT_LIST : ONYXKEYS.FUND_LIST, value: { [previousPaymentMethod.methodID]: { isDefault: !isOptimisticData, @@ -111,7 +111,7 @@ function getMakeDefaultPaymentOnyxData( if (currentPaymentMethod?.methodID) { onyxData.push({ onyxMethod: Onyx.METHOD.MERGE, - key: currentPaymentMethod.accountType === CONST.PAYMENT_METHODS.BANK_ACCOUNT ? ONYXKEYS.BANK_ACCOUNT_LIST : ONYXKEYS.FUND_LIST, + key: currentPaymentMethod.accountType === CONST.PAYMENT_METHODS.PERSONAL_BANK_ACCOUNT ? ONYXKEYS.BANK_ACCOUNT_LIST : ONYXKEYS.FUND_LIST, value: { [currentPaymentMethod.methodID]: { isDefault: isOptimisticData, @@ -223,7 +223,7 @@ function clearDebitCardFormErrorAndSubmit() { * */ function transferWalletBalance(paymentMethod: PaymentMethod) { - const paymentMethodIDKey = paymentMethod.accountType === CONST.PAYMENT_METHODS.BANK_ACCOUNT ? CONST.PAYMENT_METHOD_ID_KEYS.BANK_ACCOUNT : CONST.PAYMENT_METHOD_ID_KEYS.DEBIT_CARD; + const paymentMethodIDKey = paymentMethod.accountType === CONST.PAYMENT_METHODS.PERSONAL_BANK_ACCOUNT ? CONST.PAYMENT_METHOD_ID_KEYS.BANK_ACCOUNT : CONST.PAYMENT_METHOD_ID_KEYS.DEBIT_CARD; type TransferWalletBalanceParameters = Partial, number | undefined>>; diff --git a/src/pages/settings/Wallet/ChooseTransferAccountPage.js b/src/pages/settings/Wallet/ChooseTransferAccountPage.js index a44e21390b80..9fe95f477ac9 100644 --- a/src/pages/settings/Wallet/ChooseTransferAccountPage.js +++ b/src/pages/settings/Wallet/ChooseTransferAccountPage.js @@ -36,7 +36,7 @@ function ChooseTransferAccountPage(props) { * @param {Object} account of the selected account data */ const selectAccountAndNavigateBack = (event, accountType, account) => { - PaymentMethods.saveWalletTransferAccountTypeAndID(accountType, accountType === CONST.PAYMENT_METHODS.BANK_ACCOUNT ? account.bankAccountID : account.fundID); + PaymentMethods.saveWalletTransferAccountTypeAndID(accountType, accountType === CONST.PAYMENT_METHODS.PERSONAL_BANK_ACCOUNT ? account.bankAccountID : account.fundID); Navigation.goBack(ROUTES.SETTINGS_WALLET_TRANSFER_BALANCE); }; @@ -69,7 +69,7 @@ function ChooseTransferAccountPage(props) { method.accountType === CONST.PAYMENT_METHODS.BANK_ACCOUNT || method.accountType === CONST.PAYMENT_METHODS.DEBIT_CARD, + (method) => method.accountType === CONST.PAYMENT_METHODS.PERSONAL_BANK_ACCOUNT || method.accountType === CONST.PAYMENT_METHODS.DEBIT_CARD, ).length; return defaultablePaymentMethodCount > 1; } diff --git a/src/pages/settings/Wallet/TransferBalancePage.js b/src/pages/settings/Wallet/TransferBalancePage.js index 1df07365a1f6..fbcb7a9dc1df 100644 --- a/src/pages/settings/Wallet/TransferBalancePage.js +++ b/src/pages/settings/Wallet/TransferBalancePage.js @@ -84,7 +84,7 @@ function TransferBalancePage(props) { title: props.translate('transferAmountPage.ach'), description: props.translate('transferAmountPage.achSummary'), icon: Expensicons.Bank, - type: CONST.PAYMENT_METHODS.BANK_ACCOUNT, + type: CONST.PAYMENT_METHODS.PERSONAL_BANK_ACCOUNT, }, ]; @@ -145,7 +145,7 @@ function TransferBalancePage(props) { { - if (paymentMethod.selectedPaymentMethodType === CONST.PAYMENT_METHODS.BANK_ACCOUNT) { + if (paymentMethod.selectedPaymentMethodType === CONST.PAYMENT_METHODS.PERSONAL_BANK_ACCOUNT) { return paymentMethod.selectedPaymentMethod.bankAccountID; } if (paymentMethod.selectedPaymentMethodType === CONST.PAYMENT_METHODS.DEBIT_CARD) { @@ -150,12 +150,12 @@ function WalletPage({bankAccountList, betas, cardList, fundList, isLoadingPaymen // The delete/default menu if (accountType) { let formattedSelectedPaymentMethod; - if (accountType === CONST.PAYMENT_METHODS.BANK_ACCOUNT) { + if (accountType === CONST.PAYMENT_METHODS.PERSONAL_BANK_ACCOUNT) { formattedSelectedPaymentMethod = { title: account.addressName, icon: account.icon, description: PaymentUtils.getPaymentMethodDescription(accountType, account), - type: CONST.PAYMENT_METHODS.BANK_ACCOUNT, + type: CONST.PAYMENT_METHODS.PERSONAL_BANK_ACCOUNT, }; } else if (accountType === CONST.PAYMENT_METHODS.DEBIT_CARD) { formattedSelectedPaymentMethod = { @@ -200,7 +200,7 @@ function WalletPage({bankAccountList, betas, cardList, fundList, isLoadingPaymen return; } - if (paymentType === CONST.PAYMENT_METHODS.BANK_ACCOUNT) { + if (paymentType === CONST.PAYMENT_METHODS.PERSONAL_BANK_ACCOUNT) { BankAccounts.openPersonalBankAccountSetupView(); return; } @@ -226,7 +226,7 @@ function WalletPage({bankAccountList, betas, cardList, fundList, isLoadingPaymen const previousPaymentMethod = _.find(paymentMethods, (method) => method.isDefault); const currentPaymentMethod = _.find(paymentMethods, (method) => method.methodID === paymentMethod.methodID); - if (paymentMethod.selectedPaymentMethodType === CONST.PAYMENT_METHODS.BANK_ACCOUNT) { + if (paymentMethod.selectedPaymentMethodType === CONST.PAYMENT_METHODS.PERSONAL_BANK_ACCOUNT) { PaymentMethods.makeDefaultPaymentMethod(paymentMethod.selectedPaymentMethod.bankAccountID, null, previousPaymentMethod, currentPaymentMethod); } else if (paymentMethod.selectedPaymentMethodType === CONST.PAYMENT_METHODS.DEBIT_CARD) { PaymentMethods.makeDefaultPaymentMethod(null, paymentMethod.selectedPaymentMethod.fundID, previousPaymentMethod, currentPaymentMethod); @@ -241,7 +241,7 @@ function WalletPage({bankAccountList, betas, cardList, fundList, isLoadingPaymen ]); const deletePaymentMethod = useCallback(() => { - if (paymentMethod.selectedPaymentMethodType === CONST.PAYMENT_METHODS.BANK_ACCOUNT) { + if (paymentMethod.selectedPaymentMethodType === CONST.PAYMENT_METHODS.PERSONAL_BANK_ACCOUNT) { BankAccounts.deletePaymentBankAccount(paymentMethod.selectedPaymentMethod.bankAccountID); } else if (paymentMethod.selectedPaymentMethodType === CONST.PAYMENT_METHODS.DEBIT_CARD) { PaymentMethods.deletePaymentCard(paymentMethod.selectedPaymentMethod.fundID); @@ -292,7 +292,7 @@ function WalletPage({bankAccountList, betas, cardList, fundList, isLoadingPaymen // We should reset selected payment method state values and close corresponding modals if the selected payment method is deleted let shouldResetPaymentMethodData = false; - if (paymentMethod.selectedPaymentMethodType === CONST.PAYMENT_METHODS.BANK_ACCOUNT && _.isEmpty(bankAccountList[paymentMethod.methodID])) { + if (paymentMethod.selectedPaymentMethodType === CONST.PAYMENT_METHODS.PERSONAL_BANK_ACCOUNT && _.isEmpty(bankAccountList[paymentMethod.methodID])) { shouldResetPaymentMethodData = true; } else if (paymentMethod.selectedPaymentMethodType === CONST.PAYMENT_METHODS.DEBIT_CARD && _.isEmpty(fundList[paymentMethod.methodID])) { shouldResetPaymentMethodData = true; @@ -308,7 +308,7 @@ function WalletPage({bankAccountList, betas, cardList, fundList, isLoadingPaymen const shouldShowMakeDefaultButton = !paymentMethod.isSelectedPaymentMethodDefault && Permissions.canUseWallet(betas) && - !(paymentMethod.formattedSelectedPaymentMethod.type === CONST.PAYMENT_METHODS.BANK_ACCOUNT && paymentMethod.selectedPaymentMethod.type === CONST.BANK_ACCOUNT.TYPE.BUSINESS); + !(paymentMethod.formattedSelectedPaymentMethod.type === CONST.PAYMENT_METHODS.PERSONAL_BANK_ACCOUNT && paymentMethod.selectedPaymentMethod.type === CONST.BANK_ACCOUNT.TYPE.BUSINESS); // Determines whether or not the modal popup is mounted from the bottom of the screen instead of the side mount on Web or Desktop screens const isPopoverBottomMount = anchorPosition.anchorPositionTop === 0 || isSmallScreenWidth; @@ -362,7 +362,7 @@ function WalletPage({bankAccountList, betas, cardList, fundList, isLoadingPaymen navigateToWalletOrTransferBalancePage(source)} onSelectPaymentMethod={(selectedPaymentMethod) => { - if (hasActivatedWallet || selectedPaymentMethod !== CONST.PAYMENT_METHODS.BANK_ACCOUNT) { + if (hasActivatedWallet || selectedPaymentMethod !== CONST.PAYMENT_METHODS.PERSONAL_BANK_ACCOUNT) { return; } // To allow upgrading to a gold wallet, continue with the KYC flow after adding a bank account diff --git a/src/pages/settings/Wallet/walletTransferPropTypes.js b/src/pages/settings/Wallet/walletTransferPropTypes.js index 38c65fcfd703..9e25213382e9 100644 --- a/src/pages/settings/Wallet/walletTransferPropTypes.js +++ b/src/pages/settings/Wallet/walletTransferPropTypes.js @@ -7,7 +7,7 @@ const walletTransferPropTypes = PropTypes.shape({ selectedAccountID: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), /** Type to filter the payment Method list */ - filterPaymentMethodType: PropTypes.oneOf([CONST.PAYMENT_METHODS.DEBIT_CARD, CONST.PAYMENT_METHODS.BANK_ACCOUNT, '']), + filterPaymentMethodType: PropTypes.oneOf([CONST.PAYMENT_METHODS.DEBIT_CARD, CONST.PAYMENT_METHODS.PERSONAL_BANK_ACCOUNT, '']), /** Whether the success screen is shown to user. */ shouldShowSuccess: PropTypes.bool, diff --git a/src/types/onyx/BankAccount.ts b/src/types/onyx/BankAccount.ts index 4a7b6dac7387..2b2bee7df6b0 100644 --- a/src/types/onyx/BankAccount.ts +++ b/src/types/onyx/BankAccount.ts @@ -4,7 +4,7 @@ import * as OnyxCommon from './OnyxCommon'; type BankAccount = { /** The bank account type */ - accountType?: typeof CONST.PAYMENT_METHODS.BANK_ACCOUNT; + accountType?: typeof CONST.PAYMENT_METHODS.PERSONAL_BANK_ACCOUNT; /** string like 'Account ending in XXXX' */ description?: string; diff --git a/src/types/onyx/WalletTransfer.ts b/src/types/onyx/WalletTransfer.ts index e1b1468d6536..cebea543884b 100644 --- a/src/types/onyx/WalletTransfer.ts +++ b/src/types/onyx/WalletTransfer.ts @@ -25,7 +25,7 @@ type WalletTransfer = { paymentMethodType?: ValueOf>; }; -type FilterMethodPaymentType = typeof CONST.PAYMENT_METHODS.DEBIT_CARD | typeof CONST.PAYMENT_METHODS.BANK_ACCOUNT | null; +type FilterMethodPaymentType = typeof CONST.PAYMENT_METHODS.DEBIT_CARD | typeof CONST.PAYMENT_METHODS.PERSONAL_BANK_ACCOUNT | null; export default WalletTransfer; From ae33908060085d29e0ae3572b6bce00fbfa54b61 Mon Sep 17 00:00:00 2001 From: Vit Horacek Date: Thu, 2 Nov 2023 23:31:23 +0000 Subject: [PATCH 074/237] Flow clean up --- src/CONST.ts | 1 + src/components/KYCWall/BaseKYCWall.js | 2 +- src/libs/ReportUtils.js | 45 +++++++++++++++++++++++ src/libs/actions/Policy.js | 41 ++++++++++++++------- src/pages/home/report/ReportActionItem.js | 2 +- 5 files changed, 75 insertions(+), 16 deletions(-) diff --git a/src/CONST.ts b/src/CONST.ts index cb12a2a5f746..08a4252238d6 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -503,6 +503,7 @@ const CONST = { CREATED: 'CREATED', IOU: 'IOU', MODIFIEDEXPENSE: 'MODIFIEDEXPENSE', + MOVED: 'MOVED', REIMBURSEMENTQUEUED: 'REIMBURSEMENTQUEUED', RENAMED: 'RENAMED', REPORTPREVIEW: 'REPORTPREVIEW', diff --git a/src/components/KYCWall/BaseKYCWall.js b/src/components/KYCWall/BaseKYCWall.js index 92df53353cf6..46479d554bdf 100644 --- a/src/components/KYCWall/BaseKYCWall.js +++ b/src/components/KYCWall/BaseKYCWall.js @@ -99,7 +99,7 @@ class KYCWall extends React.Component { } else if (paymentMethod === CONST.PAYMENT_METHODS.DEBIT_CARD) { Navigation.navigate(this.props.addDebitCardRoute); } else if (paymentMethod === CONST.PAYMENT_METHODS.BUSINESS_BANK_ACCOUNT) { - Policy.startCollectFlow(this.props.iouReport); + Policy.createWorkspaceFromIOUPayment(this.props.iouReport); } } diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 10630d7fb122..d3b16a73f16f 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -2612,6 +2612,7 @@ function buildOptimisticIOUReportAction( whisperedToAccountIDs: _.contains([CONST.IOU.RECEIPT_STATE.SCANREADY, CONST.IOU.RECEIPT_STATE.SCANNING], receipt.state) ? [currentUserAccountID] : [], }; } + /** * Builds an optimistic APPROVED report action with a randomly generated reportActionID. * @@ -2650,6 +2651,49 @@ function buildOptimisticApprovedReportAction(amount, currency, expenseReportID) }; } +/** + * Builds an optimistic MOVED report action with a randomly generated reportActionID. + * This action is used when we move reports across workspaces. + * + * @param {String} fromPolicyID + * @param {String} toPolicyID + * @param {Number} newParentReportID + * @param {Number} movedReportID An ID of the report we are moveing across workspaces + * + * @returns {Object} + */ +function buildOptimisticMovedReportAction(fromPolicyID, toPolicyID, newParentReportID, movedReportID) { + const originalMessage = { + fromPolicyID, + toPolicyID, + newParentReportID, + movedReportID, + }; + + const policyName = getPolicyName(allReports[`${ONYXKEYS.COLLECTION.REPORT}${newParentReportID}`]); + + return { + actionName: CONST.REPORT.ACTIONS.TYPE.MOVED, + actorAccountID: currentUserAccountID, + automatic: false, + avatar: lodashGet(currentUserPersonalDetails, 'avatar', UserUtils.getDefaultAvatarURL(currentUserAccountID)), + isAttachment: false, + originalMessage, + message: "moved report", + person: [ + { + style: 'strong', + text: lodashGet(currentUserPersonalDetails, 'displayName', currentUserEmail), + type: 'TEXT', + }, + ], + reportActionID: NumberUtils.rand64(), + shouldShow: true, + created: DateUtils.getDBTime(), + pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, + }; +} + /** * Builds an optimistic SUBMITTED report action with a randomly generated reportActionID. * @@ -4216,6 +4260,7 @@ export { buildOptimisticEditedTaskReportAction, buildOptimisticIOUReport, buildOptimisticApprovedReportAction, + buildOptimisticMovedReportAction, buildOptimisticSubmittedReportAction, buildOptimisticExpenseReport, buildOptimisticIOUReportAction, diff --git a/src/libs/actions/Policy.js b/src/libs/actions/Policy.js index 941fa814a9b4..a022d8f61f18 100644 --- a/src/libs/actions/Policy.js +++ b/src/libs/actions/Policy.js @@ -1360,7 +1360,7 @@ function buildOptimisticPolicyRecentlyUsedCategories(policyID, category) { return lodashUnion([category], policyRecentlyUsedCategories); } -function startCollectBottomUpFlow(iouReport, firstName, lastName) { +function createWorkspaceFromIOUPayment(iouReport) { // This flow only works for IOU reports if (!ReportUtils.isIOUReport(iouReport)) { return; @@ -1544,6 +1544,7 @@ function startCollectBottomUpFlow(iouReport, firstName, lastName) { }, ...employeeWorkspaceChat.onyxSuccessData, ]; + const failureData = [ { onyxMethod: Onyx.METHOD.SET, @@ -1585,17 +1586,29 @@ function startCollectBottomUpFlow(iouReport, firstName, lastName) { // Next we need to convert the IOU report to Expense report and clean up the DM chat // Get the 1on1 chat where the request was originally made const chatReportID = iouReport.chatReportID; - ReportUtils.getReport(iouReport.chatReportID); + optimisticData.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport.reportID}`, + value: { + ...iouReport, + type: CONST.REPORT.TYPE.EXPENSE + }, + }); + failureData.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport.reportID}`, + value: iouReport, + }); + + const chatReport = ReportUtils.getReport(iouReport.chatReportID); const reportPreviewID = iouReport.parentReportActionID; - const membersData = [ - { - accountID: employeeAccountID, - email: employeeEmail, - workspaceChatReportID: employeeWorkspaceChat.reportCreationData[employeeEmail].reportID, - workspaceChatCreatedReportActionID: employeeWorkspaceChat.reportCreationData[employeeEmail].reportActionID, - }, - ]; + const memberData = { + accountID: Number(employeeAccountID), + email: employeeEmail, + workspaceChatReportID: Number(employeeWorkspaceChat.reportCreationData[employeeEmail].reportID), + workspaceChatCreatedReportActionID: Number(employeeWorkspaceChat.reportCreationData[employeeEmail].reportActionID), + }; API.write( 'CreateWorkspaceFromIOUPayment', @@ -1604,7 +1617,7 @@ function startCollectBottomUpFlow(iouReport, firstName, lastName) { announceChatReportID, adminsChatReportID, expenseChatReportID: workspaceChatReportID, - ownerEmail: sessionEmail, + ownerEmail: '', makeMeAdmin: false, policyName: workspaceName, type: CONST.POLICY.TYPE.TEAM, @@ -1614,11 +1627,11 @@ function startCollectBottomUpFlow(iouReport, firstName, lastName) { customUnitID, customUnitRateID, iouReportID: iouReport.reportID, - membersData: JSON.stringify(membersData), + memberData: JSON.stringify(memberData), + reportActionID: 0, }, {optimisticData, successData, failureData}, ); - // Navigation.dismissModal(CONST.TEACHERS_UNITE.PUBLIC_ROOM_ID); } export { @@ -1647,11 +1660,11 @@ export { openWorkspaceMembersPage, openWorkspaceInvitePage, removeWorkspace, + createWorkspaceFromIOUPayment, setWorkspaceInviteMembersDraft, clearErrors, dismissAddedWithPrimaryLoginMessages, openDraftWorkspaceRequest, buildOptimisticPolicyRecentlyUsedCategories, createDraftInitialWorkspace, - startCollectBottomUpFlow, }; diff --git a/src/pages/home/report/ReportActionItem.js b/src/pages/home/report/ReportActionItem.js index a7a3bc0739f3..eb0ae4f8978a 100644 --- a/src/pages/home/report/ReportActionItem.js +++ b/src/pages/home/report/ReportActionItem.js @@ -422,7 +422,7 @@ function ReportActionItem(props) { isHidden={isHidden} style={[ _.contains( - [..._.values(CONST.REPORT.ACTIONS.TYPE.POLICYCHANGELOG), CONST.REPORT.ACTIONS.TYPE.IOU, CONST.REPORT.ACTIONS.TYPE.APPROVED], + [..._.values(CONST.REPORT.ACTIONS.TYPE.POLICYCHANGELOG), CONST.REPORT.ACTIONS.TYPE.IOU, CONST.REPORT.ACTIONS.TYPE.APPROVED, CONST.REPORT.ACTIONS.TYPE.MOVED], props.action.actionName, ) ? styles.colorMuted From 3dc351255b70f5cce05e4a44000e6c79dd9767bc Mon Sep 17 00:00:00 2001 From: Alberto Date: Fri, 3 Nov 2023 13:04:03 +0100 Subject: [PATCH 075/237] docs --- src/components/DotIndicatorMessage.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/DotIndicatorMessage.js b/src/components/DotIndicatorMessage.js index 6610db1b4a61..3297f70fafc6 100644 --- a/src/components/DotIndicatorMessage.js +++ b/src/components/DotIndicatorMessage.js @@ -45,6 +45,7 @@ const defaultProps = { * Check if the error includes a receipt. * * @param {String} message + * @returns {Boolean} */ const isReceiptError = (message) => { if (_.isString(message)) { From 93d176c82676d091313aea251db3ab48a94fac56 Mon Sep 17 00:00:00 2001 From: Vit Horacek Date: Fri, 3 Nov 2023 14:26:39 +0000 Subject: [PATCH 076/237] Offer correct payment options --- src/components/AddPaymentMethodMenu.js | 18 +++++++++++------- src/components/KYCWall/BaseKYCWall.js | 6 +++++- src/pages/home/report/ReportActionItem.js | 17 +++++++++-------- .../home/report/ReportActionItemFragment.js | 2 +- .../home/report/ReportActionItemMessage.js | 1 - 5 files changed, 26 insertions(+), 18 deletions(-) diff --git a/src/components/AddPaymentMethodMenu.js b/src/components/AddPaymentMethodMenu.js index f6ed7e8254a0..85419387cc6e 100644 --- a/src/components/AddPaymentMethodMenu.js +++ b/src/components/AddPaymentMethodMenu.js @@ -77,14 +77,18 @@ function AddPaymentMethodMenu(props) { anchorRef={props.anchorRef} onItemSelected={props.onClose} menuItems={[ - { - text: props.translate('common.personalBankAccount'), - icon: Expensicons.Bank, - onSelected: () => { - props.onItemSelected(CONST.PAYMENT_METHODS.PERSONAL_BANK_ACCOUNT); + ...(ReportUtils.isIOUReport(props.iouReport) + ?[ + { + text: props.translate('common.personalBankAccount'), + icon: Expensicons.Bank, + onSelected: () => { + props.onItemSelected(CONST.PAYMENT_METHODS.PERSONAL_BANK_ACCOUNT); + }, }, - }, - ...(ReportUtils.isIOUReport(props.iouReport) && !ReportActionsUtils.hasRequestFromPayer(lodashGet(props.iouReport, 'reportID', 0), props.session.accountID) + ] + : []), + ...(!ReportActionsUtils.hasRequestFromPayer(lodashGet(props.iouReport, 'reportID', 0), props.session.accountID) ? [ { text: props.translate('common.businessBankAccount'), diff --git a/src/components/KYCWall/BaseKYCWall.js b/src/components/KYCWall/BaseKYCWall.js index 46479d554bdf..add5d4ba042b 100644 --- a/src/components/KYCWall/BaseKYCWall.js +++ b/src/components/KYCWall/BaseKYCWall.js @@ -99,7 +99,11 @@ class KYCWall extends React.Component { } else if (paymentMethod === CONST.PAYMENT_METHODS.DEBIT_CARD) { Navigation.navigate(this.props.addDebitCardRoute); } else if (paymentMethod === CONST.PAYMENT_METHODS.BUSINESS_BANK_ACCOUNT) { - Policy.createWorkspaceFromIOUPayment(this.props.iouReport); + if (ReportUtils.isIOUReport(this.props.iouReport)) { + Policy.createWorkspaceFromIOUPayment(this.props.iouReport); + return; + } + Navigation.navigate(this.props.addBankAccountRoute); } } diff --git a/src/pages/home/report/ReportActionItem.js b/src/pages/home/report/ReportActionItem.js index 39d3f04b3961..ace51be25ea3 100644 --- a/src/pages/home/report/ReportActionItem.js +++ b/src/pages/home/report/ReportActionItem.js @@ -425,14 +425,15 @@ function ReportActionItem(props) { action={props.action} displayAsGroup={props.displayAsGroup} isHidden={isHidden} - style={[ - _.contains( - [..._.values(CONST.REPORT.ACTIONS.TYPE.POLICYCHANGELOG), CONST.REPORT.ACTIONS.TYPE.IOU, CONST.REPORT.ACTIONS.TYPE.APPROVED, CONST.REPORT.ACTIONS.TYPE.MOVED], - props.action.actionName, - ) - ? styles.colorMuted - : undefined, - ]} + // style={[ + // _.contains( + // [..._.values(CONST.REPORT.ACTIONS.TYPE.POLICYCHANGELOG), CONST.REPORT.ACTIONS.TYPE.IOU, CONST.REPORT.ACTIONS.TYPE.APPROVED, CONST.REPORT.ACTIONS.TYPE.MOVED], + // props.action.actionName, + // ) + // ? styles.colorMuted + // : undefined, + // ]} + style={[styles.colorMuted]} /> {hasBeenFlagged && (