@sneat/auth-ui 0.5.3 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,8 +1,9 @@
1
- import { Component, signal, inject } from '@angular/core';
1
+ import { Component, computed, signal, inject } from '@angular/core';
2
+ import { toSignal } from '@angular/core/rxjs-interop';
2
3
  import { FormsModule } from '@angular/forms';
3
4
  import { ActivatedRoute } from '@angular/router';
4
5
  import { Capacitor } from '@capacitor/core';
5
- import { NavController, IonBackButton, IonButtons, IonCard, IonCardContent, IonCol, IonContent, IonGrid, IonHeader, IonIcon, IonItem, IonItemDivider, IonLabel, IonList, IonRow, IonSpinner, IonText, IonTitle, IonToolbar, } from '@ionic/angular/standalone';
6
+ import { NavController, IonBackButton, IonButton, IonButtons, IonCard, IonCardContent, IonCol, IonContent, IonGrid, IonHeader, IonIcon, IonItem, IonItemDivider, IonLabel, IonList, IonRow, IonSpinner, IonText, IonTitle, IonToolbar, } from '@ionic/angular/standalone';
6
7
  import { AuthStatuses, LoginEventsHandler, SneatAuthStateService, } from '@sneat/auth-core';
7
8
  import { SneatUserService } from '@sneat/auth-core';
8
9
  import { AnalyticsService, APP_INFO, currentSpacePath, } from '@sneat/core';
