Add shutdown message to for you feed (#3776)
parent
d0440d087e
commit
6f5b551bda
|
@ -111,6 +111,10 @@ export const RECOMMENDED_SAVED_FEEDS: Pick<
|
||||||
'type' | 'value' | 'pinned'
|
'type' | 'value' | 'pinned'
|
||||||
>[] = [DISCOVER_SAVED_FEED, TIMELINE_SAVED_FEED]
|
>[] = [DISCOVER_SAVED_FEED, TIMELINE_SAVED_FEED]
|
||||||
|
|
||||||
|
export const KNOWN_SHUTDOWN_FEEDS = [
|
||||||
|
'at://did:plc:wqowuobffl66jv3kpsvo7ak4/app.bsky.feed.generator/the-algorithm', // for you by skygaze
|
||||||
|
]
|
||||||
|
|
||||||
export const GIF_SERVICE = 'https://gifs.bsky.app'
|
export const GIF_SERVICE = 'https://gifs.bsky.app'
|
||||||
|
|
||||||
export const GIF_SEARCH = (params: string) =>
|
export const GIF_SEARCH = (params: string) =>
|
||||||
|
|
|
@ -14,6 +14,7 @@ import {useLingui} from '@lingui/react'
|
||||||
import {useQueryClient} from '@tanstack/react-query'
|
import {useQueryClient} from '@tanstack/react-query'
|
||||||
|
|
||||||
import {FALLBACK_MARKER_POST} from '#/lib/api/feed/home'
|
import {FALLBACK_MARKER_POST} from '#/lib/api/feed/home'
|
||||||
|
import {KNOWN_SHUTDOWN_FEEDS} from '#/lib/constants'
|
||||||
import {logEvent} from '#/lib/statsig/statsig'
|
import {logEvent} from '#/lib/statsig/statsig'
|
||||||
import {logger} from '#/logger'
|
import {logger} from '#/logger'
|
||||||
import {isWeb} from '#/platform/detection'
|
import {isWeb} from '#/platform/detection'
|
||||||
|
@ -36,12 +37,14 @@ import {PostFeedLoadingPlaceholder} from '../util/LoadingPlaceholder'
|
||||||
import {LoadMoreRetryBtn} from '../util/LoadMoreRetryBtn'
|
import {LoadMoreRetryBtn} from '../util/LoadMoreRetryBtn'
|
||||||
import {DiscoverFallbackHeader} from './DiscoverFallbackHeader'
|
import {DiscoverFallbackHeader} from './DiscoverFallbackHeader'
|
||||||
import {FeedErrorMessage} from './FeedErrorMessage'
|
import {FeedErrorMessage} from './FeedErrorMessage'
|
||||||
|
import {FeedShutdownMsg} from './FeedShutdownMsg'
|
||||||
import {FeedSlice} from './FeedSlice'
|
import {FeedSlice} from './FeedSlice'
|
||||||
|
|
||||||
const LOADING_ITEM = {_reactKey: '__loading__'}
|
const LOADING_ITEM = {_reactKey: '__loading__'}
|
||||||
const EMPTY_FEED_ITEM = {_reactKey: '__empty__'}
|
const EMPTY_FEED_ITEM = {_reactKey: '__empty__'}
|
||||||
const ERROR_ITEM = {_reactKey: '__error__'}
|
const ERROR_ITEM = {_reactKey: '__error__'}
|
||||||
const LOAD_MORE_ERROR_ITEM = {_reactKey: '__load_more_error__'}
|
const LOAD_MORE_ERROR_ITEM = {_reactKey: '__load_more_error__'}
|
||||||
|
const FEED_SHUTDOWN_MSG_ITEM = {_reactKey: '__feed_shutdown_msg_item__'}
|
||||||
|
|
||||||
// DISABLED need to check if this is causing random feed refreshes -prf
|
// DISABLED need to check if this is causing random feed refreshes -prf
|
||||||
// const REFRESH_AFTER = STALE.HOURS.ONE
|
// const REFRESH_AFTER = STALE.HOURS.ONE
|
||||||
|
@ -96,7 +99,7 @@ let Feed = ({
|
||||||
const [isPTRing, setIsPTRing] = React.useState(false)
|
const [isPTRing, setIsPTRing] = React.useState(false)
|
||||||
const checkForNewRef = React.useRef<(() => void) | null>(null)
|
const checkForNewRef = React.useRef<(() => void) | null>(null)
|
||||||
const lastFetchRef = React.useRef<number>(Date.now())
|
const lastFetchRef = React.useRef<number>(Date.now())
|
||||||
const feedType = feed.split('|')[0]
|
const [feedType, feedUri] = feed.split('|')
|
||||||
|
|
||||||
const opts = React.useMemo(
|
const opts = React.useMemo(
|
||||||
() => ({enabled, ignoreFilterFor}),
|
() => ({enabled, ignoreFilterFor}),
|
||||||
|
@ -196,6 +199,9 @@ let Feed = ({
|
||||||
|
|
||||||
const feedItems = React.useMemo(() => {
|
const feedItems = React.useMemo(() => {
|
||||||
let arr: any[] = []
|
let arr: any[] = []
|
||||||
|
if (KNOWN_SHUTDOWN_FEEDS.includes(feedUri)) {
|
||||||
|
arr = arr.concat([FEED_SHUTDOWN_MSG_ITEM])
|
||||||
|
}
|
||||||
if (isFetched) {
|
if (isFetched) {
|
||||||
if (isError && isEmpty) {
|
if (isError && isEmpty) {
|
||||||
arr = arr.concat([ERROR_ITEM])
|
arr = arr.concat([ERROR_ITEM])
|
||||||
|
@ -213,7 +219,7 @@ let Feed = ({
|
||||||
arr.push(LOADING_ITEM)
|
arr.push(LOADING_ITEM)
|
||||||
}
|
}
|
||||||
return arr
|
return arr
|
||||||
}, [isFetched, isError, isEmpty, data])
|
}, [isFetched, isError, isEmpty, data, feedUri])
|
||||||
|
|
||||||
// events
|
// events
|
||||||
// =
|
// =
|
||||||
|
@ -296,6 +302,8 @@ let Feed = ({
|
||||||
)
|
)
|
||||||
} else if (item === LOADING_ITEM) {
|
} else if (item === LOADING_ITEM) {
|
||||||
return <PostFeedLoadingPlaceholder />
|
return <PostFeedLoadingPlaceholder />
|
||||||
|
} else if (item === FEED_SHUTDOWN_MSG_ITEM) {
|
||||||
|
return <FeedShutdownMsg feedUri={feedUri} />
|
||||||
} else if (item.rootUri === FALLBACK_MARKER_POST.post.uri) {
|
} else if (item.rootUri === FALLBACK_MARKER_POST.post.uri) {
|
||||||
// HACK
|
// HACK
|
||||||
// tell the user we fell back to discover
|
// tell the user we fell back to discover
|
||||||
|
@ -307,6 +315,7 @@ let Feed = ({
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
feed,
|
feed,
|
||||||
|
feedUri,
|
||||||
error,
|
error,
|
||||||
onPressTryAgain,
|
onPressTryAgain,
|
||||||
onPressRetryLoadMore,
|
onPressRetryLoadMore,
|
||||||
|
|
|
@ -0,0 +1,159 @@
|
||||||
|
import React from 'react'
|
||||||
|
import {View} from 'react-native'
|
||||||
|
import {msg, Trans} from '@lingui/macro'
|
||||||
|
import {useLingui} from '@lingui/react'
|
||||||
|
|
||||||
|
import {PROD_DEFAULT_FEED} from '#/lib/constants'
|
||||||
|
import {logger} from '#/logger'
|
||||||
|
import {
|
||||||
|
useAddSavedFeedsMutation,
|
||||||
|
usePreferencesQuery,
|
||||||
|
useRemoveFeedMutation,
|
||||||
|
useUpdateSavedFeedsMutation,
|
||||||
|
} from '#/state/queries/preferences'
|
||||||
|
import {useSetSelectedFeed} from '#/state/shell/selected-feed'
|
||||||
|
import * as Toast from '#/view/com/util/Toast'
|
||||||
|
import {atoms as a, useTheme} from '#/alf'
|
||||||
|
import {Button, ButtonIcon, ButtonText} from '#/components/Button'
|
||||||
|
import {InlineLinkText} from '#/components/Link'
|
||||||
|
import {Loader} from '#/components/Loader'
|
||||||
|
import {Text} from '#/components/Typography'
|
||||||
|
|
||||||
|
export function FeedShutdownMsg({feedUri}: {feedUri: string}) {
|
||||||
|
const t = useTheme()
|
||||||
|
const {_} = useLingui()
|
||||||
|
const setSelectedFeed = useSetSelectedFeed()
|
||||||
|
const {data: preferences} = usePreferencesQuery()
|
||||||
|
const {mutateAsync: addSavedFeeds, isPending: isAddSavedFeedPending} =
|
||||||
|
useAddSavedFeedsMutation()
|
||||||
|
const {mutateAsync: removeFeed, isPending: isRemovePending} =
|
||||||
|
useRemoveFeedMutation()
|
||||||
|
const {mutateAsync: updateSavedFeeds, isPending: isUpdateFeedPending} =
|
||||||
|
useUpdateSavedFeedsMutation()
|
||||||
|
|
||||||
|
const feedConfig = preferences?.savedFeeds?.find(
|
||||||
|
f => f.value === feedUri && f.pinned,
|
||||||
|
)
|
||||||
|
const discoverFeedConfig = preferences?.savedFeeds?.find(
|
||||||
|
f => f.value === PROD_DEFAULT_FEED('whats-hot'),
|
||||||
|
)
|
||||||
|
const hasFeedPinned = Boolean(feedConfig)
|
||||||
|
const hasDiscoverPinned = Boolean(discoverFeedConfig?.pinned)
|
||||||
|
|
||||||
|
const onRemoveFeed = React.useCallback(async () => {
|
||||||
|
try {
|
||||||
|
if (feedConfig) {
|
||||||
|
await removeFeed(feedConfig)
|
||||||
|
Toast.show(_(msg`Removed from your feeds`))
|
||||||
|
}
|
||||||
|
} catch (err: any) {
|
||||||
|
Toast.show(
|
||||||
|
_(
|
||||||
|
msg`There was an an issue updating your feeds, please check your internet connection and try again.`,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
logger.error('Failed up update feeds', {message: err})
|
||||||
|
}
|
||||||
|
}, [removeFeed, feedConfig, _])
|
||||||
|
|
||||||
|
const onReplaceFeed = React.useCallback(async () => {
|
||||||
|
try {
|
||||||
|
if (!discoverFeedConfig) {
|
||||||
|
await addSavedFeeds([
|
||||||
|
{
|
||||||
|
type: 'feed',
|
||||||
|
value: PROD_DEFAULT_FEED('whats-hot'),
|
||||||
|
pinned: true,
|
||||||
|
},
|
||||||
|
])
|
||||||
|
} else {
|
||||||
|
await updateSavedFeeds([
|
||||||
|
{
|
||||||
|
...discoverFeedConfig,
|
||||||
|
pinned: true,
|
||||||
|
},
|
||||||
|
])
|
||||||
|
}
|
||||||
|
setSelectedFeed(`feedgen|${PROD_DEFAULT_FEED('whats-hot')}`)
|
||||||
|
if (feedConfig) {
|
||||||
|
await removeFeed(feedConfig)
|
||||||
|
}
|
||||||
|
Toast.show(_(msg`The feed has been replaced with Discover.`))
|
||||||
|
} catch (err: any) {
|
||||||
|
Toast.show(
|
||||||
|
_(
|
||||||
|
msg`There was an an issue updating your feeds, please check your internet connection and try again.`,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
logger.error('Failed up update feeds', {message: err})
|
||||||
|
}
|
||||||
|
}, [
|
||||||
|
addSavedFeeds,
|
||||||
|
updateSavedFeeds,
|
||||||
|
removeFeed,
|
||||||
|
discoverFeedConfig,
|
||||||
|
feedConfig,
|
||||||
|
setSelectedFeed,
|
||||||
|
_,
|
||||||
|
])
|
||||||
|
|
||||||
|
const isProcessing =
|
||||||
|
isAddSavedFeedPending || isUpdateFeedPending || isRemovePending
|
||||||
|
return (
|
||||||
|
<View
|
||||||
|
style={[
|
||||||
|
a.py_3xl,
|
||||||
|
a.px_2xl,
|
||||||
|
a.gap_xl,
|
||||||
|
t.atoms.border_contrast_low,
|
||||||
|
a.border_t,
|
||||||
|
]}>
|
||||||
|
<Text style={[a.text_5xl, a.font_bold, t.atoms.text, a.text_center]}>
|
||||||
|
:(
|
||||||
|
</Text>
|
||||||
|
<Text style={[a.text_md, a.leading_snug, t.atoms.text, a.text_center]}>
|
||||||
|
<Trans>
|
||||||
|
This feed is no longer online. We are showing{' '}
|
||||||
|
<InlineLinkText
|
||||||
|
to="/profile/bsky.app/feed/whats-hot"
|
||||||
|
style={[a.text_md]}>
|
||||||
|
Discover
|
||||||
|
</InlineLinkText>{' '}
|
||||||
|
instead.
|
||||||
|
</Trans>
|
||||||
|
</Text>
|
||||||
|
{hasFeedPinned ? (
|
||||||
|
<View style={[a.flex_row, a.justify_center, a.gap_sm]}>
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
color="primary"
|
||||||
|
size="small"
|
||||||
|
label={_(msg`Remove feed`)}
|
||||||
|
disabled={isProcessing}
|
||||||
|
onPress={onRemoveFeed}>
|
||||||
|
<ButtonText>
|
||||||
|
<Trans>Remove feed</Trans>
|
||||||
|
</ButtonText>
|
||||||
|
{isRemovePending && <ButtonIcon icon={Loader} />}
|
||||||
|
</Button>
|
||||||
|
{!hasDiscoverPinned && (
|
||||||
|
<Button
|
||||||
|
variant="solid"
|
||||||
|
color="primary"
|
||||||
|
size="small"
|
||||||
|
label={_(msg`Replace with Discover`)}
|
||||||
|
disabled={isProcessing}
|
||||||
|
onPress={onReplaceFeed}>
|
||||||
|
<ButtonText>
|
||||||
|
<Trans>Replace with Discover</Trans>
|
||||||
|
</ButtonText>
|
||||||
|
{(isAddSavedFeedPending || isUpdateFeedPending) && (
|
||||||
|
<ButtonIcon icon={Loader} />
|
||||||
|
)}
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
) : undefined}
|
||||||
|
</View>
|
||||||
|
)
|
||||||
|
}
|
Loading…
Reference in New Issue