diff --git a/assets/animations/BankVault.lottie b/assets/animations/BankVault.lottie new file mode 100644 index 000000000000..82361e8e2209 Binary files /dev/null and b/assets/animations/BankVault.lottie differ diff --git a/assets/animations/GenericEmptyState.lottie b/assets/animations/GenericEmptyState.lottie new file mode 100644 index 000000000000..d62ff9d980bb Binary files /dev/null and b/assets/animations/GenericEmptyState.lottie differ diff --git a/assets/animations/TripsEmptyState.lottie b/assets/animations/TripsEmptyState.lottie new file mode 100644 index 000000000000..8a07a6ad10d5 Binary files /dev/null and b/assets/animations/TripsEmptyState.lottie differ diff --git a/src/components/EmptyStateComponent/index.tsx b/src/components/EmptyStateComponent/index.tsx index 578ea13fece9..876f1a745403 100644 --- a/src/components/EmptyStateComponent/index.tsx +++ b/src/components/EmptyStateComponent/index.tsx @@ -7,6 +7,7 @@ import Lottie from '@components/Lottie'; import ScrollView from '@components/ScrollView'; import Text from '@components/Text'; import VideoPlayer from '@components/VideoPlayer'; +import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useThemeStyles from '@hooks/useThemeStyles'; import CONST from '@src/CONST'; import type {EmptyStateComponentProps, VideoLoadedEventType} from './types'; @@ -24,10 +25,12 @@ function EmptyStateComponent({ subtitle, headerStyles, headerContentStyles, + lottieWebViewStyles, minModalHeight = 400, }: EmptyStateComponentProps) { const styles = useThemeStyles(); const [videoAspectRatio, setVideoAspectRatio] = useState(VIDEO_ASPECT_RATIO); + const {isSmallScreenWidth} = useResponsiveLayout(); const setAspectRatio = (event: VideoReadyForDisplayEvent | VideoLoadedEventType | undefined) => { if (!event) { @@ -63,6 +66,7 @@ function EmptyStateComponent({ autoPlay loop style={headerContentStyles} + webStyle={lottieWebViewStyles} /> ); case CONST.EMPTY_STATE_MEDIA.ILLUSTRATION: @@ -75,7 +79,7 @@ function EmptyStateComponent({ default: return null; } - }, [headerMedia, headerMediaType, headerContentStyles, videoAspectRatio, styles.emptyStateVideo]); + }, [headerMedia, headerMediaType, headerContentStyles, videoAspectRatio, styles.emptyStateVideo, lottieWebViewStyles]); return ( @@ -88,7 +92,7 @@ function EmptyStateComponent({ {HeaderComponent} - + {title} {subtitle} {!!buttonText && !!buttonAction && ( diff --git a/src/components/EmptyStateComponent/types.ts b/src/components/EmptyStateComponent/types.ts index a30a9222c01f..4926d3b002b8 100644 --- a/src/components/EmptyStateComponent/types.ts +++ b/src/components/EmptyStateComponent/types.ts @@ -20,6 +20,7 @@ type SharedProps = { headerStyles?: StyleProp; headerMediaType: T; headerContentStyles?: StyleProp; + lottieWebViewStyles?: React.CSSProperties | undefined; minModalHeight?: number; }; diff --git a/src/components/LottieAnimations/index.tsx b/src/components/LottieAnimations/index.tsx index afbc9cd56e28..b9e1410809cf 100644 --- a/src/components/LottieAnimations/index.tsx +++ b/src/components/LottieAnimations/index.tsx @@ -79,6 +79,21 @@ const DotLottieAnimations = { w: 180, h: 200, }, + GenericEmptyState: { + file: require('@assets/animations/GenericEmptyState.lottie'), + w: 375, + h: 240, + }, + TripsEmptyState: { + file: require('@assets/animations/TripsEmptyState.lottie'), + w: 375, + h: 240, + }, + BankVault: { + file: require('@assets/animations/BankVault.lottie'), + w: 375, + h: 240, + }, } satisfies Record; export default DotLottieAnimations; diff --git a/src/pages/Search/EmptySearchView.tsx b/src/pages/Search/EmptySearchView.tsx index 1f259c96d625..edcf6ab23219 100644 --- a/src/pages/Search/EmptySearchView.tsx +++ b/src/pages/Search/EmptySearchView.tsx @@ -1,12 +1,12 @@ import React, {useMemo} from 'react'; import EmptyStateComponent from '@components/EmptyStateComponent'; -import * as Illustrations from '@components/Icon/Illustrations'; +import LottieAnimations from '@components/LottieAnimations'; import SearchRowSkeleton from '@components/Skeletons/SearchRowSkeleton'; import useLocalize from '@hooks/useLocalize'; import useStyleUtils from '@hooks/useStyleUtils'; import useTheme from '@hooks/useTheme'; +import useThemeStyles from '@hooks/useThemeStyles'; import Navigation from '@libs/Navigation/Navigation'; -import variables from '@styles/variables'; import CONST from '@src/CONST'; import ROUTES from '@src/ROUTES'; import type {SearchDataTypes} from '@src/types/onyx/SearchResults'; @@ -19,14 +19,14 @@ function EmptySearchView({type}: EmptySearchViewProps) { const theme = useTheme(); const StyleUtils = useStyleUtils(); const {translate} = useLocalize(); + const styles = useThemeStyles(); const content = useMemo(() => { switch (type) { case CONST.SEARCH.DATA_TYPES.TRIP: return { - headerMedia: Illustrations.EmptyStateTravel, - headerStyles: StyleUtils.getBackgroundColorStyle(theme.travelBG), - headerContentStyles: StyleUtils.getWidthAndHeightStyle(variables.w191, variables.h172), + headerMedia: LottieAnimations.TripsEmptyState, + headerStyles: [StyleUtils.getBackgroundColorStyle(theme.travelBG), styles.w100], title: translate('search.searchResults.emptyTripResults.title'), subtitle: translate('search.searchResults.emptyTripResults.subtitle'), buttonText: translate('search.searchResults.emptyTripResults.buttonText'), @@ -37,28 +37,29 @@ function EmptySearchView({type}: EmptySearchViewProps) { case CONST.SEARCH.DATA_TYPES.INVOICE: default: return { - headerMedia: Illustrations.EmptyState, - headerStyles: StyleUtils.getBackgroundColorStyle(theme.emptyFolderBG), - headerContentStyles: StyleUtils.getWidthAndHeightStyle(variables.w184, variables.h112), + headerMedia: LottieAnimations.GenericEmptyState, + headerStyles: [StyleUtils.getBackgroundColorStyle(theme.emptyFolderBG)], title: translate('search.searchResults.emptyResults.title'), subtitle: translate('search.searchResults.emptyResults.subtitle'), buttonText: undefined, buttonAction: undefined, + headerContentStyles: styles.emptyStateFolderWebStyles, }; } - }, [type, StyleUtils, translate, theme]); + }, [type, StyleUtils, translate, theme, styles.w100, styles.emptyStateFolderWebStyles]); return ( ); } diff --git a/src/pages/Travel/ManageTrips.tsx b/src/pages/Travel/ManageTrips.tsx index c5d381846631..0591d8cf2fcf 100644 --- a/src/pages/Travel/ManageTrips.tsx +++ b/src/pages/Travel/ManageTrips.tsx @@ -6,6 +6,7 @@ import type {FeatureListItem} from '@components/FeatureList'; import FeatureList from '@components/FeatureList'; import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator'; import * as Illustrations from '@components/Icon/Illustrations'; +import LottieAnimations from '@components/LottieAnimations'; import ScrollView from '@components/ScrollView'; import useLocalize from '@hooks/useLocalize'; import usePolicy from '@hooks/usePolicy'; @@ -82,8 +83,8 @@ function ManageTrips() { }); }} ctaErrorMessage={ctaErrorMessage} - illustration={Illustrations.EmptyStateTravel} - illustrationStyle={[styles.mv4, styles.tripIllustrationSize]} + illustration={LottieAnimations.TripsEmptyState} + illustrationStyle={[styles.mv4]} secondaryButtonText={translate('travel.bookDemo')} secondaryButtonAccessibilityLabel={translate('travel.bookDemo')} onSecondaryButtonPress={navigateToBookTravelDemo} diff --git a/src/pages/settings/Wallet/WalletPage/WalletPage.tsx b/src/pages/settings/Wallet/WalletPage/WalletPage.tsx index 316c0b66b95d..cf13c29ffb20 100644 --- a/src/pages/settings/Wallet/WalletPage/WalletPage.tsx +++ b/src/pages/settings/Wallet/WalletPage/WalletPage.tsx @@ -13,6 +13,7 @@ import * as Expensicons from '@components/Icon/Expensicons'; import * as Illustrations from '@components/Icon/Illustrations'; import KYCWall from '@components/KYCWall'; import type {PaymentMethodType, Source} from '@components/KYCWall/types'; +import LottieAnimations from '@components/LottieAnimations'; import MenuItem from '@components/MenuItem'; import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription'; import OfflineWithFeedback from '@components/OfflineWithFeedback'; @@ -381,7 +382,7 @@ function WalletPage({shouldListenForResize = false}: WalletPageProps) { title={translate('walletPage.bankAccounts')} isCentralPane titleStyles={styles.accountSettingsSectionTitle} - illustration={Illustrations.BigVault} + illustration={LottieAnimations.BankVault} illustrationStyle={styles.walletIllustration} illustrationContainerStyle={{height: 220}} illustrationBackgroundColor="#411103" diff --git a/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx b/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx index 340bd991c609..f82591a4fc04 100644 --- a/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx +++ b/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx @@ -13,6 +13,7 @@ import EmptyStateComponent from '@components/EmptyStateComponent'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import * as Expensicons from '@components/Icon/Expensicons'; import * as Illustrations from '@components/Icon/Illustrations'; +import LottieAnimations from '@components/LottieAnimations'; import ScreenWrapper from '@components/ScreenWrapper'; import ListItemRightCaretWithLabel from '@components/SelectionList/ListItemRightCaretWithLabel'; import TableListItem from '@components/SelectionList/TableListItem'; @@ -391,12 +392,13 @@ function WorkspaceCategoriesPage({route}: WorkspaceCategoriesPageProps) { {!hasVisibleCategories && !isLoading && ( )} {hasVisibleCategories && !isLoading && ( diff --git a/src/pages/workspace/reportFields/ReportFieldsListValuesPage.tsx b/src/pages/workspace/reportFields/ReportFieldsListValuesPage.tsx index 1ee20f1180ff..937a2d5efec4 100644 --- a/src/pages/workspace/reportFields/ReportFieldsListValuesPage.tsx +++ b/src/pages/workspace/reportFields/ReportFieldsListValuesPage.tsx @@ -315,9 +315,9 @@ function ReportFieldsListValuesPage({ subtitle={translate('workspace.reportFields.emptyReportFieldsValues.subtitle')} SkeletonComponent={TableListItemSkeleton} headerMediaType={CONST.EMPTY_STATE_MEDIA.ILLUSTRATION} - headerMedia={Illustrations.EmptyStateExpenses} - headerStyles={styles.emptyFolderBG} - headerContentStyles={styles.emptyStateFolderIconSize} + headerMedia={Illustrations.FolderWithPapers} + headerStyles={styles.emptyFolderDarkBG} + headerContentStyles={styles.emptyStateFolderWithPaperIconSize} /> )} {!shouldShowEmptyState && ( diff --git a/src/pages/workspace/reportFields/WorkspaceReportFieldsPage.tsx b/src/pages/workspace/reportFields/WorkspaceReportFieldsPage.tsx index 0ffdb362ae99..e20f3e70b2f3 100644 --- a/src/pages/workspace/reportFields/WorkspaceReportFieldsPage.tsx +++ b/src/pages/workspace/reportFields/WorkspaceReportFieldsPage.tsx @@ -11,6 +11,7 @@ import EmptyStateComponent from '@components/EmptyStateComponent'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import * as Expensicons from '@components/Icon/Expensicons'; import * as Illustrations from '@components/Icon/Illustrations'; +import LottieAnimations from '@components/LottieAnimations'; import ScreenWrapper from '@components/ScreenWrapper'; import ListItemRightCaretWithLabel from '@components/SelectionList/ListItemRightCaretWithLabel'; import TableListItem from '@components/SelectionList/TableListItem'; @@ -289,10 +290,11 @@ function WorkspaceReportFieldsPage({ title={translate('workspace.reportFields.emptyReportFields.title')} subtitle={translate('workspace.reportFields.emptyReportFields.subtitle')} SkeletonComponent={TableListItemSkeleton} - headerMediaType={CONST.EMPTY_STATE_MEDIA.ILLUSTRATION} - headerMedia={Illustrations.EmptyStateExpenses} - headerStyles={styles.emptyFolderBG} - headerContentStyles={styles.emptyStateFolderIconSize} + headerMediaType={CONST.EMPTY_STATE_MEDIA.ANIMATION} + headerMedia={LottieAnimations.GenericEmptyState} + headerStyles={[styles.emptyStateCardIllustrationContainer, styles.emptyFolderBG]} + lottieWebViewStyles={styles.emptyStateFolderWebStyles} + headerContentStyles={styles.emptyStateFolderWebStyles} /> )} {!shouldShowEmptyState && !isLoading && ( diff --git a/src/pages/workspace/tags/WorkspaceTagsPage.tsx b/src/pages/workspace/tags/WorkspaceTagsPage.tsx index 84722a1f0b5b..7bc4f9d9e603 100644 --- a/src/pages/workspace/tags/WorkspaceTagsPage.tsx +++ b/src/pages/workspace/tags/WorkspaceTagsPage.tsx @@ -12,6 +12,7 @@ import EmptyStateComponent from '@components/EmptyStateComponent'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import * as Expensicons from '@components/Icon/Expensicons'; import * as Illustrations from '@components/Icon/Illustrations'; +import LottieAnimations from '@components/LottieAnimations'; import type {PopoverMenuItem} from '@components/PopoverMenu'; import ScreenWrapper from '@components/ScreenWrapper'; import ListItemRightCaretWithLabel from '@components/SelectionList/ListItemRightCaretWithLabel'; @@ -397,12 +398,13 @@ function WorkspaceTagsPage({route}: WorkspaceTagsPageProps) { {!hasVisibleTags && !isLoading && ( )} {hasVisibleTags && !isLoading && ( diff --git a/src/styles/index.ts b/src/styles/index.ts index ad6c0552aa29..05bedf7cf3af 100644 --- a/src/styles/index.ts +++ b/src/styles/index.ts @@ -4727,8 +4727,7 @@ const styles = (theme: ThemeColors) => }, walletIllustration: { - width: 262, - height: 152, + height: 180, }, walletCardLimit: { @@ -5076,6 +5075,8 @@ const styles = (theme: ThemeColors) => emptyStateCardIllustrationContainer: { height: 220, + ...flex.alignItemsCenter, + ...flex.justifyContentCenter, }, emptyStateCardIllustration: { @@ -5113,11 +5114,6 @@ const styles = (theme: ThemeColors) => textDecorationLine: 'line-through', }, - tripIllustrationSize: { - width: 190, - height: 172, - }, - reportListItemTitle: { color: theme.text, fontSize: variables.fontSizeNormal, @@ -5163,14 +5159,27 @@ const styles = (theme: ThemeColors) => backgroundColor: theme.emptyFolderBG, }, + emptyFolderDarkBG: { + backgroundColor: '#782c04', + height: 220, + }, + emptyStateVideo: { borderTopLeftRadius: variables.componentBorderRadiusLarge, borderTopRightRadius: variables.componentBorderRadiusLarge, }, - emptyStateFolderIconSize: { - width: 184, - height: 112, + emptyStateFolderWithPaperIconSize: { + width: 160, + height: 100, + }, + + emptyStateFolderWebStyles: { + ...sizing.w100, + minWidth: 400, + ...flex.alignItemsCenter, + ...flex.justifyContentCenter, + ...display.dFlex, }, workflowApprovalVerticalLine: { diff --git a/src/styles/utils/spacing.ts b/src/styles/utils/spacing.ts index 783a9a97ac7d..79b2039f139b 100644 --- a/src/styles/utils/spacing.ts +++ b/src/styles/utils/spacing.ts @@ -87,6 +87,10 @@ export default { marginVertical: 24, }, + mvAuto: { + marginVertical: 'auto', + }, + mhv5: { marginVertical: -20, },