Bluesky app fork with some witchin' additions 💫
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Onboarding fixes (#3966)

* Ensure prefs are up-to-date before leaving onboarding

* Parallelize upsertProfile call

* Don't upsertProfile if no image

* Don't waterfall blob upload

* Fix useProfileUpdateMutation to parallelize uploads

* Invalidate user profile before leaving onboarding

* Ungate setting the pic

authored by

dan and committed by
GitHub
51b4b22d 6f5b551b

+60 -32
+35 -20
src/screens/Onboarding/StepFinished.tsx
··· 3 3 import {TID} from '@atproto/common-web' 4 4 import {msg, Trans} from '@lingui/macro' 5 5 import {useLingui} from '@lingui/react' 6 + import {useQueryClient} from '@tanstack/react-query' 6 7 7 8 import {useAnalytics} from '#/lib/analytics/analytics' 8 9 import {BSKY_APP_ACCOUNT_DID, IS_PROD_SERVICE} from '#/lib/constants' 9 10 import {DISCOVER_SAVED_FEED, TIMELINE_SAVED_FEED} from '#/lib/constants' 10 11 import {logEvent, useGate} from '#/lib/statsig/statsig' 11 12 import {logger} from '#/logger' 12 - import {useOverwriteSavedFeedsMutation} from '#/state/queries/preferences' 13 + import { 14 + preferencesQueryKey, 15 + useOverwriteSavedFeedsMutation, 16 + } from '#/state/queries/preferences' 17 + import {RQKEY as profileRQKey} from '#/state/queries/profile' 13 18 import {useAgent} from '#/state/session' 14 19 import {useOnboardingDispatch} from '#/state/shell' 15 20 import {uploadBlob} from 'lib/api' ··· 41 46 const onboardDispatch = useOnboardingDispatch() 42 47 const [saving, setSaving] = React.useState(false) 43 48 const {mutateAsync: overwriteSavedFeeds} = useOverwriteSavedFeedsMutation() 49 + const queryClient = useQueryClient() 44 50 const {getAgent} = useAgent() 45 51 const gate = useGate() 46 52 ··· 112 118 ]) 113 119 } 114 120 })(), 115 - ]) 116 - 117 - if (gate('reduced_onboarding_and_home_algo')) { 118 - await getAgent().upsertProfile(async existing => { 119 - existing = existing ?? {} 120 121 121 - if (profileStepResults.imageUri && profileStepResults.imageMime) { 122 - const res = await uploadBlob( 123 - getAgent(), 124 - profileStepResults.imageUri, 125 - profileStepResults.imageMime, 126 - ) 127 - 128 - if (res.data.blob) { 129 - existing.avatar = res.data.blob 130 - } 122 + (async () => { 123 + const {imageUri, imageMime} = profileStepResults 124 + if (imageUri && imageMime) { 125 + const blobPromise = uploadBlob(getAgent(), imageUri, imageMime) 126 + await getAgent().upsertProfile(async existing => { 127 + existing = existing ?? {} 128 + const res = await blobPromise 129 + if (res.data.blob) { 130 + existing.avatar = res.data.blob 131 + } 132 + return existing 133 + }) 131 134 } 132 - 133 - return existing 134 - }) 135 - } 135 + })(), 136 + ]) 136 137 } catch (e: any) { 137 138 logger.info(`onboarding: bulk save failed`) 138 139 logger.error(e) 139 140 // don't alert the user, just let them into their account 140 141 } 141 142 143 + // Try to ensure that prefs and profile are up-to-date by the time we render Home. 144 + await Promise.all([ 145 + queryClient.invalidateQueries({ 146 + queryKey: preferencesQueryKey, 147 + }), 148 + queryClient.invalidateQueries({ 149 + queryKey: profileRQKey(getAgent().session?.did ?? ''), 150 + }), 151 + ]).catch(e => { 152 + logger.error(e) 153 + // Keep going. 154 + }) 155 + 142 156 setSaving(false) 143 157 dispatch({type: 'finish'}) 144 158 onboardDispatch({type: 'finish'}) ··· 154 168 track, 155 169 getAgent, 156 170 gate, 171 + queryClient, 157 172 ]) 158 173 159 174 React.useEffect(() => {
+25 -12
src/state/queries/profile.ts
··· 6 6 AppBskyActorProfile, 7 7 AtUri, 8 8 BskyAgent, 9 + ComAtprotoRepoUploadBlob, 9 10 } from '@atproto/api' 10 11 import { 11 12 QueryClient, ··· 124 125 newUserBanner, 125 126 checkCommitted, 126 127 }) => { 128 + let newUserAvatarPromise: 129 + | Promise<ComAtprotoRepoUploadBlob.Response> 130 + | undefined 131 + if (newUserAvatar) { 132 + newUserAvatarPromise = uploadBlob( 133 + getAgent(), 134 + newUserAvatar.path, 135 + newUserAvatar.mime, 136 + ) 137 + } 138 + let newUserBannerPromise: 139 + | Promise<ComAtprotoRepoUploadBlob.Response> 140 + | undefined 141 + if (newUserBanner) { 142 + newUserBannerPromise = uploadBlob( 143 + getAgent(), 144 + newUserBanner.path, 145 + newUserBanner.mime, 146 + ) 147 + } 127 148 await getAgent().upsertProfile(async existing => { 128 149 existing = existing || {} 129 150 if (typeof updates === 'function') { ··· 132 153 existing.displayName = updates.displayName 133 154 existing.description = updates.description 134 155 } 135 - if (newUserAvatar) { 136 - const res = await uploadBlob( 137 - getAgent(), 138 - newUserAvatar.path, 139 - newUserAvatar.mime, 140 - ) 156 + if (newUserAvatarPromise) { 157 + const res = await newUserAvatarPromise 141 158 existing.avatar = res.data.blob 142 159 } else if (newUserAvatar === null) { 143 160 existing.avatar = undefined 144 161 } 145 - if (newUserBanner) { 146 - const res = await uploadBlob( 147 - getAgent(), 148 - newUserBanner.path, 149 - newUserBanner.mime, 150 - ) 162 + if (newUserBannerPromise) { 163 + const res = await newUserBannerPromise 151 164 existing.banner = res.data.blob 152 165 } else if (newUserBanner === null) { 153 166 existing.banner = undefined