@@ -24,6 +25,18 @@ export class LoginPageComponent extends SneatBaseComponent {
24
25
  this.loginEventsHandler = inject(LoginEventsHandler, { optional: true });
25
26
  this.signingWith = signal(undefined, ...(ngDevMode ? [{ debugName: "signingWith" }] : []));
26
27
  this.isNativePlatform = Capacitor.isNativePlatform();
28
+ // Surfaces the Firebase auth state on the login page itself: if the user is
29
+ // already signed in (e.g. the app failed to navigate them onward) we show a
30
+ // "you are already signed in as X" panel instead of the sign-in form, so an
31
+ // authenticated-but-stuck state is obvious rather than looking like sign-in
32
+ // is broken.
33
+ this.isAuthenticated = computed(() => this.authStatus() === 'authenticated', ...(ngDevMode ? [{ debugName: "isAuthenticated" }] : []));
34
+ this.authStatus = toSignal(this.authStateService.authStatus);
35
+ this.authUser = toSignal(this.authStateService.authUser);
36
+ this.signedInAs = computed(() => {
37
+ const u = this.authUser();
38
+ return u?.displayName || u?.email || u?.uid || '';
39
+ }, ...(ngDevMode ? [{ debugName: "signedInAs" }] : []));
27
40
  const appInfo = this.appInfo;
28
41
  this.appTitle = appInfo.appTitle || 'Sneat.app';
29
42
  if (location.hash.startsWith('#/')) {
@@ -55,6 +68,19 @@ export class LoginPageComponent extends SneatBaseComponent {
55
68
  onEmailFormStatusChanged(signingWith) {
56
69
  this.signingWith.set(signingWith);
57
70
  }
71
+ // Proceed into the app from the "already signed in" panel.
72
+ continueToApp() {
73
+ const redirectTo = this.redirectTo || currentSpacePath() || '/';
74
+ this.navController
75
+ .navigateRoot(redirectTo)
76
+ .catch(this.errorLogger.logErrorHandler('Failed to navigate to ' + redirectTo));
77
+ }
78
+ // Sign out so the sign-in form is shown again (e.g. to log in as someone else).
79
+ reLogin() {
80
+ this.authStateService
81
+ .signOut()
82
+ .catch(this.errorLogger.logErrorHandler('Failed to sign out for re-login'));
83
+ }
58
84
  async loginWith(provider) {
59
85
  this.signingWith.set(provider);
60
86
  try {
@@ -107,7 +133,7 @@ export class LoginPageComponent extends SneatBaseComponent {
107
133
  useValue: 'LoginPageComponent',
108
134
  },
109
135
  RandomIdService,
110
- ], usesInheritance: true, ngImport: i0, template: "<ion-header>\n <ion-toolbar color=\"light\">\n <ion-buttons slot=\"start\">\n <ion-back-button />\n </ion-buttons>\n <ion-title>Login &#64; {{ appTitle }}</ion-title>\n </ion-toolbar>\n</ion-header>\n\n<ion-content id=\"main-content\">\n @if (to) {\n <ion-card color=\"tertiary\">\n <ion-card-content>\n <p>Please sign in to join a team</p>\n </ion-card-content>\n </ion-card>\n }\n\n <p style=\"text-align: center; font-size: smaller\">\n <ion-text color=\"medium\">\n This app is free to use &\n <a target=\"_blank\" href=\"https://github.com/sneat-co\">open source</a>.\n </ion-text>\n </p>\n\n <sneat-email-login-form\n (signingWithChange)=\"onEmailFormStatusChanged()\"\n (loggedIn)=\"onLoggedIn($event)\"\n />\n\n <ion-card>\n <ion-item-divider color=\"light\">\n <ion-label\n color=\"medium\"\n style=\"text-align: center; width: 100%; font-weight: bold\"\n >\n Quick login\n </ion-label>\n </ion-item-divider>\n <ion-grid class=\"ion-grid-layout\">\n @if (!isNativePlatform) {\n <ion-row>\n <ion-col>\n <div class=\"ion-padding\" style=\"text-align: center\">\n <sneat-login-with-telegram />\n </div>\n </ion-col>\n </ion-row>\n }\n <ion-row>\n <ion-col size=\"12\" size-md=\"6\">\n <ion-list lines=\"none\">\n <ion-item\n (click)=\"loginWith('google.com')\"\n tappable\n [disabled]=\"!!signingWith()\"\n >\n @if (signingWith() === \"google.com\") {\n <ion-spinner slot=\"start\" name=\"lines-small\" />\n } @else {\n <ion-icon color=\"danger\" name=\"logo-google\" slot=\"start\" />\n }\n <ion-label color=\"danger\"> Login with Google</ion-label>\n </ion-item>\n </ion-list>\n </ion-col>\n <ion-col size=\"12\" size-md=\"6\">\n <ion-list lines=\"none\">\n <ion-item\n (click)=\"loginWith('apple.com')\"\n tappable\n [disabled]=\"!!signingWith()\"\n >\n @if (signingWith() === \"apple.com\") {\n <ion-spinner slot=\"start\" name=\"lines-small\" />\n } @else {\n <ion-icon color=\"dark\" name=\"logo-apple\" slot=\"start\" />\n }\n\n <ion-label color=\"dark\"> Login with Apple</ion-label>\n </ion-item>\n </ion-list>\n </ion-col>\n </ion-row>\n <ion-row>\n <ion-col size=\"12\" size-md=\"6\">\n <ion-list lines=\"none\">\n <ion-item\n (click)=\"loginWith('microsoft.com')\"\n tappable\n [disabled]=\"!!signingWith()\"\n >\n @if (signingWith() === \"microsoft.com\") {\n <ion-spinner\n slot=\"start\"\n color=\"secondary\"\n name=\"lines-small\"\n />\n } @else {\n <ion-icon slot=\"start\" color=\"secondary\" name=\"logo-windows\" />\n }\n <ion-label color=\"secondary\">Login with Microsoft</ion-label>\n </ion-item>\n </ion-list>\n </ion-col>\n <ion-col size=\"12\" size-md=\"6\">\n <ion-list lines=\"none\">\n <ion-item\n (click)=\"loginWith('facebook.com')\"\n tappable\n [disabled]=\"!!signingWith()\"\n >\n @if (signingWith() === \"facebook.com\") {\n <ion-spinner slot=\"start\" color=\"primary\" name=\"lines-small\" />\n } @else {\n <ion-icon slot=\"start\" color=\"primary\" name=\"logo-facebook\" />\n }\n <ion-label color=\"primary\">Login with Facebook</ion-label>\n </ion-item>\n </ion-list>\n </ion-col>\n </ion-row>\n <ion-row>\n <ion-col size=\"12\" size-md=\"6\">\n <ion-list lines=\"none\">\n <ion-item\n (click)=\"loginWith('github.com')\"\n tappable\n [disabled]=\"!!signingWith()\"\n >\n @if (signingWith() === \"github.com\") {\n <ion-spinner slot=\"start\" color=\"tertiary\" name=\"lines-small\" />\n } @else {\n <ion-icon slot=\"start\" color=\"tertiary\" name=\"logo-github\" />\n }\n <ion-label color=\"tertiary\">Login with GitHub</ion-label>\n </ion-item>\n </ion-list>\n </ion-col>\n </ion-row>\n </ion-grid>\n </ion-card>\n\n <p style=\"text-align: center; font-size: smaller\">\n <ion-text color=\"medium\">\n If any issues get\n <a href=\"mailto:help@sneat.app?subject=Problem+with+login+at+Sneat.app\"\n >help&#64;sneat.app</a\n >\n </ion-text>\n </p>\n</ion-content>\n", dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "component", type: LoginWithTelegramComponent, selector: "sneat-login-with-telegram", inputs: ["isUserAuthenticated", "botID", "size", "requestAccess", "userPic"] }, { kind: "component", type: EmailLoginFormComponent, selector: "sneat-email-login-form", outputs: ["signingWithChange", "loggedIn"] }, { kind: "component", type: IonHeader, selector: "ion-header", inputs: ["collapse", "mode", "translucent"] }, { kind: "component", type: IonToolbar, selector: "ion-toolbar", inputs: ["color", "mode"] }, { kind: "component", type: IonButtons, selector: "ion-buttons", inputs: ["collapse"] }, { kind: "component", type: IonBackButton, selector: "ion-back-button" }, { kind: "component", type: IonTitle, selector: "ion-title", inputs: ["color", "size"] }, { kind: "component", type: IonContent, selector: "ion-content", inputs: ["color", "fixedSlotPlacement", "forceOverscroll", "fullscreen", "scrollEvents", "scrollX", "scrollY"] }, { kind: "component", type: IonCardContent, selector: "ion-card-content", inputs: ["mode"] }, { kind: "component", type: IonText, selector: "ion-text", inputs: ["color", "mode"] }, { kind: "component", type: IonCard, selector: "ion-card", inputs: ["button", "color", "disabled", "download", "href", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] }, { kind: "component", type: IonItemDivider, selector: "ion-item-divider", inputs: ["color", "mode", "sticky"] }, { kind: "component", type: IonLabel, selector: "ion-label", inputs: ["color", "mode", "position"] }, { kind: "component", type: IonRow, selector: "ion-row" }, { kind: "component", type: IonCol, selector: "ion-col", inputs: ["offset", "offsetLg", "offsetMd", "offsetSm", "offsetXl", "offsetXs", "pull", "pullLg", "pullMd", "pullSm", "pullXl", "pullXs", "push", "pushLg", "pushMd", "pushSm", "pushXl", "pushXs", "size", "sizeLg", "sizeMd", "sizeSm", "sizeXl", "sizeXs"] }, { kind: "component", type: IonItem, selector: "ion-item", inputs: ["button", "color", "detail", "detailIcon", "disabled", "download", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] }, { kind: "component", type: IonSpinner, selector: "ion-spinner", inputs: ["color", "duration", "name", "paused"] }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: IonList, selector: "ion-list", inputs: ["inset", "lines", "mode"] }, { kind: "component", type: IonGrid, selector: "ion-grid", inputs: ["fixed"] }] }); }
136
+ ], usesInheritance: true, ngImport: i0, template: "<ion-header>\n <ion-toolbar color=\"light\">\n <ion-buttons slot=\"start\">\n <ion-back-button />\n </ion-buttons>\n <ion-title>Login &#64; {{ appTitle }}</ion-title>\n </ion-toolbar>\n</ion-header>\n\n<ion-content id=\"main-content\">\n @if (to) {\n <ion-card color=\"tertiary\">\n <ion-card-content>\n <p>Please sign in to join a team</p>\n </ion-card-content>\n </ion-card>\n }\n\n <p style=\"text-align: center; font-size: smaller\">\n <ion-text color=\"medium\">\n This app is free to use &\n <a target=\"_blank\" href=\"https://github.com/sneat-co\">open source</a>.\n </ion-text>\n </p>\n\n @if (isAuthenticated()) {\n <ion-card color=\"success\">\n <ion-card-content>\n <p>\n @if (signedInAs()) {\n You are already signed in as <strong>{{ signedInAs() }}</strong>.\n } @else {\n You are already signed in.\n }\n </p>\n <ion-button expand=\"block\" (click)=\"continueToApp()\">Continue</ion-button>\n <ion-button\n expand=\"block\"\n fill=\"outline\"\n color=\"medium\"\n (click)=\"reLogin()\"\n >\n Re-login as someone else\n </ion-button>\n </ion-card-content>\n </ion-card>\n } @else {\n <sneat-email-login-form\n (signingWithChange)=\"onEmailFormStatusChanged()\"\n (loggedIn)=\"onLoggedIn($event)\"\n />\n\n <ion-card>\n <ion-item-divider color=\"light\">\n <ion-label\n color=\"medium\"\n style=\"text-align: center; width: 100%; font-weight: bold\"\n >\n Quick login\n </ion-label>\n </ion-item-divider>\n <ion-grid class=\"ion-grid-layout\">\n @if (!isNativePlatform) {\n <ion-row>\n <ion-col>\n <div class=\"ion-padding\" style=\"text-align: center\">\n <sneat-login-with-telegram />\n </div>\n </ion-col>\n </ion-row>\n }\n <ion-row>\n <ion-col size=\"12\" size-md=\"6\">\n <ion-list lines=\"none\">\n <ion-item\n (click)=\"loginWith('google.com')\"\n tappable\n [disabled]=\"!!signingWith()\"\n >\n @if (signingWith() === \"google.com\") {\n <ion-spinner slot=\"start\" name=\"lines-small\" />\n } @else {\n <ion-icon color=\"danger\" name=\"logo-google\" slot=\"start\" />\n }\n <ion-label color=\"danger\"> Login with Google</ion-label>\n </ion-item>\n </ion-list>\n </ion-col>\n <ion-col size=\"12\" size-md=\"6\">\n <ion-list lines=\"none\">\n <ion-item\n (click)=\"loginWith('apple.com')\"\n tappable\n [disabled]=\"!!signingWith()\"\n >\n @if (signingWith() === \"apple.com\") {\n <ion-spinner slot=\"start\" name=\"lines-small\" />\n } @else {\n <ion-icon color=\"dark\" name=\"logo-apple\" slot=\"start\" />\n }\n\n <ion-label color=\"dark\"> Login with Apple</ion-label>\n </ion-item>\n </ion-list>\n </ion-col>\n </ion-row>\n <ion-row>\n <ion-col size=\"12\" size-md=\"6\">\n <ion-list lines=\"none\">\n <ion-item\n (click)=\"loginWith('microsoft.com')\"\n tappable\n [disabled]=\"!!signingWith()\"\n >\n @if (signingWith() === \"microsoft.com\") {\n <ion-spinner\n slot=\"start\"\n color=\"secondary\"\n name=\"lines-small\"\n />\n } @else {\n <ion-icon slot=\"start\" color=\"secondary\" name=\"logo-windows\" />\n }\n <ion-label color=\"secondary\">Login with Microsoft</ion-label>\n </ion-item>\n </ion-list>\n </ion-col>\n <ion-col size=\"12\" size-md=\"6\">\n <ion-list lines=\"none\">\n <ion-item\n (click)=\"loginWith('facebook.com')\"\n tappable\n [disabled]=\"!!signingWith()\"\n >\n @if (signingWith() === \"facebook.com\") {\n <ion-spinner slot=\"start\" color=\"primary\" name=\"lines-small\" />\n } @else {\n <ion-icon slot=\"start\" color=\"primary\" name=\"logo-facebook\" />\n }\n <ion-label color=\"primary\">Login with Facebook</ion-label>\n </ion-item>\n </ion-list>\n </ion-col>\n </ion-row>\n <ion-row>\n <ion-col size=\"12\" size-md=\"6\">\n <ion-list lines=\"none\">\n <ion-item\n (click)=\"loginWith('github.com')\"\n tappable\n [disabled]=\"!!signingWith()\"\n >\n @if (signingWith() === \"github.com\") {\n <ion-spinner slot=\"start\" color=\"tertiary\" name=\"lines-small\" />\n } @else {\n <ion-icon slot=\"start\" color=\"tertiary\" name=\"logo-github\" />\n }\n <ion-label color=\"tertiary\">Login with GitHub</ion-label>\n </ion-item>\n </ion-list>\n </ion-col>\n </ion-row>\n </ion-grid>\n </ion-card>\n }\n\n <p style=\"text-align: center; font-size: smaller\">\n <ion-text color=\"medium\">\n If any issues get\n <a href=\"mailto:help@sneat.app?subject=Problem+with+login+at+Sneat.app\"\n >help&#64;sneat.app</a\n >\n </ion-text>\n </p>\n</ion-content>\n", dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "component", type: LoginWithTelegramComponent, selector: "sneat-login-with-telegram", inputs: ["isUserAuthenticated", "botID", "size", "requestAccess", "userPic"] }, { kind: "component", type: EmailLoginFormComponent, selector: "sneat-email-login-form", outputs: ["signingWithChange", "loggedIn"] }, { kind: "component", type: IonHeader, selector: "ion-header", inputs: ["collapse", "mode", "translucent"] }, { kind: "component", type: IonToolbar, selector: "ion-toolbar", inputs: ["color", "mode"] }, { kind: "component", type: IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: IonButtons, selector: "ion-buttons", inputs: ["collapse"] }, { kind: "component", type: IonBackButton, selector: "ion-back-button" }, { kind: "component", type: IonTitle, selector: "ion-title", inputs: ["color", "size"] }, { kind: "component", type: IonContent, selector: "ion-content", inputs: ["color", "fixedSlotPlacement", "forceOverscroll", "fullscreen", "scrollEvents", "scrollX", "scrollY"] }, { kind: "component", type: IonCardContent, selector: "ion-card-content", inputs: ["mode"] }, { kind: "component", type: IonText, selector: "ion-text", inputs: ["color", "mode"] }, { kind: "component", type: IonCard, selector: "ion-card", inputs: ["button", "color", "disabled", "download", "href", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] }, { kind: "component", type: IonItemDivider, selector: "ion-item-divider", inputs: ["color", "mode", "sticky"] }, { kind: "component", type: IonLabel, selector: "ion-label", inputs: ["color", "mode", "position"] }, { kind: "component", type: IonRow, selector: "ion-row" }, { kind: "component", type: IonCol, selector: "ion-col", inputs: ["offset", "offsetLg", "offsetMd", "offsetSm", "offsetXl", "offsetXs", "pull", "pullLg", "pullMd", "pullSm", "pullXl", "pullXs", "push", "pushLg", "pushMd", "pushSm", "pushXl", "pushXs", "size", "sizeLg", "sizeMd", "sizeSm", "sizeXl", "sizeXs"] }, { kind: "component", type: IonItem, selector: "ion-item", inputs: ["button", "color", "detail", "detailIcon", "disabled", "download", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] }, { kind: "component", type: IonSpinner, selector: "ion-spinner", inputs: ["color", "duration", "name", "paused"] }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: IonList, selector: "ion-list", inputs: ["inset", "lines", "mode"] }, { kind: "component", type: IonGrid, selector: "ion-grid", inputs: ["fixed"] }] }); }
111
137
  }
