* Base work for public view

* Make default moderation settings more restrictive

* Fix type

* Handle showing sign-in on authed actions

* Fix hoc logic

* Simplify prefs logic

* Remove duplicate method

* Add todo

* Clean up RepostButton.web

* Fix x button color

* Add todo

* Retain existing label prefs for now, use separate logged out settings

* Clean up useAuthedMethod, rename to useRequireAuth

* Add todos

* Move dismiss logic to withAuthRequired

* Ooops add web

* Block public view in prod

* Add todo

* Fix bad import
This commit is contained in:
Eric Bailey 2023-11-21 10:57:34 -06:00 committed by GitHub
parent 71b59021b9
commit f18b9b32b0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
25 changed files with 1026 additions and 755 deletions

View file

@ -15,7 +15,7 @@ enum ScreenState {
S_CreateAccount,
}
export function LoggedOut() {
export function LoggedOut({onDismiss}: {onDismiss?: () => void}) {
const pal = usePalette('default')
const setMinimalShellMode = useSetMinimalShellMode()
const {screen} = useAnalytics()
@ -31,6 +31,7 @@ export function LoggedOut() {
if (screenState === ScreenState.S_LoginOrCreateAccount) {
return (
<SplashScreen
onDismiss={onDismiss}
onPressSignin={() => setScreenState(ScreenState.S_Login)}
onPressCreateAccount={() => setScreenState(ScreenState.S_CreateAccount)}
/>

View file

@ -1,5 +1,12 @@
import React from 'react'
import {SafeAreaView, StyleSheet, TouchableOpacity, View} from 'react-native'
import {
SafeAreaView,
StyleSheet,
TouchableOpacity,
Pressable,
View,
} from 'react-native'
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
import {Text} from 'view/com/util/text/Text'
import {ErrorBoundary} from 'view/com/util/ErrorBoundary'
import {s, colors} from 'lib/styles'
@ -9,9 +16,11 @@ import {Trans, msg} from '@lingui/macro'
import {useLingui} from '@lingui/react'
export const SplashScreen = ({
onDismiss,
onPressSignin,
onPressCreateAccount,
}: {
onDismiss?: () => void
onPressSignin: () => void
onPressCreateAccount: () => void
}) => {
@ -20,6 +29,27 @@ export const SplashScreen = ({
return (
<CenteredView style={[styles.container, pal.view]}>
{onDismiss && (
<Pressable
accessibilityRole="button"
style={{
position: 'absolute',
top: 20,
right: 20,
padding: 20,
zIndex: 100,
}}
onPress={onDismiss}>
<FontAwesomeIcon
icon="x"
size={24}
style={{
color: String(pal.text.color),
}}
/>
</Pressable>
)}
<SafeAreaView testID="noSessionView" style={styles.container}>
<ErrorBoundary>
<View style={styles.hero}>

View file

@ -1,5 +1,6 @@
import React from 'react'
import {StyleSheet, TouchableOpacity, View} from 'react-native'
import {StyleSheet, TouchableOpacity, View, Pressable} from 'react-native'
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
import {Text} from 'view/com/util/text/Text'
import {TextLink} from '../util/Link'
import {ErrorBoundary} from 'view/com/util/ErrorBoundary'
@ -11,9 +12,11 @@ import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
import {Trans} from '@lingui/macro'
export const SplashScreen = ({
onDismiss,
onPressSignin,
onPressCreateAccount,
}: {
onDismiss?: () => void
onPressSignin: () => void
onPressCreateAccount: () => void
}) => {
@ -23,47 +26,70 @@ export const SplashScreen = ({
const isMobileWeb = isWeb && isTabletOrMobile
return (
<CenteredView style={[styles.container, pal.view]}>
<View
testID="noSessionView"
style={[
styles.containerInner,
isMobileWeb && styles.containerInnerMobile,
pal.border,
]}>
<ErrorBoundary>
<Text style={isMobileWeb ? styles.titleMobile : styles.title}>
Bluesky
</Text>
<Text style={isMobileWeb ? styles.subtitleMobile : styles.subtitle}>
See what's next
</Text>
<View testID="signinOrCreateAccount" style={styles.btns}>
<TouchableOpacity
testID="createAccountButton"
style={[styles.btn, {backgroundColor: colors.blue3}]}
onPress={onPressCreateAccount}
// TODO: web accessibility
accessibilityRole="button">
<Text style={[s.white, styles.btnLabel]}>
Create a new account
</Text>
</TouchableOpacity>
<TouchableOpacity
testID="signInButton"
style={[styles.btn, pal.btn]}
onPress={onPressSignin}
// TODO: web accessibility
accessibilityRole="button">
<Text style={[pal.text, styles.btnLabel]}>
<Trans>Sign In</Trans>
</Text>
</TouchableOpacity>
</View>
</ErrorBoundary>
</View>
<Footer styles={styles} />
</CenteredView>
<>
{onDismiss && (
<Pressable
accessibilityRole="button"
style={{
position: 'absolute',
top: 20,
right: 20,
padding: 20,
zIndex: 100,
}}
onPress={onDismiss}>
<FontAwesomeIcon
icon="x"
size={24}
style={{
color: String(pal.text.color),
}}
/>
</Pressable>
)}
<CenteredView style={[styles.container, pal.view]}>
<View
testID="noSessionView"
style={[
styles.containerInner,
isMobileWeb && styles.containerInnerMobile,
pal.border,
]}>
<ErrorBoundary>
<Text style={isMobileWeb ? styles.titleMobile : styles.title}>
Bluesky
</Text>
<Text style={isMobileWeb ? styles.subtitleMobile : styles.subtitle}>
See what's next
</Text>
<View testID="signinOrCreateAccount" style={styles.btns}>
<TouchableOpacity
testID="createAccountButton"
style={[styles.btn, {backgroundColor: colors.blue3}]}
onPress={onPressCreateAccount}
// TODO: web accessibility
accessibilityRole="button">
<Text style={[s.white, styles.btnLabel]}>
Create a new account
</Text>
</TouchableOpacity>
<TouchableOpacity
testID="signInButton"
style={[styles.btn, pal.btn]}
onPress={onPressSignin}
// TODO: web accessibility
accessibilityRole="button">
<Text style={[pal.text, styles.btnLabel]}>
<Trans>Sign In</Trans>
</Text>
</TouchableOpacity>
</View>
</ErrorBoundary>
</View>
<Footer styles={styles} />
</CenteredView>
</>
)
}

View file

@ -13,18 +13,33 @@ import {usePalette} from 'lib/hooks/usePalette'
import {STATUS_PAGE_URL} from 'lib/constants'
import {useOnboardingState} from '#/state/shell'
import {useSession} from '#/state/session'
import {
useLoggedOutView,
useLoggedOutViewControls,
} from '#/state/shell/logged-out'
import {IS_PROD} from '#/env'
export const withAuthRequired = <P extends object>(
Component: React.ComponentType<P>,
options: {
isPublic?: boolean // TODO(pwi) need to enable in TF somehow
} = {},
): React.FC<P> =>
function AuthRequired(props: P) {
const {isInitialLoad, hasSession} = useSession()
const onboardingState = useOnboardingState()
const {showLoggedOut} = useLoggedOutView()
const {setShowLoggedOut} = useLoggedOutViewControls()
if (isInitialLoad) {
return <Loading />
}
if (!hasSession) {
return <LoggedOut />
if (showLoggedOut) {
return <LoggedOut onDismiss={() => setShowLoggedOut(false)} />
} else if (!options?.isPublic || IS_PROD) {
return <LoggedOut />
}
}
if (onboardingState.isActive) {
return <Onboarding />

View file

@ -25,6 +25,7 @@ import {
} from '#/state/queries/post'
import {useComposerControls} from '#/state/shell/composer'
import {Shadow} from '#/state/cache/types'
import {useRequireAuth} from '#/state/session'
export function PostCtrls({
big,
@ -46,6 +47,7 @@ export function PostCtrls({
const postUnlikeMutation = usePostUnlikeMutation()
const postRepostMutation = usePostRepostMutation()
const postUnrepostMutation = usePostUnrepostMutation()
const requireAuth = useRequireAuth()
const defaultCtrlColor = React.useMemo(
() => ({
@ -107,7 +109,9 @@ export function PostCtrls({
<TouchableOpacity
testID="replyBtn"
style={[styles.ctrl, !big && styles.ctrlPad, {paddingLeft: 0}]}
onPress={onPressReply}
onPress={() => {
requireAuth(() => onPressReply())
}}
accessibilityRole="button"
accessibilityLabel={`Reply (${post.replyCount} ${
post.replyCount === 1 ? 'reply' : 'replies'
@ -135,7 +139,9 @@ export function PostCtrls({
<TouchableOpacity
testID="likeBtn"
style={[styles.ctrl, !big && styles.ctrlPad]}
onPress={onPressToggleLike}
onPress={() => {
requireAuth(() => onPressToggleLike())
}}
accessibilityRole="button"
accessibilityLabel={`${post.viewer?.like ? 'Unlike' : 'Like'} (${
post.likeCount

View file

@ -7,6 +7,7 @@ import {Text} from '../text/Text'
import {pluralize} from 'lib/strings/helpers'
import {HITSLOP_10, HITSLOP_20} from 'lib/constants'
import {useModalControls} from '#/state/modals'
import {useRequireAuth} from '#/state/session'
interface Props {
isReposted: boolean
@ -25,6 +26,7 @@ export const RepostButton = ({
}: Props) => {
const theme = useTheme()
const {openModal} = useModalControls()
const requireAuth = useRequireAuth()
const defaultControlColor = React.useMemo(
() => ({
@ -45,7 +47,9 @@ export const RepostButton = ({
return (
<TouchableOpacity
testID="repostBtn"
onPress={onPressToggleRepostWrapper}
onPress={() => {
requireAuth(() => onPressToggleRepostWrapper())
}}
style={[styles.control, !big && styles.controlPad]}
accessibilityRole="button"
accessibilityLabel={`${

View file

@ -1,5 +1,5 @@
import React from 'react'
import {StyleProp, StyleSheet, View, ViewStyle} from 'react-native'
import {StyleProp, StyleSheet, View, ViewStyle, Pressable} from 'react-native'
import {RepostIcon} from 'lib/icons'
import {colors} from 'lib/styles'
import {useTheme} from 'lib/ThemeContext'
@ -12,6 +12,8 @@ import {
import {EventStopper} from '../EventStopper'
import {useLingui} from '@lingui/react'
import {msg} from '@lingui/macro'
import {useRequireAuth} from '#/state/session'
import {useSession} from '#/state/session'
interface Props {
isReposted: boolean
@ -31,6 +33,8 @@ export const RepostButton = ({
}: Props) => {
const theme = useTheme()
const {_} = useLingui()
const {hasSession} = useSession()
const requireAuth = useRequireAuth()
const defaultControlColor = React.useMemo(
() => ({
@ -62,32 +66,46 @@ export const RepostButton = ({
},
]
return (
const inner = (
<View
style={[
styles.control,
!big && styles.controlPad,
(isReposted
? styles.reposted
: defaultControlColor) as StyleProp<ViewStyle>,
]}>
<RepostIcon strokeWidth={2.2} size={big ? 24 : 20} />
{typeof repostCount !== 'undefined' ? (
<Text
testID="repostCount"
type={isReposted ? 'md-bold' : 'md'}
style={styles.repostCount}>
{repostCount ?? 0}
</Text>
) : undefined}
</View>
)
return hasSession ? (
<EventStopper>
<NativeDropdown
items={dropdownItems}
accessibilityLabel={_(msg`Repost or quote post`)}
accessibilityHint="">
<View
style={[
styles.control,
!big && styles.controlPad,
(isReposted
? styles.reposted
: defaultControlColor) as StyleProp<ViewStyle>,
]}>
<RepostIcon strokeWidth={2.2} size={big ? 24 : 20} />
{typeof repostCount !== 'undefined' ? (
<Text
testID="repostCount"
type={isReposted ? 'md-bold' : 'md'}
style={styles.repostCount}>
{repostCount ?? 0}
</Text>
) : undefined}
</View>
{inner}
</NativeDropdown>
</EventStopper>
) : (
<Pressable
accessibilityRole="button"
onPress={() => {
requireAuth(() => {})
}}
accessibilityLabel={_(msg`Repost or quote post`)}
accessibilityHint="">
{inner}
</Pressable>
)
}