Bluesky app fork with some witchin' additions 馃挮
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at 6982eb4fb4d44105dc8b44e898d452d4e5d32c82 161 lines 4.7 kB view raw
1import {useEffect} from 'react' 2import {type Agent, AppBskyActorDefs, asPredicate} from '@atproto/api' 3import {useMutation, useQueryClient} from '@tanstack/react-query' 4 5import {logger} from '#/logger' 6import { 7 preferencesQueryKey, 8 usePreferencesQuery, 9} from '#/state/queries/preferences' 10import {useAgent} from '#/state/session' 11import {IS_WEB} from '#/env' 12import * as env from '#/env' 13import { 14 type LiveEventFeed, 15 type LiveEventFeedMetricContext, 16} from '#/features/liveEvents/types' 17 18export type LiveEventPreferencesAction = Parameters< 19 Agent['updateLiveEventPreferences'] 20>[0] & { 21 /** 22 * Flag that is internal to this hook, do not set when updating prefs 23 */ 24 __canUndo?: boolean 25} 26 27export function useLiveEventPreferences() { 28 const query = usePreferencesQuery() 29 useWebOnlyDebugLiveEventPreferences() 30 return { 31 ...query, 32 data: query.data?.liveEventPreferences || { 33 hideAllFeeds: false, 34 hiddenFeedIds: [], 35 }, 36 } 37} 38 39function useWebOnlyDebugLiveEventPreferences() { 40 const queryClient = useQueryClient() 41 const agent = useAgent() 42 43 useEffect(() => { 44 if (env.IS_DEV && IS_WEB && typeof window !== 'undefined') { 45 // @ts-ignore 46 window.__updateLiveEventPreferences = async ( 47 action: LiveEventPreferencesAction, 48 ) => { 49 await agent.updateLiveEventPreferences(action) 50 // triggers a refetch 51 await queryClient.invalidateQueries({ 52 queryKey: preferencesQueryKey, 53 }) 54 } 55 } 56 }, [agent, queryClient]) 57} 58 59export function useUpdateLiveEventPreferences(props: { 60 feed?: LiveEventFeed 61 metricContext: LiveEventFeedMetricContext 62 onUpdateSuccess?: (props: { 63 undoAction: LiveEventPreferencesAction | null 64 }) => void 65}) { 66 const queryClient = useQueryClient() 67 const agent = useAgent() 68 69 return useMutation< 70 AppBskyActorDefs.LiveEventPreferences, 71 Error, 72 LiveEventPreferencesAction, 73 {undoAction: LiveEventPreferencesAction | null} 74 >({ 75 onSettled(data, error, variables) { 76 /* 77 * `onSettled` runs after the mutation completes, success or no. The idea 78 * here is that we want to invert the action that was just passed in, and 79 * provide it as an `undoAction` to the `onUpdateSuccess` callback. 80 * 81 * If the operation was not a success, we don't provide the `undoAction`. 82 * 83 * Upon the first call of the mutation, the `__canUndo` flag is undefined, 84 * so we allow the undo. However, when we create the `undoAction`, we 85 * set its `__canUndo` flag to false, so that if the user were to call 86 * the undo action, we would not provide another undo for that. 87 */ 88 const canUndo = variables.__canUndo === undefined ? true : false 89 let undoAction: LiveEventPreferencesAction | null = null 90 91 switch (variables.type) { 92 case 'hideFeed': 93 undoAction = {type: 'unhideFeed', id: variables.id, __canUndo: false} 94 break 95 case 'unhideFeed': 96 undoAction = {type: 'hideFeed', id: variables.id, __canUndo: false} 97 break 98 case 'toggleHideAllFeeds': 99 undoAction = {type: 'toggleHideAllFeeds', __canUndo: false} 100 break 101 } 102 103 if (data && !error) { 104 props?.onUpdateSuccess?.({ 105 undoAction: canUndo ? undoAction : null, 106 }) 107 } 108 }, 109 mutationFn: async action => { 110 const updated = await agent.updateLiveEventPreferences(action) 111 const prefs = updated.find(p => 112 asPredicate(AppBskyActorDefs.validateLiveEventPreferences)(p), 113 ) 114 115 switch (action.type) { 116 case 'hideFeed': 117 case 'unhideFeed': { 118 if (!props.feed) { 119 logger.error( 120 `useUpdateLiveEventPreferences: feed is missing, but required for hiding/unhiding`, 121 { 122 action, 123 }, 124 ) 125 break 126 } 127 128 logger.metric( 129 action.type === 'hideFeed' 130 ? 'liveEvents:feedBanner:hide' 131 : 'liveEvents:feedBanner:unhide', 132 { 133 feed: props.feed.url, 134 context: props.metricContext, 135 }, 136 ) 137 break 138 } 139 case 'toggleHideAllFeeds': { 140 if (prefs!.hideAllFeeds) { 141 logger.metric('liveEvents:hideAllFeedBanners', { 142 context: props.metricContext, 143 }) 144 } else { 145 logger.metric('liveEvents:unhideAllFeedBanners', { 146 context: props.metricContext, 147 }) 148 } 149 break 150 } 151 } 152 153 // triggers a refetch 154 queryClient.invalidateQueries({ 155 queryKey: preferencesQueryKey, 156 }) 157 158 return prefs! 159 }, 160 }) 161}