Create codemod for addressing ESLint warnings (#10032)
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import React from 'react'
|
||||
import {useCallback, useState} from 'react'
|
||||
import {View} from 'react-native'
|
||||
import {useSafeAreaInsets} from 'react-native-safe-area-context'
|
||||
import {msg} from '@lingui/core/macro'
|
||||
@@ -38,11 +38,11 @@ export function Deactivated() {
|
||||
const hasOtherAccounts = accounts.length > 1
|
||||
const {logoutCurrentAccount} = useSessionApi()
|
||||
const agent = useAgent()
|
||||
const [pending, setPending] = React.useState(false)
|
||||
const [error, setError] = React.useState<string | undefined>()
|
||||
const [pending, setPending] = useState(false)
|
||||
const [error, setError] = useState<string | undefined>()
|
||||
const queryClient = useQueryClient()
|
||||
|
||||
const onSelectAccount = React.useCallback(
|
||||
const onSelectAccount = useCallback(
|
||||
(account: SessionAccount) => {
|
||||
if (account.did !== currentAccount?.did) {
|
||||
onPressSwitchAccount(account, 'SwitchAccount')
|
||||
@@ -51,11 +51,11 @@ export function Deactivated() {
|
||||
[currentAccount, onPressSwitchAccount],
|
||||
)
|
||||
|
||||
const onPressAddAccount = React.useCallback(() => {
|
||||
const onPressAddAccount = useCallback(() => {
|
||||
setShowLoggedOut(true)
|
||||
}, [setShowLoggedOut])
|
||||
|
||||
const onPressLogout = React.useCallback(() => {
|
||||
const onPressLogout = useCallback(() => {
|
||||
if (IS_WEB) {
|
||||
// We're switching accounts, which remounts the entire app.
|
||||
// On mobile, this gets us Home, but on the web we also need reset the URL.
|
||||
@@ -67,7 +67,7 @@ export function Deactivated() {
|
||||
logoutCurrentAccount('Deactivated')
|
||||
}, [logoutCurrentAccount])
|
||||
|
||||
const handleActivate = React.useCallback(async () => {
|
||||
const handleActivate = useCallback(async () => {
|
||||
try {
|
||||
setPending(true)
|
||||
await agent.com.atproto.server.activateAccount()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React from 'react'
|
||||
import {useState} from 'react'
|
||||
import {View} from 'react-native'
|
||||
|
||||
import {ScrollView} from '#/view/com/util/Views'
|
||||
@@ -9,7 +9,7 @@ import {Text} from '#/components/Typography'
|
||||
import {SharedPrefs} from '../../../modules/expo-bluesky-swiss-army'
|
||||
|
||||
export function SharedPreferencesTesterScreen() {
|
||||
const [currentTestOutput, setCurrentTestOutput] = React.useState<string>('')
|
||||
const [currentTestOutput, setCurrentTestOutput] = useState<string>('')
|
||||
|
||||
return (
|
||||
<Layout.Screen>
|
||||
|
||||
+15
-15
@@ -1,4 +1,4 @@
|
||||
import React from 'react'
|
||||
import {useCallback, useMemo, useState} from 'react'
|
||||
import {type ListRenderItemInfo, View} from 'react-native'
|
||||
import {type AppBskyFeedDefs} from '@atproto/api'
|
||||
import {msg} from '@lingui/core/macro'
|
||||
@@ -47,29 +47,29 @@ export default function HashtagScreen({
|
||||
const {tag, author} = route.params
|
||||
const {_} = useLingui()
|
||||
|
||||
const decodedTag = React.useMemo(() => {
|
||||
const decodedTag = useMemo(() => {
|
||||
return decodeURIComponent(tag)
|
||||
}, [tag])
|
||||
|
||||
const isCashtag = decodedTag.startsWith('$')
|
||||
|
||||
const fullTag = React.useMemo(() => {
|
||||
const fullTag = useMemo(() => {
|
||||
// Cashtags already include the $ prefix, hashtags need # added
|
||||
return isCashtag ? decodedTag : `#${decodedTag}`
|
||||
}, [decodedTag, isCashtag])
|
||||
|
||||
const headerTitle = React.useMemo(() => {
|
||||
const headerTitle = useMemo(() => {
|
||||
// Keep cashtags uppercase, lowercase hashtags
|
||||
const displayTag = isCashtag ? fullTag.toUpperCase() : fullTag.toLowerCase()
|
||||
return enforceLen(displayTag, 24, true, 'middle')
|
||||
}, [fullTag, isCashtag])
|
||||
|
||||
const sanitizedAuthor = React.useMemo(() => {
|
||||
const sanitizedAuthor = useMemo(() => {
|
||||
if (!author) return ''
|
||||
return sanitizeHandle(author)
|
||||
}, [author])
|
||||
|
||||
const onShare = React.useCallback(() => {
|
||||
const onShare = useCallback(() => {
|
||||
const url = new URL('https://bsky.app')
|
||||
url.pathname = `/hashtag/${decodeURIComponent(tag)}`
|
||||
if (author) {
|
||||
@@ -78,16 +78,16 @@ export default function HashtagScreen({
|
||||
shareUrl(url.toString())
|
||||
}, [tag, author])
|
||||
|
||||
const [activeTab, setActiveTab] = React.useState(0)
|
||||
const [activeTab, setActiveTab] = useState(0)
|
||||
const setMinimalShellMode = useSetMinimalShellMode()
|
||||
|
||||
useFocusEffect(
|
||||
React.useCallback(() => {
|
||||
useCallback(() => {
|
||||
setMinimalShellMode(false)
|
||||
}, [setMinimalShellMode]),
|
||||
)
|
||||
|
||||
const onPageSelected = React.useCallback(
|
||||
const onPageSelected = useCallback(
|
||||
(index: number) => {
|
||||
setMinimalShellMode(false)
|
||||
setActiveTab(index)
|
||||
@@ -95,7 +95,7 @@ export default function HashtagScreen({
|
||||
[setMinimalShellMode],
|
||||
)
|
||||
|
||||
const sections = React.useMemo(() => {
|
||||
const sections = useMemo(() => {
|
||||
return [
|
||||
{
|
||||
title: _(msg`Top`),
|
||||
@@ -177,14 +177,14 @@ function HashtagScreenTab({
|
||||
}) {
|
||||
const {_} = useLingui()
|
||||
const initialNumToRender = useInitialNumToRender()
|
||||
const [isPTR, setIsPTR] = React.useState(false)
|
||||
const [isPTR, setIsPTR] = useState(false)
|
||||
const t = useTheme()
|
||||
const {hasSession} = useSession()
|
||||
const trackPostView = usePostViewTracking('Hashtag')
|
||||
|
||||
const isCashtag = fullTag.startsWith('$')
|
||||
|
||||
const queryParam = React.useMemo(() => {
|
||||
const queryParam = useMemo(() => {
|
||||
// Cashtags need # prefix for search: "#$BTC" or "#$BTC from:author"
|
||||
const searchTag = isCashtag ? `#${fullTag}` : fullTag
|
||||
if (!author) return searchTag
|
||||
@@ -203,17 +203,17 @@ function HashtagScreenTab({
|
||||
hasNextPage,
|
||||
} = useSearchPostsQuery({query: queryParam, sort, enabled: active})
|
||||
|
||||
const posts = React.useMemo(() => {
|
||||
const posts = useMemo(() => {
|
||||
return data?.pages.flatMap(page => page.posts) || []
|
||||
}, [data])
|
||||
|
||||
const onRefresh = React.useCallback(async () => {
|
||||
const onRefresh = useCallback(async () => {
|
||||
setIsPTR(true)
|
||||
await refetch()
|
||||
setIsPTR(false)
|
||||
}, [refetch])
|
||||
|
||||
const onEndReached = React.useCallback(() => {
|
||||
const onEndReached = useCallback(() => {
|
||||
if (isFetchingNextPage || !hasNextPage || error) return
|
||||
fetchNextPage()
|
||||
}, [isFetchingNextPage, hasNextPage, error, fetchNextPage])
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React from 'react'
|
||||
import {useCallback} from 'react'
|
||||
import {View} from 'react-native'
|
||||
import {TID} from '@atproto/common-web'
|
||||
import {msg} from '@lingui/core/macro'
|
||||
@@ -27,7 +27,7 @@ export function NoFeedsPinned({
|
||||
const {isPending, mutateAsync: overwriteSavedFeeds} =
|
||||
useOverwriteSavedFeedsMutation()
|
||||
|
||||
const addRecommendedFeeds = React.useCallback(async () => {
|
||||
const addRecommendedFeeds = useCallback(async () => {
|
||||
let skippedTimeline = false
|
||||
let skippedDiscover = false
|
||||
let remainingSavedFeeds = []
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React from 'react'
|
||||
import {useState} from 'react'
|
||||
import {View} from 'react-native'
|
||||
import {AppBskyGraphDefs} from '@atproto/api'
|
||||
import {msg} from '@lingui/core/macro'
|
||||
@@ -45,7 +45,7 @@ export function ListHiddenScreen({
|
||||
|
||||
const isModList = list.purpose === AppBskyGraphDefs.MODLIST
|
||||
|
||||
const [isProcessing, setIsProcessing] = React.useState(false)
|
||||
const [isProcessing, setIsProcessing] = useState(false)
|
||||
const listBlockMutation = useListBlockMutation()
|
||||
const listMuteMutation = useListMuteMutation()
|
||||
const {mutateAsync: removeSavedFeed} = useRemoveFeedMutation()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, {useState} from 'react'
|
||||
import {useCallback, useState} from 'react'
|
||||
import {Keyboard, View} from 'react-native'
|
||||
import {type ComAtprotoServerDescribeServer} from '@atproto/api'
|
||||
import {msg} from '@lingui/core/macro'
|
||||
@@ -44,7 +44,7 @@ export const ForgotPasswordForm = ({
|
||||
const [email, setEmail] = useState<string>('')
|
||||
const {_} = useLingui()
|
||||
|
||||
const onPressSelectService = React.useCallback(() => {
|
||||
const onPressSelectService = useCallback(() => {
|
||||
Keyboard.dismiss()
|
||||
}, [])
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import {type StyleProp, View, type ViewStyle} from 'react-native'
|
||||
import type React from 'react'
|
||||
|
||||
import {atoms as a, useBreakpoints, useGutters} from '#/alf'
|
||||
import {Text} from '#/components/Typography'
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, {useCallback, useEffect} from 'react'
|
||||
import {useCallback, useEffect, useMemo, useState} from 'react'
|
||||
import {View} from 'react-native'
|
||||
import {
|
||||
type AppBskyActorDefs,
|
||||
@@ -105,7 +105,7 @@ function Inner() {
|
||||
})
|
||||
const recipient = useMaybeProfileShadow(recipientUnshadowed)
|
||||
|
||||
const moderation = React.useMemo(() => {
|
||||
const moderation = useMemo(() => {
|
||||
if (!recipient || !moderationOpts) return null
|
||||
return moderateProfile(recipient, moderationOpts)
|
||||
}, [recipient, moderationOpts])
|
||||
@@ -113,7 +113,7 @@ function Inner() {
|
||||
// Because we want to give the list a chance to asynchronously scroll to the end before it is visible to the user,
|
||||
// we use `hasScrolled` to determine when to render. With that said however, there is a chance that the chat will be
|
||||
// empty. So, we also check for that possible state as well and render once we can.
|
||||
const [hasScrolled, setHasScrolled] = React.useState(false)
|
||||
const [hasScrolled, setHasScrolled] = useState(false)
|
||||
const readyToShow =
|
||||
hasScrolled ||
|
||||
(isConvoActive(convoState) &&
|
||||
@@ -122,7 +122,7 @@ function Inner() {
|
||||
|
||||
// Any time that we re-render the `Initializing` state, we have to reset `hasScrolled` to false. After entering this
|
||||
// state, we know that we're resetting the list of messages and need to re-scroll to the bottom when they get added.
|
||||
React.useEffect(() => {
|
||||
useEffect(() => {
|
||||
if (convoState.status === ConvoStatus.Initializing) {
|
||||
setHasScrolled(false)
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, {useCallback, useMemo, useState} from 'react'
|
||||
import {memo, useCallback, useMemo, useState} from 'react'
|
||||
import {type GestureResponderEvent, View} from 'react-native'
|
||||
import {
|
||||
AppBskyEmbedRecord,
|
||||
@@ -80,7 +80,7 @@ export let ChatListItem = ({
|
||||
)
|
||||
}
|
||||
|
||||
ChatListItem = React.memo(ChatListItem)
|
||||
ChatListItem = memo(ChatListItem)
|
||||
|
||||
function ChatListItemReady({
|
||||
convo,
|
||||
@@ -104,7 +104,7 @@ function ChatListItemReady({
|
||||
const {gtMobile} = useBreakpoints()
|
||||
const profile = useProfileShadow(profileUnshadowed)
|
||||
const {mutate: markAsRead} = useMarkAsReadMutation()
|
||||
const moderation = React.useMemo(
|
||||
const moderation = useMemo(
|
||||
() => moderateProfile(profile, moderationOpts),
|
||||
[profile, moderationOpts],
|
||||
)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React from 'react'
|
||||
import {useCallback, useEffect, useRef, useState} from 'react'
|
||||
import {Pressable, View} from 'react-native'
|
||||
import {msg} from '@lingui/core/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
@@ -43,16 +43,16 @@ export function MessageInput({
|
||||
const {_} = useLingui()
|
||||
const t = useTheme()
|
||||
const {getDraft, clearDraft} = useMessageDraft()
|
||||
const [message, setMessage] = React.useState(getDraft)
|
||||
const [message, setMessage] = useState(getDraft)
|
||||
|
||||
const inputStyles = useSharedInputStyles()
|
||||
const isComposing = React.useRef(false)
|
||||
const [isFocused, setIsFocused] = React.useState(false)
|
||||
const [isHovered, setIsHovered] = React.useState(false)
|
||||
const [textAreaHeight, setTextAreaHeight] = React.useState(38)
|
||||
const textAreaRef = React.useRef<HTMLTextAreaElement>(null)
|
||||
const isComposing = useRef(false)
|
||||
const [isFocused, setIsFocused] = useState(false)
|
||||
const [isHovered, setIsHovered] = useState(false)
|
||||
const [textAreaHeight, setTextAreaHeight] = useState(38)
|
||||
const textAreaRef = useRef<HTMLTextAreaElement>(null)
|
||||
|
||||
const onSubmit = React.useCallback(() => {
|
||||
const onSubmit = useCallback(() => {
|
||||
if (!hasEmbed && message.trim() === '') {
|
||||
return
|
||||
}
|
||||
@@ -66,7 +66,7 @@ export function MessageInput({
|
||||
setEmbed(undefined)
|
||||
}, [message, onSendMessage, _, clearDraft, hasEmbed, setEmbed])
|
||||
|
||||
const onKeyDown = React.useCallback(
|
||||
const onKeyDown = useCallback(
|
||||
(e: React.KeyboardEvent<HTMLTextAreaElement>) => {
|
||||
// Don't submit the form when the Japanese or any other IME is composing
|
||||
if (isComposing.current) return
|
||||
@@ -98,14 +98,11 @@ export function MessageInput({
|
||||
[onSubmit],
|
||||
)
|
||||
|
||||
const onChange = React.useCallback(
|
||||
(e: React.ChangeEvent<HTMLTextAreaElement>) => {
|
||||
setMessage(e.target.value)
|
||||
},
|
||||
[],
|
||||
)
|
||||
const onChange = useCallback((e: React.ChangeEvent<HTMLTextAreaElement>) => {
|
||||
setMessage(e.target.value)
|
||||
}, [])
|
||||
|
||||
const onEmojiInserted = React.useCallback(
|
||||
const onEmojiInserted = useCallback(
|
||||
(emoji: Emoji) => {
|
||||
if (!textAreaRef.current) {
|
||||
return
|
||||
@@ -123,7 +120,7 @@ export function MessageInput({
|
||||
},
|
||||
[setMessage],
|
||||
)
|
||||
React.useEffect(() => {
|
||||
useEffect(() => {
|
||||
textInputWebEmitter.addListener('emoji-inserted', onEmojiInserted)
|
||||
return () => {
|
||||
textInputWebEmitter.removeListener('emoji-inserted', onEmojiInserted)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React from 'react'
|
||||
import {useMemo} from 'react'
|
||||
import {View} from 'react-native'
|
||||
import {msg} from '@lingui/core/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
@@ -12,7 +12,7 @@ import {Text} from '#/components/Typography'
|
||||
export function MessageListError({item}: {item: ConvoItem & {type: 'error'}}) {
|
||||
const t = useTheme()
|
||||
const {_} = useLingui()
|
||||
const {description, help, cta} = React.useMemo(() => {
|
||||
const {description, help, cta} = useMemo(() => {
|
||||
return {
|
||||
[ConvoItemError.FirehoseFailed]: {
|
||||
description: _(msg`This chat was disconnected`),
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React from 'react'
|
||||
import {useCallback, useMemo, useState} from 'react'
|
||||
import {View} from 'react-native'
|
||||
import {msg} from '@lingui/core/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
@@ -63,9 +63,9 @@ function Inner({preferences}: {preferences: UsePreferencesQueryResponse}) {
|
||||
const {_} = useLingui()
|
||||
const {mutateAsync: setPostInteractionSettings, isPending} =
|
||||
usePostInteractionSettingsMutation()
|
||||
const [error, setError] = React.useState<string | undefined>(undefined)
|
||||
const [error, setError] = useState<string | undefined>(undefined)
|
||||
|
||||
const allowUI = React.useMemo(() => {
|
||||
const allowUI = useMemo(() => {
|
||||
return threadgateRecordToAllowUISetting({
|
||||
$type: 'app.bsky.feed.threadgate',
|
||||
post: '',
|
||||
@@ -73,7 +73,7 @@ function Inner({preferences}: {preferences: UsePreferencesQueryResponse}) {
|
||||
allow: preferences.postInteractionSettings.threadgateAllowRules,
|
||||
})
|
||||
}, [preferences.postInteractionSettings.threadgateAllowRules])
|
||||
const postgate = React.useMemo(() => {
|
||||
const postgate = useMemo(() => {
|
||||
return createPostgateRecord({
|
||||
post: '',
|
||||
embeddingRules:
|
||||
@@ -81,17 +81,17 @@ function Inner({preferences}: {preferences: UsePreferencesQueryResponse}) {
|
||||
})
|
||||
}, [preferences.postInteractionSettings.postgateEmbeddingRules])
|
||||
|
||||
const [maybeEditedAllowUI, setAllowUI] = React.useState(allowUI)
|
||||
const [maybeEditedPostgate, setEditedPostgate] = React.useState(postgate)
|
||||
const [maybeEditedAllowUI, setAllowUI] = useState(allowUI)
|
||||
const [maybeEditedPostgate, setEditedPostgate] = useState(postgate)
|
||||
|
||||
const wasEdited = React.useMemo(() => {
|
||||
const wasEdited = useMemo(() => {
|
||||
return (
|
||||
!deepEqual(allowUI, maybeEditedAllowUI) ||
|
||||
!deepEqual(postgate.embeddingRules, maybeEditedPostgate.embeddingRules)
|
||||
)
|
||||
}, [postgate, allowUI, maybeEditedAllowUI, maybeEditedPostgate])
|
||||
|
||||
const onSave = React.useCallback(async () => {
|
||||
const onSave = useCallback(async () => {
|
||||
setError('')
|
||||
|
||||
try {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React from 'react'
|
||||
import {useMemo} from 'react'
|
||||
import {type TextStyle, View, type ViewStyle} from 'react-native'
|
||||
|
||||
import {type Interest, useInterestsDisplayNames} from '#/lib/interests'
|
||||
@@ -12,7 +12,7 @@ export function InterestButton({interest}: {interest: Interest}) {
|
||||
const interestsDisplayNames = useInterestsDisplayNames()
|
||||
const ctx = Toggle.useItemContext()
|
||||
|
||||
const styles = React.useMemo(() => {
|
||||
const styles = useMemo(() => {
|
||||
const hovered: ViewStyle[] = [
|
||||
{
|
||||
backgroundColor:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React from 'react'
|
||||
import {useCallback, useState} from 'react'
|
||||
import {View} from 'react-native'
|
||||
import {msg} from '@lingui/core/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
@@ -27,12 +27,12 @@ export function StepInterests() {
|
||||
const interestsDisplayNames = useInterestsDisplayNames()
|
||||
|
||||
const {state, dispatch} = useOnboardingInternalState()
|
||||
const [saving, setSaving] = React.useState(false)
|
||||
const [selectedInterests, setSelectedInterests] = React.useState<string[]>(
|
||||
const [saving, setSaving] = useState(false)
|
||||
const [selectedInterests, setSelectedInterests] = useState<string[]>(
|
||||
state.interestsStepResults.selectedInterests.map(i => i),
|
||||
)
|
||||
|
||||
const saveInterests = React.useCallback(async () => {
|
||||
const saveInterests = useCallback(async () => {
|
||||
setSaving(true)
|
||||
|
||||
try {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React from 'react'
|
||||
import {useMemo} from 'react'
|
||||
import {View} from 'react-native'
|
||||
import {Image as ExpoImage} from 'expo-image'
|
||||
import {msg} from '@lingui/core/macro'
|
||||
@@ -22,7 +22,7 @@ export function AvatarCircle({
|
||||
const t = useTheme()
|
||||
const {avatar} = useAvatar()
|
||||
|
||||
const styles = React.useMemo(
|
||||
const styles = useMemo(
|
||||
() => ({
|
||||
imageContainer: [
|
||||
a.rounded_full,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React from 'react'
|
||||
import {useMemo} from 'react'
|
||||
import {View} from 'react-native'
|
||||
|
||||
import {type Avatar} from '#/screens/Onboarding/StepProfile/index'
|
||||
@@ -14,7 +14,7 @@ export function AvatarCreatorCircle({
|
||||
const t = useTheme()
|
||||
const Icon = avatar.placeholder.component
|
||||
|
||||
const styles = React.useMemo(
|
||||
const styles = useMemo(
|
||||
() => ({
|
||||
imageContainer: [
|
||||
a.rounded_full,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React from 'react'
|
||||
import {useCallback} from 'react'
|
||||
import {View} from 'react-native'
|
||||
import {msg} from '@lingui/core/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
@@ -39,7 +39,7 @@ export function AvatarCreatorItems({
|
||||
const t = useTheme()
|
||||
const isEmojis = type === 'emojis'
|
||||
|
||||
const onSelectEmoji = React.useCallback(
|
||||
const onSelectEmoji = useCallback(
|
||||
(emoji: EmojiName) => {
|
||||
setAvatar(prev => ({
|
||||
...prev,
|
||||
@@ -49,7 +49,7 @@ export function AvatarCreatorItems({
|
||||
[setAvatar],
|
||||
)
|
||||
|
||||
const onSelectColor = React.useCallback(
|
||||
const onSelectColor = useCallback(
|
||||
(color: AvatarColor) => {
|
||||
setAvatar(prev => ({
|
||||
...prev,
|
||||
|
||||
@@ -1,11 +1,18 @@
|
||||
import React from 'react'
|
||||
import {
|
||||
forwardRef,
|
||||
lazy,
|
||||
Suspense,
|
||||
useImperativeHandle,
|
||||
useMemo,
|
||||
useRef,
|
||||
} from 'react'
|
||||
import {View} from 'react-native'
|
||||
import type ViewShot from 'react-native-view-shot'
|
||||
|
||||
import {useAvatar} from '#/screens/Onboarding/StepProfile/index'
|
||||
import {atoms as a} from '#/alf'
|
||||
|
||||
const LazyViewShot = React.lazy(
|
||||
const LazyViewShot = lazy(
|
||||
// @ts-expect-error dynamic import
|
||||
() => import('react-native-view-shot/src/index'),
|
||||
)
|
||||
@@ -18,13 +25,13 @@ export interface PlaceholderCanvasRef {
|
||||
|
||||
// This component is supposed to be invisible to the user. We only need this for ViewShot to have something to
|
||||
// "screenshot".
|
||||
export const PlaceholderCanvas = React.forwardRef<PlaceholderCanvasRef, {}>(
|
||||
export const PlaceholderCanvas = forwardRef<PlaceholderCanvasRef, {}>(
|
||||
function PlaceholderCanvas({}, ref) {
|
||||
const {avatar} = useAvatar()
|
||||
const viewshotRef = React.useRef<ViewShot>(null)
|
||||
const viewshotRef = useRef<ViewShot>(null)
|
||||
const Icon = avatar.placeholder.component
|
||||
|
||||
const styles = React.useMemo(
|
||||
const styles = useMemo(
|
||||
() => ({
|
||||
container: [a.absolute, {top: -2000}],
|
||||
imageContainer: [
|
||||
@@ -36,7 +43,7 @@ export const PlaceholderCanvas = React.forwardRef<PlaceholderCanvasRef, {}>(
|
||||
[],
|
||||
)
|
||||
|
||||
React.useImperativeHandle(ref, () => ({
|
||||
useImperativeHandle(ref, () => ({
|
||||
capture: async () => {
|
||||
if (viewshotRef.current?.capture) {
|
||||
return await viewshotRef.current.capture()
|
||||
@@ -46,7 +53,7 @@ export const PlaceholderCanvas = React.forwardRef<PlaceholderCanvasRef, {}>(
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<React.Suspense fallback={null}>
|
||||
<Suspense fallback={null}>
|
||||
<LazyViewShot
|
||||
// @ts-ignore this library doesn't have types
|
||||
ref={viewshotRef}
|
||||
@@ -70,7 +77,7 @@ export const PlaceholderCanvas = React.forwardRef<PlaceholderCanvasRef, {}>(
|
||||
/>
|
||||
</View>
|
||||
</LazyViewShot>
|
||||
</React.Suspense>
|
||||
</Suspense>
|
||||
</View>
|
||||
)
|
||||
},
|
||||
|
||||
@@ -1,4 +1,12 @@
|
||||
import React from 'react'
|
||||
import {
|
||||
createContext,
|
||||
useCallback,
|
||||
useContext,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useRef,
|
||||
useState,
|
||||
} from 'react'
|
||||
import {View} from 'react-native'
|
||||
import {Image as ExpoImage} from 'expo-image'
|
||||
import {ImageManipulator, SaveFormat} from 'expo-image-manipulator'
|
||||
@@ -60,9 +68,9 @@ interface IAvatarContext {
|
||||
setAvatar: React.Dispatch<React.SetStateAction<Avatar>>
|
||||
}
|
||||
|
||||
const AvatarContext = React.createContext<IAvatarContext>({} as IAvatarContext)
|
||||
const AvatarContext = createContext<IAvatarContext>({} as IAvatarContext)
|
||||
AvatarContext.displayName = 'AvatarContext'
|
||||
export const useAvatar = () => React.useContext(AvatarContext)
|
||||
export const useAvatar = () => useContext(AvatarContext)
|
||||
|
||||
const randomColor =
|
||||
avatarColors[Math.floor(Math.random() * avatarColors.length)]
|
||||
@@ -76,10 +84,10 @@ export function StepProfile() {
|
||||
const requestNotificationsPermission = useRequestNotificationsPermission()
|
||||
|
||||
const creatorControl = Dialog.useDialogControl()
|
||||
const [error, setError] = React.useState('')
|
||||
const [error, setError] = useState('')
|
||||
|
||||
const {state, dispatch} = useOnboardingInternalState()
|
||||
const [avatar, setAvatar] = React.useState<Avatar>({
|
||||
const [avatar, setAvatar] = useState<Avatar>({
|
||||
image: state.profileStepResults?.image,
|
||||
placeholder: state.profileStepResults.creatorState?.emoji || emojiItems.at,
|
||||
backgroundColor:
|
||||
@@ -87,14 +95,14 @@ export function StepProfile() {
|
||||
useCreatedAvatar: state.profileStepResults.isCreatedAvatar,
|
||||
})
|
||||
|
||||
const canvasRef = React.useRef<PlaceholderCanvasRef>(null)
|
||||
const canvasRef = useRef<PlaceholderCanvasRef>(null)
|
||||
|
||||
React.useEffect(() => {
|
||||
useEffect(() => {
|
||||
requestNotificationsPermission('StartOnboarding')
|
||||
}, [requestNotificationsPermission])
|
||||
|
||||
const sheetWrapper = useSheetWrapper()
|
||||
const openPicker = React.useCallback(
|
||||
const openPicker = useCallback(
|
||||
async (opts?: ImagePickerOptions) => {
|
||||
const response = await sheetWrapper(
|
||||
launchImageLibraryAsync({
|
||||
@@ -139,7 +147,7 @@ export function StepProfile() {
|
||||
[_, setError, sheetWrapper],
|
||||
)
|
||||
|
||||
const onContinue = React.useCallback(async () => {
|
||||
const onContinue = useCallback(async () => {
|
||||
let imageUri = avatar?.image?.path
|
||||
|
||||
// In the event that view-shot didn't load in time and the user pressed continue, this will just be undefined
|
||||
@@ -167,7 +175,7 @@ export function StepProfile() {
|
||||
ax.metric('onboarding:profile:nextPressed', {})
|
||||
}, [ax, avatar, dispatch])
|
||||
|
||||
const onDoneCreating = React.useCallback(() => {
|
||||
const onDoneCreating = useCallback(() => {
|
||||
setAvatar(prev => ({
|
||||
...prev,
|
||||
image: undefined,
|
||||
@@ -176,7 +184,7 @@ export function StepProfile() {
|
||||
creatorControl.close()
|
||||
}, [creatorControl])
|
||||
|
||||
const openLibrary = React.useCallback(async () => {
|
||||
const openLibrary = useCallback(async () => {
|
||||
if (!(await requestPhotoAccessIfNeeded())) {
|
||||
return
|
||||
}
|
||||
@@ -225,7 +233,7 @@ export function StepProfile() {
|
||||
sheetWrapper,
|
||||
])
|
||||
|
||||
const onSecondaryPress = React.useCallback(() => {
|
||||
const onSecondaryPress = useCallback(() => {
|
||||
if (avatar.useCreatedAvatar) {
|
||||
openLibrary()
|
||||
} else {
|
||||
@@ -233,7 +241,7 @@ export function StepProfile() {
|
||||
}
|
||||
}, [avatar.useCreatedAvatar, creatorControl, openLibrary])
|
||||
|
||||
const value = React.useMemo(
|
||||
const value = useMemo(
|
||||
() => ({
|
||||
avatar,
|
||||
setAvatar,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React from 'react'
|
||||
import {useCallback} from 'react'
|
||||
import {Plural, Trans} from '@lingui/react/macro'
|
||||
import {useFocusEffect} from '@react-navigation/native'
|
||||
|
||||
@@ -25,7 +25,7 @@ export const PostLikedByScreen = ({route}: Props) => {
|
||||
}
|
||||
|
||||
useFocusEffect(
|
||||
React.useCallback(() => {
|
||||
useCallback(() => {
|
||||
setMinimalShellMode(false)
|
||||
}, [setMinimalShellMode]),
|
||||
)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React from 'react'
|
||||
import {useCallback} from 'react'
|
||||
import {Plural, Trans} from '@lingui/react/macro'
|
||||
import {useFocusEffect} from '@react-navigation/native'
|
||||
|
||||
@@ -25,7 +25,7 @@ export const PostQuotesScreen = ({route}: Props) => {
|
||||
}
|
||||
|
||||
useFocusEffect(
|
||||
React.useCallback(() => {
|
||||
useCallback(() => {
|
||||
setMinimalShellMode(false)
|
||||
}, [setMinimalShellMode]),
|
||||
)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React from 'react'
|
||||
import {useCallback} from 'react'
|
||||
import {Plural, Trans} from '@lingui/react/macro'
|
||||
import {useFocusEffect} from '@react-navigation/native'
|
||||
|
||||
@@ -25,7 +25,7 @@ export const PostRepostedByScreen = ({route}: Props) => {
|
||||
}
|
||||
|
||||
useFocusEffect(
|
||||
React.useCallback(() => {
|
||||
useCallback(() => {
|
||||
setMinimalShellMode(false)
|
||||
}, [setMinimalShellMode]),
|
||||
)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React from 'react'
|
||||
import {useCallback, useEffect, useMemo, useState} from 'react'
|
||||
import {type AppBskyActorDefs} from '@atproto/api'
|
||||
import {msg} from '@lingui/core/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
@@ -71,10 +71,10 @@ function PostThreadFollowBtnLoaded({
|
||||
|
||||
const isFollowing = !!profile.viewer?.following
|
||||
const isFollowedBy = !!profile.viewer?.followedBy
|
||||
const [wasFollowing, setWasFollowing] = React.useState<boolean>(isFollowing)
|
||||
const [wasFollowing, setWasFollowing] = useState<boolean>(isFollowing)
|
||||
|
||||
// This prevents the button from disappearing as soon as we follow.
|
||||
const showFollowBtn = React.useMemo(
|
||||
const showFollowBtn = useMemo(
|
||||
() => !isFollowing || !wasFollowing,
|
||||
[isFollowing, wasFollowing],
|
||||
)
|
||||
@@ -90,7 +90,7 @@ function PostThreadFollowBtnLoaded({
|
||||
* sudden rendering of the button. However, on web if we do this, there's an obvious flicker once the
|
||||
* button renders. So, we update the state in both cases.
|
||||
*/
|
||||
React.useEffect(() => {
|
||||
useEffect(() => {
|
||||
const updateWasFollowing = () => {
|
||||
if (wasFollowing !== isFollowing) {
|
||||
setWasFollowing(isFollowing)
|
||||
@@ -106,7 +106,7 @@ function PostThreadFollowBtnLoaded({
|
||||
}
|
||||
}, [isFollowing, wasFollowing, navigation])
|
||||
|
||||
const onPress = React.useCallback(() => {
|
||||
const onPress = useCallback(() => {
|
||||
if (!isFollowing) {
|
||||
requireAuth(async () => {
|
||||
try {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React from 'react'
|
||||
import {useCallback} from 'react'
|
||||
import {View} from 'react-native'
|
||||
import {msg} from '@lingui/core/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
@@ -16,7 +16,7 @@ export function ErrorState({error}: {error: string}) {
|
||||
const {_} = useLingui()
|
||||
const navigation = useNavigation<NavigationProp>()
|
||||
|
||||
const onPressBack = React.useCallback(() => {
|
||||
const onPressBack = useCallback(() => {
|
||||
if (navigation.canGoBack()) {
|
||||
navigation.goBack()
|
||||
} else {
|
||||
|
||||
@@ -5,7 +5,6 @@ import Animated, {
|
||||
type SharedValue,
|
||||
useAnimatedStyle,
|
||||
} from 'react-native-reanimated'
|
||||
import type React from 'react'
|
||||
|
||||
import {usePagerHeaderContext} from '#/view/com/pager/PagerHeaderContext'
|
||||
import {IS_IOS} from '#/env'
|
||||
|
||||
@@ -13,7 +13,6 @@ import Animated, {
|
||||
import {useSafeAreaInsets} from 'react-native-safe-area-context'
|
||||
import {BlurView} from 'expo-blur'
|
||||
import {useIsFetching} from '@tanstack/react-query'
|
||||
import type React from 'react'
|
||||
|
||||
import {RQKEY_ROOT as STARTERPACK_RQKEY_ROOT} from '#/state/queries/actor-starter-packs'
|
||||
import {RQKEY_ROOT as FEED_RQKEY_ROOT} from '#/state/queries/post-feed'
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React from 'react'
|
||||
import {useCallback, useMemo, useState} from 'react'
|
||||
import {type AppBskyActorDefs} from '@atproto/api'
|
||||
import {msg} from '@lingui/core/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
@@ -51,7 +51,7 @@ export const ProfileKnownFollowersScreen = ({route}: Props) => {
|
||||
|
||||
const {name} = route.params
|
||||
|
||||
const [isPTRing, setIsPTRing] = React.useState(false)
|
||||
const [isPTRing, setIsPTRing] = useState(false)
|
||||
const {
|
||||
data: resolvedDid,
|
||||
isLoading: isDidLoading,
|
||||
@@ -67,7 +67,7 @@ export const ProfileKnownFollowersScreen = ({route}: Props) => {
|
||||
refetch,
|
||||
} = useProfileKnownFollowersQuery(resolvedDid)
|
||||
|
||||
const onRefresh = React.useCallback(async () => {
|
||||
const onRefresh = useCallback(async () => {
|
||||
setIsPTRing(true)
|
||||
try {
|
||||
await refetch()
|
||||
@@ -77,7 +77,7 @@ export const ProfileKnownFollowersScreen = ({route}: Props) => {
|
||||
setIsPTRing(false)
|
||||
}, [refetch, setIsPTRing])
|
||||
|
||||
const onEndReached = React.useCallback(async () => {
|
||||
const onEndReached = useCallback(async () => {
|
||||
if (isFetchingNextPage || !hasNextPage || !!error) return
|
||||
try {
|
||||
await fetchNextPage()
|
||||
@@ -86,7 +86,7 @@ export const ProfileKnownFollowersScreen = ({route}: Props) => {
|
||||
}
|
||||
}, [isFetchingNextPage, hasNextPage, error, fetchNextPage])
|
||||
|
||||
const followers = React.useMemo(() => {
|
||||
const followers = useMemo(() => {
|
||||
if (data?.pages) {
|
||||
return data.pages.flatMap(page => page.followers)
|
||||
}
|
||||
@@ -96,7 +96,7 @@ export const ProfileKnownFollowersScreen = ({route}: Props) => {
|
||||
const isError = Boolean(resolveError || error)
|
||||
|
||||
useFocusEffect(
|
||||
React.useCallback(() => {
|
||||
useCallback(() => {
|
||||
setMinimalShellMode(false)
|
||||
}, [setMinimalShellMode]),
|
||||
)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React from 'react'
|
||||
import {useCallback} from 'react'
|
||||
import {Plural} from '@lingui/react/macro'
|
||||
import {useFocusEffect} from '@react-navigation/native'
|
||||
|
||||
@@ -24,7 +24,7 @@ export const ProfileFollowersScreen = ({route}: Props) => {
|
||||
})
|
||||
|
||||
useFocusEffect(
|
||||
React.useCallback(() => {
|
||||
useCallback(() => {
|
||||
setMinimalShellMode(false)
|
||||
}, [setMinimalShellMode]),
|
||||
)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React from 'react'
|
||||
import {useCallback} from 'react'
|
||||
import {Plural} from '@lingui/react/macro'
|
||||
import {useFocusEffect} from '@react-navigation/native'
|
||||
|
||||
@@ -24,7 +24,7 @@ export const ProfileFollowsScreen = ({route}: Props) => {
|
||||
})
|
||||
|
||||
useFocusEffect(
|
||||
React.useCallback(() => {
|
||||
useCallback(() => {
|
||||
setMinimalShellMode(false)
|
||||
}, [setMinimalShellMode]),
|
||||
)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React from 'react'
|
||||
import {useCallback} from 'react'
|
||||
import {msg} from '@lingui/core/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
import {useFocusEffect} from '@react-navigation/native'
|
||||
@@ -22,7 +22,7 @@ export function ProfileLabelerLikedByScreen({
|
||||
const {_} = useLingui()
|
||||
|
||||
useFocusEffect(
|
||||
React.useCallback(() => {
|
||||
useCallback(() => {
|
||||
setMinimalShellMode(false)
|
||||
}, [setMinimalShellMode]),
|
||||
)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React from 'react'
|
||||
import {useCallback, useMemo, useState} from 'react'
|
||||
import {View} from 'react-native'
|
||||
import {AtUri} from '@atproto/api'
|
||||
import {msg} from '@lingui/core/macro'
|
||||
@@ -95,7 +95,7 @@ export function ProfileFeedHeader({info}: {info: FeedSourceFeedInfo}) {
|
||||
|
||||
const {data: preferences} = usePreferencesQuery()
|
||||
|
||||
const [likeUri, setLikeUri] = React.useState(info.likeUri || '')
|
||||
const [likeUri, setLikeUri] = useState(info.likeUri || '')
|
||||
const likeCount =
|
||||
(info.likeCount || 0) +
|
||||
(likeUri && !info.likeUri ? 1 : !likeUri && info.likeUri ? -1 : 0)
|
||||
@@ -401,7 +401,7 @@ function DialogInner({
|
||||
useUnlikeMutation()
|
||||
|
||||
const isLiked = !!likeUri
|
||||
const feedRkey = React.useMemo(() => new AtUri(info.uri).rkey, [info.uri])
|
||||
const feedRkey = useMemo(() => new AtUri(info.uri).rkey, [info.uri])
|
||||
|
||||
const onToggleLiked = async () => {
|
||||
try {
|
||||
@@ -427,14 +427,14 @@ function DialogInner({
|
||||
}
|
||||
}
|
||||
|
||||
const onPressShare = React.useCallback(() => {
|
||||
const onPressShare = useCallback(() => {
|
||||
playHaptic()
|
||||
const url = toShareUrl(info.route.href)
|
||||
shareUrl(url)
|
||||
ax.metric('feed:share', {feedUrl: info.uri})
|
||||
}, [info, playHaptic])
|
||||
|
||||
const onPressReport = React.useCallback(() => {
|
||||
const onPressReport = useCallback(() => {
|
||||
reportDialogControl.open()
|
||||
}, [reportDialogControl])
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React from 'react'
|
||||
import {useState} from 'react'
|
||||
import {View} from 'react-native'
|
||||
import {
|
||||
type AppBskyGraphDefs,
|
||||
@@ -143,7 +143,7 @@ export function AvatarStack({
|
||||
const computedTotal = (total ?? numPending) - numPending
|
||||
const circlesCount = numPending + 1 // add total at end
|
||||
const widthPerc = 100 / circlesCount
|
||||
const [size, setSize] = React.useState<number | null>(null)
|
||||
const [size, setSize] = useState<number | null>(null)
|
||||
|
||||
const isPending = (numPending && profiles.length === 0) || !moderationOpts
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React from 'react'
|
||||
import {useCallback, useState} from 'react'
|
||||
import {View} from 'react-native'
|
||||
import {msg} from '@lingui/core/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
@@ -36,10 +36,10 @@ function DeactivateAccountDialogInner({
|
||||
const {_} = useLingui()
|
||||
const agent = useAgent()
|
||||
const {logoutCurrentAccount} = useSessionApi()
|
||||
const [pending, setPending] = React.useState(false)
|
||||
const [error, setError] = React.useState<string | undefined>()
|
||||
const [pending, setPending] = useState(false)
|
||||
const [error, setError] = useState<string | undefined>()
|
||||
|
||||
const handleDeactivate = React.useCallback(async () => {
|
||||
const handleDeactivate = useCallback(async () => {
|
||||
try {
|
||||
setPending(true)
|
||||
await agent.com.atproto.server.deactivateAccount({})
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React from 'react'
|
||||
import {useCallback} from 'react'
|
||||
import {msg} from '@lingui/core/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
|
||||
@@ -17,7 +17,7 @@ export function Email2FAToggle() {
|
||||
const disableDialogControl = useDialogControl()
|
||||
const emailDialogControl = useEmailDialogControl()
|
||||
|
||||
const onToggle = React.useCallback(() => {
|
||||
const onToggle = useCallback(() => {
|
||||
emailDialogControl.open({
|
||||
id: EmailDialogScreenID.Manage2FA,
|
||||
})
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React from 'react'
|
||||
import {useCallback} from 'react'
|
||||
import {View} from 'react-native'
|
||||
import {type $Typed, ComAtprotoLabelDefs} from '@atproto/api'
|
||||
import {msg} from '@lingui/core/macro'
|
||||
@@ -26,7 +26,7 @@ export function PwiOptOut() {
|
||||
profile?.labels?.some(l => l.val === '!no-unauthenticated') || false
|
||||
const canToggle = profile && !updateProfile.isPending
|
||||
|
||||
const onToggleOptOut = React.useCallback(() => {
|
||||
const onToggleOptOut = useCallback(() => {
|
||||
if (!profile) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React from 'react'
|
||||
import {useCallback, useEffect} from 'react'
|
||||
import {StyleSheet} from 'react-native'
|
||||
|
||||
// @ts-ignore web only, we will always redirect to the app on web (CORS)
|
||||
@@ -15,7 +15,7 @@ export function CaptchaWebView({
|
||||
onSuccess: (code: string) => void
|
||||
onError: (error: unknown) => void
|
||||
}) {
|
||||
React.useEffect(() => {
|
||||
useEffect(() => {
|
||||
const timeout = setTimeout(() => {
|
||||
onError({
|
||||
errorMessage: 'User did not complete the captcha within 30 seconds',
|
||||
@@ -27,7 +27,7 @@ export function CaptchaWebView({
|
||||
}
|
||||
}, [onError])
|
||||
|
||||
const onLoad = React.useCallback(() => {
|
||||
const onLoad = useCallback(() => {
|
||||
// @ts-ignore web
|
||||
const frame: HTMLIFrameElement = document.getElementById(
|
||||
'captcha-iframe',
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, {useEffect, useState} from 'react'
|
||||
import {useCallback, useEffect, useMemo, useState} from 'react'
|
||||
import {ActivityIndicator, Platform, View} from 'react-native'
|
||||
import ReactNativeDeviceAttest from 'react-native-device-attest'
|
||||
import {msg} from '@lingui/core/macro'
|
||||
@@ -75,10 +75,10 @@ function StepCaptchaInner({
|
||||
const theme = useTheme()
|
||||
const {state, dispatch} = useSignupContext()
|
||||
|
||||
const [completed, setCompleted] = React.useState(false)
|
||||
const [completed, setCompleted] = useState(false)
|
||||
|
||||
const stateParam = React.useMemo(() => nanoid(15), [])
|
||||
const url = React.useMemo(() => {
|
||||
const stateParam = useMemo(() => nanoid(15), [])
|
||||
const url = useMemo(() => {
|
||||
const newUrl = new URL(state.serviceUrl)
|
||||
newUrl.pathname = CAPTCHA_PATH
|
||||
newUrl.searchParams.set(
|
||||
@@ -107,7 +107,7 @@ function StepCaptchaInner({
|
||||
payload,
|
||||
])
|
||||
|
||||
const onSuccess = React.useCallback(
|
||||
const onSuccess = useCallback(
|
||||
(code: string) => {
|
||||
setCompleted(true)
|
||||
ax.metric('signup:captchaSuccess', {})
|
||||
@@ -119,7 +119,7 @@ function StepCaptchaInner({
|
||||
[ax, dispatch],
|
||||
)
|
||||
|
||||
const onError = React.useCallback(
|
||||
const onError = useCallback(
|
||||
(error?: unknown) => {
|
||||
dispatch({
|
||||
type: 'setError',
|
||||
@@ -134,7 +134,7 @@ function StepCaptchaInner({
|
||||
[_, ax, dispatch, state.handle],
|
||||
)
|
||||
|
||||
const onBackPress = React.useCallback(() => {
|
||||
const onBackPress = useCallback(() => {
|
||||
logger.error('Signup Flow Error', {
|
||||
errorMessage:
|
||||
'User went back from captcha step. Possibly encountered an error.',
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, {useRef} from 'react'
|
||||
import {useEffect, useRef, useState} from 'react'
|
||||
import {type TextInput, View} from 'react-native'
|
||||
import {msg} from '@lingui/core/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
@@ -89,10 +89,10 @@ export function StepInfo({
|
||||
: true
|
||||
const isDeviceGeolocationGranted = useIsDeviceGeolocationGranted()
|
||||
|
||||
const [hasWarnedEmail, setHasWarnedEmail] = React.useState<boolean>(false)
|
||||
const [hasWarnedEmail, setHasWarnedEmail] = useState<boolean>(false)
|
||||
|
||||
const tldtsRef = React.useRef<typeof tldts>(undefined)
|
||||
React.useEffect(() => {
|
||||
const tldtsRef = useRef<typeof tldts>(undefined)
|
||||
useEffect(() => {
|
||||
// @ts-expect-error - valid path
|
||||
import('tldts/dist/index.cjs.min.js').then(tldts => {
|
||||
tldtsRef.current = tldts
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, {useCallback} from 'react'
|
||||
import {createContext, useCallback, useContext} from 'react'
|
||||
import {LayoutAnimation} from 'react-native'
|
||||
import {
|
||||
ComAtprotoServerCreateAccount,
|
||||
@@ -250,9 +250,9 @@ interface IContext {
|
||||
state: SignupState
|
||||
dispatch: React.Dispatch<SignupAction>
|
||||
}
|
||||
export const SignupContext = React.createContext<IContext>({} as IContext)
|
||||
export const SignupContext = createContext<IContext>({} as IContext)
|
||||
SignupContext.displayName = 'SignupContext'
|
||||
export const useSignupContext = () => React.useContext(SignupContext)
|
||||
export const useSignupContext = () => useContext(SignupContext)
|
||||
|
||||
export function useSubmitSignup() {
|
||||
const ax = useAnalytics()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React from 'react'
|
||||
import {useCallback, useEffect, useState} from 'react'
|
||||
import {Modal, ScrollView, View} from 'react-native'
|
||||
import {SystemBars} from 'react-native-edge-to-edge'
|
||||
import {useSafeAreaInsets} from 'react-native-safe-area-context'
|
||||
@@ -27,15 +27,15 @@ export function SignupQueued() {
|
||||
const {logoutCurrentAccount} = useSessionApi()
|
||||
const agent = useAgent()
|
||||
|
||||
const [isProcessing, setProcessing] = React.useState(false)
|
||||
const [estimatedTime, setEstimatedTime] = React.useState<string | undefined>(
|
||||
const [isProcessing, setProcessing] = useState(false)
|
||||
const [estimatedTime, setEstimatedTime] = useState<string | undefined>(
|
||||
undefined,
|
||||
)
|
||||
const [placeInQueue, setPlaceInQueue] = React.useState<number | undefined>(
|
||||
const [placeInQueue, setPlaceInQueue] = useState<number | undefined>(
|
||||
undefined,
|
||||
)
|
||||
|
||||
const checkStatus = React.useCallback(async () => {
|
||||
const checkStatus = useCallback(async () => {
|
||||
setProcessing(true)
|
||||
try {
|
||||
const res = await agent.com.atproto.temp.checkSignupQueue()
|
||||
@@ -65,7 +65,7 @@ export function SignupQueued() {
|
||||
agent,
|
||||
])
|
||||
|
||||
React.useEffect(() => {
|
||||
useEffect(() => {
|
||||
checkStatus()
|
||||
const interval = setInterval(checkStatus, 60e3)
|
||||
return () => clearInterval(interval)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React from 'react'
|
||||
import {useEffect, useState} from 'react'
|
||||
import {Pressable, View} from 'react-native'
|
||||
import Animated, {FadeIn, FadeOut} from 'react-native-reanimated'
|
||||
import {
|
||||
@@ -75,7 +75,7 @@ export function LandingScreen({
|
||||
AppBskyGraphDefs.validateStarterPackView(starterPack) &&
|
||||
AppBskyGraphStarterpack.validateRecord(starterPack.record)
|
||||
|
||||
React.useEffect(() => {
|
||||
useEffect(() => {
|
||||
if (isErrorStarterPack || (starterPack && !isValid)) {
|
||||
setScreenState(LoggedOutScreenState.S_LoginOrCreateAccount)
|
||||
}
|
||||
@@ -128,8 +128,7 @@ function LandingScreenLoaded({
|
||||
const androidDialogControl = useDialogControl()
|
||||
const [descriptionRt] = useRichText(record.description || '')
|
||||
|
||||
const [appClipOverlayVisible, setAppClipOverlayVisible] =
|
||||
React.useState(false)
|
||||
const [appClipOverlayVisible, setAppClipOverlayVisible] = useState(false)
|
||||
|
||||
const listItemsCount = starterPack.list?.listItemCount ?? 0
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React from 'react'
|
||||
import {useCallback, useEffect, useState} from 'react'
|
||||
import {View} from 'react-native'
|
||||
import {Image} from 'expo-image'
|
||||
import {
|
||||
@@ -201,16 +201,16 @@ function StarterPackScreenLoaded({
|
||||
const shareDialogControl = useDialogControl()
|
||||
|
||||
const shortenLink = useShortenLink()
|
||||
const [link, setLink] = React.useState<string>()
|
||||
const [imageLoaded, setImageLoaded] = React.useState(false)
|
||||
const [link, setLink] = useState<string>()
|
||||
const [imageLoaded, setImageLoaded] = useState(false)
|
||||
|
||||
React.useEffect(() => {
|
||||
useEffect(() => {
|
||||
ax.metric('starterPack:opened', {
|
||||
starterPack: starterPack.uri,
|
||||
})
|
||||
}, [ax, starterPack.uri])
|
||||
|
||||
const onOpenShareDialog = React.useCallback(() => {
|
||||
const onOpenShareDialog = useCallback(() => {
|
||||
const rkey = new AtUri(starterPack.uri).rkey
|
||||
shortenLink(makeStarterPackLink(starterPack.creator.did, rkey)).then(
|
||||
res => {
|
||||
@@ -227,7 +227,7 @@ function StarterPackScreenLoaded({
|
||||
shareDialogControl.open()
|
||||
}, [shareDialogControl, shortenLink, starterPack])
|
||||
|
||||
React.useEffect(() => {
|
||||
useEffect(() => {
|
||||
if (routeParams.new) {
|
||||
onOpenShareDialog()
|
||||
}
|
||||
@@ -316,7 +316,7 @@ function Header({
|
||||
const {requestSwitchToAccount} = useLoggedOutViewControls()
|
||||
const {captureAction} = useProgressGuideControls()
|
||||
|
||||
const [isProcessing, setIsProcessing] = React.useState(false)
|
||||
const [isProcessing, setIsProcessing] = useState(false)
|
||||
|
||||
const {record, creator} = starterPack
|
||||
const isOwn = creator?.did === currentAccount?.did
|
||||
@@ -325,7 +325,7 @@ function Header({
|
||||
|
||||
const navigation = useNavigation<NavigationProp>()
|
||||
|
||||
React.useEffect(() => {
|
||||
useEffect(() => {
|
||||
const onFocus = () => {
|
||||
if (hasSession) return
|
||||
setActiveStarterPack({
|
||||
@@ -731,7 +731,7 @@ function InvalidStarterPack({rkey}: {rkey: string}) {
|
||||
const t = useTheme()
|
||||
const navigation = useNavigation<NavigationProp>()
|
||||
const {gtMobile} = useBreakpoints()
|
||||
const [isProcessing, setIsProcessing] = React.useState(false)
|
||||
const [isProcessing, setIsProcessing] = useState(false)
|
||||
|
||||
const goBack = () => {
|
||||
if (navigation.canGoBack()) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React from 'react'
|
||||
import {createContext, useContext, useReducer} from 'react'
|
||||
import {
|
||||
type AppBskyFeedDefs,
|
||||
type AppBskyGraphDefs,
|
||||
@@ -41,12 +41,12 @@ interface State {
|
||||
|
||||
type TStateContext = [State, (action: Action) => void]
|
||||
|
||||
const StateContext = React.createContext<TStateContext>([
|
||||
const StateContext = createContext<TStateContext>([
|
||||
{} as State,
|
||||
(_: Action) => {},
|
||||
])
|
||||
StateContext.displayName = 'StarterPackWizardStateContext'
|
||||
export const useWizardState = () => React.useContext(StateContext)
|
||||
export const useWizardState = () => useContext(StateContext)
|
||||
|
||||
function reducer(state: State, action: Action): State {
|
||||
let updatedState = state
|
||||
@@ -157,7 +157,7 @@ export function Provider({
|
||||
}
|
||||
}
|
||||
|
||||
const [state, dispatch] = React.useReducer(reducer, null, createInitialState)
|
||||
const [state, dispatch] = useReducer(reducer, null, createInitialState)
|
||||
|
||||
return (
|
||||
<StateContext.Provider value={[state, dispatch]}>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React from 'react'
|
||||
import {useCallback, useEffect} from 'react'
|
||||
import {Keyboard, View} from 'react-native'
|
||||
import {KeyboardAwareScrollView} from 'react-native-keyboard-controller'
|
||||
import {useSafeAreaInsets} from 'react-native-safe-area-context'
|
||||
@@ -179,14 +179,14 @@ function WizardInner({
|
||||
})
|
||||
const parsed = parseStarterPackUri(currentStarterPack?.uri)
|
||||
|
||||
React.useEffect(() => {
|
||||
useEffect(() => {
|
||||
navigation.setOptions({
|
||||
gestureEnabled: false,
|
||||
})
|
||||
}, [navigation])
|
||||
|
||||
useFocusEffect(
|
||||
React.useCallback(() => {
|
||||
useCallback(() => {
|
||||
setMinimalShellMode(true)
|
||||
|
||||
return () => {
|
||||
|
||||
+11
-11
@@ -1,4 +1,4 @@
|
||||
import React from 'react'
|
||||
import {useCallback, useMemo, useState} from 'react'
|
||||
import {type ListRenderItemInfo, View} from 'react-native'
|
||||
import {type AppBskyFeedDefs} from '@atproto/api'
|
||||
import {msg} from '@lingui/core/macro'
|
||||
@@ -39,26 +39,26 @@ export default function TopicScreen({
|
||||
const {topic} = route.params
|
||||
const {_} = useLingui()
|
||||
|
||||
const headerTitle = React.useMemo(() => {
|
||||
const headerTitle = useMemo(() => {
|
||||
return enforceLen(decodeURIComponent(topic), 24, true, 'middle')
|
||||
}, [topic])
|
||||
|
||||
const onShare = React.useCallback(() => {
|
||||
const onShare = useCallback(() => {
|
||||
const url = new URL('https://bsky.app')
|
||||
url.pathname = `/topic/${topic}`
|
||||
shareUrl(url.toString())
|
||||
}, [topic])
|
||||
|
||||
const [activeTab, setActiveTab] = React.useState(0)
|
||||
const [activeTab, setActiveTab] = useState(0)
|
||||
const setMinimalShellMode = useSetMinimalShellMode()
|
||||
|
||||
useFocusEffect(
|
||||
React.useCallback(() => {
|
||||
useCallback(() => {
|
||||
setMinimalShellMode(false)
|
||||
}, [setMinimalShellMode]),
|
||||
)
|
||||
|
||||
const onPageSelected = React.useCallback(
|
||||
const onPageSelected = useCallback(
|
||||
(index: number) => {
|
||||
setMinimalShellMode(false)
|
||||
setActiveTab(index)
|
||||
@@ -66,7 +66,7 @@ export default function TopicScreen({
|
||||
[setMinimalShellMode],
|
||||
)
|
||||
|
||||
const sections = React.useMemo(() => {
|
||||
const sections = useMemo(() => {
|
||||
return [
|
||||
{
|
||||
title: _(msg`Top`),
|
||||
@@ -135,7 +135,7 @@ function TopicScreenTab({
|
||||
}) {
|
||||
const {_} = useLingui()
|
||||
const initialNumToRender = useInitialNumToRender()
|
||||
const [isPTR, setIsPTR] = React.useState(false)
|
||||
const [isPTR, setIsPTR] = useState(false)
|
||||
const trackPostView = usePostViewTracking('Topic')
|
||||
|
||||
const {
|
||||
@@ -154,17 +154,17 @@ function TopicScreenTab({
|
||||
enabled: active,
|
||||
})
|
||||
|
||||
const posts = React.useMemo(() => {
|
||||
const posts = useMemo(() => {
|
||||
return data?.pages.flatMap(page => page.posts) || []
|
||||
}, [data])
|
||||
|
||||
const onRefresh = React.useCallback(async () => {
|
||||
const onRefresh = useCallback(async () => {
|
||||
setIsPTR(true)
|
||||
await refetch()
|
||||
setIsPTR(false)
|
||||
}, [refetch])
|
||||
|
||||
const onEndReached = React.useCallback(() => {
|
||||
const onEndReached = useCallback(() => {
|
||||
if (isFetchingNextPage || !hasNextPage || error) return
|
||||
fetchNextPage()
|
||||
}, [isFetchingNextPage, hasNextPage, error, fetchNextPage])
|
||||
|
||||
Reference in New Issue
Block a user