Onboarding tweaks (#272)

* Small fix to side menu rendering

* Change onboarding to use an explicit 'is onboarding' mode to more clearly control the flow

* Add a progress bar to the welcome banner

* Dont show the 'unfollow button' on posts in weird times (close #271)

* Improve the empty state of the feed

* Only suggest recent posts
This commit is contained in:
Paul Frazee 2023-03-06 15:34:22 -06:00 committed by GitHub
parent 74c30c60b8
commit 36791e68b3
13 changed files with 259 additions and 123 deletions

View file

@ -24,20 +24,18 @@ export const PostMeta = observer(function (opts: PostMetaOpts) {
let handle = opts.authorHandle
const store = useStores()
const isMe = opts.did === store.me.did
const isFollowing =
typeof opts.did === 'string' && store.me.follows.isFollowing(opts.did)
// NOTE we capture `isFollowing` via a memo so that follows
// don't change this UI immediately, but rather upon future
// renders
const isFollowing = React.useMemo(
() =>
typeof opts.did === 'string' && store.me.follows.isFollowing(opts.did),
[opts.did, store.me.follows],
)
const [didFollow, setDidFollow] = React.useState(false)
const onToggleFollow = React.useCallback(() => {
setDidFollow(true)
}, [setDidFollow])
if (
opts.showFollowBtn &&
!isMe &&
!isFollowing &&
(!isFollowing || didFollow) &&
opts.did &&
opts.declarationCid
) {
@ -71,7 +69,11 @@ export const PostMeta = observer(function (opts: PostMetaOpts) {
</View>
<View>
<FollowButton did={opts.did} declarationCid={opts.declarationCid} />
<FollowButton
did={opts.did}
declarationCid={opts.declarationCid}
onToggleFollow={onToggleFollow}
/>
</View>
</View>
)

View file

@ -1,11 +1,43 @@
import React from 'react'
import {StyleSheet, View} from 'react-native'
import {observer} from 'mobx-react-lite'
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
import {usePalette} from 'lib/hooks/usePalette'
import {Text} from './text/Text'
import {Button} from './forms/Button'
import {s} from 'lib/styles'
import {useStores} from 'state/index'
import {SUGGESTED_FOLLOWS} from 'lib/constants'
// @ts-ignore no type definition -prf
import ProgressBar from 'react-native-progress/Bar'
export function WelcomeBanner() {
export const WelcomeBanner = observer(() => {
const pal = usePalette('default')
const store = useStores()
const [isReady, setIsReady] = React.useState(false)
const numFollows = Math.min(
SUGGESTED_FOLLOWS(String(store.agent.service)).length,
5,
)
const remaining = numFollows - store.me.follows.numFollows
React.useEffect(() => {
if (remaining <= 0) {
// wait 500ms for the progress bar anim to finish
const ti = setTimeout(() => {
setIsReady(true)
}, 500)
return () => clearTimeout(ti)
} else {
setIsReady(false)
}
}, [remaining])
const onPressDone = React.useCallback(() => {
store.shell.setOnboarding(false)
}, [store])
return (
<View
testID="welcomeBanner"
@ -16,18 +48,53 @@ export function WelcomeBanner() {
lineHeight={1.1}>
Welcome to the private beta!
</Text>
<Text type="lg" style={[pal.text, s.textCenter]}>
Here are some recent posts. Follow their creators to build your feed.
</Text>
{isReady ? (
<View style={styles.controls}>
<Button
type="primary"
style={[s.flexRow, s.alignCenter]}
onPress={onPressDone}>
<Text type="md-bold" style={s.white}>
See my feed!
</Text>
<FontAwesomeIcon icon="angle-right" size={14} style={s.white} />
</Button>
</View>
) : (
<>
<Text type="lg" style={[pal.text, s.textCenter]}>
Follow at least {remaining} {remaining === 1 ? 'person' : 'people'}{' '}
to build your feed.
</Text>
<View style={[styles.controls, styles.progress]}>
<ProgressBar
progress={Math.max(
store.me.follows.numFollows / numFollows,
0.05,
)}
/>
</View>
</>
)}
</View>
)
}
})
const styles = StyleSheet.create({
container: {
paddingTop: 30,
paddingBottom: 26,
paddingTop: 16,
paddingBottom: 16,
paddingHorizontal: 20,
borderTopWidth: 1,
borderBottomWidth: 1,
},
controls: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
marginTop: 10,
},
progress: {
marginTop: 12,
},
})

View file

@ -13,6 +13,7 @@ import {choose} from 'lib/functions'
export type ButtonType =
| 'primary'
| 'secondary'
| 'default'
| 'inverted'
| 'primary-outline'
| 'secondary-outline'
@ -40,6 +41,9 @@ export function Button({
secondary: {
backgroundColor: theme.palette.secondary.background,
},
default: {
backgroundColor: theme.palette.default.backgroundLight,
},
inverted: {
backgroundColor: theme.palette.inverted.background,
},
@ -66,15 +70,18 @@ export function Button({
const labelStyle = choose<TextStyle, Record<ButtonType, TextStyle>>(type, {
primary: {
color: theme.palette.primary.text,
fontWeight: theme.palette.primary.isLowContrast ? '500' : undefined,
fontWeight: '600',
},
secondary: {
color: theme.palette.secondary.text,
fontWeight: theme.palette.secondary.isLowContrast ? '500' : undefined,
},
default: {
color: theme.palette.default.text,
},
inverted: {
color: theme.palette.inverted.text,
fontWeight: theme.palette.inverted.isLowContrast ? '500' : undefined,
fontWeight: '600',
},
'primary-outline': {
color: theme.palette.primary.textInverted,
@ -114,7 +121,8 @@ export function Button({
const styles = StyleSheet.create({
outer: {
paddingHorizontal: 10,
paddingHorizontal: 14,
paddingVertical: 8,
borderRadius: 24,
},
})