feat: Show details of invalid invite (#1970)
Resolves https://github.com/webrecorder/browsertrix/issues/1912 ### Changes - Show support email, if available, in invalid invite error message - Separate error message for invite email that doesn't match current user's
This commit is contained in:
		
							parent
							
								
									d38abbca7f
								
							
						
					
					
						commit
						dd6c33a59d
					
				| @ -188,6 +188,7 @@ export class App extends LiteElement { | ||||
|         maxScale: 0, | ||||
|         billingEnabled: false, | ||||
|         salesEmail: "", | ||||
|         supportEmail: "", | ||||
|       }; | ||||
|     } | ||||
|   } | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| import { localized, msg, str } from "@lit/localize"; | ||||
| import { Task } from "@lit/task"; | ||||
| import { html } from "lit"; | ||||
| import { html, nothing } from "lit"; | ||||
| import { customElement, property, state } from "lit/decorators.js"; | ||||
| 
 | ||||
| import { renderInviteMessage } from "./ui/inviteMessage"; | ||||
| @ -15,7 +15,7 @@ import { ROUTES } from "@/routes"; | ||||
| import type { UserOrg, UserOrgInviteInfo } from "@/types/user"; | ||||
| import { isApiError } from "@/utils/api"; | ||||
| import type { Auth, AuthState } from "@/utils/AuthService"; | ||||
| import { AppStateService } from "@/utils/state"; | ||||
| import appState, { AppStateService, use } from "@/utils/state"; | ||||
| import { formatAPIUser } from "@/utils/user"; | ||||
| 
 | ||||
| import "./ui/org-form"; | ||||
| @ -32,6 +32,9 @@ export class AcceptInvite extends TailwindElement { | ||||
|   @property({ type: String }) | ||||
|   email?: string; | ||||
| 
 | ||||
|   @use() | ||||
|   appState = appState; | ||||
| 
 | ||||
|   @state() | ||||
|   private serverError?: string; | ||||
| 
 | ||||
| @ -49,9 +52,7 @@ export class AcceptInvite extends TailwindElement { | ||||
|   }); | ||||
| 
 | ||||
|   get _isLoggedIn(): boolean { | ||||
|     return Boolean( | ||||
|       this.authState && this.email && this.authState.username === this.email, | ||||
|     ); | ||||
|     return Boolean(this.authState && this.email); | ||||
|   } | ||||
| 
 | ||||
