diff --git a/src/components/AddPaymentMethodMenu.tsx b/src/components/AddPaymentMethodMenu.tsx index 25b6595a0296..3d9b649108ce 100644 --- a/src/components/AddPaymentMethodMenu.tsx +++ b/src/components/AddPaymentMethodMenu.tsx @@ -2,6 +2,7 @@ import type {RefObject} from 'react'; import React, {useEffect, useState} from 'react'; import type {View} from 'react-native'; import type {OnyxEntry} from 'react-native-onyx'; +import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; import {completePaymentOnboarding} from '@libs/actions/IOU'; @@ -13,6 +14,7 @@ import type {AnchorPosition} from '@src/styles'; import type {Report} from '@src/types/onyx'; import type AnchorAlignment from '@src/types/utils/AnchorAlignment'; import isLoadingOnyxValue from '@src/types/utils/isLoadingOnyxValue'; +// eslint-disable-next-line no-restricted-imports import * as Expensicons from './Icon/Expensicons'; import type {PaymentMethod} from './KYCWall/types'; import type BaseModalProps from './Modal/types'; @@ -57,6 +59,7 @@ function AddPaymentMethodMenu({ onItemSelected, shouldShowPersonalBankAccountOption = false, }: AddPaymentMethodMenuProps) { + const icons = useMemoizedLazyExpensifyIcons(['Building'] as const); const {translate} = useLocalize(); const [restoreFocusType, setRestoreFocusType] = useState(); const [session] = useOnyx(ONYXKEYS.SESSION, {canBeMissing: true}); @@ -116,7 +119,7 @@ function AddPaymentMethodMenu({ ? [ { text: translate('common.businessBankAccount'), - icon: Expensicons.Building, + icon: icons.Building, onSelected: () => { onItemSelected(CONST.PAYMENT_METHODS.BUSINESS_BANK_ACCOUNT); }, diff --git a/src/components/ApprovalWorkflowSection.tsx b/src/components/ApprovalWorkflowSection.tsx index 6a38eaec86f7..9f9c2c5a249f 100644 --- a/src/components/ApprovalWorkflowSection.tsx +++ b/src/components/ApprovalWorkflowSection.tsx @@ -1,6 +1,7 @@ import {Str} from 'expensify-common'; import React, {useCallback, useMemo} from 'react'; import {View} from 'react-native'; +import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useTheme from '@hooks/useTheme'; @@ -8,6 +9,7 @@ import useThemeStyles from '@hooks/useThemeStyles'; import {sortAlphabetically} from '@libs/OptionsListUtils'; import type ApprovalWorkflow from '@src/types/onyx/ApprovalWorkflow'; import Icon from './Icon'; +// eslint-disable-next-line no-restricted-imports import * as Expensicons from './Icon/Expensicons'; import MenuItem from './MenuItem'; import PressableWithoutFeedback from './Pressable/PressableWithoutFeedback'; @@ -22,6 +24,7 @@ type ApprovalWorkflowSectionProps = { }; function ApprovalWorkflowSection({approvalWorkflow, onPress}: ApprovalWorkflowSectionProps) { + const icons = useMemoizedLazyExpensifyIcons(['Users', 'UserCheck'] as const); const styles = useThemeStyles(); const theme = useTheme(); const {translate, toLocaleOrdinal, localeCompare} = useLocalize(); @@ -74,7 +77,7 @@ function ApprovalWorkflowSection({approvalWorkflow, onPress}: ApprovalWorkflowSe descriptionTextStyle={[styles.textNormalThemeText, styles.lineHeightXLarge]} description={members} numberOfLinesDescription={4} - icon={Expensicons.Users} + icon={icons.Users} iconHeight={20} iconWidth={20} iconFill={theme.icon} @@ -92,7 +95,7 @@ function ApprovalWorkflowSection({approvalWorkflow, onPress}: ApprovalWorkflowSe titleStyle={styles.textLabelSupportingNormal} descriptionTextStyle={[styles.textNormalThemeText, styles.lineHeightXLarge]} description={Str.removeSMSDomain(approver.displayName)} - icon={Expensicons.UserCheck} + icon={icons.UserCheck} iconHeight={20} iconWidth={20} numberOfLinesDescription={1} diff --git a/src/components/AttachmentPicker/index.native.tsx b/src/components/AttachmentPicker/index.native.tsx index d4cedd8f31ad..da69896bd446 100644 --- a/src/components/AttachmentPicker/index.native.tsx +++ b/src/components/AttachmentPicker/index.native.tsx @@ -8,11 +8,13 @@ import RNFetchBlob from 'react-native-blob-util'; import {launchImageLibrary} from 'react-native-image-picker'; import type {Asset, Callback, CameraOptions, ImageLibraryOptions, ImagePickerResponse} from 'react-native-image-picker'; import ImageSize from 'react-native-image-size'; +// eslint-disable-next-line no-restricted-imports import * as Expensicons from '@components/Icon/Expensicons'; import MenuItem from '@components/MenuItem'; import Popover from '@components/Popover'; import useArrowKeyFocusManager from '@hooks/useArrowKeyFocusManager'; import useKeyboardShortcut from '@hooks/useKeyboardShortcut'; +import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useStyleUtils from '@hooks/useStyleUtils'; @@ -123,6 +125,7 @@ function AttachmentPicker({ fileLimit = 1, onOpenPicker, }: AttachmentPickerProps) { + const icons = useMemoizedLazyExpensifyIcons(['Gallery', 'Paperclip'] as const); const styles = useThemeStyles(); const [isVisible, setIsVisible] = useState(false); const StyleUtils = useStyleUtils(); @@ -281,14 +284,14 @@ function AttachmentPicker({ const menuItemData: Item[] = useMemo(() => { const data: Item[] = [ { - icon: Expensicons.Paperclip, + icon: icons.Paperclip, textTranslationKey: 'attachmentPicker.chooseDocument', pickAttachment: showDocumentPicker, }, ]; if (!shouldHideGalleryOption) { data.unshift({ - icon: Expensicons.Gallery, + icon: icons.Gallery, textTranslationKey: 'attachmentPicker.chooseFromGallery', pickAttachment: () => showImagePicker(launchImageLibrary), }); @@ -302,7 +305,7 @@ function AttachmentPicker({ } return data; - }, [showDocumentPicker, shouldHideGalleryOption, shouldHideCameraOption, showImagePicker]); + }, [icons.Paperclip, icons.Gallery, showDocumentPicker, shouldHideGalleryOption, shouldHideCameraOption, showImagePicker]); const [focusedIndex, setFocusedIndex] = useArrowKeyFocusManager({initialFocusedIndex: -1, maxIndex: menuItemData.length - 1, isActive: isVisible}); diff --git a/src/components/Attachments/AttachmentView/DefaultAttachmentView/index.tsx b/src/components/Attachments/AttachmentView/DefaultAttachmentView/index.tsx index 2639c618cbc8..10d0d532862a 100644 --- a/src/components/Attachments/AttachmentView/DefaultAttachmentView/index.tsx +++ b/src/components/Attachments/AttachmentView/DefaultAttachmentView/index.tsx @@ -3,9 +3,9 @@ import type {StyleProp, ViewStyle} from 'react-native'; import {View} from 'react-native'; import ActivityIndicator from '@components/ActivityIndicator'; import Icon from '@components/Icon'; -import * as Expensicons from '@components/Icon/Expensicons'; import Text from '@components/Text'; import Tooltip from '@components/Tooltip'; +import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; @@ -34,6 +34,7 @@ type DefaultAttachmentViewProps = { }; function DefaultAttachmentView({fileName = '', shouldShowLoadingSpinnerIcon = false, shouldShowDownloadIcon, containerStyles, icon, isUploading, isDeleted}: DefaultAttachmentViewProps) { + const icons = useMemoizedLazyExpensifyIcons(['Download', 'Paperclip'] as const); const theme = useTheme(); const styles = useThemeStyles(); const {translate} = useLocalize(); @@ -43,7 +44,7 @@ function DefaultAttachmentView({fileName = '', shouldShowLoadingSpinnerIcon = fa @@ -53,7 +54,7 @@ function DefaultAttachmentView({fileName = '', shouldShowLoadingSpinnerIcon = fa diff --git a/src/components/Attachments/AttachmentView/index.tsx b/src/components/Attachments/AttachmentView/index.tsx index 71ab5c8b54fa..c74fa704e581 100644 --- a/src/components/Attachments/AttachmentView/index.tsx +++ b/src/components/Attachments/AttachmentView/index.tsx @@ -9,12 +9,14 @@ import Button from '@components/Button'; import DistanceEReceipt from '@components/DistanceEReceipt'; import EReceipt from '@components/EReceipt'; import Icon from '@components/Icon'; -import {ArrowCircleClockwise, Gallery} from '@components/Icon/Expensicons'; +// eslint-disable-next-line no-restricted-imports +import {ArrowCircleClockwise} from '@components/Icon/Expensicons'; import PerDiemEReceipt from '@components/PerDiemEReceipt'; import ScrollView from '@components/ScrollView'; import Text from '@components/Text'; import {usePlaybackContext} from '@components/VideoPlayerContexts/PlaybackContext'; import useFirstRenderRoute from '@hooks/useFirstRenderRoute'; +import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; import useOnyx from '@hooks/useOnyx'; @@ -131,6 +133,7 @@ function AttachmentView({ reportID, transaction: transactionProp, }: AttachmentViewProps) { + const icons = useMemoizedLazyExpensifyIcons(['Gallery'] as const); const [transactionFromOnyx] = useOnyx(`${ONYXKEYS.COLLECTION.TRANSACTION}${getNonEmptyStringOnyxID(transactionID)}`, {canBeMissing: true}); const transaction = transactionProp ?? transactionFromOnyx; const {translate} = useLocalize(); @@ -311,7 +314,7 @@ function AttachmentView({ <> { const menuItems: MenuItem[] = [ { - icon: Expensicons.Upload, + icon: icons.Upload, text: translate('avatarWithImagePicker.uploadPhoto'), onSelected: () => { if (isSafari()) { diff --git a/src/components/DatePicker/index.tsx b/src/components/DatePicker/index.tsx index 0562e558e6dc..bbc9f4eeda8b 100644 --- a/src/components/DatePicker/index.tsx +++ b/src/components/DatePicker/index.tsx @@ -1,9 +1,9 @@ import {format, setYear} from 'date-fns'; import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react'; import {InteractionManager, View} from 'react-native'; -import * as Expensicons from '@components/Icon/Expensicons'; import TextInput from '@components/TextInput'; import type {BaseTextInputRef} from '@components/TextInput/BaseTextInput/types'; +import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import useWindowDimensions from '@hooks/useWindowDimensions'; @@ -33,6 +33,7 @@ function DatePicker({ shouldHideClearButton = false, ref, }: DateInputWithPickerProps) { + const icons = useMemoizedLazyExpensifyIcons(['Calendar'] as const); const styles = useThemeStyles(); const {windowHeight, windowWidth} = useWindowDimensions(); const {translate} = useLocalize(); @@ -127,7 +128,7 @@ function DatePicker({ ref={mergeRefs(ref, textInputRef)} inputID={inputID} forceActiveLabel - icon={selectedDate ? null : Expensicons.Calendar} + icon={selectedDate ? null : icons.Calendar} iconContainerStyle={styles.pr0} label={label} accessibilityLabel={label} diff --git a/src/components/Domain/DomainMenuItem.tsx b/src/components/Domain/DomainMenuItem.tsx index 0af6c5e5f8ee..f34291532b11 100644 --- a/src/components/Domain/DomainMenuItem.tsx +++ b/src/components/Domain/DomainMenuItem.tsx @@ -1,10 +1,12 @@ import React from 'react'; import Icon from '@components/Icon'; +// eslint-disable-next-line no-restricted-imports import * as Expensicons from '@components/Icon/Expensicons'; import type {OfflineWithFeedbackProps} from '@components/OfflineWithFeedback'; import OfflineWithFeedback from '@components/OfflineWithFeedback'; import type {PopoverMenuItem} from '@components/PopoverMenu'; import {PressableWithoutFeedback} from '@components/Pressable'; +import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; @@ -42,6 +44,7 @@ type DomainItem = { } & Pick; function DomainMenuItem({item, index}: DomainMenuItemProps) { + const icons = useMemoizedLazyExpensifyIcons(['NewWindow'] as const); const styles = useThemeStyles(); const {translate} = useLocalize(); const {isAdmin, isValidated} = item; @@ -85,7 +88,7 @@ function DomainMenuItem({item, index}: DomainMenuItemProps) { rightIcon={ isValidated ? ( diff --git a/src/components/EReceiptThumbnail.tsx b/src/components/EReceiptThumbnail.tsx index 3a93dff269fb..f6515de9aa99 100644 --- a/src/components/EReceiptThumbnail.tsx +++ b/src/components/EReceiptThumbnail.tsx @@ -1,6 +1,7 @@ import React from 'react'; import {View} from 'react-native'; import useEReceipt from '@hooks/useEReceipt'; +import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; import useOnyx from '@hooks/useOnyx'; import useStyleUtils from '@hooks/useStyleUtils'; import useThemeStyles from '@hooks/useThemeStyles'; @@ -10,6 +11,7 @@ import colors from '@styles/theme/colors'; import variables from '@styles/variables'; import ONYXKEYS from '@src/ONYXKEYS'; import Icon from './Icon'; +// eslint-disable-next-line no-restricted-imports import * as Expensicons from './Icon/Expensicons'; import ImageSVG from './ImageSVG'; import Text from './Text'; @@ -37,6 +39,7 @@ type EReceiptThumbnailProps = { }; function EReceiptThumbnail({transactionID, borderRadius, fileExtension, isReceiptThumbnail = false, centerIconV = true, iconSize = 'large'}: EReceiptThumbnailProps) { + const icons = useMemoizedLazyExpensifyIcons(['CalendarSolid'] as const); const styles = useThemeStyles(); const StyleUtils = useStyleUtils(); const [transaction] = useOnyx(`${ONYXKEYS.COLLECTION.TRANSACTION}${getNonEmptyStringOnyxID(transactionID)}`, { @@ -112,7 +115,7 @@ function EReceiptThumbnail({transactionID, borderRadius, fileExtension, isReceip )} {isPerDiemRequest ? ( ) { + const icons = useMemoizedLazyExpensifyIcons(['Document', 'GalleryNotFound'] as const); const styles = useThemeStyles(); const {translate} = useLocalize(); @@ -65,7 +66,7 @@ function ImageRenderer({tnode}: CustomRendererProps) { const imagePreviewModalDisabled = htmlAttribs['data-expensify-preview-modal-disabled'] === 'true'; const fileType = getFileType(attachmentSourceAttribute); - const fallbackIcon = fileType === CONST.ATTACHMENT_FILE_TYPE.FILE ? Document : GalleryNotFound; + const fallbackIcon = fileType === CONST.ATTACHMENT_FILE_TYPE.FILE ? icons.Document : icons.GalleryNotFound; const theme = useTheme(); let fileName = htmlAttribs[CONST.ATTACHMENT_ORIGINAL_FILENAME_ATTRIBUTE] || getFileName(`${isAttachmentOrReceipt ? attachmentSourceAttribute : htmlAttribs.src}`); diff --git a/src/components/HeaderWithBackButton/index.tsx b/src/components/HeaderWithBackButton/index.tsx index 8df34b97933a..68d9a99b4644 100755 --- a/src/components/HeaderWithBackButton/index.tsx +++ b/src/components/HeaderWithBackButton/index.tsx @@ -6,6 +6,7 @@ import Avatar from '@components/Avatar'; import AvatarWithDisplayName from '@components/AvatarWithDisplayName'; import Header from '@components/Header'; import Icon from '@components/Icon'; +// eslint-disable-next-line no-restricted-imports import * as Expensicons from '@components/Icon/Expensicons'; import PinButton from '@components/PinButton'; import PressableWithoutFeedback from '@components/Pressable/PressableWithoutFeedback'; @@ -13,6 +14,7 @@ import SearchButton from '@components/Search/SearchRouter/SearchButton'; import HelpButton from '@components/SidePanel/HelpComponents/HelpButton'; import ThreeDotsMenu from '@components/ThreeDotsMenu'; import Tooltip from '@components/Tooltip'; +import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useStyleUtils from '@hooks/useStyleUtils'; import useTheme from '@hooks/useTheme'; @@ -73,6 +75,7 @@ function HeaderWithBackButton({ shouldMinimizeMenuButton = false, openParentReportInCurrentTab = false, }: HeaderWithBackButtonProps) { + const icons = useMemoizedLazyExpensifyIcons(['Download'] as const); const theme = useTheme(); const styles = useThemeStyles(); const StyleUtils = useStyleUtils(); @@ -269,7 +272,7 @@ function HeaderWithBackButton({ accessibilityLabel={translate('common.download')} > diff --git a/src/components/ImportOnyxState/BaseImportOnyxState.tsx b/src/components/ImportOnyxState/BaseImportOnyxState.tsx index ca5a5104c9fa..d34e189dc88f 100644 --- a/src/components/ImportOnyxState/BaseImportOnyxState.tsx +++ b/src/components/ImportOnyxState/BaseImportOnyxState.tsx @@ -1,8 +1,8 @@ import React from 'react'; import AttachmentPicker from '@components/AttachmentPicker'; import DecisionModal from '@components/DecisionModal'; -import * as Expensicons from '@components/Icon/Expensicons'; import MenuItem from '@components/MenuItem'; +import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useThemeStyles from '@hooks/useThemeStyles'; @@ -17,6 +17,7 @@ function BaseImportOnyxState({ isErrorModalVisible: boolean; setIsErrorModalVisible: (value: boolean) => void; }) { + const icons = useMemoizedLazyExpensifyIcons(['Upload'] as const); const {translate} = useLocalize(); const styles = useThemeStyles(); @@ -34,7 +35,7 @@ function BaseImportOnyxState({ {({openPicker}) => { return ( { diff --git a/src/components/ImportSpreadsheet.tsx b/src/components/ImportSpreadsheet.tsx index 3e9e77000761..b66ac37fecb9 100644 --- a/src/components/ImportSpreadsheet.tsx +++ b/src/components/ImportSpreadsheet.tsx @@ -2,6 +2,7 @@ import React, {useRef, useState} from 'react'; import {PanResponder, PixelRatio, Platform, View} from 'react-native'; import RNFetchBlob from 'react-native-blob-util'; import type {TupleToUnion} from 'type-fest'; +import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useThemeStyles from '@hooks/useThemeStyles'; @@ -20,7 +21,6 @@ import DragAndDropConsumer from './DragAndDrop/Consumer'; import DragAndDropProvider from './DragAndDrop/Provider'; import FilePicker from './FilePicker'; import HeaderWithBackButton from './HeaderWithBackButton'; -import * as Expensicons from './Icon/Expensicons'; import ImageSVG from './ImageSVG'; import RenderHTML from './RenderHTML'; import ScreenWrapper from './ScreenWrapper'; @@ -38,6 +38,7 @@ type ImportSpreadsheetProps = { }; function ImportSpreadsheet({backTo, goTo, isImportingMultiLevelTags}: ImportSpreadsheetProps) { + const icons = useMemoizedLazyExpensifyIcons(['SpreadsheetComputer'] as const); const styles = useThemeStyles(); const {translate} = useLocalize(); const [isReadingFile, setIsReadingFile] = useState(false); @@ -151,7 +152,7 @@ function ImportSpreadsheet({backTo, goTo, isImportingMultiLevelTags}: ImportSpre <> setFileTopPosition(PixelRatio.roundToNearestPixel((nativeEvent.layout as DOMRect).top))}> { clearBookingDraft(); @@ -98,7 +100,7 @@ function OnboardingHelpDropdownButton({reportID, shouldUseNarrowLayout, shouldSh text: translate('common.reschedule'), value: CONST.ONBOARDING_HELP.RESCHEDULE, onSelected: () => rescheduleBooking(latestScheduledCall), - icon: CalendarSolid, + icon: icons.CalendarSolid, }); options.push({ text: translate('common.cancel'), diff --git a/src/components/ReceiptAlternativeMethods.tsx b/src/components/ReceiptAlternativeMethods.tsx index 805f962ec54b..7a38ff5b127c 100644 --- a/src/components/ReceiptAlternativeMethods.tsx +++ b/src/components/ReceiptAlternativeMethods.tsx @@ -4,6 +4,7 @@ import type {LayoutChangeEvent} from 'react-native'; import useEnvironment from '@hooks/useEnvironment'; import useHasLoggedIntoMobileApp from '@hooks/useHasLoggedIntoMobileApp'; import useHasPhoneNumberLogin from '@hooks/useHasPhoneNumberLogin'; +import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; @@ -11,7 +12,8 @@ import CONST from '@src/CONST'; import {addLeadingForwardSlash} from '@src/libs/Url'; import ROUTES from '@src/ROUTES'; import Icon from './Icon'; -import {ChatBubbles, Download, Mail} from './Icon/Expensicons'; +// eslint-disable-next-line no-restricted-imports +import {ChatBubbles, Mail} from './Icon/Expensicons'; import RenderHTML from './RenderHTML'; import Text from './Text'; @@ -20,6 +22,7 @@ type ReceiptAlternativeMethodsProps = { }; function ReceiptAlternativeMethods({onLayout}: ReceiptAlternativeMethodsProps) { + const icons = useMemoizedLazyExpensifyIcons(['Download'] as const); const styles = useThemeStyles(); const theme = useTheme(); const {environmentURL} = useEnvironment(); @@ -45,7 +48,7 @@ function ReceiptAlternativeMethods({onLayout}: ReceiptAlternativeMethodsProps) { {translate('search.moneyRequestReport.emptyStateTitle')} diff --git a/src/components/ReportActionItem/TransactionPreview/TransactionPreviewContent.tsx b/src/components/ReportActionItem/TransactionPreview/TransactionPreviewContent.tsx index 76a9ed9fd268..990ef95673ad 100644 --- a/src/components/ReportActionItem/TransactionPreview/TransactionPreviewContent.tsx +++ b/src/components/ReportActionItem/TransactionPreview/TransactionPreviewContent.tsx @@ -3,7 +3,8 @@ import React, {useMemo} from 'react'; import {View} from 'react-native'; import Button from '@components/Button'; import Icon from '@components/Icon'; -import {DotIndicator, Folder, Tag} from '@components/Icon/Expensicons'; +// eslint-disable-next-line no-restricted-imports +import {DotIndicator} from '@components/Icon/Expensicons'; import OfflineWithFeedback from '@components/OfflineWithFeedback'; import ReportActionAvatars from '@components/ReportActionAvatars'; import ReportActionItemImages from '@components/ReportActionItem/ReportActionItemImages'; @@ -11,6 +12,7 @@ import UserInfoCellsWithArrow from '@components/SelectionListWithSections/Search import Text from '@components/Text'; import TransactionPreviewSkeletonView from '@components/TransactionPreviewSkeletonView'; import useEnvironment from '@hooks/useEnvironment'; +import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; import useReportIsArchived from '@hooks/useReportIsArchived'; @@ -60,6 +62,7 @@ function TransactionPreviewContent({ navigateToReviewFields, isReviewDuplicateTransactionPage = false, }: TransactionPreviewContentProps) { + const icons = useMemoizedLazyExpensifyIcons(['Folder', 'Tag'] as const); const theme = useTheme(); const styles = useThemeStyles(); const {translate} = useLocalize(); @@ -327,7 +330,7 @@ function TransactionPreviewContent({ ]} > clearAvatarErrors(report.reportID)} style={[styles.w100, styles.mb3, styles.alignItemsStart, styles.sectionMenuItemTopDescription]} type={icon.type} - editorMaskImage={Expensicons.ImageCropSquareMask} + editorMaskImage={expensifyIcons.ImageCropSquareMask} name={icon.name} /> ); diff --git a/src/components/SelectionListWithSections/SplitListItem.tsx b/src/components/SelectionListWithSections/SplitListItem.tsx index ab327b30c784..f5b7c09d23ca 100644 --- a/src/components/SelectionListWithSections/SplitListItem.tsx +++ b/src/components/SelectionListWithSections/SplitListItem.tsx @@ -1,12 +1,13 @@ import React, {useCallback, useLayoutEffect, useRef, useState} from 'react'; import {View} from 'react-native'; import Icon from '@components/Icon'; -import {Folder, Tag} from '@components/Icon/Expensicons'; +// eslint-disable-next-line no-restricted-imports import * as Expensicons from '@components/Icon/Expensicons'; import MoneyRequestAmountInput from '@components/MoneyRequestAmountInput'; import Text from '@components/Text'; import type {BaseTextInputRef} from '@components/TextInput/BaseTextInput/types'; import useAnimatedHighlightStyle from '@hooks/useAnimatedHighlightStyle'; +import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; import useScreenWrapperTransitionStatus from '@hooks/useScreenWrapperTransitionStatus'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; @@ -31,6 +32,7 @@ function SplitListItem({ onInputFocus, onInputBlur, }: SplitListItemProps) { + const icons = useMemoizedLazyExpensifyIcons(['Folder', 'Tag'] as const); const theme = useTheme(); const styles = useThemeStyles(); const {didScreenTransitionEnd} = useScreenWrapperTransitionStatus(); @@ -130,7 +132,7 @@ function SplitListItem({ {!!splitItem.category && ( ({ {!!splitItem.tags?.at(0) && ( { const buttonOptions = []; - const paymentMethods = getSettlementButtonPaymentMethods(hasActivatedWallet, translate); + const paymentMethods = getSettlementButtonPaymentMethods(icons, hasActivatedWallet, translate); const shortFormPayElsewhereButton = { text: translate('iou.pay'), @@ -299,7 +303,7 @@ function SettlementButton({ const policyName = activePolicy.name; buttonOptions.push({ text: translate('iou.payWithPolicy', {policyName: truncate(policyName, {length: CONST.ADDITIONAL_ALLOWED_CHARACTERS}), formattedAmount: ''}), - icon: Expensicons.Building, + icon: icons.Building, value: activePolicy.id, shouldUpdateSelectedIndex: false, }); @@ -346,14 +350,14 @@ function SettlementButton({ if (isIndividualInvoiceRoomUtil(chatReport)) { buttonOptions.push({ text: translate('iou.settlePersonal', {formattedAmount}), - icon: Expensicons.User, + icon: icons.User, value: hasIntentToPay ? CONST.IOU.PAYMENT_TYPE.EXPENSIFY : (lastPaymentMethod ?? CONST.IOU.PAYMENT_TYPE.ELSEWHERE), backButtonText: translate('iou.individual'), subMenuItems: getInvoicesOptions(false), }); buttonOptions.push({ text: translate('iou.settleBusiness', {formattedAmount}), - icon: Expensicons.Building, + icon: icons.Building, value: hasIntentToPay ? CONST.IOU.PAYMENT_TYPE.EXPENSIFY : (lastPaymentMethod ?? CONST.IOU.PAYMENT_TYPE.ELSEWHERE), backButtonText: translate('iou.business'), subMenuItems: getInvoicesOptions(true), diff --git a/src/components/TabSelector/TabSelector.tsx b/src/components/TabSelector/TabSelector.tsx index 2bfc66b990cd..ed1be0c80664 100644 --- a/src/components/TabSelector/TabSelector.tsx +++ b/src/components/TabSelector/TabSelector.tsx @@ -3,9 +3,11 @@ import {TabActions} from '@react-navigation/native'; import React, {useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState} from 'react'; import {View} from 'react-native'; import FocusTrapContainerElement from '@components/FocusTrap/FocusTrapContainerElement'; +// eslint-disable-next-line no-restricted-imports import * as Expensicons from '@components/Icon/Expensicons'; import type {LocaleContextProps} from '@components/LocaleContextProvider'; import useIsResizing from '@hooks/useIsResizing'; +import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; @@ -41,7 +43,7 @@ type IconTitleAndTestID = { testID?: string; }; -function getIconTitleAndTestID(route: string, translate: LocaleContextProps['translate']): IconTitleAndTestID { +function getIconTitleAndTestID(icons: Record<'CalendarSolid' | 'UploadAlt' | 'User', IconAsset>, route: string, translate: LocaleContextProps['translate']): IconTitleAndTestID { switch (route) { case CONST.TAB.RECEIPT_PARTNERS.ALL: return {title: translate('workspace.receiptPartners.uber.all'), testID: 'all'}; @@ -54,17 +56,17 @@ function getIconTitleAndTestID(route: string, translate: LocaleContextProps['tra case CONST.TAB_REQUEST.SCAN: return {icon: Expensicons.ReceiptScan, title: translate('tabSelector.scan'), testID: 'scan'}; case CONST.TAB.NEW_CHAT: - return {icon: Expensicons.User, title: translate('tabSelector.chat'), testID: 'chat'}; + return {icon: icons.User, title: translate('tabSelector.chat'), testID: 'chat'}; case CONST.TAB.NEW_ROOM: return {icon: Expensicons.Hashtag, title: translate('tabSelector.room'), testID: 'room'}; case CONST.TAB_REQUEST.DISTANCE: return {icon: Expensicons.Car, title: translate('common.distance'), testID: 'distance'}; case CONST.TAB.SHARE.SHARE: - return {icon: Expensicons.UploadAlt, title: translate('common.share'), testID: 'share'}; + return {icon: icons.UploadAlt, title: translate('common.share'), testID: 'share'}; case CONST.TAB.SHARE.SUBMIT: return {icon: Expensicons.Receipt, title: translate('common.submit'), testID: 'submit'}; case CONST.TAB_REQUEST.PER_DIEM: - return {icon: Expensicons.CalendarSolid, title: translate('common.perDiem'), testID: 'perDiem'}; + return {icon: icons.CalendarSolid, title: translate('common.perDiem'), testID: 'perDiem'}; case CONST.TAB_REQUEST.DISTANCE_MAP: return {icon: Expensicons.Map, title: translate('tabSelector.map'), testID: 'distanceMap'}; case CONST.TAB_REQUEST.DISTANCE_MANUAL: @@ -85,6 +87,7 @@ function TabSelector({ renderProductTrainingTooltip, equalWidth = false, }: TabSelectorProps) { + const icons = useMemoizedLazyExpensifyIcons(['CalendarSolid', 'UploadAlt', 'User'] as const); const {translate} = useLocalize(); const theme = useTheme(); const styles = useThemeStyles(); @@ -137,7 +140,7 @@ function TabSelector({ const activeOpacity = getOpacity({routesLength: state.routes.length, tabIndex: index, active: true, affectedTabs: affectedAnimatedTabs, position, isActive}); const inactiveOpacity = getOpacity({routesLength: state.routes.length, tabIndex: index, active: false, affectedTabs: affectedAnimatedTabs, position, isActive}); const backgroundColor = getBackgroundColor({routesLength: state.routes.length, tabIndex: index, affectedTabs: affectedAnimatedTabs, theme, position, isActive}); - const {icon, title, testID} = getIconTitleAndTestID(route.name, translate); + const {icon, title, testID} = getIconTitleAndTestID(icons, route.name, translate); const onPress = () => { if (isActive) { return; diff --git a/src/components/ThumbnailImage.tsx b/src/components/ThumbnailImage.tsx index 3e5f521e2daf..5631c08a4e7a 100644 --- a/src/components/ThumbnailImage.tsx +++ b/src/components/ThumbnailImage.tsx @@ -1,6 +1,7 @@ import React, {useCallback, useEffect, useState} from 'react'; import type {ImageSourcePropType, StyleProp, ViewStyle} from 'react-native'; import {View} from 'react-native'; +import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; import useNetwork from '@hooks/useNetwork'; import useStyleUtils from '@hooks/useStyleUtils'; import useTheme from '@hooks/useTheme'; @@ -13,6 +14,7 @@ import type {Dimensions} from '@src/types/utils/Layout'; import AttachmentDeletedIndicator from './AttachmentDeletedIndicator'; import type {FullScreenLoadingIndicatorIconSize} from './FullscreenLoadingIndicator'; import Icon from './Icon'; +// eslint-disable-next-line no-restricted-imports import * as Expensicons from './Icon/Expensicons'; import type {ImageObjectPosition} from './Image/types'; import ImageWithSizeCalculation from './ImageWithSizeCalculation'; @@ -87,7 +89,7 @@ function ThumbnailImage({ imageHeight = 200, shouldDynamicallyResize = true, loadingIconSize, - fallbackIcon = Expensicons.Gallery, + fallbackIcon, fallbackIconSize = variables.iconSizeSuperLarge, fallbackIconColor, fallbackIconBackground, @@ -98,6 +100,7 @@ function ThumbnailImage({ loadingIndicatorStyles, onLoad, }: ThumbnailImageProps) { + const icons = useMemoizedLazyExpensifyIcons(['Gallery'] as const); const styles = useThemeStyles(); const theme = useTheme(); const {isOffline} = useNetwork(); @@ -143,7 +146,7 @@ function ThumbnailImage({ diff --git a/src/components/VideoPlayerContexts/VideoPopoverMenuContext.tsx b/src/components/VideoPlayerContexts/VideoPopoverMenuContext.tsx index ff4a349f898e..8481f5668dc0 100644 --- a/src/components/VideoPlayerContexts/VideoPopoverMenuContext.tsx +++ b/src/components/VideoPlayerContexts/VideoPopoverMenuContext.tsx @@ -1,7 +1,9 @@ import React, {useCallback, useContext, useMemo, useRef, useState} from 'react'; +// eslint-disable-next-line no-restricted-imports import * as Expensicons from '@components/Icon/Expensicons'; import type {PopoverMenuItem} from '@components/PopoverMenu'; import type {VideoWithOnFullScreenUpdate} from '@components/VideoPlayer/types'; +import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; import addEncryptedAuthTokenToURL from '@libs/addEncryptedAuthTokenToURL'; @@ -13,6 +15,7 @@ import type {PlaybackSpeed, VideoPopoverMenuContext} from './types'; const Context = React.createContext(null); function VideoPopoverMenuContextProvider({children}: ChildrenProps) { + const icons = useMemoizedLazyExpensifyIcons(['Download'] as const); const {translate} = useLocalize(); const [source, setSource] = useState(''); const [currentPlaybackSpeed, setCurrentPlaybackSpeed] = useState(CONST.VIDEO_PLAYER.PLAYBACK_SPEEDS[3]); @@ -41,7 +44,7 @@ function VideoPopoverMenuContextProvider({children}: ChildrenProps) { if (!isOffline && !isLocalFile) { // eslint-disable-next-line react-compiler/react-compiler items.push({ - icon: Expensicons.Download, + icon: icons.Download, text: translate('common.download'), onSelected: () => { downloadAttachment(); @@ -63,7 +66,7 @@ function VideoPopoverMenuContextProvider({children}: ChildrenProps) { })), }); return items; - }, [currentPlaybackSpeed, downloadAttachment, translate, updatePlaybackSpeed, isOffline, isLocalFile]); + }, [icons.Download, currentPlaybackSpeed, downloadAttachment, translate, updatePlaybackSpeed, isOffline, isLocalFile]); const contextValue = useMemo( () => ({menuItems, videoPopoverMenuPlayerRef, currentPlaybackSpeed, updatePlaybackSpeed, setCurrentPlaybackSpeed, setSource}), diff --git a/src/components/WorkspaceConfirmationForm.tsx b/src/components/WorkspaceConfirmationForm.tsx index bb6107047b9c..650c0da1a595 100644 --- a/src/components/WorkspaceConfirmationForm.tsx +++ b/src/components/WorkspaceConfirmationForm.tsx @@ -2,6 +2,7 @@ import React, {useCallback, useEffect, useMemo, useState} from 'react'; import {View} from 'react-native'; import useAutoFocusInput from '@hooks/useAutoFocusInput'; import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; +import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; import useThemeStyles from '@hooks/useThemeStyles'; @@ -25,6 +26,7 @@ import FormProvider from './Form/FormProvider'; import InputWrapper from './Form/InputWrapper'; import type {FormInputErrors, FormOnyxValues} from './Form/types'; import HeaderWithBackButton from './HeaderWithBackButton'; +// eslint-disable-next-line no-restricted-imports import * as Expensicons from './Icon/Expensicons'; import ScrollView from './ScrollView'; import Text from './Text'; @@ -55,6 +57,7 @@ type WorkspaceConfirmationFormProps = { }; function WorkspaceConfirmationForm({onSubmit, policyOwnerEmail = '', onBackButtonPress = () => Navigation.goBack(), addBottomSafeAreaPadding = true}: WorkspaceConfirmationFormProps) { + const icons = useMemoizedLazyExpensifyIcons(['ImageCropSquareMask'] as const); const styles = useThemeStyles(); const {translate} = useLocalize(); const {inputCallbackRef} = useAutoFocusInput(); @@ -147,7 +150,7 @@ function WorkspaceConfirmationForm({onSubmit, policyOwnerEmail = '', onBackButto type={CONST.ICON_TYPE_WORKSPACE} style={[styles.w100, styles.alignItemsCenter, styles.mv4, styles.mb6, styles.alignSelfCenter, styles.ph5]} DefaultAvatar={DefaultAvatar} - editorMaskImage={Expensicons.ImageCropSquareMask} + editorMaskImage={icons.ImageCropSquareMask} /> void}) => void; @@ -30,6 +32,7 @@ type UseAvatarMenuParams = { * Custom hook to create avatar menu items */ function useAvatarMenu({shouldHideAvatarEdit, accountID, onImageRemoved, showAvatarCropModal, clearError, source, originalFileName}: UseAvatarMenuParams) { + const icons = useMemoizedLazyExpensifyIcons(['Upload'] as const); const {translate} = useLocalize(); const attachmentContext = useContext(AttachmentModalContext); @@ -40,7 +43,7 @@ function useAvatarMenu({shouldHideAvatarEdit, accountID, onImageRemoved, showAva (openPicker: OpenPicker): Array> => { const menuItems: Array> = [ { - icon: Expensicons.Upload, + icon: icons.Upload, text: translate('avatarWithImagePicker.uploadPhoto'), onSelected: () => { openPicker({ @@ -79,7 +82,7 @@ function useAvatarMenu({shouldHideAvatarEdit, accountID, onImageRemoved, showAva }, ]; }, - [translate, shouldHideAvatarEdit, source, showAvatarCropModal, clearError, onImageRemoved, attachmentContext, originalFileName, accountID], + [icons.Upload, translate, shouldHideAvatarEdit, source, showAvatarCropModal, clearError, onImageRemoved, attachmentContext, originalFileName, accountID], ); return {createMenuItems}; diff --git a/src/hooks/useBulkPayOptions.ts b/src/hooks/useBulkPayOptions.ts index 5c9d0de7a978..9a197bad3bdd 100644 --- a/src/hooks/useBulkPayOptions.ts +++ b/src/hooks/useBulkPayOptions.ts @@ -1,7 +1,8 @@ import truncate from 'lodash/truncate'; import {useCallback, useMemo} from 'react'; import type {TupleToUnion} from 'type-fest'; -import {Bank, Building, Cash, User, Wallet} from '@components/Icon/Expensicons'; +// eslint-disable-next-line no-restricted-imports +import {Bank, Cash, Wallet} from '@components/Icon/Expensicons'; import type {PopoverMenuItem} from '@components/PopoverMenu'; import type {BankAccountMenuItem} from '@components/Search/types'; import {isCurrencySupportedForDirectReimbursement} from '@libs/actions/Policy/Policy'; @@ -20,6 +21,7 @@ import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type {AccountData, Policy} from '@src/types/onyx'; import useCurrentUserPersonalDetails from './useCurrentUserPersonalDetails'; +import {useMemoizedLazyExpensifyIcons} from './useLazyAsset'; import useLocalize from './useLocalize'; import useOnyx from './useOnyx'; import usePolicy from './usePolicy'; @@ -53,6 +55,7 @@ function useBulkPayOptions({ currency, formattedAmount, }: UseBulkPayOptionProps): UseBulkPayOptionReturnType { + const icons = useMemoizedLazyExpensifyIcons(['Building', 'User'] as const); const {translate} = useLocalize(); const styles = useThemeStyles(); const {accountID} = useCurrentUserPersonalDetails(); @@ -128,7 +131,7 @@ function useBulkPayOptions({ const bulkPayButtonOptions = useMemo(() => { const buttonOptions = []; - const paymentMethods = getSettlementButtonPaymentMethods(hasActivatedWallet, translate); + const paymentMethods = getSettlementButtonPaymentMethods(icons, hasActivatedWallet, translate); if (!selectedReportID || !selectedPolicyID) { return undefined; @@ -159,7 +162,7 @@ function useBulkPayOptions({ const policyName = activePolicy.name; buttonOptions.push({ text: translate('iou.payWithPolicy', {policyName: truncate(policyName, {length: CONST.ADDITIONAL_ALLOWED_CHARACTERS}), formattedAmount: ''}), - icon: Building, + icon: icons.Building, key: activePolicy.id, shouldUpdateSelectedIndex: false, }); @@ -198,13 +201,13 @@ function useBulkPayOptions({ if (isIndividualInvoiceRoomUtil(chatReport)) { buttonOptions.push({ text: translate('iou.settlePersonal', {formattedAmount}), - icon: User, + icon: icons.User, backButtonText: translate('iou.individual'), subMenuItems: getInvoicesOptions(false), }); buttonOptions.push({ text: translate('iou.settleBusiness', {formattedAmount}), - icon: Building, + icon: icons.Building, backButtonText: translate('iou.business'), subMenuItems: getInvoicesOptions(true), }); @@ -217,6 +220,7 @@ function useBulkPayOptions({ return buttonOptions; }, [ hasActivatedWallet, + icons, translate, selectedReportID, selectedPolicyID, diff --git a/src/hooks/usePaymentOptions.ts b/src/hooks/usePaymentOptions.ts index ca9a3edbc911..837a7940feea 100644 --- a/src/hooks/usePaymentOptions.ts +++ b/src/hooks/usePaymentOptions.ts @@ -1,6 +1,7 @@ import {useCallback, useEffect, useMemo, useRef} from 'react'; import type {OnyxEntry} from 'react-native-onyx'; import type {TupleToUnion} from 'type-fest'; +// eslint-disable-next-line no-restricted-imports import * as Expensicons from '@components/Icon/Expensicons'; import type SettlementButtonProps from '@components/SettlementButton/types'; import type {PaymentOrApproveOption} from '@libs/PaymentUtils'; @@ -21,6 +22,7 @@ import type {BankAccountList, FundList, LastPaymentMethod} from '@src/types/onyx import {getEmptyObject, isEmptyObject} from '@src/types/utils/EmptyObject'; import isLoadingOnyxValue from '@src/types/utils/isLoadingOnyxValue'; import useCurrentUserPersonalDetails from './useCurrentUserPersonalDetails'; +import {useMemoizedLazyExpensifyIcons} from './useLazyAsset'; import useLocalize from './useLocalize'; import useOnyx from './useOnyx'; import usePolicy from './usePolicy'; @@ -59,6 +61,7 @@ function usePaymentOptions({ shouldDisableApproveButton = false, onlyShowPayElsewhere, }: UsePaymentOptionsProps): PaymentOrApproveOption[] { + const icons = useMemoizedLazyExpensifyIcons(['Building', 'User'] as const); const styles = useThemeStyles(); const {translate} = useLocalize(); const policy = usePolicy(policyID); @@ -121,7 +124,7 @@ function usePaymentOptions({ }, [CONST.IOU.PAYMENT_TYPE.VBBA]: { text: translate('iou.settleBusiness', {formattedAmount}), - icon: Expensicons.Building, + icon: icons.Building, value: CONST.IOU.PAYMENT_TYPE.VBBA, }, [CONST.IOU.PAYMENT_TYPE.ELSEWHERE]: { @@ -184,7 +187,7 @@ function usePaymentOptions({ if (isIndividualInvoiceRoomUtil(chatReport)) { buttonOptions.push({ text: translate('iou.settlePersonal', {formattedAmount}), - icon: Expensicons.User, + icon: icons.User, value: CONST.IOU.PAYMENT_TYPE.ELSEWHERE, backButtonText: translate('iou.individual'), subMenuItems: [ @@ -202,7 +205,7 @@ function usePaymentOptions({ buttonOptions.push({ text: translate('iou.settleBusiness', {formattedAmount}), - icon: Expensicons.Building, + icon: icons.Building, value: CONST.IOU.PAYMENT_TYPE.ELSEWHERE, backButtonText: translate('iou.business'), subMenuItems: [ diff --git a/src/hooks/useSearchTypeMenuSections.ts b/src/hooks/useSearchTypeMenuSections.ts index 847c3e99a53b..bccb282f0429 100644 --- a/src/hooks/useSearchTypeMenuSections.ts +++ b/src/hooks/useSearchTypeMenuSections.ts @@ -9,6 +9,7 @@ import ONYXKEYS from '@src/ONYXKEYS'; import type {PersonalDetails, Policy, Session} from '@src/types/onyx'; import useCardFeedsForDisplay from './useCardFeedsForDisplay'; import useCreateEmptyReportConfirmation from './useCreateEmptyReportConfirmation'; +import {useMemoizedLazyExpensifyIcons} from './useLazyAsset'; import useNetwork from './useNetwork'; import useOnyx from './useOnyx'; import usePermissions from './usePermissions'; @@ -47,6 +48,7 @@ const currentUserLoginAndAccountIDSelector = (session: OnyxEntry) => ({ const useSearchTypeMenuSections = () => { const {defaultCardFeed, cardFeedsByPolicy, defaultExpensifyCard} = useCardFeedsForDisplay(); + const icons = useMemoizedLazyExpensifyIcons(['Document'] as const); const {isOffline} = useNetwork(); const [allPolicies] = useOnyx(ONYXKEYS.COLLECTION.POLICY, {selector: policiesSelector, canBeMissing: true}); const [currentUserLoginAndAccountID] = useOnyx(ONYXKEYS.SESSION, {selector: currentUserLoginAndAccountIDSelector, canBeMissing: false}); @@ -116,6 +118,7 @@ const useSearchTypeMenuSections = () => { const typeMenuSections = useMemo( () => createTypeMenuSections( + icons, currentUserLoginAndAccountID?.email, currentUserLoginAndAccountID?.accountID, cardFeedsByPolicy, @@ -142,6 +145,7 @@ const useSearchTypeMenuSections = () => { isASAPSubmitBetaEnabled, hasViolations, createReportWithConfirmation, + icons, ], ); diff --git a/src/libs/Navigation/DebugTabNavigator.tsx b/src/libs/Navigation/DebugTabNavigator.tsx index a0673436de10..5663fa249f63 100644 --- a/src/libs/Navigation/DebugTabNavigator.tsx +++ b/src/libs/Navigation/DebugTabNavigator.tsx @@ -8,6 +8,7 @@ import type {LocaleContextProps} from '@components/LocaleContextProvider'; import getBackgroundColor from '@components/TabSelector/getBackground'; import getOpacity from '@components/TabSelector/getOpacity'; import TabSelectorItem from '@components/TabSelector/TabSelectorItem'; +import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; @@ -19,16 +20,16 @@ type IconAndTitle = { title: string; }; -function getIconAndTitle(route: string, translate: LocaleContextProps['translate']): IconAndTitle { +function getIconAndTitle(icons: Record<'Document', IconAsset>, route: string, translate: LocaleContextProps['translate']): IconAndTitle { switch (route) { case CONST.DEBUG.DETAILS: return {icon: Expensicons.Info, title: translate('debug.details')}; case CONST.DEBUG.JSON: return {icon: Expensicons.Eye, title: translate('debug.JSON')}; case CONST.DEBUG.REPORT_ACTIONS: - return {icon: Expensicons.Document, title: translate('debug.reportActions')}; + return {icon: icons.Document, title: translate('debug.reportActions')}; case CONST.DEBUG.REPORT_ACTION_PREVIEW: - return {icon: Expensicons.Document, title: translate('debug.reportActionPreview')}; + return {icon: icons.Document, title: translate('debug.reportActionPreview')}; case CONST.DEBUG.TRANSACTION_VIOLATIONS: return {icon: Expensicons.Exclamation, title: translate('debug.violations')}; default: @@ -51,6 +52,7 @@ type DebugTabNavigatorProps = { }; function DebugTabNavigator({id, routes}: DebugTabNavigatorProps) { + const icons = useMemoizedLazyExpensifyIcons(['Document'] as const); const styles = useThemeStyles(); const theme = useTheme(); const navigation = useNavigation>>(); @@ -96,7 +98,7 @@ function DebugTabNavigator({id, routes}: DebugTabNavigatorProps) { position: undefined, isActive, }); - const {icon, title} = getIconAndTitle(route.name, translate); + const {icon, title} = getIconAndTitle(icons, route.name, translate); const onPress = () => { navigation.navigate(routeData.name, {...routeData?.params, screen: route.name}); diff --git a/src/libs/QuickActionUtils.ts b/src/libs/QuickActionUtils.ts index 253cdb46e55f..0be7eba8eb13 100644 --- a/src/libs/QuickActionUtils.ts +++ b/src/libs/QuickActionUtils.ts @@ -1,14 +1,15 @@ -import type {SvgProps} from 'react-native-svg'; +// eslint-disable-next-line no-restricted-imports import * as Expensicons from '@components/Icon/Expensicons'; import CONST from '@src/CONST'; import type {TranslationPaths} from '@src/languages/types'; import type {Policy, Report} from '@src/types/onyx'; import type {QuickActionName} from '@src/types/onyx/QuickAction'; import type QuickAction from '@src/types/onyx/QuickAction'; +import type IconAsset from '@src/types/utils/IconAsset'; import getIconForAction from './getIconForAction'; import {canCreateRequest} from './ReportUtils'; -const getQuickActionIcon = (action: QuickActionName): React.FC => { +const getQuickActionIcon = (icons: Record<'CalendarSolid', IconAsset>, action: QuickActionName): IconAsset => { switch (action) { case CONST.QUICK_ACTIONS.REQUEST_MANUAL: return getIconForAction(CONST.IOU.TYPE.REQUEST); @@ -17,7 +18,7 @@ const getQuickActionIcon = (action: QuickActionName): React.FC => { case CONST.QUICK_ACTIONS.REQUEST_DISTANCE: return Expensicons.Car; case CONST.QUICK_ACTIONS.PER_DIEM: - return Expensicons.CalendarSolid; + return icons.CalendarSolid; case CONST.QUICK_ACTIONS.SPLIT_MANUAL: case CONST.QUICK_ACTIONS.SPLIT_SCAN: case CONST.QUICK_ACTIONS.SPLIT_DISTANCE: diff --git a/src/libs/SearchUIUtils.ts b/src/libs/SearchUIUtils.ts index ad27a0ee2312..4255b895a514 100644 --- a/src/libs/SearchUIUtils.ts +++ b/src/libs/SearchUIUtils.ts @@ -253,7 +253,7 @@ type SearchTypeMenuItem = { key: SearchKey; translationPath: TranslationPaths; type: SearchDataTypes; - icon: IconAsset; + icon?: IconAsset; searchQuery: string; searchQueryJSON: SearchQueryJSON | undefined; hash: number; @@ -306,7 +306,11 @@ type GetSectionsParams = { * If you are trying to access data about a specific search, you do NOT need to subscribe to the data (such as feeds) if it does not * affect the specific query you are looking for */ -function getSuggestedSearches(accountID: number = CONST.DEFAULT_NUMBER_ID, defaultFeedID?: string): Record, SearchTypeMenuItem> { +function getSuggestedSearches( + accountID: number = CONST.DEFAULT_NUMBER_ID, + defaultFeedID?: string, + icons?: Record<'Document', IconAsset>, +): Record, SearchTypeMenuItem> { return { [CONST.SEARCH.SEARCH_KEYS.EXPENSES]: { key: CONST.SEARCH.SEARCH_KEYS.EXPENSES, @@ -328,7 +332,7 @@ function getSuggestedSearches(accountID: number = CONST.DEFAULT_NUMBER_ID, defau key: CONST.SEARCH.SEARCH_KEYS.REPORTS, translationPath: 'common.reports', type: CONST.SEARCH.DATA_TYPES.EXPENSE_REPORT, - icon: Expensicons.Document, + icon: icons?.Document, searchQuery: buildCannedSearchQuery({type: CONST.SEARCH.DATA_TYPES.EXPENSE_REPORT}), get searchQueryJSON() { return buildSearchQueryJSON(this.searchQuery); @@ -2009,6 +2013,7 @@ function isCorrectSearchUserName(displayName?: string) { // eslint-disable-next-line @typescript-eslint/max-params function createTypeMenuSections( + icons: Record<'Document', IconAsset>, currentUserEmail: string | undefined, currentUserAccountID: number | undefined, cardFeedsByPolicy: Record, @@ -2024,7 +2029,7 @@ function createTypeMenuSections( ): SearchTypeMenuSection[] { const typeMenuSections: SearchTypeMenuSection[] = []; - const suggestedSearches = getSuggestedSearches(currentUserAccountID, defaultCardFeed?.id); + const suggestedSearches = getSuggestedSearches(currentUserAccountID, defaultCardFeed?.id, icons); const suggestedSearchesVisibility = getSuggestedSearchesVisibility(currentUserEmail, cardFeedsByPolicy, policies, defaultExpensifyCard); // Todo section diff --git a/src/libs/SettlementButtonUtils.ts b/src/libs/SettlementButtonUtils.ts index c873e8216d95..5476e7e8dc78 100644 --- a/src/libs/SettlementButtonUtils.ts +++ b/src/libs/SettlementButtonUtils.ts @@ -2,6 +2,7 @@ import * as Expensicons from '@components/Icon/Expensicons'; import type {LocaleContextProps} from '@components/LocaleContextProvider'; import CONST from '@src/CONST'; import ROUTES from '@src/ROUTES'; +import type IconAsset from '@src/types/utils/IconAsset'; import Log from './Log'; import Navigation from './Navigation/Navigation'; @@ -79,16 +80,16 @@ const handleUnvalidatedUserNavigation = (chatReportID: string, reportID?: string /** * Retrieves SettlementButton payment methods. */ -const getSettlementButtonPaymentMethods = (hasActivatedWallet: boolean, translate: LocaleContextProps['translate']) => { +const getSettlementButtonPaymentMethods = (icons: Record<'Building' | 'User', IconAsset>, hasActivatedWallet: boolean, translate: LocaleContextProps['translate']) => { return { [CONST.PAYMENT_METHODS.PERSONAL_BANK_ACCOUNT]: { text: hasActivatedWallet ? translate('iou.settleWallet', {formattedAmount: ''}) : translate('iou.settlePersonal', {formattedAmount: ''}), - icon: Expensicons.User, + icon: icons.User, value: CONST.PAYMENT_METHODS.PERSONAL_BANK_ACCOUNT, }, [CONST.PAYMENT_METHODS.BUSINESS_BANK_ACCOUNT]: { text: translate('iou.settleBusiness', {formattedAmount: ''}), - icon: Expensicons.Building, + icon: icons.Building, value: CONST.PAYMENT_METHODS.BUSINESS_BANK_ACCOUNT, }, [CONST.IOU.PAYMENT_TYPE.ELSEWHERE]: { diff --git a/src/pages/EnablePayments/TermsPage/LongTermsForm.tsx b/src/pages/EnablePayments/TermsPage/LongTermsForm.tsx index d5a7c7821186..9db248b09d8a 100644 --- a/src/pages/EnablePayments/TermsPage/LongTermsForm.tsx +++ b/src/pages/EnablePayments/TermsPage/LongTermsForm.tsx @@ -2,9 +2,9 @@ import React from 'react'; import {View} from 'react-native'; import CollapsibleSection from '@components/CollapsibleSection'; import Icon from '@components/Icon'; -import * as Expensicons from '@components/Icon/Expensicons'; import Text from '@components/Text'; import TextLink from '@components/TextLink'; +import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; @@ -12,6 +12,7 @@ import {convertToDisplayString} from '@libs/CurrencyUtils'; import CONST from '@src/CONST'; function LongTermsForm() { + const icons = useMemoizedLazyExpensifyIcons(['Printer'] as const); const theme = useTheme(); const styles = useThemeStyles(); const {translate, numberFormat} = useLocalize(); @@ -101,7 +102,7 @@ function LongTermsForm() { ; function ReferralDetailsPage({route}: ReferralDetailsPageProps) { + const icons = useMemoizedLazyExpensifyIcons(['NewWindow'] as const); const theme = useTheme(); const styles = useThemeStyles(); const illustrations = useMemoizedLazyIllustrations(['PaymentHands'] as const); const {translate} = useLocalize(); - const [account] = useOnyx(ONYXKEYS.ACCOUNT, {canBeMissing: true}); + const [account] = useOnyx(ONYXKEYS.ACCOUNT, {canBeMissing: false}); const popoverAnchor = useRef(null); const {isExecuting, singleExecution} = useSingleExecution(); let {contentType} = route.params; @@ -87,7 +88,7 @@ function ReferralDetailsPage({route}: ReferralDetailsPageProps) { title={translate('requestorStep.learnMore')} icon={Expensicons.QuestionMark} shouldShowRightIcon - iconRight={Expensicons.NewWindow} + iconRight={icons.NewWindow} disabled={isExecuting} shouldBlockSelection onPress={singleExecution(() => openExternalLink(CONST.REFERRAL_PROGRAM.LEARN_MORE_LINK))} diff --git a/src/pages/ReimbursementAccount/NonUSD/Finish/index.tsx b/src/pages/ReimbursementAccount/NonUSD/Finish/index.tsx index 5c4df2e6b808..c39bc8013f3e 100644 --- a/src/pages/ReimbursementAccount/NonUSD/Finish/index.tsx +++ b/src/pages/ReimbursementAccount/NonUSD/Finish/index.tsx @@ -1,15 +1,18 @@ import React from 'react'; import {View} from 'react-native'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; +// eslint-disable-next-line no-restricted-imports import * as Expensicons from '@components/Icon/Expensicons'; +// eslint-disable-next-line no-restricted-imports import {ChatBubble} from '@components/Icon/Expensicons'; +// eslint-disable-next-line no-restricted-imports import * as Illustrations from '@components/Icon/Illustrations'; import MenuItem from '@components/MenuItem'; import ScreenWrapper from '@components/ScreenWrapper'; import ScrollView from '@components/ScrollView'; import Section from '@components/Section'; import Text from '@components/Text'; -import {useMemoizedLazyIllustrations} from '@hooks/useLazyAsset'; +import {useMemoizedLazyExpensifyIcons, useMemoizedLazyIllustrations} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; @@ -23,6 +26,7 @@ function Finish() { const styles = useThemeStyles(); const {translate} = useLocalize(); const {shouldUseNarrowLayout} = useResponsiveLayout(); + const icons = useMemoizedLazyExpensifyIcons(['NewWindow'] as const); const illustrations = useMemoizedLazyIllustrations(['ConciergeBubble'] as const); const [reimbursementAccount] = useOnyx(ONYXKEYS.REIMBURSEMENT_ACCOUNT, {canBeMissing: true}); @@ -73,7 +77,7 @@ function Finish() { }, icon: Expensicons.Shield, shouldShowRightIcon: true, - iconRight: Expensicons.NewWindow, + iconRight: icons.NewWindow, outerWrapperStyle: shouldUseNarrowLayout ? styles.mhn5 : styles.mhn8, }, ]} diff --git a/src/pages/ReportParticipantDetailsPage.tsx b/src/pages/ReportParticipantDetailsPage.tsx index 6080ff7d728a..ce75eeb9dc61 100644 --- a/src/pages/ReportParticipantDetailsPage.tsx +++ b/src/pages/ReportParticipantDetailsPage.tsx @@ -4,6 +4,7 @@ import Avatar from '@components/Avatar'; import Button from '@components/Button'; import ConfirmModal from '@components/ConfirmModal'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; +// eslint-disable-next-line no-restricted-imports import * as Expensicons from '@components/Icon/Expensicons'; import MenuItem from '@components/MenuItem'; import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription'; @@ -11,14 +12,15 @@ import OfflineWithFeedback from '@components/OfflineWithFeedback'; import ScreenWrapper from '@components/ScreenWrapper'; import Text from '@components/Text'; import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; +import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; import useStyleUtils from '@hooks/useStyleUtils'; import useThemeStyles from '@hooks/useThemeStyles'; -import * as Report from '@libs/actions/Report'; +import {removeFromGroupChat} from '@libs/actions/Report'; import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types'; -import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils'; -import * as ReportUtils from '@libs/ReportUtils'; +import {getDisplayNameOrDefault} from '@libs/PersonalDetailsUtils'; +import {isGroupChatAdmin} from '@libs/ReportUtils'; import Navigation from '@navigation/Navigation'; import type {ParticipantsNavigatorParamList} from '@navigation/types'; import CONST from '@src/CONST'; @@ -33,26 +35,27 @@ import type {WithReportOrNotFoundProps} from './home/report/withReportOrNotFound type ReportParticipantDetailsPageProps = WithReportOrNotFoundProps & PlatformStackScreenProps; function ReportParticipantDetails({report, route}: ReportParticipantDetailsPageProps) { + const icons = useMemoizedLazyExpensifyIcons(['RemoveMembers'] as const); const styles = useThemeStyles(); const {formatPhoneNumber, translate} = useLocalize(); const StyleUtils = useStyleUtils(); - const [personalDetails] = useOnyx(ONYXKEYS.PERSONAL_DETAILS_LIST); + const [personalDetails] = useOnyx(ONYXKEYS.PERSONAL_DETAILS_LIST, {canBeMissing: false}); const currentUserPersonalDetails = useCurrentUserPersonalDetails(); const [isRemoveMemberConfirmModalVisible, setIsRemoveMemberConfirmModalVisible] = React.useState(false); const accountID = Number(route.params.accountID); - const backTo = ROUTES.REPORT_PARTICIPANTS.getRoute(report?.reportID ?? '-1', route.params.backTo); + const backTo = ROUTES.REPORT_PARTICIPANTS.getRoute(report?.reportID, route.params.backTo); const member = report?.participants?.[accountID]; const details = personalDetails?.[accountID] ?? ({} as PersonalDetails); const fallbackIcon = details.fallbackIcon ?? ''; - const displayName = formatPhoneNumber(PersonalDetailsUtils.getDisplayNameOrDefault(details)); - const isCurrentUserAdmin = ReportUtils.isGroupChatAdmin(report, currentUserPersonalDetails?.accountID); + const displayName = formatPhoneNumber(getDisplayNameOrDefault(details)); + const isCurrentUserAdmin = isGroupChatAdmin(report, currentUserPersonalDetails?.accountID); const isSelectedMemberCurrentUser = accountID === currentUserPersonalDetails?.accountID; const removeUser = useCallback(() => { setIsRemoveMemberConfirmModalVisible(false); - Report.removeFromGroupChat(report?.reportID, [accountID]); + removeFromGroupChat(report?.reportID, [accountID]); Navigation.goBack(backTo); }, [backTo, report, accountID]); @@ -99,7 +102,7 @@ function ReportParticipantDetails({report, route}: ReportParticipantDetailsPageP text={translate('workspace.people.removeGroupMemberButtonTitle')} onPress={() => setIsRemoveMemberConfirmModalVisible(true)} isDisabled={isSelectedMemberCurrentUser} - icon={Expensicons.RemoveMembers} + icon={icons.RemoveMembers} iconStyles={StyleUtils.getTransformScaleStyle(0.8)} style={styles.mv5} /> diff --git a/src/pages/ReportParticipantsPage.tsx b/src/pages/ReportParticipantsPage.tsx index 48f4cdba91f7..338a7c731fff 100755 --- a/src/pages/ReportParticipantsPage.tsx +++ b/src/pages/ReportParticipantsPage.tsx @@ -11,13 +11,15 @@ import ButtonWithDropdownMenu from '@components/ButtonWithDropdownMenu'; import type {DropdownOption, WorkspaceMemberBulkActionType} from '@components/ButtonWithDropdownMenu/types'; import ConfirmModal from '@components/ConfirmModal'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; -import {FallbackAvatar, MakeAdmin, Plus, RemoveMembers, User} from '@components/Icon/Expensicons'; +// eslint-disable-next-line no-restricted-imports +import {FallbackAvatar, Plus} from '@components/Icon/Expensicons'; import ScreenWrapper from '@components/ScreenWrapper'; import SelectionListWithModal from '@components/SelectionListWithModal'; import TableListItem from '@components/SelectionListWithSections/TableListItem'; import type {ListItem, SelectionListHandle} from '@components/SelectionListWithSections/types'; import Text from '@components/Text'; import useFilteredSelection from '@hooks/useFilteredSelection'; +import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useMobileSelectionMode from '@hooks/useMobileSelectionMode'; import useNetwork from '@hooks/useNetwork'; @@ -62,6 +64,7 @@ type MemberOption = Omit & {accountID: number}; type ReportParticipantsPageProps = WithReportOrNotFoundProps & PlatformStackScreenProps; function ReportParticipantsPage({report, route}: ReportParticipantsPageProps) { const backTo = route.params.backTo; + const icons = useMemoizedLazyExpensifyIcons(['User', 'MakeAdmin', 'RemoveMembers'] as const); const [removeMembersConfirmModalVisible, setRemoveMembersConfirmModalVisible] = useState(false); const {translate, formatPhoneNumber, localeCompare} = useLocalize(); const styles = useThemeStyles(); @@ -304,7 +307,7 @@ function ReportParticipantsPage({report, route}: ReportParticipantsPageProps) { { text: translate('workspace.people.removeMembersTitle', {count: selectedMembers.length}), value: CONST.POLICY.MEMBERS_BULK_ACTION_TYPES.REMOVE, - icon: RemoveMembers, + icon: icons.RemoveMembers, onSelected: () => setRemoveMembersConfirmModalVisible(true), }, ]; @@ -315,7 +318,7 @@ function ReportParticipantsPage({report, route}: ReportParticipantsPageProps) { options.push({ text: translate('workspace.people.makeMember'), value: CONST.POLICY.MEMBERS_BULK_ACTION_TYPES.MAKE_MEMBER, - icon: User, + icon: icons.User, onSelected: () => changeUserRole(CONST.REPORT.ROLE.MEMBER), }); } @@ -326,13 +329,13 @@ function ReportParticipantsPage({report, route}: ReportParticipantsPageProps) { options.push({ text: translate('workspace.people.makeAdmin'), value: CONST.POLICY.MEMBERS_BULK_ACTION_TYPES.MAKE_ADMIN, - icon: MakeAdmin, + icon: icons.MakeAdmin, onSelected: () => changeUserRole(CONST.REPORT.ROLE.ADMIN), }); } return options; - }, [changeUserRole, translate, setRemoveMembersConfirmModalVisible, selectedMembers, report.participants]); + }, [icons.RemoveMembers, icons.User, icons.MakeAdmin, changeUserRole, translate, setRemoveMembersConfirmModalVisible, selectedMembers, report.participants]); const headerButtons = useMemo(() => { if (!isGroupChat) { diff --git a/src/pages/RoomMemberDetailsPage.tsx b/src/pages/RoomMemberDetailsPage.tsx index 93dd1f6269c4..510c51d575a5 100644 --- a/src/pages/RoomMemberDetailsPage.tsx +++ b/src/pages/RoomMemberDetailsPage.tsx @@ -4,22 +4,24 @@ import Avatar from '@components/Avatar'; import Button from '@components/Button'; import ConfirmModal from '@components/ConfirmModal'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; +// eslint-disable-next-line no-restricted-imports import * as Expensicons from '@components/Icon/Expensicons'; import MenuItem from '@components/MenuItem'; import ScreenWrapper from '@components/ScreenWrapper'; import Text from '@components/Text'; import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; +import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; import usePolicy from '@hooks/usePolicy'; import useStyleUtils from '@hooks/useStyleUtils'; import useThemeStyles from '@hooks/useThemeStyles'; -import * as Report from '@libs/actions/Report'; +import {removeFromRoom} from '@libs/actions/Report'; import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types'; import type {RoomMembersNavigatorParamList} from '@libs/Navigation/types'; -import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils'; -import * as PolicyUtils from '@libs/PolicyUtils'; -import * as ReportUtils from '@libs/ReportUtils'; +import {getDisplayNameOrDefault} from '@libs/PersonalDetailsUtils'; +import {isUserPolicyAdmin} from '@libs/PolicyUtils'; +import {isPolicyExpenseChat} from '@libs/ReportUtils'; import Navigation from '@navigation/Navigation'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; @@ -33,28 +35,29 @@ import type {WithReportOrNotFoundProps} from './home/report/withReportOrNotFound type RoomMemberDetailsPagePageProps = WithReportOrNotFoundProps & PlatformStackScreenProps; function RoomMemberDetailsPage({report, route}: RoomMemberDetailsPagePageProps) { + const icons = useMemoizedLazyExpensifyIcons(['RemoveMembers'] as const); const styles = useThemeStyles(); const {formatPhoneNumber, translate} = useLocalize(); const StyleUtils = useStyleUtils(); const currentUserPersonalDetails = useCurrentUserPersonalDetails(); - const [personalDetails] = useOnyx(ONYXKEYS.PERSONAL_DETAILS_LIST); + const [personalDetails] = useOnyx(ONYXKEYS.PERSONAL_DETAILS_LIST, {canBeMissing: false}); const policy = usePolicy(report?.policyID); const [isRemoveMemberConfirmModalVisible, setIsRemoveMemberConfirmModalVisible] = React.useState(false); const accountID = Number(route.params.accountID); - const backTo = ROUTES.ROOM_MEMBERS.getRoute(report?.reportID ?? '-1', route.params.backTo); + const backTo = ROUTES.ROOM_MEMBERS.getRoute(report?.reportID, route.params.backTo); const member = report?.participants?.[accountID]; const details = personalDetails?.[accountID] ?? ({} as PersonalDetails); const fallbackIcon = details.fallbackIcon ?? ''; - const displayName = formatPhoneNumber(PersonalDetailsUtils.getDisplayNameOrDefault(details)); + const displayName = formatPhoneNumber(getDisplayNameOrDefault(details)); const isSelectedMemberCurrentUser = accountID === currentUserPersonalDetails?.accountID; const isSelectedMemberOwner = accountID === report.ownerAccountID; - const shouldDisableRemoveUser = (ReportUtils.isPolicyExpenseChat(report) && PolicyUtils.isUserPolicyAdmin(policy, details.login)) || isSelectedMemberCurrentUser || isSelectedMemberOwner; + const shouldDisableRemoveUser = (isPolicyExpenseChat(report) && isUserPolicyAdmin(policy, details.login)) || isSelectedMemberCurrentUser || isSelectedMemberOwner; const removeUser = useCallback(() => { setIsRemoveMemberConfirmModalVisible(false); - Report.removeFromRoom(report?.reportID, [accountID]); + removeFromRoom(report?.reportID, [accountID]); Navigation.goBack(backTo); }, [backTo, report, accountID]); @@ -96,7 +99,7 @@ function RoomMemberDetailsPage({report, route}: RoomMemberDetailsPagePageProps) text={translate('workspace.people.removeRoomMemberButtonTitle')} onPress={() => setIsRemoveMemberConfirmModalVisible(true)} isDisabled={shouldDisableRemoveUser} - icon={Expensicons.RemoveMembers} + icon={icons.RemoveMembers} iconStyles={StyleUtils.getTransformScaleStyle(0.8)} style={styles.mv5} /> diff --git a/src/pages/RoomMembersPage.tsx b/src/pages/RoomMembersPage.tsx index 4625c9fec4ec..d453d1a7362c 100644 --- a/src/pages/RoomMembersPage.tsx +++ b/src/pages/RoomMembersPage.tsx @@ -7,7 +7,8 @@ import ButtonWithDropdownMenu from '@components/ButtonWithDropdownMenu'; import type {DropdownOption, RoomMemberBulkActionType} from '@components/ButtonWithDropdownMenu/types'; import ConfirmModal from '@components/ConfirmModal'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; -import {FallbackAvatar, Plus, RemoveMembers} from '@components/Icon/Expensicons'; +// eslint-disable-next-line no-restricted-imports +import {FallbackAvatar, Plus} from '@components/Icon/Expensicons'; import {usePersonalDetails} from '@components/OnyxListItemProvider'; import ScreenWrapper from '@components/ScreenWrapper'; import SelectionListWithModal from '@components/SelectionListWithModal'; @@ -17,6 +18,7 @@ import Text from '@components/Text'; import type {WithCurrentUserPersonalDetailsProps} from '@components/withCurrentUserPersonalDetails'; import withCurrentUserPersonalDetails from '@components/withCurrentUserPersonalDetails'; import useFilteredSelection from '@hooks/useFilteredSelection'; +import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useMobileSelectionMode from '@hooks/useMobileSelectionMode'; import useNetwork from '@hooks/useNetwork'; @@ -51,6 +53,7 @@ type RoomMembersPageProps = WithReportOrNotFoundProps & WithCurrentUserPersonalD function RoomMembersPage({report, policy}: RoomMembersPageProps) { const route = useRoute>(); + const icons = useMemoizedLazyExpensifyIcons(['RemoveMembers'] as const); const styles = useThemeStyles(); const [session] = useOnyx(ONYXKEYS.SESSION, {canBeMissing: false}); const [reportMetadata] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_METADATA}${report?.reportID}`, {canBeMissing: false}); @@ -315,12 +318,12 @@ function RoomMembersPage({report, policy}: RoomMembersPageProps) { { text: translate('workspace.people.removeMembersTitle', {count: selectedMembers.length}), value: CONST.POLICY.MEMBERS_BULK_ACTION_TYPES.REMOVE, - icon: RemoveMembers, + icon: icons.RemoveMembers, onSelected: () => setRemoveMembersConfirmModalVisible(true), }, ]; return options; - }, [translate, selectedMembers.length]); + }, [icons.RemoveMembers, translate, selectedMembers.length]); const headerButtons = useMemo(() => { return ( diff --git a/src/pages/ShareCodePage.tsx b/src/pages/ShareCodePage.tsx index 5e7d2e76c4bc..5965c8454db4 100644 --- a/src/pages/ShareCodePage.tsx +++ b/src/pages/ShareCodePage.tsx @@ -6,6 +6,7 @@ import type {SvgProps} from 'react-native-svg'; import expensifyLogo from '@assets/images/expensify-logo-round-transparent.png'; import ContextMenuItem from '@components/ContextMenuItem'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; +// eslint-disable-next-line no-restricted-imports import * as Expensicons from '@components/Icon/Expensicons'; import MenuItem from '@components/MenuItem'; import QRShareWithDownload from '@components/QRShare/QRShareWithDownload'; @@ -14,6 +15,7 @@ import ScreenWrapper from '@components/ScreenWrapper'; import ScrollView from '@components/ScrollView'; import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; import useEnvironment from '@hooks/useEnvironment'; +import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useReportIsArchived from '@hooks/useReportIsArchived'; import useStyleUtils from '@hooks/useStyleUtils'; @@ -67,6 +69,7 @@ function getLogoForWorkspace(report: OnyxEntry, policy?: OnyxEntry qrCodeRef.current?.download?.()} /> diff --git a/src/pages/Travel/TripDetailsPage.tsx b/src/pages/Travel/TripDetailsPage.tsx index 9a4c9dc5ab34..cf23620abc52 100644 --- a/src/pages/Travel/TripDetailsPage.tsx +++ b/src/pages/Travel/TripDetailsPage.tsx @@ -3,10 +3,12 @@ import React, {useCallback, useState} from 'react'; import type {OnyxEntry} from 'react-native-onyx'; import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; +// eslint-disable-next-line no-restricted-imports import * as Expensicons from '@components/Icon/Expensicons'; import MenuItem from '@components/MenuItem'; import ScreenWrapper from '@components/ScreenWrapper'; import ScrollView from '@components/ScrollView'; +import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; import useOnyx from '@hooks/useOnyx'; @@ -37,6 +39,7 @@ function pickTravelerPersonalDetails(personalDetails: OnyxEntry; function TripDetailsPage({route}: TripDetailsPageProps) { + const icons = useMemoizedLazyExpensifyIcons(['NewWindow'] as const); const theme = useTheme(); const styles = useThemeStyles(); const StyleUtils = useStyleUtils(); @@ -114,7 +117,7 @@ function TripDetailsPage({route}: TripDetailsPageProps) { { setIsModifyTripLoading(true); @@ -129,7 +132,7 @@ function TripDetailsPage({route}: TripDetailsPageProps) { { setIsTripSupportLoading(true); diff --git a/src/pages/domain/DomainInitialPage.tsx b/src/pages/domain/DomainInitialPage.tsx index fc3afd8e4b81..1c0c3952c147 100644 --- a/src/pages/domain/DomainInitialPage.tsx +++ b/src/pages/domain/DomainInitialPage.tsx @@ -6,11 +6,11 @@ import type {ValueOf} from 'type-fest'; import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import HighlightableMenuItem from '@components/HighlightableMenuItem'; -import {UserLock} from '@components/Icon/Expensicons'; import NavigationTabBar from '@components/Navigation/NavigationTabBar'; import NAVIGATION_TABS from '@components/Navigation/NavigationTabBar/NAVIGATION_TABS'; import ScreenWrapper from '@components/ScreenWrapper'; import ScrollView from '@components/ScrollView'; +import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; @@ -44,6 +44,7 @@ type DomainMenuItem = { type DomainInitialPageProps = PlatformStackScreenProps; function DomainInitialPage({route}: DomainInitialPageProps) { + const icons = useMemoizedLazyExpensifyIcons(['UserLock'] as const); const styles = useThemeStyles(); const waitForNavigate = useWaitForNavigation(); const {singleExecution, isExecuting} = useSingleExecution(); @@ -61,14 +62,14 @@ function DomainInitialPage({route}: DomainInitialPageProps) { const menuItems: DomainMenuItem[] = [ { translationKey: 'domain.saml', - icon: UserLock, + icon: icons.UserLock, action: singleExecution(waitForNavigate(() => Navigation.navigate(ROUTES.DOMAIN_SAML.getRoute(accountID)))), screenName: SCREENS.DOMAIN.SAML, }, ]; return menuItems; - }, [accountID, singleExecution, waitForNavigate]); + }, [icons.UserLock, accountID, singleExecution, waitForNavigate]); useEffect(() => { confirmReadyToOpenApp(); diff --git a/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.tsx b/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.tsx index 0ba3843d94fa..7f41640d56d6 100755 --- a/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.tsx +++ b/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.tsx @@ -13,6 +13,7 @@ import useArrowKeyFocusManager from '@hooks/useArrowKeyFocusManager'; import useEnvironment from '@hooks/useEnvironment'; import useGetExpensifyCardFromReportAction from '@hooks/useGetExpensifyCardFromReportAction'; import useKeyboardShortcut from '@hooks/useKeyboardShortcut'; +import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; import useOnyx from '@hooks/useOnyx'; @@ -130,6 +131,7 @@ function BaseReportActionContextMenu({ setIsEmojiPickerActive, }: BaseReportActionContextMenuProps) { const actionSheetAwareScrollViewContext = useContext(ActionSheetAwareScrollView.ActionSheetAwareScrollViewContext); + const icons = useMemoizedLazyExpensifyIcons(['Download'] as const); const StyleUtils = useStyleUtils(); const {translate, getLocalDateFromDatetime} = useLocalize(); // eslint-disable-next-line rulesdir/prefer-shouldUseNarrowLayout-instead-of-isSmallScreenWidth @@ -385,6 +387,8 @@ function BaseReportActionContextMenu({ const text = textTranslateKey && (isKeyInActionUpdateKeys ? translate(textTranslateKey, {action: moneyRequestAction ?? reportAction}) : translate(textTranslateKey)); const transactionPayload = textTranslateKey === 'reportActionContextMenu.copyMessage' && transaction && {transaction}; const isMenuAction = textTranslateKey === 'reportActionContextMenu.menu'; + const icon = typeof contextAction.icon === 'string' ? icons[contextAction.icon] : contextAction.icon; + const successIcon = typeof contextAction.successIcon === 'string' ? icons[contextAction.successIcon] : contextAction.successIcon; return ( ; successTextTranslateKey?: TranslationPaths; - successIcon?: IconAsset; + successIcon?: IconAsset | Extract; onPress: OnPress; getDescription: GetDescription; }; @@ -850,9 +852,9 @@ const ContextMenuActions: ContextMenuAction[] = [ { isAnonymousAction: true, textTranslateKey: 'common.download', - icon: Expensicons.Download, + icon: 'Download', successTextTranslateKey: 'common.download', - successIcon: Expensicons.Download, + successIcon: 'Download', shouldShow: ({reportAction, isOffline}) => { const isAttachment = isReportActionAttachment(reportAction); const html = getActionHtml(reportAction); diff --git a/src/pages/home/report/RepliesDivider.tsx b/src/pages/home/report/RepliesDivider.tsx index d6d5e1d3cfc8..8ee946ddac15 100644 --- a/src/pages/home/report/RepliesDivider.tsx +++ b/src/pages/home/report/RepliesDivider.tsx @@ -1,8 +1,8 @@ import React from 'react'; import {View} from 'react-native'; import Icon from '@components/Icon'; -import * as Expensicons from '@components/Icon/Expensicons'; import Text from '@components/Text'; +import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; @@ -15,6 +15,7 @@ type RepliesDividerProps = { }; function RepliesDivider({shouldHideThreadDividerLine}: RepliesDividerProps) { + const icons = useMemoizedLazyExpensifyIcons(['Thread'] as const); const styles = useThemeStyles(); const theme = useTheme(); const {translate} = useLocalize(); @@ -25,7 +26,7 @@ function RepliesDivider({shouldHideThreadDividerLine}: RepliesDividerProps) { dataSet={{[CONST.SELECTION_SCRAPER_HIDDEN_ELEMENT]: true}} > selectOption(() => handleCreateReport(), true), }, ]; - }, [handleCreateReport, report, selectOption, shouldUseNarrowLayout, translate]); + }, [icons.Document, handleCreateReport, report, selectOption, shouldUseNarrowLayout, translate]); /** * Determines if we can show the task option @@ -380,7 +383,7 @@ function AttachmentPickerWithMenuItems({ ...(!isTeachersUniteReport ? createReportOption : []), ...taskOption, { - icon: Expensicons.Paperclip, + icon: icons.Paperclip, text: translate('reportActionCompose.addAttachment'), disabled: shouldDisableAttachmentItem, }, diff --git a/src/pages/home/report/ThreadDivider.tsx b/src/pages/home/report/ThreadDivider.tsx index f673a05b8495..36abf5a0b0b4 100644 --- a/src/pages/home/report/ThreadDivider.tsx +++ b/src/pages/home/report/ThreadDivider.tsx @@ -1,9 +1,9 @@ import React from 'react'; import {View} from 'react-native'; import Icon from '@components/Icon'; -import * as Expensicons from '@components/Icon/Expensicons'; import {PressableWithoutFeedback} from '@components/Pressable'; import Text from '@components/Text'; +import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; import useReportIsArchived from '@hooks/useReportIsArchived'; @@ -24,6 +24,7 @@ type ThreadDividerProps = { }; function ThreadDivider({ancestor, isLinkDisabled = false}: ThreadDividerProps) { + const icons = useMemoizedLazyExpensifyIcons(['Thread'] as const); const styles = useThemeStyles(); const theme = useTheme(); const {translate} = useLocalize(); @@ -39,7 +40,7 @@ function ThreadDivider({ancestor, isLinkDisabled = false}: ThreadDividerProps) { {isLinkDisabled ? ( <> ) => a * FAB that can open or close the menu. */ function FloatingActionButtonAndPopover({onHideCreateMenu, onShowCreateMenu, ref}: FloatingActionButtonAndPopoverProps) { + const icons = useMemoizedLazyExpensifyIcons(['CalendarSolid', 'Document', 'NewWorkspace', 'NewWindow'] as const); const styles = useThemeStyles(); const theme = useTheme(); const {translate} = useLocalize(); @@ -436,7 +439,7 @@ function FloatingActionButtonAndPopover({onHideCreateMenu, onShowCreateMenu, ref return [ { ...baseQuickAction, - icon: getQuickActionIcon(quickAction?.action), + icon: getQuickActionIcon(icons, quickAction?.action), text: quickActionTitle, rightIconAccountID: quickActionAvatars.at(0)?.id ?? CONST.DEFAULT_NUMBER_ID, description: quickActionSubtitle, @@ -474,6 +477,7 @@ function FloatingActionButtonAndPopover({onHideCreateMenu, onShowCreateMenu, ref return []; }, [ + icons, translate, styles.pt3, styles.pb2, @@ -536,7 +540,7 @@ function FloatingActionButtonAndPopover({onHideCreateMenu, onShowCreateMenu, ref ...(shouldShowCreateReportOption ? [ { - icon: Expensicons.Document, + icon: icons.Document, text: translate('report.newReport.createReport'), shouldCallAfterModalHide: shouldUseNarrowLayout, onSelected: () => { @@ -598,7 +602,7 @@ function FloatingActionButtonAndPopover({onHideCreateMenu, onShowCreateMenu, ref { icon: Expensicons.Suitcase, text: translate('travel.bookTravel'), - rightIcon: isTravelEnabled && shouldOpenTravelDotLinkWeb() ? Expensicons.NewWindow : undefined, + rightIcon: isTravelEnabled && shouldOpenTravelDotLinkWeb() ? icons.NewWindow : undefined, onSelected: () => interceptAnonymousUser(() => openTravel()), }, ], @@ -618,7 +622,7 @@ function FloatingActionButtonAndPopover({onHideCreateMenu, onShowCreateMenu, ref { displayInDefaultIconColor: true, contentFit: 'contain' as ImageContentFit, - icon: Expensicons.NewWorkspace, + icon: icons.NewWorkspace, iconWidth: variables.w46, iconHeight: variables.h40, text: translate('workspace.new.newWorkspace'), diff --git a/src/pages/iou/request/MoneyRequestParticipantsSelector.tsx b/src/pages/iou/request/MoneyRequestParticipantsSelector.tsx index 7583df6c049f..1c691c4fc639 100644 --- a/src/pages/iou/request/MoneyRequestParticipantsSelector.tsx +++ b/src/pages/iou/request/MoneyRequestParticipantsSelector.tsx @@ -12,7 +12,6 @@ import Button from '@components/Button'; import ContactPermissionModal from '@components/ContactPermissionModal'; import EmptySelectionListContent from '@components/EmptySelectionListContent'; import FormHelpMessage from '@components/FormHelpMessage'; -import {UserPlus} from '@components/Icon/Expensicons'; import MenuItem from '@components/MenuItem'; import {usePersonalDetails} from '@components/OnyxListItemProvider'; import ReferralProgramCTA from '@components/ReferralProgramCTA'; @@ -21,6 +20,7 @@ import InviteMemberListItem from '@components/SelectionListWithSections/InviteMe import type {SelectionListHandle} from '@components/SelectionListWithSections/types'; import useContactImport from '@hooks/useContactImport'; import useDismissedReferralBanners from '@hooks/useDismissedReferralBanners'; +import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; import useOnyx from '@hooks/useOnyx'; @@ -100,6 +100,7 @@ function MoneyRequestParticipantsSelector({ isCorporateCardTransaction = false, ref, }: MoneyRequestParticipantsSelectorProps) { + const icons = useMemoizedLazyExpensifyIcons(['UserPlus'] as const); const {translate} = useLocalize(); const styles = useThemeStyles(); const {contactPermissionState, contacts, setContactPermissionState, importAndSaveContacts} = useContactImport(); @@ -506,13 +507,13 @@ function MoneyRequestParticipantsSelector({ return ( ); - }, [contactState?.showImportUI, showImportContacts, styles.mb3, translate]); + }, [icons.UserPlus, contactState?.showImportUI, showImportContacts, styles.mb3, translate]); const ClickableImportContactTextComponent = useMemo(() => { if (searchTerm.length || isSearchingForReports) { diff --git a/src/pages/iou/request/step/IOURequestEditReportCommon.tsx b/src/pages/iou/request/step/IOURequestEditReportCommon.tsx index 30a9e88c098c..de81c7795e0d 100644 --- a/src/pages/iou/request/step/IOURequestEditReportCommon.tsx +++ b/src/pages/iou/request/step/IOURequestEditReportCommon.tsx @@ -1,6 +1,7 @@ import {createPoliciesSelector} from '@selectors/Policy'; import React, {useMemo} from 'react'; import type {OnyxCollection, OnyxEntry} from 'react-native-onyx'; +// eslint-disable-next-line no-restricted-imports import * as Expensicons from '@components/Icon/Expensicons'; import MenuItem from '@components/MenuItem'; import {useOptionsList} from '@components/OptionListContextProvider'; @@ -9,6 +10,7 @@ import InviteMemberListItem from '@components/SelectionList/ListItem/InviteMembe import type {ListItem} from '@components/SelectionList/types'; import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; import useDebouncedState from '@hooks/useDebouncedState'; +import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; import usePolicy from '@hooks/usePolicy'; @@ -62,6 +64,7 @@ function IOURequestEditReportCommon({ createReport, isPerDiemRequest, }: Props) { + const icons = useMemoizedLazyExpensifyIcons(['Document'] as const); const {translate, localeCompare} = useLocalize(); const {options} = useOptionsList(); const [outstandingReportsByPolicyID] = useOnyx(ONYXKEYS.DERIVED.OUTSTANDING_REPORTS_BY_POLICY_ID, {canBeMissing: true}); @@ -209,10 +212,10 @@ function IOURequestEditReportCommon({ onPress={createReport} title={translate('report.newReport.createReport')} description={policyForMovingExpenses?.name} - icon={Expensicons.Document} + icon={icons.Document} /> ); - }, [createReport, isEditing, isOwner, translate, policyForMovingExpenses?.name]); + }, [icons.Document, createReport, isEditing, isOwner, translate, policyForMovingExpenses?.name]); // eslint-disable-next-line rulesdir/no-negated-variables const shouldShowNotFoundPage = useMemo(() => { diff --git a/src/pages/media/AttachmentModalScreen/routes/TransactionReceiptModalContent.tsx b/src/pages/media/AttachmentModalScreen/routes/TransactionReceiptModalContent.tsx index ed52569e23ee..0b442898b1c0 100644 --- a/src/pages/media/AttachmentModalScreen/routes/TransactionReceiptModalContent.tsx +++ b/src/pages/media/AttachmentModalScreen/routes/TransactionReceiptModalContent.tsx @@ -1,7 +1,9 @@ import React, {useCallback, useEffect, useMemo, useState} from 'react'; import {InteractionManager} from 'react-native'; import ConfirmModal from '@components/ConfirmModal'; +// eslint-disable-next-line no-restricted-imports import * as Expensicons from '@components/Icon/Expensicons'; +import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; import useOnyx from '@hooks/useOnyx'; @@ -27,6 +29,7 @@ import useDownloadAttachment from './hooks/useDownloadAttachment'; function TransactionReceiptModalContent({navigation, route}: AttachmentModalScreenProps) { const {reportID, transactionID, action, iouType: iouTypeParam, readonly: readonlyParam, isFromReviewDuplicates: isFromReviewDuplicatesParam, mergeTransactionID} = route.params; + const icons = useMemoizedLazyExpensifyIcons(['Download'] as const); const {translate} = useLocalize(); const {isOffline} = useNetwork(); @@ -177,7 +180,7 @@ function TransactionReceiptModalContent({navigation, route}: AttachmentModalScre } if ((!isOffline && allowDownload && !isLocalSource) || !!draftTransactionID) { menuItems.push({ - icon: Expensicons.Download, + icon: icons.Download, text: translate('common.download'), onSelected: () => onDownloadAttachment({source: innerSource, file}), }); @@ -196,6 +199,7 @@ function TransactionReceiptModalContent({navigation, route}: AttachmentModalScre // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps }, [ + icons.Download, shouldShowReplaceReceiptButton, isOffline, allowDownload, diff --git a/src/pages/settings/AboutPage/AboutPage.tsx b/src/pages/settings/AboutPage/AboutPage.tsx index 04f3962ca761..5e872d2a5b81 100644 --- a/src/pages/settings/AboutPage/AboutPage.tsx +++ b/src/pages/settings/AboutPage/AboutPage.tsx @@ -4,7 +4,9 @@ import {View} from 'react-native'; import type {GestureResponderEvent, StyleProp, ViewStyle} from 'react-native'; import DeviceInfo from 'react-native-device-info'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; +// eslint-disable-next-line no-restricted-imports import * as Expensicons from '@components/Icon/Expensicons'; +// eslint-disable-next-line no-restricted-imports import * as Illustrations from '@components/Icon/Illustrations'; import LottieAnimations from '@components/LottieAnimations'; import MenuItemList from '@components/MenuItemList'; @@ -13,6 +15,7 @@ import ScreenWrapper from '@components/ScreenWrapper'; import ScrollView from '@components/ScrollView'; import Section from '@components/Section'; import Text from '@components/Text'; +import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useThemeStyles from '@hooks/useThemeStyles'; @@ -49,6 +52,7 @@ type MenuItem = { }; function AboutPage() { + const icons = useMemoizedLazyExpensifyIcons(['NewWindow'] as const); const {translate} = useLocalize(); const styles = useThemeStyles(); const popoverAnchor = useRef(null); @@ -70,7 +74,7 @@ function AboutPage() { { translationKey: 'initialSettingsPage.aboutPage.viewTheCode', icon: Expensicons.Eye, - iconRight: Expensicons.NewWindow, + iconRight: icons.NewWindow, action: () => { openExternalLink(CONST.GITHUB_URL); return Promise.resolve(); @@ -80,7 +84,7 @@ function AboutPage() { { translationKey: 'initialSettingsPage.aboutPage.viewOpenJobs', icon: Expensicons.MoneyBag, - iconRight: Expensicons.NewWindow, + iconRight: icons.NewWindow, action: () => { openExternalLink(CONST.UPWORK_URL); return Promise.resolve(); @@ -114,7 +118,7 @@ function AboutPage() { shouldBlockSelection: !!link, wrapperStyle: [styles.sectionMenuItemTopDescription], })); - }, [styles, translate, waitForNavigate]); + }, [icons.NewWindow, styles, translate, waitForNavigate]); const overlayContent = useCallback( () => ( diff --git a/src/pages/settings/AboutPage/ConsolePage.tsx b/src/pages/settings/AboutPage/ConsolePage.tsx index 590601fbc74a..1f546d56f48d 100644 --- a/src/pages/settings/AboutPage/ConsolePage.tsx +++ b/src/pages/settings/AboutPage/ConsolePage.tsx @@ -7,6 +7,7 @@ import type {OnyxEntry} from 'react-native-onyx'; import Button from '@components/Button'; import ConfirmModal from '@components/ConfirmModal'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; +// eslint-disable-next-line no-restricted-imports import * as Expensicons from '@components/Icon/Expensicons'; import InvertedFlatList from '@components/InvertedFlatList'; import type {PopoverMenuItem} from '@components/PopoverMenu'; @@ -15,6 +16,7 @@ import Text from '@components/Text'; import TextInput from '@components/TextInput'; import useIsAuthenticated from '@hooks/useIsAuthenticated'; import useKeyboardShortcut from '@hooks/useKeyboardShortcut'; +import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; import useTheme from '@hooks/useTheme'; @@ -40,6 +42,7 @@ const filterBy = { type FilterBy = (typeof filterBy)[keyof typeof filterBy]; function ConsolePage() { + const icons = useMemoizedLazyExpensifyIcons(['Download', 'UploadAlt'] as const); const [capturedLogs] = useOnyx(ONYXKEYS.LOGS, {canBeMissing: false}); const [shouldStoreLogs] = useOnyx(ONYXKEYS.SHOULD_STORE_LOGS, {canBeMissing: true}); const [input, setInput] = useState(''); @@ -179,7 +182,7 @@ function ConsolePage() { text={translate('initialSettingsPage.debugConsole.saveLog')} onPress={saveLogs} large - icon={Expensicons.Download} + icon={icons.Download} style={[styles.flex1, styles.mr1]} /> {isAuthenticated && ( @@ -187,7 +190,7 @@ function ConsolePage() { text={translate('initialSettingsPage.debugConsole.shareLog')} onPress={shareLogs} large - icon={!isGeneratingLogsFile ? Expensicons.UploadAlt : undefined} + icon={!isGeneratingLogsFile ? icons.UploadAlt : undefined} style={[styles.flex1, styles.ml1]} isLoading={isGeneratingLogsFile} /> diff --git a/src/pages/settings/AppDownloadLinks.tsx b/src/pages/settings/AppDownloadLinks.tsx index d030473bbbd7..fb6bdfb6d98e 100644 --- a/src/pages/settings/AppDownloadLinks.tsx +++ b/src/pages/settings/AppDownloadLinks.tsx @@ -2,12 +2,14 @@ import React, {useRef} from 'react'; import type {View} from 'react-native'; import expensifyLogo from '@assets/images/expensify-logo-round-transparent.png'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; +// eslint-disable-next-line no-restricted-imports import * as Expensicons from '@components/Icon/Expensicons'; import MenuItem from '@components/MenuItem'; import type {MenuItemProps} from '@components/MenuItem'; import QRShare from '@components/QRShare'; import ScreenWrapper from '@components/ScreenWrapper'; import ScrollView from '@components/ScrollView'; +import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import {openExternalLink} from '@libs/actions/Link'; @@ -23,6 +25,7 @@ type DownloadMenuItem = MenuItemProps & { }; function AppDownloadLinksPage() { + const icons = useMemoizedLazyExpensifyIcons(['NewWindow'] as const); const styles = useThemeStyles(); const {translate} = useLocalize(); const popoverAnchor = useRef(null); @@ -35,7 +38,7 @@ function AppDownloadLinksPage() { }, link: CONST.APP_DOWNLOAD_LINKS.ANDROID, icon: Expensicons.Android, - iconRight: Expensicons.NewWindow, + iconRight: icons.NewWindow, }, { translationKey: 'initialSettingsPage.appDownloadLinks.ios.label', @@ -44,7 +47,7 @@ function AppDownloadLinksPage() { }, link: CONST.APP_DOWNLOAD_LINKS.IOS, icon: Expensicons.Apple, - iconRight: Expensicons.NewWindow, + iconRight: icons.NewWindow, }, { translationKey: 'initialSettingsPage.appDownloadLinks.desktop.label', @@ -53,7 +56,7 @@ function AppDownloadLinksPage() { }, link: CONST.APP_DOWNLOAD_LINKS.DESKTOP, icon: Expensicons.Monitor, - iconRight: Expensicons.NewWindow, + iconRight: icons.NewWindow, }, ]; diff --git a/src/pages/settings/InitialSettingsPage.tsx b/src/pages/settings/InitialSettingsPage.tsx index 756e92101e05..006e19e84498 100755 --- a/src/pages/settings/InitialSettingsPage.tsx +++ b/src/pages/settings/InitialSettingsPage.tsx @@ -9,6 +9,7 @@ import AccountSwitcher from '@components/AccountSwitcher'; import AccountSwitcherSkeletonView from '@components/AccountSwitcherSkeletonView'; import ConfirmModal from '@components/ConfirmModal'; import Icon from '@components/Icon'; +// eslint-disable-next-line no-restricted-imports import * as Expensicons from '@components/Icon/Expensicons'; import MenuItem from '@components/MenuItem'; import NavigationTabBar from '@components/Navigation/NavigationTabBar'; @@ -21,6 +22,7 @@ import Text from '@components/Text'; import Tooltip from '@components/Tooltip'; import type {WithCurrentUserPersonalDetailsProps} from '@components/withCurrentUserPersonalDetails'; import withCurrentUserPersonalDetails from '@components/withCurrentUserPersonalDetails'; +import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; import useOnyx from '@hooks/useOnyx'; @@ -85,6 +87,7 @@ type MenuData = { type Menu = {sectionStyle: StyleProp; sectionTranslationKey: TranslationPaths; items: MenuData[]}; function InitialSettingsPage({currentUserPersonalDetails}: InitialSettingsPageProps) { + const icons = useMemoizedLazyExpensifyIcons(['Gear', 'Profile', 'NewWindow'] as const); const [userWallet] = useOnyx(ONYXKEYS.USER_WALLET, {canBeMissing: true}); const [bankAccountList] = useOnyx(ONYXKEYS.BANK_ACCOUNT_LIST, {canBeMissing: true}); const [fundList] = useOnyx(ONYXKEYS.FUND_LIST, {canBeMissing: true}); @@ -184,7 +187,7 @@ function InitialSettingsPage({currentUserPersonalDetails}: InitialSettingsPagePr const items: MenuData[] = [ { translationKey: 'common.profile', - icon: Expensicons.Profile, + icon: icons.Profile, screenName: SCREENS.SETTINGS.PROFILE.ROOT, brickRoadIndicator: profileBrickRoadIndicator, action: () => Navigation.navigate(ROUTES.SETTINGS_PROFILE.getRoute()), @@ -199,7 +202,7 @@ function InitialSettingsPage({currentUserPersonalDetails}: InitialSettingsPagePr }, { translationKey: 'common.preferences', - icon: Expensicons.Gear, + icon: icons.Gear, screenName: SCREENS.SETTINGS.PREFERENCES.ROOT, action: () => Navigation.navigate(ROUTES.SETTINGS_PREFERENCES), }, @@ -232,6 +235,8 @@ function InitialSettingsPage({currentUserPersonalDetails}: InitialSettingsPagePr items, }; }, [ + icons.Gear, + icons.Profile, loginList, privatePersonalDetails, vacationDelegate, @@ -299,7 +304,7 @@ function InitialSettingsPage({currentUserPersonalDetails}: InitialSettingsPagePr { translationKey: 'initialSettingsPage.help', icon: Expensicons.QuestionMark, - iconRight: Expensicons.NewWindow, + iconRight: icons.NewWindow, shouldShowRightIcon: true, link: CONST.NEWHELP_URL, action: () => { @@ -309,7 +314,7 @@ function InitialSettingsPage({currentUserPersonalDetails}: InitialSettingsPagePr { translationKey: 'initialSettingsPage.whatIsNew', icon: Expensicons.TreasureChest, - iconRight: Expensicons.NewWindow, + iconRight: icons.NewWindow, shouldShowRightIcon: true, link: CONST.WHATS_NEW_URL, action: () => { @@ -343,7 +348,7 @@ function InitialSettingsPage({currentUserPersonalDetails}: InitialSettingsPagePr }, ], }; - }, [styles.pt4, classicRedirectMenuItem, tryNewDot?.nudgeMigration, signOut]); + }, [icons.NewWindow, styles.pt4, classicRedirectMenuItem, tryNewDot?.nudgeMigration, signOut]); /** * Return JSX.Element with menu items diff --git a/src/pages/settings/Profile/Avatar/AvatarPage.tsx b/src/pages/settings/Profile/Avatar/AvatarPage.tsx index b4d6a3a61b7e..5ef1c0ade9c0 100644 --- a/src/pages/settings/Profile/Avatar/AvatarPage.tsx +++ b/src/pages/settings/Profile/Avatar/AvatarPage.tsx @@ -9,11 +9,11 @@ import ButtonWithDropdownMenu from '@components/ButtonWithDropdownMenu'; import DotIndicatorMessage from '@components/DotIndicatorMessage'; import FixedFooter from '@components/FixedFooter'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; -import * as Expensicons from '@components/Icon/Expensicons'; import ScreenWrapper from '@components/ScreenWrapper'; import ScrollView from '@components/ScrollView'; import useAvatarMenu from '@hooks/useAvatarMenu'; import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; +import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; import useLetterAvatars from '@hooks/useLetterAvatars'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; @@ -53,6 +53,7 @@ function ProfileAvatar() { const avatarCaptureRef = useRef(null); const isSavingRef = useRef(false); + const icons = useMemoizedLazyExpensifyIcons(['Upload'] as const); const styles = useThemeStyles(); const {translate} = useLocalize(); const [cropImageData, setCropImageData] = useState({...EMPTY_FILE}); @@ -233,7 +234,7 @@ function ProfileAvatar() { if (menuItems?.length <= 1) { return (