Show invite message to super admin & layout fixes (#181)
This commit is contained in:
		
							parent
							
								
									fe31f551b2
								
							
						
					
					
						commit
						c18418ff09
					
				| @ -14,12 +14,12 @@ type LocaleNames = { | |||||||
| @localized() | @localized() | ||||||
| export class LocalePicker extends LitElement { | export class LocalePicker extends LitElement { | ||||||
|   @state() |   @state() | ||||||
|   private localeNames?: LocaleNames; |   private localeNames: LocaleNames = {} as LocaleNames; | ||||||
| 
 | 
 | ||||||
|   private setLocaleName = (locale: LocaleCode) => { |   private setLocaleName = (locale: LocaleCode) => { | ||||||
|     this.localeNames![locale] = new Intl.DisplayNames([locale], { |     this.localeNames[locale] = new Intl.DisplayNames([locale], { | ||||||
|       type: "language", |       type: "language", | ||||||
|     }).of(locale); |     }).of(locale)!; | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
|   async firstUpdated() { |   async firstUpdated() { | ||||||
| @ -63,22 +63,33 @@ export class LocalePicker extends LitElement { | |||||||
|     const selectedLocale = getLocale(); |     const selectedLocale = getLocale(); | ||||||
| 
 | 
 | ||||||
|     return html` |     return html` | ||||||
|       <sl-select value=${selectedLocale} @sl-change=${this.localeChanged}> |       <sl-dropdown | ||||||
|         ${allLocales.map( |         value=${selectedLocale} | ||||||
|           (locale) => |         @sl-select=${this.localeChanged} | ||||||
|             html`<sl-menu-item
 |         placement="top-end" | ||||||
|               value=${locale} |         distance="4" | ||||||
|               ?selected=${locale === selectedLocale} |         hoist | ||||||
|             > |       > | ||||||
|               ${this.localeNames![locale]} |         <sl-button slot="trigger" size="small" caret | ||||||
|             </sl-menu-item>` |           >${this.localeNames[selectedLocale as LocaleCode]}</sl-button | ||||||
|         )} |         > | ||||||
|       </sl-select> |         <sl-menu> | ||||||
|  |           ${allLocales.map( | ||||||
|  |             (locale) => | ||||||
|  |               html`<sl-menu-item
 | ||||||
|  |                 value=${locale} | ||||||
|  |                 ?checked=${locale === selectedLocale} | ||||||
|  |               > | ||||||
|  |                 ${this.localeNames[locale]} | ||||||
|  |               </sl-menu-item>` | ||||||
|  |           )} | ||||||
|  |         </sl-menu> | ||||||
|  |       </sl-dropdown> | ||||||
|     `;
 |     `;
 | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   async localeChanged(event: Event) { |   async localeChanged(event: CustomEvent) { | ||||||
|     const newLocale = (event.target as HTMLSelectElement).value as LocaleCode; |     const newLocale = event.detail.item.value as LocaleCode; | ||||||
| 
 | 
 | ||||||
|     if (newLocale !== getLocale()) { |     if (newLocale !== getLocale()) { | ||||||
|       const url = new URL(window.location.href); |       const url = new URL(window.location.href); | ||||||
|  | |||||||
| @ -194,9 +194,7 @@ export class App extends LiteElement { | |||||||
|       <div class="min-w-screen min-h-screen flex flex-col"> |       <div class="min-w-screen min-h-screen flex flex-col"> | ||||||
|         ${this.renderNavBar()} |         ${this.renderNavBar()} | ||||||
|         <main class="relative flex-auto flex">${this.renderPage()}</main> |         <main class="relative flex-auto flex">${this.renderPage()}</main> | ||||||
|         <footer class="flex justify-center p-4 border-t"> |         <div class="border-t border-neutral-100">${this.renderFooter()}</div> | ||||||
|           <btrix-locale-picker></btrix-locale-picker> |  | ||||||
|         </footer> |  | ||||||
|       </div> |       </div> | ||||||
| 
 | 
 | ||||||
|       <sl-dialog |       <sl-dialog | ||||||
| @ -217,34 +215,61 @@ export class App extends LiteElement { | |||||||
|         > |         > | ||||||
|           <div> |           <div> | ||||||
|             <a href="/archives" @click="${this.navLink}" |             <a href="/archives" @click="${this.navLink}" | ||||||
|               ><h1 class="text-base">${msg("Browsertrix Cloud")}</h1></a |               ><h1 class="text-sm font-medium"> | ||||||
|  |                 ${msg("Browsertrix Cloud")} | ||||||
|  |               </h1></a | ||||||
|             > |             > | ||||||
|           </div> |           </div> | ||||||
|           <div class="grid grid-flow-col gap-5 items-center"> |           <div class="grid grid-flow-col gap-5 items-center"> | ||||||
|             ${this.authService.authState |             ${this.authService.authState | ||||||
|               ? html` <sl-dropdown placement="bottom-end">
 |               ? html` <sl-dropdown placement="bottom-end">
 | ||||||
|                   <div class="p-2" role="button" slot="trigger"> |                   <sl-icon-button | ||||||
|                     ${this.userInfo?.name || this.userInfo?.email} |                     slot="trigger" | ||||||
|                     <span class="text-xs" |                     name="person-circle" | ||||||
|                       ><sl-icon name="chevron-down"></sl-icon |                     style="font-size: 1.5rem;" | ||||||
|                     ></span> |                   ></sl-icon-button> | ||||||
|                   </div> | 
 | ||||||
|                   <sl-menu> |                   <sl-menu class="w-60 min-w-min max-w-full"> | ||||||
|  |                     <div class="px-7 py-2"> | ||||||
|  |                       ${this.userInfo?.isAdmin | ||||||
|  |                         ? html` | ||||||
|  |                             <div class="mb-2"> | ||||||
|  |                               <sl-tag | ||||||
|  |                                 class="uppercase" | ||||||
|  |                                 type="primary" | ||||||
|  |                                 size="small" | ||||||
|  |                                 >${msg("admin")}</sl-tag | ||||||
|  |                               > | ||||||
|  |                             </div> | ||||||
|  |                           ` | ||||||
|  |                         : ""} | ||||||
|  |                       <div class="font-medium text-neutral-700"> | ||||||
|  |                         ${this.userInfo?.name} | ||||||
|  |                       </div> | ||||||
|  |                       <div class="text-sm text-neutral-500"> | ||||||
|  |                         ${this.userInfo?.email} | ||||||
|  |                       </div> | ||||||
|  |                     </div> | ||||||
|  |                     <sl-divider></sl-divider> | ||||||
|                     <sl-menu-item |                     <sl-menu-item | ||||||
|                       @click=${() => this.navigate(ROUTES.accountSettings)} |                       @click=${() => this.navigate(ROUTES.accountSettings)} | ||||||
|                     > |                     > | ||||||
|  |                       <sl-icon slot="prefix" name="gear"></sl-icon> | ||||||
|                       ${msg("Your account")} |                       ${msg("Your account")} | ||||||
|                     </sl-menu-item> |                     </sl-menu-item> | ||||||
|                     ${this.userInfo?.isAdmin |                     ${this.userInfo?.isAdmin | ||||||
|                       ? html` <sl-menu-item
 |                       ? html` <sl-menu-item
 | ||||||
|                           @click=${() => this.navigate(ROUTES.usersInvite)} |                           @click=${() => this.navigate(ROUTES.usersInvite)} | ||||||
|                         > |                         > | ||||||
|  |                           <sl-icon slot="prefix" name="person-plus"></sl-icon> | ||||||
|                           ${msg("Invite Users")} |                           ${msg("Invite Users")} | ||||||
|                         </sl-menu-item>` |                         </sl-menu-item>` | ||||||
|                       : ""} |                       : ""} | ||||||
|                     <sl-menu-item @click="${this.onLogOut}" |                     <sl-divider></sl-divider> | ||||||
|                       >${msg("Log Out")}</sl-menu-item |                     <sl-menu-item @click="${this.onLogOut}"> | ||||||
|                     > |                       <sl-icon slot="prefix" name="box-arrow-right"></sl-icon> | ||||||
|  |                       ${msg("Log Out")} | ||||||
|  |                     </sl-menu-item> | ||||||
|                   </sl-menu> |                   </sl-menu> | ||||||
|                 </sl-dropdown>` |                 </sl-dropdown>` | ||||||
|               : html` |               : html` | ||||||
| @ -266,17 +291,36 @@ export class App extends LiteElement { | |||||||
|     `;
 |     `;
 | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   renderFooter() { | ||||||
|  |     return html` | ||||||
|  |       <footer | ||||||
|  |         class="w-full max-w-screen-lg mx-auto p-3 box-border flex justify-between" | ||||||
|  |       > | ||||||
|  |         <div> | ||||||
|  |           <sl-icon-button | ||||||
|  |             name="github" | ||||||
|  |             href="https://github.com/webrecorder/browsertrix-cloud" | ||||||
|  |             target="_blank" | ||||||
|  |           ></sl-icon-button> | ||||||
|  |         </div> | ||||||
|  |         <div> | ||||||
|  |           <btrix-locale-picker></btrix-locale-picker> | ||||||
|  |         </div> | ||||||
|  |       </footer> | ||||||
|  |     `;
 | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   renderPage() { |   renderPage() { | ||||||
|     switch (this.viewState.route) { |     switch (this.viewState.route) { | ||||||
|       case "signUp": { |       case "signUp": { | ||||||
|         if (!this.isAppSettingsLoaded) { |         if (!this.isAppSettingsLoaded) { | ||||||
|           return html`<div
 |           return html`<div
 | ||||||
|             class="w-full md:bg-gray-50 flex items-center justify-center" |             class="w-full md:bg-neutral-50 flex items-center justify-center" | ||||||
|           ></div>`;
 |           ></div>`;
 | ||||||
|         } |         } | ||||||
|         if (this.isRegistrationEnabled) { |         if (this.isRegistrationEnabled) { | ||||||
|           return html`<btrix-sign-up
 |           return html`<btrix-sign-up
 | ||||||
|             class="w-full md:bg-gray-50 flex items-center justify-center" |             class="w-full md:bg-neutral-50 flex items-center justify-center" | ||||||
|             @navigate="${this.onNavigateTo}" |             @navigate="${this.onNavigateTo}" | ||||||
|             @logged-in="${this.onLoggedIn}" |             @logged-in="${this.onLoggedIn}" | ||||||
|             @log-out="${this.onLogOut}" |             @log-out="${this.onLogOut}" | ||||||
| @ -289,7 +333,7 @@ export class App extends LiteElement { | |||||||
| 
 | 
 | ||||||
|       case "verify": |       case "verify": | ||||||
|         return html`<btrix-verify
 |         return html`<btrix-verify
 | ||||||
|           class="w-full md:bg-gray-50 flex items-center justify-center" |           class="w-full md:bg-neutral-50 flex items-center justify-center" | ||||||
|           token="${this.viewState.params.token}" |           token="${this.viewState.params.token}" | ||||||
|           @navigate="${this.onNavigateTo}" |           @navigate="${this.onNavigateTo}" | ||||||
|           @notify="${this.onNotify}" |           @notify="${this.onNotify}" | ||||||
| @ -300,7 +344,7 @@ export class App extends LiteElement { | |||||||
| 
 | 
 | ||||||
|       case "join": |       case "join": | ||||||
|         return html`<btrix-join
 |         return html`<btrix-join
 | ||||||
|           class="w-full md:bg-gray-50 flex items-center justify-center" |           class="w-full md:bg-neutral-50 flex items-center justify-center" | ||||||
|           @navigate="${this.onNavigateTo}" |           @navigate="${this.onNavigateTo}" | ||||||
|           @logged-in="${this.onLoggedIn}" |           @logged-in="${this.onLoggedIn}" | ||||||
|           token="${this.viewState.params.token}" |           token="${this.viewState.params.token}" | ||||||
| @ -309,7 +353,7 @@ export class App extends LiteElement { | |||||||
| 
 | 
 | ||||||
|       case "acceptInvite": |       case "acceptInvite": | ||||||
|         return html`<btrix-accept-invite
 |         return html`<btrix-accept-invite
 | ||||||
|           class="w-full md:bg-gray-50 flex items-center justify-center" |           class="w-full md:bg-neutral-50 flex items-center justify-center" | ||||||
|           @navigate="${this.onNavigateTo}" |           @navigate="${this.onNavigateTo}" | ||||||
|           @logged-in="${this.onLoggedIn}" |           @logged-in="${this.onLoggedIn}" | ||||||
|           @notify="${this.onNotify}" |           @notify="${this.onNotify}" | ||||||
| @ -322,7 +366,7 @@ export class App extends LiteElement { | |||||||
|       case "loginWithRedirect": |       case "loginWithRedirect": | ||||||
|       case "forgotPassword": |       case "forgotPassword": | ||||||
|         return html`<btrix-log-in
 |         return html`<btrix-log-in
 | ||||||
|           class="w-full md:bg-gray-50 flex items-center justify-center" |           class="w-full md:bg-neutral-50 flex items-center justify-center" | ||||||
|           @navigate=${this.onNavigateTo} |           @navigate=${this.onNavigateTo} | ||||||
|           @logged-in=${this.onLoggedIn} |           @logged-in=${this.onLoggedIn} | ||||||
|           .authState=${this.authService.authState} |           .authState=${this.authService.authState} | ||||||
| @ -332,7 +376,7 @@ export class App extends LiteElement { | |||||||
| 
 | 
 | ||||||
|       case "resetPassword": |       case "resetPassword": | ||||||
|         return html`<btrix-reset-password
 |         return html`<btrix-reset-password
 | ||||||
|           class="w-full md:bg-gray-50 flex items-center justify-center" |           class="w-full md:bg-neutral-50 flex items-center justify-center" | ||||||
|           @navigate=${this.onNavigateTo} |           @navigate=${this.onNavigateTo} | ||||||
|           @logged-in=${this.onLoggedIn} |           @logged-in=${this.onLoggedIn} | ||||||
|           .authState=${this.authService.authState} |           .authState=${this.authService.authState} | ||||||
| @ -352,7 +396,7 @@ export class App extends LiteElement { | |||||||
| 
 | 
 | ||||||
|       case "archives": |       case "archives": | ||||||
|         return html`<btrix-archives
 |         return html`<btrix-archives
 | ||||||
|           class="w-full max-w-screen-lg mx-auto p-2 md:py-8 box-border" |           class="w-full md:bg-neutral-50" | ||||||
|           @navigate="${this.onNavigateTo}" |           @navigate="${this.onNavigateTo}" | ||||||
|           @need-login="${this.onNeedLogin}" |           @need-login="${this.onNeedLogin}" | ||||||
|           .authState="${this.authService.authState}" |           .authState="${this.authService.authState}" | ||||||
| @ -412,7 +456,7 @@ export class App extends LiteElement { | |||||||
| 
 | 
 | ||||||
|   renderNotFoundPage() { |   renderNotFoundPage() { | ||||||
|     return html`<btrix-not-found
 |     return html`<btrix-not-found
 | ||||||
|       class="w-full md:bg-gray-50 flex items-center justify-center" |       class="w-full md:bg-neutral-50 flex items-center justify-center" | ||||||
|     ></btrix-not-found>`; |     ></btrix-not-found>`; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -18,34 +18,78 @@ export class Archives extends LiteElement { | |||||||
|   userInfo?: CurrentUser; |   userInfo?: CurrentUser; | ||||||
| 
 | 
 | ||||||
|   @state() |   @state() | ||||||
|   archiveList?: ArchiveData[]; |   private archiveList?: ArchiveData[]; | ||||||
|  | 
 | ||||||
|  |   @state() | ||||||
|  |   private isInviteComplete?: boolean; | ||||||
| 
 | 
 | ||||||
|   async firstUpdated() { |   async firstUpdated() { | ||||||
|     this.archiveList = await this.getArchives(); |     this.archiveList = await this.getArchives(); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   render() { |   render() { | ||||||
|     if (!this.archiveList) { |     if (!this.archiveList || !this.userInfo) { | ||||||
|       return html`<div
 |       return html` | ||||||
|         class="w-full flex items-center justify-center my-24 text-4xl" |         <div class="flex items-center justify-center my-24 text-4xl"> | ||||||
|       > |           <sl-spinner></sl-spinner> | ||||||
|         <sl-spinner></sl-spinner> |         </div> | ||||||
|  |       `;
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (this.userInfo.isAdmin && !this.archiveList.length) { | ||||||
|  |       return html` | ||||||
|  |         <div class="bg-white"> | ||||||
|  |           <header | ||||||
|  |             class="w-full max-w-screen-lg mx-auto px-3 py-4 box-border md:py-8" | ||||||
|  |           > | ||||||
|  |             <h1 class="text-2xl font-medium">${msg("Archives")}</h1> | ||||||
|  |             <p class="mt-4 text-neutral-600"> | ||||||
|  |               ${msg("Invite users to start archiving.")} | ||||||
|  |             </p> | ||||||
|  |           </header> | ||||||
|  |           <hr /> | ||||||
|  |         </div> | ||||||
|  |         <main class="w-full max-w-screen-lg mx-auto px-3 py-4 box-border"> | ||||||
|  |           ${this.renderAdminOnboarding()} | ||||||
|  |         </main> | ||||||
|  |       `;
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return html` | ||||||
|  |       <div class="bg-white"> | ||||||
|  |         <header | ||||||
|  |           class="w-full max-w-screen-lg mx-auto px-3 py-4 box-border md:py-8" | ||||||
|  |         > | ||||||
|  |           <h1 class="text-2xl font-medium">${msg("Archives")}</h1> | ||||||
|  |         </header> | ||||||
|  |         <hr /> | ||||||
|  |       </div> | ||||||
|  |       <main class="w-full max-w-screen-lg mx-auto px-3 py-4 box-border"> | ||||||
|  |         ${this.renderArchives()} | ||||||
|  |       </main> | ||||||
|  |     `;
 | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   private renderArchives() { | ||||||
|  |     if (!this.archiveList?.length) { | ||||||
|  |       return html`<div class="border rounded-lg bg-white p-4 md:p-8">
 | ||||||
|  |         <p class="text-neutral-400 text-center"> | ||||||
|  |           ${msg("You don't have any archives.")} | ||||||
|  |         </p> | ||||||
|       </div>`;
 |       </div>`;
 | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return html`<div class="grid gap-4">
 |     return html` | ||||||
|       <h1 class="text-xl font-bold">${msg("Archives")}</h1> |  | ||||||
| 
 |  | ||||||
|       <ul class="border rounded-lg overflow-hidden"> |       <ul class="border rounded-lg overflow-hidden"> | ||||||
|         ${this.archiveList.map( |         ${this.archiveList.map( | ||||||
|           (archive, i) => |           (archive) => | ||||||
|             html` |             html` | ||||||
|               <li |               <li | ||||||
|                 class="p-3 md:p-6 hover:bg-gray-50${i > 0 ? " border-t" : ""}" |                 class="p-3 md:p-6 bg-white border-t first:border-t-0 text-primary hover:text-indigo-400" | ||||||
|                 role="button" |                 role="button" | ||||||
|                 @click=${this.makeOnArchiveClick(archive)} |                 @click=${this.makeOnArchiveClick(archive)} | ||||||
|               > |               > | ||||||
|                 <span class="text-primary font-medium mr-2" |                 <span class="font-medium mr-2 transition-colors" | ||||||
|                   >${archive.name}</span |                   >${archive.name}</span | ||||||
|                 > |                 > | ||||||
|                 ${this.userInfo && |                 ${this.userInfo && | ||||||
| @ -59,7 +103,33 @@ export class Archives extends LiteElement { | |||||||
|             ` |             ` | ||||||
|         )} |         )} | ||||||
|       </ul> |       </ul> | ||||||
|     </div>`;
 |     `;
 | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   private renderAdminOnboarding() { | ||||||
|  |     if (this.isInviteComplete) { | ||||||
|  |       return html` | ||||||
|  |         <div class="border rounded-lg bg-white p-4 md:p-8"> | ||||||
|  |           <h2 class="text-2xl font-medium mb-4">${msg("Invite a User")}</h2> | ||||||
|  |           <sl-button @click=${() => (this.isInviteComplete = false)} | ||||||
|  |             >${msg("Send another invite")}</sl-button | ||||||
|  |           > | ||||||
|  |         </div> | ||||||
|  |       `;
 | ||||||
|  |     } | ||||||
|  |     return html` | ||||||
|  |       <div class="border rounded-lg bg-white p-4 md:p-8"> | ||||||
|  |         <h2 class="text-2xl font-medium mb-4">${msg("Invite a User")}</h2> | ||||||
|  |         <p class="mb-4 text-neutral-600 text-sm"> | ||||||
|  |           ${msg("Each user will manage their own archive.")} | ||||||
|  |         </p> | ||||||
|  | 
 | ||||||
|  |         <btrix-invite-form | ||||||
|  |           .authState=${this.authState} | ||||||
|  |           @success=${() => (this.isInviteComplete = true)} | ||||||
|  |         ></btrix-invite-form> | ||||||
|  |       </div> | ||||||
|  |     `;
 | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   async getArchives(): Promise<ArchiveData[]> { |   async getArchives(): Promise<ArchiveData[]> { | ||||||
|  | |||||||
| @ -20,6 +20,9 @@ import( | |||||||
| import( | import( | ||||||
|   /* webpackChunkName: "shoelace" */ "@shoelace-style/shoelace/dist/components/dialog/dialog" |   /* webpackChunkName: "shoelace" */ "@shoelace-style/shoelace/dist/components/dialog/dialog" | ||||||
| ); | ); | ||||||
|  | import( | ||||||
|  |   /* webpackChunkName: "shoelace" */ "@shoelace-style/shoelace/dist/components/divider/divider" | ||||||
|  | ); | ||||||
| import( | import( | ||||||
|   /* webpackChunkName: "shoelace" */ "@shoelace-style/shoelace/dist/components/form/form" |   /* webpackChunkName: "shoelace" */ "@shoelace-style/shoelace/dist/components/form/form" | ||||||
| ); | ); | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user