Add account-activation queueing to signup (#2613)

* Add deactivated-account tracking

* Center button text

* Add Deactivated screen

* Add icon to Deactivated screen

* Abort session resumption if the session is deactivated

* Implement deactivated screen status checks

* Bump api@0.9.5

* Use new typo-fixed scope

* UI refinements
This commit is contained in:
Paul Frazee 2024-01-25 15:33:23 -08:00 committed by GitHub
parent 335bef3d30
commit 5443503593
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 304 additions and 11 deletions

View file

@ -12,6 +12,7 @@ const accountSchema = z.object({
emailConfirmed: z.boolean().optional(),
refreshJwt: z.string().optional(), // optional because it can expire
accessJwt: z.string().optional(), // optional because it can expire
deactivated: z.boolean().optional(),
})
export type PersistedAccount = z.infer<typeof accountSchema>

View file

@ -12,6 +12,7 @@ import {emitSessionDropped} from '../events'
import {useLoggedOutViewControls} from '#/state/shell/logged-out'
import {useCloseAllActiveElements} from '#/state/util'
import {track} from '#/lib/analytics/analytics'
import {hasProp} from '#/lib/type-guards'
let __globalAgent: BskyAgent = PUBLIC_BSKY_AGENT
@ -125,6 +126,7 @@ function createPersistSessionHandler(
handle: session?.handle || account.handle,
email: session?.email || account.email,
emailConfirmed: session?.emailConfirmed || account.emailConfirmed,
deactivated: isSessionDeactivated(session?.accessJwt),
/*
* Tokens are undefined if the session expires, or if creation fails for
@ -139,6 +141,7 @@ function createPersistSessionHandler(
did: refreshedAccount.did,
handle: refreshedAccount.handle,
service: refreshedAccount.service,
deactivated: refreshedAccount.deactivated,
})
if (expired) {
@ -235,11 +238,14 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
throw new Error(`session: createAccount failed to establish a session`)
}
/*dont await*/ agent.upsertProfile(_existing => {
return {
displayName: handle,
}
})
const deactivated = isSessionDeactivated(agent.session.accessJwt)
if (!deactivated) {
/*dont await*/ agent.upsertProfile(_existing => {
return {
displayName: handle,
}
})
}
const account: SessionAccount = {
service: agent.service.toString(),
@ -249,6 +255,7 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
emailConfirmed: false,
refreshJwt: agent.session.refreshJwt,
accessJwt: agent.session.accessJwt,
deactivated,
}
agent.setPersistSessionHandler(
@ -305,6 +312,7 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
emailConfirmed: agent.session.emailConfirmed || false,
refreshJwt: agent.session.refreshJwt,
accessJwt: agent.session.accessJwt,
deactivated: isSessionDeactivated(agent.session.accessJwt),
}
agent.setPersistSessionHandler(
@ -392,6 +400,8 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
refreshJwt: account.refreshJwt || '',
did: account.did,
handle: account.handle,
deactivated:
isSessionDeactivated(account.accessJwt) || account.deactivated,
}
if (canReusePrevSession) {
@ -402,6 +412,13 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
queryClient.clear()
upsertAccount(account)
if (prevSession.deactivated) {
// don't attempt to resume
// use will be taken to the deactivated screen
logger.info(`session: reusing session for deactivated account`)
return
}
// Intentionally not awaited to unblock the UI:
resumeSessionWithFreshAccount()
.then(freshAccount => {
@ -466,6 +483,7 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
emailConfirmed: agent.session.emailConfirmed || false,
refreshJwt: agent.session.refreshJwt,
accessJwt: agent.session.accessJwt,
deactivated: isSessionDeactivated(agent.session.accessJwt),
}
}
},
@ -687,3 +705,13 @@ export function useRequireAuth() {
[hasSession, setShowLoggedOut, closeAll],
)
}
export function isSessionDeactivated(accessJwt: string | undefined) {
if (accessJwt) {
const sessData = jwtDecode(accessJwt)
return (
hasProp(sessData, 'scope') && sessData.scope === 'com.atproto.deactivated'
)
}
return false
}