112
138
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: LoginPageComponent, decorators: [{
113
139
  type: Component,
@@ -117,6 +143,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
117
143
  EmailLoginFormComponent,
118
144
  IonHeader,
119
145
  IonToolbar,
146
+ IonButton,
120
147
  IonButtons,
121
148
  IonBackButton,
122
149
  IonTitle,
@@ -139,6 +166,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
139
166
  useValue: 'LoginPageComponent',
140
167
  },
141
168
  RandomIdService,
142
- ], template: "<ion-header>\n <ion-toolbar color=\"light\">\n <ion-buttons slot=\"start\">\n <ion-back-button />\n </ion-buttons>\n <ion-title>Login &#64; {{ appTitle }}</ion-title>\n </ion-toolbar>\n</ion-header>\n\n<ion-content id=\"main-content\">\n @if (to) {\n <ion-card color=\"tertiary\">\n <ion-card-content>\n <p>Please sign in to join a team</p>\n </ion-card-content>\n </ion-card>\n }\n\n <p style=\"text-align: center; font-size: smaller\">\n <ion-text color=\"medium\">\n This app is free to use &\n <a target=\"_blank\" href=\"https://github.com/sneat-co\">open source</a>.\n </ion-text>\n </p>\n\n <sneat-email-login-form\n (signingWithChange)=\"onEmailFormStatusChanged()\"\n (loggedIn)=\"onLoggedIn($event)\"\n />\n\n <ion-card>\n <ion-item-divider color=\"light\">\n <ion-label\n color=\"medium\"\n style=\"text-align: center; width: 100%; font-weight: bold\"\n >\n Quick login\n </ion-label>\n </ion-item-divider>\n <ion-grid class=\"ion-grid-layout\">\n @if (!isNativePlatform) {\n <ion-row>\n <ion-col>\n <div class=\"ion-padding\" style=\"text-align: center\">\n <sneat-login-with-telegram />\n </div>\n </ion-col>\n </ion-row>\n }\n <ion-row>\n <ion-col size=\"12\" size-md=\"6\">\n <ion-list lines=\"none\">\n <ion-item\n (click)=\"loginWith('google.com')\"\n tappable\n [disabled]=\"!!signingWith()\"\n >\n @if (signingWith() === \"google.com\") {\n <ion-spinner slot=\"start\" name=\"lines-small\" />\n } @else {\n <ion-icon color=\"danger\" name=\"logo-google\" slot=\"start\" />\n }\n <ion-label color=\"danger\"> Login with Google</ion-label>\n </ion-item>\n </ion-list>\n </ion-col>\n <ion-col size=\"12\" size-md=\"6\">\n <ion-list lines=\"none\">\n <ion-item\n (click)=\"loginWith('apple.com')\"\n tappable\n [disabled]=\"!!signingWith()\"\n >\n @if (signingWith() === \"apple.com\") {\n <ion-spinner slot=\"start\" name=\"lines-small\" />\n } @else {\n <ion-icon color=\"dark\" name=\"logo-apple\" slot=\"start\" />\n }\n\n <ion-label color=\"dark\"> Login with Apple</ion-label>\n </ion-item>\n </ion-list>\n </ion-col>\n </ion-row>\n <ion-row>\n <ion-col size=\"12\" size-md=\"6\">\n <ion-list lines=\"none\">\n <ion-item\n (click)=\"loginWith('microsoft.com')\"\n tappable\n [disabled]=\"!!signingWith()\"\n >\n @if (signingWith() === \"microsoft.com\") {\n <ion-spinner\n slot=\"start\"\n color=\"secondary\"\n name=\"lines-small\"\n />\n } @else {\n <ion-icon slot=\"start\" color=\"secondary\" name=\"logo-windows\" />\n }\n <ion-label color=\"secondary\">Login with Microsoft</ion-label>\n </ion-item>\n </ion-list>\n </ion-col>\n <ion-col size=\"12\" size-md=\"6\">\n <ion-list lines=\"none\">\n <ion-item\n (click)=\"loginWith('facebook.com')\"\n tappable\n [disabled]=\"!!signingWith()\"\n >\n @if (signingWith() === \"facebook.com\") {\n <ion-spinner slot=\"start\" color=\"primary\" name=\"lines-small\" />\n } @else {\n <ion-icon slot=\"start\" color=\"primary\" name=\"logo-facebook\" />\n }\n <ion-label color=\"primary\">Login with Facebook</ion-label>\n </ion-item>\n </ion-list>\n </ion-col>\n </ion-row>\n <ion-row>\n <ion-col size=\"12\" size-md=\"6\">\n <ion-list lines=\"none\">\n <ion-item\n (click)=\"loginWith('github.com')\"\n tappable\n [disabled]=\"!!signingWith()\"\n >\n @if (signingWith() === \"github.com\") {\n <ion-spinner slot=\"start\" color=\"tertiary\" name=\"lines-small\" />\n } @else {\n <ion-icon slot=\"start\" color=\"tertiary\" name=\"logo-github\" />\n }\n <ion-label color=\"tertiary\">Login with GitHub</ion-label>\n </ion-item>\n </ion-list>\n </ion-col>\n </ion-row>\n </ion-grid>\n </ion-card>\n\n <p style=\"text-align: center; font-size: smaller\">\n <ion-text color=\"medium\">\n If any issues get\n <a href=\"mailto:help@sneat.app?subject=Problem+with+login+at+Sneat.app\"\n >help&#64;sneat.app</a\n >\n </ion-text>\n </p>\n</ion-content>\n" }]
169
+ ], template: "<ion-header>\n <ion-toolbar color=\"light\">\n <ion-buttons slot=\"start\">\n <ion-back-button />\n </ion-buttons>\n <ion-title>Login &#64; {{ appTitle }}</ion-title>\n </ion-toolbar>\n</ion-header>\n\n<ion-content id=\"main-content\">\n @if (to) {\n <ion-card color=\"tertiary\">\n <ion-card-content>\n <p>Please sign in to join a team</p>\n </ion-card-content>\n </ion-card>\n }\n\n <p style=\"text-align: center; font-size: smaller\">\n <ion-text color=\"medium\">\n This app is free to use &\n <a target=\"_blank\" href=\"https://github.com/sneat-co\">open source</a>.\n </ion-text>\n </p>\n\n @if (isAuthenticated()) {\n <ion-card color=\"success\">\n <ion-card-content>\n <p>\n @if (signedInAs()) {\n You are already signed in as <strong>{{ signedInAs() }}</strong>.\n } @else {\n You are already signed in.\n }\n </p>\n <ion-button expand=\"block\" (click)=\"continueToApp()\">Continue</ion-button>\n <ion-button\n expand=\"block\"\n fill=\"outline\"\n color=\"medium\"\n (click)=\"reLogin()\"\n >\n Re-login as someone else\n </ion-button>\n </ion-card-content>\n </ion-card>\n } @else {\n <sneat-email-login-form\n (signingWithChange)=\"onEmailFormStatusChanged()\"\n (loggedIn)=\"onLoggedIn($event)\"\n />\n\n <ion-card>\n <ion-item-divider color=\"light\">\n <ion-label\n color=\"medium\"\n style=\"text-align: center; width: 100%; font-weight: bold\"\n >\n Quick login\n </ion-label>\n </ion-item-divider>\n <ion-grid class=\"ion-grid-layout\">\n @if (!isNativePlatform) {\n <ion-row>\n <ion-col>\n <div class=\"ion-padding\" style=\"text-align: center\">\n <sneat-login-with-telegram />\n </div>\n </ion-col>\n </ion-row>\n }\n <ion-row>\n <ion-col size=\"12\" size-md=\"6\">\n <ion-list lines=\"none\">\n <ion-item\n (click)=\"loginWith('google.com')\"\n tappable\n [disabled]=\"!!signingWith()\"\n >\n @if (signingWith() === \"google.com\") {\n <ion-spinner slot=\"start\" name=\"lines-small\" />\n } @else {\n <ion-icon color=\"danger\" name=\"logo-google\" slot=\"start\" />\n }\n <ion-label color=\"danger\"> Login with Google</ion-label>\n </ion-item>\n </ion-list>\n </ion-col>\n <ion-col size=\"12\" size-md=\"6\">\n <ion-list lines=\"none\">\n <ion-item\n (click)=\"loginWith('apple.com')\"\n tappable\n [disabled]=\"!!signingWith()\"\n >\n @if (signingWith() === \"apple.com\") {\n <ion-spinner slot=\"start\" name=\"lines-small\" />\n } @else {\n <ion-icon color=\"dark\" name=\"logo-apple\" slot=\"start\" />\n }\n\n <ion-label color=\"dark\"> Login with Apple</ion-label>\n </ion-item>\n </ion-list>\n </ion-col>\n </ion-row>\n <ion-row>\n <ion-col size=\"12\" size-md=\"6\">\n <ion-list lines=\"none\">\n <ion-item\n (click)=\"loginWith('microsoft.com')\"\n tappable\n [disabled]=\"!!signingWith()\"\n >\n @if (signingWith() === \"microsoft.com\") {\n <ion-spinner\n slot=\"start\"\n color=\"secondary\"\n name=\"lines-small\"\n />\n } @else {\n <ion-icon slot=\"start\" color=\"secondary\" name=\"logo-windows\" />\n }\n <ion-label color=\"secondary\">Login with Microsoft</ion-label>\n </ion-item>\n </ion-list>\n </ion-col>\n <ion-col size=\"12\" size-md=\"6\">\n <ion-list lines=\"none\">\n <ion-item\n (click)=\"loginWith('facebook.com')\"\n tappable\n [disabled]=\"!!signingWith()\"\n >\n @if (signingWith() === \"facebook.com\") {\n <ion-spinner slot=\"start\" color=\"primary\" name=\"lines-small\" />\n } @else {\n <ion-icon slot=\"start\" color=\"primary\" name=\"logo-facebook\" />\n }\n <ion-label color=\"primary\">Login with Facebook</ion-label>\n </ion-item>\n </ion-list>\n </ion-col>\n </ion-row>\n <ion-row>\n <ion-col size=\"12\" size-md=\"6\">\n <ion-list lines=\"none\">\n <ion-item\n (click)=\"loginWith('github.com')\"\n tappable\n [disabled]=\"!!signingWith()\"\n >\n @if (signingWith() === \"github.com\") {\n <ion-spinner slot=\"start\" color=\"tertiary\" name=\"lines-small\" />\n } @else {\n <ion-icon slot=\"start\" color=\"tertiary\" name=\"logo-github\" />\n }\n <ion-label color=\"tertiary\">Login with GitHub</ion-label>\n </ion-item>\n </ion-list>\n </ion-col>\n </ion-row>\n </ion-grid>\n </ion-card>\n }\n\n <p style=\"text-align: center; font-size: smaller\">\n <ion-text color=\"medium\">\n If any issues get\n <a href=\"mailto:help@sneat.app?subject=Problem+with+login+at+Sneat.app\"\n >help&#64;sneat.app</a\n >\n </ion-text>\n </p>\n</ion-content>\n" }]
143
170
  }], ctorParameters: () => [] });
