From f67e7532a59c496eeeba6708070c43033aae2e71 Mon Sep 17 00:00:00 2001 From: Julian Kobrynski Date: Mon, 13 Nov 2023 09:11:22 +0100 Subject: [PATCH 01/34] migrate resizeModes to TypeScript --- src/components/Image/{resizeModes.js => resizeModes.ts} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename src/components/Image/{resizeModes.js => resizeModes.ts} (92%) diff --git a/src/components/Image/resizeModes.js b/src/components/Image/resizeModes.ts similarity index 92% rename from src/components/Image/resizeModes.js rename to src/components/Image/resizeModes.ts index e6cc699a2fe3..246793a9e3a3 100644 --- a/src/components/Image/resizeModes.js +++ b/src/components/Image/resizeModes.ts @@ -3,6 +3,6 @@ const RESIZE_MODES = { cover: 'cover', stretch: 'stretch', center: 'center', -}; +} as const; export default RESIZE_MODES; From ba4eda894774c0c2c37829623b55e49fee35006e Mon Sep 17 00:00:00 2001 From: Julian Kobrynski Date: Mon, 13 Nov 2023 09:11:42 +0100 Subject: [PATCH 02/34] start migrating Image to TypeScript --- src/components/Image/{index.js => index.tsx} | 6 ++- src/components/Image/types.ts | 41 ++++++++++++++++++++ 2 files changed, 45 insertions(+), 2 deletions(-) rename src/components/Image/{index.js => index.tsx} (92%) create mode 100644 src/components/Image/types.ts diff --git a/src/components/Image/index.js b/src/components/Image/index.tsx similarity index 92% rename from src/components/Image/index.js rename to src/components/Image/index.tsx index ef1a69e19c12..68f289b3bef0 100644 --- a/src/components/Image/index.js +++ b/src/components/Image/index.tsx @@ -6,8 +6,10 @@ import _ from 'underscore'; import ONYXKEYS from '@src/ONYXKEYS'; import {defaultProps, imagePropTypes} from './imagePropTypes'; import RESIZE_MODES from './resizeModes'; +import ImageProps from './types'; -function Image(props) { +function Image(props: ImageProps) { + console.log('*** I RENDER ***', props); const {source: propsSource, isAuthTokenRequired, onLoad, session} = props; /** * Check if the image source is a URL - if so the `encryptedAuthToken` is appended @@ -19,7 +21,7 @@ function Image(props) { // in the headers of the image request so the authToken is added as a query param. // On native the authToken IS passed in the image request headers const authToken = lodashGet(session, 'encryptedAuthToken', null); - return {uri: `${propsSource.uri}?encryptedAuthToken=${encodeURIComponent(authToken)}`}; + return {uri: `${propsSource?.uri}?encryptedAuthToken=${encodeURIComponent(authToken)}`}; } return propsSource; // The session prop is not required, as it causes the image to reload whenever the session changes. For more information, please refer to issue #26034. diff --git a/src/components/Image/types.ts b/src/components/Image/types.ts new file mode 100644 index 000000000000..99ebd0bc0e8a --- /dev/null +++ b/src/components/Image/types.ts @@ -0,0 +1,41 @@ +import {ImageResizeMode, ImageSourcePropType, ImageStyle, StyleProp} from 'react-native'; +import {OnLoadEvent} from 'react-native-fast-image'; + +type ImageProps = { + /** Styles for the Image */ + style?: StyleProp; + + /** The static asset or URI source of the image */ + source: ImageSourcePropType; + + /** Should an auth token be included in the image request */ + isAuthTokenRequired: boolean; + + /** How should the image fit within its container */ + resizeMode: ImageResizeMode; + + /** Event for when the image begins loading */ + onLoadStart: () => void; + + /** Event for when the image finishes loading */ + onLoadEnd: () => void; + + /** Event for when the image is fully loaded and returns the natural dimensions of the image */ + onLoad: (event: OnLoadEvent) => void; + + /** Progress events while the image is downloading */ + onProgress: () => void; + + /* Onyx Props */ + /** Session info for the currently logged in user. */ + session: { + /** Currently logged in user authToken */ + authToken?: string; + accountId?: number; + email?: string; + encryptedAuthToken?: string; + loading: boolean; + }; +}; + +export default ImageProps; From 98bd9e171bbf0e0c6c3791bff285c5c36c254c03 Mon Sep 17 00:00:00 2001 From: Julian Kobrynski Date: Mon, 13 Nov 2023 14:00:40 +0100 Subject: [PATCH 03/34] migrate index.js to TypeScript --- src/components/Image/index.tsx | 35 ++++++++++++++-------------------- src/components/Image/types.ts | 27 +++++++++++++------------- 2 files changed, 27 insertions(+), 35 deletions(-) diff --git a/src/components/Image/index.tsx b/src/components/Image/index.tsx index 68f289b3bef0..d161d89dcbdb 100644 --- a/src/components/Image/index.tsx +++ b/src/components/Image/index.tsx @@ -1,26 +1,23 @@ -import lodashGet from 'lodash/get'; import React, {useEffect, useMemo} from 'react'; import {Image as RNImage} from 'react-native'; import {withOnyx} from 'react-native-onyx'; -import _ from 'underscore'; import ONYXKEYS from '@src/ONYXKEYS'; -import {defaultProps, imagePropTypes} from './imagePropTypes'; import RESIZE_MODES from './resizeModes'; -import ImageProps from './types'; +import {ImageOnyxProps, ImageProps, ImagePropsWithOnyx} from './types'; -function Image(props: ImageProps) { - console.log('*** I RENDER ***', props); - const {source: propsSource, isAuthTokenRequired, onLoad, session} = props; +function Image(props: ImagePropsWithOnyx) { + const {source: propsSource, isAuthTokenRequired, onLoad, session, ...forwardedProps} = props; /** * Check if the image source is a URL - if so the `encryptedAuthToken` is appended * to the source. */ const source = useMemo(() => { - if (isAuthTokenRequired) { - // There is currently a `react-native-web` bug preventing the authToken being passed - // in the headers of the image request so the authToken is added as a query param. - // On native the authToken IS passed in the image request headers - const authToken = lodashGet(session, 'encryptedAuthToken', null); + // There is currently a `react-native-web` bug preventing the authToken being passed + // in the headers of the image request so the authToken is added as a query param. + // On native the authToken IS passed in the image request headers + const authToken = session?.encryptedAuthToken ?? null; + + if (isAuthTokenRequired && authToken && typeof propsSource !== 'number') { return {uri: `${propsSource?.uri}?encryptedAuthToken=${encodeURIComponent(authToken)}`}; } return propsSource; @@ -35,7 +32,7 @@ function Image(props: ImageProps) { useEffect(() => { // If an onLoad callback was specified then manually call it and pass // the natural image dimensions to match the native API - if (onLoad == null) { + if (onLoad == null || typeof source === 'number' || !source.uri) { return; } RNImage.getSize(source.uri, (width, height) => { @@ -43,9 +40,6 @@ function Image(props: ImageProps) { }); }, [onLoad, source]); - // Omit the props which the underlying RNImage won't use - const forwardedProps = _.omit(props, ['source', 'onLoad', 'session', 'isAuthTokenRequired']); - return ( ({ session: { key: ONYXKEYS.SESSION, }, })(Image), imagePropsAreEqual, ); -ImageWithOnyx.resizeMode = RESIZE_MODES; export default ImageWithOnyx; diff --git a/src/components/Image/types.ts b/src/components/Image/types.ts index 99ebd0bc0e8a..e89fc81125cf 100644 --- a/src/components/Image/types.ts +++ b/src/components/Image/types.ts @@ -1,12 +1,20 @@ -import {ImageResizeMode, ImageSourcePropType, ImageStyle, StyleProp} from 'react-native'; +import {ImageRequireSource, ImageResizeMode, ImageStyle, ImageURISource, StyleProp} from 'react-native'; import {OnLoadEvent} from 'react-native-fast-image'; +import {OnyxEntry} from 'react-native-onyx'; +import {Session} from '@src/types/onyx'; + +type ImageOnyxProps = { + /* Onyx Props */ + /** Session info for the currently logged in user. */ + session: OnyxEntry; +}; type ImageProps = { /** Styles for the Image */ style?: StyleProp; /** The static asset or URI source of the image */ - source: ImageSourcePropType; + source: ImageURISource | ImageRequireSource; /** Should an auth token be included in the image request */ isAuthTokenRequired: boolean; @@ -25,17 +33,8 @@ type ImageProps = { /** Progress events while the image is downloading */ onProgress: () => void; - - /* Onyx Props */ - /** Session info for the currently logged in user. */ - session: { - /** Currently logged in user authToken */ - authToken?: string; - accountId?: number; - email?: string; - encryptedAuthToken?: string; - loading: boolean; - }; }; -export default ImageProps; +type ImagePropsWithOnyx = ImageOnyxProps & ImageProps; + +export type {ImageProps, ImageOnyxProps, ImagePropsWithOnyx}; From 1e9542124ffe74af8e8d1000779f0e002267fa2c Mon Sep 17 00:00:00 2001 From: Julian Kobrynski Date: Tue, 14 Nov 2023 09:14:32 +0100 Subject: [PATCH 04/34] migrate index.native.js to TypeScript --- .../{index.native.js => index.native.tsx} | 34 ++++++++++--------- src/components/Image/types.ts | 8 ++--- 2 files changed, 22 insertions(+), 20 deletions(-) rename src/components/Image/{index.native.js => index.native.tsx} (55%) diff --git a/src/components/Image/index.native.js b/src/components/Image/index.native.tsx similarity index 55% rename from src/components/Image/index.native.js rename to src/components/Image/index.native.tsx index cf5320392d1b..0acf57d099a9 100644 --- a/src/components/Image/index.native.js +++ b/src/components/Image/index.native.tsx @@ -1,35 +1,35 @@ -import lodashGet from 'lodash/get'; import React from 'react'; -import RNFastImage from 'react-native-fast-image'; +import {ImageRequireSource, ImageURISource} from 'react-native'; +import RNFastImage, {Source} from 'react-native-fast-image'; import {withOnyx} from 'react-native-onyx'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; -import {defaultProps, imagePropTypes} from './imagePropTypes'; import RESIZE_MODES from './resizeModes'; +import {ImageOnyxProps, ImagePropsWithOnyx} from './types'; -const dimensionsCache = new Map(); +const dimensionsCache = new Map(); -function resolveDimensions(key) { +function resolveDimensions(key: string) { return dimensionsCache.get(key); } -function Image(props) { +function Image(props: ImagePropsWithOnyx) { // eslint-disable-next-line react/destructuring-assignment const {source, isAuthTokenRequired, session, ...rest} = props; - let imageSource = source; - if (source && source.uri && typeof source.uri === 'number') { + let imageSource: Omit | ImageRequireSource | Source = source; + if (typeof source !== 'number' && typeof source.uri === 'number') { imageSource = source.uri; } - if (typeof imageSource !== 'number' && isAuthTokenRequired) { - const authToken = lodashGet(props, 'session.encryptedAuthToken', null); + if (typeof source !== 'number' && isAuthTokenRequired) { + const authToken = props.session?.encryptedAuthToken ?? null; imageSource = { ...source, headers: authToken ? { [CONST.CHAT_ATTACHMENT_TOKEN_KEY]: authToken, } - : null, + : undefined, }; } @@ -39,6 +39,9 @@ function Image(props) { {...rest} source={imageSource} onLoad={(evt) => { + if (typeof source === 'number' || !source.uri) { + return; + } const {width, height} = evt.nativeEvent; dimensionsCache.set(source.uri, {width, height}); if (props.onLoad) { @@ -49,15 +52,14 @@ function Image(props) { ); } -Image.propTypes = imagePropTypes; -Image.defaultProps = defaultProps; Image.displayName = 'Image'; -const ImageWithOnyx = withOnyx({ +Image.resizeMode = RESIZE_MODES; +Image.resolveDimensions = resolveDimensions; + +const ImageWithOnyx = withOnyx({ session: { key: ONYXKEYS.SESSION, }, })(Image); -ImageWithOnyx.resizeMode = RESIZE_MODES; -ImageWithOnyx.resolveDimensions = resolveDimensions; export default ImageWithOnyx; diff --git a/src/components/Image/types.ts b/src/components/Image/types.ts index e89fc81125cf..d2cd31a75f0d 100644 --- a/src/components/Image/types.ts +++ b/src/components/Image/types.ts @@ -1,5 +1,5 @@ import {ImageRequireSource, ImageResizeMode, ImageStyle, ImageURISource, StyleProp} from 'react-native'; -import {OnLoadEvent} from 'react-native-fast-image'; +import {ImageStyle as FastImageStyle, OnLoadEvent, ResizeMode, Source} from 'react-native-fast-image'; import {OnyxEntry} from 'react-native-onyx'; import {Session} from '@src/types/onyx'; @@ -11,16 +11,16 @@ type ImageOnyxProps = { type ImageProps = { /** Styles for the Image */ - style?: StyleProp; + style?: StyleProp; /** The static asset or URI source of the image */ - source: ImageURISource | ImageRequireSource; + source: Omit | ImageRequireSource | Omit; /** Should an auth token be included in the image request */ isAuthTokenRequired: boolean; /** How should the image fit within its container */ - resizeMode: ImageResizeMode; + resizeMode: ImageResizeMode & ResizeMode; /** Event for when the image begins loading */ onLoadStart: () => void; From ed90b35e0d51391264838b3df499b25ddce1b3be Mon Sep 17 00:00:00 2001 From: Julian Kobrynski Date: Tue, 14 Nov 2023 10:36:06 +0100 Subject: [PATCH 05/34] remove unnecessary js files --- src/components/Image/imagePropTypes.js | 51 ------------------- src/components/Image/sourcePropTypes/index.js | 11 ---- .../Image/sourcePropTypes/index.native.js | 10 ---- 3 files changed, 72 deletions(-) delete mode 100644 src/components/Image/imagePropTypes.js delete mode 100644 src/components/Image/sourcePropTypes/index.js delete mode 100644 src/components/Image/sourcePropTypes/index.native.js diff --git a/src/components/Image/imagePropTypes.js b/src/components/Image/imagePropTypes.js deleted file mode 100644 index 78bd48ba47ec..000000000000 --- a/src/components/Image/imagePropTypes.js +++ /dev/null @@ -1,51 +0,0 @@ -import PropTypes from 'prop-types'; -import stylePropTypes from '@styles/stylePropTypes'; -import RESIZE_MODES from './resizeModes'; -import sourcePropTypes from './sourcePropTypes'; - -const imagePropTypes = { - /** Styles for the Image */ - style: stylePropTypes, - - /** The static asset or URI source of the image */ - source: sourcePropTypes.isRequired, - - /** Should an auth token be included in the image request */ - isAuthTokenRequired: PropTypes.bool, - - /** How should the image fit within its container */ - resizeMode: PropTypes.string, - - /** Event for when the image begins loading */ - onLoadStart: PropTypes.func, - - /** Event for when the image finishes loading */ - onLoadEnd: PropTypes.func, - - /** Event for when the image is fully loaded and returns the natural dimensions of the image */ - onLoad: PropTypes.func, - - /** Progress events while the image is downloading */ - onProgress: PropTypes.func, - - /* Onyx Props */ - /** Session info for the currently logged in user. */ - session: PropTypes.shape({ - /** Currently logged in user authToken */ - authToken: PropTypes.string, - }), -}; - -const defaultProps = { - style: [], - session: { - authToken: null, - }, - isAuthTokenRequired: false, - resizeMode: RESIZE_MODES.cover, - onLoadStart: () => {}, - onLoadEnd: () => {}, - onLoad: () => {}, -}; - -export {imagePropTypes, defaultProps}; diff --git a/src/components/Image/sourcePropTypes/index.js b/src/components/Image/sourcePropTypes/index.js deleted file mode 100644 index 99e88b5cf343..000000000000 --- a/src/components/Image/sourcePropTypes/index.js +++ /dev/null @@ -1,11 +0,0 @@ -import PropTypes from 'prop-types'; - -export default PropTypes.oneOfType([ - PropTypes.number, - PropTypes.shape({ - uri: PropTypes.string.isRequired, - // eslint-disable-next-line react/forbid-prop-types - headers: PropTypes.object, - }), - PropTypes.string, -]); diff --git a/src/components/Image/sourcePropTypes/index.native.js b/src/components/Image/sourcePropTypes/index.native.js deleted file mode 100644 index 629b21852613..000000000000 --- a/src/components/Image/sourcePropTypes/index.native.js +++ /dev/null @@ -1,10 +0,0 @@ -import PropTypes from 'prop-types'; - -export default PropTypes.oneOfType([ - PropTypes.number, - PropTypes.shape({ - uri: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired, - // eslint-disable-next-line react/forbid-prop-types - headers: PropTypes.object, - }), -]); From c1d0c2c6885960897ed7e9c547a11262b5347271 Mon Sep 17 00:00:00 2001 From: Julian Kobrynski Date: Tue, 14 Nov 2023 10:37:14 +0100 Subject: [PATCH 06/34] extract map type --- src/components/Image/index.native.tsx | 4 ++-- src/components/Image/types.ts | 7 ++++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/components/Image/index.native.tsx b/src/components/Image/index.native.tsx index 0acf57d099a9..b9c36c7d1b9e 100644 --- a/src/components/Image/index.native.tsx +++ b/src/components/Image/index.native.tsx @@ -5,9 +5,9 @@ import {withOnyx} from 'react-native-onyx'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import RESIZE_MODES from './resizeModes'; -import {ImageOnyxProps, ImagePropsWithOnyx} from './types'; +import {DimensionsCacheValue, ImageOnyxProps, ImagePropsWithOnyx} from './types'; -const dimensionsCache = new Map(); +const dimensionsCache = new Map(); function resolveDimensions(key: string) { return dimensionsCache.get(key); diff --git a/src/components/Image/types.ts b/src/components/Image/types.ts index d2cd31a75f0d..5c46e25e8d12 100644 --- a/src/components/Image/types.ts +++ b/src/components/Image/types.ts @@ -37,4 +37,9 @@ type ImageProps = { type ImagePropsWithOnyx = ImageOnyxProps & ImageProps; -export type {ImageProps, ImageOnyxProps, ImagePropsWithOnyx}; +type DimensionsCacheValue = { + width: number; + height: number; +}; + +export type {ImageProps, ImageOnyxProps, ImagePropsWithOnyx, DimensionsCacheValue}; From 46c9f9269ce4d3988677757256b2da53fc0586d6 Mon Sep 17 00:00:00 2001 From: Julian Kobrynski Date: Tue, 14 Nov 2023 11:17:21 +0100 Subject: [PATCH 07/34] bring back optional props --- src/components/Image/types.ts | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/components/Image/types.ts b/src/components/Image/types.ts index 5c46e25e8d12..d91345b1690d 100644 --- a/src/components/Image/types.ts +++ b/src/components/Image/types.ts @@ -17,22 +17,25 @@ type ImageProps = { source: Omit | ImageRequireSource | Omit; /** Should an auth token be included in the image request */ - isAuthTokenRequired: boolean; + isAuthTokenRequired?: boolean; /** How should the image fit within its container */ - resizeMode: ImageResizeMode & ResizeMode; + resizeMode?: ImageResizeMode & ResizeMode; /** Event for when the image begins loading */ - onLoadStart: () => void; + onLoadStart?: () => void; /** Event for when the image finishes loading */ - onLoadEnd: () => void; + onLoadEnd?: () => void; + + /** Error handler */ + onError?: () => void; /** Event for when the image is fully loaded and returns the natural dimensions of the image */ - onLoad: (event: OnLoadEvent) => void; + onLoad?: (event: OnLoadEvent) => void; /** Progress events while the image is downloading */ - onProgress: () => void; + onProgress?: () => void; }; type ImagePropsWithOnyx = ImageOnyxProps & ImageProps; From 0041ba83f1011b334256e2313b9d6e75205ff1eb Mon Sep 17 00:00:00 2001 From: Julian Kobrynski Date: Tue, 14 Nov 2023 12:16:36 +0100 Subject: [PATCH 08/34] destructure props, add return types --- src/components/Image/index.native.tsx | 13 +++++-------- src/components/Image/index.tsx | 3 +-- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/src/components/Image/index.native.tsx b/src/components/Image/index.native.tsx index b9c36c7d1b9e..2196eaa17631 100644 --- a/src/components/Image/index.native.tsx +++ b/src/components/Image/index.native.tsx @@ -9,20 +9,17 @@ import {DimensionsCacheValue, ImageOnyxProps, ImagePropsWithOnyx} from './types' const dimensionsCache = new Map(); -function resolveDimensions(key: string) { +function resolveDimensions(key: string): DimensionsCacheValue | undefined { return dimensionsCache.get(key); } -function Image(props: ImagePropsWithOnyx) { - // eslint-disable-next-line react/destructuring-assignment - const {source, isAuthTokenRequired, session, ...rest} = props; - +function Image({source, isAuthTokenRequired, session, ...rest}: ImagePropsWithOnyx) { let imageSource: Omit | ImageRequireSource | Source = source; if (typeof source !== 'number' && typeof source.uri === 'number') { imageSource = source.uri; } if (typeof source !== 'number' && isAuthTokenRequired) { - const authToken = props.session?.encryptedAuthToken ?? null; + const authToken = session?.encryptedAuthToken ?? null; imageSource = { ...source, headers: authToken @@ -44,8 +41,8 @@ function Image(props: ImagePropsWithOnyx) { } const {width, height} = evt.nativeEvent; dimensionsCache.set(source.uri, {width, height}); - if (props.onLoad) { - props.onLoad(evt); + if (rest.onLoad) { + rest.onLoad(evt); } }} /> diff --git a/src/components/Image/index.tsx b/src/components/Image/index.tsx index d161d89dcbdb..9da6020f7fb9 100644 --- a/src/components/Image/index.tsx +++ b/src/components/Image/index.tsx @@ -5,8 +5,7 @@ import ONYXKEYS from '@src/ONYXKEYS'; import RESIZE_MODES from './resizeModes'; import {ImageOnyxProps, ImageProps, ImagePropsWithOnyx} from './types'; -function Image(props: ImagePropsWithOnyx) { - const {source: propsSource, isAuthTokenRequired, onLoad, session, ...forwardedProps} = props; +function Image({source: propsSource, isAuthTokenRequired, onLoad, session, ...forwardedProps}: ImagePropsWithOnyx) { /** * Check if the image source is a URL - if so the `encryptedAuthToken` is appended * to the source. From b44660936a731c44db6b9ac173e5169d6bef5fba Mon Sep 17 00:00:00 2001 From: Julian Kobrynski Date: Wed, 15 Nov 2023 08:43:43 +0100 Subject: [PATCH 09/34] extract source type, improve if statements --- src/components/Image/index.native.tsx | 7 +++---- src/components/Image/index.tsx | 6 +++--- src/components/Image/types.ts | 4 +++- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/components/Image/index.native.tsx b/src/components/Image/index.native.tsx index 2196eaa17631..70be8f9f995e 100644 --- a/src/components/Image/index.native.tsx +++ b/src/components/Image/index.native.tsx @@ -1,11 +1,10 @@ import React from 'react'; -import {ImageRequireSource, ImageURISource} from 'react-native'; -import RNFastImage, {Source} from 'react-native-fast-image'; +import RNFastImage from 'react-native-fast-image'; import {withOnyx} from 'react-native-onyx'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import RESIZE_MODES from './resizeModes'; -import {DimensionsCacheValue, ImageOnyxProps, ImagePropsWithOnyx} from './types'; +import {DimensionsCacheValue, FastImageSource, ImageOnyxProps, ImagePropsWithOnyx} from './types'; const dimensionsCache = new Map(); @@ -14,7 +13,7 @@ function resolveDimensions(key: string): DimensionsCacheValue | undefined { } function Image({source, isAuthTokenRequired, session, ...rest}: ImagePropsWithOnyx) { - let imageSource: Omit | ImageRequireSource | Source = source; + let imageSource: FastImageSource = source; if (typeof source !== 'number' && typeof source.uri === 'number') { imageSource = source.uri; } diff --git a/src/components/Image/index.tsx b/src/components/Image/index.tsx index 9da6020f7fb9..61a11e31f163 100644 --- a/src/components/Image/index.tsx +++ b/src/components/Image/index.tsx @@ -16,8 +16,8 @@ function Image({source: propsSource, isAuthTokenRequired, onLoad, session, ...fo // On native the authToken IS passed in the image request headers const authToken = session?.encryptedAuthToken ?? null; - if (isAuthTokenRequired && authToken && typeof propsSource !== 'number') { - return {uri: `${propsSource?.uri}?encryptedAuthToken=${encodeURIComponent(authToken)}`}; + if (isAuthTokenRequired && authToken && typeof propsSource !== 'number' && propsSource.uri) { + return {uri: `${propsSource.uri}?encryptedAuthToken=${encodeURIComponent(authToken)}`}; } return propsSource; // The session prop is not required, as it causes the image to reload whenever the session changes. For more information, please refer to issue #26034. @@ -31,7 +31,7 @@ function Image({source: propsSource, isAuthTokenRequired, onLoad, session, ...fo useEffect(() => { // If an onLoad callback was specified then manually call it and pass // the natural image dimensions to match the native API - if (onLoad == null || typeof source === 'number' || !source.uri) { + if (typeof onLoad !== 'function' || typeof source === 'number' || !source.uri) { return; } RNImage.getSize(source.uri, (width, height) => { diff --git a/src/components/Image/types.ts b/src/components/Image/types.ts index d91345b1690d..3edf97b15e71 100644 --- a/src/components/Image/types.ts +++ b/src/components/Image/types.ts @@ -45,4 +45,6 @@ type DimensionsCacheValue = { height: number; }; -export type {ImageProps, ImageOnyxProps, ImagePropsWithOnyx, DimensionsCacheValue}; +type FastImageSource = Omit | ImageRequireSource | Source; + +export type {ImageProps, ImageOnyxProps, ImagePropsWithOnyx, DimensionsCacheValue, FastImageSource}; From 21c79807f87386247df859426101a6ff56ef357a Mon Sep 17 00:00:00 2001 From: Julian Kobrynski Date: Wed, 15 Nov 2023 12:48:51 +0100 Subject: [PATCH 10/34] change Image prop types names --- src/components/Image/index.native.tsx | 6 +++--- src/components/Image/index.tsx | 8 ++++---- src/components/Image/types.ts | 6 +++--- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/components/Image/index.native.tsx b/src/components/Image/index.native.tsx index 70be8f9f995e..d75b768b27b6 100644 --- a/src/components/Image/index.native.tsx +++ b/src/components/Image/index.native.tsx @@ -4,7 +4,7 @@ import {withOnyx} from 'react-native-onyx'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import RESIZE_MODES from './resizeModes'; -import {DimensionsCacheValue, FastImageSource, ImageOnyxProps, ImagePropsWithOnyx} from './types'; +import {DimensionsCacheValue, FastImageSource, ImageOnyxProps, ImageProps} from './types'; const dimensionsCache = new Map(); @@ -12,7 +12,7 @@ function resolveDimensions(key: string): DimensionsCacheValue | undefined { return dimensionsCache.get(key); } -function Image({source, isAuthTokenRequired, session, ...rest}: ImagePropsWithOnyx) { +function Image({source, isAuthTokenRequired, session, ...rest}: ImageProps) { let imageSource: FastImageSource = source; if (typeof source !== 'number' && typeof source.uri === 'number') { imageSource = source.uri; @@ -52,7 +52,7 @@ Image.displayName = 'Image'; Image.resizeMode = RESIZE_MODES; Image.resolveDimensions = resolveDimensions; -const ImageWithOnyx = withOnyx({ +const ImageWithOnyx = withOnyx({ session: { key: ONYXKEYS.SESSION, }, diff --git a/src/components/Image/index.tsx b/src/components/Image/index.tsx index 61a11e31f163..ecf1d8fb504c 100644 --- a/src/components/Image/index.tsx +++ b/src/components/Image/index.tsx @@ -3,9 +3,9 @@ import {Image as RNImage} from 'react-native'; import {withOnyx} from 'react-native-onyx'; import ONYXKEYS from '@src/ONYXKEYS'; import RESIZE_MODES from './resizeModes'; -import {ImageOnyxProps, ImageProps, ImagePropsWithOnyx} from './types'; +import {ImageOnyxProps, ImageOwnProps, ImageProps} from './types'; -function Image({source: propsSource, isAuthTokenRequired, onLoad, session, ...forwardedProps}: ImagePropsWithOnyx) { +function Image({source: propsSource, isAuthTokenRequired, onLoad, session, ...forwardedProps}: ImageProps) { /** * Check if the image source is a URL - if so the `encryptedAuthToken` is appended * to the source. @@ -48,7 +48,7 @@ function Image({source: propsSource, isAuthTokenRequired, onLoad, session, ...fo ); } -function imagePropsAreEqual(prevProps: ImageProps, nextProps: ImageProps) { +function imagePropsAreEqual(prevProps: ImageOwnProps, nextProps: ImageOwnProps) { return prevProps.source === nextProps.source; } @@ -56,7 +56,7 @@ Image.resizeMode = RESIZE_MODES; Image.displayName = 'Image'; const ImageWithOnyx = React.memo( - withOnyx({ + withOnyx({ session: { key: ONYXKEYS.SESSION, }, diff --git a/src/components/Image/types.ts b/src/components/Image/types.ts index 3edf97b15e71..2ddf3975af8c 100644 --- a/src/components/Image/types.ts +++ b/src/components/Image/types.ts @@ -9,7 +9,7 @@ type ImageOnyxProps = { session: OnyxEntry; }; -type ImageProps = { +type ImageOwnProps = { /** Styles for the Image */ style?: StyleProp; @@ -38,7 +38,7 @@ type ImageProps = { onProgress?: () => void; }; -type ImagePropsWithOnyx = ImageOnyxProps & ImageProps; +type ImageProps = ImageOnyxProps & ImageOwnProps; type DimensionsCacheValue = { width: number; @@ -47,4 +47,4 @@ type DimensionsCacheValue = { type FastImageSource = Omit | ImageRequireSource | Source; -export type {ImageProps, ImageOnyxProps, ImagePropsWithOnyx, DimensionsCacheValue, FastImageSource}; +export type {ImageOwnProps, ImageOnyxProps, ImageProps, DimensionsCacheValue, FastImageSource}; From f11591421b72221fa191c0b6311898d417161751 Mon Sep 17 00:00:00 2001 From: Julian Kobrynski Date: Wed, 15 Nov 2023 13:41:31 +0100 Subject: [PATCH 11/34] bring back imageSource to if statement --- src/components/Image/index.native.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Image/index.native.tsx b/src/components/Image/index.native.tsx index d75b768b27b6..981b8c1eaf2e 100644 --- a/src/components/Image/index.native.tsx +++ b/src/components/Image/index.native.tsx @@ -17,7 +17,7 @@ function Image({source, isAuthTokenRequired, session, ...rest}: ImageProps) { if (typeof source !== 'number' && typeof source.uri === 'number') { imageSource = source.uri; } - if (typeof source !== 'number' && isAuthTokenRequired) { + if (typeof imageSource !== 'number' && typeof source !== 'number' && isAuthTokenRequired) { const authToken = session?.encryptedAuthToken ?? null; imageSource = { ...source, From e2508f9d16c1a8e0627d8a4cf514d53fffcb59a2 Mon Sep 17 00:00:00 2001 From: Julian Kobrynski Date: Fri, 17 Nov 2023 08:24:17 +0100 Subject: [PATCH 12/34] remove resolveDimensions from native Image --- src/components/Image/index.native.tsx | 18 ++---------------- src/components/Image/types.ts | 7 +------ 2 files changed, 3 insertions(+), 22 deletions(-) diff --git a/src/components/Image/index.native.tsx b/src/components/Image/index.native.tsx index 981b8c1eaf2e..02127c4ae63d 100644 --- a/src/components/Image/index.native.tsx +++ b/src/components/Image/index.native.tsx @@ -4,13 +4,7 @@ import {withOnyx} from 'react-native-onyx'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import RESIZE_MODES from './resizeModes'; -import {DimensionsCacheValue, FastImageSource, ImageOnyxProps, ImageProps} from './types'; - -const dimensionsCache = new Map(); - -function resolveDimensions(key: string): DimensionsCacheValue | undefined { - return dimensionsCache.get(key); -} +import {FastImageSource, ImageOnyxProps, ImageProps} from './types'; function Image({source, isAuthTokenRequired, session, ...rest}: ImageProps) { let imageSource: FastImageSource = source; @@ -35,14 +29,7 @@ function Image({source, isAuthTokenRequired, session, ...rest}: ImageProps) { {...rest} source={imageSource} onLoad={(evt) => { - if (typeof source === 'number' || !source.uri) { - return; - } - const {width, height} = evt.nativeEvent; - dimensionsCache.set(source.uri, {width, height}); - if (rest.onLoad) { - rest.onLoad(evt); - } + rest.onLoad?.(evt); }} /> ); @@ -50,7 +37,6 @@ function Image({source, isAuthTokenRequired, session, ...rest}: ImageProps) { Image.displayName = 'Image'; Image.resizeMode = RESIZE_MODES; -Image.resolveDimensions = resolveDimensions; const ImageWithOnyx = withOnyx({ session: { diff --git a/src/components/Image/types.ts b/src/components/Image/types.ts index 2ddf3975af8c..60479e9dee50 100644 --- a/src/components/Image/types.ts +++ b/src/components/Image/types.ts @@ -40,11 +40,6 @@ type ImageOwnProps = { type ImageProps = ImageOnyxProps & ImageOwnProps; -type DimensionsCacheValue = { - width: number; - height: number; -}; - type FastImageSource = Omit | ImageRequireSource | Source; -export type {ImageOwnProps, ImageOnyxProps, ImageProps, DimensionsCacheValue, FastImageSource}; +export type {ImageOwnProps, ImageOnyxProps, ImageProps, FastImageSource}; From 3f260bc6d9407a3ecbc7b661f419e65a17280698 Mon Sep 17 00:00:00 2001 From: Julian Kobrynski Date: Fri, 17 Nov 2023 08:40:04 +0100 Subject: [PATCH 13/34] remove references to Image.resizeModes --- src/components/ImageView/index.js | 3 ++- src/components/ImageView/index.native.js | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/components/ImageView/index.js b/src/components/ImageView/index.js index a733466e1ae2..8da3f9ca4770 100644 --- a/src/components/ImageView/index.js +++ b/src/components/ImageView/index.js @@ -3,6 +3,7 @@ import React, {useCallback, useEffect, useRef, useState} from 'react'; import {View} from 'react-native'; import FullscreenLoadingIndicator from '@components/FullscreenLoadingIndicator'; import Image from '@components/Image'; +import RESIZE_MODES from '@components/Image/resizeModes'; import PressableWithoutFeedback from '@components/Pressable/PressableWithoutFeedback'; import * as DeviceCapabilities from '@libs/DeviceCapabilities'; import styles from '@styles/styles'; @@ -238,7 +239,7 @@ function ImageView({isAuthTokenRequired, url, fileName, onError}) { style={isLoading || zoomScale === 0 ? undefined : [styles.w100, styles.h100]} // When Image dimensions are lower than the container boundary(zoomscale <= 1), use `contain` to render the image with natural dimensions. // Both `center` and `contain` keeps the image centered on both x and y axis. - resizeMode={zoomScale > 1 ? Image.resizeMode.center : Image.resizeMode.contain} + resizeMode={zoomScale > 1 ? RESIZE_MODES.center : RESIZE_MODES.contain} onLoadStart={imageLoadingStart} onLoad={imageLoad} onError={onError} diff --git a/src/components/ImageView/index.native.js b/src/components/ImageView/index.native.js index dd17e2d27a4e..d8124f30cde9 100644 --- a/src/components/ImageView/index.native.js +++ b/src/components/ImageView/index.native.js @@ -5,6 +5,7 @@ import ImageZoom from 'react-native-image-pan-zoom'; import _ from 'underscore'; import FullscreenLoadingIndicator from '@components/FullscreenLoadingIndicator'; import Image from '@components/Image'; +import RESIZE_MODES from '@components/Image/resizeModes'; import useWindowDimensions from '@hooks/useWindowDimensions'; import styles from '@styles/styles'; import variables from '@styles/variables'; @@ -218,7 +219,7 @@ function ImageView({isAuthTokenRequired, url, onScaleChanged, onPress, style}) { ]} source={{uri: url}} isAuthTokenRequired={isAuthTokenRequired} - resizeMode={Image.resizeMode.contain} + resizeMode={RESIZE_MODES.contain} onLoadStart={imageLoadingStart} onLoad={configureImageZoom} /> From 3a76fb01e498973e4ef358670c60b7efcc181637 Mon Sep 17 00:00:00 2001 From: Julian Kobrynski Date: Mon, 20 Nov 2023 12:36:51 +0100 Subject: [PATCH 14/34] remove RESIZE_MODES from Image --- src/components/Image/index.native.tsx | 6 ++---- src/components/Image/index.tsx | 6 ++---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/components/Image/index.native.tsx b/src/components/Image/index.native.tsx index 02127c4ae63d..1d2d33501644 100644 --- a/src/components/Image/index.native.tsx +++ b/src/components/Image/index.native.tsx @@ -3,7 +3,6 @@ import RNFastImage from 'react-native-fast-image'; import {withOnyx} from 'react-native-onyx'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; -import RESIZE_MODES from './resizeModes'; import {FastImageSource, ImageOnyxProps, ImageProps} from './types'; function Image({source, isAuthTokenRequired, session, ...rest}: ImageProps) { @@ -35,13 +34,12 @@ function Image({source, isAuthTokenRequired, session, ...rest}: ImageProps) { ); } -Image.displayName = 'Image'; -Image.resizeMode = RESIZE_MODES; - const ImageWithOnyx = withOnyx({ session: { key: ONYXKEYS.SESSION, }, })(Image); +ImageWithOnyx.displayName = 'Image'; + export default ImageWithOnyx; diff --git a/src/components/Image/index.tsx b/src/components/Image/index.tsx index ecf1d8fb504c..0d867c831919 100644 --- a/src/components/Image/index.tsx +++ b/src/components/Image/index.tsx @@ -2,7 +2,6 @@ import React, {useEffect, useMemo} from 'react'; import {Image as RNImage} from 'react-native'; import {withOnyx} from 'react-native-onyx'; import ONYXKEYS from '@src/ONYXKEYS'; -import RESIZE_MODES from './resizeModes'; import {ImageOnyxProps, ImageOwnProps, ImageProps} from './types'; function Image({source: propsSource, isAuthTokenRequired, onLoad, session, ...forwardedProps}: ImageProps) { @@ -52,9 +51,6 @@ function imagePropsAreEqual(prevProps: ImageOwnProps, nextProps: ImageOwnProps) return prevProps.source === nextProps.source; } -Image.resizeMode = RESIZE_MODES; -Image.displayName = 'Image'; - const ImageWithOnyx = React.memo( withOnyx({ session: { @@ -64,4 +60,6 @@ const ImageWithOnyx = React.memo( imagePropsAreEqual, ); +ImageWithOnyx.displayName = 'Image'; + export default ImageWithOnyx; From 02daaf589d85faac1b8a7a67fdd983f7c78a5405 Mon Sep 17 00:00:00 2001 From: Julian Kobrynski Date: Mon, 27 Nov 2023 11:26:57 +0100 Subject: [PATCH 15/34] remove unnecessary comment --- src/components/Image/types.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/Image/types.ts b/src/components/Image/types.ts index 60479e9dee50..9f49ea16f076 100644 --- a/src/components/Image/types.ts +++ b/src/components/Image/types.ts @@ -4,7 +4,6 @@ import {OnyxEntry} from 'react-native-onyx'; import {Session} from '@src/types/onyx'; type ImageOnyxProps = { - /* Onyx Props */ /** Session info for the currently logged in user. */ session: OnyxEntry; }; From 0e11fb813a21955b81a8aa0f21bce1abed463834 Mon Sep 17 00:00:00 2001 From: Julian Kobrynski Date: Mon, 27 Nov 2023 11:41:23 +0100 Subject: [PATCH 16/34] remove Image.resizeMode --- src/components/ImageView/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/ImageView/index.js b/src/components/ImageView/index.js index e2a76bf2a1f8..b96222a17c7c 100644 --- a/src/components/ImageView/index.js +++ b/src/components/ImageView/index.js @@ -271,7 +271,7 @@ function ImageView({isAuthTokenRequired, url, fileName, onError}) { source={{uri: url}} isAuthTokenRequired={isAuthTokenRequired} style={[styles.h100, styles.w100]} - resizeMode={Image.resizeMode.contain} + resizeMode={RESIZE_MODES.contain} onLoadStart={imageLoadingStart} onLoad={imageLoad} onError={onError} From 06c374c064ad50e7d75918b3c0972b9279b20da9 Mon Sep 17 00:00:00 2001 From: Julian Kobrynski Date: Mon, 15 Jan 2024 15:49:33 +0100 Subject: [PATCH 17/34] adjust types to expo-image --- src/components/Image/index.native.tsx | 4 ++-- src/components/Image/index.tsx | 7 ++++--- src/components/Image/types.ts | 10 +++++----- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/components/Image/index.native.tsx b/src/components/Image/index.native.tsx index 50451c20d5d3..27f00adbb2ce 100644 --- a/src/components/Image/index.native.tsx +++ b/src/components/Image/index.native.tsx @@ -3,7 +3,7 @@ import React from 'react'; import {withOnyx} from 'react-native-onyx'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; -import type {ImageOnyxProps, ImageProps, ImageSource} from './types'; +import type {ExpoImageSource, ImageOnyxProps, ImageProps} from './types'; const dimensionsCache = new Map(); @@ -11,7 +11,7 @@ function Image(props: ImageProps) { // eslint-disable-next-line react/destructuring-assignment const {source, isAuthTokenRequired, session, ...rest} = props; - let imageSource: ImageSource = source; + let imageSource: ExpoImageSource = source; if (source && typeof source === 'object' && 'uri' in source && typeof source.uri === 'number') { imageSource = source.uri; } diff --git a/src/components/Image/index.tsx b/src/components/Image/index.tsx index 0d867c831919..930cb89dee74 100644 --- a/src/components/Image/index.tsx +++ b/src/components/Image/index.tsx @@ -2,7 +2,7 @@ import React, {useEffect, useMemo} from 'react'; import {Image as RNImage} from 'react-native'; import {withOnyx} from 'react-native-onyx'; import ONYXKEYS from '@src/ONYXKEYS'; -import {ImageOnyxProps, ImageOwnProps, ImageProps} from './types'; +import type {ImageOnyxProps, ImageOwnProps, ImageProps} from './types'; function Image({source: propsSource, isAuthTokenRequired, onLoad, session, ...forwardedProps}: ImageProps) { /** @@ -15,7 +15,7 @@ function Image({source: propsSource, isAuthTokenRequired, onLoad, session, ...fo // On native the authToken IS passed in the image request headers const authToken = session?.encryptedAuthToken ?? null; - if (isAuthTokenRequired && authToken && typeof propsSource !== 'number' && propsSource.uri) { + if (isAuthTokenRequired && authToken && typeof propsSource === 'object' && propsSource && 'uri' in propsSource) { return {uri: `${propsSource.uri}?encryptedAuthToken=${encodeURIComponent(authToken)}`}; } return propsSource; @@ -30,9 +30,10 @@ function Image({source: propsSource, isAuthTokenRequired, onLoad, session, ...fo useEffect(() => { // If an onLoad callback was specified then manually call it and pass // the natural image dimensions to match the native API - if (typeof onLoad !== 'function' || typeof source === 'number' || !source.uri) { + if (typeof onLoad !== 'function' || !source || typeof source !== 'object' || !('uri' in source) || !source?.uri) { return; } + RNImage.getSize(source.uri, (width, height) => { onLoad({nativeEvent: {width, height}}); }); diff --git a/src/components/Image/types.ts b/src/components/Image/types.ts index e792a0c22c6f..e194a545aec4 100644 --- a/src/components/Image/types.ts +++ b/src/components/Image/types.ts @@ -1,9 +1,9 @@ -import type {ImageSource as ExpoImageSource} from 'expo-image'; -import type {ImageResizeMode, ImageStyle, StyleProp} from 'react-native'; +import type {ImageSource} from 'expo-image'; +import type {ImageRequireSource, ImageResizeMode, ImageStyle, ImageURISource, StyleProp} from 'react-native'; import type {OnyxEntry} from 'react-native-onyx'; import type {Session} from '@src/types/onyx'; -type ImageSource = ExpoImageSource | string | number | ExpoImageSource[] | string[] | null; +type ExpoImageSource = ImageSource | string | number | ImageSource[] | string[] | null; type ImageOnyxProps = { /** Session info for the currently logged in user. */ @@ -15,7 +15,7 @@ type ImageOwnProps = { style?: StyleProp; /** The static asset or URI source of the image */ - source: ImageSource; + source: ExpoImageSource | Omit | ImageRequireSource; /** Should an auth token be included in the image request */ isAuthTokenRequired?: boolean; @@ -46,4 +46,4 @@ type ImageOwnProps = { type ImageProps = ImageOnyxProps & ImageOwnProps; -export type {ImageOwnProps, ImageOnyxProps, ImageProps, ImageSource}; +export type {ImageOwnProps, ImageOnyxProps, ImageProps, ExpoImageSource}; From e9451f09734ab8bbea510e36e6104db64b33c064 Mon Sep 17 00:00:00 2001 From: Julian Kobrynski Date: Tue, 16 Jan 2024 15:53:12 +0100 Subject: [PATCH 18/34] fix source type --- src/components/Image/types.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/Image/types.ts b/src/components/Image/types.ts index e194a545aec4..ba351b8031af 100644 --- a/src/components/Image/types.ts +++ b/src/components/Image/types.ts @@ -3,7 +3,8 @@ import type {ImageRequireSource, ImageResizeMode, ImageStyle, ImageURISource, St import type {OnyxEntry} from 'react-native-onyx'; import type {Session} from '@src/types/onyx'; -type ExpoImageSource = ImageSource | string | number | ImageSource[] | string[] | null; +// type ExpoImageSource = ImageSource | string | number | ImageSource[] | string[] | null; +type ExpoImageSource = ImageSource | number | ImageSource[]; type ImageOnyxProps = { /** Session info for the currently logged in user. */ From ee813605c7b3516633c146118e7b891d5892dd41 Mon Sep 17 00:00:00 2001 From: Julian Kobrynski Date: Thu, 18 Jan 2024 15:14:36 +0100 Subject: [PATCH 19/34] bring back sourcePropTypes directory --- src/components/Avatar.tsx | 4 ++-- src/components/Image/sourcePropTypes/index.js | 13 +++++++++++++ .../Image/sourcePropTypes/index.native.js | 12 ++++++++++++ 3 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 src/components/Image/sourcePropTypes/index.js create mode 100644 src/components/Image/sourcePropTypes/index.native.js diff --git a/src/components/Avatar.tsx b/src/components/Avatar.tsx index 4da91c2e7d19..6b4e2cc2eb4d 100644 --- a/src/components/Avatar.tsx +++ b/src/components/Avatar.tsx @@ -1,5 +1,5 @@ import React, {useEffect, useState} from 'react'; -import type {StyleProp, ViewStyle} from 'react-native'; +import type {ImageStyle, StyleProp, ViewStyle} from 'react-native'; import {View} from 'react-native'; import useNetwork from '@hooks/useNetwork'; import useStyleUtils from '@hooks/useStyleUtils'; @@ -112,7 +112,7 @@ function Avatar({ } onError={() => setImageError(true)} /> diff --git a/src/components/Image/sourcePropTypes/index.js b/src/components/Image/sourcePropTypes/index.js new file mode 100644 index 000000000000..c5102b240cb1 --- /dev/null +++ b/src/components/Image/sourcePropTypes/index.js @@ -0,0 +1,13 @@ +import PropTypes from 'prop-types'; + +export default PropTypes.oneOfType([ + PropTypes.func, + PropTypes.elementType, + PropTypes.number, + PropTypes.shape({ + uri: PropTypes.string, + // eslint-disable-next-line react/forbid-prop-types + headers: PropTypes.object, + }), + PropTypes.string, +]); diff --git a/src/components/Image/sourcePropTypes/index.native.js b/src/components/Image/sourcePropTypes/index.native.js new file mode 100644 index 000000000000..ade254718879 --- /dev/null +++ b/src/components/Image/sourcePropTypes/index.native.js @@ -0,0 +1,12 @@ +import PropTypes from 'prop-types'; + +export default PropTypes.oneOfType([ + PropTypes.func, + PropTypes.elementType, + PropTypes.number, + PropTypes.shape({ + uri: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired, + // eslint-disable-next-line react/forbid-prop-types + headers: PropTypes.object, + }), +]); From 9ceb2eb12f72840d86bf68c2b1f3ca5b768d0150 Mon Sep 17 00:00:00 2001 From: Julian Kobrynski Date: Thu, 18 Jan 2024 15:55:02 +0100 Subject: [PATCH 20/34] fix type errors in Avatar.tsx --- src/components/Avatar.tsx | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/components/Avatar.tsx b/src/components/Avatar.tsx index 6b4e2cc2eb4d..23759dbee937 100644 --- a/src/components/Avatar.tsx +++ b/src/components/Avatar.tsx @@ -92,7 +92,15 @@ function Avatar({ return ( - {typeof avatarSource === 'function' || typeof avatarSource === 'number' ? ( + {typeof avatarSource === 'string' ? ( + + } + onError={() => setImageError(true)} + /> + + ) : ( - ) : ( - - } - onError={() => setImageError(true)} - /> - )} ); From 50726c72d5b0e09c4c5b5c692adebde3290323e3 Mon Sep 17 00:00:00 2001 From: Julian Kobrynski Date: Thu, 18 Jan 2024 15:56:33 +0100 Subject: [PATCH 21/34] remove unnecessary comment --- src/components/Image/types.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/Image/types.ts b/src/components/Image/types.ts index ba351b8031af..7e344e608c48 100644 --- a/src/components/Image/types.ts +++ b/src/components/Image/types.ts @@ -3,7 +3,6 @@ import type {ImageRequireSource, ImageResizeMode, ImageStyle, ImageURISource, St import type {OnyxEntry} from 'react-native-onyx'; import type {Session} from '@src/types/onyx'; -// type ExpoImageSource = ImageSource | string | number | ImageSource[] | string[] | null; type ExpoImageSource = ImageSource | number | ImageSource[]; type ImageOnyxProps = { From 4c69801821da6cc897f74d6b4750f9d3c6f2cef8 Mon Sep 17 00:00:00 2001 From: Julian Kobrynski Date: Thu, 18 Jan 2024 16:11:12 +0100 Subject: [PATCH 22/34] simplify source related if statements --- src/components/Image/index.native.tsx | 3 ++- src/components/Image/index.tsx | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/components/Image/index.native.tsx b/src/components/Image/index.native.tsx index 27f00adbb2ce..22466cd938b9 100644 --- a/src/components/Image/index.native.tsx +++ b/src/components/Image/index.native.tsx @@ -12,7 +12,8 @@ function Image(props: ImageProps) { const {source, isAuthTokenRequired, session, ...rest} = props; let imageSource: ExpoImageSource = source; - if (source && typeof source === 'object' && 'uri' in source && typeof source.uri === 'number') { + + if (typeof source === 'object' && 'uri' in source && typeof source.uri === 'number') { imageSource = source.uri; } if (typeof imageSource !== 'number' && isAuthTokenRequired && typeof source === 'object') { diff --git a/src/components/Image/index.tsx b/src/components/Image/index.tsx index 930cb89dee74..2f9cff851438 100644 --- a/src/components/Image/index.tsx +++ b/src/components/Image/index.tsx @@ -15,7 +15,7 @@ function Image({source: propsSource, isAuthTokenRequired, onLoad, session, ...fo // On native the authToken IS passed in the image request headers const authToken = session?.encryptedAuthToken ?? null; - if (isAuthTokenRequired && authToken && typeof propsSource === 'object' && propsSource && 'uri' in propsSource) { + if (isAuthTokenRequired && authToken && typeof propsSource === 'object' && 'uri' in propsSource) { return {uri: `${propsSource.uri}?encryptedAuthToken=${encodeURIComponent(authToken)}`}; } return propsSource; @@ -30,7 +30,7 @@ function Image({source: propsSource, isAuthTokenRequired, onLoad, session, ...fo useEffect(() => { // If an onLoad callback was specified then manually call it and pass // the natural image dimensions to match the native API - if (typeof onLoad !== 'function' || !source || typeof source !== 'object' || !('uri' in source) || !source?.uri) { + if (typeof onLoad !== 'function' || typeof source !== 'object' || !('uri' in source) || !source?.uri) { return; } From 1056c9f3238b95125b27037e64c1e93e334d36c0 Mon Sep 17 00:00:00 2001 From: Julian Kobrynski Date: Mon, 5 Feb 2024 09:59:28 +0100 Subject: [PATCH 23/34] fix headers type issue --- src/components/Image/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Image/index.tsx b/src/components/Image/index.tsx index a74ae33a1764..9ca27cae3a1d 100644 --- a/src/components/Image/index.tsx +++ b/src/components/Image/index.tsx @@ -16,7 +16,7 @@ function Image({source: propsSource, isAuthTokenRequired, session, ...forwardedP return { ...propsSource, headers: { - [CONST.CHAT_ATTACHMENT_TOKEN_KEY]: authToken, + [CONST.CHAT_ATTACHMENT_TOKEN_KEY]: authToken ?? '', }, }; } From 611227e397444a3366b93e099d9df09737e3f972 Mon Sep 17 00:00:00 2001 From: Julian Kobrynski Date: Mon, 5 Feb 2024 15:20:52 +0100 Subject: [PATCH 24/34] migrate index.native.js to TypeScript --- .../{index.native.js => index.native.tsx} | 25 ++++++------------- 1 file changed, 8 insertions(+), 17 deletions(-) rename src/components/Image/{index.native.js => index.native.tsx} (64%) diff --git a/src/components/Image/index.native.js b/src/components/Image/index.native.tsx similarity index 64% rename from src/components/Image/index.native.js rename to src/components/Image/index.native.tsx index f31cfb6936d9..1705f7a2a9fe 100644 --- a/src/components/Image/index.native.js +++ b/src/components/Image/index.native.tsx @@ -1,35 +1,29 @@ import {Image as ImageComponent} from 'expo-image'; -import lodashGet from 'lodash/get'; import React from 'react'; import {withOnyx} from 'react-native-onyx'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; -import {defaultProps, imagePropTypes} from './imagePropTypes'; -import RESIZE_MODES from './resizeModes'; +import type {ImageOnyxProps, ImageProps} from './types'; const dimensionsCache = new Map(); -function resolveDimensions(key) { - return dimensionsCache.get(key); -} - -function Image(props) { +function Image(props: ImageProps) { // eslint-disable-next-line react/destructuring-assignment const {source, isAuthTokenRequired, session, ...rest} = props; let imageSource = source; - if (source && source.uri && typeof source.uri === 'number') { + if (typeof source === 'object' && 'uri' in source && typeof source.uri === 'number') { imageSource = source.uri; } - if (typeof imageSource !== 'number' && isAuthTokenRequired) { - const authToken = lodashGet(props, 'session.encryptedAuthToken', null); + if (typeof imageSource === 'object' && typeof source === 'object' && isAuthTokenRequired) { + const authToken = props.session?.encryptedAuthToken ?? null; imageSource = { ...source, headers: authToken ? { [CONST.CHAT_ATTACHMENT_TOKEN_KEY]: authToken, } - : null, + : undefined, }; } @@ -49,15 +43,12 @@ function Image(props) { ); } -Image.propTypes = imagePropTypes; -Image.defaultProps = defaultProps; Image.displayName = 'Image'; -const ImageWithOnyx = withOnyx({ + +const ImageWithOnyx = withOnyx({ session: { key: ONYXKEYS.SESSION, }, })(Image); -ImageWithOnyx.resizeMode = RESIZE_MODES; -ImageWithOnyx.resolveDimensions = resolveDimensions; export default ImageWithOnyx; From 7b6ce9856624f3b4d053de522db453890d291cfd Mon Sep 17 00:00:00 2001 From: Julian Kobrynski Date: Tue, 6 Feb 2024 09:32:34 +0100 Subject: [PATCH 25/34] fix onLoad method typing --- src/components/Image/types.ts | 24 +++++++++-------------- src/components/ImageView/index.native.tsx | 2 +- src/components/ImageView/index.tsx | 7 ++++--- src/components/ImageView/types.ts | 7 +------ src/components/Lightbox/index.tsx | 5 ++--- 5 files changed, 17 insertions(+), 28 deletions(-) diff --git a/src/components/Image/types.ts b/src/components/Image/types.ts index aba2b9021541..8cbf3014a0e9 100644 --- a/src/components/Image/types.ts +++ b/src/components/Image/types.ts @@ -10,6 +10,13 @@ type ImageOnyxProps = { session: OnyxEntry; }; +type ImageOnLoadEvent = { + nativeEvent: { + width: number; + height: number; + }; +}; + type ImageOwnProps = { /** Styles for the Image */ style?: StyleProp; @@ -33,12 +40,7 @@ type ImageOwnProps = { onError?: () => void; /** Event for when the image is fully loaded and returns the natural dimensions of the image */ - onLoad?: (event: { - nativeEvent: { - width: number; - height: number; - }; - }) => void; + onLoad?: (event: ImageOnLoadEvent) => void; /** Progress events while the image is downloading */ onProgress?: () => void; @@ -46,12 +48,4 @@ type ImageOwnProps = { type ImageProps = ImageOnyxProps & ImageOwnProps; -export type {ImageOwnProps, ImageOnyxProps, ImageProps, ExpoImageSource}; -type BaseImageProps = { - /** Event called with image dimensions when image is loaded */ - onLoad?: (event: {nativeEvent: {width: number; height: number}}) => void; -}; - -export type {BaseImageProps}; - -export default BaseImageProps; +export type {ImageOwnProps, ImageOnyxProps, ImageProps, ExpoImageSource, ImageOnLoadEvent}; diff --git a/src/components/ImageView/index.native.tsx b/src/components/ImageView/index.native.tsx index 8de1946ef554..127cf4072e27 100644 --- a/src/components/ImageView/index.native.tsx +++ b/src/components/ImageView/index.native.tsx @@ -1,7 +1,7 @@ import React from 'react'; import Lightbox from '@components/Lightbox'; import {DEFAULT_ZOOM_RANGE} from '@components/MultiGestureCanvas'; -import type {ImageViewProps} from './types'; +import type ImageViewProps from './types'; function ImageView({ isAuthTokenRequired = false, diff --git a/src/components/ImageView/index.tsx b/src/components/ImageView/index.tsx index ec37abf6d275..5d09e7abf41d 100644 --- a/src/components/ImageView/index.tsx +++ b/src/components/ImageView/index.tsx @@ -1,17 +1,18 @@ import type {SyntheticEvent} from 'react'; import React, {useCallback, useEffect, useRef, useState} from 'react'; -import type {GestureResponderEvent, LayoutChangeEvent, NativeSyntheticEvent} from 'react-native'; +import type {GestureResponderEvent, LayoutChangeEvent} from 'react-native'; import {View} from 'react-native'; import FullscreenLoadingIndicator from '@components/FullscreenLoadingIndicator'; import Image from '@components/Image'; import RESIZE_MODES from '@components/Image/resizeModes'; +import type {ImageOnLoadEvent} from '@components/Image/types'; import PressableWithoutFeedback from '@components/Pressable/PressableWithoutFeedback'; import useStyleUtils from '@hooks/useStyleUtils'; import useThemeStyles from '@hooks/useThemeStyles'; import * as DeviceCapabilities from '@libs/DeviceCapabilities'; import CONST from '@src/CONST'; import viewRef from '@src/types/utils/viewRef'; -import type {ImageLoadNativeEventData, ImageViewProps} from './types'; +import type ImageViewProps from './types'; type ZoomDelta = {offsetX: number; offsetY: number}; @@ -73,7 +74,7 @@ function ImageView({isAuthTokenRequired = false, url, fileName, onError}: ImageV setIsZoomed(false); }; - const imageLoad = ({nativeEvent}: NativeSyntheticEvent) => { + const imageLoad = ({nativeEvent}: ImageOnLoadEvent) => { setImageRegion(nativeEvent.width, nativeEvent.height); setIsLoading(false); }; diff --git a/src/components/ImageView/types.ts b/src/components/ImageView/types.ts index b85115874a5a..6edd515d7ff8 100644 --- a/src/components/ImageView/types.ts +++ b/src/components/ImageView/types.ts @@ -33,9 +33,4 @@ type ImageViewProps = { zoomRange?: ZoomRange; }; -type ImageLoadNativeEventData = { - width: number; - height: number; -}; - -export type {ImageViewProps, ImageLoadNativeEventData}; +export default ImageViewProps; diff --git a/src/components/Lightbox/index.tsx b/src/components/Lightbox/index.tsx index aeec1876eb93..9eaf3d2969e0 100644 --- a/src/components/Lightbox/index.tsx +++ b/src/components/Lightbox/index.tsx @@ -1,7 +1,8 @@ import React, {useCallback, useEffect, useMemo, useState} from 'react'; -import type {LayoutChangeEvent, NativeSyntheticEvent, StyleProp, ViewStyle} from 'react-native'; +import type {LayoutChangeEvent, StyleProp, ViewStyle} from 'react-native'; import {ActivityIndicator, PixelRatio, StyleSheet, View} from 'react-native'; import Image from '@components/Image'; +import type {ImageOnLoadEvent} from '@components/Image/types'; import MultiGestureCanvas, {DEFAULT_ZOOM_RANGE} from '@components/MultiGestureCanvas'; import type {CanvasSize, ContentSize, OnScaleChangedCallback, ZoomRange} from '@components/MultiGestureCanvas/types'; import {getCanvasFitScale} from '@components/MultiGestureCanvas/utils'; @@ -11,8 +12,6 @@ import NUMBER_OF_CONCURRENT_LIGHTBOXES from './numberOfConcurrentLightboxes'; const DEFAULT_IMAGE_SIZE = 200; const DEFAULT_IMAGE_DIMENSION: ContentSize = {width: DEFAULT_IMAGE_SIZE, height: DEFAULT_IMAGE_SIZE}; -type ImageOnLoadEvent = NativeSyntheticEvent; - const cachedImageDimensions = new Map(); type LightboxProps = { From 6cc06a2ed4e9cff2a598e86cff591b92febb80aa Mon Sep 17 00:00:00 2001 From: Julian Kobrynski Date: Tue, 6 Feb 2024 10:26:37 +0100 Subject: [PATCH 26/34] fix source type mismatches --- src/components/Image/types.ts | 2 +- src/components/ImageWithSizeCalculation.tsx | 2 +- .../ReportActionItem/ReportActionItemImage.tsx | 18 +++++++++++++----- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/components/Image/types.ts b/src/components/Image/types.ts index 8cbf3014a0e9..e764b53706a2 100644 --- a/src/components/Image/types.ts +++ b/src/components/Image/types.ts @@ -22,7 +22,7 @@ type ImageOwnProps = { style?: StyleProp; /** The static asset or URI source of the image */ - source: ExpoImageSource | Omit | ImageRequireSource; + source: ExpoImageSource | Omit | ImageRequireSource | undefined; /** Should an auth token be included in the image request */ isAuthTokenRequired?: boolean; diff --git a/src/components/ImageWithSizeCalculation.tsx b/src/components/ImageWithSizeCalculation.tsx index d0559327274a..e28bc67a9e31 100644 --- a/src/components/ImageWithSizeCalculation.tsx +++ b/src/components/ImageWithSizeCalculation.tsx @@ -73,7 +73,7 @@ function ImageWithSizeCalculation({url, style, onMeasure, isAuthTokenRequired}: { diff --git a/src/components/ReportActionItem/ReportActionItemImage.tsx b/src/components/ReportActionItem/ReportActionItemImage.tsx index 04a99e00c6bf..c8e0cb6f3bf8 100644 --- a/src/components/ReportActionItem/ReportActionItemImage.tsx +++ b/src/components/ReportActionItem/ReportActionItemImage.tsx @@ -1,5 +1,5 @@ import Str from 'expensify-common/lib/str'; -import React from 'react'; +import React, {useMemo} from 'react'; import type {ReactElement} from 'react'; import type {ImageSourcePropType, ViewStyle} from 'react-native'; import {View} from 'react-native'; @@ -49,19 +49,27 @@ type ReportActionItemImageProps = { function ReportActionItemImage({thumbnail, image, enablePreviewModal = false, transaction, canEditReceipt = false, isLocalFile = false, filename}: ReportActionItemImageProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); - const imageSource = tryResolveUrlFromApiRoot(image ?? ''); + const attachmentModalSource = tryResolveUrlFromApiRoot(image ?? ''); const thumbnailSource = tryResolveUrlFromApiRoot(thumbnail ?? ''); const isEReceipt = transaction && TransactionUtils.hasEReceipt(transaction); let receiptImageComponent: ReactElement; + const imageSource = useMemo(() => { + if (thumbnail) { + return typeof thumbnail === 'string' ? {uri: thumbnail} : thumbnail; + } + + return typeof image === 'string' ? {uri: image} : image; + }, [image, thumbnail]); + if (isEReceipt) { receiptImageComponent = ( ); - } else if (thumbnail && !isLocalFile && !Str.isPDF(imageSource as string)) { + } else if (thumbnail && !isLocalFile && !Str.isPDF(attachmentModalSource as string)) { receiptImageComponent = ( ); @@ -84,7 +92,7 @@ function ReportActionItemImage({thumbnail, image, enablePreviewModal = false, tr {({report}) => ( Date: Wed, 7 Feb 2024 08:28:35 +0100 Subject: [PATCH 27/34] add default props --- src/components/Image/index.native.tsx | 2 +- src/components/Image/index.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/Image/index.native.tsx b/src/components/Image/index.native.tsx index 1705f7a2a9fe..8a88d3fd96cb 100644 --- a/src/components/Image/index.native.tsx +++ b/src/components/Image/index.native.tsx @@ -9,7 +9,7 @@ const dimensionsCache = new Map(); function Image(props: ImageProps) { // eslint-disable-next-line react/destructuring-assignment - const {source, isAuthTokenRequired, session, ...rest} = props; + const {source, isAuthTokenRequired = false, session, ...rest} = props; let imageSource = source; if (typeof source === 'object' && 'uri' in source && typeof source.uri === 'number') { diff --git a/src/components/Image/index.tsx b/src/components/Image/index.tsx index 3e3adfac6f4d..89271b6f8a88 100644 --- a/src/components/Image/index.tsx +++ b/src/components/Image/index.tsx @@ -6,7 +6,7 @@ import ONYXKEYS from '@src/ONYXKEYS'; import type {ImageOnyxProps, ImageOwnProps, ImageProps} from './types'; function Image(props: ImageProps) { - const {source: propsSource, isAuthTokenRequired, onLoad, session, ...forwardedProps} = props; + const {source: propsSource, isAuthTokenRequired = false, onLoad, session, ...forwardedProps} = props; /** * Check if the image source is a URL - if so the `encryptedAuthToken` is appended * to the source. From 9dcfc34588210c272a2eedf4fed4da32123f6b8c Mon Sep 17 00:00:00 2001 From: Julian Kobrynski Date: Wed, 21 Feb 2024 11:32:40 +0100 Subject: [PATCH 28/34] fix image source bug --- src/components/Image/index.tsx | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/src/components/Image/index.tsx b/src/components/Image/index.tsx index 89271b6f8a88..dc0968ed8b49 100644 --- a/src/components/Image/index.tsx +++ b/src/components/Image/index.tsx @@ -1,7 +1,6 @@ import React, {useEffect, useMemo} from 'react'; import {Image as RNImage} from 'react-native'; import {withOnyx} from 'react-native-onyx'; -import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type {ImageOnyxProps, ImageOwnProps, ImageProps} from './types'; @@ -12,19 +11,13 @@ function Image(props: ImageProps) { * to the source. */ const source = useMemo(() => { - if (typeof propsSource === 'object' && 'uri' in propsSource && typeof propsSource.uri === 'number') { - return propsSource.uri; + const authToken = session?.encryptedAuthToken ?? null; + if (isAuthTokenRequired && typeof propsSource === 'object' && 'uri' in propsSource && authToken) { + // There is currently a `react-native-web` bug preventing the authToken being passed + // in the headers of the image request so the authToken is added as a query param. + // On native the authToken IS passed in the image request headers + return {uri: `${propsSource?.uri}?encryptedAuthToken=${encodeURIComponent(authToken)}`}; } - if (typeof propsSource !== 'number' && isAuthTokenRequired) { - const authToken = session?.encryptedAuthToken; - return { - ...propsSource, - headers: { - [CONST.CHAT_ATTACHMENT_TOKEN_KEY]: authToken ?? '', - }, - }; - } - return propsSource; // The session prop is not required, as it causes the image to reload whenever the session changes. For more information, please refer to issue #26034. // eslint-disable-next-line react-hooks/exhaustive-deps From 171e45aab8f630d068f7b3e77f8c4e3ca115a925 Mon Sep 17 00:00:00 2001 From: Julian Kobrynski Date: Thu, 22 Feb 2024 10:43:21 +0100 Subject: [PATCH 29/34] destructure props in function declaration --- ios/Podfile.lock | 2 +- ios/tmp.xcconfig | 11 ++++++++++- src/components/Image/index.native.tsx | 11 ++++------- src/components/Image/index.tsx | 3 +-- 4 files changed, 16 insertions(+), 11 deletions(-) diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 52c817c739b3..24a8d07b7d34 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -1999,7 +1999,7 @@ SPEC CHECKSUMS: SocketRocket: f32cd54efbe0f095c4d7594881e52619cfe80b17 Turf: 13d1a92d969ca0311bbc26e8356cca178ce95da2 VisionCamera: 0a6794d1974aed5d653d0d0cb900493e2583e35a - Yoga: e64aa65de36c0832d04e8c7bd614396c77a80047 + Yoga: 13c8ef87792450193e117976337b8527b49e8c03 PODFILE CHECKSUM: 0ccbb4f2406893c6e9f266dc1e7470dcd72885d2 diff --git a/ios/tmp.xcconfig b/ios/tmp.xcconfig index 8b137891791f..4b1346bf72e2 100644 --- a/ios/tmp.xcconfig +++ b/ios/tmp.xcconfig @@ -1 +1,10 @@ - +NEW_EXPENSIFY_URL=https:/$()/new.expensify.com/ +SECURE_EXPENSIFY_URL=https:/$()/secure.expensify.com/ +EXPENSIFY_URL=https:/$()/www.expensify.com/ +EXPENSIFY_PARTNER_NAME=chat-expensify-com +EXPENSIFY_PARTNER_PASSWORD=e21965746fd75f82bb66 +PUSHER_APP_KEY=268df511a204fbb60884 +USE_WEB_PROXY=false +ENVIRONMENT=production +SEND_CRASH_REPORTS=true +GOOGLE_GEOLOCATION_API_KEY=AIzaSyBFKujMpzExz0_z2pAGfPUwkmlaUc-uw1Q diff --git a/src/components/Image/index.native.tsx b/src/components/Image/index.native.tsx index 8a88d3fd96cb..63440ca96dc0 100644 --- a/src/components/Image/index.native.tsx +++ b/src/components/Image/index.native.tsx @@ -7,16 +7,13 @@ import type {ImageOnyxProps, ImageProps} from './types'; const dimensionsCache = new Map(); -function Image(props: ImageProps) { - // eslint-disable-next-line react/destructuring-assignment - const {source, isAuthTokenRequired = false, session, ...rest} = props; - +function Image({source, isAuthTokenRequired = false, session, onLoad, ...rest}: ImageProps) { let imageSource = source; if (typeof source === 'object' && 'uri' in source && typeof source.uri === 'number') { imageSource = source.uri; } if (typeof imageSource === 'object' && typeof source === 'object' && isAuthTokenRequired) { - const authToken = props.session?.encryptedAuthToken ?? null; + const authToken = session?.encryptedAuthToken ?? null; imageSource = { ...source, headers: authToken @@ -35,8 +32,8 @@ function Image(props: ImageProps) { onLoad={(evt) => { const {width, height, url} = evt.source; dimensionsCache.set(url, {width, height}); - if (props.onLoad) { - props.onLoad({nativeEvent: {width, height}}); + if (onLoad) { + onLoad({nativeEvent: {width, height}}); } }} /> diff --git a/src/components/Image/index.tsx b/src/components/Image/index.tsx index df79fb4a2242..a2198223c12e 100644 --- a/src/components/Image/index.tsx +++ b/src/components/Image/index.tsx @@ -5,8 +5,7 @@ import useNetwork from '@hooks/useNetwork'; import ONYXKEYS from '@src/ONYXKEYS'; import type {ImageOnyxProps, ImageOwnProps, ImageProps} from './types'; -function Image(props: ImageProps) { - const {source: propsSource, isAuthTokenRequired = false, onLoad, session, ...forwardedProps} = props; +function Image({source: propsSource, isAuthTokenRequired = false, onLoad, session, ...forwardedProps}: ImageProps) { const {isOffline} = useNetwork(); /** From 5d125cf4b9a305e25ddd9692adcb009d44f2d620 Mon Sep 17 00:00:00 2001 From: Julian Kobrynski Date: Thu, 22 Feb 2024 11:03:30 +0100 Subject: [PATCH 30/34] fix types --- src/components/Avatar.tsx | 6 +++--- src/components/MultipleAvatars.tsx | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/components/Avatar.tsx b/src/components/Avatar.tsx index 7e4b53526b75..2b2d0a60f657 100644 --- a/src/components/Avatar.tsx +++ b/src/components/Avatar.tsx @@ -19,7 +19,7 @@ type AvatarProps = { source?: AvatarSource; /** Extra styles to pass to Image */ - imageStyles?: StyleProp; + imageStyles?: StyleProp; /** Additional styles to pass to Icon */ iconAdditionalStyles?: StyleProp; @@ -81,7 +81,7 @@ function Avatar({ const isWorkspace = type === CONST.ICON_TYPE_WORKSPACE; const iconSize = StyleUtils.getAvatarSize(size); - const imageStyle = [StyleUtils.getAvatarStyle(size), imageStyles, styles.noBorderRadius]; + const imageStyle: StyleProp = [StyleUtils.getAvatarStyle(size), imageStyles, styles.noBorderRadius]; const iconStyle = imageStyles ? [StyleUtils.getAvatarStyle(size), styles.bgTransparent, imageStyles] : undefined; const iconFillColor = isWorkspace ? StyleUtils.getDefaultWorkspaceAvatarColor(name).fill : fill; @@ -96,7 +96,7 @@ function Avatar({ } + style={imageStyle} onError={() => setImageError(true)} /> diff --git a/src/components/MultipleAvatars.tsx b/src/components/MultipleAvatars.tsx index 1d1eea0d20ba..52e173ec4a67 100644 --- a/src/components/MultipleAvatars.tsx +++ b/src/components/MultipleAvatars.tsx @@ -1,5 +1,5 @@ import React, {memo, useMemo} from 'react'; -import type {StyleProp, ViewStyle} from 'react-native'; +import type {ImageStyle, StyleProp, ViewStyle} from 'react-native'; import {View} from 'react-native'; import type {ValueOf} from 'type-fest'; import useStyleUtils from '@hooks/useStyleUtils'; @@ -56,8 +56,8 @@ type MultipleAvatarsProps = { }; type AvatarStyles = { - singleAvatarStyle: ViewStyle; - secondAvatarStyles: ViewStyle; + singleAvatarStyle: ViewStyle & ImageStyle; + secondAvatarStyles: ViewStyle & ImageStyle; }; type AvatarSizeToStyles = typeof CONST.AVATAR_SIZE.SMALL | typeof CONST.AVATAR_SIZE.LARGE | typeof CONST.AVATAR_SIZE.DEFAULT; From d1e55ccab87d607fb569ba3b1440cdc0502a87a5 Mon Sep 17 00:00:00 2001 From: Julian Kobrynski Date: Fri, 23 Feb 2024 11:53:01 +0100 Subject: [PATCH 31/34] revert ios related changes --- ios/Podfile.lock | 2 +- ios/tmp.xcconfig | 10 ---------- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 24a8d07b7d34..52c817c739b3 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -1999,7 +1999,7 @@ SPEC CHECKSUMS: SocketRocket: f32cd54efbe0f095c4d7594881e52619cfe80b17 Turf: 13d1a92d969ca0311bbc26e8356cca178ce95da2 VisionCamera: 0a6794d1974aed5d653d0d0cb900493e2583e35a - Yoga: 13c8ef87792450193e117976337b8527b49e8c03 + Yoga: e64aa65de36c0832d04e8c7bd614396c77a80047 PODFILE CHECKSUM: 0ccbb4f2406893c6e9f266dc1e7470dcd72885d2 diff --git a/ios/tmp.xcconfig b/ios/tmp.xcconfig index 4b1346bf72e2..e69de29bb2d1 100644 --- a/ios/tmp.xcconfig +++ b/ios/tmp.xcconfig @@ -1,10 +0,0 @@ -NEW_EXPENSIFY_URL=https:/$()/new.expensify.com/ -SECURE_EXPENSIFY_URL=https:/$()/secure.expensify.com/ -EXPENSIFY_URL=https:/$()/www.expensify.com/ -EXPENSIFY_PARTNER_NAME=chat-expensify-com -EXPENSIFY_PARTNER_PASSWORD=e21965746fd75f82bb66 -PUSHER_APP_KEY=268df511a204fbb60884 -USE_WEB_PROXY=false -ENVIRONMENT=production -SEND_CRASH_REPORTS=true -GOOGLE_GEOLOCATION_API_KEY=AIzaSyBFKujMpzExz0_z2pAGfPUwkmlaUc-uw1Q From 065c27cc876c1a6e7f3fb747695cd6962b26fcd1 Mon Sep 17 00:00:00 2001 From: Julian Kobrynski Date: Fri, 23 Feb 2024 12:13:19 +0100 Subject: [PATCH 32/34] revert tmp.xcconfig --- ios/tmp.xcconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/ios/tmp.xcconfig b/ios/tmp.xcconfig index e69de29bb2d1..8b137891791f 100644 --- a/ios/tmp.xcconfig +++ b/ios/tmp.xcconfig @@ -0,0 +1 @@ + From cc789409f1378c31889c949ae7b917f012348f8f Mon Sep 17 00:00:00 2001 From: Julian Kobrynski Date: Thu, 29 Feb 2024 12:26:43 +0100 Subject: [PATCH 33/34] fix type errors --- src/components/AvatarWithImagePicker.tsx | 6 ++---- src/components/MoneyRequestConfirmationList.tsx | 11 ++++++++++- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/components/AvatarWithImagePicker.tsx b/src/components/AvatarWithImagePicker.tsx index 4388ebb8f815..5755c69641c8 100644 --- a/src/components/AvatarWithImagePicker.tsx +++ b/src/components/AvatarWithImagePicker.tsx @@ -1,6 +1,6 @@ import React, {useEffect, useRef, useState} from 'react'; import {StyleSheet, View} from 'react-native'; -import type {StyleProp, ViewStyle} from 'react-native'; +import type {ImageStyle, StyleProp, ViewStyle} from 'react-native'; import useLocalize from '@hooks/useLocalize'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; @@ -103,7 +103,7 @@ type AvatarWithImagePickerProps = { isFocused: boolean; /** Style applied to the avatar */ - avatarStyle: StyleProp; + avatarStyle: StyleProp; /** Indicates if picker feature should be disabled */ disabled?: boolean; @@ -279,8 +279,6 @@ function AvatarWithImagePicker({ vertical: y + height + variables.spacing2, }); }); - - // eslint-disable-next-line react-hooks/exhaustive-deps }, [isMenuVisible, windowWidth]); return ( diff --git a/src/components/MoneyRequestConfirmationList.tsx b/src/components/MoneyRequestConfirmationList.tsx index 773e98b6462e..5fe1942348b1 100755 --- a/src/components/MoneyRequestConfirmationList.tsx +++ b/src/components/MoneyRequestConfirmationList.tsx @@ -598,6 +598,15 @@ function MoneyRequestConfirmationList({ ]); const receiptData = receiptPath && receiptFilename ? ReceiptUtils.getThumbnailAndImageURIs(transaction ?? null, receiptPath, receiptFilename) : null; + + const imageSource = useMemo(() => { + if (receiptData?.thumbnail) { + return typeof receiptData.thumbnail === 'string' ? {uri: receiptData.thumbnail} : receiptData.thumbnail; + } + + return typeof receiptData?.image === 'string' ? {uri: receiptData.image} : receiptData?.image; + }, []); + return ( // @ts-expect-error TODO: Remove this once OptionsSelector (https://github.com/Expensify/App/issues/25125) is migrated to TypeScript. Date: Thu, 29 Feb 2024 12:36:01 +0100 Subject: [PATCH 34/34] fill the dependency array in MoneyRequestCOnfirmationList --- src/components/MoneyRequestConfirmationList.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/MoneyRequestConfirmationList.tsx b/src/components/MoneyRequestConfirmationList.tsx index 5fe1942348b1..df5984d8ac86 100755 --- a/src/components/MoneyRequestConfirmationList.tsx +++ b/src/components/MoneyRequestConfirmationList.tsx @@ -605,7 +605,7 @@ function MoneyRequestConfirmationList({ } return typeof receiptData?.image === 'string' ? {uri: receiptData.image} : receiptData?.image; - }, []); + }, [receiptData?.thumbnail, receiptData?.image]); return ( // @ts-expect-error TODO: Remove this once OptionsSelector (https://github.com/Expensify/App/issues/25125) is migrated to TypeScript.