Skip to content
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

ProfileHeader component cleanup, generic button with icon elements #1836

Closed
wants to merge 9 commits into from
31 changes: 24 additions & 7 deletions src/view/com/profile/FollowButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,29 @@ import {Button, ButtonType} from '../util/forms/Button'
import * as Toast from '../util/Toast'
import {FollowState} from 'state/models/cache/my-follows'
import {useFollowProfile} from 'lib/hooks/useFollowProfile'
import {s} from '#/lib/styles'
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
import {usePalette} from '#/lib/hooks/usePalette'

type Props = {
unfollowedType?: ButtonType
followedType?: ButtonType
profile: AppBskyActorDefs.ProfileViewBasic
onToggleFollow?: (v: boolean) => void
labelStyle?: StyleProp<TextStyle>
} & React.ComponentProps<typeof Button>

export const FollowButton = observer(function FollowButtonImpl({
unfollowedType = 'inverted',
followedType = 'default',
profile,
onToggleFollow,
labelStyle,
}: {
unfollowedType?: ButtonType
followedType?: ButtonType
profile: AppBskyActorDefs.ProfileViewBasic
onToggleFollow?: (v: boolean) => void
labelStyle?: StyleProp<TextStyle>
}) {
...rest
}: Props) {
const pal = usePalette('default')
const palInverted = usePalette('inverted')

const {state, following, toggle} = useFollowProfile(profile)

const onPress = React.useCallback(async () => {
Expand All @@ -37,11 +46,19 @@ export const FollowButton = observer(function FollowButtonImpl({

return (
<Button
StartIcon={
following ? (
<FontAwesomeIcon icon="check" style={[pal.text, s.mr2]} size={14} />
) : (
<FontAwesomeIcon icon="plus" style={[palInverted.text, s.mr2]} />
)
}
type={following ? followedType : unfollowedType}
labelStyle={labelStyle}
onPress={onPress}
label={following ? 'Unfollow' : 'Follow'}
withLoading={true}
{...rest}
/>
)
})
57 changes: 20 additions & 37 deletions src/view/com/profile/ProfileHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import {makeProfileLink} from 'lib/routes/links'
import {Link} from '../util/Link'
import {ProfileHeaderSuggestedFollows} from './ProfileHeaderSuggestedFollows'
import {logger} from '#/logger'
import {FollowButton} from './FollowButton'

interface Props {
view: ProfileModel
Expand Down Expand Up @@ -111,7 +112,6 @@ const ProfileHeaderLoaded = observer(function ProfileHeaderLoadedImpl({
isProfilePreview,
}: Props) {
const pal = usePalette('default')
const palInverted = usePalette('inverted')
const store = useStores()
const navigation = useNavigation<NavigationProp>()
const {track} = useAnalytics()
Expand Down Expand Up @@ -355,6 +355,8 @@ const ProfileHeaderLoaded = observer(function ProfileHeaderLoadedImpl({
const following = formatCount(view.followsCount)
const followers = formatCount(view.followersCount)
const pluralizedFollowers = pluralize(view.followersCount, 'follower')
const isFollowing =
store.me.follows.getFollowState(view.did) === FollowState.Following

return (
<View style={pal.view}>
Expand Down Expand Up @@ -413,7 +415,7 @@ const ProfileHeaderLoaded = observer(function ProfileHeaderLoadedImpl({
pal.text,
{
color: showSuggestedFollows
? colors.white
? pal.textInverted.color
: pal.text.color,
},
]}
Expand All @@ -422,41 +424,22 @@ const ProfileHeaderLoaded = observer(function ProfileHeaderLoadedImpl({
</TouchableOpacity>
)}

{store.me.follows.getFollowState(view.did) ===
FollowState.Following ? (
<TouchableOpacity
testID="unfollowBtn"
onPress={onPressToggleFollow}
style={[styles.btn, styles.mainBtn, pal.btn]}
accessibilityRole="button"
accessibilityLabel={`Unfollow ${view.handle}`}
accessibilityHint={`Hides posts from ${view.handle} in your feed`}>
<FontAwesomeIcon
icon="check"
style={[pal.text, s.mr5]}
size={14}
/>
<Text type="button" style={pal.text}>
Following
</Text>
</TouchableOpacity>
) : (
<TouchableOpacity
testID="followBtn"
onPress={onPressToggleFollow}
style={[styles.btn, styles.mainBtn, palInverted.view]}
accessibilityRole="button"
accessibilityLabel={`Follow ${view.handle}`}
accessibilityHint={`Shows posts from ${view.handle} in your feed`}>
<FontAwesomeIcon
icon="plus"
style={[palInverted.text, s.mr5]}
/>
<Text type="button" style={[palInverted.text, s.bold]}>
Follow
</Text>
</TouchableOpacity>
)}
<FollowButton
style={styles.btn}
testID={isFollowing ? 'unfollowBtn' : 'followBtn'}
unfollowedType="inverted"
profile={view}
accessibilityHint={
isFollowing
? `Hides posts from ${view.handle} in your feed`
: `Shows posts from ${view.handle} in your feed`
}
accessibilityLabel={`${isFollowing ? 'Unfollow' : 'Follow'} ${
view.handle
}`}
onToggleFollow={onPressToggleFollow}
followedType="default"
/>
</>
) : null}
{dropdownItems?.length ? (
Expand Down
27 changes: 22 additions & 5 deletions src/view/com/util/forms/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
import {Text} from '../text/Text'
import {useTheme} from 'lib/ThemeContext'
import {choose} from 'lib/functions'
import {s} from '#/lib/styles'

type Event =
| React.MouseEvent<HTMLAnchorElement, MouseEvent>
Expand Down Expand Up @@ -42,6 +43,8 @@ export function Button({
type = 'primary',
label,
style,
StartIcon,
EndIcon,
labelContainerStyle,
labelStyle,
onPress,
Expand All @@ -56,6 +59,8 @@ export function Button({
type?: ButtonType
label?: string
style?: StyleProp<ViewStyle>
StartIcon?: React.ReactElement
EndIcon?: React.ReactElement
labelContainerStyle?: StyleProp<ViewStyle>
labelStyle?: StyleProp<TextStyle>
onPress?: () => void | Promise<void>
Expand Down Expand Up @@ -169,29 +174,40 @@ export function Button({
[typeOuterStyle, style],
)

const renderChildern = React.useCallback(() => {
const renderChildren = React.useCallback(() => {
if (!label) {
return children
}

return (
<View style={[styles.labelContainer, labelContainerStyle]}>
{React.isValidElement(StartIcon) && !isLoading ? StartIcon : null}

{label && withLoading && isLoading ? (
<ActivityIndicator size={12} color={typeLabelStyle.color} />
<ActivityIndicator
style={s.mr2}
size={12}
color={typeLabelStyle.color}
/>
) : null}

<Text type="button" style={[typeLabelStyle, labelStyle]}>
{label}
</Text>

{React.isValidElement(EndIcon) && !isLoading && EndIcon}
</View>
)
}, [
children,
label,
labelContainerStyle,
StartIcon,
withLoading,
isLoading,
labelContainerStyle,
typeLabelStyle,
labelStyle,
EndIcon,
children,
])

return (
Expand All @@ -205,7 +221,7 @@ export function Button({
accessibilityHint={accessibilityHint}
accessibilityLabelledBy={accessibilityLabelledBy}
onAccessibilityEscape={onAccessibilityEscape}>
{renderChildern}
{renderChildren}
</Pressable>
)
}
Expand All @@ -217,6 +233,7 @@ const styles = StyleSheet.create({
borderRadius: 24,
},
labelContainer: {
alignItems: 'center',
flexDirection: 'row',
gap: 8,
},
Expand Down
Loading