From 1d78c3f37515c43b03ae94ad44a0c35fb0266a04 Mon Sep 17 00:00:00 2001 From: krishna2323 Date: Wed, 13 Aug 2025 03:04:18 +0530 Subject: [PATCH 01/12] fix: Add accounting connection logo in Categories when connected to integration. Signed-off-by: krishna2323 --- .../categories/WorkspaceCategoriesPage.tsx | 30 +++++++++---------- .../reports/WorkspaceReportsPage.tsx | 18 +++++------ .../workspace/tags/WorkspaceTagsPage.tsx | 20 ++++++------- .../workspace/taxes/WorkspaceTaxesPage.tsx | 21 ++++++------- 4 files changed, 42 insertions(+), 47 deletions(-) diff --git a/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx b/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx index 645162f98e66..2dabbfba7b75 100644 --- a/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx +++ b/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx @@ -9,6 +9,7 @@ import EmptyStateComponent from '@components/EmptyStateComponent'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import * as Expensicons from '@components/Icon/Expensicons'; import * as Illustrations from '@components/Icon/Illustrations'; +import ImportedFromAccountingSoftware from '@components/ImportedFromAccountingSoftware'; import LottieAnimations from '@components/LottieAnimations'; import RenderHTML from '@components/RenderHTML'; import ScreenWrapper from '@components/ScreenWrapper'; @@ -21,7 +22,6 @@ import CustomListHeader from '@components/SelectionListWithModal/CustomListHeade import TableListItemSkeleton from '@components/Skeletons/TableRowSkeleton'; import Switch from '@components/Switch'; import Text from '@components/Text'; -import TextLink from '@components/TextLink'; import useAutoTurnSelectionModeOffWhenHasNoActiveOption from '@hooks/useAutoTurnSelectionModeOffWhenHasNoActiveOption'; import useCleanupSelectedOptions from '@hooks/useCleanupSelectedOptions'; import useEnvironment from '@hooks/useEnvironment'; @@ -415,20 +415,20 @@ function WorkspaceCategoriesPage({route}: WorkspaceCategoriesPageProps) { const headerContent = ( <> - {!hasSyncError && isConnectionVerified ? ( - - {`${translate('workspace.categories.importedFromAccountingSoftware')} `} - - {`${currentConnectionName} ${translate('workspace.accounting.settings')}`} - - . - - ) : ( - {translate('workspace.categories.subtitle')} - )} + {(() => { + if (!hasSyncError && isConnectionVerified && currentConnectionName) { + return ( + + ); + } + return {translate('workspace.categories.subtitle')}; + })()} {categoryList.length > CONST.SEARCH_ITEM_LIMIT && ( - !hasSyncError && isConnectionVerified ? ( + !hasSyncError && isConnectionVerified && currentConnectionName ? ( - {`${translate('workspace.reportFields.importedFromAccountingSoftware')} `} - - {`${currentConnectionName} ${translate('workspace.accounting.settings')}`} - - . + ) : ( {translate('workspace.reportFields.subtitle')} diff --git a/src/pages/workspace/tags/WorkspaceTagsPage.tsx b/src/pages/workspace/tags/WorkspaceTagsPage.tsx index 54ceecde89f6..fdd72f74d83d 100644 --- a/src/pages/workspace/tags/WorkspaceTagsPage.tsx +++ b/src/pages/workspace/tags/WorkspaceTagsPage.tsx @@ -9,6 +9,7 @@ import EmptyStateComponent from '@components/EmptyStateComponent'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import * as Expensicons from '@components/Icon/Expensicons'; import * as Illustrations from '@components/Icon/Illustrations'; +import ImportedFromAccountingSoftware from '@components/ImportedFromAccountingSoftware'; import LottieAnimations from '@components/LottieAnimations'; import RenderHTML from '@components/RenderHTML'; import ScreenWrapper from '@components/ScreenWrapper'; @@ -559,17 +560,14 @@ function WorkspaceTagsPage({route}: WorkspaceTagsPageProps) { const headerContent = ( <> - {!hasSyncError && isConnectionVerified ? ( - - {`${translate('workspace.tags.importedFromAccountingSoftware')} `} - - {`${currentConnectionName} ${translate('workspace.accounting.settings')}`} - - . - + {!hasSyncError && isConnectionVerified && currentConnectionName ? ( + ) : ( {translate('workspace.tags.subtitle')} diff --git a/src/pages/workspace/taxes/WorkspaceTaxesPage.tsx b/src/pages/workspace/taxes/WorkspaceTaxesPage.tsx index ce446a3b81ba..917151ba3651 100644 --- a/src/pages/workspace/taxes/WorkspaceTaxesPage.tsx +++ b/src/pages/workspace/taxes/WorkspaceTaxesPage.tsx @@ -7,6 +7,7 @@ import ConfirmModal from '@components/ConfirmModal'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import * as Expensicons from '@components/Icon/Expensicons'; import * as Illustrations from '@components/Icon/Illustrations'; +import ImportedFromAccountingSoftware from '@components/ImportedFromAccountingSoftware'; import ScreenWrapper from '@components/ScreenWrapper'; import SearchBar from '@components/SearchBar'; import TableListItem from '@components/SelectionList/TableListItem'; @@ -15,7 +16,6 @@ import SelectionListWithModal from '@components/SelectionListWithModal'; import CustomListHeader from '@components/SelectionListWithModal/CustomListHeader'; import Switch from '@components/Switch'; import Text from '@components/Text'; -import TextLink from '@components/TextLink'; import useCleanupSelectedOptions from '@hooks/useCleanupSelectedOptions'; import useEnvironment from '@hooks/useEnvironment'; import useLocalize from '@hooks/useLocalize'; @@ -362,17 +362,14 @@ function WorkspaceTaxesPage({ const headerContent = ( <> - {!hasSyncError && isConnectionVerified ? ( - - {`${translate('workspace.taxes.importedFromAccountingSoftware')} `} - - {`${currentConnectionName} ${translate('workspace.accounting.settings')}`} - - . - + {!hasSyncError && isConnectionVerified && currentConnectionName ? ( + ) : ( {translate('workspace.taxes.subtitle')} )} From 37dc472331090911d3a483aed13e9eba83e4a830 Mon Sep 17 00:00:00 2001 From: krishna2323 Date: Wed, 13 Aug 2025 03:05:51 +0530 Subject: [PATCH 02/12] add ImportedFromAccountingSoftware.tsx. Signed-off-by: krishna2323 --- .../ImportedFromAccountingSoftware.tsx | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 src/components/ImportedFromAccountingSoftware.tsx diff --git a/src/components/ImportedFromAccountingSoftware.tsx b/src/components/ImportedFromAccountingSoftware.tsx new file mode 100644 index 000000000000..cab17dca4064 --- /dev/null +++ b/src/components/ImportedFromAccountingSoftware.tsx @@ -0,0 +1,61 @@ +import React from 'react'; +import useLocalize from '@hooks/useLocalize'; +import useStyleUtils from '@hooks/useStyleUtils'; +import useThemeStyles from '@hooks/useThemeStyles'; +import {getIntegrationIcon} from '@libs/ReportUtils'; +import variables from '@styles/variables'; +import CONST from '@src/CONST'; +import ROUTES from '@src/ROUTES'; +import type {ConnectionName} from '@src/types/onyx/Policy'; +import Icon from './Icon'; +import Text from './Text'; +import TextLink from './TextLink'; + +type ImportedFromAccountingSoftwareProps = { + /** The policy ID to link to */ + policyID: string; + + /** The name of the current connection */ + currentConnectionName: string; + + /** The connected integration */ + connectedIntegration: ConnectionName | undefined; + + /** The translated text for the "imported from" message */ + translatedText: string; + + /** The environment URL for the link */ + environmentURL: string; +}; + +function ImportedFromAccountingSoftware({policyID, currentConnectionName, translatedText, environmentURL, connectedIntegration}: ImportedFromAccountingSoftwareProps) { + const styles = useThemeStyles(); + const StyleUtils = useStyleUtils(); + const {translate} = useLocalize(); + const icon = getIntegrationIcon(connectedIntegration); + + return ( + + {`${translatedText} `} + + {!!icon && ( + + )} + {`${currentConnectionName} ${translate('workspace.accounting.settings')}`} + + . + + ); +} + +ImportedFromAccountingSoftware.displayName = 'ImportedFromAccountingSoftware'; + +export default ImportedFromAccountingSoftware; From 79043cb33a7f6f3def472b42b4757a6fe2d0cc0c Mon Sep 17 00:00:00 2001 From: krishna2323 Date: Thu, 14 Aug 2025 04:43:18 +0530 Subject: [PATCH 03/12] fix categories page rendering. Signed-off-by: krishna2323 --- .../categories/WorkspaceCategoriesPage.tsx | 25 ++++++++----------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx b/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx index 2dabbfba7b75..515f7989e471 100644 --- a/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx +++ b/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx @@ -415,20 +415,17 @@ function WorkspaceCategoriesPage({route}: WorkspaceCategoriesPageProps) { const headerContent = ( <> - {(() => { - if (!hasSyncError && isConnectionVerified && currentConnectionName) { - return ( - - ); - } - return {translate('workspace.categories.subtitle')}; - })()} + {!hasSyncError && isConnectionVerified && currentConnectionName ? ( + + ) : ( + {translate('workspace.categories.subtitle')} + )} {categoryList.length > CONST.SEARCH_ITEM_LIMIT && ( Date: Thu, 14 Aug 2025 16:30:42 +0530 Subject: [PATCH 04/12] create TextLinkBlock component for aligning the icon. Signed-off-by: krishna2323 --- .../ImportedFromAccountingSoftware.tsx | 22 +++++-- src/components/TextLinkBlock.tsx | 64 +++++++++++++++++++ 2 files changed, 81 insertions(+), 5 deletions(-) create mode 100644 src/components/TextLinkBlock.tsx diff --git a/src/components/ImportedFromAccountingSoftware.tsx b/src/components/ImportedFromAccountingSoftware.tsx index cab17dca4064..807b5aaf2550 100644 --- a/src/components/ImportedFromAccountingSoftware.tsx +++ b/src/components/ImportedFromAccountingSoftware.tsx @@ -1,4 +1,5 @@ import React from 'react'; +import {View} from 'react-native'; import useLocalize from '@hooks/useLocalize'; import useStyleUtils from '@hooks/useStyleUtils'; import useThemeStyles from '@hooks/useThemeStyles'; @@ -9,7 +10,10 @@ import ROUTES from '@src/ROUTES'; import type {ConnectionName} from '@src/types/onyx/Policy'; import Icon from './Icon'; import Text from './Text'; +import TextBlock from './TextBlock'; import TextLink from './TextLink'; +// import TextLink from './TextLink'; +import TextLinkBlock from './TextLinkBlock'; type ImportedFromAccountingSoftwareProps = { /** The policy ID to link to */ @@ -35,10 +39,13 @@ function ImportedFromAccountingSoftware({policyID, currentConnectionName, transl const icon = getIntegrationIcon(connectedIntegration); return ( - - {`${translatedText} `} + + {!!icon && ( @@ -49,10 +56,15 @@ function ImportedFromAccountingSoftware({policyID, currentConnectionName, transl additionalStyles={[StyleUtils.getAvatarBorderStyle(CONST.AVATAR_SIZE.SMALLER, '')]} /> )} - {`${currentConnectionName} ${translate('workspace.accounting.settings')}`} + + . - + ); } diff --git a/src/components/TextLinkBlock.tsx b/src/components/TextLinkBlock.tsx new file mode 100644 index 000000000000..5ed75205e6a8 --- /dev/null +++ b/src/components/TextLinkBlock.tsx @@ -0,0 +1,64 @@ +/** + * TextLinkBlock component splits a given text into individual words and displays + * each word within a TextLink component so the link text wraps naturally. + */ +import React, {memo, useMemo} from 'react'; +import type {MouseEventHandler} from 'react'; +import type {StyleProp, TextStyle} from 'react-native'; +import TextLink from './TextLink'; +import type {LinkProps, PressProps} from './TextLink'; + +type TextLinkBlockProps = (LinkProps | PressProps) & { + /** Styles to apply to each word */ + style?: StyleProp; + + /** Callback that is called when mousedown is triggered */ + onMouseDown?: MouseEventHandler; + + /** The full text to be split into words */ + text: string; +}; + +function TextLinkBlock({text, style, onMouseDown, ...rest}: TextLinkBlockProps) { + const words = useMemo(() => text.match(/(\S+\s*)/g) ?? [], [text]); + + if ('href' in rest) { + const {href} = rest as LinkProps; + return ( + <> + {words.map((word, index) => ( + + {word} + + ))} + + ); + } + + const {onPress} = rest as PressProps; + return ( + <> + {words.map((word, index) => ( + + {word} + + ))} + + ); +} + +TextLinkBlock.displayName = 'TextLinkBlock'; + +export default memo(TextLinkBlock); From 903114200fee512d5c3dce193e438fb0dc59b9b9 Mon Sep 17 00:00:00 2001 From: krishna2323 Date: Thu, 14 Aug 2025 17:20:30 +0530 Subject: [PATCH 05/12] fix icon alignment on native devices. Signed-off-by: krishna2323 --- .../ImportedFromAccountingSoftware.tsx | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/components/ImportedFromAccountingSoftware.tsx b/src/components/ImportedFromAccountingSoftware.tsx index 807b5aaf2550..bf5c60cdd1a1 100644 --- a/src/components/ImportedFromAccountingSoftware.tsx +++ b/src/components/ImportedFromAccountingSoftware.tsx @@ -5,14 +5,15 @@ import useStyleUtils from '@hooks/useStyleUtils'; import useThemeStyles from '@hooks/useThemeStyles'; import {getIntegrationIcon} from '@libs/ReportUtils'; import variables from '@styles/variables'; +import * as Link from '@userActions/Link'; import CONST from '@src/CONST'; import ROUTES from '@src/ROUTES'; import type {ConnectionName} from '@src/types/onyx/Policy'; import Icon from './Icon'; +import {PressableWithoutFeedback} from './Pressable'; import Text from './Text'; import TextBlock from './TextBlock'; import TextLink from './TextLink'; -// import TextLink from './TextLink'; import TextLinkBlock from './TextLinkBlock'; type ImportedFromAccountingSoftwareProps = { @@ -44,20 +45,26 @@ function ImportedFromAccountingSoftware({policyID, currentConnectionName, transl textStyles={[styles.textNormal, styles.colorMuted]} text={`${translatedText} `} /> - Link.openLink(`${environmentURL}/${ROUTES.POLICY_ACCOUNTING.getRoute(policyID)}`, environmentURL)} + role={CONST.ROLE.BUTTON} + accessibilityLabel={translate('common.close')} > {!!icon && ( )} + + Link.openLink(`${environmentURL}/${ROUTES.POLICY_ACCOUNTING.getRoute(policyID)}`, environmentURL)} + > + {' '} - Date: Thu, 14 Aug 2025 17:29:43 +0530 Subject: [PATCH 06/12] fix ESLint. Signed-off-by: krishna2323 --- src/components/ImportedFromAccountingSoftware.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/ImportedFromAccountingSoftware.tsx b/src/components/ImportedFromAccountingSoftware.tsx index bf5c60cdd1a1..b618de0177fc 100644 --- a/src/components/ImportedFromAccountingSoftware.tsx +++ b/src/components/ImportedFromAccountingSoftware.tsx @@ -3,9 +3,9 @@ import {View} from 'react-native'; import useLocalize from '@hooks/useLocalize'; import useStyleUtils from '@hooks/useStyleUtils'; import useThemeStyles from '@hooks/useThemeStyles'; +import {openLink} from '@libs/actions/Link'; import {getIntegrationIcon} from '@libs/ReportUtils'; import variables from '@styles/variables'; -import * as Link from '@userActions/Link'; import CONST from '@src/CONST'; import ROUTES from '@src/ROUTES'; import type {ConnectionName} from '@src/types/onyx/Policy'; @@ -46,7 +46,7 @@ function ImportedFromAccountingSoftware({policyID, currentConnectionName, transl text={`${translatedText} `} /> Link.openLink(`${environmentURL}/${ROUTES.POLICY_ACCOUNTING.getRoute(policyID)}`, environmentURL)} + onPress={() => openLink(`${environmentURL}/${ROUTES.POLICY_ACCOUNTING.getRoute(policyID)}`, environmentURL)} role={CONST.ROLE.BUTTON} accessibilityLabel={translate('common.close')} > @@ -61,7 +61,7 @@ function ImportedFromAccountingSoftware({policyID, currentConnectionName, transl Link.openLink(`${environmentURL}/${ROUTES.POLICY_ACCOUNTING.getRoute(policyID)}`, environmentURL)} + onPress={() => openLink(`${environmentURL}/${ROUTES.POLICY_ACCOUNTING.getRoute(policyID)}`, environmentURL)} > {' '} From df5f2ea7cbc1bd78b53bbb17cd35f39b59791eaf Mon Sep 17 00:00:00 2001 From: krishna2323 Date: Thu, 14 Aug 2025 18:19:44 +0530 Subject: [PATCH 07/12] fix icon floating issue. Signed-off-by: krishna2323 --- .../ImportedFromAccountingSoftware.tsx | 35 +++++----------- src/components/TextLinkBlock.tsx | 40 +++++++++++++------ 2 files changed, 38 insertions(+), 37 deletions(-) diff --git a/src/components/ImportedFromAccountingSoftware.tsx b/src/components/ImportedFromAccountingSoftware.tsx index b618de0177fc..fe4d19e3a870 100644 --- a/src/components/ImportedFromAccountingSoftware.tsx +++ b/src/components/ImportedFromAccountingSoftware.tsx @@ -3,17 +3,14 @@ import {View} from 'react-native'; import useLocalize from '@hooks/useLocalize'; import useStyleUtils from '@hooks/useStyleUtils'; import useThemeStyles from '@hooks/useThemeStyles'; -import {openLink} from '@libs/actions/Link'; import {getIntegrationIcon} from '@libs/ReportUtils'; import variables from '@styles/variables'; import CONST from '@src/CONST'; import ROUTES from '@src/ROUTES'; import type {ConnectionName} from '@src/types/onyx/Policy'; import Icon from './Icon'; -import {PressableWithoutFeedback} from './Pressable'; import Text from './Text'; import TextBlock from './TextBlock'; -import TextLink from './TextLink'; import TextLinkBlock from './TextLinkBlock'; type ImportedFromAccountingSoftwareProps = { @@ -45,30 +42,20 @@ function ImportedFromAccountingSoftware({policyID, currentConnectionName, transl textStyles={[styles.textNormal, styles.colorMuted]} text={`${translatedText} `} /> - openLink(`${environmentURL}/${ROUTES.POLICY_ACCOUNTING.getRoute(policyID)}`, environmentURL)} - role={CONST.ROLE.BUTTON} - accessibilityLabel={translate('common.close')} - > - {!!icon && ( - - )} - - openLink(`${environmentURL}/${ROUTES.POLICY_ACCOUNTING.getRoute(policyID)}`, environmentURL)} - > - {' '} - + ) : undefined + } /> . diff --git a/src/components/TextLinkBlock.tsx b/src/components/TextLinkBlock.tsx index 5ed75205e6a8..6bcff6dac98c 100644 --- a/src/components/TextLinkBlock.tsx +++ b/src/components/TextLinkBlock.tsx @@ -5,6 +5,7 @@ import React, {memo, useMemo} from 'react'; import type {MouseEventHandler} from 'react'; import type {StyleProp, TextStyle} from 'react-native'; +import {View} from 'react-native-web'; import TextLink from './TextLink'; import type {LinkProps, PressProps} from './TextLink'; @@ -17,9 +18,12 @@ type TextLinkBlockProps = (LinkProps | PressProps) & { /** The full text to be split into words */ text: string; + + /** The full text to be split into words */ + prefixIcon?: React.JSX.Element; }; -function TextLinkBlock({text, style, onMouseDown, ...rest}: TextLinkBlockProps) { +function TextLinkBlock({text, style, onMouseDown, prefixIcon, ...rest}: TextLinkBlockProps) { const words = useMemo(() => text.match(/(\S+\s*)/g) ?? [], [text]); if ('href' in rest) { @@ -27,15 +31,20 @@ function TextLinkBlock({text, style, onMouseDown, ...rest}: TextLinkBlockProps) return ( <> {words.map((word, index) => ( - - {word} - + {prefixIcon && index === 0 && prefixIcon} + + {word} + + ))} ); @@ -45,15 +54,20 @@ function TextLinkBlock({text, style, onMouseDown, ...rest}: TextLinkBlockProps) return ( <> {words.map((word, index) => ( - - {word} - + {prefixIcon && index === 0 && prefixIcon} + + {word} + + ))} ); From d0aa899c1b4d9916b81bce1a28cfe5b1076e0a5e Mon Sep 17 00:00:00 2001 From: krishna2323 Date: Thu, 14 Aug 2025 18:30:02 +0530 Subject: [PATCH 08/12] fix spacing. Signed-off-by: krishna2323 --- src/components/TextLinkBlock.tsx | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/components/TextLinkBlock.tsx b/src/components/TextLinkBlock.tsx index 6bcff6dac98c..b1ccb7c56eab 100644 --- a/src/components/TextLinkBlock.tsx +++ b/src/components/TextLinkBlock.tsx @@ -5,7 +5,9 @@ import React, {memo, useMemo} from 'react'; import type {MouseEventHandler} from 'react'; import type {StyleProp, TextStyle} from 'react-native'; -import {View} from 'react-native-web'; +import {View} from 'react-native'; +import useThemeStyles from '@hooks/useThemeStyles'; +import Text from './Text'; import TextLink from './TextLink'; import type {LinkProps, PressProps} from './TextLink'; @@ -25,6 +27,7 @@ type TextLinkBlockProps = (LinkProps | PressProps) & { function TextLinkBlock({text, style, onMouseDown, prefixIcon, ...rest}: TextLinkBlockProps) { const words = useMemo(() => text.match(/(\S+\s*)/g) ?? [], [text]); + const styles = useThemeStyles(); if ('href' in rest) { const {href} = rest as LinkProps; @@ -34,9 +37,10 @@ function TextLinkBlock({text, style, onMouseDown, prefixIcon, ...rest}: TextLink {prefixIcon && index === 0 && prefixIcon} + {!!prefixIcon && index === 0 && } {prefixIcon && index === 0 && prefixIcon} Date: Sat, 16 Aug 2025 04:52:27 +0530 Subject: [PATCH 09/12] remove environmentURL prop from TextLinkBlock. Signed-off-by: krishna2323 --- .../ImportedFromAccountingSoftware.tsx | 7 ++-- src/components/TextLink.tsx | 2 +- src/components/TextLinkBlock.tsx | 37 ++----------------- .../categories/WorkspaceCategoriesPage.tsx | 1 - .../reports/WorkspaceReportsPage.tsx | 3 -- .../workspace/tags/WorkspaceTagsPage.tsx | 1 - .../workspace/taxes/WorkspaceTaxesPage.tsx | 3 -- 7 files changed, 8 insertions(+), 46 deletions(-) diff --git a/src/components/ImportedFromAccountingSoftware.tsx b/src/components/ImportedFromAccountingSoftware.tsx index fe4d19e3a870..48c44573702e 100644 --- a/src/components/ImportedFromAccountingSoftware.tsx +++ b/src/components/ImportedFromAccountingSoftware.tsx @@ -1,5 +1,6 @@ import React from 'react'; import {View} from 'react-native'; +import useEnvironment from '@hooks/useEnvironment'; import useLocalize from '@hooks/useLocalize'; import useStyleUtils from '@hooks/useStyleUtils'; import useThemeStyles from '@hooks/useThemeStyles'; @@ -25,15 +26,13 @@ type ImportedFromAccountingSoftwareProps = { /** The translated text for the "imported from" message */ translatedText: string; - - /** The environment URL for the link */ - environmentURL: string; }; -function ImportedFromAccountingSoftware({policyID, currentConnectionName, translatedText, environmentURL, connectedIntegration}: ImportedFromAccountingSoftwareProps) { +function ImportedFromAccountingSoftware({policyID, currentConnectionName, translatedText, connectedIntegration}: ImportedFromAccountingSoftwareProps) { const styles = useThemeStyles(); const StyleUtils = useStyleUtils(); const {translate} = useLocalize(); + const {environmentURL} = useEnvironment(); const icon = getIntegrationIcon(connectedIntegration); return ( diff --git a/src/components/TextLink.tsx b/src/components/TextLink.tsx index 2d390f9811e6..6c7918c76acc 100644 --- a/src/components/TextLink.tsx +++ b/src/components/TextLink.tsx @@ -79,6 +79,6 @@ function TextLink({href, onPress, children, style, onMouseDown = (event) => even TextLink.displayName = 'TextLink'; -export type {LinkProps, PressProps}; +export type {LinkProps, PressProps, TextLinkProps}; export default forwardRef(TextLink); diff --git a/src/components/TextLinkBlock.tsx b/src/components/TextLinkBlock.tsx index b1ccb7c56eab..539f5a49851b 100644 --- a/src/components/TextLinkBlock.tsx +++ b/src/components/TextLinkBlock.tsx @@ -3,7 +3,6 @@ * each word within a TextLink component so the link text wraps naturally. */ import React, {memo, useMemo} from 'react'; -import type {MouseEventHandler} from 'react'; import type {StyleProp, TextStyle} from 'react-native'; import {View} from 'react-native'; import useThemeStyles from '@hooks/useThemeStyles'; @@ -15,9 +14,6 @@ type TextLinkBlockProps = (LinkProps | PressProps) & { /** Styles to apply to each word */ style?: StyleProp; - /** Callback that is called when mousedown is triggered */ - onMouseDown?: MouseEventHandler; - /** The full text to be split into words */ text: string; @@ -25,36 +21,10 @@ type TextLinkBlockProps = (LinkProps | PressProps) & { prefixIcon?: React.JSX.Element; }; -function TextLinkBlock({text, style, onMouseDown, prefixIcon, ...rest}: TextLinkBlockProps) { +function TextLinkBlock({text, style, prefixIcon, ...rest}: TextLinkBlockProps) { const words = useMemo(() => text.match(/(\S+\s*)/g) ?? [], [text]); const styles = useThemeStyles(); - if ('href' in rest) { - const {href} = rest as LinkProps; - return ( - <> - {words.map((word, index) => ( - - {prefixIcon && index === 0 && prefixIcon} - {!!prefixIcon && index === 0 && } - - {word} - - - ))} - - ); - } - - const {onPress} = rest as PressProps; return ( <> {words.map((word, index) => ( @@ -64,10 +34,11 @@ function TextLinkBlock({text, style, onMouseDown, prefixIcon, ...rest}: TextLink style={[styles.dInlineFlex, styles.alignItemsCenter, styles.flexRow]} > {prefixIcon && index === 0 && prefixIcon} + {!!prefixIcon && index === 0 && } {word} diff --git a/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx b/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx index be1ee2d68545..f4ecc1c4fe45 100644 --- a/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx +++ b/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx @@ -446,7 +446,6 @@ function WorkspaceCategoriesPage({route}: WorkspaceCategoriesPageProps) { currentConnectionName={currentConnectionName} connectedIntegration={connectedIntegration} translatedText={translate('workspace.categories.importedFromAccountingSoftware')} - environmentURL={environmentURL} /> ) : ( {translate('workspace.categories.subtitle')} diff --git a/src/pages/workspace/reports/WorkspaceReportsPage.tsx b/src/pages/workspace/reports/WorkspaceReportsPage.tsx index 252463c82df6..ab44454cf2ff 100644 --- a/src/pages/workspace/reports/WorkspaceReportsPage.tsx +++ b/src/pages/workspace/reports/WorkspaceReportsPage.tsx @@ -17,7 +17,6 @@ import Section from '@components/Section'; import type {ListItem} from '@components/SelectionList/types'; import Text from '@components/Text'; import TextLink from '@components/TextLink'; -import useEnvironment from '@hooks/useEnvironment'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; import useOnyx from '@hooks/useOnyx'; @@ -69,7 +68,6 @@ function WorkspaceReportFieldsPage({ const [isReportFieldsWarningModalOpen, setIsReportFieldsWarningModalOpen] = useState(false); const policy = usePolicy(policyID); const [connectionSyncProgress] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CONNECTION_SYNC_PROGRESS}${policyID}`, {canBeMissing: true}); - const {environmentURL} = useEnvironment(); const isSyncInProgress = isConnectionInProgress(connectionSyncProgress, policy); const hasSyncError = shouldShowSyncError(policy, isSyncInProgress); const connectedIntegration = getConnectedIntegration(policy) ?? connectionSyncProgress?.connectionName; @@ -134,7 +132,6 @@ function WorkspaceReportFieldsPage({ currentConnectionName={currentConnectionName} connectedIntegration={connectedIntegration} translatedText={translate('workspace.reportFields.importedFromAccountingSoftware')} - environmentURL={environmentURL} /> ) : ( diff --git a/src/pages/workspace/tags/WorkspaceTagsPage.tsx b/src/pages/workspace/tags/WorkspaceTagsPage.tsx index 0de488aa6ce4..558c8effac58 100644 --- a/src/pages/workspace/tags/WorkspaceTagsPage.tsx +++ b/src/pages/workspace/tags/WorkspaceTagsPage.tsx @@ -611,7 +611,6 @@ function WorkspaceTagsPage({route}: WorkspaceTagsPageProps) { currentConnectionName={currentConnectionName} connectedIntegration={connectedIntegration} translatedText={translate('workspace.tags.importedFromAccountingSoftware')} - environmentURL={environmentURL} /> ) : ( diff --git a/src/pages/workspace/taxes/WorkspaceTaxesPage.tsx b/src/pages/workspace/taxes/WorkspaceTaxesPage.tsx index 917151ba3651..7e9d0d3d1ada 100644 --- a/src/pages/workspace/taxes/WorkspaceTaxesPage.tsx +++ b/src/pages/workspace/taxes/WorkspaceTaxesPage.tsx @@ -17,7 +17,6 @@ import CustomListHeader from '@components/SelectionListWithModal/CustomListHeade import Switch from '@components/Switch'; import Text from '@components/Text'; import useCleanupSelectedOptions from '@hooks/useCleanupSelectedOptions'; -import useEnvironment from '@hooks/useEnvironment'; import useLocalize from '@hooks/useLocalize'; import useMobileSelectionMode from '@hooks/useMobileSelectionMode'; import useNetwork from '@hooks/useNetwork'; @@ -66,7 +65,6 @@ function WorkspaceTaxesPage({ const styles = useThemeStyles(); const theme = useTheme(); const {translate, localeCompare} = useLocalize(); - const {environmentURL} = useEnvironment(); const [selectedTaxesIDs, setSelectedTaxesIDs] = useState([]); const [isDeleteModalVisible, setIsDeleteModalVisible] = useState(false); const isMobileSelectionModeEnabled = useMobileSelectionMode(); @@ -368,7 +366,6 @@ function WorkspaceTaxesPage({ currentConnectionName={currentConnectionName} connectedIntegration={connectedIntegration} translatedText={translate('workspace.taxes.importedFromAccountingSoftware')} - environmentURL={environmentURL} /> ) : ( {translate('workspace.taxes.subtitle')} From c85c955534207b34a4c0651026197da50022bc36 Mon Sep 17 00:00:00 2001 From: krishna2323 Date: Sat, 16 Aug 2025 04:59:44 +0530 Subject: [PATCH 10/12] fix ESLint. Signed-off-by: krishna2323 --- src/components/TextLink.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/TextLink.tsx b/src/components/TextLink.tsx index 6c7918c76acc..715d25e040a9 100644 --- a/src/components/TextLink.tsx +++ b/src/components/TextLink.tsx @@ -4,7 +4,7 @@ import React, {forwardRef} from 'react'; import type {GestureResponderEvent, Text as RNText, StyleProp, TextStyle} from 'react-native'; import useEnvironment from '@hooks/useEnvironment'; import useThemeStyles from '@hooks/useThemeStyles'; -import * as Link from '@userActions/Link'; +import {openLink as openLinkUtil} from '@userActions/Link'; import CONST from '@src/CONST'; import type {TextProps} from './Text'; import Text from './Text'; @@ -40,7 +40,7 @@ function TextLink({href, onPress, children, style, onMouseDown = (event) => even if (onPress) { onPress(event); } else { - Link.openLink(href, environmentURL); + openLinkUtil(href, environmentURL); } }; From baab803cb274ca8590162ed1d6b8c5015a72a548 Mon Sep 17 00:00:00 2001 From: krishna2323 Date: Sat, 16 Aug 2025 05:13:37 +0530 Subject: [PATCH 11/12] fix ESLint. Signed-off-by: krishna2323 --- src/pages/workspace/reports/WorkspaceReportsPage.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pages/workspace/reports/WorkspaceReportsPage.tsx b/src/pages/workspace/reports/WorkspaceReportsPage.tsx index 185fb8b6152a..90015b13e7cb 100644 --- a/src/pages/workspace/reports/WorkspaceReportsPage.tsx +++ b/src/pages/workspace/reports/WorkspaceReportsPage.tsx @@ -17,7 +17,6 @@ import ScrollView from '@components/ScrollView'; import Section from '@components/Section'; import type {ListItem} from '@components/SelectionList/types'; import Text from '@components/Text'; -import TextLink from '@components/TextLink'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; import useOnyx from '@hooks/useOnyx'; From 6e55339945ddfb5b996bfdd2fc3f675629d2e9b2 Mon Sep 17 00:00:00 2001 From: krishna2323 Date: Tue, 19 Aug 2025 03:52:12 +0530 Subject: [PATCH 12/12] add style for dInline. Signed-off-by: krishna2323 --- src/components/TextLinkBlock.tsx | 23 +++++++++++++++++++++-- src/styles/utils/display.ts | 8 ++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/src/components/TextLinkBlock.tsx b/src/components/TextLinkBlock.tsx index 539f5a49851b..ce0454b0ae26 100644 --- a/src/components/TextLinkBlock.tsx +++ b/src/components/TextLinkBlock.tsx @@ -5,7 +5,11 @@ import React, {memo, useMemo} from 'react'; import type {StyleProp, TextStyle} from 'react-native'; import {View} from 'react-native'; +import useEnvironment from '@hooks/useEnvironment'; import useThemeStyles from '@hooks/useThemeStyles'; +import {openLink as openLinkUtil} from '@userActions/Link'; +import CONST from '@src/CONST'; +import {PressableWithoutFeedback} from './Pressable'; import Text from './Text'; import TextLink from './TextLink'; import type {LinkProps, PressProps} from './TextLink'; @@ -23,10 +27,25 @@ type TextLinkBlockProps = (LinkProps | PressProps) & { function TextLinkBlock({text, style, prefixIcon, ...rest}: TextLinkBlockProps) { const words = useMemo(() => text.match(/(\S+\s*)/g) ?? [], [text]); + + const {environmentURL} = useEnvironment(); const styles = useThemeStyles(); + const openLink = () => { + if (!rest.href) { + return; + } + openLinkUtil(rest.href, environmentURL); + }; + return ( - <> + {words.map((word, index) => ( ))} - + ); } diff --git a/src/styles/utils/display.ts b/src/styles/utils/display.ts index 0f0166e135c9..dc2ee88fe68c 100644 --- a/src/styles/utils/display.ts +++ b/src/styles/utils/display.ts @@ -19,6 +19,14 @@ export default { display: 'none', }, + /** + * display: 'contents' - Supported in React Native 0.77+ + * Ref: https://reactnative.dev/blog/2025/01/21/version-0.77#simpler-layouts-with-display-contents + */ + dContents: { + display: 'contents', + }, + /** * Web-only style. */