144
171
  //# sourceMappingURL=login-page.component.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"login-page.component.js","sourceRoot":"","sources":["../../../../../../../../libs/auth/ui/src/lib/pages/login-page/login-page.component.ts","../../../../../../../../libs/auth/ui/src/lib/pages/login-page/login-page.component.html"],"names":[],"mappings":"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","sourcesContent":["import { Component, signal, inject } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\nimport { ActivatedRoute } from '@angular/router';\nimport { Capacitor } from '@capacitor/core';\nimport {\n NavController,\n IonBackButton,\n IonButtons,\n IonCard,\n IonCardContent,\n IonCol,\n IonContent,\n IonGrid,\n IonHeader,\n IonIcon,\n IonItem,\n IonItemDivider,\n IonLabel,\n IonList,\n IonRow,\n IonSpinner,\n IonText,\n IonTitle,\n IonToolbar,\n} from '@ionic/angular/standalone';\nimport {\n AuthProviderID,\n AuthStatuses,\n ILoginEventsHandler,\n ISneatAuthState,\n LoginEventsHandler,\n SneatAuthStateService,\n} from '@sneat/auth-core';\nimport { SneatUserService } from '@sneat/auth-core';\nimport {\n AnalyticsService,\n APP_INFO,\n currentSpacePath,\n IAnalyticsService,\n IAppInfo,\n} from '@sneat/core';\nimport { RandomIdService } from '@sneat/random';\nimport { ClassName, SneatBaseComponent } from '@sneat/ui';\nimport { Subject, takeUntil } from 'rxjs';\nimport {\n EmailFormSigningWith,\n EmailLoginFormComponent,\n} from './email-login-form/email-login-form.component';\nimport { UserCredential } from 'firebase/auth';\nimport { LoginWithTelegramComponent } from './login-with-telegram.component';\n\ntype Action = 'join' | 'refuse'; // TODO: inject provider for action descriptions/messages.\n\n@Component({\n selector: 'sneat-login',\n templateUrl: './login-page.component.html',\n imports: [\n FormsModule,\n LoginWithTelegramComponent,\n EmailLoginFormComponent,\n IonHeader,\n IonToolbar,\n IonButtons,\n IonBackButton,\n IonTitle,\n IonContent,\n IonCardContent,\n IonText,\n IonCard,\n IonItemDivider,\n IonLabel,\n IonRow,\n IonCol,\n IonItem,\n IonSpinner,\n IonIcon,\n IonList,\n IonGrid,\n ],\n providers: [\n {\n provide: ClassName,\n useValue: 'LoginPageComponent',\n },\n RandomIdService,\n ],\n})\nexport class LoginPageComponent extends SneatBaseComponent {\n private readonly analyticsService =\n inject<IAnalyticsService>(AnalyticsService);\n private readonly route = inject(ActivatedRoute);\n private readonly navController = inject(NavController);\n private readonly userService = inject(SneatUserService);\n private readonly authStateService = inject(SneatAuthStateService);\n private appInfo = inject<IAppInfo>(APP_INFO);\n private readonly loginEventsHandler = inject<ILoginEventsHandler>(\n LoginEventsHandler,\n { optional: true },\n );\n\n protected readonly signingWith = signal<AuthProviderID | undefined>(\n undefined,\n );\n private readonly redirectTo?: string;\n protected readonly to?: string;\n protected readonly action?: Action; // TODO: document possible values?\n\n protected readonly isNativePlatform = Capacitor.isNativePlatform();\n\n protected readonly appTitle: string;\n\n constructor() {\n super();\n const appInfo = this.appInfo;\n this.appTitle = appInfo.appTitle || 'Sneat.app';\n if (location.hash.startsWith('#/')) {\n this.redirectTo = location.hash.substring(1);\n }\n this.to = this.route.snapshot.queryParams['to']; // should we subscribe? I believe no.\n const action = location.hash.match(/[#&]action=(\\w+)/);\n this.action = action?.[1] as Action;\n\n const userRecordLoaded = new Subject<void>();\n this.userService.userState\n .pipe(takeUntil(userRecordLoaded), this.takeUntilDestroyed())\n .subscribe({\n next: (userState) => {\n if (userState.record) {\n userRecordLoaded.next();\n } else {\n return;\n }\n // Fall back to the persisted current space so it is restored after login.\n const redirectTo = this.redirectTo || currentSpacePath() || '/';\n this.navController\n .navigateRoot(redirectTo)\n .catch(\n this.errorLogger.logErrorHandler(\n 'Failed to navigate back to ' + redirectTo,\n ),\n );\n },\n error: this.errorHandler('Failed to get user state after login'),\n });\n }\n\n protected onEmailFormStatusChanged(signingWith?: EmailFormSigningWith): void {\n this.signingWith.set(signingWith as AuthProviderID);\n }\n\n protected async loginWith(provider: AuthProviderID) {\n this.signingWith.set(provider);\n try {\n await this.authStateService.signInWith(provider);\n // We do not reset this.signingWith in case of succesful sign in as we should redirect from login page\n // and not to allow user to do a double sign-in.\n } catch (e) {\n const errMsg = (e as { errorMessage?: string }).errorMessage;\n if (\n errMsg !== 'The user canceled the sign-in flow.' &&\n !errMsg?.includes(\n 'com.apple.AuthenticationServices.AuthorizationError error 1001.',\n )\n ) {\n this.errorLogger.logError(e, `Failed to sign-in with ${provider}`);\n }\n this.signingWith.set(undefined);\n }\n }\n\n protected onLoggedIn(userCredential: UserCredential): void {\n this.signingWith.set(undefined);\n if (!userCredential.user) {\n return;\n }\n if (userCredential.user.email) {\n const prevEmail = localStorage.getItem('emailForSignIn') || '';\n if (!prevEmail) {\n localStorage.setItem('emailForSignIn', userCredential.user.email);\n }\n }\n const authState: ISneatAuthState = {\n status: AuthStatuses.authenticated,\n user: userCredential.user,\n };\n this.userService.onUserSignedIn(authState);\n }\n\n private errorHandler(\n m: string,\n eventName?: string,\n eventParams?: Record<string, string>,\n ): (err: unknown) => void {\n return (err) => this.handleError(err, m, eventName, eventParams);\n }\n\n private handleError(\n err: unknown,\n m: string,\n eventName?: string,\n eventParams?: Record<string, string>,\n ): void {\n if (eventName) {\n this.analyticsService.logEvent(eventName, eventParams);\n }\n this.errorLogger.logError(err, m, {\n report: !(err as { code: unknown }).code,\n });\n this.signingWith.set(undefined);\n }\n}\n","<ion-header>\n <ion-toolbar color=\"light\">\n <ion-buttons slot=\"start\">\n <ion-back-button />\n </ion-buttons>\n <ion-title>Login &#64; {{ appTitle }}</ion-title>\n </ion-toolbar>\n</ion-header>\n\n<ion-content id=\"main-content\">\n @if (to) {\n <ion-card color=\"tertiary\">\n <ion-card-content>\n <p>Please sign in to join a team</p>\n </ion-card-content>\n </ion-card>\n }\n\n <p style=\"text-align: center; font-size: smaller\">\n <ion-text color=\"medium\">\n This app is free to use &\n <a target=\"_blank\" href=\"https://github.com/sneat-co\">open source</a>.\n </ion-text>\n </p>\n\n <sneat-email-login-form\n (signingWithChange)=\"onEmailFormStatusChanged()\"\n (loggedIn)=\"onLoggedIn($event)\"\n />\n\n <ion-card>\n <ion-item-divider color=\"light\">\n <ion-label\n color=\"medium\"\n style=\"text-align: center; width: 100%; font-weight: bold\"\n >\n Quick login\n </ion-label>\n </ion-item-divider>\n <ion-grid class=\"ion-grid-layout\">\n @if (!isNativePlatform) {\n <ion-row>\n <ion-col>\n <div class=\"ion-padding\" style=\"text-align: center\">\n <sneat-login-with-telegram />\n </div>\n </ion-col>\n </ion-row>\n }\n <ion-row>\n <ion-col size=\"12\" size-md=\"6\">\n <ion-list lines=\"none\">\n <ion-item\n (click)=\"loginWith('google.com')\"\n tappable\n [disabled]=\"!!signingWith()\"\n >\n @if (signingWith() === \"google.com\") {\n <ion-spinner slot=\"start\" name=\"lines-small\" />\n } @else {\n <ion-icon color=\"danger\" name=\"logo-google\" slot=\"start\" />\n }\n <ion-label color=\"danger\"> Login with Google</ion-label>\n </ion-item>\n </ion-list>\n </ion-col>\n <ion-col size=\"12\" size-md=\"6\">\n <ion-list lines=\"none\">\n <ion-item\n (click)=\"loginWith('apple.com')\"\n tappable\n [disabled]=\"!!signingWith()\"\n >\n @if (signingWith() === \"apple.com\") {\n <ion-spinner slot=\"start\" name=\"lines-small\" />\n } @else {\n <ion-icon color=\"dark\" name=\"logo-apple\" slot=\"start\" />\n }\n\n <ion-label color=\"dark\"> Login with Apple</ion-label>\n </ion-item>\n </ion-list>\n </ion-col>\n </ion-row>\n <ion-row>\n <ion-col size=\"12\" size-md=\"6\">\n <ion-list lines=\"none\">\n <ion-item\n (click)=\"loginWith('microsoft.com')\"\n tappable\n [disabled]=\"!!signingWith()\"\n >\n @if (signingWith() === \"microsoft.com\") {\n <ion-spinner\n slot=\"start\"\n color=\"secondary\"\n name=\"lines-small\"\n />\n } @else {\n <ion-icon slot=\"start\" color=\"secondary\" name=\"logo-windows\" />\n }\n <ion-label color=\"secondary\">Login with Microsoft</ion-label>\n </ion-item>\n </ion-list>\n </ion-col>\n <ion-col size=\"12\" size-md=\"6\">\n <ion-list lines=\"none\">\n <ion-item\n (click)=\"loginWith('facebook.com')\"\n tappable\n [disabled]=\"!!signingWith()\"\n >\n @if (signingWith() === \"facebook.com\") {\n <ion-spinner slot=\"start\" color=\"primary\" name=\"lines-small\" />\n } @else {\n <ion-icon slot=\"start\" color=\"primary\" name=\"logo-facebook\" />\n }\n <ion-label color=\"primary\">Login with Facebook</ion-label>\n </ion-item>\n </ion-list>\n </ion-col>\n </ion-row>\n <ion-row>\n <ion-col size=\"12\" size-md=\"6\">\n <ion-list lines=\"none\">\n <ion-item\n (click)=\"loginWith('github.com')\"\n tappable\n [disabled]=\"!!signingWith()\"\n >\n @if (signingWith() === \"github.com\") {\n <ion-spinner slot=\"start\" color=\"tertiary\" name=\"lines-small\" />\n } @else {\n <ion-icon slot=\"start\" color=\"tertiary\" name=\"logo-github\" />\n }\n <ion-label color=\"tertiary\">Login with GitHub</ion-label>\n </ion-item>\n </ion-list>\n </ion-col>\n </ion-row>\n </ion-grid>\n </ion-card>\n\n <p style=\"text-align: center; font-size: smaller\">\n <ion-text color=\"medium\">\n If any issues get\n <a href=\"mailto:help@sneat.app?subject=Problem+with+login+at+Sneat.app\"\n >help&#64;sneat.app</a\n >\n </ion-text>\n </p>\n</ion-content>\n"]}
