diff --git a/assets/images/product-illustrations/fireworks.svg b/assets/images/product-illustrations/fireworks.svg new file mode 100644 index 000000000000..e5da607d0909 --- /dev/null +++ b/assets/images/product-illustrations/fireworks.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/images/product-illustrations/folder-with-papers-and-watch.svg b/assets/images/product-illustrations/folder-with-papers-and-watch.svg new file mode 100644 index 000000000000..935280fa0eee --- /dev/null +++ b/assets/images/product-illustrations/folder-with-papers-and-watch.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/images/product-illustrations/planet-with-mobile-app.svg b/assets/images/product-illustrations/planet-with-mobile-app.svg new file mode 100644 index 000000000000..8397cce09f19 --- /dev/null +++ b/assets/images/product-illustrations/planet-with-mobile-app.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/components/BlockingViews/BlockingView.tsx b/src/components/BlockingViews/BlockingView.tsx index 68d1ff21c87c..ce8f833f08ed 100644 --- a/src/components/BlockingViews/BlockingView.tsx +++ b/src/components/BlockingViews/BlockingView.tsx @@ -182,4 +182,5 @@ function BlockingView({ BlockingView.displayName = 'BlockingView'; +export type {BlockingViewProps}; export default BlockingView; diff --git a/src/components/EmptyStateComponent/GenericEmptyStateComponent.tsx b/src/components/EmptyStateComponent/GenericEmptyStateComponent.tsx new file mode 100644 index 000000000000..aaf20fd9b04b --- /dev/null +++ b/src/components/EmptyStateComponent/GenericEmptyStateComponent.tsx @@ -0,0 +1,12 @@ +import React from 'react'; +import EmptyStateComponent from '.'; +import type {EmptyStateComponentProps, GenericEmptyStateComponentProps} from './types'; + +// Only use this component when you need to pass/spread the props in a generic way, as +// EmptyStateComponent component wouldn't allow it in some cases. +function GenericEmptyStateComponent(props: GenericEmptyStateComponentProps) { + // eslint-disable-next-line react/jsx-props-no-spreading + return ; +} + +export default GenericEmptyStateComponent; diff --git a/src/components/EmptyStateComponent/index.tsx b/src/components/EmptyStateComponent/index.tsx index a00475785702..88f1e5bdcd12 100644 --- a/src/components/EmptyStateComponent/index.tsx +++ b/src/components/EmptyStateComponent/index.tsx @@ -1,7 +1,7 @@ import type {VideoReadyForDisplayEvent} from 'expo-av'; import isEmpty from 'lodash/isEmpty'; import React, {useMemo, useState} from 'react'; -import {View} from 'react-native'; +import {StyleSheet, View} from 'react-native'; import Button from '@components/Button'; import ButtonWithDropdownMenu from '@components/ButtonWithDropdownMenu'; import ImageSVG from '@components/ImageSVG'; @@ -80,7 +80,7 @@ function EmptyStateComponent({ case CONST.EMPTY_STATE_MEDIA.ILLUSTRATION: return ( ); diff --git a/src/components/EmptyStateComponent/types.ts b/src/components/EmptyStateComponent/types.ts index 5f62c0eac26f..23601b8087a3 100644 --- a/src/components/EmptyStateComponent/types.ts +++ b/src/components/EmptyStateComponent/types.ts @@ -10,6 +10,7 @@ import type IconAsset from '@src/types/utils/IconAsset'; type ValidSkeletons = typeof SearchRowSkeleton | typeof TableRowSkeleton; type MediaTypes = ValueOf; +type HeaderMedia = string | IconAsset | DotLottieAnimation; type EmptyStateButton = { buttonText?: string; buttonAction?: () => void; @@ -24,7 +25,7 @@ type EmptyStateButton = { >; }; -type SharedProps = { +type SharedProps = { SkeletonComponent?: ValidSkeletons; title: string; titleStyles?: StyleProp; @@ -35,15 +36,15 @@ type SharedProps = { cardStyles?: StyleProp; cardContentStyles?: StyleProp; headerStyles?: StyleProp; - headerMediaType: T; + headerMediaType: TMediaType; headerContentStyles?: StyleProp; lottieWebViewStyles?: React.CSSProperties | undefined; minModalHeight?: number; subtitleText?: React.ReactNode; }; -type MediaType = SharedProps & { - headerMedia: HeaderMedia; +type MediaType = SharedProps & { + headerMedia: THeaderMedia; }; type VideoProps = MediaType; @@ -51,6 +52,7 @@ type IllustrationProps = MediaType; type AnimationProps = MediaType; type EmptyStateComponentProps = VideoProps | IllustrationProps | AnimationProps; +type GenericEmptyStateComponentProps = SharedProps & {headerMedia: HeaderMedia}; type VideoLoadedEventType = { srcElement: { @@ -59,4 +61,4 @@ type VideoLoadedEventType = { }; }; -export type {EmptyStateComponentProps, VideoLoadedEventType, EmptyStateButton}; +export type {EmptyStateComponentProps, VideoLoadedEventType, EmptyStateButton, GenericEmptyStateComponentProps, MediaTypes, HeaderMedia}; diff --git a/src/components/Icon/chunks/illustrations.chunk.ts b/src/components/Icon/chunks/illustrations.chunk.ts index fa28809fadb6..31a3e8c55d01 100644 --- a/src/components/Icon/chunks/illustrations.chunk.ts +++ b/src/components/Icon/chunks/illustrations.chunk.ts @@ -49,6 +49,8 @@ import DjBoothReferenceHands from '@assets/images/product-illustrations/dj-booth import EmptyStateExpenses from '@assets/images/product-illustrations/emptystate__expenses.svg'; import HoldExpense from '@assets/images/product-illustrations/emptystate__holdexpense.svg'; import ReceiptFairy from '@assets/images/product-illustrations/emptystate__receiptfairy.svg'; +import Fireworks from '@assets/images/product-illustrations/fireworks.svg'; +import FolderWithPapersAndWatch from '@assets/images/product-illustrations/folder-with-papers-and-watch.svg'; import FolderWithPapers from '@assets/images/product-illustrations/folder-with-papers.svg'; import Hands from '@assets/images/product-illustrations/home-illustration-hands.svg'; import CardReplacementSuccess from '@assets/images/product-illustrations/illustration__card-replacement-success.svg'; @@ -56,6 +58,7 @@ import MagicCode from '@assets/images/product-illustrations/magic-code.svg'; import ModalHoldOrReject from '@assets/images/product-illustrations/modal-hold-or-reject.svg'; import MushroomTopHat from '@assets/images/product-illustrations/mushroom-top-hat.svg'; import PaymentHands from '@assets/images/product-illustrations/payment-hands.svg'; +import PlanetWithMobileApp from '@assets/images/product-illustrations/planet-with-mobile-app.svg'; import ReceiptsStackedOnPin from '@assets/images/product-illustrations/receipts-stacked-on-pin.svg'; import RocketBlue from '@assets/images/product-illustrations/rocket--blue.svg'; import RocketDude from '@assets/images/product-illustrations/rocket-dude.svg'; @@ -204,6 +207,8 @@ const Illustrations = { EmptyStateExpenses, HoldExpense, ReceiptFairy, + Fireworks, + FolderWithPapersAndWatch, FolderWithPapers, Hands, CardReplacementSuccess, @@ -211,6 +216,7 @@ const Illustrations = { ModalHoldOrReject, MushroomTopHat, PaymentHands, + PlanetWithMobileApp, ReceiptsStackedOnPin, RocketBlue, RocketDude, diff --git a/src/components/LHNOptionsList/LHNOptionsList.tsx b/src/components/LHNOptionsList/LHNOptionsList.tsx index 6a73cfeba010..14436979ab03 100644 --- a/src/components/LHNOptionsList/LHNOptionsList.tsx +++ b/src/components/LHNOptionsList/LHNOptionsList.tsx @@ -7,10 +7,10 @@ import type {ReactElement} from 'react'; import React, {memo, useCallback, useContext, useEffect, useMemo, useRef} from 'react'; import {StyleSheet, View} from 'react-native'; import type {OnyxEntry} from 'react-native-onyx'; +import type {BlockingViewProps} from '@components/BlockingViews/BlockingView'; import BlockingView from '@components/BlockingViews/BlockingView'; import Icon from '@components/Icon'; import * as Expensicons from '@components/Icon/Expensicons'; -import LottieAnimations from '@components/LottieAnimations'; import {ScrollOffsetContext} from '@components/ScrollOffsetContextProvider'; import TextBlock from '@components/TextBlock'; import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; @@ -46,6 +46,7 @@ import {isEmptyObject} from '@src/types/utils/EmptyObject'; import OptionRowLHNData from './OptionRowLHNData'; import OptionRowRendererComponent from './OptionRowRendererComponent'; import type {LHNOptionsListProps, RenderItemProps} from './types'; +import useEmptyLHNIllustration from './useEmptyLHNIllustration'; const keyExtractor = (item: Report) => `report_${item.reportID}`; @@ -79,6 +80,7 @@ function LHNOptionsList({style, contentContainerStyles, data, onSelectRow, optio const estimatedItemSize = optionMode === CONST.OPTION_MODE.COMPACT ? variables.optionRowHeightCompact : variables.optionRowHeight; const platform = getPlatform(); const isWebOrDesktop = platform === CONST.PLATFORM.WEB || platform === CONST.PLATFORM.DESKTOP; + const emptyLHNIllustration = useEmptyLHNIllustration(); const firstReportIDWithGBRorRBR = useMemo(() => { const firstReportWithGBRorRBR = data.find((report) => { @@ -420,9 +422,8 @@ function LHNOptionsList({style, contentContainerStyles, data, onSelectRow, optio {shouldShowEmptyLHN ? ( { + const styles = useThemeStyles(); + + return { + animation: LottieAnimations.Fireworks, + animationStyles: styles.emptyLHNAnimation, + animationWebStyle: styles.emptyLHNAnimation, + }; +}; + +export default useEmptyLHNIllustration; diff --git a/src/components/LHNOptionsList/useEmptyLHNIllustration/index.ts b/src/components/LHNOptionsList/useEmptyLHNIllustration/index.ts new file mode 100644 index 000000000000..c5c8985dddba --- /dev/null +++ b/src/components/LHNOptionsList/useEmptyLHNIllustration/index.ts @@ -0,0 +1,16 @@ +import {useMemoizedLazyIllustrations} from '@hooks/useLazyAsset'; +import useThemeStyles from '@hooks/useThemeStyles'; +import type UseEmptyLHNIllustration from './types'; + +const useEmptyLHNIllustration: UseEmptyLHNIllustration = () => { + const illustrations = useMemoizedLazyIllustrations(['Fireworks'] as const); + const styles = useThemeStyles(); + + return { + icon: illustrations.Fireworks, + iconWidth: styles.emptyStateFireworksStaticIllustration.width, + iconHeight: styles.emptyStateFireworksStaticIllustration.height, + }; +}; + +export default useEmptyLHNIllustration; diff --git a/src/components/LHNOptionsList/useEmptyLHNIllustration/types.ts b/src/components/LHNOptionsList/useEmptyLHNIllustration/types.ts new file mode 100644 index 000000000000..b32c65b44cae --- /dev/null +++ b/src/components/LHNOptionsList/useEmptyLHNIllustration/types.ts @@ -0,0 +1,5 @@ +import type {BlockingViewProps} from '@components/BlockingViews/BlockingView'; + +type UseEmptyLHNIllustration = () => Pick; + +export default UseEmptyLHNIllustration; diff --git a/src/libs/SearchUIUtils.ts b/src/libs/SearchUIUtils.ts index e00127fdb1ef..39e2528750a2 100644 --- a/src/libs/SearchUIUtils.ts +++ b/src/libs/SearchUIUtils.ts @@ -2,8 +2,6 @@ import type {TextStyle, ViewStyle} from 'react-native'; import type {OnyxCollection, OnyxEntry} from 'react-native-onyx'; import type {ValueOf} from 'type-fest'; import type {LocaleContextProps, LocalizedTranslate} from '@components/LocaleContextProvider'; -import DotLottieAnimations from '@components/LottieAnimations'; -import type DotLottieAnimation from '@components/LottieAnimations/types'; import type {MenuItemWithLink} from '@components/MenuItemList'; import type {MultiSelectItem} from '@components/Search/FilterDropdowns/MultiSelectPopup'; import type {SingleSelectItem} from '@components/Search/FilterDropdowns/SingleSelectPopup'; @@ -274,7 +272,6 @@ type SearchTypeMenuItem = { hash: number; similarSearchHash: number; emptyState?: { - headerMedia: DotLottieAnimation; title: TranslationPaths; subtitle: TranslationPaths; buttons?: Array<{ @@ -2136,7 +2133,6 @@ function createTypeMenuSections( todoSection.menuItems.push({ ...suggestedSearches[CONST.SEARCH.SEARCH_KEYS.SUBMIT], emptyState: { - headerMedia: DotLottieAnimations.Fireworks, title: 'search.searchResults.emptySubmitResults.title', subtitle: 'search.searchResults.emptySubmitResults.subtitle', buttons: @@ -2165,7 +2161,6 @@ function createTypeMenuSections( todoSection.menuItems.push({ ...suggestedSearches[CONST.SEARCH.SEARCH_KEYS.APPROVE], emptyState: { - headerMedia: DotLottieAnimations.Fireworks, title: 'search.searchResults.emptyApproveResults.title', subtitle: 'search.searchResults.emptyApproveResults.subtitle', }, @@ -2175,7 +2170,6 @@ function createTypeMenuSections( todoSection.menuItems.push({ ...suggestedSearches[CONST.SEARCH.SEARCH_KEYS.PAY], emptyState: { - headerMedia: DotLottieAnimations.Fireworks, title: 'search.searchResults.emptyPayResults.title', subtitle: 'search.searchResults.emptyPayResults.subtitle', }, @@ -2185,7 +2179,6 @@ function createTypeMenuSections( todoSection.menuItems.push({ ...suggestedSearches[CONST.SEARCH.SEARCH_KEYS.EXPORT], emptyState: { - headerMedia: DotLottieAnimations.Fireworks, title: 'search.searchResults.emptyExportResults.title', subtitle: 'search.searchResults.emptyExportResults.subtitle', }, @@ -2208,7 +2201,6 @@ function createTypeMenuSections( accountingSection.menuItems.push({ ...suggestedSearches[CONST.SEARCH.SEARCH_KEYS.STATEMENTS], emptyState: { - headerMedia: DotLottieAnimations.Fireworks, title: 'search.searchResults.emptyStatementsResults.title', subtitle: 'search.searchResults.emptyStatementsResults.subtitle', }, @@ -2218,7 +2210,6 @@ function createTypeMenuSections( accountingSection.menuItems.push({ ...suggestedSearches[CONST.SEARCH.SEARCH_KEYS.UNAPPROVED_CASH], emptyState: { - headerMedia: DotLottieAnimations.Fireworks, title: 'search.searchResults.emptyUnapprovedResults.title', subtitle: 'search.searchResults.emptyUnapprovedResults.subtitle', }, @@ -2228,7 +2219,6 @@ function createTypeMenuSections( accountingSection.menuItems.push({ ...suggestedSearches[CONST.SEARCH.SEARCH_KEYS.UNAPPROVED_CARD], emptyState: { - headerMedia: DotLottieAnimations.Fireworks, title: 'search.searchResults.emptyUnapprovedResults.title', subtitle: 'search.searchResults.emptyUnapprovedResults.subtitle', }, @@ -2238,7 +2228,6 @@ function createTypeMenuSections( accountingSection.menuItems.push({ ...suggestedSearches[CONST.SEARCH.SEARCH_KEYS.RECONCILIATION], emptyState: { - headerMedia: DotLottieAnimations.Fireworks, title: 'search.searchResults.emptyStatementsResults.title', subtitle: 'search.searchResults.emptyStatementsResults.subtitle', }, diff --git a/src/pages/Search/EmptySearchView.tsx b/src/pages/Search/EmptySearchView.tsx index 909057025aad..f24503361c1c 100644 --- a/src/pages/Search/EmptySearchView.tsx +++ b/src/pages/Search/EmptySearchView.tsx @@ -8,11 +8,10 @@ import {Linking, View} from 'react-native'; import type {OnyxCollection, OnyxEntry} from 'react-native-onyx'; import BookTravelButton from '@components/BookTravelButton'; import ConfirmModal from '@components/ConfirmModal'; -import EmptyStateComponent from '@components/EmptyStateComponent'; -import type {EmptyStateButton} from '@components/EmptyStateComponent/types'; +import GenericEmptyStateComponent from '@components/EmptyStateComponent/GenericEmptyStateComponent'; +import type {EmptyStateButton, HeaderMedia, MediaTypes} from '@components/EmptyStateComponent/types'; import type {FeatureListItem} from '@components/FeatureList'; import LottieAnimations from '@components/LottieAnimations'; -import type DotLottieAnimation from '@components/LottieAnimations/types'; import MenuItem from '@components/MenuItem'; import PressableWithSecondaryInteraction from '@components/PressableWithSecondaryInteraction'; import ScrollView from '@components/ScrollView'; @@ -51,6 +50,7 @@ import ROUTES from '@src/ROUTES'; import type {IntroSelected, PersonalDetails, Policy, Report, Transaction} from '@src/types/onyx'; import type {SearchDataTypes} from '@src/types/onyx/SearchResults'; import getEmptyArray from '@src/types/utils/getEmptyArray'; +import useSearchEmptyStateIllustration from './useSearchEmptyStateIllustration'; type EmptySearchViewProps = { similarSearchHash: number; @@ -72,7 +72,8 @@ type EmptySearchViewContentProps = EmptySearchViewProps & { }; type EmptySearchViewItem = { - headerMedia: DotLottieAnimation; + headerMediaType: MediaTypes; + headerMedia: HeaderMedia; title: string; subtitle?: string; headerContentStyles: Array>; @@ -312,14 +313,7 @@ function EmptySearchViewContent({ }, [contextMenuAnchor, handleContextMenuAnchorRef, styles, translate, tripsFeatures]); // Default 'Folder' lottie animation, along with its background styles - const defaultViewItemHeader = useMemo( - () => ({ - headerMedia: LottieAnimations.GenericEmptyState, - headerContentStyles: [styles.emptyStateFolderWebStyles, StyleUtils.getBackgroundColorStyle(theme.emptyFolderBG)], - lottieWebViewStyles: {backgroundColor: theme.emptyFolderBG, ...styles.emptyStateFolderWebStyles}, - }), - [StyleUtils, styles.emptyStateFolderWebStyles, theme.emptyFolderBG], - ); + const defaultViewItemHeader = useSearchEmptyStateIllustration(); const content: EmptySearchViewItem = useMemo(() => { // Begin by going through all of our To-do searches, and returning their empty state @@ -327,12 +321,9 @@ function EmptySearchViewContent({ for (const menuItem of typeMenuItems) { if (menuItem.similarSearchHash === similarSearchHash && menuItem.emptyState) { return { - headerMedia: menuItem.emptyState.headerMedia, + ...defaultViewItemHeader.fireworks, title: translate(menuItem.emptyState.title), subtitle: translate(menuItem.emptyState.subtitle), - headerStyles: StyleUtils.getBackgroundColorStyle(theme.todoBG), - headerContentStyles: [StyleUtils.getWidthAndHeightStyle(375, 240), StyleUtils.getBackgroundColorStyle(theme.todoBG)], - lottieWebViewStyles: styles.emptyStateFireworksWebStyles, buttons: menuItem.emptyState.buttons?.map((button) => ({ ...button, buttonText: translate(button.buttonText), @@ -349,6 +340,7 @@ function EmptySearchViewContent({ switch (type) { case CONST.SEARCH.DATA_TYPES.TRIP: return { + headerMediaType: CONST.EMPTY_STATE_MEDIA.ANIMATION, headerMedia: LottieAnimations.TripsEmptyState, headerContentStyles: [styles.emptyStateFolderWebStyles, StyleUtils.getBackgroundColorStyle(theme.travelBG)], title: translate('travel.title'), @@ -359,14 +351,14 @@ function EmptySearchViewContent({ case CONST.SEARCH.DATA_TYPES.EXPENSE_REPORT: if (hasResults && (!queryJSON || !isDefaultExpenseReportsQuery(queryJSON) || hasExpenseReports)) { return { - ...defaultViewItemHeader, + ...defaultViewItemHeader.folder, title: translate('search.searchResults.emptyResults.title'), subtitle: translate('search.searchResults.emptyResults.subtitle'), }; } if (!hasResults || !hasExpenseReports) { return { - ...defaultViewItemHeader, + ...defaultViewItemHeader.folder, title: translate('search.searchResults.emptyReportResults.title'), subtitle: translate(hasSeenTour ? 'search.searchResults.emptyReportResults.subtitleWithOnlyCreateButton' : 'search.searchResults.emptyReportResults.subtitle'), buttons: [ @@ -413,14 +405,14 @@ function EmptySearchViewContent({ case CONST.SEARCH.DATA_TYPES.EXPENSE: if (hasResults && (!queryJSON || !isDefaultExpensesQuery(queryJSON) || hasTransactions)) { return { - ...defaultViewItemHeader, + ...defaultViewItemHeader.folder, title: translate('search.searchResults.emptyResults.title'), subtitle: translate('search.searchResults.emptyResults.subtitle'), }; } if (!hasResults || !hasTransactions) { return { - ...defaultViewItemHeader, + ...defaultViewItemHeader.folder, title: translate('search.searchResults.emptyExpenseResults.title'), subtitle: translate(hasSeenTour ? 'search.searchResults.emptyExpenseResults.subtitleWithOnlyCreateButton' : 'search.searchResults.emptyExpenseResults.subtitle'), buttons: [ @@ -476,14 +468,14 @@ function EmptySearchViewContent({ success: true, }, ], - ...defaultViewItemHeader, + ...defaultViewItemHeader.folder, }; } // eslint-disable-next-line no-fallthrough case CONST.SEARCH.DATA_TYPES.CHAT: default: return { - ...defaultViewItemHeader, + ...defaultViewItemHeader.folder, title: translate('search.searchResults.emptyResults.title'), subtitle: translate('search.searchResults.emptyResults.subtitle'), }; @@ -494,9 +486,7 @@ function EmptySearchViewContent({ similarSearchHash, translate, StyleUtils, - theme.todoBG, theme.travelBG, - styles.emptyStateFireworksWebStyles, styles.emptyStateFolderWebStyles, styles.textAlignLeft, styles.tripEmptyStateLottieWebView, @@ -504,7 +494,8 @@ function EmptySearchViewContent({ tryNewDot?.hasBeenAddedToNudgeMigration, isUserPaidPolicyMember, hasResults, - defaultViewItemHeader, + defaultViewItemHeader.fireworks, + defaultViewItemHeader.folder, hasSeenTour, groupPoliciesWithChatEnabled.length, tripViewChildren, @@ -523,9 +514,9 @@ function EmptySearchViewContent({ showsVerticalScrollIndicator={false} contentContainerStyle={[styles.flexGrow1, styles.flexShrink0]} > - {content.children} - + {CreateReportConfirmationModal} { + const theme = useTheme(); + const StyleUtils = useStyleUtils(); + const styles = useThemeStyles(); + + return { + fireworks: { + headerMediaType: CONST.EMPTY_STATE_MEDIA.ANIMATION, + headerMedia: LottieAnimations.Fireworks, + headerStyles: StyleUtils.getBackgroundColorStyle(theme.todoBG), + headerContentStyles: [StyleUtils.getWidthAndHeightStyle(375, 240), StyleUtils.getBackgroundColorStyle(theme.todoBG)], + lottieWebViewStyles: styles.emptyStateFireworksWebStyles, + }, + folder: { + headerMediaType: CONST.EMPTY_STATE_MEDIA.ANIMATION, + headerMedia: LottieAnimations.GenericEmptyState, + headerContentStyles: [styles.emptyStateFolderWebStyles, StyleUtils.getBackgroundColorStyle(theme.emptyFolderBG)], + lottieWebViewStyles: {backgroundColor: theme.emptyFolderBG, ...styles.emptyStateFolderWebStyles}, + }, + }; +}; + +export default useSearchEmptyStateIllustration; diff --git a/src/pages/Search/useSearchEmptyStateIllustration/index.ts b/src/pages/Search/useSearchEmptyStateIllustration/index.ts new file mode 100644 index 000000000000..98a5bf37f33a --- /dev/null +++ b/src/pages/Search/useSearchEmptyStateIllustration/index.ts @@ -0,0 +1,30 @@ +import {useMemoizedLazyIllustrations} from '@hooks/useLazyAsset'; +import useStyleUtils from '@hooks/useStyleUtils'; +import useTheme from '@hooks/useTheme'; +import useThemeStyles from '@hooks/useThemeStyles'; +import CONST from '@src/CONST'; +import type UseSearchEmptyStateIllustration from './types'; + +const useSearchEmptyStateIllustration: UseSearchEmptyStateIllustration = () => { + const illustrations = useMemoizedLazyIllustrations(['Fireworks', 'FolderWithPapersAndWatch'] as const); + const theme = useTheme(); + const StyleUtils = useStyleUtils(); + const styles = useThemeStyles(); + + return { + fireworks: { + headerMediaType: CONST.EMPTY_STATE_MEDIA.ILLUSTRATION, + headerMedia: illustrations.Fireworks, + headerStyles: StyleUtils.getBackgroundColorStyle(theme.todoBG), + headerContentStyles: [styles.emptyStateFireworksStaticIllustration, StyleUtils.getBackgroundColorStyle(theme.todoBG)], + }, + folder: { + headerMediaType: CONST.EMPTY_STATE_MEDIA.ILLUSTRATION, + headerMedia: illustrations.FolderWithPapersAndWatch, + headerStyles: StyleUtils.getBackgroundColorStyle(theme.emptyFolderBG), + headerContentStyles: [styles.emptyStateFolderWebStyles, styles.emptyStateFolderStaticIllustration, StyleUtils.getBackgroundColorStyle(theme.emptyFolderBG)], + }, + }; +}; + +export default useSearchEmptyStateIllustration; diff --git a/src/pages/Search/useSearchEmptyStateIllustration/types.ts b/src/pages/Search/useSearchEmptyStateIllustration/types.ts new file mode 100644 index 000000000000..967d77ee74a9 --- /dev/null +++ b/src/pages/Search/useSearchEmptyStateIllustration/types.ts @@ -0,0 +1,8 @@ +import type {EmptySearchViewItem} from '@pages/Search/EmptySearchView'; + +type UseSearchEmptyStateIllustration = () => Record< + 'fireworks' | 'folder', + Pick +>; + +export default UseSearchEmptyStateIllustration; diff --git a/src/components/WorkspacesEmptyStateComponent.tsx b/src/pages/workspace/WorkspacesEmptyStateComponent.tsx similarity index 77% rename from src/components/WorkspacesEmptyStateComponent.tsx rename to src/pages/workspace/WorkspacesEmptyStateComponent.tsx index a20cb77e2271..3a5755c9cca3 100644 --- a/src/components/WorkspacesEmptyStateComponent.tsx +++ b/src/pages/workspace/WorkspacesEmptyStateComponent.tsx @@ -1,4 +1,6 @@ import React from 'react'; +import GenericEmptyStateComponent from '@components/EmptyStateComponent/GenericEmptyStateComponent'; +import WorkspaceRowSkeleton from '@components/Skeletons/WorkspaceRowSkeleton'; import useLocalize from '@hooks/useLocalize'; import usePreferredPolicy from '@hooks/usePreferredPolicy'; import useStyleUtils from '@hooks/useStyleUtils'; @@ -7,29 +9,25 @@ import interceptAnonymousUser from '@libs/interceptAnonymousUser'; import Navigation from '@libs/Navigation/Navigation'; import colors from '@styles/theme/colors'; import variables from '@styles/variables'; -import CONST from '@src/CONST'; import ROUTES from '@src/ROUTES'; -import EmptyStateComponent from './EmptyStateComponent'; -import LottieAnimations from './LottieAnimations'; -import WorkspaceRowSkeleton from './Skeletons/WorkspaceRowSkeleton'; +import useWorkspacesEmptyStateIllustration from './useWorkspacesEmptyStateIllustration'; function WorkspacesEmptyStateComponent() { const styles = useThemeStyles(); const {translate} = useLocalize(); const StyleUtils = useStyleUtils(); const {isRestrictedPolicyCreation} = usePreferredPolicy(); + const illustration = useWorkspacesEmptyStateIllustration(); return ( - { + const styles = useThemeStyles(); + + return { + headerMediaType: CONST.EMPTY_STATE_MEDIA.ANIMATION, + headerMedia: LottieAnimations.WorkspacePlanet, + headerContentStyles: styles.emptyWorkspaceListLottieIllustrationStyle, + lottieWebViewStyles: styles.emptyWorkspaceListLottieIllustrationStyle, + }; +}; + +export default useWorkspacesEmptyStateIllustration; diff --git a/src/pages/workspace/useWorkspacesEmptyStateIllustration/index.ts b/src/pages/workspace/useWorkspacesEmptyStateIllustration/index.ts new file mode 100644 index 000000000000..7f2dc7caa4dc --- /dev/null +++ b/src/pages/workspace/useWorkspacesEmptyStateIllustration/index.ts @@ -0,0 +1,17 @@ +import {useMemoizedLazyIllustrations} from '@hooks/useLazyAsset'; +import useThemeStyles from '@hooks/useThemeStyles'; +import CONST from '@src/CONST'; +import type UseWorkspacesEmptyStateIllustration from './types'; + +const useWorkspacesEmptyStateIllustration: UseWorkspacesEmptyStateIllustration = () => { + const illustrations = useMemoizedLazyIllustrations(['PlanetWithMobileApp'] as const); + const styles = useThemeStyles(); + + return { + headerMediaType: CONST.EMPTY_STATE_MEDIA.ILLUSTRATION, + headerMedia: illustrations.PlanetWithMobileApp, + headerContentStyles: styles.emptyWorkspaceListStaticIllustrationStyle, + }; +}; + +export default useWorkspacesEmptyStateIllustration; diff --git a/src/pages/workspace/useWorkspacesEmptyStateIllustration/types.ts b/src/pages/workspace/useWorkspacesEmptyStateIllustration/types.ts new file mode 100644 index 000000000000..7be58885e00f --- /dev/null +++ b/src/pages/workspace/useWorkspacesEmptyStateIllustration/types.ts @@ -0,0 +1,5 @@ +import type {EmptyStateComponentProps} from '@components/EmptyStateComponent/types'; + +type UseWorkspacesEmptyStateIllustration = () => Pick; + +export default UseWorkspacesEmptyStateIllustration; diff --git a/src/styles/index.ts b/src/styles/index.ts index 815536b71f8e..a8e22b665bc0 100644 --- a/src/styles/index.ts +++ b/src/styles/index.ts @@ -1871,11 +1871,15 @@ const staticStyles = (theme: ThemeColors) => marginBottom: -20, }, - emptyWorkspaceListIllustrationStyle: { + emptyWorkspaceListLottieIllustrationStyle: { marginTop: 12, marginBottom: -20, height: '100%', }, + emptyWorkspaceListStaticIllustrationStyle: { + width: 203, + height: 166, + }, appContent: { backgroundColor: theme.appBG, @@ -5163,6 +5167,11 @@ const staticStyles = (theme: ThemeColors) => ...display.dFlex, }, + emptyStateFolderStaticIllustration: { + width: 184, + height: 112, + }, + emptyStateFireworksWebStyles: { width: 250, ...flex.alignItemsCenter, @@ -5170,6 +5179,11 @@ const staticStyles = (theme: ThemeColors) => ...display.dFlex, }, + emptyStateFireworksStaticIllustration: { + width: 164, + height: 148, + }, + tripEmptyStateLottieWebView: { width: 335, height: 220,