diff --git a/src/lib/constants.ts b/src/lib/constants.ts index 85e48922bb..4457b69798 100644 --- a/src/lib/constants.ts +++ b/src/lib/constants.ts @@ -1,6 +1,5 @@ import {Insets, Platform} from 'react-native' import {AppBskyActorDefs} from '@atproto/api' -import {TID} from '@atproto/common-web' export const LOCAL_DEV_SERVICE = Platform.OS === 'android' ? 'http://10.0.2.2:2583' : 'http://localhost:2583' @@ -95,15 +94,16 @@ export const BSKY_FEED_OWNER_DIDS = [ export const DISCOVER_FEED_URI = 'at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.generator/whats-hot' -export const RECOMMENDED_SAVED_FEEDS: AppBskyActorDefs.SavedFeed[] = [ +export const RECOMMENDED_SAVED_FEEDS: Pick< + AppBskyActorDefs.SavedFeed, + 'type' | 'value' | 'pinned' +>[] = [ { - id: TID.nextStr(), type: 'feed', value: DISCOVER_FEED_URI, pinned: true, }, { - id: TID.nextStr(), type: 'timeline', value: 'home', pinned: true, diff --git a/src/screens/Feeds/NoFollowingFeed.tsx b/src/screens/Feeds/NoFollowingFeed.tsx index ec80209316..f0a8ab2065 100644 --- a/src/screens/Feeds/NoFollowingFeed.tsx +++ b/src/screens/Feeds/NoFollowingFeed.tsx @@ -3,7 +3,7 @@ import {View} from 'react-native' import {msg, Trans} from '@lingui/macro' import {useLingui} from '@lingui/react' -import {useAddSavedFeedMutation} from '#/state/queries/preferences' +import {useAddSavedFeedsMutation} from '#/state/queries/preferences' import {atoms as a, useTheme} from '#/alf' import {InlineLinkText} from '#/components/Link' import {Text} from '#/components/Typography' @@ -11,22 +11,24 @@ import {Text} from '#/components/Typography' export function NoFollowingFeed() { const t = useTheme() const {_} = useLingui() - const {mutateAsync: addSavedFeed} = useAddSavedFeedMutation() + const {mutateAsync: addSavedFeeds} = useAddSavedFeedsMutation() const addRecommendedFeeds = React.useCallback( (e: any) => { e.preventDefault() - addSavedFeed({ - type: 'timeline', - value: 'home', - pinned: true, - }) + addSavedFeeds([ + { + type: 'timeline', + value: 'home', + pinned: true, + }, + ]) // prevent navigation return false }, - [addSavedFeed], + [addSavedFeeds], ) return ( diff --git a/src/screens/Feeds/NoSavedFeeds.tsx b/src/screens/Feeds/NoSavedFeeds.tsx index 2dbc6b5d99..d9a593f06c 100644 --- a/src/screens/Feeds/NoSavedFeeds.tsx +++ b/src/screens/Feeds/NoSavedFeeds.tsx @@ -4,7 +4,7 @@ import {msg, Trans} from '@lingui/macro' import {useLingui} from '@lingui/react' import {RECOMMENDED_SAVED_FEEDS} from '#/lib/constants' -import {useSetSaveFeedsMutation} from '#/state/queries/preferences' +import {useAddSavedFeedsMutation} from '#/state/queries/preferences' import {atoms as a, useTheme} from '#/alf' import {Button, ButtonIcon, ButtonText} from '#/components/Button' import {PlusLarge_Stroke2_Corner0_Rounded as Plus} from '#/components/icons/Plus' @@ -13,11 +13,11 @@ import {Text} from '#/components/Typography' export function NoSavedFeeds() { const t = useTheme() const {_} = useLingui() - const {isPending, mutateAsync: setSavedFeeds} = useSetSaveFeedsMutation() + const {isPending, mutateAsync: addSavedFeeds} = useAddSavedFeedsMutation() const addRecommendedFeeds = React.useCallback(async () => { - await setSavedFeeds(RECOMMENDED_SAVED_FEEDS) - }, [setSavedFeeds]) + await addSavedFeeds(RECOMMENDED_SAVED_FEEDS) + }, [addSavedFeeds]) return ( { - await setSavedFeeds(RECOMMENDED_SAVED_FEEDS) - }, [setSavedFeeds]) + await addSavedFeeds(RECOMMENDED_SAVED_FEEDS) + }, [addSavedFeeds]) return ( diff --git a/src/screens/Onboarding/StepFinished.tsx b/src/screens/Onboarding/StepFinished.tsx index b4a28c3084..30e8820e6a 100644 --- a/src/screens/Onboarding/StepFinished.tsx +++ b/src/screens/Onboarding/StepFinished.tsx @@ -1,6 +1,5 @@ import React from 'react' import {View} from 'react-native' -import {TID} from '@atproto/common-web' import {msg, Trans} from '@lingui/macro' import {useLingui} from '@lingui/react' @@ -8,7 +7,7 @@ import {useAnalytics} from '#/lib/analytics/analytics' import {BSKY_APP_ACCOUNT_DID} from '#/lib/constants' import {logEvent} from '#/lib/statsig/statsig' import {logger} from '#/logger' -import {useSetSaveFeedsMutation} from '#/state/queries/preferences' +import {useAddSavedFeedsMutation} from '#/state/queries/preferences' import {getAgent} from '#/state/session' import {useOnboardingDispatch} from '#/state/shell' import { @@ -38,7 +37,7 @@ export function StepFinished() { const {state, dispatch} = React.useContext(Context) const onboardDispatch = useOnboardingDispatch() const [saving, setSaving] = React.useState(false) - const {mutateAsync: saveFeeds} = useSetSaveFeedsMutation() + const {mutateAsync: addSavedFeeds} = useAddSavedFeedsMutation() const finishOnboarding = React.useCallback(async () => { setSaving(true) @@ -63,9 +62,8 @@ export function StepFinished() { // these must be serial (async () => { await getAgent().setInterestsPref({tags: selectedInterests}) - await saveFeeds( + await addSavedFeeds( selectedFeeds.map(f => ({ - id: TID.nextStr(), type: 'feed', value: f, pinned: true, @@ -85,7 +83,7 @@ export function StepFinished() { track('OnboardingV2:StepFinished:End') track('OnboardingV2:Complete') logEvent('onboarding:finished:nextPressed', {}) - }, [state, dispatch, onboardDispatch, setSaving, saveFeeds, track]) + }, [state, dispatch, onboardDispatch, setSaving, addSavedFeeds, track]) React.useEffect(() => { track('OnboardingV2:StepFinished:Start') diff --git a/src/screens/Signup/state.ts b/src/screens/Signup/state.ts index 9e4ab32c07..8d7616844c 100644 --- a/src/screens/Signup/state.ts +++ b/src/screens/Signup/state.ts @@ -15,7 +15,7 @@ import {getAge} from '#/lib/strings/time' import {logger} from '#/logger' import { DEFAULT_PROD_FEED, - useAddSavedFeedMutation, + useAddSavedFeedsMutation, usePreferencesSetBirthDateMutation, } from '#/state/queries/preferences' import {useSessionApi} from '#/state/session' @@ -208,7 +208,7 @@ export function useSubmitSignup({ const {_} = useLingui() const {createAccount} = useSessionApi() const {mutateAsync: setBirthDate} = usePreferencesSetBirthDateMutation() - const {mutate: addSavedFeed} = useAddSavedFeedMutation() + const {mutate: addSavedFeeds} = useAddSavedFeedsMutation() const onboardingDispatch = useOnboardingDispatch() return useCallback( @@ -266,7 +266,7 @@ export function useSubmitSignup({ }) await setBirthDate({birthDate: state.dateOfBirth}) if (IS_PROD_SERVICE(state.serviceUrl)) { - addSavedFeed(DEFAULT_PROD_FEED) + addSavedFeeds([DEFAULT_PROD_FEED]) } } catch (e: any) { onboardingDispatch({type: 'skip'}) // undo starting the onboard @@ -314,7 +314,7 @@ export function useSubmitSignup({ onboardingDispatch, createAccount, setBirthDate, - addSavedFeed, + addSavedFeeds, ], ) } diff --git a/src/state/queries/preferences/index.ts b/src/state/queries/preferences/index.ts index d719660e60..703a69c728 100644 --- a/src/state/queries/preferences/index.ts +++ b/src/state/queries/preferences/index.ts @@ -232,16 +232,16 @@ export function useSetSaveFeedsMutation() { }) } -export function useAddSavedFeedMutation() { +export function useAddSavedFeedsMutation() { const queryClient = useQueryClient() return useMutation< void, unknown, - Pick + Pick[] >({ - mutationFn: async savedFeed => { - await getAgent().addSavedFeedV2(savedFeed) + mutationFn: async savedFeeds => { + await getAgent().addSavedFeeds(savedFeeds) track('CustomFeed:Save') // triggers a refetch await queryClient.invalidateQueries({ @@ -255,8 +255,8 @@ export function useRemoveFeedMutation() { const queryClient = useQueryClient() return useMutation>({ - mutationFn: async ({id}) => { - await getAgent().removeSavedFeedV2(id) + mutationFn: async savedFeed => { + await getAgent().removeSavedFeeds([savedFeed.id]) track('CustomFeed:Unsave') // triggers a refetch await queryClient.invalidateQueries({ diff --git a/src/view/com/feeds/FeedSourceCard.tsx b/src/view/com/feeds/FeedSourceCard.tsx index 3ce1e57dc6..fbdea7277d 100644 --- a/src/view/com/feeds/FeedSourceCard.tsx +++ b/src/view/com/feeds/FeedSourceCard.tsx @@ -8,7 +8,7 @@ import {useLingui} from '@lingui/react' import {logger} from '#/logger' import {FeedSourceInfo, useFeedSourceInfoQuery} from '#/state/queries/feed' import { - useAddSavedFeedMutation, + useAddSavedFeedsMutation, usePreferencesQuery, UsePreferencesQueryResponse, useRemoveFeedMutation, @@ -89,8 +89,8 @@ export function FeedSourceCardLoaded({ const removePromptControl = Prompt.usePromptControl() const navigation = useNavigationDeduped() - const {isPending: isAddSavedFeedPending, mutateAsync: addSavedFeed} = - useAddSavedFeedMutation() + const {isPending: isAddSavedFeedPending, mutateAsync: addSavedFeeds} = + useAddSavedFeedsMutation() const {isPending: isRemovePending, mutateAsync: removeFeed} = useRemoveFeedMutation() @@ -103,17 +103,19 @@ export function FeedSourceCardLoaded({ if (!feed) return try { - await addSavedFeed({ - type: 'feed', - value: feed.uri, - pinned: pinOnSave, - }) + await addSavedFeeds([ + { + type: 'feed', + value: feed.uri, + pinned: pinOnSave, + }, + ]) Toast.show(_(msg`Added to my feeds`)) } catch (e) { Toast.show(_(msg`There was an issue contacting your server`)) logger.error('Failed to save feed', {message: e}) } - }, [_, feed, pinOnSave, addSavedFeed]) + }, [_, feed, pinOnSave, addSavedFeeds]) const onUnsave = React.useCallback(async () => { if (!savedFeedConfig) return diff --git a/src/view/screens/ProfileFeed.tsx b/src/view/screens/ProfileFeed.tsx index fea270a972..9189864445 100644 --- a/src/view/screens/ProfileFeed.tsx +++ b/src/view/screens/ProfileFeed.tsx @@ -15,7 +15,7 @@ import {useLikeMutation, useUnlikeMutation} from '#/state/queries/like' import {FeedDescriptor} from '#/state/queries/post-feed' import {RQKEY as FEED_RQKEY} from '#/state/queries/post-feed' import { - useAddSavedFeedMutation, + useAddSavedFeedsMutation, usePreferencesQuery, UsePreferencesQueryResponse, useRemoveFeedMutation, @@ -162,8 +162,8 @@ export function ProfileFeedScreenInner({ const feedSectionRef = React.useRef(null) const isScreenFocused = useIsFocused() - const {mutateAsync: addSavedFeed, isPending: isAddSavedFeedPending} = - useAddSavedFeedMutation() + const {mutateAsync: addSavedFeeds, isPending: isAddSavedFeedPending} = + useAddSavedFeedsMutation() const {mutateAsync: removeFeed, isPending: isRemovePending} = useRemoveFeedMutation() const {mutateAsync: updateFeed, isPending: isUpdateFeedPending} = @@ -193,11 +193,13 @@ export function ProfileFeedScreenInner({ Toast.show(_(msg`Removed from your feeds`)) } } else { - await addSavedFeed({ - type: 'feed', - value: feedInfo.uri, - pinned: false, - }) + await addSavedFeeds([ + { + type: 'feed', + value: feedInfo.uri, + pinned: false, + }, + ]) Toast.show(_(msg`Saved to your feeds`)) } } catch (err) { @@ -208,7 +210,7 @@ export function ProfileFeedScreenInner({ ) logger.error('Failed up update feeds', {message: err}) } - }, [_, playHaptic, feedInfo, removeFeed, addSavedFeed, savedFeedConfig]) + }, [_, playHaptic, feedInfo, removeFeed, addSavedFeeds, savedFeedConfig]) const onTogglePinned = React.useCallback(async () => { try { @@ -227,17 +229,19 @@ export function ProfileFeedScreenInner({ }) } } else { - await addSavedFeed({ - type: 'feed', - value: feedInfo.uri, - pinned: true, - }) + await addSavedFeeds([ + { + type: 'feed', + value: feedInfo.uri, + pinned: true, + }, + ]) } } catch (e) { Toast.show(_(msg`There was an issue contacting the server`)) logger.error('Failed to toggle pinned feed', {message: e}) } - }, [playHaptic, feedInfo, _, savedFeedConfig, updateFeed, addSavedFeed]) + }, [playHaptic, feedInfo, _, savedFeedConfig, updateFeed, addSavedFeeds]) const onPressShare = React.useCallback(() => { const url = toShareUrl(feedInfo.route.href) diff --git a/src/view/screens/ProfileList.tsx b/src/view/screens/ProfileList.tsx index 62f880fb29..5f7f5f3afb 100644 --- a/src/view/screens/ProfileList.tsx +++ b/src/view/screens/ProfileList.tsx @@ -23,7 +23,7 @@ import { import {FeedDescriptor} from '#/state/queries/post-feed' import {RQKEY as FEED_RQKEY} from '#/state/queries/post-feed' import { - useAddSavedFeedMutation, + useAddSavedFeedsMutation, usePreferencesQuery, useRemoveFeedMutation, } from '#/state/queries/preferences' @@ -251,8 +251,8 @@ function Header({rkey, list}: {rkey: string; list: AppBskyGraphDefs.ListView}) { const {track} = useAnalytics() const playHaptic = useHaptics() - const {mutateAsync: addSavedFeed, isPending: isAddSavedFeedPending} = - useAddSavedFeedMutation() + const {mutateAsync: addSavedFeeds, isPending: isAddSavedFeedPending} = + useAddSavedFeedsMutation() const {mutateAsync: removeSavedFeed, isPending: isRemovePending} = useRemoveFeedMutation() @@ -276,18 +276,20 @@ function Header({rkey, list}: {rkey: string; list: AppBskyGraphDefs.ListView}) { await removeSavedFeed(savedFeedConfig) Toast.show(_(msg`Removed from your feeds`)) } else { - await addSavedFeed({ - type: 'list', - value: list.uri, - pinned: true, - }) + await addSavedFeeds([ + { + type: 'list', + value: list.uri, + pinned: true, + }, + ]) Toast.show(_(msg`Saved to your feeds`)) } } catch (e) { Toast.show(_(msg`There was an issue contacting the server`)) logger.error('Failed to toggle pinned feed', {message: e}) } - }, [playHaptic, addSavedFeed, removeSavedFeed, list.uri, _, savedFeedConfig]) + }, [playHaptic, addSavedFeeds, removeSavedFeed, list.uri, _, savedFeedConfig]) const onSubscribeMute = useCallback(async () => { try {