profile(): resolve 'login' when login flow completes inside the dialog
The overlay now tracks which dialog kind is open: auth-success from a profile dialog resolves 'login', auth-back only rejects AuthCancelledError for auth dialogs.
This commit is contained in:
+16
-12
@@ -41,15 +41,18 @@ body.paskia-backdrop {
|
|||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
type DialogResult = 'logout' | 'back'
|
type DialogResult = 'login' | 'logout' | 'back'
|
||||||
|
type DialogKind = 'auth' | 'profile'
|
||||||
|
|
||||||
let authIframe: HTMLIFrameElement | null = null
|
let authIframe: HTMLIFrameElement | null = null
|
||||||
let authPromise: Promise<DialogResult | undefined> | null = null
|
let authPromise: Promise<DialogResult | undefined> | null = null
|
||||||
let authResolve: ((result?: DialogResult) => void) | null = null
|
let authResolve: ((result?: DialogResult) => void) | null = null
|
||||||
let authReject: ((error: Error) => void) | null = null
|
let authReject: ((error: Error) => void) | null = null
|
||||||
// Auth flows reject AuthCancelledError on auth-back (callers rely on it to
|
// Auth flows reject AuthCancelledError on auth-back (callers rely on it to
|
||||||
// abort request retries); the profile dialog resolves 'back' instead.
|
// abort request retries) and resolve void on auth-success. The profile dialog
|
||||||
let cancelAsError = true
|
// never rejects: auth-back resolves 'back', and auth-success (the user logged
|
||||||
|
// in while the profile dialog was open) resolves 'login'.
|
||||||
|
let dialogKind: DialogKind = 'auth'
|
||||||
let messageListenerInstalled = false
|
let messageListenerInstalled = false
|
||||||
let backdropHolders = 0
|
let backdropHolders = 0
|
||||||
|
|
||||||
@@ -101,7 +104,7 @@ function handleAuthMessage(event: MessageEvent): void {
|
|||||||
case 'auth-success':
|
case 'auth-success':
|
||||||
hideAuthIframe()
|
hideAuthIframe()
|
||||||
if (authResolve) {
|
if (authResolve) {
|
||||||
authResolve()
|
authResolve(dialogKind === 'profile' ? 'login' : undefined)
|
||||||
authPromise = null
|
authPromise = null
|
||||||
authResolve = null
|
authResolve = null
|
||||||
authReject = null
|
authReject = null
|
||||||
@@ -110,7 +113,7 @@ function handleAuthMessage(event: MessageEvent): void {
|
|||||||
|
|
||||||
case 'auth-back':
|
case 'auth-back':
|
||||||
hideAuthIframe()
|
hideAuthIframe()
|
||||||
if (cancelAsError && authReject) {
|
if (dialogKind === 'auth' && authReject) {
|
||||||
authReject(new AuthCancelledError())
|
authReject(new AuthCancelledError())
|
||||||
} else if (authResolve) {
|
} else if (authResolve) {
|
||||||
authResolve('back')
|
authResolve('back')
|
||||||
@@ -140,13 +143,13 @@ function ensureMessageListener(): void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function openIframe(iframeUrl: string, title: string, dialog: boolean, cancelError: boolean): Promise<DialogResult | undefined> {
|
function openIframe(iframeUrl: string, title: string, kind: DialogKind): Promise<DialogResult | undefined> {
|
||||||
injectStyles()
|
injectStyles()
|
||||||
ensureMessageListener()
|
ensureMessageListener()
|
||||||
|
|
||||||
if (authPromise) return authPromise
|
if (authPromise) return authPromise
|
||||||
|
|
||||||
cancelAsError = cancelError
|
dialogKind = kind
|
||||||
iframeUrl = withAppTheme(iframeUrl)
|
iframeUrl = withAppTheme(iframeUrl)
|
||||||
|
|
||||||
if (document.getElementById(AUTH_IFRAME_ID)) {
|
if (document.getElementById(AUTH_IFRAME_ID)) {
|
||||||
@@ -167,7 +170,7 @@ function openIframe(iframeUrl: string, title: string, dialog: boolean, cancelErr
|
|||||||
|
|
||||||
authIframe = document.createElement('iframe')
|
authIframe = document.createElement('iframe')
|
||||||
authIframe.id = AUTH_IFRAME_ID
|
authIframe.id = AUTH_IFRAME_ID
|
||||||
if (dialog) authIframe.classList.add('paskia-dialog')
|
if (kind === 'profile') authIframe.classList.add('paskia-dialog')
|
||||||
authIframe.title = title
|
authIframe.title = title
|
||||||
authIframe.src = iframeUrl
|
authIframe.src = iframeUrl
|
||||||
document.body.appendChild(authIframe)
|
document.body.appendChild(authIframe)
|
||||||
@@ -201,19 +204,20 @@ function withAppTheme(iframeUrl: string): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function showAuthIframe(iframeUrl: string, title = 'Authentication'): Promise<void> {
|
export function showAuthIframe(iframeUrl: string, title = 'Authentication'): Promise<void> {
|
||||||
return openIframe(iframeUrl, title, false, true).then(() => undefined)
|
return openIframe(iframeUrl, title, 'auth').then(() => undefined)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show the minimal profile of the logged-in user in a compact dialog iframe.
|
* Show the minimal profile of the logged-in user in a compact dialog iframe.
|
||||||
*
|
*
|
||||||
* Unlike the auth flows, this always resolves — 'logout' when the user
|
* Unlike the auth flows, this always resolves — 'login' when the user was
|
||||||
* signed out inside the frame, 'back' when they closed it without action.
|
* signed out and completed the login flow inside the frame, 'logout' when
|
||||||
|
* they signed out inside the frame, 'back' when they closed it otherwise.
|
||||||
* The caller decides from context how to react to each (e.g. whether to
|
* The caller decides from context how to react to each (e.g. whether to
|
||||||
* start a new login attempt with showAuthIframe).
|
* start a new login attempt with showAuthIframe).
|
||||||
*/
|
*/
|
||||||
export function profile(): Promise<DialogResult> {
|
export function profile(): Promise<DialogResult> {
|
||||||
return openIframe('/auth/restricted/iframe#mode=profile', 'Profile', true, false)
|
return openIframe('/auth/restricted/iframe#mode=profile', 'Profile', 'profile')
|
||||||
.then((result) => result ?? 'back')
|
.then((result) => result ?? 'back')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user