handle following and pinning feeds, acocunt createdAt
This commit is contained in:
@@ -39,7 +39,6 @@ import {ToastContainer} from 'view/com/util/Toast.web'
|
|||||||
import {Shell} from 'view/shell/index'
|
import {Shell} from 'view/shell/index'
|
||||||
import {ThemeProvider as Alf} from '#/alf'
|
import {ThemeProvider as Alf} from '#/alf'
|
||||||
import {useColorModeTheme} from '#/alf/util/useColorModeTheme'
|
import {useColorModeTheme} from '#/alf/util/useColorModeTheme'
|
||||||
import {useStarterPackEntry} from '#/components/hooks/useStarterPackEntry'
|
|
||||||
import {Provider as PortalProvider} from '#/components/Portal'
|
import {Provider as PortalProvider} from '#/components/Portal'
|
||||||
import {BackgroundNotificationPreferencesProvider} from '../modules/expo-background-notification-handler/src/BackgroundNotificationHandlerProvider'
|
import {BackgroundNotificationPreferencesProvider} from '../modules/expo-background-notification-handler/src/BackgroundNotificationHandlerProvider'
|
||||||
import I18nProvider from './locale/i18nProvider'
|
import I18nProvider from './locale/i18nProvider'
|
||||||
@@ -52,7 +51,6 @@ function InnerApp() {
|
|||||||
const theme = useColorModeTheme()
|
const theme = useColorModeTheme()
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
useIntentHandler()
|
useIntentHandler()
|
||||||
useStarterPackEntry()
|
|
||||||
|
|
||||||
// init
|
// init
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
@@ -1,15 +0,0 @@
|
|||||||
import React from 'react'
|
|
||||||
|
|
||||||
import {useSetStarterPack} from 'state/preferences/starter-pack'
|
|
||||||
|
|
||||||
export function useStarterPackEntry() {
|
|
||||||
const setStarterPack = useSetStarterPack()
|
|
||||||
|
|
||||||
React.useEffect(() => {
|
|
||||||
const url = new URL(window.location.href)
|
|
||||||
const pathParts = url.pathname.split('/')
|
|
||||||
if (pathParts[0] === 'start' && pathParts.length === 2) {
|
|
||||||
setStarterPack(pathParts[1])
|
|
||||||
}
|
|
||||||
}, [setStarterPack])
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import {View} from 'react-native'
|
import {View} from 'react-native'
|
||||||
|
import {AppBskyGraphDefs, AtUri} from '@atproto/api'
|
||||||
import {msg, Trans} from '@lingui/macro'
|
import {msg, Trans} from '@lingui/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
import {useQueryClient} from '@tanstack/react-query'
|
import {useQueryClient} from '@tanstack/react-query'
|
||||||
@@ -14,6 +15,10 @@ import {useAgent} from '#/state/session'
|
|||||||
import {useOnboardingDispatch} from '#/state/shell'
|
import {useOnboardingDispatch} from '#/state/shell'
|
||||||
import {uploadBlob} from 'lib/api'
|
import {uploadBlob} from 'lib/api'
|
||||||
import {useRequestNotificationsPermission} from 'lib/notifications/notifications'
|
import {useRequestNotificationsPermission} from 'lib/notifications/notifications'
|
||||||
|
import {
|
||||||
|
useSetUsedStarterPack,
|
||||||
|
useUsedStarterPack,
|
||||||
|
} from 'state/preferences/starter-pack'
|
||||||
import {
|
import {
|
||||||
DescriptionText,
|
DescriptionText,
|
||||||
OnboardingControls,
|
OnboardingControls,
|
||||||
@@ -41,15 +46,49 @@ export function StepFinished() {
|
|||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
const agent = useAgent()
|
const agent = useAgent()
|
||||||
const requestNotificationsPermission = useRequestNotificationsPermission()
|
const requestNotificationsPermission = useRequestNotificationsPermission()
|
||||||
|
const usedStarterPack = useUsedStarterPack()
|
||||||
|
const setUsedStarterPack = useSetUsedStarterPack()
|
||||||
|
|
||||||
const finishOnboarding = React.useCallback(async () => {
|
const finishOnboarding = React.useCallback(async () => {
|
||||||
setSaving(true)
|
setSaving(true)
|
||||||
|
|
||||||
const {interestsStepResults, profileStepResults} = state
|
|
||||||
const {selectedInterests} = interestsStepResults
|
|
||||||
try {
|
try {
|
||||||
|
let starterPack: AppBskyGraphDefs.StarterPackView | undefined
|
||||||
|
let listItems: AppBskyGraphDefs.ListItemView[] | undefined
|
||||||
|
if (usedStarterPack) {
|
||||||
|
const spRes = await agent.app.bsky.graph.getStarterPack({
|
||||||
|
starterPack: usedStarterPack.uri,
|
||||||
|
})
|
||||||
|
starterPack = spRes.data.starterPack
|
||||||
|
|
||||||
|
if (starterPack.list) {
|
||||||
|
const listRes = await agent.app.bsky.graph.getList({
|
||||||
|
list: starterPack.list.uri,
|
||||||
|
limit: 51,
|
||||||
|
})
|
||||||
|
listItems = listRes.data.items
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const {interestsStepResults, profileStepResults} = state
|
||||||
|
const {selectedInterests} = interestsStepResults
|
||||||
|
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
bulkWriteFollows(agent, [BSKY_APP_ACCOUNT_DID]),
|
bulkWriteFollows(agent, [
|
||||||
|
BSKY_APP_ACCOUNT_DID,
|
||||||
|
...(listItems?.map(i => i.subject.did) ?? []),
|
||||||
|
]),
|
||||||
|
(async () => {
|
||||||
|
if (starterPack?.feeds?.length) {
|
||||||
|
await agent.addSavedFeeds(
|
||||||
|
starterPack.feeds.map(f => ({
|
||||||
|
type: 'feed',
|
||||||
|
value: f.uri,
|
||||||
|
pinned: true,
|
||||||
|
id: new AtUri(f.uri).rkey,
|
||||||
|
})),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})(),
|
||||||
(async () => {
|
(async () => {
|
||||||
await agent.setInterestsPref({tags: selectedInterests})
|
await agent.setInterestsPref({tags: selectedInterests})
|
||||||
})(),
|
})(),
|
||||||
@@ -63,9 +102,20 @@ export function StepFinished() {
|
|||||||
if (res.data.blob) {
|
if (res.data.blob) {
|
||||||
existing.avatar = res.data.blob
|
existing.avatar = res.data.blob
|
||||||
}
|
}
|
||||||
|
|
||||||
|
existing.createdAt = new Date().toISOString()
|
||||||
|
|
||||||
|
if (starterPack) {
|
||||||
|
existing.joinedViaStarterPack = {
|
||||||
|
uri: starterPack.uri,
|
||||||
|
cid: starterPack.cid,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return existing
|
return existing
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
logEvent('onboarding:finished:avatarResult', {
|
logEvent('onboarding:finished:avatarResult', {
|
||||||
avatarResult: profileStepResults.isCreatedAvatar
|
avatarResult: profileStepResults.isCreatedAvatar
|
||||||
? 'created'
|
? 'created'
|
||||||
@@ -96,6 +146,7 @@ export function StepFinished() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
setSaving(false)
|
setSaving(false)
|
||||||
|
setUsedStarterPack(undefined)
|
||||||
dispatch({type: 'finish'})
|
dispatch({type: 'finish'})
|
||||||
onboardDispatch({type: 'finish'})
|
onboardDispatch({type: 'finish'})
|
||||||
track('OnboardingV2:StepFinished:End')
|
track('OnboardingV2:StepFinished:End')
|
||||||
@@ -105,10 +156,12 @@ export function StepFinished() {
|
|||||||
state,
|
state,
|
||||||
queryClient,
|
queryClient,
|
||||||
agent,
|
agent,
|
||||||
|
setUsedStarterPack,
|
||||||
dispatch,
|
dispatch,
|
||||||
onboardDispatch,
|
onboardDispatch,
|
||||||
track,
|
track,
|
||||||
requestNotificationsPermission,
|
requestNotificationsPermission,
|
||||||
|
usedStarterPack,
|
||||||
])
|
])
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
|
|||||||
@@ -8,10 +8,13 @@ import {
|
|||||||
} from '@atproto/api'
|
} from '@atproto/api'
|
||||||
import {msg, Trans} from '@lingui/macro'
|
import {msg, Trans} from '@lingui/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
import {NativeStackScreenProps} from '@react-navigation/native-stack'
|
import {useNavigation} from '@react-navigation/native'
|
||||||
|
|
||||||
import {CommonNavigatorParams} from 'lib/routes/types'
|
import {NavigationProp} from 'lib/routes/types'
|
||||||
|
import {useSetUsedStarterPack} from 'state/preferences/starter-pack'
|
||||||
|
import {useSession} from 'state/session'
|
||||||
import {useSetMinimalShellMode} from 'state/shell'
|
import {useSetMinimalShellMode} from 'state/shell'
|
||||||
|
import {useLoggedOutViewControls} from 'state/shell/logged-out'
|
||||||
import {FeedSourceCard} from 'view/com/feeds/FeedSourceCard'
|
import {FeedSourceCard} from 'view/com/feeds/FeedSourceCard'
|
||||||
import {UserAvatar} from 'view/com/util/UserAvatar'
|
import {UserAvatar} from 'view/com/util/UserAvatar'
|
||||||
import {CenteredView} from 'view/com/util/Views'
|
import {CenteredView} from 'view/com/util/Views'
|
||||||
@@ -116,10 +119,10 @@ const mockSP = {
|
|||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
export function LandingScreen({
|
export function LandingScreen({}) {
|
||||||
navigation,
|
|
||||||
}: NativeStackScreenProps<CommonNavigatorParams, 'StarterPackLanding'>) {
|
|
||||||
// const {name, rkey} = route.params
|
// const {name, rkey} = route.params
|
||||||
|
const navigation = useNavigation<NavigationProp>()
|
||||||
|
const {currentAccount} = useSession()
|
||||||
const setMinimalShellMode = useSetMinimalShellMode()
|
const setMinimalShellMode = useSetMinimalShellMode()
|
||||||
|
|
||||||
// const {
|
// const {
|
||||||
@@ -134,11 +137,16 @@ export function LandingScreen({
|
|||||||
// } = useStarterPackQuery({did, rkey})
|
// } = useStarterPackQuery({did, rkey})
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
|
if (currentAccount) {
|
||||||
|
navigation.navigate('Home')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
setMinimalShellMode(true)
|
setMinimalShellMode(true)
|
||||||
return () => {
|
return () => {
|
||||||
setMinimalShellMode(false)
|
setMinimalShellMode(false)
|
||||||
}
|
}
|
||||||
}, [navigation, setMinimalShellMode])
|
}, [currentAccount, navigation, setMinimalShellMode])
|
||||||
|
|
||||||
// if (!did || !starterPack) {
|
// if (!did || !starterPack) {
|
||||||
// return (
|
// return (
|
||||||
@@ -160,6 +168,8 @@ function LandingScreenInner({
|
|||||||
const {record, creator, listItemsSample, feeds, joinedWeekCount} = starterPack
|
const {record, creator, listItemsSample, feeds, joinedWeekCount} = starterPack
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
|
const {requestSwitchToAccount} = useLoggedOutViewControls()
|
||||||
|
const setUsedStarterPack = useSetUsedStarterPack()
|
||||||
|
|
||||||
const gradient =
|
const gradient =
|
||||||
t.name === 'light'
|
t.name === 'light'
|
||||||
@@ -205,7 +215,13 @@ function LandingScreenInner({
|
|||||||
)}
|
)}
|
||||||
<Button
|
<Button
|
||||||
label={_(msg`Join Bluesky now`)}
|
label={_(msg`Join Bluesky now`)}
|
||||||
onPress={() => {}}
|
onPress={() => {
|
||||||
|
setUsedStarterPack({
|
||||||
|
uri: starterPack.uri,
|
||||||
|
cid: starterPack.cid,
|
||||||
|
})
|
||||||
|
requestSwitchToAccount({requestedAccount: 'new'})
|
||||||
|
}}
|
||||||
variant="solid"
|
variant="solid"
|
||||||
color="primary"
|
color="primary"
|
||||||
size="large">
|
size="large">
|
||||||
|
|||||||
@@ -25,9 +25,7 @@ export function StepFeeds() {
|
|||||||
const [state, dispatch] = useWizardState()
|
const [state, dispatch] = useWizardState()
|
||||||
const [query, setQuery] = useState('')
|
const [query, setQuery] = useState('')
|
||||||
|
|
||||||
const {data: popularFeedsPages, fetchNextPage} = useGetPopularFeedsQuery({
|
const {data: popularFeedsPages, fetchNextPage} = useGetPopularFeedsQuery(30)
|
||||||
limit: 30,
|
|
||||||
})
|
|
||||||
|
|
||||||
const popularFeeds =
|
const popularFeeds =
|
||||||
popularFeedsPages?.pages.flatMap(page => page.feeds) || []
|
popularFeedsPages?.pages.flatMap(page => page.feeds) || []
|
||||||
|
|||||||
@@ -88,7 +88,12 @@ export const schema = z.object({
|
|||||||
disableHaptics: z.boolean().optional(),
|
disableHaptics: z.boolean().optional(),
|
||||||
disableAutoplay: z.boolean().optional(),
|
disableAutoplay: z.boolean().optional(),
|
||||||
kawaii: z.boolean().optional(),
|
kawaii: z.boolean().optional(),
|
||||||
starterPackId: z.string().optional(),
|
usedStarterPack: z
|
||||||
|
.object({
|
||||||
|
uri: z.string(),
|
||||||
|
cid: z.string(),
|
||||||
|
})
|
||||||
|
.optional(),
|
||||||
})
|
})
|
||||||
export type Schema = z.infer<typeof schema>
|
export type Schema = z.infer<typeof schema>
|
||||||
|
|
||||||
@@ -127,5 +132,5 @@ export const defaults: Schema = {
|
|||||||
disableHaptics: false,
|
disableHaptics: false,
|
||||||
disableAutoplay: prefersReducedMotion,
|
disableAutoplay: prefersReducedMotion,
|
||||||
kawaii: false,
|
kawaii: false,
|
||||||
starterPackId: undefined,
|
usedStarterPack: undefined,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,23 +2,23 @@ import React from 'react'
|
|||||||
|
|
||||||
import * as persisted from '#/state/persisted'
|
import * as persisted from '#/state/persisted'
|
||||||
|
|
||||||
type StateContext = string | undefined
|
type StateContext = {uri: string; cid: string} | undefined
|
||||||
type SetContext = (v: string) => void
|
type SetContext = (v: StateContext) => void
|
||||||
|
|
||||||
const stateContext = React.createContext<StateContext>(undefined)
|
const stateContext = React.createContext<StateContext>(undefined)
|
||||||
const setContext = React.createContext<SetContext>((_: string) => {})
|
const setContext = React.createContext<SetContext>((_: StateContext) => {})
|
||||||
|
|
||||||
export function Provider({children}: {children: React.ReactNode}) {
|
export function Provider({children}: {children: React.ReactNode}) {
|
||||||
const [state, setState] = React.useState<string>()
|
const [state, setState] = React.useState<StateContext>()
|
||||||
|
|
||||||
const setStateWrapped = (v: string) => {
|
const setStateWrapped = (v: StateContext) => {
|
||||||
setState(v)
|
setState(v)
|
||||||
persisted.write('starterPackId', v)
|
persisted.write('usedStarterPack', v)
|
||||||
}
|
}
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
return persisted.onUpdate(() => {
|
return persisted.onUpdate(() => {
|
||||||
setState(persisted.get('starterPackId'))
|
setState(persisted.get('usedStarterPack'))
|
||||||
})
|
})
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
@@ -31,5 +31,5 @@ export function Provider({children}: {children: React.ReactNode}) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useStarterPack = () => React.useContext(stateContext)
|
export const useUsedStarterPack = () => React.useContext(stateContext)
|
||||||
export const useSetStarterPack = () => React.useContext(setContext)
|
export const useSetUsedStarterPack = () => React.useContext(setContext)
|
||||||
|
|||||||
@@ -173,7 +173,7 @@ export function useFeedSourceInfoQuery({uri}: {uri: string}) {
|
|||||||
|
|
||||||
export const useGetPopularFeedsQueryKey = ['getPopularFeeds']
|
export const useGetPopularFeedsQueryKey = ['getPopularFeeds']
|
||||||
|
|
||||||
export function useGetPopularFeedsQuery({limit = 10}: {limit?: number}) {
|
export function useGetPopularFeedsQuery(limit: number = 10) {
|
||||||
const agent = useAgent()
|
const agent = useAgent()
|
||||||
return useInfiniteQuery<
|
return useInfiniteQuery<
|
||||||
AppBskyUnspeccedGetPopularFeedGenerators.OutputSchema,
|
AppBskyUnspeccedGetPopularFeedGenerators.OutputSchema,
|
||||||
|
|||||||
Reference in New Issue
Block a user