about summary refs log tree commit diff
path: root/src/state/queries/preferences/index.ts
diff options
context:
space:
mode:
authorEric Bailey <git@esb.lol>2023-11-12 13:31:11 -0600
committerGitHub <noreply@github.com>2023-11-12 11:31:11 -0800
commit05b728fffcdb17708fdb52685725faf7fdc545bc (patch)
treeb6523916d965f921d3f03d101dc60a7e74569bce /src/state/queries/preferences/index.ts
parentc8c308e31e63607280648e3e9f1f56a371adcd05 (diff)
downloadvoidsky-05b728fffcdb17708fdb52685725faf7fdc545bc.tar.zst
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>
Diffstat (limited to 'src/state/queries/preferences/index.ts')
-rw-r--r--src/state/queries/preferences/index.ts257
1 files changed, 257 insertions, 0 deletions
diff --git a/src/state/queries/preferences/index.ts b/src/state/queries/preferences/index.ts
new file mode 100644
index 000000000..d64bbd954
--- /dev/null
+++ b/src/state/queries/preferences/index.ts
@@ -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,
+      })
+    },
+  })
+}