-
Notifications
You must be signed in to change notification settings - Fork 3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Empty State Component for Search #44137
Merged
mountiny
merged 38 commits into
Expensify:main
from
software-mansion-labs:filip-solecki/empty-state-component
Jul 10, 2024
Merged
Changes from 37 commits
Commits
Show all changes
38 commits
Select commit
Hold shift + click to select a range
f0ba486
Empty State Component for Search
filip-solecki a995861
Remove backgroundColor
filip-solecki 9f3a62c
Animation case
filip-solecki 01333bc
Add animation and implement on Search page
filip-solecki d1ad016
Merge branch 'main' into filip-solecki/empty-state-component
filip-solecki 9c09664
Small fixes on search empty page, add new empty component on tags and…
filip-solecki 87c69fa
Small fixes
filip-solecki a19228a
remove unnecessary expensicon
filip-solecki 094a373
Adjust to final design
filip-solecki 31f04c7
Fix video styling
filip-solecki 77fc807
remove unnecessary styles
filip-solecki 0b8b124
self review fixes
filip-solecki a4bbb64
Add height for illustrations
filip-solecki ed66059
Fix lint
filip-solecki 2676725
Use RN StyleSheet flatten function
filip-solecki 774345b
cr fixes
filip-solecki 4ee0ab8
Remove redundant margin
filip-solecki d29b846
Add displayName
filip-solecki 4e54f88
Add double negation for checks
filip-solecki df19d03
remove empty line
filip-solecki 0526ef3
Merge branch 'main' into filip-solecki/empty-state-component
filip-solecki 370310a
rename to gradientOpacityEnabled
filip-solecki a0244ab
Remove redundant empty lines
filip-solecki 5d75244
Move headerMediaType values to CONST
filip-solecki 8e0b43f
Fix lint
filip-solecki 8a9748d
Adjust Search desktop skeleton
filip-solecki 2257f30
Merge branch 'main' into filip-solecki/empty-state-component
filip-solecki 54e6dd4
Fix overflowing modal
filip-solecki e5bab71
Merge branch 'main' into filip-solecki/empty-state-component
filip-solecki 3651cb1
Merge branch 'main' into filip-solecki/empty-state-component
filip-solecki 3ddfee2
Merge branch 'main' into filip-solecki/empty-state-component
filip-solecki 9e0f407
Remove unnecessary empty string
filip-solecki e89aeb8
Move calcuations values to consts
filip-solecki 742e197
Merge branch 'main' into filip-solecki/empty-state-component
filip-solecki f52dfd6
Fix styling
filip-solecki 5ffc2bc
Fix skeleton styling
filip-solecki 9a5c4b5
Fix padding for empty state modal
filip-solecki 544bb4c
Use variables for LHP width calculations
filip-solecki File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
102 changes: 102 additions & 0 deletions
102
assets/images/simple-illustrations/simple-illustration__empty-state.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
import type {VideoReadyForDisplayEvent} from 'expo-av'; | ||
import React, {useMemo, useState} from 'react'; | ||
import {View} from 'react-native'; | ||
import Button from '@components/Button'; | ||
import ImageSVG from '@components/ImageSVG'; | ||
import Lottie from '@components/Lottie'; | ||
import ScrollView from '@components/ScrollView'; | ||
import Text from '@components/Text'; | ||
import VideoPlayer from '@components/VideoPlayer'; | ||
import useThemeStyles from '@hooks/useThemeStyles'; | ||
import useWindowDimensions from '@hooks/useWindowDimensions'; | ||
import CONST from '@src/CONST'; | ||
import type {EmptyStateComponentProps, VideoLoadedEventType} from './types'; | ||
|
||
const VIDEO_ASPECT_RATIO = 400 / 225; | ||
|
||
function EmptyStateComponent({SkeletonComponent, headerMediaType, headerMedia, buttonText, buttonAction, title, subtitle, headerStyles, headerContentStyles}: EmptyStateComponentProps) { | ||
const styles = useThemeStyles(); | ||
const {isSmallScreenWidth} = useWindowDimensions(); | ||
const [videoAspectRatio, setVideoAspectRatio] = useState(VIDEO_ASPECT_RATIO); | ||
|
||
const setAspectRatio = (event: VideoReadyForDisplayEvent | VideoLoadedEventType | undefined) => { | ||
if (!event) { | ||
return; | ||
} | ||
|
||
if ('naturalSize' in event) { | ||
setVideoAspectRatio(event.naturalSize.width / event.naturalSize.height); | ||
} else { | ||
setVideoAspectRatio(event.srcElement.videoWidth / event.srcElement.videoHeight); | ||
} | ||
}; | ||
|
||
const HeaderComponent = useMemo(() => { | ||
switch (headerMediaType) { | ||
case CONST.EMPTY_STATE_MEDIA.VIDEO: | ||
return ( | ||
<VideoPlayer | ||
url={headerMedia} | ||
videoPlayerStyle={[headerContentStyles, {aspectRatio: videoAspectRatio}]} | ||
videoStyle={styles.emptyStateVideo} | ||
onVideoLoaded={setAspectRatio} | ||
controlsStatus={CONST.VIDEO_PLAYER.CONTROLS_STATUS.SHOW} | ||
shouldUseControlsBottomMargin={false} | ||
shouldPlay | ||
isLooping | ||
/> | ||
); | ||
case CONST.EMPTY_STATE_MEDIA.ANIMATION: | ||
return ( | ||
<Lottie | ||
source={headerMedia} | ||
autoPlay | ||
loop | ||
style={headerContentStyles} | ||
/> | ||
); | ||
case CONST.EMPTY_STATE_MEDIA.ILLUSTRATION: | ||
return ( | ||
<ImageSVG | ||
style={headerContentStyles} | ||
src={headerMedia} | ||
/> | ||
); | ||
default: | ||
return null; | ||
} | ||
}, [headerMedia, headerMediaType, headerContentStyles, videoAspectRatio, styles.emptyStateVideo]); | ||
|
||
return ( | ||
<ScrollView contentContainerStyle={styles.emptyStateScrollView}> | ||
<View style={styles.skeletonBackground}> | ||
<SkeletonComponent | ||
gradientOpacityEnabled | ||
shouldAnimate={false} | ||
/> | ||
</View> | ||
<View style={styles.emptyStateForeground(isSmallScreenWidth)}> | ||
<View style={styles.emptyStateContent}> | ||
<View style={[styles.emptyStateHeader(headerMediaType === CONST.EMPTY_STATE_MEDIA.ILLUSTRATION), headerStyles]}>{HeaderComponent}</View> | ||
<View style={styles.p8}> | ||
<Text style={[styles.textAlignCenter, styles.textHeadlineH1, styles.mb2]}>{title}</Text> | ||
<Text style={[styles.textAlignCenter, styles.textSupporting, styles.textNormal]}>{subtitle}</Text> | ||
{!!buttonText && !!buttonAction && ( | ||
<Button | ||
success | ||
onPress={buttonAction} | ||
> | ||
{buttonText} | ||
</Button> | ||
)} | ||
</View> | ||
</View> | ||
</View> | ||
</ScrollView> | ||
); | ||
} | ||
|
||
EmptyStateComponent.displayName = 'EmptyStateComponent'; | ||
export default EmptyStateComponent; | ||
filip-solecki marked this conversation as resolved.
Show resolved
Hide resolved
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
import type {ImageStyle} from 'expo-image'; | ||
import type {StyleProp, ViewStyle} from 'react-native'; | ||
import type {ValueOf} from 'type-fest'; | ||
import type DotLottieAnimation from '@components/LottieAnimations/types'; | ||
import type SearchRowSkeleton from '@components/Skeletons/SearchRowSkeleton'; | ||
import type TableRowSkeleton from '@components/Skeletons/TableRowSkeleton'; | ||
import type CONST from '@src/CONST'; | ||
import type IconAsset from '@src/types/utils/IconAsset'; | ||
|
||
type ValidSkeletons = typeof SearchRowSkeleton | typeof TableRowSkeleton; | ||
type MediaTypes = ValueOf<typeof CONST.EMPTY_STATE_MEDIA>; | ||
|
||
type SharedProps<T> = { | ||
SkeletonComponent: ValidSkeletons; | ||
title: string; | ||
subtitle: string; | ||
buttonText?: string; | ||
buttonAction?: () => void; | ||
headerStyles?: StyleProp<ViewStyle>; | ||
headerMediaType: T; | ||
headerContentStyles?: StyleProp<ViewStyle & ImageStyle>; | ||
}; | ||
|
||
type MediaType<HeaderMedia, T extends MediaTypes> = SharedProps<T> & { | ||
headerMedia: HeaderMedia; | ||
}; | ||
|
||
type VideoProps = MediaType<string, 'video'>; | ||
type IllustrationProps = MediaType<IconAsset, 'illustration'>; | ||
type AnimationProps = MediaType<DotLottieAnimation, 'animation'>; | ||
|
||
type EmptyStateComponentProps = VideoProps | IllustrationProps | AnimationProps; | ||
|
||
type VideoLoadedEventType = { | ||
srcElement: { | ||
videoWidth: number; | ||
videoHeight: number; | ||
}; | ||
}; | ||
|
||
export type {EmptyStateComponentProps, VideoLoadedEventType}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure, but shouldn't it be included in CONSTs?
Will the aspect ratio always be the same?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It may be different for each usage. Here it is adjusted to the "Modal" size
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be great to leave a comment about this, how did we get to this ratio?