about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/screens/Signup/StepInfo/index.tsx16
-rw-r--r--src/screens/Signup/index.tsx63
-rw-r--r--src/screens/Signup/state.ts2
-rw-r--r--src/screens/StarterPack/StarterPackScreen.tsx152
-rw-r--r--src/state/queries/starter-packs.ts20
-rw-r--r--src/state/shell/logged-out.tsx20
6 files changed, 142 insertions, 131 deletions
diff --git a/src/screens/Signup/StepInfo/index.tsx b/src/screens/Signup/StepInfo/index.tsx
index 4104b79b3..ea10d4365 100644
--- a/src/screens/Signup/StepInfo/index.tsx
+++ b/src/screens/Signup/StepInfo/index.tsx
@@ -1,5 +1,5 @@
-import React from 'react'
-import {View} from 'react-native'
+import React, {useEffect} from 'react'
+import {LayoutAnimation, View} from 'react-native'
 import {msg, Trans} from '@lingui/macro'
 import {useLingui} from '@lingui/react'
 
@@ -27,10 +27,18 @@ function sanitizeDate(date: Date): Date {
   return date
 }
 
-export function StepInfo() {
+export function StepInfo({
+  isLoadingStarterPack,
+}: {
+  isLoadingStarterPack: boolean
+}) {
   const {_} = useLingui()
   const {state, dispatch} = useSignupContext()
 
+  useEffect(() => {
+    LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut)
+  }, [state.isLoading, isLoadingStarterPack])
+
   return (
     <ScreenTransition>
       <View style={[a.gap_md]}>
@@ -46,7 +54,7 @@ export function StepInfo() {
             }
           />
         </View>
-        {state.isLoading ? (
+        {state.isLoading || isLoadingStarterPack ? (
           <View style={[a.align_center]}>
             <Loader size="xl" />
           </View>
diff --git a/src/screens/Signup/index.tsx b/src/screens/Signup/index.tsx
index 3203d443c..2ccb38846 100644
--- a/src/screens/Signup/index.tsx
+++ b/src/screens/Signup/index.tsx
@@ -1,10 +1,6 @@
 import React from 'react'
 import {View} from 'react-native'
-import Animated, {
-  FadeIn,
-  FadeOut,
-  LayoutAnimationConfig,
-} from 'react-native-reanimated'
+import {LayoutAnimationConfig} from 'react-native-reanimated'
 import {AppBskyGraphStarterpack} from '@atproto/api'
 import {msg, Trans} from '@lingui/macro'
 import {useLingui} from '@lingui/react'
@@ -47,9 +43,15 @@ export function Signup({onPressBack}: {onPressBack: () => void}) {
   const agent = useAgent()
 
   const activeStarterPack = useActiveStarterPack()
-  const {data: starterPack} = useStarterPackQuery({
+  const {
+    data: starterPack,
+    isFetching: isFetchingStarterPack,
+    isError: isErrorStarterPack,
+  } = useStarterPackQuery({
     uri: activeStarterPack?.uri,
   })
+  const showStarterPackCard =
+    activeStarterPack?.uri && !isFetchingStarterPack && starterPack
 
   const {
     data: serviceInfo,
@@ -155,30 +157,27 @@ export function Signup({onPressBack}: {onPressBack: () => void}) {
         description={_(msg`We're so excited to have you join us!`)}
         scrollable>
         <View testID="createAccount" style={a.flex_1}>
-          {state.activeStep === SignupStep.INFO &&
-          starterPack &&
+          {showStarterPackCard &&
           AppBskyGraphStarterpack.isRecord(starterPack.record) ? (
-            <Animated.View entering={FadeIn} exiting={FadeOut}>
-              <LinearGradientBackground
-                style={[a.mx_lg, a.p_lg, a.gap_sm, a.rounded_sm]}>
-                <Text style={[a.font_bold, a.text_xl, {color: 'white'}]}>
-                  {starterPack.record.name}
-                </Text>
-                <Text style={[{color: 'white'}]}>
-                  {starterPack.feeds?.length ? (
-                    <Trans>
-                      You'll follow the suggested users and feeds once you
-                      finish creating your account!
-                    </Trans>
-                  ) : (
-                    <Trans>
-                      You'll follow the suggested users once you finish creating
-                      your account!
-                    </Trans>
-                  )}
-                </Text>
-              </LinearGradientBackground>
-            </Animated.View>
+            <LinearGradientBackground
+              style={[a.mx_lg, a.p_lg, a.gap_sm, a.rounded_sm]}>
+              <Text style={[a.font_bold, a.text_xl, {color: 'white'}]}>
+                {starterPack.record.name}
+              </Text>
+              <Text style={[{color: 'white'}]}>
+                {starterPack.feeds?.length ? (
+                  <Trans>
+                    You'll follow the suggested users and feeds once you finish
+                    creating your account!
+                  </Trans>
+                ) : (
+                  <Trans>
+                    You'll follow the suggested users once you finish creating
+                    your account!
+                  </Trans>
+                )}
+              </Text>
+            </LinearGradientBackground>
           ) : null}
           <View
             style={[
@@ -211,7 +210,11 @@ export function Signup({onPressBack}: {onPressBack: () => void}) {
             <View style={[a.pb_3xl]}>
               <LayoutAnimationConfig skipEntering skipExiting>
                 {state.activeStep === SignupStep.INFO ? (
-                  <StepInfo />
+                  <StepInfo
+                    isLoadingStarterPack={
+                      isFetchingStarterPack && !isErrorStarterPack
+                    }
+                  />
                 ) : state.activeStep === SignupStep.HANDLE ? (
                   <StepHandle />
                 ) : (
diff --git a/src/screens/Signup/state.ts b/src/screens/Signup/state.ts
index 87700cb88..70b74a930 100644
--- a/src/screens/Signup/state.ts
+++ b/src/screens/Signup/state.ts
@@ -116,8 +116,6 @@ export function reducer(s: SignupState, a: SignupAction): SignupState {
       break
     }
     case 'setServiceDescription': {
-      LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut)
-
       next.serviceDescription = a.value
       next.userDomain = a.value?.availableUserDomains[0] ?? ''
       next.isLoading = false
diff --git a/src/screens/StarterPack/StarterPackScreen.tsx b/src/screens/StarterPack/StarterPackScreen.tsx
index 679b3f2cb..12b36f43c 100644
--- a/src/screens/StarterPack/StarterPackScreen.tsx
+++ b/src/screens/StarterPack/StarterPackScreen.tsx
@@ -28,10 +28,7 @@ import {HITSLOP_20} from 'lib/constants'
 import {makeProfileLink, makeStarterPackLink} from 'lib/routes/links'
 import {CommonNavigatorParams, NavigationProp} from 'lib/routes/types'
 import {logEvent} from 'lib/statsig/statsig'
-import {
-  createStarterPackUri,
-  getStarterPackOgCard,
-} from 'lib/strings/starter-pack'
+import {getStarterPackOgCard} from 'lib/strings/starter-pack'
 import {isWeb} from 'platform/detection'
 import {updateProfileShadow} from 'state/cache/profile-shadow'
 import {useModerationOpts} from 'state/preferences/moderation-opts'
@@ -41,6 +38,7 @@ import {useResolveDidQuery} from 'state/queries/resolve-uri'
 import {useShortenLink} from 'state/queries/shorten-link'
 import {useStarterPackQuery} from 'state/queries/starter-packs'
 import {useAgent, useSession} from 'state/session'
+import {useLoggedOutViewControls} from 'state/shell/logged-out'
 import {useSetActiveStarterPack} from 'state/shell/starter-pack'
 import * as Toast from '#/view/com/util/Toast'
 import {PagerWithHeader} from 'view/com/pager/PagerWithHeader'
@@ -78,7 +76,7 @@ type StarterPackScreenShortProps = NativeStackScreenProps<
 >
 
 export function StarterPackScreen({route}: StarterPackScreeProps) {
-  return <StarterPackAuthCheck routeParams={route.params} />
+  return <StarterPackScreenInner routeParams={route.params} />
 }
 
 export function StarterPackScreenShort({route}: StarterPackScreenShortProps) {
@@ -101,37 +99,7 @@ export function StarterPackScreenShort({route}: StarterPackScreenShortProps) {
       />
     )
   }
-  return <StarterPackAuthCheck routeParams={resolvedStarterPack} />
-}
-
-export function StarterPackAuthCheck({
-  routeParams,
-}: {
-  routeParams: StarterPackScreeProps['route']['params']
-}) {
-  const navigation = useNavigation<NavigationProp>()
-  const setActiveStarterPack = useSetActiveStarterPack()
-  const {currentAccount} = useSession()
-
-  React.useEffect(() => {
-    if (currentAccount) return
-
-    const uri = createStarterPackUri({
-      did: routeParams.name,
-      rkey: routeParams.rkey,
-    })
-
-    if (!uri) return
-    setActiveStarterPack({
-      uri,
-    })
-
-    navigation.goBack()
-  }, [routeParams, currentAccount, navigation, setActiveStarterPack])
-
-  if (!currentAccount) return null
-
-  return <StarterPackScreenInner routeParams={routeParams} />
+  return <StarterPackScreenInner routeParams={resolvedStarterPack} />
 }
 
 export function StarterPackScreenInner({
@@ -330,9 +298,11 @@ function Header({
 }) {
   const {_} = useLingui()
   const t = useTheme()
-  const {currentAccount} = useSession()
+  const {currentAccount, hasSession} = useSession()
   const agent = useAgent()
   const queryClient = useQueryClient()
+  const setActiveStarterPack = useSetActiveStarterPack()
+  const {requestSwitchToAccount} = useLoggedOutViewControls()
 
   const [isProcessing, setIsProcessing] = React.useState(false)
 
@@ -340,6 +310,29 @@ function Header({
   const isOwn = creator?.did === currentAccount?.did
   const joinedAllTimeCount = starterPack.joinedAllTimeCount ?? 0
 
+  const navigation = useNavigation<NavigationProp>()
+
+  React.useEffect(() => {
+    const onFocus = () => {
+      if (hasSession) return
+      setActiveStarterPack({
+        uri: starterPack.uri,
+      })
+    }
+    const onBeforeRemove = () => {
+      if (hasSession) return
+      setActiveStarterPack(undefined)
+    }
+
+    navigation.addListener('focus', onFocus)
+    navigation.addListener('beforeRemove', onBeforeRemove)
+
+    return () => {
+      navigation.removeListener('focus', onFocus)
+      navigation.removeListener('beforeRemove', onBeforeRemove)
+    }
+  }, [hasSession, navigation, setActiveStarterPack, starterPack.uri])
+
   const onFollowAll = async () => {
     if (!starterPack.list) return
 
@@ -397,44 +390,63 @@ function Header({
         avatar={undefined}
         creator={creator}
         avatarType="starter-pack">
-        <View style={[a.flex_row, a.gap_sm, a.align_center]}>
-          {isOwn ? (
-            <Button
-              label={_(msg`Share this starter pack`)}
-              hitSlop={HITSLOP_20}
-              variant="solid"
-              color="primary"
-              size="small"
-              onPress={onOpenShareDialog}>
-              <ButtonText>
-                <Trans>Share</Trans>
-              </ButtonText>
-            </Button>
-          ) : (
+        {hasSession ? (
+          <View style={[a.flex_row, a.gap_sm, a.align_center]}>
+            {isOwn ? (
+              <Button
+                label={_(msg`Share this starter pack`)}
+                hitSlop={HITSLOP_20}
+                variant="solid"
+                color="primary"
+                size="small"
+                onPress={onOpenShareDialog}>
+                <ButtonText>
+                  <Trans>Share</Trans>
+                </ButtonText>
+              </Button>
+            ) : (
+              <Button
+                label={_(msg`Follow all`)}
+                variant="solid"
+                color="primary"
+                size="small"
+                disabled={isProcessing}
+                onPress={onFollowAll}>
+                <ButtonText>
+                  <Trans>Follow all</Trans>
+                  {isProcessing && <Loader size="xs" />}
+                </ButtonText>
+              </Button>
+            )}
+            <OverflowMenu
+              routeParams={routeParams}
+              starterPack={starterPack}
+              onOpenShareDialog={onOpenShareDialog}
+            />
+          </View>
+        ) : null}
+      </ProfileSubpageHeader>
+      {!hasSession || richText || joinedAllTimeCount >= 25 ? (
+        <View style={[a.px_lg, a.pt_md, a.pb_sm, a.gap_md]}>
+          {richText ? (
+            <RichText value={richText} style={[a.text_md, a.leading_snug]} />
+          ) : null}
+          {!hasSession ? (
             <Button
-              label={_(msg`Follow all`)}
+              label={_(msg`Join Bluesky`)}
+              onPress={() => {
+                setActiveStarterPack({
+                  uri: starterPack.uri,
+                })
+                requestSwitchToAccount({requestedAccount: 'new'})
+              }}
               variant="solid"
               color="primary"
-              size="small"
-              disabled={isProcessing}
-              onPress={onFollowAll}>
-              <ButtonText>
-                <Trans>Follow all</Trans>
-                {isProcessing && <Loader size="xs" />}
+              size="medium">
+              <ButtonText style={[a.text_lg]}>
+                <Trans>Join Bluesky</Trans>
               </ButtonText>
             </Button>
-          )}
-          <OverflowMenu
-            routeParams={routeParams}
-            starterPack={starterPack}
-            onOpenShareDialog={onOpenShareDialog}
-          />
-        </View>
-      </ProfileSubpageHeader>
-      {richText || joinedAllTimeCount >= 25 ? (
-        <View style={[a.px_lg, a.pt_md, a.pb_sm, a.gap_md]}>
-          {richText ? (
-            <RichText value={richText} style={[a.text_md, a.leading_snug]} />
           ) : null}
           {joinedAllTimeCount >= 25 ? (
             <View style={[a.flex_row, a.align_center, a.gap_sm]}>
diff --git a/src/state/queries/starter-packs.ts b/src/state/queries/starter-packs.ts
index c279b6dc4..f441a8ed2 100644
--- a/src/state/queries/starter-packs.ts
+++ b/src/state/queries/starter-packs.ts
@@ -25,13 +25,22 @@ import {
   parseStarterPackUri,
 } from 'lib/strings/starter-pack'
 import {invalidateActorStarterPacksQuery} from 'state/queries/actor-starter-packs'
+import {STALE} from 'state/queries/index'
 import {invalidateListMembersQuery} from 'state/queries/list-members'
 import {useAgent} from 'state/session'
 
 const RQKEY_ROOT = 'starter-pack'
-const RQKEY = (did?: string, rkey?: string) => {
-  if (did?.startsWith('https://') || did?.startsWith('at://')) {
-    const parsed = parseStarterPackUri(did)
+const RQKEY = ({
+  uri,
+  did,
+  rkey,
+}: {
+  uri?: string
+  did?: string
+  rkey?: string
+}) => {
+  if (uri?.startsWith('https://') || uri?.startsWith('at://')) {
+    const parsed = parseStarterPackUri(uri)
     return [RQKEY_ROOT, parsed?.name, parsed?.rkey]
   } else {
     return [RQKEY_ROOT, did, rkey]
@@ -50,7 +59,7 @@ export function useStarterPackQuery({
   const agent = useAgent()
 
   return useQuery<StarterPackView>({
-    queryKey: RQKEY(did, rkey),
+    queryKey: RQKEY(uri ? {uri} : {did, rkey}),
     queryFn: async () => {
       if (!uri) {
         uri = `at://${did}/app.bsky.graph.starterpack/${rkey}`
@@ -64,6 +73,7 @@ export function useStarterPackQuery({
       return res.data.starterPack
     },
     enabled: Boolean(uri) || Boolean(did && rkey),
+    staleTime: STALE.MINUTES.FIVE,
   })
 }
 
@@ -76,7 +86,7 @@ export async function invalidateStarterPack({
   did: string
   rkey: string
 }) {
-  await queryClient.invalidateQueries({queryKey: RQKEY(did, rkey)})
+  await queryClient.invalidateQueries({queryKey: RQKEY({did, rkey})})
 }
 
 interface UseCreateStarterPackMutationParams {
diff --git a/src/state/shell/logged-out.tsx b/src/state/shell/logged-out.tsx
index 2c577fdd2..dc78d03d5 100644
--- a/src/state/shell/logged-out.tsx
+++ b/src/state/shell/logged-out.tsx
@@ -50,7 +50,6 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
   const activeStarterPack = useActiveStarterPack()
   const {hasSession} = useSession()
   const shouldShowStarterPack = Boolean(activeStarterPack?.uri) && !hasSession
-
   const [state, setState] = React.useState<State>({
     showLoggedOut: shouldShowStarterPack,
     requestedAccountSwitchTo: shouldShowStarterPack
@@ -60,25 +59,6 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
       : undefined,
   })
 
-  const [prevActiveStarterPack, setPrevActiveStarterPack] =
-    React.useState(activeStarterPack)
-  if (activeStarterPack?.uri !== prevActiveStarterPack?.uri) {
-    setPrevActiveStarterPack(activeStarterPack)
-    if (activeStarterPack) {
-      setState(s => ({
-        ...s,
-        showLoggedOut: true,
-        requestedAccountSwitchTo: 'starterpack',
-      }))
-    } else {
-      setState(s => ({
-        ...s,
-        showLoggedOut: false,
-        requestedAccountSwitchTo: undefined,
-      }))
-    }
-  }
-
   const controls = React.useMemo<Controls>(
     () => ({
       setShowLoggedOut(show) {