about summary refs log tree commit diff
path: root/src/state
diff options
context:
space:
mode:
authorSamuel Newman <mozzius@protonmail.com>2024-12-17 17:13:18 +0000
committerGitHub <noreply@github.com>2024-12-17 17:13:18 +0000
commit0cbb03cd14c226bcbfd146a586d97c62a0fc4c9d (patch)
treec9053654e8d1813b6c8108bce53ac5eb883fed43 /src/state
parent32611391a35cbfe3f4a57882c117d52de022fb89 (diff)
downloadvoidsky-0cbb03cd14c226bcbfd146a586d97c62a0fc4c9d.tar.zst
New progress guide - 10 follows (#7128)
* new follow-10 progress guide

* find follows dialog

* wip tabs

* flatlist version with search

* hardcode out jake gold

* lazy load followup suggestions

* Update src/components/ProgressGuide/FollowDialog.tsx

Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>

* comment out replacing, enable paging

* rm autofocus

* find shadow profiles in paginated search

* clear search when press tabs

* better tab a11y

* fix label

* adjust scroll indicator insets

* do the same scroll indicator adjustment for searchable people list

* hardcode jake to just be 'tech'

* Retain state on close/reopen

* only change follow btn color when not followed

* add guide to inside dialog

* fix task alignment

* Enable contextual suggestions

* WIP: show multiple suggestions

* Rework so it animates well

* Show more items

* remove card style

* move tabs to own component

* split out header top

* scroll active tab into view

* rm log

* Improve perf a bit

* boost popular interests over alphabetical ones

* scroll active tab into view

* revert back to round buttons

* Fix overrenders of the tab bar items

* Fix unintended animation

* Scroll initial into view if needed

* Unlift state, the dialog thing breaks lifting

* Persist simply

* Fix empty state

* Fix incorrect gate exposure

* Fix another bad useGate

* Nit

---------

Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>
Co-authored-by: Dan Abramov <dan.abramov@gmail.com>
Diffstat (limited to 'src/state')
-rw-r--r--src/state/queries/actor-search.ts26
-rw-r--r--src/state/queries/suggested-follows.ts9
-rw-r--r--src/state/shell/progress-guide.tsx96
3 files changed, 108 insertions, 23 deletions
diff --git a/src/state/queries/actor-search.ts b/src/state/queries/actor-search.ts
index 479fc1a9f..6d6c46e04 100644
--- a/src/state/queries/actor-search.ts
+++ b/src/state/queries/actor-search.ts
@@ -1,6 +1,7 @@
 import {AppBskyActorDefs, AppBskyActorSearchActors} from '@atproto/api'
 import {
   InfiniteData,
+  keepPreviousData,
   QueryClient,
   QueryKey,
   useInfiniteQuery,
@@ -13,10 +14,8 @@ import {useAgent} from '#/state/session'
 const RQKEY_ROOT = 'actor-search'
 export const RQKEY = (query: string) => [RQKEY_ROOT, query]
 
-export const RQKEY_PAGINATED = (query: string) => [
-  `${RQKEY_ROOT}_paginated`,
-  query,
-]
+const RQKEY_ROOT_PAGINATED = `${RQKEY_ROOT}_paginated`
+export const RQKEY_PAGINATED = (query: string) => [RQKEY_ROOT_PAGINATED, query]
 
 export function useActorSearch({
   query,
@@ -42,9 +41,11 @@ export function useActorSearch({
 export function useActorSearchPaginated({
   query,
   enabled,
+  maintainData,
 }: {
   query: string
   enabled?: boolean
+  maintainData?: boolean
 }) {
   const agent = useAgent()
   return useInfiniteQuery<
@@ -67,6 +68,7 @@ export function useActorSearchPaginated({
     enabled: enabled && !!query,
     initialPageParam: undefined,
     getNextPageParam: lastPage => lastPage.cursor,
+    placeholderData: maintainData ? keepPreviousData : undefined,
   })
 }
 
@@ -89,4 +91,20 @@ export function* findAllProfilesInQueryData(
       }
     }
   }
+
+  const queryDatasPaginated = queryClient.getQueriesData<
+    InfiniteData<AppBskyActorSearchActors.OutputSchema>
+  >({
+    queryKey: [RQKEY_ROOT_PAGINATED],
+  })
+  for (const [_queryKey, queryData] of queryDatasPaginated) {
+    if (!queryData) {
+      continue
+    }
+    for (const actor of queryData.pages.flatMap(page => page.actors)) {
+      if (actor.did === did) {
+        yield actor
+      }
+    }
+  }
 }
diff --git a/src/state/queries/suggested-follows.ts b/src/state/queries/suggested-follows.ts
index 07e16946e..22033c0a8 100644
--- a/src/state/queries/suggested-follows.ts
+++ b/src/state/queries/suggested-follows.ts
@@ -103,7 +103,13 @@ export function useSuggestedFollowsQuery(options?: SuggestedFollowsOptions) {
   })
 }
 
-export function useSuggestedFollowsByActorQuery({did}: {did: string}) {
+export function useSuggestedFollowsByActorQuery({
+  did,
+  enabled,
+}: {
+  did: string
+  enabled?: boolean
+}) {
   const agent = useAgent()
   return useQuery({
     queryKey: suggestedFollowsByActorQueryKey(did),
@@ -116,6 +122,7 @@ export function useSuggestedFollowsByActorQuery({did}: {did: string}) {
         : res.data.suggestions.filter(profile => !profile.viewer?.following)
       return {suggestions}
     },
+    enabled,
   })
 }
 
diff --git a/src/state/shell/progress-guide.tsx b/src/state/shell/progress-guide.tsx
index d64e9984f..af3d60ebb 100644
--- a/src/state/shell/progress-guide.tsx
+++ b/src/state/shell/progress-guide.tsx
@@ -1,4 +1,4 @@
-import React from 'react'
+import React, {useMemo} from 'react'
 import {msg} from '@lingui/macro'
 import {useLingui} from '@lingui/react'
 
@@ -16,20 +16,32 @@ export enum ProgressGuideAction {
   Follow = 'follow',
 }
 
-type ProgressGuideName = 'like-10-and-follow-7'
+type ProgressGuideName = 'like-10-and-follow-7' | 'follow-10'
 
+/**
+ * Progress Guides that extend this interface must specify their name in the `guide` field, so it can be used as a discriminated union
+ */
 interface BaseProgressGuide {
-  guide: string
+  guide: ProgressGuideName
   isComplete: boolean
   [key: string]: any
 }
 
-interface Like10AndFollow7ProgressGuide extends BaseProgressGuide {
+export interface Like10AndFollow7ProgressGuide extends BaseProgressGuide {
+  guide: 'like-10-and-follow-7'
   numLikes: number
   numFollows: number
 }
 
-type ProgressGuide = Like10AndFollow7ProgressGuide | undefined
+export interface Follow10ProgressGuide extends BaseProgressGuide {
+  guide: 'follow-10'
+  numFollows: number
+}
+
+export type ProgressGuide =
+  | Like10AndFollow7ProgressGuide
+  | Follow10ProgressGuide
+  | undefined
 
 const ProgressGuideContext = React.createContext<ProgressGuide>(undefined)
 
@@ -61,15 +73,28 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
   const {mutateAsync, variables, isPending} =
     useSetActiveProgressGuideMutation()
 
-  const activeProgressGuide = (
-    isPending ? variables : preferences?.bskyAppState?.activeProgressGuide
-  ) as ProgressGuide
+  const activeProgressGuide = useMemo(() => {
+    const rawProgressGuide = (
+      isPending ? variables : preferences?.bskyAppState?.activeProgressGuide
+    ) as ProgressGuide
+
+    if (!rawProgressGuide) return undefined
+
+    // ensure the unspecced attributes have the correct types
+    // clone then mutate
+    const {...maybeWronglyTypedProgressGuide} = rawProgressGuide
+    if (maybeWronglyTypedProgressGuide?.guide === 'like-10-and-follow-7') {
+      maybeWronglyTypedProgressGuide.numLikes =
+        Number(maybeWronglyTypedProgressGuide.numLikes) || 0
+      maybeWronglyTypedProgressGuide.numFollows =
+        Number(maybeWronglyTypedProgressGuide.numFollows) || 0
+    } else if (maybeWronglyTypedProgressGuide?.guide === 'follow-10') {
+      maybeWronglyTypedProgressGuide.numFollows =
+        Number(maybeWronglyTypedProgressGuide.numFollows) || 0
+    }
 
-  // ensure the unspecced attributes have the correct types
-  if (activeProgressGuide?.guide === 'like-10-and-follow-7') {
-    activeProgressGuide.numLikes = Number(activeProgressGuide.numLikes) || 0
-    activeProgressGuide.numFollows = Number(activeProgressGuide.numFollows) || 0
-  }
+    return maybeWronglyTypedProgressGuide
+  }, [isPending, variables, preferences])
 
   const [localGuideState, setLocalGuideState] =
     React.useState<ProgressGuide>(undefined)
@@ -82,7 +107,9 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
   const firstLikeToastRef = React.useRef<ProgressGuideToastRef | null>(null)
   const fifthLikeToastRef = React.useRef<ProgressGuideToastRef | null>(null)
   const tenthLikeToastRef = React.useRef<ProgressGuideToastRef | null>(null)
-  const guideCompleteToastRef = React.useRef<ProgressGuideToastRef | null>(null)
+
+  const fifthFollowToastRef = React.useRef<ProgressGuideToastRef | null>(null)
+  const tenthFollowToastRef = React.useRef<ProgressGuideToastRef | null>(null)
 
   const controls = React.useMemo(() => {
     return {
@@ -93,7 +120,15 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
             numLikes: 0,
             numFollows: 0,
             isComplete: false,
-          }
+          } satisfies ProgressGuide
+          setLocalGuideState(guideObj)
+          mutateAsync(guideObj)
+        } else if (guide === 'follow-10') {
+          const guideObj = {
+            guide: 'follow-10',
+            numFollows: 0,
+            isComplete: false,
+          } satisfies ProgressGuide
           setLocalGuideState(guideObj)
           mutateAsync(guideObj)
         }
@@ -137,6 +172,26 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
               isComplete: true,
             }
           }
+        } else if (guide?.guide === 'follow-10') {
+          if (action === ProgressGuideAction.Follow) {
+            guide = {
+              ...guide,
+              numFollows: (Number(guide.numFollows) || 0) + count,
+            }
+
+            if (guide.numFollows === 5) {
+              fifthFollowToastRef.current?.open()
+            }
+            if (guide.numFollows === 10) {
+              tenthFollowToastRef.current?.open()
+            }
+          }
+          if (Number(guide.numFollows) >= 10) {
+            guide = {
+              ...guide,
+              isComplete: true,
+            }
+          }
         }
 
         setLocalGuideState(guide)
@@ -167,9 +222,14 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
               subtitle={_(msg`The Discover feed now knows what you like`)}
             />
             <ProgressGuideToast
-              ref={guideCompleteToastRef}
-              title={_(msg`Algorithm training complete!`)}
-              subtitle={_(msg`The Discover feed now knows what you like`)}
+              ref={fifthFollowToastRef}
+              title={_(msg`Half way there!`)}
+              subtitle={_(msg`Follow 10 accounts`)}
+            />
+            <ProgressGuideToast
+              ref={tenthFollowToastRef}
+              title={_(msg`Task complete - 10 follows!`)}
+              subtitle={_(msg`You've found some people to follow`)}
             />
           </>
         )}