[APP-1403] Profile empty states (#8969)

* update: Empty state component

* update type error fixes

* add empty state icon

* update translations on labels

* update: lint error for empty state

* remove unused prompt

* update type errors

* fix lint errors and update profile followers and profile follows

* updated starterpack

* fix lint errors

* address feedback

* update icons to be a react element

* update icons

* update viewbox for icons

* optimize: icons and update profile lists

* optimize: icons and update profile lists

* lint error fix

* update iconSize from the rebase
This commit is contained in:
Anastasiya Uraleva
2025-11-27 03:22:03 -08:00
committed by GitHub
parent 2d056e5be6
commit d0649e9a9e
44 changed files with 551 additions and 124 deletions
+84 -49
View File
@@ -1,76 +1,111 @@
import {type StyleProp, StyleSheet, View, type ViewStyle} from 'react-native'
import {type IconProp} from '@fortawesome/fontawesome-svg-core'
import {
FontAwesomeIcon,
type FontAwesomeIconStyle,
} from '@fortawesome/react-native-fontawesome'
import React from 'react'
import {type StyleProp, type TextStyle, type ViewStyle} from 'react-native'
import {View} from 'react-native'
import {usePalette} from '#/lib/hooks/usePalette'
import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
import {UserGroupIcon} from '#/lib/icons'
import {Growth_Stroke2_Corner0_Rounded as Growth} from '#/components/icons/Growth'
import {Text} from './text/Text'
import {atoms as a, useBreakpoints, useTheme} from '#/alf'
import {Button, type ButtonProps, ButtonText} from '#/components/Button'
import {EditBig_Stroke1_Corner0_Rounded as EditIcon} from '#/components/icons/EditBig'
import {Text} from '#/components/Typography'
export type EmptyStateButtonProps = Omit<ButtonProps, 'children' | 'label'> & {
label: string
text: string
}
export function EmptyState({
testID,
icon,
iconSize = '3xl',
message,
style,
textStyle,
button,
}: {
testID?: string
icon: IconProp | 'user-group' | 'growth'
icon?: React.ComponentType<any> | React.ReactElement
iconSize?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl'
message: string
style?: StyleProp<ViewStyle>
textStyle?: StyleProp<TextStyle>
button?: EmptyStateButtonProps
}) {
const pal = usePalette('default')
const {isTabletOrDesktop} = useWebMediaQueries()
const iconSize = isTabletOrDesktop ? 64 : 48
const t = useTheme()
const {gtMobile} = useBreakpoints()
const placeholderIcon = (
<EditIcon size="2xl" fill={t.atoms.text_contrast_medium.color} />
)
const renderIcon = () => {
if (!icon) {
return placeholderIcon
}
if (React.isValidElement(icon)) {
return icon
}
if (
typeof icon === 'function' ||
(typeof icon === 'object' && icon && 'render' in icon)
) {
const IconComponent = icon
return (
<IconComponent
size={iconSize}
fill={t.atoms.text_contrast_medium.color}
style={{color: t.atoms.text_contrast_low.color}}
/>
)
}
return placeholderIcon
}
return (
<View testID={testID} style={style}>
<View
style={[
styles.iconContainer,
isTabletOrDesktop && styles.iconContainerBig,
pal.viewLight,
a.flex_row,
a.align_center,
a.justify_center,
a.self_center,
a.rounded_full,
a.mt_5xl,
{height: 64, width: 64},
React.isValidElement(icon)
? a.bg_transparent
: [isTabletOrDesktop && {marginTop: 50}],
]}>
{icon === 'user-group' ? (
<UserGroupIcon size={iconSize} />
) : icon === 'growth' ? (
<Growth width={iconSize} fill={pal.colors.emptyStateIcon} />
) : (
<FontAwesomeIcon
icon={icon}
size={iconSize}
style={[{color: pal.colors.emptyStateIcon} as FontAwesomeIconStyle]}
/>
)}
{renderIcon()}
</View>
<Text type="xl" style={[{color: pal.colors.textLight}, styles.text]}>
<Text
style={[
{
color: pal.colors.textLight,
maxWidth: gtMobile ? '40%' : '60%',
},
a.pt_xs,
a.font_medium,
a.text_md,
a.leading_snug,
a.text_center,
a.self_center,
textStyle,
]}>
{message}
</Text>
{button && (
<View style={[a.flex_shrink, a.mt_xl, a.self_center]}>
<Button {...button}>
<ButtonText>{button.text}</ButtonText>
</Button>
</View>
)}
</View>
)
}
const styles = StyleSheet.create({
iconContainer: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
height: 80,
width: 80,
marginLeft: 'auto',
marginRight: 'auto',
borderRadius: 80,
marginTop: 30,
},
iconContainerBig: {
width: 100,
height: 100,
marginTop: 50,
},
text: {
textAlign: 'center',
paddingTop: 20,
},
})