parent
							
								
									ba69ac02bc
								
							
						
					
					
						commit
						d5c665be8e
					
				@ -288,13 +288,25 @@ export class App extends LiteElement {
 | 
			
		||||
      case "join":
 | 
			
		||||
        return html`<btrix-join
 | 
			
		||||
          class="w-full md:bg-gray-100 flex items-center justify-center"
 | 
			
		||||
          @navigate="${this.onNavigateTo}"
 | 
			
		||||
          @logged-in="${this.onLoggedIn}"
 | 
			
		||||
          .authState="${this.authService.authState}"
 | 
			
		||||
          token="${this.viewState.params.token}"
 | 
			
		||||
          email="${this.viewState.params.email}"
 | 
			
		||||
        ></btrix-join>`;
 | 
			
		||||
 | 
			
		||||
      case "acceptInvite":
 | 
			
		||||
        return html`<btrix-accept-invite
 | 
			
		||||
          class="w-full md:bg-gray-100 flex items-center justify-center"
 | 
			
		||||
          @navigate="${this.onNavigateTo}"
 | 
			
		||||
          @logged-in="${this.onLoggedIn}"
 | 
			
		||||
          @notify="${this.onNotify}"
 | 
			
		||||
          .authState="${this.authService.authState}"
 | 
			
		||||
          token="${this.viewState.params.token}"
 | 
			
		||||
          email="${this.viewState.params.email}"
 | 
			
		||||
        ></btrix-accept-invite>`;
 | 
			
		||||
 | 
			
		||||
      case "login":
 | 
			
		||||
      case "loginWithRedirect":
 | 
			
		||||
      case "forgotPassword":
 | 
			
		||||
        return html`<btrix-log-in
 | 
			
		||||
          class="w-full md:bg-gray-100 flex items-center justify-center"
 | 
			
		||||
@ -302,6 +314,7 @@ export class App extends LiteElement {
 | 
			
		||||
          @logged-in=${this.onLoggedIn}
 | 
			
		||||
          .authState=${this.authService.authState}
 | 
			
		||||
          .viewState=${this.viewState}
 | 
			
		||||
          redirectUrl=${this.viewState.params.redirectUrl}
 | 
			
		||||
        ></btrix-log-in>`;
 | 
			
		||||
 | 
			
		||||
      case "resetPassword":
 | 
			
		||||
@ -413,7 +426,7 @@ export class App extends LiteElement {
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    if (!detail.api) {
 | 
			
		||||
      this.navigate(DASHBOARD_ROUTE);
 | 
			
		||||
      this.navigate(detail.redirectUrl || DASHBOARD_ROUTE);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (detail.firstLogin) {
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										129
									
								
								frontend/src/pages/accept-invite.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										129
									
								
								frontend/src/pages/accept-invite.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,129 @@
 | 
			
		||||
import { state, property } from "lit/decorators.js";
 | 
			
		||||
import { msg, localized } from "@lit/localize";
 | 
			
		||||
 | 
			
		||||
import LiteElement, { html } from "../utils/LiteElement";
 | 
			
		||||
import type { AuthState, LoggedInEvent } from "../utils/AuthService";
 | 
			
		||||
import AuthService from "../utils/AuthService";
 | 
			
		||||
import { DASHBOARD_ROUTE } from "../routes";
 | 
			
		||||
 | 
			
		||||
@localized()
 | 
			
		||||
export class AcceptInvite extends LiteElement {
 | 
			
		||||
  @property({ type: Object })
 | 
			
		||||
  authState?: AuthState;
 | 
			
		||||
 | 
			
		||||
  @property({ type: String })
 | 
			
		||||
  token?: string;
 | 
			
		||||
 | 
			
		||||
  @property({ type: String })
 | 
			
		||||
  email?: string;
 | 
			
		||||
 | 
			
		||||
  @state()
 | 
			
		||||
  serverError?: string;
 | 
			
		||||
 | 
			
		||||
  connectedCallback(): void {
 | 
			
		||||
    if (this.token && this.email) {
 | 
			
		||||
      super.connectedCallback();
 | 
			
		||||
    } else {
 | 
			
		||||
      throw new Error("Missing email or token");
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private get isLoggedIn(): boolean {
 | 
			
		||||
    return Boolean(
 | 
			
		||||
      this.authState && this.email && this.authState.username === this.email
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  firstUpdated() {
 | 
			
		||||
    if (!this.isLoggedIn) {
 | 
			
		||||
      this.dispatchEvent(
 | 
			
		||||
        new CustomEvent("notify", {
 | 
			
		||||
          detail: {
 | 
			
		||||
            message: msg("Log in to continue."),
 | 
			
		||||
            type: "success",
 | 
			
		||||
            icon: "check2-circle",
 | 
			
		||||
            duration: 10000,
 | 
			
		||||
          },
 | 
			
		||||
        })
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
      this.navTo(
 | 
			
		||||
        `/log-in?redirectUrl=${encodeURIComponent(
 | 
			
		||||
          `${window.location.pathname}${window.location.search}`
 | 
			
		||||
        )}`
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  render() {
 | 
			
		||||
    let serverError;
 | 
			
		||||
 | 
			
		||||
    if (this.serverError) {
 | 
			
		||||
      serverError = html`
 | 
			
		||||
        <div class="mb-5">
 | 
			
		||||
          <btrix-alert id="formError" type="danger"
 | 
			
		||||
            >${this.serverError}</btrix-alert
 | 
			
		||||
          >
 | 
			
		||||
        </div>
 | 
			
		||||
      `;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return html`
 | 
			
		||||
      <article class="w-full max-w-sm grid gap-5">
 | 
			
		||||
        ${serverError}
 | 
			
		||||
 | 
			
		||||
        <main class="md:bg-white md:shadow-xl md:rounded-lg md:px-12 md:py-12">
 | 
			
		||||
          <h1 class="text-3xl text-center font-semibold mb-5">
 | 
			
		||||
            ${msg("Join archive")}
 | 
			
		||||
          </h1>
 | 
			
		||||
 | 
			
		||||
          <!-- TODO archive details -->
 | 
			
		||||
 | 
			
		||||
          <div class="text-center">
 | 
			
		||||
            <sl-button type="primary" @click=${this.onAccept}
 | 
			
		||||
              >${msg("Accept invitation")}</sl-button
 | 
			
		||||
            >
 | 
			
		||||
          </div>
 | 
			
		||||
        </main>
 | 
			
		||||
      </article>
 | 
			
		||||
    `;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private async onAccept() {
 | 
			
		||||
    if (!this.authState || !this.isLoggedIn) {
 | 
			
		||||
      // TODO handle error
 | 
			
		||||
      this.serverError = msg("Something unexpected went wrong");
 | 
			
		||||
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    try {
 | 
			
		||||
      await this.apiFetch(
 | 
			
		||||
        `/archives/invite-accept/${this.token}`,
 | 
			
		||||
        this.authState,
 | 
			
		||||
        {
 | 
			
		||||
          method: "POST",
 | 
			
		||||
        }
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
      this.dispatchEvent(
 | 
			
		||||
        new CustomEvent("notify", {
 | 
			
		||||
          detail: {
 | 
			
		||||
            // TODO archive details
 | 
			
		||||
            message: msg("You've joined the archive."),
 | 
			
		||||
            type: "success",
 | 
			
		||||
            icon: "check2-circle",
 | 
			
		||||
          },
 | 
			
		||||
        })
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
      this.navTo(DASHBOARD_ROUTE);
 | 
			
		||||
    } catch (err: any) {
 | 
			
		||||
      if (err.isApiError && err.message === "Invalid Invite Code") {
 | 
			
		||||
        this.serverError = msg("This invitation is not valid.");
 | 
			
		||||
      } else {
 | 
			
		||||
        this.serverError = msg("Something unexpected went wrong");
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -36,12 +36,12 @@ export class Archives extends LiteElement {
 | 
			
		||||
    return html`<div class="grid gap-4">
 | 
			
		||||
      <h1 class="text-xl font-bold">${msg("Archives")}</h1>
 | 
			
		||||
 | 
			
		||||
      <ul class="border rounded-lg grid gap-6 overflow-hidden">
 | 
			
		||||
      <ul class="border rounded-lg overflow-hidden">
 | 
			
		||||
        ${this.archiveList.map(
 | 
			
		||||
          (archive) =>
 | 
			
		||||
          (archive, i) =>
 | 
			
		||||
            html`
 | 
			
		||||
              <li
 | 
			
		||||
                class="p-3 md:p-6 hover:bg-gray-50"
 | 
			
		||||
                class="p-3 md:p-6 hover:bg-gray-50${i > 0 ? " border-t" : ""}"
 | 
			
		||||
                role="button"
 | 
			
		||||
                @click=${this.makeOnArchiveClick(archive)}
 | 
			
		||||
              >
 | 
			
		||||
 | 
			
		||||
@ -26,3 +26,8 @@ import(/* webpackChunkName: "users-invite" */ "./users-invite").then(
 | 
			
		||||
    customElements.define("btrix-users-invite", UsersInvite);
 | 
			
		||||
  }
 | 
			
		||||
);
 | 
			
		||||
import(/* webpackChunkName: "accept-invite" */ "./accept-invite").then(
 | 
			
		||||
  ({ AcceptInvite }) => {
 | 
			
		||||
    customElements.define("btrix-accept-invite", AcceptInvite);
 | 
			
		||||
  }
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
@ -1,99 +1,12 @@
 | 
			
		||||
import { state, property } from "lit/decorators.js";
 | 
			
		||||
import { msg, localized, str } from "@lit/localize";
 | 
			
		||||
import { createMachine, interpret, assign } from "@xstate/fsm";
 | 
			
		||||
import { msg, localized } from "@lit/localize";
 | 
			
		||||
 | 
			
		||||
import { DASHBOARD_ROUTE } from "../routes";
 | 
			
		||||
import type { AuthState } from "../utils/AuthService";
 | 
			
		||||
import LiteElement, { html } from "../utils/LiteElement";
 | 
			
		||||
import type { LoggedInEvent } from "../utils/AuthService";
 | 
			
		||||
import AuthService from "../utils/AuthService";
 | 
			
		||||
 | 
			
		||||
type JoinContext = {
 | 
			
		||||
  serverError?: string;
 | 
			
		||||
};
 | 
			
		||||
type JoinErrorEvent = {
 | 
			
		||||
  type: "ERROR";
 | 
			
		||||
  detail: {
 | 
			
		||||
    serverError?: JoinContext["serverError"];
 | 
			
		||||
  };
 | 
			
		||||
};
 | 
			
		||||
type JoinEvent =
 | 
			
		||||
  | { type: "SUBMIT_SIGN_UP" }
 | 
			
		||||
  | { type: "ACCEPT_INVITE" }
 | 
			
		||||
  | { type: "SIGN_UP_SUCCESS" }
 | 
			
		||||
  | JoinErrorEvent;
 | 
			
		||||
type JoinTypestate =
 | 
			
		||||
  | {
 | 
			
		||||
      value: "initial";
 | 
			
		||||
      context: JoinContext;
 | 
			
		||||
    }
 | 
			
		||||
  | {
 | 
			
		||||
      value: "submittingForm";
 | 
			
		||||
      context: JoinContext;
 | 
			
		||||
    }
 | 
			
		||||
  | {
 | 
			
		||||
      value: "acceptInvite";
 | 
			
		||||
      context: JoinContext;
 | 
			
		||||
    }
 | 
			
		||||
  | {
 | 
			
		||||
      value: "acceptingInvite";
 | 
			
		||||
      context: JoinContext;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
const initialContext = {};
 | 
			
		||||
 | 
			
		||||
const machine = createMachine<JoinContext, JoinEvent, JoinTypestate>(
 | 
			
		||||
  {
 | 
			
		||||
    id: "join",
 | 
			
		||||
    initial: "initial",
 | 
			
		||||
    context: initialContext,
 | 
			
		||||
    states: {
 | 
			
		||||
      ["initial"]: {
 | 
			
		||||
        on: {
 | 
			
		||||
          SUBMIT_SIGN_UP: "submittingForm",
 | 
			
		||||
        },
 | 
			
		||||
      },
 | 
			
		||||
      ["submittingForm"]: {
 | 
			
		||||
        on: {
 | 
			
		||||
          SIGN_UP_SUCCESS: "acceptInvite",
 | 
			
		||||
          ERROR: {
 | 
			
		||||
            target: "initial",
 | 
			
		||||
            actions: "setError",
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
      },
 | 
			
		||||
      ["acceptInvite"]: {
 | 
			
		||||
        on: {
 | 
			
		||||
          ACCEPT_INVITE: "acceptingInvite",
 | 
			
		||||
        },
 | 
			
		||||
      },
 | 
			
		||||
      ["acceptingInvite"]: {
 | 
			
		||||
        on: {
 | 
			
		||||
          ERROR: {
 | 
			
		||||
            target: "acceptInvite",
 | 
			
		||||
            actions: "setError",
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    actions: {
 | 
			
		||||
      setError: assign((context, event) => ({
 | 
			
		||||
        ...context,
 | 
			
		||||
        ...(event as JoinErrorEvent).detail,
 | 
			
		||||
      })),
 | 
			
		||||
    },
 | 
			
		||||
  }
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
@localized()
 | 
			
		||||
export class Join extends LiteElement {
 | 
			
		||||
  private joinStateService = interpret(machine);
 | 
			
		||||
 | 
			
		||||
  @property({ type: Object })
 | 
			
		||||
  authState?: AuthState;
 | 
			
		||||
 | 
			
		||||
  @property({ type: String })
 | 
			
		||||
  token?: string;
 | 
			
		||||
 | 
			
		||||
@ -101,7 +14,7 @@ export class Join extends LiteElement {
 | 
			
		||||
  email?: string;
 | 
			
		||||
 | 
			
		||||
  @state()
 | 
			
		||||
  private joinState = machine.initialState;
 | 
			
		||||
  serverError?: string;
 | 
			
		||||
 | 
			
		||||
  connectedCallback(): void {
 | 
			
		||||
    if (this.token && this.email) {
 | 
			
		||||
@ -111,151 +24,33 @@ export class Join extends LiteElement {
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  firstUpdated() {
 | 
			
		||||
    // Enable state machine
 | 
			
		||||
    this.joinStateService.subscribe((state) => {
 | 
			
		||||
      this.joinState = state;
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    this.joinStateService.start();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  disconnectedCallback() {
 | 
			
		||||
    this.joinStateService.stop();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  render() {
 | 
			
		||||
    const isSignUp =
 | 
			
		||||
      this.joinState.value === "initial" ||
 | 
			
		||||
      this.joinState.value === "submittingForm";
 | 
			
		||||
    const isAcceptInvite =
 | 
			
		||||
      this.joinState.value === "acceptInvite" ||
 | 
			
		||||
      this.joinState.value === "acceptingInvite";
 | 
			
		||||
 | 
			
		||||
    let content;
 | 
			
		||||
 | 
			
		||||
    if (isSignUp) {
 | 
			
		||||
      content = this.renderSignUp();
 | 
			
		||||
    } else if (isAcceptInvite) {
 | 
			
		||||
      content = this.renderAccept();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return html`
 | 
			
		||||
      <article class="w-full max-w-sm grid gap-5">
 | 
			
		||||
        <h1 class="text-3xl font-semibold mb-3">${msg("Join archive")}</h1>
 | 
			
		||||
 | 
			
		||||
        <!-- TODO invitation details -->
 | 
			
		||||
 | 
			
		||||
        <div class="flex items-center text-sm font-medium">
 | 
			
		||||
          <div
 | 
			
		||||
            class="flex-0 mx-3 ${isSignUp ? "text-primary" : "text-blue-400"}"
 | 
			
		||||
          >
 | 
			
		||||
            1. Create account
 | 
			
		||||
          </div>
 | 
			
		||||
          <hr
 | 
			
		||||
            class="flex-1 mx-3 ${isSignUp
 | 
			
		||||
              ? "border-gray-400"
 | 
			
		||||
              : "border-blue-400"}"
 | 
			
		||||
          />
 | 
			
		||||
          <div
 | 
			
		||||
            class="flex-0 mx-3 ${isSignUp ? "text-gray-400" : "text-primary"}"
 | 
			
		||||
          >
 | 
			
		||||
            2. Accept invite
 | 
			
		||||
          </div>
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        <main class="md:bg-white md:shadow-xl md:rounded-lg md:px-12 md:py-12">
 | 
			
		||||
          ${content}
 | 
			
		||||
          <h1 class="text-3xl font-semibold mb-5">
 | 
			
		||||
            ${msg("Join Browsertrix Cloud")}
 | 
			
		||||
          </h1>
 | 
			
		||||
 | 
			
		||||
          <!-- TODO archive details if available -->
 | 
			
		||||
 | 
			
		||||
          <btrix-sign-up-form
 | 
			
		||||
            email=${this.email!}
 | 
			
		||||
            inviteToken=${this.token!}
 | 
			
		||||
            @authenticated=${this.onAuthenticated}
 | 
			
		||||
          ></btrix-sign-up-form>
 | 
			
		||||
        </main>
 | 
			
		||||
      </article>
 | 
			
		||||
    `;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private renderSignUp() {
 | 
			
		||||
    return html`
 | 
			
		||||
      <btrix-sign-up-form
 | 
			
		||||
        email=${this.email!}
 | 
			
		||||
        inviteToken=${this.token!}
 | 
			
		||||
        @submit=${this.onSignUp}
 | 
			
		||||
        @error=${() => this.joinStateService.send("ERROR")}
 | 
			
		||||
        @authenticated=${this.onAuthenticated}
 | 
			
		||||
      ></btrix-sign-up-form>
 | 
			
		||||
    `;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private renderAccept() {
 | 
			
		||||
    let serverError;
 | 
			
		||||
 | 
			
		||||
    if (this.joinState.context.serverError) {
 | 
			
		||||
      serverError = html`
 | 
			
		||||
        <div class="mb-5">
 | 
			
		||||
          <btrix-alert id="formError" type="danger"
 | 
			
		||||
            >${this.joinState.context.serverError}</btrix-alert
 | 
			
		||||
          >
 | 
			
		||||
        </div>
 | 
			
		||||
      `;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return html`
 | 
			
		||||
      ${serverError}
 | 
			
		||||
 | 
			
		||||
      <div class="text-center">
 | 
			
		||||
        <sl-button type="primary" @click=${this.onAccept}
 | 
			
		||||
          >Accept invitation</sl-button
 | 
			
		||||
        >
 | 
			
		||||
      </div>
 | 
			
		||||
    `;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private onSignUp() {
 | 
			
		||||
    this.joinStateService.send("SUBMIT_SIGN_UP");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private onAuthenticated(event: LoggedInEvent) {
 | 
			
		||||
    this.joinStateService.send("SIGN_UP_SUCCESS");
 | 
			
		||||
 | 
			
		||||
    this.dispatchEvent(
 | 
			
		||||
      AuthService.createLoggedInEvent({
 | 
			
		||||
        ...event.detail,
 | 
			
		||||
        api: true,
 | 
			
		||||
        // TODO separate logic for confirmation message
 | 
			
		||||
        // firstLogin: true,
 | 
			
		||||
      })
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private async onAccept() {
 | 
			
		||||
    this.joinStateService.send("ACCEPT_INVITE");
 | 
			
		||||
 | 
			
		||||
    if (!this.authState) {
 | 
			
		||||
      this.joinStateService.send({
 | 
			
		||||
        type: "ERROR",
 | 
			
		||||
        detail: {
 | 
			
		||||
          serverError: msg("Something unexpected went wrong"),
 | 
			
		||||
        },
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    try {
 | 
			
		||||
      await this.apiFetch(`/invite/accept/${this.token}`, this.authState);
 | 
			
		||||
 | 
			
		||||
      this.navTo(DASHBOARD_ROUTE);
 | 
			
		||||
    } catch (err: any) {
 | 
			
		||||
      if (err.isApiError && err.message === "Invalid Invite Code") {
 | 
			
		||||
        this.joinStateService.send({
 | 
			
		||||
          type: "ERROR",
 | 
			
		||||
          detail: {
 | 
			
		||||
            serverError: msg("This invitation is not valid."),
 | 
			
		||||
          },
 | 
			
		||||
        });
 | 
			
		||||
      } else {
 | 
			
		||||
        this.joinStateService.send({
 | 
			
		||||
          type: "ERROR",
 | 
			
		||||
          detail: {
 | 
			
		||||
            serverError: msg("Something unexpected went wrong"),
 | 
			
		||||
          },
 | 
			
		||||
        });
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -4,7 +4,9 @@ import { createMachine, interpret, assign } from "@xstate/fsm";
 | 
			
		||||
 | 
			
		||||
import type { ViewState } from "../utils/APIRouter";
 | 
			
		||||
import LiteElement, { html } from "../utils/LiteElement";
 | 
			
		||||
import type { LoggedInEventDetail } from "../utils/AuthService";
 | 
			
		||||
import AuthService from "../utils/AuthService";
 | 
			
		||||
import { DASHBOARD_ROUTE } from "../routes";
 | 
			
		||||
 | 
			
		||||
type FormContext = {
 | 
			
		||||
  successMessage?: string;
 | 
			
		||||
@ -126,6 +128,9 @@ export class LogInPage extends LiteElement {
 | 
			
		||||
  @property({ type: Object })
 | 
			
		||||
  viewState!: ViewState;
 | 
			
		||||
 | 
			
		||||
  @property({ type: String })
 | 
			
		||||
  redirectUrl: string = DASHBOARD_ROUTE;
 | 
			
		||||
 | 
			
		||||
  private formStateService = interpret(machine);
 | 
			
		||||
 | 
			
		||||
  @state()
 | 
			
		||||
@ -308,6 +313,8 @@ export class LogInPage extends LiteElement {
 | 
			
		||||
    try {
 | 
			
		||||
      const data = await AuthService.login({ email: username, password });
 | 
			
		||||
 | 
			
		||||
      (data as LoggedInEventDetail).redirectUrl = this.redirectUrl;
 | 
			
		||||
 | 
			
		||||
      this.dispatchEvent(AuthService.createLoggedInEvent(data));
 | 
			
		||||
 | 
			
		||||
      // no state update here, since "logged-in" event
 | 
			
		||||
 | 
			
		||||
@ -2,8 +2,10 @@ export const ROUTES = {
 | 
			
		||||
  home: "/",
 | 
			
		||||
  join: "/join/:token?email",
 | 
			
		||||
  signUp: "/sign-up",
 | 
			
		||||
  acceptInvite: "/invite/accept/:token?email",
 | 
			
		||||
  verify: "/verify?token",
 | 
			
		||||
  login: "/log-in",
 | 
			
		||||
  loginWithRedirect: "/log-in?redirectUrl",
 | 
			
		||||
  forgotPassword: "/log-in/forgot-password",
 | 
			
		||||
  resetPassword: "/reset-password?token",
 | 
			
		||||
  myAccount: "/my-account",
 | 
			
		||||
 | 
			
		||||
@ -14,9 +14,10 @@ type Session = {
 | 
			
		||||
 | 
			
		||||
export type AuthState = (Auth & Session) | null;
 | 
			
		||||
 | 
			
		||||
type LoggedInEventDetail = Auth & {
 | 
			
		||||
export type LoggedInEventDetail = Auth & {
 | 
			
		||||
  api?: boolean;
 | 
			
		||||
  firstLogin?: boolean;
 | 
			
		||||
  redirectUrl?: string;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export interface LoggedInEvent<T = LoggedInEventDetail> extends CustomEvent {
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user