|   readonly _api = new APIController(this); | ||||
| @ -69,7 +70,7 @@ export class AcceptInvite extends TailwindElement { | ||||
|   firstUpdated() { | ||||
|     if (!this._isLoggedIn) { | ||||
|       this._notify.toast({ | ||||
|         message: msg("Log in to continue."), | ||||
|         message: msg("Please log in to accept this invite."), | ||||
|         variant: "warning", | ||||
|         icon: "exclamation-triangle", | ||||
|       }); | ||||
| @ -152,13 +153,17 @@ export class AcceptInvite extends TailwindElement { | ||||
|               error: (err) => | ||||
|                 html`<btrix-alert variant="danger">
 | ||||
|                   <div>${err instanceof Error ? err.message : err}</div> | ||||
|                   <a | ||||
|                     href=${ROUTES.home} | ||||
|                     @click=${this._navigate.link} | ||||
|                     class="mt-3 inline-block underline hover:no-underline" | ||||
|                   > | ||||
|                     ${msg("Go to home page")} | ||||
|                   </a> | ||||
|                   ${this.authState && this.authState.username !== this.email | ||||
|                     ? nothing | ||||
|                     : html` | ||||
|                         <a | ||||
|                           href=${ROUTES.home} | ||||
|                           @click=${this._navigate.link} | ||||
|                           class="mt-3 inline-block underline hover:no-underline" | ||||
|                         > | ||||
|                           ${msg("Go to home page")} | ||||
|                         </a> | ||||
|                       `}
 | ||||
|                 </btrix-alert> `, | ||||
|             })} | ||||
|           </div> | ||||
| @ -181,7 +186,38 @@ export class AcceptInvite extends TailwindElement { | ||||
|       ); | ||||
|     } catch (e) { | ||||
|       console.debug(e); | ||||
|       throw new Error(msg("This invitation is not valid.")); | ||||
| 
 | ||||
|       const status = isApiError(e) ? e.statusCode : null; | ||||
| 
 | ||||
|       switch (status) { | ||||
|         case 404: | ||||
|           throw new Error( | ||||
|             msg( | ||||
|               "This invite doesn't exist or has expired. Please ask the organization administrator to resend an invitation.", | ||||
|             ), | ||||
|           ); | ||||
|         case 400: { | ||||
|           if (auth.username === this.email) { | ||||
|             throw new Error( | ||||
|               msg( | ||||
|                 str`This is not a valid invite, or it may have expired. If you believe this is an error, please contact ${this.appState.settings?.supportEmail || msg("your Browsertrix administrator")} for help.`, | ||||
|               ), | ||||
|             ); | ||||
|           } else { | ||||
|             throw new Error( | ||||
|               msg( | ||||
|                 str`This invitation is for ${this.email}. You are currently logged in as ${auth.username}. Please log in with the correct email to access this invite.`, | ||||
|               ), | ||||
|             ); | ||||
|           } | ||||
|         } | ||||
|         default: | ||||
|           throw new Error( | ||||
|             msg( | ||||
|               str`Something unexpected went wrong retrieving this invite. Please contact ${this.appState.settings?.supportEmail || msg("your Browsertrix administrator")} for help.`, | ||||
|             ), | ||||
|           ); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| import { localized, msg } from "@lit/localize"; | ||||
| import { localized, msg, str } from "@lit/localize"; | ||||
| import { Task } from "@lit/task"; | ||||
| import { customElement, property, state } from "lit/decorators.js"; | ||||
| 
 | ||||
| @ -132,16 +132,27 @@ export class Join extends LiteElement { | ||||
|       `/api/users/invite/${token}?email=${encodeURIComponent(email)}`, | ||||
|     ); | ||||
| 
 | ||||
|     if (resp.status === 200) { | ||||
|       return (await resp.json()) as UserOrgInviteInfo; | ||||
|     } else if (resp.status === 404) { | ||||
|       throw new Error( | ||||
|         msg( | ||||
|           "This invite doesn't exist or has expired. Please ask the organization administrator to resend an invitation.", | ||||
|         ), | ||||
|       ); | ||||
|     } else { | ||||
|       throw new Error(msg("This invitation is not valid.")); | ||||
|     switch (resp.status) { | ||||
|       case 200: | ||||
|         return (await resp.json()) as UserOrgInviteInfo; | ||||
|       case 404: | ||||
|         throw new Error( | ||||
|           msg( | ||||
|             "This invite doesn't exist or has expired. Please ask the organization administrator to resend an invitation.", | ||||
|           ), | ||||
|         ); | ||||
|       case 400: | ||||
|         throw new Error( | ||||
|           msg( | ||||
|             str`This is not a valid invite, or it may have expired. If you believe this is an error, please contact ${this.appState.settings?.supportEmail || msg("your Browsertrix administrator")} for help.`, | ||||
|           ), | ||||
|         ); | ||||
|       default: | ||||
|         throw new Error( | ||||
|           msg( | ||||
|             str`Something unexpected went wrong retrieving this invite. Please contact ${this.appState.settings?.supportEmail || msg("your Browsertrix administrator")} for help.`, | ||||
|           ), | ||||
|         ); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|  | ||||
| @ -7,4 +7,5 @@ export type AppSettings = { | ||||
|   maxScale: number; | ||||
|   billingEnabled: boolean; | ||||
|   salesEmail: string; | ||||
|   supportEmail: string; | ||||
| }; | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user