From e451c6e629add1ce73873eb3f5aea4786f7a715f Mon Sep 17 00:00:00 2001 From: Samran Ahmed Date: Tue, 18 Nov 2025 17:14:15 +0500 Subject: [PATCH 1/8] Migrate simple illustrations to lazy loading --- src/components/AutoSubmitModal.tsx | 32 ++++++----- src/components/HoldMenuSectionList.tsx | 24 ++++---- .../HoldOrRejectEducationalModal.tsx | 32 ++++++----- src/components/Icon/Illustrations.ts | 56 ------------------- .../Icon/chunks/illustrations.chunk.ts | 50 +++++++++++++++++ .../LocationPermissionModal/index.android.tsx | 5 +- .../LocationPermissionModal/index.desktop.tsx | 5 +- .../LocationPermissionModal/index.tsx | 5 +- src/components/MigratedUserWelcomeModal.tsx | 32 ++++++----- src/libs/SubscriptionUtils.ts | 5 +- .../BaseOnboardingPurpose.tsx | 18 +++--- .../BaseOnboardingWorkEmail.tsx | 4 +- .../ConnectedVerifiedBankAccount.tsx | 5 +- .../NonUSD/Finish/index.tsx | 4 +- .../NonUSD/SignerInfo/HangTight.tsx | 7 ++- .../components/Enable2FACard.tsx | 5 +- src/pages/Search/EmptySearchView.tsx | 25 +++++---- src/pages/TeachersUnite/SaveTheWorldPage.tsx | 8 ++- src/pages/Travel/ManageTrips.tsx | 5 +- src/pages/domain/DomainSamlPage.tsx | 35 ++++++------ src/pages/settings/AboutPage/AboutPage.tsx | 5 +- src/pages/settings/Profile/ProfilePage.tsx | 5 +- .../Security/TwoFactorAuth/CopyCodesPage.tsx | 7 ++- .../Security/TwoFactorAuth/EnabledPage.tsx | 7 ++- .../BillingBanner/EarlyDiscountBanner.tsx | 8 ++- .../BillingBanner/PreTrialBillingBanner.tsx | 8 ++- .../BillingBanner/TrialEndedBillingBanner.tsx | 8 ++- .../TrialStartedBillingBanner.tsx | 8 ++- .../Subscription/PaymentCard/index.tsx | 8 ++- .../SubscriptionPlan/SubscriptionPlanCard.tsx | 5 ++ .../SubscriptionSettings/index.native.tsx | 11 ++-- .../SubscriptionSettings/index.tsx | 33 +++++------ .../settings/Wallet/WalletPage/WalletPage.tsx | 8 ++- .../workspace/WorkspaceMoreFeaturesPage.tsx | 16 +++++- src/pages/workspace/WorkspacesListRow.tsx | 25 +++++---- .../distanceRates/PolicyDistanceRatesPage.tsx | 8 ++- .../expensifyCard/issueNew/CardTypeStep.tsx | 4 +- .../members/WorkspaceOwnerPaymentCardForm.tsx | 8 ++- .../WorkspaceReceiptPartnersPage.tsx | 8 ++- .../workspace/upgrade/GenericFeaturesView.tsx | 8 ++- 40 files changed, 319 insertions(+), 241 deletions(-) diff --git a/src/components/AutoSubmitModal.tsx b/src/components/AutoSubmitModal.tsx index 401675d66cce..b75ac9cdc897 100644 --- a/src/components/AutoSubmitModal.tsx +++ b/src/components/AutoSubmitModal.tsx @@ -1,5 +1,6 @@ -import React, {useCallback} from 'react'; +import React, {useCallback, useMemo} from 'react'; import {InteractionManager, View} from 'react-native'; +import {useMemoizedLazyIllustrations} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; import useStyleUtils from '@hooks/useStyleUtils'; @@ -15,24 +16,27 @@ import Icon from './Icon'; import * as Illustrations from './Icon/Illustrations'; import Text from './Text'; -const menuSections = [ - { - icon: Illustrations.PaperAirplane, - titleTranslationKey: 'autoSubmitModal.submittedExpensesTitle', - descriptionTranslationKey: 'autoSubmitModal.submittedExpensesDescription', - }, - { - icon: Illustrations.Pencil, - titleTranslationKey: 'autoSubmitModal.pendingExpensesTitle', - descriptionTranslationKey: 'autoSubmitModal.pendingExpensesDescription', - }, -]; - function AutoSubmitModal() { const [dismissedASAPSubmitExplanation] = useOnyx(ONYXKEYS.NVP_DISMISSED_ASAP_SUBMIT_EXPLANATION, {canBeMissing: true}); const {translate} = useLocalize(); const styles = useThemeStyles(); const StyleUtils = useStyleUtils(); + const illustrations = useMemoizedLazyIllustrations(['PaperAirplane', 'Pencil'] as const); + const menuSections = useMemo( + () => [ + { + icon: illustrations.PaperAirplane, + titleTranslationKey: 'autoSubmitModal.submittedExpensesTitle', + descriptionTranslationKey: 'autoSubmitModal.submittedExpensesDescription', + }, + { + icon: illustrations.Pencil, + titleTranslationKey: 'autoSubmitModal.pendingExpensesTitle', + descriptionTranslationKey: 'autoSubmitModal.pendingExpensesDescription', + }, + ], + [illustrations], + ); const onClose = useCallback((willShowAgain: boolean) => { // eslint-disable-next-line @typescript-eslint/no-deprecated diff --git a/src/components/HoldMenuSectionList.tsx b/src/components/HoldMenuSectionList.tsx index b2dc5b1213e9..96331a7152f9 100644 --- a/src/components/HoldMenuSectionList.tsx +++ b/src/components/HoldMenuSectionList.tsx @@ -1,12 +1,12 @@ import React from 'react'; import {View} from 'react-native'; +import {useMemoizedLazyIllustrations} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import variables from '@styles/variables'; import type {TranslationPaths} from '@src/languages/types'; import type IconAsset from '@src/types/utils/IconAsset'; import Icon from './Icon'; -import * as Illustrations from './Icon/Illustrations'; import Text from './Text'; type HoldMenuSection = { @@ -17,20 +17,20 @@ type HoldMenuSection = { titleTranslationKey: TranslationPaths; }; -const holdMenuSections: HoldMenuSection[] = [ - { - icon: Illustrations.Stopwatch, - titleTranslationKey: 'iou.holdIsLeftBehind', - }, - { - icon: Illustrations.RealtimeReport, - titleTranslationKey: 'iou.unholdWhenReady', - }, -]; - function HoldMenuSectionList() { const {translate} = useLocalize(); const styles = useThemeStyles(); + const illustrations = useMemoizedLazyIllustrations(['RealtimeReport', 'Stopwatch'] as const); + const holdMenuSections: HoldMenuSection[] = [ + { + icon: illustrations.Stopwatch, + titleTranslationKey: 'iou.holdIsLeftBehind', + }, + { + icon: illustrations.RealtimeReport, + titleTranslationKey: 'iou.unholdWhenReady', + }, + ]; return ( <> diff --git a/src/components/HoldOrRejectEducationalModal.tsx b/src/components/HoldOrRejectEducationalModal.tsx index 3a2ccd478452..ab5859331793 100644 --- a/src/components/HoldOrRejectEducationalModal.tsx +++ b/src/components/HoldOrRejectEducationalModal.tsx @@ -1,6 +1,7 @@ import React from 'react'; import {View} from 'react-native'; import useBeforeRemove from '@hooks/useBeforeRemove'; +import {useMemoizedLazyIllustrations} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import variables from '@styles/variables'; @@ -28,24 +29,25 @@ type HoldOrRejectEducationalModalProps = { onConfirm: () => void; }; -const menuSections: SectionMenuItem[] = [ - { - icon: Illustrations.Stopwatch, - titleTranslationKey: 'iou.reject.holdExpenseTitle', - }, - { - icon: Illustrations.RealtimeReport, - titleTranslationKey: 'iou.reject.heldExpenseLeftBehindTitle', - }, - { - icon: Illustrations.ThumbsDown, - titleTranslationKey: 'iou.reject.rejectExpenseTitle', - }, -]; - function HoldOrRejectEducationalModal({onClose, onConfirm}: HoldOrRejectEducationalModalProps) { const {translate} = useLocalize(); const styles = useThemeStyles(); + const illustrations = useMemoizedLazyIllustrations(['RealtimeReport', 'Stopwatch', 'ThumbsDown'] as const); + + const menuSections: SectionMenuItem[] = [ + { + icon: illustrations.Stopwatch, + titleTranslationKey: 'iou.reject.holdExpenseTitle', + }, + { + icon: illustrations.RealtimeReport, + titleTranslationKey: 'iou.reject.heldExpenseLeftBehindTitle', + }, + { + icon: illustrations.ThumbsDown, + titleTranslationKey: 'iou.reject.rejectExpenseTitle', + }, + ]; useBeforeRemove(onClose); diff --git a/src/components/Icon/Illustrations.ts b/src/components/Icon/Illustrations.ts index 456e4ae1a055..a369be0c37a9 100644 --- a/src/components/Icon/Illustrations.ts +++ b/src/components/Icon/Illustrations.ts @@ -57,9 +57,7 @@ import Abacus from '@assets/images/simple-illustrations/simple-illustration__aba import Alert from '@assets/images/simple-illustrations/simple-illustration__alert.svg'; import Approval from '@assets/images/simple-illustrations/simple-illustration__approval.svg'; import Binoculars from '@assets/images/simple-illustrations/simple-illustration__binoculars.svg'; -import BlueShield from '@assets/images/simple-illustrations/simple-illustration__blueshield.svg'; import Buildings from '@assets/images/simple-illustrations/simple-illustration__buildings.svg'; -import CarIce from '@assets/images/simple-illustrations/simple-illustration__car-ice.svg'; import Car from '@assets/images/simple-illustrations/simple-illustration__car.svg'; import PinkCar from '@assets/images/simple-illustrations/simple-illustration__car_pink.svg'; import ChatBubbles from '@assets/images/simple-illustrations/simple-illustration__chatbubbles.svg'; @@ -84,33 +82,7 @@ import LockClosedOrange from '@assets/images/simple-illustrations/simple-illustr import LockOpen from '@assets/images/simple-illustrations/simple-illustration__lockopen.svg'; import Luggage from '@assets/images/simple-illustrations/simple-illustration__luggage.svg'; import Mailbox from '@assets/images/simple-illustrations/simple-illustration__mailbox.svg'; -import ExpensifyMobileApp from '@assets/images/simple-illustrations/simple-illustration__mobileapp.svg'; -import MoneyIntoWallet from '@assets/images/simple-illustrations/simple-illustration__moneyintowallet.svg'; import OpenSafe from '@assets/images/simple-illustrations/simple-illustration__opensafe.svg'; -import PalmTree from '@assets/images/simple-illustrations/simple-illustration__palmtree.svg'; -import PaperAirplane from '@assets/images/simple-illustrations/simple-illustration__paperairplane.svg'; -import Pencil from '@assets/images/simple-illustrations/simple-illustration__pencil.svg'; -import PiggyBank from '@assets/images/simple-illustrations/simple-illustration__piggybank.svg'; -import Pillow from '@assets/images/simple-illustrations/simple-illustration__pillow.svg'; -import Profile from '@assets/images/simple-illustrations/simple-illustration__profile.svg'; -import QRCode from '@assets/images/simple-illustrations/simple-illustration__qr-code.svg'; -import RealtimeReport from '@assets/images/simple-illustrations/simple-illustration__realtimereports.svg'; -import ReceiptLocationMarker from '@assets/images/simple-illustrations/simple-illustration__receipt-location-marker.svg'; -import ReceiptPartners from '@assets/images/simple-illustrations/simple-illustration__receipt.svg'; -import ReceiptUpload from '@assets/images/simple-illustrations/simple-illustration__receiptupload.svg'; -import SendMoney from '@assets/images/simple-illustrations/simple-illustration__sendmoney.svg'; -import ShieldYellow from '@assets/images/simple-illustrations/simple-illustration__shield.svg'; -import SplitBill from '@assets/images/simple-illustrations/simple-illustration__splitbill.svg'; -import Stopwatch from '@assets/images/simple-illustrations/simple-illustration__stopwatch.svg'; -import SubscriptionAnnual from '@assets/images/simple-illustrations/simple-illustration__subscription-annual.svg'; -import SubscriptionPPU from '@assets/images/simple-illustrations/simple-illustration__subscription-ppu.svg'; -import TeachersUnite from '@assets/images/simple-illustrations/simple-illustration__teachers-unite.svg'; -import ThumbsDown from '@assets/images/simple-illustrations/simple-illustration__thumbsdown.svg'; -import ThumbsUpStars from '@assets/images/simple-illustrations/simple-illustration__thumbsupstars.svg'; -import Tire from '@assets/images/simple-illustrations/simple-illustration__tire.svg'; -import TrashCan from '@assets/images/simple-illustrations/simple-illustration__trashcan.svg'; -import TreasureChest from '@assets/images/simple-illustrations/simple-illustration__treasurechest.svg'; -import VirtualCard from '@assets/images/simple-illustrations/simple-illustration__virtualcard.svg'; import ExpensifyApprovedLogo from '@assets/images/subscription-details__approvedlogo.svg'; import TurtleInShell from '@assets/images/turtle-in-shell.svg'; @@ -136,7 +108,6 @@ export { SewerDino, ToddWithPhones, ToddInCar, - ShieldYellow, BrokenCompanyCardBankConnection, CreditCardsNewGreen, LaptopWithSecondScreenAndHourglass, @@ -144,23 +115,15 @@ export { LaptopWithSecondScreenX, LockOpen, Luggage, - MoneyIntoWallet, ConciergeBubble, - TreasureChest, - ThumbsUpStars, Hands, HeadSet, SmartScan, Hourglass, CommentBubbles, - TrashCan, - Profile, Puzzle, - PalmTree, LockClosed, Gears, - QRCode, - RealtimeReport, HoldExpense, ReceiptFairy, Approval, @@ -169,29 +132,15 @@ export { House, Buildings, Alert, - TeachersUnite, Abacus, Binoculars, - ReceiptUpload, - SplitBill, - PiggyBank, - Pillow, Car, - Pencil, - CarIce, - ReceiptLocationMarker, Lightbulb, - Stopwatch, - SubscriptionAnnual, - SubscriptionPPU, ExpensifyApprovedLogo, - SendMoney, CheckmarkCircle, CreditCardEyes, LockClosedOrange, FolderWithPapers, - VirtualCard, - Tire, Filters, RunningTurtle, CompanyCardsPendingState, @@ -213,21 +162,16 @@ export { ChaseCompanyCardDetailLarge, CitibankCompanyCardDetailLarge, MasterCardCompanyCardDetailLarge, - ReceiptPartners, StripeCompanyCardDetailLarge, VisaCompanyCardDetailLarge, WellsFargoCompanyCardDetailLarge, Flash, - ExpensifyMobileApp, ModalHoldOrReject, - ThumbsDown, PlaidCompanyCardDetailLarge, PlaidCompanyCardDetail, ReceiptsStackedOnPin, - PaperAirplane, CardReplacementSuccess, EmptyShelves, - BlueShield, OpenSafe, LaptopOnDeskWithCoffeeAndKey, }; diff --git a/src/components/Icon/chunks/illustrations.chunk.ts b/src/components/Icon/chunks/illustrations.chunk.ts index 866363886244..4abc16ff2b36 100644 --- a/src/components/Icon/chunks/illustrations.chunk.ts +++ b/src/components/Icon/chunks/illustrations.chunk.ts @@ -23,15 +23,40 @@ import HandCard from '@assets/images/simple-illustrations/simple-illustration__h import InvoiceBlue from '@assets/images/simple-illustrations/simple-illustration__invoice.svg'; import Luggage from '@assets/images/simple-illustrations/simple-illustration__luggage.svg'; import MagnifyingGlassMoney from '@assets/images/simple-illustrations/simple-illustration__magnifyingglass-money.svg'; +import ExpensifyMobileApp from '@assets/images/simple-illustrations/simple-illustration__mobileapp.svg'; import MoneyReceipts from '@assets/images/simple-illustrations/simple-illustration__money-receipts.svg'; +import MoneyIntoWallet from '@assets/images/simple-illustrations/simple-illustration__moneyintowallet.svg'; import MoneyWings from '@assets/images/simple-illustrations/simple-illustration__moneywings.svg'; +import PalmTree from '@assets/images/simple-illustrations/simple-illustration__palmtree.svg'; +import PaperAirplane from '@assets/images/simple-illustrations/simple-illustration__paperairplane.svg'; import Pencil from '@assets/images/simple-illustrations/simple-illustration__pencil.svg'; import PerDiem from '@assets/images/simple-illustrations/simple-illustration__perdiem.svg'; +import PiggyBank from '@assets/images/simple-illustrations/simple-illustration__piggybank.svg'; +import Pillow from '@assets/images/simple-illustrations/simple-illustration__pillow.svg'; +import Profile from '@assets/images/simple-illustrations/simple-illustration__profile.svg'; +import QRCode from '@assets/images/simple-illustrations/simple-illustration__qr-code.svg'; +import RealtimeReport from '@assets/images/simple-illustrations/simple-illustration__realtimereports.svg'; +import ReceiptLocationMarker from '@assets/images/simple-illustrations/simple-illustration__receipt-location-marker.svg'; import ReceiptWrangler from '@assets/images/simple-illustrations/simple-illustration__receipt-wrangler.svg'; +import ReceiptPartners from '@assets/images/simple-illustrations/simple-illustration__receipt.svg'; +import ReceiptUpload from '@assets/images/simple-illustrations/simple-illustration__receiptupload.svg'; import ReportReceipt from '@assets/images/simple-illustrations/simple-illustration__report-receipt.svg'; import Rules from '@assets/images/simple-illustrations/simple-illustration__rules.svg'; +import SendMoney from '@assets/images/simple-illustrations/simple-illustration__sendmoney.svg'; +import ShieldYellow from '@assets/images/simple-illustrations/simple-illustration__shield.svg'; +import SplitBill from '@assets/images/simple-illustrations/simple-illustration__splitbill.svg'; +import Stopwatch from '@assets/images/simple-illustrations/simple-illustration__stopwatch.svg'; +import SubscriptionAnnual from '@assets/images/simple-illustrations/simple-illustration__subscription-annual.svg'; +import SubscriptionPPU from '@assets/images/simple-illustrations/simple-illustration__subscription-ppu.svg'; import Tag from '@assets/images/simple-illustrations/simple-illustration__tag.svg'; +import TeachersUnite from '@assets/images/simple-illustrations/simple-illustration__teachers-unite.svg'; +import ThumbsDown from '@assets/images/simple-illustrations/simple-illustration__thumbsdown.svg'; +import ThumbsUpStars from '@assets/images/simple-illustrations/simple-illustration__thumbsupstars.svg'; +import Tire from '@assets/images/simple-illustrations/simple-illustration__tire.svg'; +import TrashCan from '@assets/images/simple-illustrations/simple-illustration__trashcan.svg'; +import TreasureChest from '@assets/images/simple-illustrations/simple-illustration__treasurechest.svg'; import CompanyCard from '@assets/images/simple-illustrations/simple-illustration__twocards-horizontal.svg'; +import VirtualCard from '@assets/images/simple-illustrations/simple-illustration__virtualcard.svg'; import Workflows from '@assets/images/simple-illustrations/simple-illustration__workflows.svg'; // Create the illustrations object with all imported illustrations @@ -76,6 +101,31 @@ const Illustrations = { Luggage, // Legacy aliases for compatibility Car: CompanyCard, // Fallback for Car illustration requests + ExpensifyMobileApp, + MoneyIntoWallet, + PalmTree, + PaperAirplane, + PiggyBank, + Pillow, + Profile, + QRCode, + RealtimeReport, + ReceiptLocationMarker, + ReceiptPartners, + ReceiptUpload, + SendMoney, + ShieldYellow, + SplitBill, + Stopwatch, + SubscriptionAnnual, + SubscriptionPPU, + TeachersUnite, + ThumbsDown, + ThumbsUpStars, + Tire, + TrashCan, + TreasureChest, + VirtualCard, }; /** diff --git a/src/components/LocationPermissionModal/index.android.tsx b/src/components/LocationPermissionModal/index.android.tsx index 9d4ae24ed483..098eca38e15b 100644 --- a/src/components/LocationPermissionModal/index.android.tsx +++ b/src/components/LocationPermissionModal/index.android.tsx @@ -2,7 +2,7 @@ import React, {useEffect, useState} from 'react'; import {Linking} from 'react-native'; import {RESULTS} from 'react-native-permissions'; import ConfirmModal from '@components/ConfirmModal'; -import * as Illustrations from '@components/Icon/Illustrations'; +import {useMemoizedLazyIllustrations} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import {getLocationPermission, requestLocationPermission} from '@pages/iou/request/step/IOURequestStepScan/LocationPermission'; @@ -15,6 +15,7 @@ function LocationPermissionModal({startPermissionFlow, resetPermissionFlow, onDe const styles = useThemeStyles(); const {translate} = useLocalize(); + const illustrations = useMemoizedLazyIllustrations(['ReceiptLocationMarker'] as const); useEffect(() => { if (!startPermissionFlow) { @@ -88,7 +89,7 @@ function LocationPermissionModal({startPermissionFlow, resetPermissionFlow, onDe title={translate(hasError ? 'receipt.locationErrorTitle' : 'receipt.locationAccessTitle')} titleContainerStyles={[styles.mt2, styles.mb0]} titleStyles={[styles.textHeadline]} - iconSource={Illustrations.ReceiptLocationMarker} + iconSource={illustrations.ReceiptLocationMarker} iconFill={false} iconWidth={140} iconHeight={120} diff --git a/src/components/LocationPermissionModal/index.desktop.tsx b/src/components/LocationPermissionModal/index.desktop.tsx index 8af5cfc6d34b..3f86fa6ba60d 100644 --- a/src/components/LocationPermissionModal/index.desktop.tsx +++ b/src/components/LocationPermissionModal/index.desktop.tsx @@ -2,8 +2,8 @@ import lodashDebounce from 'lodash/debounce'; import React, {useCallback, useEffect, useMemo, useState} from 'react'; import {RESULTS} from 'react-native-permissions'; import ConfirmModal from '@components/ConfirmModal'; -import * as Illustrations from '@components/Icon/Illustrations'; import ELECTRON_EVENTS from '@desktop/ELECTRON_EVENTS'; +import {useMemoizedLazyIllustrations} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import getPlatform from '@libs/getPlatform'; @@ -19,6 +19,7 @@ function LocationPermissionModal({startPermissionFlow, resetPermissionFlow, onDe const styles = useThemeStyles(); const {translate} = useLocalize(); + const illustrations = useMemoizedLazyIllustrations(['ReceiptLocationMarker'] as const); const isWeb = getPlatform() === CONST.PLATFORM.WEB; @@ -132,7 +133,7 @@ function LocationPermissionModal({startPermissionFlow, resetPermissionFlow, onDe title={translate(hasError ? 'receipt.locationErrorTitle' : 'receipt.locationAccessTitle')} titleContainerStyles={[styles.mt2, styles.mb0]} titleStyles={[styles.textHeadline]} - iconSource={Illustrations.ReceiptLocationMarker} + iconSource={illustrations.ReceiptLocationMarker} iconFill={false} iconWidth={140} iconHeight={120} diff --git a/src/components/LocationPermissionModal/index.tsx b/src/components/LocationPermissionModal/index.tsx index 3dbb7e7425b0..cc9895ecf4a6 100644 --- a/src/components/LocationPermissionModal/index.tsx +++ b/src/components/LocationPermissionModal/index.tsx @@ -3,7 +3,7 @@ import React, {useCallback, useEffect, useMemo, useState} from 'react'; import {Linking} from 'react-native'; import {RESULTS} from 'react-native-permissions'; import ConfirmModal from '@components/ConfirmModal'; -import * as Illustrations from '@components/Icon/Illustrations'; +import {useMemoizedLazyIllustrations} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import getPlatform from '@libs/getPlatform'; @@ -19,6 +19,7 @@ function LocationPermissionModal({startPermissionFlow, resetPermissionFlow, onDe const styles = useThemeStyles(); const {translate} = useLocalize(); + const illustrations = useMemoizedLazyIllustrations(['ReceiptLocationMarker'] as const); const isWeb = getPlatform() === CONST.PLATFORM.WEB; @@ -144,7 +145,7 @@ function LocationPermissionModal({startPermissionFlow, resetPermissionFlow, onDe title={translate(hasError ? 'receipt.locationErrorTitle' : 'receipt.locationAccessTitle')} titleContainerStyles={[styles.mt2, styles.mb0]} titleStyles={[styles.textHeadline]} - iconSource={Illustrations.ReceiptLocationMarker} + iconSource={illustrations.ReceiptLocationMarker} iconFill={false} iconWidth={140} iconHeight={120} diff --git a/src/components/MigratedUserWelcomeModal.tsx b/src/components/MigratedUserWelcomeModal.tsx index 5943df77e296..cf015e858a83 100644 --- a/src/components/MigratedUserWelcomeModal.tsx +++ b/src/components/MigratedUserWelcomeModal.tsx @@ -2,6 +2,7 @@ import {useRoute} from '@react-navigation/native'; import {tryNewDotOnyxSelector} from '@selectors/Onboarding'; import React, {useEffect, useState} from 'react'; import {View} from 'react-native'; +import {useMemoizedLazyIllustrations} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; @@ -28,25 +29,26 @@ import * as Illustrations from './Icon/Illustrations'; import LottieAnimations from './LottieAnimations'; import RenderHTML from './RenderHTML'; -const ExpensifyFeatures: FeatureListItem[] = [ - { - icon: Illustrations.ChatBubbles, - translationKey: 'migratedUserWelcomeModal.features.chat', - }, - { - icon: Illustrations.Flash, - translationKey: 'migratedUserWelcomeModal.features.scanReceipt', - }, - { - icon: Illustrations.ExpensifyMobileApp, - translationKey: 'migratedUserWelcomeModal.features.crossPlatform', - }, -]; - function MigratedUserWelcomeModal() { const {translate} = useLocalize(); const styles = useThemeStyles(); const StyleUtils = useStyleUtils(); + const illustrations = useMemoizedLazyIllustrations(['ExpensifyMobileApp'] as const); + const ExpensifyFeatures: FeatureListItem[] = [ + { + icon: Illustrations.ChatBubbles, + translationKey: 'migratedUserWelcomeModal.features.chat', + }, + { + icon: Illustrations.Flash, + translationKey: 'migratedUserWelcomeModal.features.scanReceipt', + }, + { + icon: illustrations.ExpensifyMobileApp, + translationKey: 'migratedUserWelcomeModal.features.crossPlatform', + }, + ]; + const {shouldUseNarrowLayout} = useResponsiveLayout(); const {typeMenuSections} = useSearchTypeMenuSections(); const [isModalDisabled, setIsModalDisabled] = useState(true); diff --git a/src/libs/SubscriptionUtils.ts b/src/libs/SubscriptionUtils.ts index 2f940513152a..345624161f19 100644 --- a/src/libs/SubscriptionUtils.ts +++ b/src/libs/SubscriptionUtils.ts @@ -4,6 +4,7 @@ import type {OnyxCollection, OnyxEntry} from 'react-native-onyx'; import Onyx from 'react-native-onyx'; import type {SvgProps} from 'react-native-svg'; import type {ValueOf} from 'type-fest'; +import type {IllustrationName} from '@components/Icon/IllustrationLoader'; import * as Illustrations from '@components/Icon/Illustrations'; import type {LocalizedTranslate} from '@components/LocaleContextProvider'; import type {PreferredCurrency} from '@hooks/usePreferredCurrency'; @@ -13,6 +14,7 @@ import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type {BillingGraceEndPeriod, BillingStatus, Fund, FundList, IntroSelected, Policy, StripeCustomerID} from '@src/types/onyx'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; +import IconAsset from '@src/types/utils/IconAsset'; import {convertToShortDisplayString} from './CurrencyUtils'; import {getOwnedPaidPolicies, isPolicyOwner} from './PolicyUtils'; @@ -555,6 +557,7 @@ function getSubscriptionPlanInfo( preferredCurrency: PreferredCurrency, isFromComparisonModal: boolean, hasTeam2025Pricing: boolean, + illustrations: Partial>, ): SubscriptionPlanInfo { const priceValue = getSubscriptionPrice(subscriptionPlan, preferredCurrency, privateSubscriptionType, hasTeam2025Pricing); const price = convertToShortDisplayString(priceValue, preferredCurrency); @@ -606,7 +609,7 @@ function getSubscriptionPlanInfo( translate('subscription.yourPlan.control.benefit7'), translate('subscription.yourPlan.control.benefit8'), ], - src: Illustrations.ShieldYellow, + src: illustrations.ShieldYellow as React.FC, description: translate('subscription.yourPlan.control.description'), }; } diff --git a/src/pages/OnboardingPurpose/BaseOnboardingPurpose.tsx b/src/pages/OnboardingPurpose/BaseOnboardingPurpose.tsx index 8ee9ab3f4047..dc363acaf1f7 100644 --- a/src/pages/OnboardingPurpose/BaseOnboardingPurpose.tsx +++ b/src/pages/OnboardingPurpose/BaseOnboardingPurpose.tsx @@ -9,6 +9,7 @@ import type {MenuItemProps} from '@components/MenuItem'; import MenuItemList from '@components/MenuItemList'; import ScreenWrapper from '@components/ScreenWrapper'; import Text from '@components/Text'; +import {useMemoizedLazyIllustrations} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useOnboardingMessages from '@hooks/useOnboardingMessages'; import useOnyx from '@hooks/useOnyx'; @@ -39,14 +40,6 @@ function getOnboardingChoices(customChoices: OnboardingPurpose[]) { return selectableOnboardingChoices.filter((choice) => customChoices.includes(choice)); } -const menuIcons = { - [CONST.ONBOARDING_CHOICES.EMPLOYER]: Illustrations.ReceiptUpload, - [CONST.ONBOARDING_CHOICES.MANAGE_TEAM]: Illustrations.Abacus, - [CONST.ONBOARDING_CHOICES.PERSONAL_SPEND]: Illustrations.PiggyBank, - [CONST.ONBOARDING_CHOICES.CHAT_SPLIT]: Illustrations.SplitBill, - [CONST.ONBOARDING_CHOICES.LOOKING_AROUND]: Illustrations.Binoculars, -}; - function BaseOnboardingPurpose({shouldUseNativeStyles, shouldEnableMaxHeight, route}: BaseOnboardingPurposeProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); @@ -67,6 +60,15 @@ function BaseOnboardingPurpose({shouldUseNativeStyles, shouldEnableMaxHeight, ro const [customChoices = getEmptyArray()] = useOnyx(ONYXKEYS.ONBOARDING_CUSTOM_CHOICES, {canBeMissing: true}); const onboardingChoices = getOnboardingChoices(customChoices); + const illustrations = useMemoizedLazyIllustrations(['PiggyBank', 'ReceiptUpload', 'SplitBill'] as const); + + const menuIcons = { + [CONST.ONBOARDING_CHOICES.EMPLOYER]: illustrations.ReceiptUpload, + [CONST.ONBOARDING_CHOICES.MANAGE_TEAM]: Illustrations.Abacus, + [CONST.ONBOARDING_CHOICES.PERSONAL_SPEND]: illustrations.PiggyBank, + [CONST.ONBOARDING_CHOICES.CHAT_SPLIT]: illustrations.SplitBill, + [CONST.ONBOARDING_CHOICES.LOOKING_AROUND]: Illustrations.Binoculars, + }; const menuItems: MenuItemProps[] = onboardingChoices.map((choice) => { const translationKey = `onboarding.purpose.${choice}` as const; diff --git a/src/pages/OnboardingWorkEmail/BaseOnboardingWorkEmail.tsx b/src/pages/OnboardingWorkEmail/BaseOnboardingWorkEmail.tsx index ac9155fec631..ba7f15a257df 100644 --- a/src/pages/OnboardingWorkEmail/BaseOnboardingWorkEmail.tsx +++ b/src/pages/OnboardingWorkEmail/BaseOnboardingWorkEmail.tsx @@ -16,6 +16,7 @@ import ScreenWrapper from '@components/ScreenWrapper'; import Text from '@components/Text'; import TextInput from '@components/TextInput'; import useAutoFocusInput from '@hooks/useAutoFocusInput'; +import {useMemoizedLazyIllustrations} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; import useOnyx from '@hooks/useOnyx'; @@ -58,6 +59,7 @@ function BaseOnboardingWorkEmail({shouldUseNativeStyles}: BaseOnboardingWorkEmai const ICON_SIZE = 48; const operatingSystem = getOperatingSystem(); const isFocused = useIsFocused(); + const illustrations = useMemoizedLazyIllustrations(['Profile'] as const); useEffect(() => { setOnboardingErrorMessage(null); @@ -126,7 +128,7 @@ function BaseOnboardingWorkEmail({shouldUseNativeStyles}: BaseOnboardingWorkEmai shouldRenderEmail: true, }, { - icon: Illustrations.Profile, + icon: illustrations.Profile, titleTranslationKey: 'onboarding.workEmail.explanationModal.descriptionTwo', }, { diff --git a/src/pages/ReimbursementAccount/ConnectedVerifiedBankAccount.tsx b/src/pages/ReimbursementAccount/ConnectedVerifiedBankAccount.tsx index 2283603d8f46..4eb93f312590 100644 --- a/src/pages/ReimbursementAccount/ConnectedVerifiedBankAccount.tsx +++ b/src/pages/ReimbursementAccount/ConnectedVerifiedBankAccount.tsx @@ -3,13 +3,13 @@ import type {OnyxEntry} from 'react-native-onyx'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import getBankIcon from '@components/Icon/BankIcons'; import {Close} from '@components/Icon/Expensicons'; -import {ThumbsUpStars} from '@components/Icon/Illustrations'; import MenuItem from '@components/MenuItem'; import OfflineWithFeedback from '@components/OfflineWithFeedback'; 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 useLocalize from '@hooks/useLocalize'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useThemeStyles from '@hooks/useThemeStyles'; @@ -60,6 +60,7 @@ function ConnectedVerifiedBankAccount({ const errors = reimbursementAccount?.errors ?? {}; const pendingAction = reimbursementAccount?.pendingAction; const shouldShowResetModal = reimbursementAccount?.shouldShowResetModal ?? false; + const illustrations = useMemoizedLazyIllustrations(['ThumbsUpStars'] as const); return (
navigateToConciergeChat(true); + const illustrations = useMemoizedLazyIllustrations(['ShieldYellow'] as const); return (
loadIllustration('Pillow' as IllustrationName)); const handleSendReminder = () => { if (!signerEmail || !policyID) { @@ -66,7 +69,7 @@ function HangTight({policyID, bankAccountID}: HangTightProps) { {translate('signerInfoStep.hangTight')} diff --git a/src/pages/ReimbursementAccount/USD/ConnectBankAccount/components/Enable2FACard.tsx b/src/pages/ReimbursementAccount/USD/ConnectBankAccount/components/Enable2FACard.tsx index 94a07400205f..3f995a353f75 100644 --- a/src/pages/ReimbursementAccount/USD/ConnectBankAccount/components/Enable2FACard.tsx +++ b/src/pages/ReimbursementAccount/USD/ConnectBankAccount/components/Enable2FACard.tsx @@ -1,9 +1,11 @@ import React from 'react'; import {View} from 'react-native'; import {Shield} from '@components/Icon/Expensicons'; -import {ShieldYellow} from '@components/Icon/Illustrations'; +import {loadIllustration} from '@components/Icon/IllustrationLoader'; +import type {IllustrationName} from '@components/Icon/IllustrationLoader'; import Section from '@components/Section'; import Text from '@components/Text'; +import {useMemoizedLazyAsset} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useThemeStyles from '@hooks/useThemeStyles'; @@ -18,6 +20,7 @@ function Enable2FACard({policyID}: Enable2FACardProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); const {shouldUseNarrowLayout} = useResponsiveLayout(); + const {asset: ShieldYellow} = useMemoizedLazyAsset(() => loadIllustration('ShieldYellow' as IllustrationName)); return (
[number]; function EmptySearchView({similarSearchHash, type, hasResults}: EmptySearchViewProps) { @@ -176,6 +166,17 @@ function EmptySearchViewContent({ canBeMissing: true, selector: hasExpenseReportsSelector, }); + const illustrations = useMemoizedLazyIllustrations(['PiggyBank'] as const); + const tripsFeatures: FeatureListItem[] = [ + { + icon: illustrations.PiggyBank, + translationKey: 'travel.features.saveMoney', + }, + { + icon: Alert, + translationKey: 'travel.features.alerts', + }, + ]; const [tryNewDot] = useOnyx(ONYXKEYS.NVP_TRY_NEW_DOT, {selector: tryNewDotOnyxSelector, canBeMissing: true}); diff --git a/src/pages/TeachersUnite/SaveTheWorldPage.tsx b/src/pages/TeachersUnite/SaveTheWorldPage.tsx index dcdab230d899..9ccd4226f245 100644 --- a/src/pages/TeachersUnite/SaveTheWorldPage.tsx +++ b/src/pages/TeachersUnite/SaveTheWorldPage.tsx @@ -1,12 +1,14 @@ import React, {useMemo} from 'react'; import {View} from 'react-native'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; -import * as Illustrations from '@components/Icon/Illustrations'; +import {loadIllustration} from '@components/Icon/IllustrationLoader'; +import type {IllustrationName} from '@components/Icon/IllustrationLoader'; import LottieAnimations from '@components/LottieAnimations'; import MenuItemList from '@components/MenuItemList'; import ScreenWrapper from '@components/ScreenWrapper'; import ScrollView from '@components/ScrollView'; import Section from '@components/Section'; +import {useMemoizedLazyAsset} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useTheme from '@hooks/useTheme'; @@ -23,7 +25,7 @@ function SaveTheWorldPage() { const waitForNavigate = useWaitForNavigation(); const {shouldUseNarrowLayout} = useResponsiveLayout(); const theme = useTheme(); - + const {asset: TeachersUnite} = useMemoizedLazyAsset(() => loadIllustration('TeachersUnite' as IllustrationName)); const menuItems = useMemo(() => { const baseMenuItems = [ { @@ -58,7 +60,7 @@ function SaveTheWorldPage() { shouldShowBackButton={shouldUseNarrowLayout} shouldDisplaySearchRouter onBackButtonPress={Navigation.popToSidebar} - icon={Illustrations.TeachersUnite} + icon={TeachersUnite} shouldUseHeadlineHeader /> diff --git a/src/pages/Travel/ManageTrips.tsx b/src/pages/Travel/ManageTrips.tsx index 8af395178ab5..c22c22a455f0 100644 --- a/src/pages/Travel/ManageTrips.tsx +++ b/src/pages/Travel/ManageTrips.tsx @@ -9,15 +9,18 @@ import FeatureList from '@components/FeatureList'; import * as Illustrations from '@components/Icon/Illustrations'; import LottieAnimations from '@components/LottieAnimations'; import ScrollView from '@components/ScrollView'; +import {useMemoizedLazyIllustrations} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useThemeStyles from '@hooks/useThemeStyles'; import colors from '@styles/theme/colors'; import CONST from '@src/CONST'; +const illustrations = useMemoizedLazyIllustrations(['PiggyBank'] as const); + const tripsFeatures: FeatureListItem[] = [ { - icon: Illustrations.PiggyBank, + icon: illustrations.PiggyBank, translationKey: 'travel.features.saveMoney', }, { diff --git a/src/pages/domain/DomainSamlPage.tsx b/src/pages/domain/DomainSamlPage.tsx index 81d2c3e34f8c..83f6ec594abd 100644 --- a/src/pages/domain/DomainSamlPage.tsx +++ b/src/pages/domain/DomainSamlPage.tsx @@ -5,10 +5,11 @@ import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView import type {FeatureListItem} from '@components/FeatureList'; import FeatureList from '@components/FeatureList'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; -import {LaptopOnDeskWithCoffeeAndKey, LockClosed, OpenSafe, ShieldYellow} from '@components/Icon/Illustrations'; +import {LaptopOnDeskWithCoffeeAndKey, LockClosed, OpenSafe} from '@components/Icon/Illustrations'; import RenderHTML from '@components/RenderHTML'; import ScreenWrapper from '@components/ScreenWrapper'; import ScrollViewWithContext from '@components/ScrollViewWithContext'; +import {useMemoizedLazyIllustrations} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; @@ -24,26 +25,28 @@ import isLoadingOnyxValue from '@src/types/utils/isLoadingOnyxValue'; type DomainSamlPageProps = PlatformStackScreenProps; -const samlFeatures: FeatureListItem[] = [ - { - icon: OpenSafe, - translationKey: 'domain.samlFeatureList.fasterAndEasierLogin', - }, - { - icon: ShieldYellow, - translationKey: 'domain.samlFeatureList.moreSecurityAndControl', - }, - { - icon: LockClosed, - translationKey: 'domain.samlFeatureList.onePasswordForAnything', - }, -]; - function DomainSamlPage({route}: DomainSamlPageProps) { const styles = useThemeStyles(); const {shouldUseNarrowLayout} = useResponsiveLayout(); const {translate} = useLocalize(); + const illustrations = useMemoizedLazyIllustrations(['ShieldYellow'] as const); + + const samlFeatures: FeatureListItem[] = [ + { + icon: OpenSafe, + translationKey: 'domain.samlFeatureList.fasterAndEasierLogin', + }, + { + icon: illustrations.ShieldYellow, + translationKey: 'domain.samlFeatureList.moreSecurityAndControl', + }, + { + icon: LockClosed, + translationKey: 'domain.samlFeatureList.onePasswordForAnything', + }, + ]; + const accountID = route.params.accountID; const [domain, domainResults] = useOnyx(`${ONYXKEYS.COLLECTION.DOMAIN}${accountID}`, {canBeMissing: true}); const [isAdmin, isAdminResults] = useOnyx(`${ONYXKEYS.COLLECTION.SHARED_NVP_PRIVATE_ADMIN_ACCESS}${accountID}`, {canBeMissing: false}); diff --git a/src/pages/settings/AboutPage/AboutPage.tsx b/src/pages/settings/AboutPage/AboutPage.tsx index 04f3962ca761..7385f23fd2ed 100644 --- a/src/pages/settings/AboutPage/AboutPage.tsx +++ b/src/pages/settings/AboutPage/AboutPage.tsx @@ -5,7 +5,6 @@ import type {GestureResponderEvent, StyleProp, ViewStyle} from 'react-native'; import DeviceInfo from 'react-native-device-info'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import * as Expensicons from '@components/Icon/Expensicons'; -import * as Illustrations from '@components/Icon/Illustrations'; import LottieAnimations from '@components/LottieAnimations'; import MenuItemList from '@components/MenuItemList'; import RenderHTML from '@components/RenderHTML'; @@ -13,6 +12,7 @@ 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 useLocalize from '@hooks/useLocalize'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useThemeStyles from '@hooks/useThemeStyles'; @@ -54,6 +54,7 @@ function AboutPage() { const popoverAnchor = useRef(null); const waitForNavigate = useWaitForNavigation(); const {shouldUseNarrowLayout} = useResponsiveLayout(); + const illustrations = useMemoizedLazyIllustrations(['PalmTree'] as const); const menuItems = useMemo(() => { const baseMenuItems: MenuItem[] = [ @@ -143,7 +144,7 @@ function AboutPage() { shouldShowBackButton={shouldUseNarrowLayout} shouldDisplaySearchRouter onBackButtonPress={Navigation.popToSidebar} - icon={Illustrations.PalmTree} + icon={illustrations.PalmTree} shouldUseHeadlineHeader /> diff --git a/src/pages/settings/Profile/ProfilePage.tsx b/src/pages/settings/Profile/ProfilePage.tsx index 7935699eacee..597dc7f34a46 100755 --- a/src/pages/settings/Profile/ProfilePage.tsx +++ b/src/pages/settings/Profile/ProfilePage.tsx @@ -8,13 +8,13 @@ import {DelegateNoAccessContext} from '@components/DelegateNoAccessModalProvider import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import * as Expensicons from '@components/Icon/Expensicons'; -import * as Illustrations from '@components/Icon/Illustrations'; import MenuItemGroup from '@components/MenuItemGroup'; import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription'; import ScreenWrapper from '@components/ScreenWrapper'; import ScrollView from '@components/ScrollView'; import Section from '@components/Section'; import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; +import {useMemoizedLazyIllustrations} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; @@ -56,6 +56,7 @@ function ProfilePage() { const avatarURL = currentUserPersonalDetails?.avatar ?? ''; const accountID = currentUserPersonalDetails?.accountID ?? CONST.DEFAULT_NUMBER_ID; const avatarStyle = [styles.avatarXLarge, styles.alignSelfStart]; + const illustrations = useMemoizedLazyIllustrations(['Profile'] as const); const contactMethodBrickRoadIndicator = getLoginListBrickRoadIndicator(loginList, currentUserPersonalDetails?.email); const emojiCode = currentUserPersonalDetails?.status?.emojiCode ?? ''; @@ -160,7 +161,7 @@ function ProfilePage() { }} shouldShowBackButton={shouldUseNarrowLayout} shouldDisplaySearchRouter - icon={Illustrations.Profile} + icon={illustrations.Profile} shouldUseHeadlineHeader /> loadIllustration('ShieldYellow' as IllustrationName)); useEffect(() => { if (!isUserValidated) { @@ -70,7 +73,7 @@ function CopyCodesPage({route}: TwoFactorAuthPageProps) { {!!isUserValidated && (
diff --git a/src/pages/settings/Security/TwoFactorAuth/EnabledPage.tsx b/src/pages/settings/Security/TwoFactorAuth/EnabledPage.tsx index 83d7e82f5f6f..7f18083cc152 100644 --- a/src/pages/settings/Security/TwoFactorAuth/EnabledPage.tsx +++ b/src/pages/settings/Security/TwoFactorAuth/EnabledPage.tsx @@ -3,11 +3,13 @@ import React, {useCallback, useState} from 'react'; import {View} from 'react-native'; import ConfirmModal from '@components/ConfirmModal'; import * as Expensicons from '@components/Icon/Expensicons'; -import * as Illustrations from '@components/Icon/Illustrations'; +import {loadIllustration} from '@components/Icon/IllustrationLoader'; +import type {IllustrationName} from '@components/Icon/IllustrationLoader'; import MenuItem from '@components/MenuItem'; import ScrollView from '@components/ScrollView'; import Section from '@components/Section'; import Text from '@components/Text'; +import {useMemoizedLazyAsset} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; import useTheme from '@hooks/useTheme'; @@ -25,6 +27,7 @@ function EnabledPage() { const [isVisible, setIsVisible] = useState(false); const [currentUserLogin] = useOnyx(ONYXKEYS.SESSION, {selector: emailSelector, canBeMissing: false}); + const {asset: ShieldYellow} = useMemoizedLazyAsset(() => loadIllustration('ShieldYellow' as IllustrationName)); const {translate} = useLocalize(); const closeModal = useCallback(() => { @@ -40,7 +43,7 @@ function EnabledPage() {
diff --git a/src/pages/settings/Subscription/CardSection/BillingBanner/EarlyDiscountBanner.tsx b/src/pages/settings/Subscription/CardSection/BillingBanner/EarlyDiscountBanner.tsx index 342f28d114c5..b3d2c44f7d40 100644 --- a/src/pages/settings/Subscription/CardSection/BillingBanner/EarlyDiscountBanner.tsx +++ b/src/pages/settings/Subscription/CardSection/BillingBanner/EarlyDiscountBanner.tsx @@ -3,10 +3,12 @@ import {View} from 'react-native'; import Button from '@components/Button'; import Icon from '@components/Icon'; import * as Expensicons from '@components/Icon/Expensicons'; -import * as Illustrations from '@components/Icon/Illustrations'; +import {loadIllustration} from '@components/Icon/IllustrationLoader'; +import type {IllustrationName} from '@components/Icon/IllustrationLoader'; import {PressableWithFeedback} from '@components/Pressable'; import RenderHTML from '@components/RenderHTML'; import Tooltip from '@components/Tooltip'; +import {useMemoizedLazyAsset} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; @@ -47,7 +49,7 @@ function EarlyDiscountBanner({isSubscriptionPage, onboardingHelpDropdownButton, const [discountInfo, setDiscountInfo] = useState(initialDiscountInfo); const [isDismissed, setIsDismissed] = useState(false); const {shouldUseNarrowLayout} = useResponsiveLayout(); - + const {asset: TreasureChest} = useMemoizedLazyAsset(() => loadIllustration('TreasureChest' as IllustrationName)); useEffect(() => { const intervalID = setInterval(() => { setDiscountInfo(getEarlyDiscountInfo(firstDayFreeTrial)); @@ -145,7 +147,7 @@ function EarlyDiscountBanner({isSubscriptionPage, onboardingHelpDropdownButton, seconds: discountInfo?.seconds, })} subtitleStyle={[styles.mt1, styles.mutedNormalTextLabel, isSubscriptionPage && StyleUtils.getTextColorStyle(theme.trialTimer)]} - icon={Illustrations.TreasureChest} + icon={TreasureChest} rightComponent={!isSubscriptionPage && rightComponent} /> ); diff --git a/src/pages/settings/Subscription/CardSection/BillingBanner/PreTrialBillingBanner.tsx b/src/pages/settings/Subscription/CardSection/BillingBanner/PreTrialBillingBanner.tsx index bb3b5bcbdfd6..b2215bf4a40b 100644 --- a/src/pages/settings/Subscription/CardSection/BillingBanner/PreTrialBillingBanner.tsx +++ b/src/pages/settings/Subscription/CardSection/BillingBanner/PreTrialBillingBanner.tsx @@ -1,7 +1,9 @@ import React from 'react'; -import * as Illustrations from '@components/Icon/Illustrations'; +import {loadIllustration} from '@components/Icon/IllustrationLoader'; +import type {IllustrationName} from '@components/Icon/IllustrationLoader'; import Text from '@components/Text'; import TextLink from '@components/TextLink'; +import {useMemoizedLazyAsset} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import * as Report from '@libs/actions/Report'; @@ -13,7 +15,7 @@ import BillingBanner from './BillingBanner'; function PreTrialBillingBanner() { const {translate} = useLocalize(); const styles = useThemeStyles(); - + const {asset: TreasureChest} = useMemoizedLazyAsset(() => loadIllustration('TreasureChest' as IllustrationName)); const navigateToChat = () => { const reportUsedForOnboarding = ReportUtils.getChatUsedForOnboarding(); @@ -40,7 +42,7 @@ function PreTrialBillingBanner() { {translate('subscription.billingBanner.preTrial.subtitleEnd')} } - icon={Illustrations.TreasureChest} + icon={TreasureChest} /> ); } diff --git a/src/pages/settings/Subscription/CardSection/BillingBanner/TrialEndedBillingBanner.tsx b/src/pages/settings/Subscription/CardSection/BillingBanner/TrialEndedBillingBanner.tsx index afaff9739008..4c7ae875aa49 100644 --- a/src/pages/settings/Subscription/CardSection/BillingBanner/TrialEndedBillingBanner.tsx +++ b/src/pages/settings/Subscription/CardSection/BillingBanner/TrialEndedBillingBanner.tsx @@ -1,5 +1,7 @@ import React from 'react'; -import * as Illustrations from '@components/Icon/Illustrations'; +import {loadIllustration} from '@components/Icon/IllustrationLoader'; +import type {IllustrationName} from '@components/Icon/IllustrationLoader'; +import {useMemoizedLazyAsset} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; import {doesUserHavePaymentCardAdded} from '@libs/SubscriptionUtils'; @@ -9,7 +11,7 @@ import BillingBanner from './BillingBanner'; function TrialEndedBillingBanner() { const {translate} = useLocalize(); const [userBillingFundID] = useOnyx(ONYXKEYS.NVP_BILLING_FUND_ID, {canBeMissing: true}); - + const {asset: Tire} = useMemoizedLazyAsset(() => loadIllustration('Tire' as IllustrationName)); if (doesUserHavePaymentCardAdded(userBillingFundID)) { return null; } @@ -18,7 +20,7 @@ function TrialEndedBillingBanner() { ); } diff --git a/src/pages/settings/Subscription/CardSection/BillingBanner/TrialStartedBillingBanner.tsx b/src/pages/settings/Subscription/CardSection/BillingBanner/TrialStartedBillingBanner.tsx index 6de323091743..8446fafdc56b 100644 --- a/src/pages/settings/Subscription/CardSection/BillingBanner/TrialStartedBillingBanner.tsx +++ b/src/pages/settings/Subscription/CardSection/BillingBanner/TrialStartedBillingBanner.tsx @@ -1,5 +1,7 @@ import React from 'react'; -import * as Illustrations from '@components/Icon/Illustrations'; +import {loadIllustration} from '@components/Icon/IllustrationLoader'; +import type {IllustrationName} from '@components/Icon/IllustrationLoader'; +import {useMemoizedLazyAsset} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; import {calculateRemainingFreeTrialDays, doesUserHavePaymentCardAdded} from '@libs/SubscriptionUtils'; @@ -11,12 +13,12 @@ function TrialStartedBillingBanner() { const [userBillingFundID] = useOnyx(ONYXKEYS.NVP_BILLING_FUND_ID, {canBeMissing: true}); const [lastDayFreeTrial] = useOnyx(ONYXKEYS.NVP_LAST_DAY_FREE_TRIAL, {canBeMissing: true}); const subtitle = !doesUserHavePaymentCardAdded(userBillingFundID) ? translate('subscription.billingBanner.trialStarted.subtitle') : ''; - + const {asset: TreasureChest} = useMemoizedLazyAsset(() => loadIllustration('TreasureChest' as IllustrationName)); return ( ); } diff --git a/src/pages/settings/Subscription/PaymentCard/index.tsx b/src/pages/settings/Subscription/PaymentCard/index.tsx index 8746da545cb1..4b87ace9ccc2 100644 --- a/src/pages/settings/Subscription/PaymentCard/index.tsx +++ b/src/pages/settings/Subscription/PaymentCard/index.tsx @@ -5,12 +5,14 @@ import PaymentCardForm from '@components/AddPaymentCard/PaymentCardForm'; import DelegateNoAccessWrapper from '@components/DelegateNoAccessWrapper'; import type {FormOnyxValues} from '@components/Form/types'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; -import * as Illustrations from '@components/Icon/Illustrations'; +import {loadIllustration} from '@components/Icon/IllustrationLoader'; +import type {IllustrationName} from '@components/Icon/IllustrationLoader'; import ScreenWrapper from '@components/ScreenWrapper'; import Section, {CARD_LAYOUT} from '@components/Section'; import Text from '@components/Text'; import TextLink from '@components/TextLink'; import useHasTeam2025Pricing from '@hooks/useHasTeam2025Pricing'; +import {useMemoizedLazyAsset} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; import usePreferredCurrency from '@hooks/usePreferredCurrency'; @@ -41,7 +43,7 @@ function AddPaymentCard() { const isCollect = subscriptionPlan === CONST.POLICY.TYPE.TEAM; const isAnnual = privateSubscription?.type === CONST.SUBSCRIPTION.TYPE.ANNUAL; - + const {asset: ShieldYellow} = useMemoizedLazyAsset(() => loadIllustration('ShieldYellow' as IllustrationName)); const subscriptionPricingInfo = hasTeam2025Pricing && isCollect ? translate('subscription.yourPlan.pricePerMemberPerMonth', {price: convertToShortDisplayString(subscriptionPrice, preferredCurrency)}) @@ -101,7 +103,7 @@ function AddPaymentCard() { footerContent={ <>
@@ -100,14 +101,14 @@ function SubscriptionSettings() { {privateSubscription?.type === CONST.SUBSCRIPTION.TYPE.PAY_PER_USE ? ( ) : ( diff --git a/src/pages/settings/Subscription/SubscriptionSettings/index.tsx b/src/pages/settings/Subscription/SubscriptionSettings/index.tsx index d0be665d971b..9b8e9714861c 100644 --- a/src/pages/settings/Subscription/SubscriptionSettings/index.tsx +++ b/src/pages/settings/Subscription/SubscriptionSettings/index.tsx @@ -5,7 +5,6 @@ import {DelegateNoAccessContext} from '@components/DelegateNoAccessModalProvider import HeaderWithBackButton from '@components/HeaderWithBackButton'; import Icon from '@components/Icon'; import * as Expensicons from '@components/Icon/Expensicons'; -import * as Illustrations from '@components/Icon/Illustrations'; import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription'; import OfflineWithFeedback from '@components/OfflineWithFeedback'; import OptionsPicker from '@components/OptionsPicker'; @@ -15,6 +14,7 @@ import ScrollView from '@components/ScrollView'; import Text from '@components/Text'; import TextLink from '@components/TextLink'; import useHasTeam2025Pricing from '@hooks/useHasTeam2025Pricing'; +import {useMemoizedLazyIllustrations} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; import usePolicy from '@hooks/usePolicy'; @@ -40,19 +40,6 @@ import type {SubscriptionType} from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; -const options: Array> = [ - { - key: CONST.SUBSCRIPTION.TYPE.ANNUAL, - title: 'subscription.details.annual', - icon: Illustrations.SubscriptionAnnual, - }, - { - key: CONST.SUBSCRIPTION.TYPE.PAY_PER_USE, - title: 'subscription.details.payPerUse', - icon: Illustrations.SubscriptionPPU, - }, -]; - function SubscriptionSettings() { const {translate} = useLocalize(); const styles = useThemeStyles(); @@ -65,7 +52,7 @@ function SubscriptionSettings() { const subscriptionPlan = useSubscriptionPlan(); const hasTeam2025Pricing = useHasTeam2025Pricing(); const preferredCurrency = usePreferredCurrency(); - const illustrations = useThemeIllustrations(); + const themeIllustrations = useThemeIllustrations(); const possibleCostSavings = useSubscriptionPossibleCostSavings(); const {isActingAsDelegate, showDelegateNoAccessModal} = useContext(DelegateNoAccessContext); const isAnnual = privateSubscription?.type === CONST.SUBSCRIPTION.TYPE.ANNUAL; @@ -97,6 +84,20 @@ function SubscriptionSettings() { } Navigation.navigate(ROUTES.SETTINGS_SUBSCRIPTION_SIZE.getRoute(1)); }; + const illustrations = useMemoizedLazyIllustrations(['SubscriptionAnnual', 'SubscriptionPPU'] as const); + + const options: Array> = [ + { + key: CONST.SUBSCRIPTION.TYPE.ANNUAL, + title: 'subscription.details.annual', + icon: illustrations.SubscriptionAnnual, + }, + { + key: CONST.SUBSCRIPTION.TYPE.PAY_PER_USE, + title: 'subscription.details.payPerUse', + icon: illustrations.SubscriptionPPU, + }, + ]; // This section is only shown when the subscription is annual const subscriptionSizeSection: React.JSX.Element | null = @@ -195,7 +196,7 @@ function SubscriptionSettings() { {!!account?.isApprovedAccountant || !!account?.isApprovedAccountantClient ? ( diff --git a/src/pages/settings/Wallet/WalletPage/WalletPage.tsx b/src/pages/settings/Wallet/WalletPage/WalletPage.tsx index 195d67713156..80f45e003553 100644 --- a/src/pages/settings/Wallet/WalletPage/WalletPage.tsx +++ b/src/pages/settings/Wallet/WalletPage/WalletPage.tsx @@ -10,7 +10,8 @@ import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import Icon from '@components/Icon'; import * as Expensicons from '@components/Icon/Expensicons'; -import * as Illustrations from '@components/Icon/Illustrations'; +import {loadIllustration} from '@components/Icon/IllustrationLoader'; +import type {IllustrationName} from '@components/Icon/IllustrationLoader'; import KYCWall from '@components/KYCWall'; import {KYCWallContext} from '@components/KYCWall/KYCWallContext'; import type {PaymentMethodType, Source} from '@components/KYCWall/types'; @@ -25,6 +26,7 @@ import ScrollView from '@components/ScrollView'; import Section from '@components/Section'; import Text from '@components/Text'; import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; +import {useMemoizedLazyAsset} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; import useOnyx from '@hooks/useOnyx'; @@ -80,7 +82,7 @@ function WalletPage({shouldListenForResize = false}: WalletPageProps) { const kycWallRef = useContext(KYCWallContext); const {isBetaEnabled} = usePermissions(); const expensifyIcons = useMemoizedLazyExpensifyIcons(['MoneySearch'] as const); - + const {asset: MoneyIntoWallet} = useMemoizedLazyAsset(() => loadIllustration('MoneyIntoWallet' as IllustrationName)); const theme = useTheme(); const styles = useThemeStyles(); const {translate} = useLocalize(); @@ -363,7 +365,7 @@ function WalletPage({shouldListenForResize = false}: WalletPageProps) { const headerWithBackButton = ( { if (!hasAccountingConnection) { @@ -398,7 +410,7 @@ function WorkspaceMoreFeaturesPage({policy, route}: WorkspaceMoreFeaturesPagePro if (isBetaEnabled(CONST.BETAS.UBER_FOR_BUSINESS)) { integrateItems.push({ - icon: Illustrations.ReceiptPartners, + icon: illustrations.ReceiptPartners, titleTranslationKey: 'workspace.moreFeatures.receiptPartners.title', subtitleTranslationKey: 'workspace.moreFeatures.receiptPartners.subtitle', isActive: policy?.receiptPartners?.enabled ?? false, diff --git a/src/pages/workspace/WorkspacesListRow.tsx b/src/pages/workspace/WorkspacesListRow.tsx index 3b1d8a792f09..7e794ec19fa7 100644 --- a/src/pages/workspace/WorkspacesListRow.tsx +++ b/src/pages/workspace/WorkspacesListRow.tsx @@ -18,6 +18,7 @@ import type {WithCurrentUserPersonalDetailsProps} from '@components/withCurrentU import withCurrentUserPersonalDetails from '@components/withCurrentUserPersonalDetails'; import WorkspacesListRowDisplayName from '@components/WorkspacesListRowDisplayName'; import useAnimatedHighlightStyle from '@hooks/useAnimatedHighlightStyle'; +import {useMemoizedLazyIllustrations} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useTheme from '@hooks/useTheme'; @@ -90,17 +91,6 @@ type BrickRoadIndicatorIconProps = { brickRoadIndicator?: ValueOf; }; -const workspaceTypeIcon = (workspaceType: WorkspacesListRowProps['workspaceType']): IconAsset => { - switch (workspaceType) { - case CONST.POLICY.TYPE.CORPORATE: - return Illustrations.ShieldYellow; - case CONST.POLICY.TYPE.TEAM: - return Illustrations.Mailbox; - default: - return Illustrations.Mailbox; - } -}; - function BrickRoadIndicatorIcon({brickRoadIndicator}: BrickRoadIndicatorIconProps) { const theme = useTheme(); @@ -138,7 +128,18 @@ function WorkspacesListRow({ const {shouldUseNarrowLayout} = useResponsiveLayout(); const theme = useTheme(); const isNarrow = layoutWidth === CONST.LAYOUT_WIDTH.NARROW; - + const illustrations = useMemoizedLazyIllustrations(['ShieldYellow'] as const); + + const workspaceTypeIcon = (workspaceType: WorkspacesListRowProps['workspaceType']): IconAsset => { + switch (workspaceType) { + case CONST.POLICY.TYPE.CORPORATE: + return illustrations.ShieldYellow; + case CONST.POLICY.TYPE.TEAM: + return Illustrations.Mailbox; + default: + return Illustrations.Mailbox; + } + }; const ownerDetails = ownerAccountID && getPersonalDetailsByIDs({accountIDs: [ownerAccountID], currentUserAccountID: currentUserPersonalDetails.accountID}).at(0); const threeDotsMenuRef = useRef<{hidePopoverMenu: () => void; isPopupMenuVisible: boolean}>(null); const animatedHighlightStyle = useAnimatedHighlightStyle({ diff --git a/src/pages/workspace/distanceRates/PolicyDistanceRatesPage.tsx b/src/pages/workspace/distanceRates/PolicyDistanceRatesPage.tsx index 609e80593ff7..42df20fa6499 100644 --- a/src/pages/workspace/distanceRates/PolicyDistanceRatesPage.tsx +++ b/src/pages/workspace/distanceRates/PolicyDistanceRatesPage.tsx @@ -7,7 +7,8 @@ import type {DropdownOption, WorkspaceDistanceRatesBulkActionType} from '@compon import ConfirmModal from '@components/ConfirmModal'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import * as Expensicons from '@components/Icon/Expensicons'; -import * as Illustrations from '@components/Icon/Illustrations'; +import {loadIllustration} from '@components/Icon/IllustrationLoader'; +import type {IllustrationName} from '@components/Icon/IllustrationLoader'; import ScreenWrapper from '@components/ScreenWrapper'; import SearchBar from '@components/SearchBar'; import SelectionListWithModal from '@components/SelectionListWithModal'; @@ -17,6 +18,7 @@ import type {ListItem} from '@components/SelectionListWithSections/types'; import Switch from '@components/Switch'; import Text from '@components/Text'; import useFilteredSelection from '@hooks/useFilteredSelection'; +import {useMemoizedLazyAsset} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useMobileSelectionMode from '@hooks/useMobileSelectionMode'; import useNetwork from '@hooks/useNetwork'; @@ -69,7 +71,7 @@ function PolicyDistanceRatesPage({ const isMobileSelectionModeEnabled = useMobileSelectionMode(); const canSelectMultiple = shouldUseNarrowLayout ? isMobileSelectionModeEnabled : true; - + const {asset: CarIce} = useMemoizedLazyAsset(() => loadIllustration('CarIce' as IllustrationName)); const customUnit = useMemo(() => getDistanceRateCustomUnit(policy), [policy]); const customUnitRates: Record = useMemo(() => customUnit?.rates ?? {}, [customUnit]); @@ -469,7 +471,7 @@ function PolicyDistanceRatesPage({ shouldShowOfflineIndicatorInWideScreen > loadIllustration('ShieldYellow' as IllustrationName)); const policyID = policy?.id; const checkIfCanBeRendered = useCallback(() => { @@ -87,7 +89,7 @@ function WorkspaceOwnerPaymentCardForm({policy}: WorkspaceOwnerPaymentCardFormPr
loadIllustration('ReceiptPartners' as IllustrationName)); // Track focus and connection change to route to the invite flow once after successful connection const prevIsUberConnected = usePrevious(isUberConnected); @@ -253,7 +255,7 @@ function WorkspaceReceiptPartnersPage({route}: WorkspaceReceiptPartnersPageProps diff --git a/src/pages/workspace/upgrade/GenericFeaturesView.tsx b/src/pages/workspace/upgrade/GenericFeaturesView.tsx index 6d05e4644f15..3241facc1678 100644 --- a/src/pages/workspace/upgrade/GenericFeaturesView.tsx +++ b/src/pages/workspace/upgrade/GenericFeaturesView.tsx @@ -2,11 +2,13 @@ import React from 'react'; import {View} from 'react-native'; import Button from '@components/Button'; import Icon from '@components/Icon'; -import * as Illustrations from '@components/Icon/Illustrations'; +import {loadIllustration} from '@components/Icon/IllustrationLoader'; +import type {IllustrationName} from '@components/Icon/IllustrationLoader'; import RenderHTML from '@components/RenderHTML'; import Text from '@components/Text'; import useEnvironment from '@hooks/useEnvironment'; import useHasTeam2025Pricing from '@hooks/useHasTeam2025Pricing'; +import {useMemoizedLazyAsset} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useThemeStyles from '@hooks/useThemeStyles'; @@ -28,7 +30,7 @@ function GenericFeaturesView({onUpgrade, buttonDisabled, loading, formattedPrice const {translate} = useLocalize(); const {environmentURL} = useEnvironment(); const learnMoreMethodsRoute = `${environmentURL}/${ROUTES.SETTINGS_SUBSCRIPTION.getRoute(Navigation.getActiveRoute())}`; - + const {asset: ShieldYellow} = useMemoizedLazyAsset(() => loadIllustration('ShieldYellow' as IllustrationName)); const {isExtraSmallScreenWidth} = useResponsiveLayout(); const hasTeam2025Pricing = useHasTeam2025Pricing(); @@ -43,7 +45,7 @@ function GenericFeaturesView({onUpgrade, buttonDisabled, loading, formattedPrice From 32ad34bde1a100547d9dfa66bf3f61acf3ae8209 Mon Sep 17 00:00:00 2001 From: Samran Ahmed Date: Tue, 18 Nov 2025 17:44:11 +0500 Subject: [PATCH 2/8] fix failing checks --- src/libs/SubscriptionUtils.ts | 2 +- src/pages/Travel/ManageTrips.tsx | 25 +++++++++---------- .../BillingBanner/PreTrialBillingBanner.tsx | 8 +++--- .../SubscriptionPlan/SubscriptionPlanCard.tsx | 1 - .../settings/Wallet/WalletPage/WalletPage.tsx | 3 +-- src/pages/workspace/WorkspacesListRow.tsx | 4 +-- .../expensifyCard/issueNew/CardTypeStep.tsx | 1 - 7 files changed, 20 insertions(+), 24 deletions(-) diff --git a/src/libs/SubscriptionUtils.ts b/src/libs/SubscriptionUtils.ts index 345624161f19..03f4a6c0ba2d 100644 --- a/src/libs/SubscriptionUtils.ts +++ b/src/libs/SubscriptionUtils.ts @@ -14,7 +14,7 @@ import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type {BillingGraceEndPeriod, BillingStatus, Fund, FundList, IntroSelected, Policy, StripeCustomerID} from '@src/types/onyx'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; -import IconAsset from '@src/types/utils/IconAsset'; +import type IconAsset from '@src/types/utils/IconAsset'; import {convertToShortDisplayString} from './CurrencyUtils'; import {getOwnedPaidPolicies, isPolicyOwner} from './PolicyUtils'; diff --git a/src/pages/Travel/ManageTrips.tsx b/src/pages/Travel/ManageTrips.tsx index c22c22a455f0..02d9046fda20 100644 --- a/src/pages/Travel/ManageTrips.tsx +++ b/src/pages/Travel/ManageTrips.tsx @@ -16,25 +16,24 @@ import useThemeStyles from '@hooks/useThemeStyles'; import colors from '@styles/theme/colors'; import CONST from '@src/CONST'; -const illustrations = useMemoizedLazyIllustrations(['PiggyBank'] as const); - -const tripsFeatures: FeatureListItem[] = [ - { - icon: illustrations.PiggyBank, - translationKey: 'travel.features.saveMoney', - }, - { - icon: Illustrations.Alert, - translationKey: 'travel.features.alerts', - }, -]; - function ManageTrips() { const styles = useThemeStyles(); const {shouldUseNarrowLayout} = useResponsiveLayout(); const {translate} = useLocalize(); const [shouldScrollToBottom, setShouldScrollToBottom] = useState(false); + const illustrations = useMemoizedLazyIllustrations(['PiggyBank'] as const); + const tripsFeatures: FeatureListItem[] = [ + { + icon: illustrations.PiggyBank, + translationKey: 'travel.features.saveMoney', + }, + { + icon: Illustrations.Alert, + translationKey: 'travel.features.alerts', + }, + ]; + const navigateToBookTravelDemo = () => { Linking.openURL(CONST.BOOK_TRAVEL_DEMO_URL); }; diff --git a/src/pages/settings/Subscription/CardSection/BillingBanner/PreTrialBillingBanner.tsx b/src/pages/settings/Subscription/CardSection/BillingBanner/PreTrialBillingBanner.tsx index b2215bf4a40b..06ec7738d70f 100644 --- a/src/pages/settings/Subscription/CardSection/BillingBanner/PreTrialBillingBanner.tsx +++ b/src/pages/settings/Subscription/CardSection/BillingBanner/PreTrialBillingBanner.tsx @@ -6,9 +6,9 @@ import TextLink from '@components/TextLink'; import {useMemoizedLazyAsset} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; -import * as Report from '@libs/actions/Report'; +import {navigateToConciergeChat} from '@libs/actions/Report'; import Navigation from '@libs/Navigation/Navigation'; -import * as ReportUtils from '@libs/ReportUtils'; +import {getChatUsedForOnboarding} from '@libs/ReportUtils'; import ROUTES from '@src/ROUTES'; import BillingBanner from './BillingBanner'; @@ -17,10 +17,10 @@ function PreTrialBillingBanner() { const styles = useThemeStyles(); const {asset: TreasureChest} = useMemoizedLazyAsset(() => loadIllustration('TreasureChest' as IllustrationName)); const navigateToChat = () => { - const reportUsedForOnboarding = ReportUtils.getChatUsedForOnboarding(); + const reportUsedForOnboarding = getChatUsedForOnboarding(); if (!reportUsedForOnboarding) { - Report.navigateToConciergeChat(); + navigateToConciergeChat(); return; } diff --git a/src/pages/settings/Subscription/SubscriptionPlan/SubscriptionPlanCard.tsx b/src/pages/settings/Subscription/SubscriptionPlan/SubscriptionPlanCard.tsx index b2d31abbf69a..e4452323e0b8 100644 --- a/src/pages/settings/Subscription/SubscriptionPlan/SubscriptionPlanCard.tsx +++ b/src/pages/settings/Subscription/SubscriptionPlan/SubscriptionPlanCard.tsx @@ -41,7 +41,6 @@ function SubscriptionPlanCard({subscriptionPlan, isFromComparisonModal = false, const privateSubscription = usePrivateSubscription(); const preferredCurrency = usePreferredCurrency(); const hasTeam2025Pricing = useHasTeam2025Pricing(); - console.log('SubscriptionPlanCard'); const illustrations = useMemoizedLazyIllustrations(['ShieldYellow'] as const); const {title, src, description, benefits, note, subtitle} = getSubscriptionPlanInfo( diff --git a/src/pages/settings/Wallet/WalletPage/WalletPage.tsx b/src/pages/settings/Wallet/WalletPage/WalletPage.tsx index 80f45e003553..5127cf35bcf2 100644 --- a/src/pages/settings/Wallet/WalletPage/WalletPage.tsx +++ b/src/pages/settings/Wallet/WalletPage/WalletPage.tsx @@ -25,8 +25,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 {useMemoizedLazyAsset} from '@hooks/useLazyAsset'; +import {useMemoizedLazyAsset, useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; import useOnyx from '@hooks/useOnyx'; diff --git a/src/pages/workspace/WorkspacesListRow.tsx b/src/pages/workspace/WorkspacesListRow.tsx index 7e794ec19fa7..d05cda772d10 100644 --- a/src/pages/workspace/WorkspacesListRow.tsx +++ b/src/pages/workspace/WorkspacesListRow.tsx @@ -130,8 +130,8 @@ function WorkspacesListRow({ const isNarrow = layoutWidth === CONST.LAYOUT_WIDTH.NARROW; const illustrations = useMemoizedLazyIllustrations(['ShieldYellow'] as const); - const workspaceTypeIcon = (workspaceType: WorkspacesListRowProps['workspaceType']): IconAsset => { - switch (workspaceType) { + const workspaceTypeIcon = (type: WorkspacesListRowProps['workspaceType']): IconAsset => { + switch (type) { case CONST.POLICY.TYPE.CORPORATE: return illustrations.ShieldYellow; case CONST.POLICY.TYPE.TEAM: diff --git a/src/pages/workspace/expensifyCard/issueNew/CardTypeStep.tsx b/src/pages/workspace/expensifyCard/issueNew/CardTypeStep.tsx index e0c937b5b358..92ed42964575 100644 --- a/src/pages/workspace/expensifyCard/issueNew/CardTypeStep.tsx +++ b/src/pages/workspace/expensifyCard/issueNew/CardTypeStep.tsx @@ -1,7 +1,6 @@ import React from 'react'; import {View} from 'react-native'; import type {ValueOf} from 'type-fest'; -import * as Illustrations from '@components/Icon/Illustrations'; import InteractiveStepWrapper from '@components/InteractiveStepWrapper'; import MenuItem from '@components/MenuItem'; import Text from '@components/Text'; From 1a9ace0c19b970fcb089a3ed816531e5c2970f2a Mon Sep 17 00:00:00 2001 From: Samran Ahmed Date: Wed, 19 Nov 2025 22:28:55 +0500 Subject: [PATCH 3/8] lint --- src/components/MigratedUserWelcomeModal.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/components/MigratedUserWelcomeModal.tsx b/src/components/MigratedUserWelcomeModal.tsx index 65ac4112657a..a5deed023c6b 100644 --- a/src/components/MigratedUserWelcomeModal.tsx +++ b/src/components/MigratedUserWelcomeModal.tsx @@ -2,7 +2,6 @@ import {useRoute} from '@react-navigation/native'; import {tryNewDotOnyxSelector} from '@selectors/Onboarding'; import React, {lazy, Suspense, useEffect, useState} from 'react'; import {View} from 'react-native'; -import {useMemoizedLazyIllustrations} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; @@ -49,6 +48,10 @@ const ExpensifyFeatures: FeatureListItem[] = [ }, ]; +function MigratedUserWelcomeModal() { + const {translate} = useLocalize(); + const styles = useThemeStyles(); + const StyleUtils = useStyleUtils(); const {shouldUseNarrowLayout} = useResponsiveLayout(); const {typeMenuSections} = useSearchTypeMenuSections(); const [isModalDisabled, setIsModalDisabled] = useState(true); From 41bd3fea731c568c23ceaa2714a43b1ca612ee5f Mon Sep 17 00:00:00 2001 From: Samran Ahmed Date: Thu, 20 Nov 2025 11:28:05 +0500 Subject: [PATCH 4/8] lint --- .../BaseOnboardingPurpose.tsx | 18 ++++-------------- .../NonUSD/Finish/index.tsx | 4 +--- src/pages/Travel/ManageTrips.tsx | 17 ++--------------- .../workspace/WorkspaceMoreFeaturesPage.tsx | 1 - src/pages/workspace/WorkspacesListRow.tsx | 1 - 5 files changed, 7 insertions(+), 34 deletions(-) diff --git a/src/pages/OnboardingPurpose/BaseOnboardingPurpose.tsx b/src/pages/OnboardingPurpose/BaseOnboardingPurpose.tsx index 949ef4a4606f..38be097bdf9f 100644 --- a/src/pages/OnboardingPurpose/BaseOnboardingPurpose.tsx +++ b/src/pages/OnboardingPurpose/BaseOnboardingPurpose.tsx @@ -4,7 +4,6 @@ import {InteractionManager, View} from 'react-native'; import {ScrollView} from 'react-native-gesture-handler'; import FormHelpMessage from '@components/FormHelpMessage'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; -import * as Illustrations from '@components/Icon/Illustrations'; import type {MenuItemProps} from '@components/MenuItem'; import MenuItemList from '@components/MenuItemList'; import ScreenWrapper from '@components/ScreenWrapper'; @@ -43,14 +42,14 @@ function getOnboardingChoices(customChoices: OnboardingPurpose[]) { function BaseOnboardingPurpose({shouldUseNativeStyles, shouldEnableMaxHeight, route}: BaseOnboardingPurposeProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); - const illustrations = useMemoizedLazyIllustrations(['Abacus', 'Binoculars'] as const); + const illustrations = useMemoizedLazyIllustrations(['Abacus', 'Binoculars', 'ReceiptUpload', 'PiggyBank', 'SplitBill'] as const); const menuIcons = useMemo( () => ({ - [CONST.ONBOARDING_CHOICES.EMPLOYER]: Illustrations.ReceiptUpload, + [CONST.ONBOARDING_CHOICES.EMPLOYER]: illustrations.ReceiptUpload, [CONST.ONBOARDING_CHOICES.MANAGE_TEAM]: illustrations.Abacus, - [CONST.ONBOARDING_CHOICES.PERSONAL_SPEND]: Illustrations.PiggyBank, - [CONST.ONBOARDING_CHOICES.CHAT_SPLIT]: Illustrations.SplitBill, + [CONST.ONBOARDING_CHOICES.PERSONAL_SPEND]: illustrations.PiggyBank, + [CONST.ONBOARDING_CHOICES.CHAT_SPLIT]: illustrations.SplitBill, [CONST.ONBOARDING_CHOICES.LOOKING_AROUND]: illustrations.Binoculars, }), [illustrations.Abacus, illustrations.Binoculars], @@ -72,15 +71,6 @@ function BaseOnboardingPurpose({shouldUseNativeStyles, shouldEnableMaxHeight, ro const [customChoices = getEmptyArray()] = useOnyx(ONYXKEYS.ONBOARDING_CUSTOM_CHOICES, {canBeMissing: true}); const onboardingChoices = getOnboardingChoices(customChoices); - const illustrations = useMemoizedLazyIllustrations(['PiggyBank', 'ReceiptUpload', 'SplitBill'] as const); - - const menuIcons = { - [CONST.ONBOARDING_CHOICES.EMPLOYER]: illustrations.ReceiptUpload, - [CONST.ONBOARDING_CHOICES.MANAGE_TEAM]: Illustrations.Abacus, - [CONST.ONBOARDING_CHOICES.PERSONAL_SPEND]: illustrations.PiggyBank, - [CONST.ONBOARDING_CHOICES.CHAT_SPLIT]: illustrations.SplitBill, - [CONST.ONBOARDING_CHOICES.LOOKING_AROUND]: Illustrations.Binoculars, - }; const menuItems: MenuItemProps[] = onboardingChoices.map((choice) => { const translationKey = `onboarding.purpose.${choice}` as const; diff --git a/src/pages/ReimbursementAccount/NonUSD/Finish/index.tsx b/src/pages/ReimbursementAccount/NonUSD/Finish/index.tsx index 1b10bb34b299..1b1ef4208d98 100644 --- a/src/pages/ReimbursementAccount/NonUSD/Finish/index.tsx +++ b/src/pages/ReimbursementAccount/NonUSD/Finish/index.tsx @@ -3,7 +3,6 @@ import {View} from 'react-native'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import * as Expensicons from '@components/Icon/Expensicons'; import {ChatBubble} from '@components/Icon/Expensicons'; -import * as Illustrations from '@components/Icon/Illustrations'; import MenuItem from '@components/MenuItem'; import ScreenWrapper from '@components/ScreenWrapper'; import ScrollView from '@components/ScrollView'; @@ -23,7 +22,7 @@ function Finish() { const styles = useThemeStyles(); const {translate} = useLocalize(); const {shouldUseNarrowLayout} = useResponsiveLayout(); - const illustrations = useMemoizedLazyIllustrations(['ConciergeBubble'] as const); + const illustrations = useMemoizedLazyIllustrations(['ConciergeBubble', 'ShieldYellow'] as const); const [reimbursementAccount] = useOnyx(ONYXKEYS.REIMBURSEMENT_ACCOUNT, {canBeMissing: true}); const policyID = reimbursementAccount?.achData?.policyID; @@ -32,7 +31,6 @@ function Finish() { Navigation.goBack(); }; const handleNavigateToConciergeChat = () => navigateToConciergeChat(true); - const illustrations = useMemoizedLazyIllustrations(['ShieldYellow'] as const); return ( [ { - icon: Illustrations.PiggyBank, + icon: illustrations.PiggyBank, translationKey: 'travel.features.saveMoney', }, { @@ -37,18 +36,6 @@ function ManageTrips() { [illustrations.Alert], ); - const illustrations = useMemoizedLazyIllustrations(['PiggyBank'] as const); - const tripsFeatures: FeatureListItem[] = [ - { - icon: illustrations.PiggyBank, - translationKey: 'travel.features.saveMoney', - }, - { - icon: Illustrations.Alert, - translationKey: 'travel.features.alerts', - }, - ]; - const navigateToBookTravelDemo = () => { Linking.openURL(CONST.BOOK_TRAVEL_DEMO_URL); }; diff --git a/src/pages/workspace/WorkspaceMoreFeaturesPage.tsx b/src/pages/workspace/WorkspaceMoreFeaturesPage.tsx index 870608f5a9b7..d2cfdacbcecf 100644 --- a/src/pages/workspace/WorkspaceMoreFeaturesPage.tsx +++ b/src/pages/workspace/WorkspaceMoreFeaturesPage.tsx @@ -3,7 +3,6 @@ import {View} from 'react-native'; import ConfirmModal from '@components/ConfirmModal'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import Hoverable from '@components/Hoverable'; -import * as Illustrations from '@components/Icon/Illustrations'; import ScreenWrapper from '@components/ScreenWrapper'; import ScrollView from '@components/ScrollView'; import Section from '@components/Section'; diff --git a/src/pages/workspace/WorkspacesListRow.tsx b/src/pages/workspace/WorkspacesListRow.tsx index 48ee5a8f7bca..880e5d054d6d 100644 --- a/src/pages/workspace/WorkspacesListRow.tsx +++ b/src/pages/workspace/WorkspacesListRow.tsx @@ -8,7 +8,6 @@ import Avatar from '@components/Avatar'; import Badge from '@components/Badge'; import Icon from '@components/Icon'; import * as Expensicons from '@components/Icon/Expensicons'; -import * as Illustrations from '@components/Icon/Illustrations'; import type {PopoverMenuItem} from '@components/PopoverMenu'; import Text from '@components/Text'; import TextWithTooltip from '@components/TextWithTooltip'; From 3c97e2d06f7c3f63f1971219518f6a5d644e4717 Mon Sep 17 00:00:00 2001 From: Samran Ahmed Date: Thu, 20 Nov 2025 15:11:09 +0500 Subject: [PATCH 5/8] add missing deps --- src/pages/OnboardingPurpose/BaseOnboardingPurpose.tsx | 2 +- src/pages/Search/EmptySearchView.tsx | 2 +- src/pages/Travel/ManageTrips.tsx | 2 +- src/pages/domain/DomainSamlPage.tsx | 2 +- .../Subscription/CardSection/BillingBanner/BillingBanner.tsx | 2 +- src/pages/workspace/WorkspacesListRow.tsx | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/pages/OnboardingPurpose/BaseOnboardingPurpose.tsx b/src/pages/OnboardingPurpose/BaseOnboardingPurpose.tsx index 38be097bdf9f..3e223002926e 100644 --- a/src/pages/OnboardingPurpose/BaseOnboardingPurpose.tsx +++ b/src/pages/OnboardingPurpose/BaseOnboardingPurpose.tsx @@ -52,7 +52,7 @@ function BaseOnboardingPurpose({shouldUseNativeStyles, shouldEnableMaxHeight, ro [CONST.ONBOARDING_CHOICES.CHAT_SPLIT]: illustrations.SplitBill, [CONST.ONBOARDING_CHOICES.LOOKING_AROUND]: illustrations.Binoculars, }), - [illustrations.Abacus, illustrations.Binoculars], + [illustrations.Abacus, illustrations.Binoculars, illustrations.ReceiptUpload, illustrations.PiggyBank, illustrations.SplitBill], ); const {onboardingIsMediumOrLargerScreenWidth} = useResponsiveLayout(); const [account] = useOnyx(ONYXKEYS.ACCOUNT, {canBeMissing: true}); diff --git a/src/pages/Search/EmptySearchView.tsx b/src/pages/Search/EmptySearchView.tsx index 32a3f1910f8a..a608e1c80c30 100644 --- a/src/pages/Search/EmptySearchView.tsx +++ b/src/pages/Search/EmptySearchView.tsx @@ -291,7 +291,7 @@ function EmptySearchViewContent({ ); - }, [contextMenuAnchor, handleContextMenuAnchorRef, styles, translate]); + }, [contextMenuAnchor, handleContextMenuAnchorRef, styles, translate, tripsFeatures]); // Default 'Folder' lottie animation, along with its background styles const defaultViewItemHeader = useMemo( diff --git a/src/pages/Travel/ManageTrips.tsx b/src/pages/Travel/ManageTrips.tsx index cc2986601482..f5b8d9408a5c 100644 --- a/src/pages/Travel/ManageTrips.tsx +++ b/src/pages/Travel/ManageTrips.tsx @@ -33,7 +33,7 @@ function ManageTrips() { translationKey: 'travel.features.alerts', }, ], - [illustrations.Alert], + [illustrations.Alert, illustrations.PiggyBank], ); const navigateToBookTravelDemo = () => { diff --git a/src/pages/domain/DomainSamlPage.tsx b/src/pages/domain/DomainSamlPage.tsx index ad88ae3a2f42..b2c35efe7586 100644 --- a/src/pages/domain/DomainSamlPage.tsx +++ b/src/pages/domain/DomainSamlPage.tsx @@ -46,7 +46,7 @@ function DomainSamlPage({route}: DomainSamlPageProps) { translationKey: 'domain.samlFeatureList.onePasswordForAnything', }, ], - [illustrations.LockClosed], + [illustrations.LockClosed, illustrations.ShieldYellow], ); const accountID = route.params.accountID; diff --git a/src/pages/settings/Subscription/CardSection/BillingBanner/BillingBanner.tsx b/src/pages/settings/Subscription/CardSection/BillingBanner/BillingBanner.tsx index 46ff788693c1..59946119cd6e 100644 --- a/src/pages/settings/Subscription/CardSection/BillingBanner/BillingBanner.tsx +++ b/src/pages/settings/Subscription/CardSection/BillingBanner/BillingBanner.tsx @@ -96,7 +96,7 @@ function BillingBanner({ /> ) ); - }, [brickRoadIndicator, onRightIconPress, rightIcon, rightIconAccessibilityLabel, styles.touchableButtonImage, theme.danger, theme.icon, theme.success]); + }, [brickRoadIndicator, onRightIconPress, rightIcon, rightIconAccessibilityLabel, styles.touchableButtonImage, theme.danger, theme.icon, theme.success, expensifyIcons.DotIndicator]); return ( diff --git a/src/pages/workspace/WorkspacesListRow.tsx b/src/pages/workspace/WorkspacesListRow.tsx index 880e5d054d6d..8102e23fdc95 100644 --- a/src/pages/workspace/WorkspacesListRow.tsx +++ b/src/pages/workspace/WorkspacesListRow.tsx @@ -140,7 +140,7 @@ function WorkspacesListRow({ return illustrations.Mailbox; } }, - [illustrations.Mailbox], + [illustrations.Mailbox, illustrations.ShieldYellow], ); const ownerDetails = ownerAccountID && getPersonalDetailsByIDs({accountIDs: [ownerAccountID], currentUserAccountID: currentUserPersonalDetails.accountID}).at(0); From 94a0e91ebf03871e0d711ac331123d6179442790 Mon Sep 17 00:00:00 2001 From: Samran Ahmed Date: Fri, 21 Nov 2025 18:55:44 +0500 Subject: [PATCH 6/8] fix lint --- src/components/MigratedUserWelcomeModal.tsx | 37 ++++++++++++--------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/src/components/MigratedUserWelcomeModal.tsx b/src/components/MigratedUserWelcomeModal.tsx index 5943df77e296..ae1d80ad5669 100644 --- a/src/components/MigratedUserWelcomeModal.tsx +++ b/src/components/MigratedUserWelcomeModal.tsx @@ -1,7 +1,8 @@ import {useRoute} from '@react-navigation/native'; import {tryNewDotOnyxSelector} from '@selectors/Onboarding'; -import React, {useEffect, useState} from 'react'; +import React, {useEffect, useMemo, useState} from 'react'; import {View} from 'react-native'; +import {useMemoizedLazyIllustrations} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; @@ -28,21 +29,6 @@ import * as Illustrations from './Icon/Illustrations'; import LottieAnimations from './LottieAnimations'; import RenderHTML from './RenderHTML'; -const ExpensifyFeatures: FeatureListItem[] = [ - { - icon: Illustrations.ChatBubbles, - translationKey: 'migratedUserWelcomeModal.features.chat', - }, - { - icon: Illustrations.Flash, - translationKey: 'migratedUserWelcomeModal.features.scanReceipt', - }, - { - icon: Illustrations.ExpensifyMobileApp, - translationKey: 'migratedUserWelcomeModal.features.crossPlatform', - }, -]; - function MigratedUserWelcomeModal() { const {translate} = useLocalize(); const styles = useThemeStyles(); @@ -52,6 +38,25 @@ function MigratedUserWelcomeModal() { const [isModalDisabled, setIsModalDisabled] = useState(true); const route = useRoute>(); const shouldOpenSearch = route?.params?.shouldOpenSearch === 'true'; + const illustrations = useMemoizedLazyIllustrations(['ExpensifyMobileApp'] as const); + + const ExpensifyFeatures = useMemo( + () => [ + { + icon: Illustrations.ChatBubbles, + translationKey: 'migratedUserWelcomeModal.features.chat', + }, + { + icon: Illustrations.Flash, + translationKey: 'migratedUserWelcomeModal.features.scanReceipt', + }, + { + icon: illustrations.ExpensifyMobileApp, + translationKey: 'migratedUserWelcomeModal.features.crossPlatform', + }, + ], + [illustrations.ExpensifyMobileApp], + ); const [tryNewDot, tryNewDotMetadata] = useOnyx(ONYXKEYS.NVP_TRY_NEW_DOT, { selector: tryNewDotOnyxSelector, From 360a7506566b22b84b1d50cebf7ecc0d9e2d076a Mon Sep 17 00:00:00 2001 From: Samran Ahmed Date: Fri, 21 Nov 2025 19:13:31 +0500 Subject: [PATCH 7/8] fix: failing checks --- src/pages/settings/AboutPage/AboutPage.tsx | 3 +-- src/pages/settings/Security/TwoFactorAuth/CopyCodesPage.tsx | 3 +-- src/pages/workspace/distanceRates/PolicyDistanceRatesPage.tsx | 3 +-- .../workspace/receiptPartners/WorkspaceReceiptPartnersPage.tsx | 3 +-- 4 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/pages/settings/AboutPage/AboutPage.tsx b/src/pages/settings/AboutPage/AboutPage.tsx index 12eb72579929..340764ecdc91 100644 --- a/src/pages/settings/AboutPage/AboutPage.tsx +++ b/src/pages/settings/AboutPage/AboutPage.tsx @@ -13,8 +13,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 {useMemoizedLazyIllustrations} from '@hooks/useLazyAsset'; +import {useMemoizedLazyExpensifyIcons, useMemoizedLazyIllustrations} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useThemeStyles from '@hooks/useThemeStyles'; diff --git a/src/pages/settings/Security/TwoFactorAuth/CopyCodesPage.tsx b/src/pages/settings/Security/TwoFactorAuth/CopyCodesPage.tsx index 62865ca9122b..2bd8818f3842 100644 --- a/src/pages/settings/Security/TwoFactorAuth/CopyCodesPage.tsx +++ b/src/pages/settings/Security/TwoFactorAuth/CopyCodesPage.tsx @@ -12,8 +12,7 @@ import PressableWithDelayToggle from '@components/Pressable/PressableWithDelayTo import ScrollView from '@components/ScrollView'; import Section from '@components/Section'; import Text from '@components/Text'; -import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; -import {useMemoizedLazyAsset} from '@hooks/useLazyAsset'; +import {useMemoizedLazyAsset, useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; diff --git a/src/pages/workspace/distanceRates/PolicyDistanceRatesPage.tsx b/src/pages/workspace/distanceRates/PolicyDistanceRatesPage.tsx index 467df14fdb92..2b8bc8634666 100644 --- a/src/pages/workspace/distanceRates/PolicyDistanceRatesPage.tsx +++ b/src/pages/workspace/distanceRates/PolicyDistanceRatesPage.tsx @@ -19,8 +19,7 @@ import type {ListItem} from '@components/SelectionListWithSections/types'; import Switch from '@components/Switch'; import Text from '@components/Text'; import useFilteredSelection from '@hooks/useFilteredSelection'; -import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; -import {useMemoizedLazyAsset} from '@hooks/useLazyAsset'; +import {useMemoizedLazyAsset, useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useMobileSelectionMode from '@hooks/useMobileSelectionMode'; import useNetwork from '@hooks/useNetwork'; diff --git a/src/pages/workspace/receiptPartners/WorkspaceReceiptPartnersPage.tsx b/src/pages/workspace/receiptPartners/WorkspaceReceiptPartnersPage.tsx index 094cc6b50814..9796e123292f 100644 --- a/src/pages/workspace/receiptPartners/WorkspaceReceiptPartnersPage.tsx +++ b/src/pages/workspace/receiptPartners/WorkspaceReceiptPartnersPage.tsx @@ -16,8 +16,7 @@ import ScrollView from '@components/ScrollView'; import Section from '@components/Section'; import ThreeDotsMenu from '@components/ThreeDotsMenu'; import useGetReceiptPartnersIntegrationData from '@hooks/useGetReceiptPartnersIntegrationData'; -import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; -import {useMemoizedLazyAsset} from '@hooks/useLazyAsset'; +import {useMemoizedLazyAsset, useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; import usePolicy from '@hooks/usePolicy'; From 2b47891c1900f48cbca5789c6d346a53062a8583 Mon Sep 17 00:00:00 2001 From: Samran Ahmed Date: Mon, 24 Nov 2025 13:07:25 +0500 Subject: [PATCH 8/8] use pattern 3 to load a single asset --- src/components/LocationPermissionModal/index.android.tsx | 8 +++++--- src/components/LocationPermissionModal/index.desktop.tsx | 8 +++++--- src/components/LocationPermissionModal/index.tsx | 8 +++++--- .../ReimbursementAccount/ConnectedVerifiedBankAccount.tsx | 8 +++++--- src/pages/settings/AboutPage/AboutPage.tsx | 8 +++++--- src/pages/settings/Profile/ProfilePage.tsx | 8 +++++--- 6 files changed, 30 insertions(+), 18 deletions(-) diff --git a/src/components/LocationPermissionModal/index.android.tsx b/src/components/LocationPermissionModal/index.android.tsx index 098eca38e15b..9fd080c8863b 100644 --- a/src/components/LocationPermissionModal/index.android.tsx +++ b/src/components/LocationPermissionModal/index.android.tsx @@ -2,7 +2,9 @@ import React, {useEffect, useState} from 'react'; import {Linking} from 'react-native'; import {RESULTS} from 'react-native-permissions'; import ConfirmModal from '@components/ConfirmModal'; -import {useMemoizedLazyIllustrations} from '@hooks/useLazyAsset'; +import {loadIllustration} from '@components/Icon/IllustrationLoader'; +import type {IllustrationName} from '@components/Icon/IllustrationLoader'; +import {useMemoizedLazyAsset} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import {getLocationPermission, requestLocationPermission} from '@pages/iou/request/step/IOURequestStepScan/LocationPermission'; @@ -15,7 +17,7 @@ function LocationPermissionModal({startPermissionFlow, resetPermissionFlow, onDe const styles = useThemeStyles(); const {translate} = useLocalize(); - const illustrations = useMemoizedLazyIllustrations(['ReceiptLocationMarker'] as const); + const {asset: ReceiptLocationMarker} = useMemoizedLazyAsset(() => loadIllustration('ReceiptLocationMarker' as IllustrationName)); useEffect(() => { if (!startPermissionFlow) { @@ -89,7 +91,7 @@ function LocationPermissionModal({startPermissionFlow, resetPermissionFlow, onDe title={translate(hasError ? 'receipt.locationErrorTitle' : 'receipt.locationAccessTitle')} titleContainerStyles={[styles.mt2, styles.mb0]} titleStyles={[styles.textHeadline]} - iconSource={illustrations.ReceiptLocationMarker} + iconSource={ReceiptLocationMarker} iconFill={false} iconWidth={140} iconHeight={120} diff --git a/src/components/LocationPermissionModal/index.desktop.tsx b/src/components/LocationPermissionModal/index.desktop.tsx index 3f86fa6ba60d..a791a3e83341 100644 --- a/src/components/LocationPermissionModal/index.desktop.tsx +++ b/src/components/LocationPermissionModal/index.desktop.tsx @@ -2,8 +2,10 @@ import lodashDebounce from 'lodash/debounce'; import React, {useCallback, useEffect, useMemo, useState} from 'react'; import {RESULTS} from 'react-native-permissions'; import ConfirmModal from '@components/ConfirmModal'; +import {loadIllustration} from '@components/Icon/IllustrationLoader'; +import type {IllustrationName} from '@components/Icon/IllustrationLoader'; import ELECTRON_EVENTS from '@desktop/ELECTRON_EVENTS'; -import {useMemoizedLazyIllustrations} from '@hooks/useLazyAsset'; +import {useMemoizedLazyAsset} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import getPlatform from '@libs/getPlatform'; @@ -19,7 +21,7 @@ function LocationPermissionModal({startPermissionFlow, resetPermissionFlow, onDe const styles = useThemeStyles(); const {translate} = useLocalize(); - const illustrations = useMemoizedLazyIllustrations(['ReceiptLocationMarker'] as const); + const {asset: ReceiptLocationMarker} = useMemoizedLazyAsset(() => loadIllustration('ReceiptLocationMarker' as IllustrationName)); const isWeb = getPlatform() === CONST.PLATFORM.WEB; @@ -133,7 +135,7 @@ function LocationPermissionModal({startPermissionFlow, resetPermissionFlow, onDe title={translate(hasError ? 'receipt.locationErrorTitle' : 'receipt.locationAccessTitle')} titleContainerStyles={[styles.mt2, styles.mb0]} titleStyles={[styles.textHeadline]} - iconSource={illustrations.ReceiptLocationMarker} + iconSource={ReceiptLocationMarker} iconFill={false} iconWidth={140} iconHeight={120} diff --git a/src/components/LocationPermissionModal/index.tsx b/src/components/LocationPermissionModal/index.tsx index cc9895ecf4a6..cfaa7f23d1e2 100644 --- a/src/components/LocationPermissionModal/index.tsx +++ b/src/components/LocationPermissionModal/index.tsx @@ -3,7 +3,9 @@ import React, {useCallback, useEffect, useMemo, useState} from 'react'; import {Linking} from 'react-native'; import {RESULTS} from 'react-native-permissions'; import ConfirmModal from '@components/ConfirmModal'; -import {useMemoizedLazyIllustrations} from '@hooks/useLazyAsset'; +import {loadIllustration} from '@components/Icon/IllustrationLoader'; +import type {IllustrationName} from '@components/Icon/IllustrationLoader'; +import {useMemoizedLazyAsset} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import getPlatform from '@libs/getPlatform'; @@ -19,7 +21,7 @@ function LocationPermissionModal({startPermissionFlow, resetPermissionFlow, onDe const styles = useThemeStyles(); const {translate} = useLocalize(); - const illustrations = useMemoizedLazyIllustrations(['ReceiptLocationMarker'] as const); + const {asset: ReceiptLocationMarker} = useMemoizedLazyAsset(() => loadIllustration('ReceiptLocationMarker' as IllustrationName)); const isWeb = getPlatform() === CONST.PLATFORM.WEB; @@ -145,7 +147,7 @@ function LocationPermissionModal({startPermissionFlow, resetPermissionFlow, onDe title={translate(hasError ? 'receipt.locationErrorTitle' : 'receipt.locationAccessTitle')} titleContainerStyles={[styles.mt2, styles.mb0]} titleStyles={[styles.textHeadline]} - iconSource={illustrations.ReceiptLocationMarker} + iconSource={ReceiptLocationMarker} iconFill={false} iconWidth={140} iconHeight={120} diff --git a/src/pages/ReimbursementAccount/ConnectedVerifiedBankAccount.tsx b/src/pages/ReimbursementAccount/ConnectedVerifiedBankAccount.tsx index 4eb93f312590..0a1233d53bbf 100644 --- a/src/pages/ReimbursementAccount/ConnectedVerifiedBankAccount.tsx +++ b/src/pages/ReimbursementAccount/ConnectedVerifiedBankAccount.tsx @@ -3,13 +3,15 @@ import type {OnyxEntry} from 'react-native-onyx'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import getBankIcon from '@components/Icon/BankIcons'; import {Close} from '@components/Icon/Expensicons'; +import {loadIllustration} from '@components/Icon/IllustrationLoader'; +import type {IllustrationName} from '@components/Icon/IllustrationLoader'; import MenuItem from '@components/MenuItem'; import OfflineWithFeedback from '@components/OfflineWithFeedback'; 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 {useMemoizedLazyAsset} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useThemeStyles from '@hooks/useThemeStyles'; @@ -60,7 +62,7 @@ function ConnectedVerifiedBankAccount({ const errors = reimbursementAccount?.errors ?? {}; const pendingAction = reimbursementAccount?.pendingAction; const shouldShowResetModal = reimbursementAccount?.shouldShowResetModal ?? false; - const illustrations = useMemoizedLazyIllustrations(['ThumbsUpStars'] as const); + const {asset: ThumbsUpStars} = useMemoizedLazyAsset(() => loadIllustration('ThumbsUpStars' as IllustrationName)); return (
(null); const waitForNavigate = useWaitForNavigation(); const {shouldUseNarrowLayout} = useResponsiveLayout(); - const illustrations = useMemoizedLazyIllustrations(['PalmTree'] as const); + const {asset: PalmTree} = useMemoizedLazyAsset(() => loadIllustration('PalmTree' as IllustrationName)); const menuItems = useMemo(() => { const baseMenuItems: MenuItem[] = [ @@ -146,7 +148,7 @@ function AboutPage() { shouldShowBackButton={shouldUseNarrowLayout} shouldDisplaySearchRouter onBackButtonPress={Navigation.popToSidebar} - icon={illustrations.PalmTree} + icon={PalmTree} shouldUseHeadlineHeader /> diff --git a/src/pages/settings/Profile/ProfilePage.tsx b/src/pages/settings/Profile/ProfilePage.tsx index 597dc7f34a46..fcf0f63f9c26 100755 --- a/src/pages/settings/Profile/ProfilePage.tsx +++ b/src/pages/settings/Profile/ProfilePage.tsx @@ -8,13 +8,15 @@ import {DelegateNoAccessContext} from '@components/DelegateNoAccessModalProvider import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import * as Expensicons from '@components/Icon/Expensicons'; +import {loadIllustration} from '@components/Icon/IllustrationLoader'; +import type {IllustrationName} from '@components/Icon/IllustrationLoader'; import MenuItemGroup from '@components/MenuItemGroup'; import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription'; import ScreenWrapper from '@components/ScreenWrapper'; import ScrollView from '@components/ScrollView'; import Section from '@components/Section'; import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; -import {useMemoizedLazyIllustrations} from '@hooks/useLazyAsset'; +import {useMemoizedLazyAsset} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; @@ -56,7 +58,7 @@ function ProfilePage() { const avatarURL = currentUserPersonalDetails?.avatar ?? ''; const accountID = currentUserPersonalDetails?.accountID ?? CONST.DEFAULT_NUMBER_ID; const avatarStyle = [styles.avatarXLarge, styles.alignSelfStart]; - const illustrations = useMemoizedLazyIllustrations(['Profile'] as const); + const {asset: Profile} = useMemoizedLazyAsset(() => loadIllustration('Profile' as IllustrationName)); const contactMethodBrickRoadIndicator = getLoginListBrickRoadIndicator(loginList, currentUserPersonalDetails?.email); const emojiCode = currentUserPersonalDetails?.status?.emojiCode ?? ''; @@ -161,7 +163,7 @@ function ProfilePage() { }} shouldShowBackButton={shouldUseNarrowLayout} shouldDisplaySearchRouter - icon={illustrations.Profile} + icon={Profile} shouldUseHeadlineHeader />