1
+ {"version":3,"file":"login-page.component.js","sourceRoot":"","sources":["../../../../../../../../libs/auth/ui/src/lib/pages/login-page/login-page.component.ts","../../../../../../../../libs/auth/ui/src/lib/pages/login-page/login-page.component.html"],"names":[],"mappings":"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","sourcesContent":["import { Component, computed, signal, inject } from '@angular/core';\nimport { toSignal } from '@angular/core/rxjs-interop';\nimport { FormsModule } from '@angular/forms';\nimport { ActivatedRoute } from '@angular/router';\nimport { Capacitor } from '@capacitor/core';\nimport {\n NavController,\n IonBackButton,\n IonButton,\n IonButtons,\n IonCard,\n IonCardContent,\n IonCol,\n IonContent,\n IonGrid,\n IonHeader,\n IonIcon,\n IonItem,\n IonItemDivider,\n IonLabel,\n IonList,\n IonRow,\n IonSpinner,\n IonText,\n IonTitle,\n IonToolbar,\n} from '@ionic/angular/standalone';\nimport {\n AuthProviderID,\n AuthStatuses,\n ILoginEventsHandler,\n ISneatAuthState,\n LoginEventsHandler,\n SneatAuthStateService,\n} from '@sneat/auth-core';\nimport { SneatUserService } from '@sneat/auth-core';\nimport {\n AnalyticsService,\n APP_INFO,\n currentSpacePath,\n IAnalyticsService,\n IAppInfo,\n} from '@sneat/core';\nimport { RandomIdService } from '@sneat/random';\nimport { ClassName, SneatBaseComponent } from '@sneat/ui';\nimport { Subject, takeUntil } from 'rxjs';\nimport {\n EmailFormSigningWith,\n EmailLoginFormComponent,\n} from './email-login-form/email-login-form.component';\nimport { UserCredential } from 'firebase/auth';\nimport { LoginWithTelegramComponent } from './login-with-telegram.component';\n\ntype Action = 'join' | 'refuse'; // TODO: inject provider for action descriptions/messages.\n\n@Component({\n selector: 'sneat-login',\n templateUrl: './login-page.component.html',\n imports: [\n FormsModule,\n LoginWithTelegramComponent,\n EmailLoginFormComponent,\n IonHeader,\n IonToolbar,\n IonButton,\n IonButtons,\n IonBackButton,\n IonTitle,\n IonContent,\n IonCardContent,\n IonText,\n IonCard,\n IonItemDivider,\n IonLabel,\n IonRow,\n IonCol,\n IonItem,\n IonSpinner,\n IonIcon,\n IonList,\n IonGrid,\n ],\n providers: [\n {\n provide: ClassName,\n useValue: 'LoginPageComponent',\n },\n RandomIdService,\n ],\n})\nexport class LoginPageComponent extends SneatBaseComponent {\n private readonly analyticsService =\n inject<IAnalyticsService>(AnalyticsService);\n private readonly route = inject(ActivatedRoute);\n private readonly navController = inject(NavController);\n private readonly userService = inject(SneatUserService);\n private readonly authStateService = inject(SneatAuthStateService);\n private appInfo = inject<IAppInfo>(APP_INFO);\n private readonly loginEventsHandler = inject<ILoginEventsHandler>(\n LoginEventsHandler,\n { optional: true },\n );\n\n protected readonly signingWith = signal<AuthProviderID | undefined>(\n undefined,\n );\n private readonly redirectTo?: string;\n protected readonly to?: string;\n protected readonly action?: Action; // TODO: document possible values?\n\n protected readonly isNativePlatform = Capacitor.isNativePlatform();\n\n protected readonly appTitle: string;\n\n // Surfaces the Firebase auth state on the login page itself: if the user is\n // already signed in (e.g. the app failed to navigate them onward) we show a\n // \"you are already signed in as X\" panel instead of the sign-in form, so an\n // authenticated-but-stuck state is obvious rather than looking like sign-in\n // is broken.\n protected readonly isAuthenticated = computed(\n () => this.authStatus() === 'authenticated',\n );\n private readonly authStatus = toSignal(this.authStateService.authStatus);\n private readonly authUser = toSignal(this.authStateService.authUser);\n protected readonly signedInAs = computed(() => {\n const u = this.authUser();\n return u?.displayName || u?.email || u?.uid || '';\n });\n\n constructor() {\n super();\n const appInfo = this.appInfo;\n this.appTitle = appInfo.appTitle || 'Sneat.app';\n if (location.hash.startsWith('#/')) {\n this.redirectTo = location.hash.substring(1);\n }\n this.to = this.route.snapshot.queryParams['to']; // should we subscribe? I believe no.\n const action = location.hash.match(/[#&]action=(\\w+)/);\n this.action = action?.[1] as Action;\n\n const userRecordLoaded = new Subject<void>();\n this.userService.userState\n .pipe(takeUntil(userRecordLoaded), this.takeUntilDestroyed())\n .subscribe({\n next: (userState) => {\n if (userState.record) {\n userRecordLoaded.next();\n } else {\n return;\n }\n // Fall back to the persisted current space so it is restored after login.\n const redirectTo = this.redirectTo || currentSpacePath() || '/';\n this.navController\n .navigateRoot(redirectTo)\n .catch(\n this.errorLogger.logErrorHandler(\n 'Failed to navigate back to ' + redirectTo,\n ),\n );\n },\n error: this.errorHandler('Failed to get user state after login'),\n });\n }\n\n protected onEmailFormStatusChanged(signingWith?: EmailFormSigningWith): void {\n this.signingWith.set(signingWith as AuthProviderID);\n }\n\n // Proceed into the app from the \"already signed in\" panel.\n protected continueToApp(): void {\n const redirectTo = this.redirectTo || currentSpacePath() || '/';\n this.navController\n .navigateRoot(redirectTo)\n .catch(this.errorLogger.logErrorHandler('Failed to navigate to ' + redirectTo));\n }\n\n // Sign out so the sign-in form is shown again (e.g. to log in as someone else).\n protected reLogin(): void {\n this.authStateService\n .signOut()\n .catch(this.errorLogger.logErrorHandler('Failed to sign out for re-login'));\n }\n\n protected async loginWith(provider: AuthProviderID) {\n this.signingWith.set(provider);\n try {\n await this.authStateService.signInWith(provider);\n // We do not reset this.signingWith in case of succesful sign in as we should redirect from login page\n // and not to allow user to do a double sign-in.\n } catch (e) {\n const errMsg = (e as { errorMessage?: string }).errorMessage;\n if (\n errMsg !== 'The user canceled the sign-in flow.' &&\n !errMsg?.includes(\n 'com.apple.AuthenticationServices.AuthorizationError error 1001.',\n )\n ) {\n this.errorLogger.logError(e, `Failed to sign-in with ${provider}`);\n }\n this.signingWith.set(undefined);\n }\n }\n\n protected onLoggedIn(userCredential: UserCredential): void {\n this.signingWith.set(undefined);\n if (!userCredential.user) {\n return;\n }\n if (userCredential.user.email) {\n const prevEmail = localStorage.getItem('emailForSignIn') || '';\n if (!prevEmail) {\n localStorage.setItem('emailForSignIn', userCredential.user.email);\n }\n }\n const authState: ISneatAuthState = {\n status: AuthStatuses.authenticated,\n user: userCredential.user,\n };\n this.userService.onUserSignedIn(authState);\n }\n\n private errorHandler(\n m: string,\n eventName?: string,\n eventParams?: Record<string, string>,\n ): (err: unknown) => void {\n return (err) => this.handleError(err, m, eventName, eventParams);\n }\n\n private handleError(\n err: unknown,\n m: string,\n eventName?: string,\n eventParams?: Record<string, string>,\n ): void {\n if (eventName) {\n this.analyticsService.logEvent(eventName, eventParams);\n }\n this.errorLogger.logError(err, m, {\n report: !(err as { code: unknown }).code,\n });\n this.signingWith.set(undefined);\n }\n}\n","<ion-header>\n <ion-toolbar color=\"light\">\n <ion-buttons slot=\"start\">\n <ion-back-button />\n </ion-buttons>\n <ion-title>Login &#64; {{ appTitle }}</ion-title>\n </ion-toolbar>\n</ion-header>\n\n<ion-content id=\"main-content\">\n @if (to) {\n <ion-card color=\"tertiary\">\n <ion-card-content>\n <p>Please sign in to join a team</p>\n </ion-card-content>\n </ion-card>\n }\n\n <p style=\"text-align: center; font-size: smaller\">\n <ion-text color=\"medium\">\n This app is free to use &\n <a target=\"_blank\" href=\"https://github.com/sneat-co\">open source</a>.\n </ion-text>\n </p>\n\n @if (isAuthenticated()) {\n <ion-card color=\"success\">\n <ion-card-content>\n <p>\n @if (signedInAs()) {\n You are already signed in as <strong>{{ signedInAs() }}</strong>.\n } @else {\n You are already signed in.\n }\n </p>\n <ion-button expand=\"block\" (click)=\"continueToApp()\">Continue</ion-button>\n <ion-button\n expand=\"block\"\n fill=\"outline\"\n color=\"medium\"\n (click)=\"reLogin()\"\n >\n Re-login as someone else\n </ion-button>\n </ion-card-content>\n </ion-card>\n } @else {\n <sneat-email-login-form\n (signingWithChange)=\"onEmailFormStatusChanged()\"\n (loggedIn)=\"onLoggedIn($event)\"\n />\n\n <ion-card>\n <ion-item-divider color=\"light\">\n <ion-label\n color=\"medium\"\n style=\"text-align: center; width: 100%; font-weight: bold\"\n >\n Quick login\n </ion-label>\n </ion-item-divider>\n <ion-grid class=\"ion-grid-layout\">\n @if (!isNativePlatform) {\n <ion-row>\n <ion-col>\n <div class=\"ion-padding\" style=\"text-align: center\">\n <sneat-login-with-telegram />\n </div>\n </ion-col>\n </ion-row>\n }\n <ion-row>\n <ion-col size=\"12\" size-md=\"6\">\n <ion-list lines=\"none\">\n <ion-item\n (click)=\"loginWith('google.com')\"\n tappable\n [disabled]=\"!!signingWith()\"\n >\n @if (signingWith() === \"google.com\") {\n <ion-spinner slot=\"start\" name=\"lines-small\" />\n } @else {\n <ion-icon color=\"danger\" name=\"logo-google\" slot=\"start\" />\n }\n <ion-label color=\"danger\"> Login with Google</ion-label>\n </ion-item>\n </ion-list>\n </ion-col>\n <ion-col size=\"12\" size-md=\"6\">\n <ion-list lines=\"none\">\n <ion-item\n (click)=\"loginWith('apple.com')\"\n tappable\n [disabled]=\"!!signingWith()\"\n >\n @if (signingWith() === \"apple.com\") {\n <ion-spinner slot=\"start\" name=\"lines-small\" />\n } @else {\n <ion-icon color=\"dark\" name=\"logo-apple\" slot=\"start\" />\n }\n\n <ion-label color=\"dark\"> Login with Apple</ion-label>\n </ion-item>\n </ion-list>\n </ion-col>\n </ion-row>\n <ion-row>\n <ion-col size=\"12\" size-md=\"6\">\n <ion-list lines=\"none\">\n <ion-item\n (click)=\"loginWith('microsoft.com')\"\n tappable\n [disabled]=\"!!signingWith()\"\n >\n @if (signingWith() === \"microsoft.com\") {\n <ion-spinner\n slot=\"start\"\n color=\"secondary\"\n name=\"lines-small\"\n />\n } @else {\n <ion-icon slot=\"start\" color=\"secondary\" name=\"logo-windows\" />\n }\n <ion-label color=\"secondary\">Login with Microsoft</ion-label>\n </ion-item>\n </ion-list>\n </ion-col>\n <ion-col size=\"12\" size-md=\"6\">\n <ion-list lines=\"none\">\n <ion-item\n (click)=\"loginWith('facebook.com')\"\n tappable\n [disabled]=\"!!signingWith()\"\n >\n @if (signingWith() === \"facebook.com\") {\n <ion-spinner slot=\"start\" color=\"primary\" name=\"lines-small\" />\n } @else {\n <ion-icon slot=\"start\" color=\"primary\" name=\"logo-facebook\" />\n }\n <ion-label color=\"primary\">Login with Facebook</ion-label>\n </ion-item>\n </ion-list>\n </ion-col>\n </ion-row>\n <ion-row>\n <ion-col size=\"12\" size-md=\"6\">\n <ion-list lines=\"none\">\n <ion-item\n (click)=\"loginWith('github.com')\"\n tappable\n [disabled]=\"!!signingWith()\"\n >\n @if (signingWith() === \"github.com\") {\n <ion-spinner slot=\"start\" color=\"tertiary\" name=\"lines-small\" />\n } @else {\n <ion-icon slot=\"start\" color=\"tertiary\" name=\"logo-github\" />\n }\n <ion-label color=\"tertiary\">Login with GitHub</ion-label>\n </ion-item>\n </ion-list>\n </ion-col>\n </ion-row>\n </ion-grid>\n </ion-card>\n }\n\n <p style=\"text-align: center; font-size: smaller\">\n <ion-text color=\"medium\">\n If any issues get\n <a href=\"mailto:help@sneat.app?subject=Problem+with+login+at+Sneat.app\"\n >help&#64;sneat.app</a\n >\n </ion-text>\n </p>\n</ion-content>\n"]}
@@ -18,8 +18,14 @@ export declare class LoginPageComponent extends SneatBaseComponent {
18
18
  protected readonly action?: Action;
19
19
  protected readonly isNativePlatform: boolean;
20
20
  protected readonly appTitle: string;
21
+ protected readonly isAuthenticated: import("@angular/core").Signal<boolean>;
22
+ private readonly authStatus;
23
+ private readonly authUser;
24
+ protected readonly signedInAs: import("@angular/core").Signal<string>;
21
25
  constructor();
22
26
  protected onEmailFormStatusChanged(signingWith?: EmailFormSigningWith): void;
27
+ protected continueToApp(): void;
28
+ protected reLogin(): void;
23
29
  protected loginWith(provider: AuthProviderID): Promise<void>;
24
30
  protected onLoggedIn(userCredential: UserCredential): void;
25
31
  private errorHandler;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sneat/auth-ui",
3
- "version": "0.5.3",
3
+ "version": "0.6.0",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },