Eric/preferences (#1873)

* Add initial preferences query, couple mutations

* Remove unused

* Clean up labels, migrate getModerationOpts

* Add birth date handling

* Migrate feed prefs

* Migrate thread view prefs

* Migrate homeFeed to use existing key name

* Fix up saved feeds in response, no impl yet

* Migrate saved feeds to new hooks

* Clean up more of preferences

* Fix PreferencesThreads load state

* Fix modal dismissal

* Small spacing fix

---------

Co-authored-by: Paul Frazee <pfrazee@gmail.com>
This commit is contained in:
Eric Bailey 2023-11-12 13:31:11 -06:00 committed by GitHub
parent c8c308e31e
commit 05b728fffc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 1339 additions and 914 deletions

View file

@ -0,0 +1,257 @@
import {useQuery, useMutation, useQueryClient} from '@tanstack/react-query'
import {LabelPreference, BskyFeedViewPreference} from '@atproto/api'
import {track} from '#/lib/analytics/analytics'
import {getAge} from '#/lib/strings/time'
import {useSession} from '#/state/session'
import {DEFAULT_LABEL_PREFERENCES} from '#/state/queries/preferences/moderation'
import {
ConfigurableLabelGroup,
UsePreferencesQueryResponse,
ThreadViewPreferences,
} from '#/state/queries/preferences/types'
import {temp__migrateLabelPref} from '#/state/queries/preferences/util'
import {
DEFAULT_HOME_FEED_PREFS,
DEFAULT_THREAD_VIEW_PREFS,
} from '#/state/queries/preferences/const'
export * from '#/state/queries/preferences/types'
export * from '#/state/queries/preferences/moderation'
export * from '#/state/queries/preferences/const'
export const usePreferencesQueryKey = ['getPreferences']
export function usePreferencesQuery() {
const {agent} = useSession()
return useQuery({
queryKey: usePreferencesQueryKey,
queryFn: async () => {
const res = await agent.getPreferences()
const preferences: UsePreferencesQueryResponse = {
...res,
feeds: {
saved: res.feeds?.saved || [],
pinned: res.feeds?.pinned || [],
unpinned:
res.feeds.saved?.filter(f => {
return !res.feeds.pinned?.includes(f)
}) || [],
},
// labels are undefined until set by user
contentLabels: {
nsfw: temp__migrateLabelPref(
res.contentLabels?.nsfw || DEFAULT_LABEL_PREFERENCES.nsfw,
),
nudity: temp__migrateLabelPref(
res.contentLabels?.nudity || DEFAULT_LABEL_PREFERENCES.nudity,
),
suggestive: temp__migrateLabelPref(
res.contentLabels?.suggestive ||
DEFAULT_LABEL_PREFERENCES.suggestive,
),
gore: temp__migrateLabelPref(
res.contentLabels?.gore || DEFAULT_LABEL_PREFERENCES.gore,
),
hate: temp__migrateLabelPref(
res.contentLabels?.hate || DEFAULT_LABEL_PREFERENCES.hate,
),
spam: temp__migrateLabelPref(
res.contentLabels?.spam || DEFAULT_LABEL_PREFERENCES.spam,
),
impersonation: temp__migrateLabelPref(
res.contentLabels?.impersonation ||
DEFAULT_LABEL_PREFERENCES.impersonation,
),
},
feedViewPrefs: {
...DEFAULT_HOME_FEED_PREFS,
...(res.feedViewPrefs.home || {}),
},
threadViewPrefs: {
...DEFAULT_THREAD_VIEW_PREFS,
...(res.threadViewPrefs ?? {}),
},
userAge: res.birthDate ? getAge(res.birthDate) : undefined,
}
return preferences
},
})
}
export function useClearPreferencesMutation() {
const {agent} = useSession()
const queryClient = useQueryClient()
return useMutation({
mutationFn: async () => {
await agent.app.bsky.actor.putPreferences({preferences: []})
// triggers a refetch
await queryClient.invalidateQueries({
queryKey: usePreferencesQueryKey,
})
},
})
}
export function usePreferencesSetContentLabelMutation() {
const {agent} = useSession()
const queryClient = useQueryClient()
return useMutation<
void,
unknown,
{labelGroup: ConfigurableLabelGroup; visibility: LabelPreference}
>({
mutationFn: async ({labelGroup, visibility}) => {
await agent.setContentLabelPref(labelGroup, visibility)
// triggers a refetch
await queryClient.invalidateQueries({
queryKey: usePreferencesQueryKey,
})
},
})
}
export function usePreferencesSetAdultContentMutation() {
const {agent} = useSession()
const queryClient = useQueryClient()
return useMutation<void, unknown, {enabled: boolean}>({
mutationFn: async ({enabled}) => {
await agent.setAdultContentEnabled(enabled)
// triggers a refetch
await queryClient.invalidateQueries({
queryKey: usePreferencesQueryKey,
})
},
})
}
export function usePreferencesSetBirthDateMutation() {
const {agent} = useSession()
const queryClient = useQueryClient()
return useMutation<void, unknown, {birthDate: Date}>({
mutationFn: async ({birthDate}: {birthDate: Date}) => {
await agent.setPersonalDetails({birthDate})
// triggers a refetch
await queryClient.invalidateQueries({
queryKey: usePreferencesQueryKey,
})
},
})
}
export function useSetFeedViewPreferencesMutation() {
const {agent} = useSession()
const queryClient = useQueryClient()
return useMutation<void, unknown, Partial<BskyFeedViewPreference>>({
mutationFn: async prefs => {
await agent.setFeedViewPrefs('home', prefs)
// triggers a refetch
await queryClient.invalidateQueries({
queryKey: usePreferencesQueryKey,
})
},
})
}
export function useSetThreadViewPreferencesMutation() {
const {agent} = useSession()
const queryClient = useQueryClient()
return useMutation<void, unknown, Partial<ThreadViewPreferences>>({
mutationFn: async prefs => {
await agent.setThreadViewPrefs(prefs)
// triggers a refetch
await queryClient.invalidateQueries({
queryKey: usePreferencesQueryKey,
})
},
})
}
export function useSetSaveFeedsMutation() {
const {agent} = useSession()
const queryClient = useQueryClient()
return useMutation<
void,
unknown,
Pick<UsePreferencesQueryResponse['feeds'], 'saved' | 'pinned'>
>({
mutationFn: async ({saved, pinned}) => {
await agent.setSavedFeeds(saved, pinned)
// triggers a refetch
await queryClient.invalidateQueries({
queryKey: usePreferencesQueryKey,
})
},
})
}
export function useSaveFeedMutation() {
const {agent} = useSession()
const queryClient = useQueryClient()
return useMutation<void, unknown, {uri: string}>({
mutationFn: async ({uri}) => {
await agent.addSavedFeed(uri)
track('CustomFeed:Save')
// triggers a refetch
await queryClient.invalidateQueries({
queryKey: usePreferencesQueryKey,
})
},
})
}
export function useRemoveFeedMutation() {
const {agent} = useSession()
const queryClient = useQueryClient()
return useMutation<void, unknown, {uri: string}>({
mutationFn: async ({uri}) => {
await agent.removeSavedFeed(uri)
track('CustomFeed:Unsave')
// triggers a refetch
await queryClient.invalidateQueries({
queryKey: usePreferencesQueryKey,
})
},
})
}
export function usePinFeedMutation() {
const {agent} = useSession()
const queryClient = useQueryClient()
return useMutation<void, unknown, {uri: string}>({
mutationFn: async ({uri}) => {
await agent.addPinnedFeed(uri)
track('CustomFeed:Pin', {uri})
// triggers a refetch
await queryClient.invalidateQueries({
queryKey: usePreferencesQueryKey,
})
},
})
}
export function useUnpinFeedMutation() {
const {agent} = useSession()
const queryClient = useQueryClient()
return useMutation<void, unknown, {uri: string}>({
mutationFn: async ({uri}) => {
await agent.removePinnedFeed(uri)
track('CustomFeed:Unpin', {uri})
// triggers a refetch
await queryClient.invalidateQueries({
queryKey: usePreferencesQueryKey,
})
},
})
}