@sneat/auth-ui 0.6.1 → 0.8.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.
@@ -14,6 +14,7 @@ export class UserAuthAccountsComponent extends SneatBaseComponent {
14
14
  this.sneatApiService = inject(SneatApiService);
15
15
  this.$userRecord = signal(undefined, ...(ngDevMode ? [{ debugName: "$userRecord" }] : []));
16
16
  this.signingInWith = signal(undefined, ...(ngDevMode ? [{ debugName: "signingInWith" }] : []));
17
+ this.disconnecting = signal(undefined, ...(ngDevMode ? [{ debugName: "disconnecting" }] : []));
17
18
  this.sneatUserService.userState.pipe(this.takeUntilDestroyed()).subscribe({
18
19
  next: (user) => {
19
20
  this.$userRecord.set(user.record || undefined);
@@ -38,12 +39,12 @@ export class UserAuthAccountsComponent extends SneatBaseComponent {
38
39
  if (!confirm('Are you sure you want to disconnect Telegram login from your account?')) {
39
40
  return;
40
41
  }
41
- this.disconnecting = provider;
42
+ this.disconnecting.set(provider);
42
43
  this.sneatApiService
43
44
  .delete('auth/disconnect?provider=' + provider)
44
45
  .subscribe({
45
46
  next: () => {
46
- this.disconnecting = undefined;
47
+ this.disconnecting.set(undefined);
47
48
  alert('Disconnected!');
48
49
  },
49
50
  error: this.errorLogger.logErrorHandler('Failed to disconnect'),
@@ -55,7 +56,7 @@ export class UserAuthAccountsComponent extends SneatBaseComponent {
55
56
  provide: ClassName,
56
57
  useValue: 'UserAuthAccountsComponent',
57
58
  },
58
- ], usesInheritance: true, ngImport: i0, template: "<ion-card>\n <!--\t<ion-item color=\"light\" lines=\"full\">-->\n <!--\t\t<ion-label color=\"medium\"-->\n <!--\t\t\t><h2 style=\"font-weight: bold\">Authentication</h2></ion-label-->\n <!--\t\t>-->\n <!--\t</ion-item>-->\n <!--\t<ion-accordion-group [value]=\"integrations\">-->\n <!--\t\t<ion-accordion value=\"messaging-apps\">-->\n <!--\t\t\t<ion-item slot=\"header\" color=\"light\">-->\n <!--\t\t\t\t<ion-label>First Accordion</ion-label>-->\n <!--\t\t\t</ion-item>-->\n <!--\t\t\t<div class=\"ion-padding\" slot=\"content\">First Content</div>-->\n <!--\t\t</ion-accordion>-->\n <!--\t\t<ion-accordion value=\"quick-logins\">-->\n <!--\t\t\t<ion-item slot=\"header\" color=\"light\">-->\n <!--\t\t\t\t<ion-label>Second Accordion</ion-label>-->\n <!--\t\t\t</ion-item>-->\n <!--\t\t\t<div class=\"ion-padding\" slot=\"content\">Second Content</div>-->\n <!--\t\t</ion-accordion>-->\n <!--\t</ion-accordion-group>-->\n <!--\t<ion-item>-->\n <!--\t\t<ion-segment [(ngModel)]=\"integrations\" style=\"margin-bottom: 0.5em\">-->\n <!--\t\t\t<ion-segment-button value=\"messaging-apps\"-->\n <!--\t\t\t\t>Messaging Apps-->\n <!--\t\t\t</ion-segment-button>-->\n <!--\t\t\t<ion-segment-button value=\"quick-logins\">Quick logins</ion-segment-button>-->\n <!--\t\t</ion-segment>-->\n <!--\t</ion-item>-->\n <ion-list>\n <ion-item-divider color=\"light\">\n <ion-label color=\"medium\" style=\"font-weight: bold\"\n >Quick logins</ion-label\n >\n </ion-item-divider>\n <sneat-user-auth-provider-status\n providerID=\"google.com\"\n [signingInWith]=\"signingInWith()\"\n (signingInWithChange)=\"signingInWith.set($event)\"\n />\n <sneat-user-auth-provider-status\n providerID=\"apple.com\"\n [signingInWith]=\"signingInWith()\"\n (signingInWithChange)=\"signingInWith.set($event)\"\n />\n <sneat-user-auth-provider-status\n providerID=\"microsoft.com\"\n [signingInWith]=\"signingInWith()\"\n (signingInWithChange)=\"signingInWith.set($event)\"\n />\n </ion-list>\n <ion-list>\n <ion-item-divider color=\"light\">\n <ion-label color=\"medium\" style=\"font-weight: bold\"\n >Messaging apps</ion-label\n >\n </ion-item-divider>\n\n <ion-item>\n <ion-icon slot=\"start\" name=\"paper-plane\" color=\"primary\"></ion-icon>\n @if (!$userRecord()) {\n <ion-label>\n <h3>Telegram</h3>\n <p>Checking....</p>\n </ion-label>\n } @else if (hasAccount(\"telegram\")) {\n <ion-label>\n <h3 style=\"font-weight: bold\">Telegram</h3>\n <ion-text color=\"success\" [title]=\"getAccountID('telegram')\"\n >Connected!\n </ion-text>\n </ion-label>\n <ion-buttons slot=\"end\">\n <ion-button\n [disabled]=\"disconnecting\"\n color=\"warning\"\n fill=\"solid\"\n (click)=\"disconnect('telegram')\"\n >\n <ion-icon name=\"close-outline\" slot=\"start\"></ion-icon>\n <ion-label>Disconnect</ion-label>\n </ion-button>\n </ion-buttons>\n } @else {\n <ion-label>\n <h3>Telegram</h3>\n <p>Not connected yet.</p>\n </ion-label>\n <ion-buttons slot=\"end\">\n <sneat-login-with-telegram [isUserAuthenticated]=\"true\" />\n </ion-buttons>\n }\n </ion-item>\n <ion-item>\n <ion-icon slot=\"start\" name=\"logo-whatsapp\"></ion-icon>\n <ion-label color=\"medium\">\n <h3 style=\"font-weight: bold\">WhatsApp</h3>\n <p>Not implemented yet - coming soon!</p>\n </ion-label>\n <!--\t\t<ion-buttons slot=\"end\">-->\n <!--\t\t\t<ion-button color=\"danger\">-->\n <!--\t\t\t\t<ion-icon name=\"close-circle-outline\" slot=\"start\"></ion-icon>-->\n <!--\t\t\t\t<ion-label>I have no WhatsApp</ion-label>-->\n <!--\t\t\t</ion-button>-->\n <!--\t\t</ion-buttons>-->\n </ion-item>\n <ion-item>\n <ion-icon slot=\"start\" name=\"logo-whatsapp\"></ion-icon>\n <!-- TODO: place Viber logo here -->\n <ion-label color=\"medium\">\n <h3 style=\"font-weight: bold\">Viber</h3>\n <p>Not implemented yet - coming soon!</p>\n </ion-label>\n </ion-item>\n </ion-list>\n <ion-card-content>\n <p>\n You'll get much more out of Sneat.app if you integrate it with messaging\n apps you use. Benefits:\n </p>\n <ul>\n <li>Easily add contacts</li>\n <li>Get reminders</li>\n <li>Add todo/to_buy from your messenger</li>\n <li>etc.</li>\n </ul>\n </ion-card-content>\n</ion-card>\n", dependencies: [{ kind: "component", type: LoginWithTelegramComponent, selector: "sneat-login-with-telegram", inputs: ["isUserAuthenticated", "botID", "size", "requestAccess", "userPic"] }, { kind: "ngmodule", type: FormsModule }, { kind: "component", type: UserAuthAProviderStatusComponent, selector: "sneat-user-auth-provider-status", inputs: ["providerID", "signingInWith"], outputs: ["signingInWithChange"] }, { kind: "component", type: IonCard, selector: "ion-card", inputs: ["button", "color", "disabled", "download", "href", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] }, { kind: "component", type: IonList, selector: "ion-list", inputs: ["inset", "lines", "mode"] }, { 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: IonItem, selector: "ion-item", inputs: ["button", "color", "detail", "detailIcon", "disabled", "download", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: IonText, selector: "ion-text", inputs: ["color", "mode"] }, { kind: "component", type: IonButtons, selector: "ion-buttons", inputs: ["collapse"] }, { 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: IonCardContent, selector: "ion-card-content", inputs: ["mode"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
59
+ ], usesInheritance: true, ngImport: i0, template: "<ion-card>\n <!--\t<ion-item color=\"light\" lines=\"full\">-->\n <!--\t\t<ion-label color=\"medium\"-->\n <!--\t\t\t><h2 style=\"font-weight: bold\">Authentication</h2></ion-label-->\n <!--\t\t>-->\n <!--\t</ion-item>-->\n <!--\t<ion-accordion-group [value]=\"integrations\">-->\n <!--\t\t<ion-accordion value=\"messaging-apps\">-->\n <!--\t\t\t<ion-item slot=\"header\" color=\"light\">-->\n <!--\t\t\t\t<ion-label>First Accordion</ion-label>-->\n <!--\t\t\t</ion-item>-->\n <!--\t\t\t<div class=\"ion-padding\" slot=\"content\">First Content</div>-->\n <!--\t\t</ion-accordion>-->\n <!--\t\t<ion-accordion value=\"quick-logins\">-->\n <!--\t\t\t<ion-item slot=\"header\" color=\"light\">-->\n <!--\t\t\t\t<ion-label>Second Accordion</ion-label>-->\n <!--\t\t\t</ion-item>-->\n <!--\t\t\t<div class=\"ion-padding\" slot=\"content\">Second Content</div>-->\n <!--\t\t</ion-accordion>-->\n <!--\t</ion-accordion-group>-->\n <!--\t<ion-item>-->\n <!--\t\t<ion-segment [(ngModel)]=\"integrations\" style=\"margin-bottom: 0.5em\">-->\n <!--\t\t\t<ion-segment-button value=\"messaging-apps\"-->\n <!--\t\t\t\t>Messaging Apps-->\n <!--\t\t\t</ion-segment-button>-->\n <!--\t\t\t<ion-segment-button value=\"quick-logins\">Quick logins</ion-segment-button>-->\n <!--\t\t</ion-segment>-->\n <!--\t</ion-item>-->\n <ion-list>\n <ion-item-divider color=\"light\">\n <ion-label color=\"medium\" style=\"font-weight: bold\"\n >Quick logins</ion-label\n >\n </ion-item-divider>\n <sneat-user-auth-provider-status\n providerID=\"google.com\"\n [signingInWith]=\"signingInWith()\"\n (signingInWithChange)=\"signingInWith.set($event)\"\n />\n <sneat-user-auth-provider-status\n providerID=\"apple.com\"\n [signingInWith]=\"signingInWith()\"\n (signingInWithChange)=\"signingInWith.set($event)\"\n />\n <sneat-user-auth-provider-status\n providerID=\"microsoft.com\"\n [signingInWith]=\"signingInWith()\"\n (signingInWithChange)=\"signingInWith.set($event)\"\n />\n </ion-list>\n <ion-list>\n <ion-item-divider color=\"light\">\n <ion-label color=\"medium\" style=\"font-weight: bold\"\n >Messaging apps</ion-label\n >\n </ion-item-divider>\n\n <ion-item>\n <ion-icon slot=\"start\" name=\"paper-plane\" color=\"primary\"></ion-icon>\n @if (!$userRecord()) {\n <ion-label>\n <h3>Telegram</h3>\n <p>Checking....</p>\n </ion-label>\n } @else if (hasAccount(\"telegram\")) {\n <ion-label>\n <h3 style=\"font-weight: bold\">Telegram</h3>\n <ion-text color=\"success\" [title]=\"getAccountID('telegram')\"\n >Connected!\n </ion-text>\n </ion-label>\n <ion-buttons slot=\"end\">\n <ion-button\n [disabled]=\"disconnecting()\"\n color=\"warning\"\n fill=\"solid\"\n (click)=\"disconnect('telegram')\"\n >\n <ion-icon name=\"close-outline\" slot=\"start\"></ion-icon>\n <ion-label>Disconnect</ion-label>\n </ion-button>\n </ion-buttons>\n } @else {\n <ion-label>\n <h3>Telegram</h3>\n <p>Not connected yet.</p>\n </ion-label>\n <ion-buttons slot=\"end\">\n <sneat-login-with-telegram [isUserAuthenticated]=\"true\" />\n </ion-buttons>\n }\n </ion-item>\n <ion-item>\n <ion-icon slot=\"start\" name=\"logo-whatsapp\"></ion-icon>\n <ion-label color=\"medium\">\n <h3 style=\"font-weight: bold\">WhatsApp</h3>\n <p>Not implemented yet - coming soon!</p>\n </ion-label>\n <!--\t\t<ion-buttons slot=\"end\">-->\n <!--\t\t\t<ion-button color=\"danger\">-->\n <!--\t\t\t\t<ion-icon name=\"close-circle-outline\" slot=\"start\"></ion-icon>-->\n <!--\t\t\t\t<ion-label>I have no WhatsApp</ion-label>-->\n <!--\t\t\t</ion-button>-->\n <!--\t\t</ion-buttons>-->\n </ion-item>\n <ion-item>\n <ion-icon slot=\"start\" name=\"logo-whatsapp\"></ion-icon>\n <!-- TODO: place Viber logo here -->\n <ion-label color=\"medium\">\n <h3 style=\"font-weight: bold\">Viber</h3>\n <p>Not implemented yet - coming soon!</p>\n </ion-label>\n </ion-item>\n </ion-list>\n <ion-card-content>\n <p>\n You'll get much more out of Sneat.app if you integrate it with messaging\n apps you use. Benefits:\n </p>\n <ul>\n <li>Easily add contacts</li>\n <li>Get reminders</li>\n <li>Add todo/to_buy from your messenger</li>\n <li>etc.</li>\n </ul>\n </ion-card-content>\n</ion-card>\n", dependencies: [{ kind: "component", type: LoginWithTelegramComponent, selector: "sneat-login-with-telegram", inputs: ["isUserAuthenticated", "botID", "size", "requestAccess", "userPic"] }, { kind: "ngmodule", type: FormsModule }, { kind: "component", type: UserAuthAProviderStatusComponent, selector: "sneat-user-auth-provider-status", inputs: ["providerID", "signingInWith"], outputs: ["signingInWithChange"] }, { kind: "component", type: IonCard, selector: "ion-card", inputs: ["button", "color", "disabled", "download", "href", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] }, { kind: "component", type: IonList, selector: "ion-list", inputs: ["inset", "lines", "mode"] }, { 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: IonItem, selector: "ion-item", inputs: ["button", "color", "detail", "detailIcon", "disabled", "download", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: IonText, selector: "ion-text", inputs: ["color", "mode"] }, { kind: "component", type: IonButtons, selector: "ion-buttons", inputs: ["collapse"] }, { 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: IonCardContent, selector: "ion-card-content", inputs: ["mode"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
59
60
  }
60
61
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: UserAuthAccountsComponent, decorators: [{
61
62
  type: Component,
@@ -78,6 +79,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
78
79
  provide: ClassName,
79
80
  useValue: 'UserAuthAccountsComponent',
80
81
  },
81
- ], template: "<ion-card>\n <!--\t<ion-item color=\"light\" lines=\"full\">-->\n <!--\t\t<ion-label color=\"medium\"-->\n <!--\t\t\t><h2 style=\"font-weight: bold\">Authentication</h2></ion-label-->\n <!--\t\t>-->\n <!--\t</ion-item>-->\n <!--\t<ion-accordion-group [value]=\"integrations\">-->\n <!--\t\t<ion-accordion value=\"messaging-apps\">-->\n <!--\t\t\t<ion-item slot=\"header\" color=\"light\">-->\n <!--\t\t\t\t<ion-label>First Accordion</ion-label>-->\n <!--\t\t\t</ion-item>-->\n <!--\t\t\t<div class=\"ion-padding\" slot=\"content\">First Content</div>-->\n <!--\t\t</ion-accordion>-->\n <!--\t\t<ion-accordion value=\"quick-logins\">-->\n <!--\t\t\t<ion-item slot=\"header\" color=\"light\">-->\n <!--\t\t\t\t<ion-label>Second Accordion</ion-label>-->\n <!--\t\t\t</ion-item>-->\n <!--\t\t\t<div class=\"ion-padding\" slot=\"content\">Second Content</div>-->\n <!--\t\t</ion-accordion>-->\n <!--\t</ion-accordion-group>-->\n <!--\t<ion-item>-->\n <!--\t\t<ion-segment [(ngModel)]=\"integrations\" style=\"margin-bottom: 0.5em\">-->\n <!--\t\t\t<ion-segment-button value=\"messaging-apps\"-->\n <!--\t\t\t\t>Messaging Apps-->\n <!--\t\t\t</ion-segment-button>-->\n <!--\t\t\t<ion-segment-button value=\"quick-logins\">Quick logins</ion-segment-button>-->\n <!--\t\t</ion-segment>-->\n <!--\t</ion-item>-->\n <ion-list>\n <ion-item-divider color=\"light\">\n <ion-label color=\"medium\" style=\"font-weight: bold\"\n >Quick logins</ion-label\n >\n </ion-item-divider>\n <sneat-user-auth-provider-status\n providerID=\"google.com\"\n [signingInWith]=\"signingInWith()\"\n (signingInWithChange)=\"signingInWith.set($event)\"\n />\n <sneat-user-auth-provider-status\n providerID=\"apple.com\"\n [signingInWith]=\"signingInWith()\"\n (signingInWithChange)=\"signingInWith.set($event)\"\n />\n <sneat-user-auth-provider-status\n providerID=\"microsoft.com\"\n [signingInWith]=\"signingInWith()\"\n (signingInWithChange)=\"signingInWith.set($event)\"\n />\n </ion-list>\n <ion-list>\n <ion-item-divider color=\"light\">\n <ion-label color=\"medium\" style=\"font-weight: bold\"\n >Messaging apps</ion-label\n >\n </ion-item-divider>\n\n <ion-item>\n <ion-icon slot=\"start\" name=\"paper-plane\" color=\"primary\"></ion-icon>\n @if (!$userRecord()) {\n <ion-label>\n <h3>Telegram</h3>\n <p>Checking....</p>\n </ion-label>\n } @else if (hasAccount(\"telegram\")) {\n <ion-label>\n <h3 style=\"font-weight: bold\">Telegram</h3>\n <ion-text color=\"success\" [title]=\"getAccountID('telegram')\"\n >Connected!\n </ion-text>\n </ion-label>\n <ion-buttons slot=\"end\">\n <ion-button\n [disabled]=\"disconnecting\"\n color=\"warning\"\n fill=\"solid\"\n (click)=\"disconnect('telegram')\"\n >\n <ion-icon name=\"close-outline\" slot=\"start\"></ion-icon>\n <ion-label>Disconnect</ion-label>\n </ion-button>\n </ion-buttons>\n } @else {\n <ion-label>\n <h3>Telegram</h3>\n <p>Not connected yet.</p>\n </ion-label>\n <ion-buttons slot=\"end\">\n <sneat-login-with-telegram [isUserAuthenticated]=\"true\" />\n </ion-buttons>\n }\n </ion-item>\n <ion-item>\n <ion-icon slot=\"start\" name=\"logo-whatsapp\"></ion-icon>\n <ion-label color=\"medium\">\n <h3 style=\"font-weight: bold\">WhatsApp</h3>\n <p>Not implemented yet - coming soon!</p>\n </ion-label>\n <!--\t\t<ion-buttons slot=\"end\">-->\n <!--\t\t\t<ion-button color=\"danger\">-->\n <!--\t\t\t\t<ion-icon name=\"close-circle-outline\" slot=\"start\"></ion-icon>-->\n <!--\t\t\t\t<ion-label>I have no WhatsApp</ion-label>-->\n <!--\t\t\t</ion-button>-->\n <!--\t\t</ion-buttons>-->\n </ion-item>\n <ion-item>\n <ion-icon slot=\"start\" name=\"logo-whatsapp\"></ion-icon>\n <!-- TODO: place Viber logo here -->\n <ion-label color=\"medium\">\n <h3 style=\"font-weight: bold\">Viber</h3>\n <p>Not implemented yet - coming soon!</p>\n </ion-label>\n </ion-item>\n </ion-list>\n <ion-card-content>\n <p>\n You'll get much more out of Sneat.app if you integrate it with messaging\n apps you use. Benefits:\n </p>\n <ul>\n <li>Easily add contacts</li>\n <li>Get reminders</li>\n <li>Add todo/to_buy from your messenger</li>\n <li>etc.</li>\n </ul>\n </ion-card-content>\n</ion-card>\n" }]
82
+ ], template: "<ion-card>\n <!--\t<ion-item color=\"light\" lines=\"full\">-->\n <!--\t\t<ion-label color=\"medium\"-->\n <!--\t\t\t><h2 style=\"font-weight: bold\">Authentication</h2></ion-label-->\n <!--\t\t>-->\n <!--\t</ion-item>-->\n <!--\t<ion-accordion-group [value]=\"integrations\">-->\n <!--\t\t<ion-accordion value=\"messaging-apps\">-->\n <!--\t\t\t<ion-item slot=\"header\" color=\"light\">-->\n <!--\t\t\t\t<ion-label>First Accordion</ion-label>-->\n <!--\t\t\t</ion-item>-->\n <!--\t\t\t<div class=\"ion-padding\" slot=\"content\">First Content</div>-->\n <!--\t\t</ion-accordion>-->\n <!--\t\t<ion-accordion value=\"quick-logins\">-->\n <!--\t\t\t<ion-item slot=\"header\" color=\"light\">-->\n <!--\t\t\t\t<ion-label>Second Accordion</ion-label>-->\n <!--\t\t\t</ion-item>-->\n <!--\t\t\t<div class=\"ion-padding\" slot=\"content\">Second Content</div>-->\n <!--\t\t</ion-accordion>-->\n <!--\t</ion-accordion-group>-->\n <!--\t<ion-item>-->\n <!--\t\t<ion-segment [(ngModel)]=\"integrations\" style=\"margin-bottom: 0.5em\">-->\n <!--\t\t\t<ion-segment-button value=\"messaging-apps\"-->\n <!--\t\t\t\t>Messaging Apps-->\n <!--\t\t\t</ion-segment-button>-->\n <!--\t\t\t<ion-segment-button value=\"quick-logins\">Quick logins</ion-segment-button>-->\n <!--\t\t</ion-segment>-->\n <!--\t</ion-item>-->\n <ion-list>\n <ion-item-divider color=\"light\">\n <ion-label color=\"medium\" style=\"font-weight: bold\"\n >Quick logins</ion-label\n >\n </ion-item-divider>\n <sneat-user-auth-provider-status\n providerID=\"google.com\"\n [signingInWith]=\"signingInWith()\"\n (signingInWithChange)=\"signingInWith.set($event)\"\n />\n <sneat-user-auth-provider-status\n providerID=\"apple.com\"\n [signingInWith]=\"signingInWith()\"\n (signingInWithChange)=\"signingInWith.set($event)\"\n />\n <sneat-user-auth-provider-status\n providerID=\"microsoft.com\"\n [signingInWith]=\"signingInWith()\"\n (signingInWithChange)=\"signingInWith.set($event)\"\n />\n </ion-list>\n <ion-list>\n <ion-item-divider color=\"light\">\n <ion-label color=\"medium\" style=\"font-weight: bold\"\n >Messaging apps</ion-label\n >\n </ion-item-divider>\n\n <ion-item>\n <ion-icon slot=\"start\" name=\"paper-plane\" color=\"primary\"></ion-icon>\n @if (!$userRecord()) {\n <ion-label>\n <h3>Telegram</h3>\n <p>Checking....</p>\n </ion-label>\n } @else if (hasAccount(\"telegram\")) {\n <ion-label>\n <h3 style=\"font-weight: bold\">Telegram</h3>\n <ion-text color=\"success\" [title]=\"getAccountID('telegram')\"\n >Connected!\n </ion-text>\n </ion-label>\n <ion-buttons slot=\"end\">\n <ion-button\n [disabled]=\"disconnecting()\"\n color=\"warning\"\n fill=\"solid\"\n (click)=\"disconnect('telegram')\"\n >\n <ion-icon name=\"close-outline\" slot=\"start\"></ion-icon>\n <ion-label>Disconnect</ion-label>\n </ion-button>\n </ion-buttons>\n } @else {\n <ion-label>\n <h3>Telegram</h3>\n <p>Not connected yet.</p>\n </ion-label>\n <ion-buttons slot=\"end\">\n <sneat-login-with-telegram [isUserAuthenticated]=\"true\" />\n </ion-buttons>\n }\n </ion-item>\n <ion-item>\n <ion-icon slot=\"start\" name=\"logo-whatsapp\"></ion-icon>\n <ion-label color=\"medium\">\n <h3 style=\"font-weight: bold\">WhatsApp</h3>\n <p>Not implemented yet - coming soon!</p>\n </ion-label>\n <!--\t\t<ion-buttons slot=\"end\">-->\n <!--\t\t\t<ion-button color=\"danger\">-->\n <!--\t\t\t\t<ion-icon name=\"close-circle-outline\" slot=\"start\"></ion-icon>-->\n <!--\t\t\t\t<ion-label>I have no WhatsApp</ion-label>-->\n <!--\t\t\t</ion-button>-->\n <!--\t\t</ion-buttons>-->\n </ion-item>\n <ion-item>\n <ion-icon slot=\"start\" name=\"logo-whatsapp\"></ion-icon>\n <!-- TODO: place Viber logo here -->\n <ion-label color=\"medium\">\n <h3 style=\"font-weight: bold\">Viber</h3>\n <p>Not implemented yet - coming soon!</p>\n </ion-label>\n </ion-item>\n </ion-list>\n <ion-card-content>\n <p>\n You'll get much more out of Sneat.app if you integrate it with messaging\n apps you use. Benefits:\n </p>\n <ul>\n <li>Easily add contacts</li>\n <li>Get reminders</li>\n <li>Add todo/to_buy from your messenger</li>\n <li>etc.</li>\n </ul>\n </ion-card-content>\n</ion-card>\n" }]
82
83
  }], ctorParameters: () => [] });
83
84
  //# sourceMappingURL=user-auth-accounts.component.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"user-auth-accounts.component.js","sourceRoot":"","sources":["../../../../../../../../libs/auth/ui/src/lib/components/user-auth-providers/user-auth-accounts.component.ts","../../../../../../../../libs/auth/ui/src/lib/components/user-auth-providers/user-auth-accounts.component.html"],"names":[],"mappings":"AAAA,OAAO,EACL,uBAAuB,EACvB,SAAS,EACT,MAAM,EACN,MAAM,GACP,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,EACL,SAAS,EACT,UAAU,EACV,OAAO,EACP,cAAc,EACd,OAAO,EACP,OAAO,EACP,cAAc,EACd,QAAQ,EACR,OAAO,EACP,OAAO,GACR,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,EAAkB,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAEpE,OAAO,EAAE,SAAS,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAC1D,OAAO,EAAE,0BAA0B,EAAE,MAAM,sDAAsD,CAAC;AAClG,OAAO,EAAE,gCAAgC,EAAE,MAAM,6BAA6B,CAAC;;AA4B/E,MAAM,OAAO,yBAA0B,SAAQ,kBAAkB;IAU/D;QACE,KAAK,EAAE,CAAC;QAVO,qBAAgB,GAAG,MAAM,CAAC,gBAAgB,CAAC,CAAC;QAC5C,oBAAe,GAAG,MAAM,CAAC,eAAe,CAAC,CAAC;QAExC,gBAAW,GAAG,MAAM,CAA0B,SAAS,uDAAC,CAAC;QAEzD,kBAAa,GAAG,MAAM,CACvC,SAAS,yDACV,CAAC;QAIA,IAAI,CAAC,gBAAgB,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,kBAAkB,EAAE,CAAC,CAAC,SAAS,CAAC;YACxE,IAAI,EAAE,CAAC,IAAI,EAAE,EAAE;gBACb,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,IAAI,SAAS,CAAC,CAAC;YACjD,CAAC;SACF,CAAC,CAAC;IACL,CAAC;IAES,UAAU,CAAC,QAA2C;QAC9D,QAAQ,GAAG,QAAQ,GAAG,GAAG,CAAC;QAC1B,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,WAAW,EAAE,EAAE,QAAQ,IAAI,EAAE,EAAE,CAAC;YACzD,IAAI,OAAO,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;gBACjC,OAAO,IAAI,CAAC;YACd,CAAC;QACH,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAES,YAAY,CAAC,QAAoB;QACzC,MAAM,MAAM,GAAG,QAAQ,GAAG,IAAI,CAAC;QAC/B,MAAM,CAAC,GAAG,IAAI,CAAC,WAAW,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC;QAC1E,OAAO,CAAC,EAAE,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,EAAE,CAAC;IACtC,CAAC;IAIS,UAAU,CAAC,QAAoB;QACvC,IACE,CAAC,OAAO,CACN,uEAAuE,CACxE,EACD,CAAC;YACD,OAAO;QACT,CAAC;QACD,IAAI,CAAC,aAAa,GAAG,QAAQ,CAAC;QAC9B,IAAI,CAAC,eAAe;aACjB,MAAM,CAAC,2BAA2B,GAAG,QAAQ,CAAC;aAC9C,SAAS,CAAC;YACT,IAAI,EAAE,GAAG,EAAE;gBACT,IAAI,CAAC,aAAa,GAAG,SAAS,CAAC;gBAC/B,KAAK,CAAC,eAAe,CAAC,CAAC;YACzB,CAAC;YACD,KAAK,EAAE,IAAI,CAAC,WAAW,CAAC,eAAe,CAAC,sBAAsB,CAAC;SAChE,CAAC,CAAC;IACP,CAAC;8GAvDU,yBAAyB;kGAAzB,yBAAyB,uEAPzB;YACT;gBACE,OAAO,EAAE,SAAS;gBAClB,QAAQ,EAAE,2BAA2B;aACtC;SACF,iDClDH,glJA+HA,4CDhGI,0BAA0B,mJAC1B,WAAW,+BACX,gCAAgC,uJAChC,OAAO,yLACP,OAAO,yFACP,cAAc,kGACd,QAAQ,6FACR,OAAO,0NACP,OAAO,2JACP,OAAO,gFACP,UAAU,8EACV,SAAS,oPACT,cAAc;;2FASL,yBAAyB;kBA1BrC,SAAS;+BACE,0BAA0B,mBAEnB,uBAAuB,CAAC,MAAM,WACtC;wBACP,0BAA0B;wBAC1B,WAAW;wBACX,gCAAgC;wBAChC,OAAO;wBACP,OAAO;wBACP,cAAc;wBACd,QAAQ;wBACR,OAAO;wBACP,OAAO;wBACP,OAAO;wBACP,UAAU;wBACV,SAAS;wBACT,cAAc;qBACf,aACU;wBACT;4BACE,OAAO,EAAE,SAAS;4BAClB,QAAQ,EAAE,2BAA2B;yBACtC;qBACF","sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n signal,\n inject,\n} from '@angular/core';\nimport { FormsModule } from '@angular/forms';\nimport {\n IonButton,\n IonButtons,\n IonCard,\n IonCardContent,\n IonIcon,\n IonItem,\n IonItemDivider,\n IonLabel,\n IonList,\n IonText,\n} from '@ionic/angular/standalone';\nimport { SneatApiService } from '@sneat/api';\nimport { AuthProviderID, SneatUserService } from '@sneat/auth-core';\nimport { IUserRecord } from '@sneat/auth-models';\nimport { ClassName, SneatBaseComponent } from '@sneat/ui';\nimport { LoginWithTelegramComponent } from '../../pages/login-page/login-with-telegram.component';\nimport { UserAuthAProviderStatusComponent } from './user-auth-provider-status';\n\n@Component({\n selector: 'sneat-user-auth-accounts',\n templateUrl: './user-auth-accounts.component.html',\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [\n LoginWithTelegramComponent,\n FormsModule,\n UserAuthAProviderStatusComponent,\n IonCard,\n IonList,\n IonItemDivider,\n IonLabel,\n IonItem,\n IonIcon,\n IonText,\n IonButtons,\n IonButton,\n IonCardContent,\n ],\n providers: [\n {\n provide: ClassName,\n useValue: 'UserAuthAccountsComponent',\n },\n ],\n})\nexport class UserAuthAccountsComponent extends SneatBaseComponent {\n private readonly sneatUserService = inject(SneatUserService);\n private readonly sneatApiService = inject(SneatApiService);\n\n protected readonly $userRecord = signal<IUserRecord | undefined>(undefined);\n\n protected readonly signingInWith = signal<AuthProviderID | undefined>(\n undefined,\n );\n\n constructor() {\n super();\n this.sneatUserService.userState.pipe(this.takeUntilDestroyed()).subscribe({\n next: (user) => {\n this.$userRecord.set(user.record || undefined);\n },\n });\n }\n\n protected hasAccount(provider: 'telegram' | 'viber' | 'whatsapp'): boolean {\n provider = provider + ':';\n for (const account of this.$userRecord()?.accounts || []) {\n if (account.startsWith(provider)) {\n return true;\n }\n }\n return false;\n }\n\n protected getAccountID(provider: 'telegram'): string {\n const prefix = provider + '::';\n const a = this.$userRecord()?.accounts?.find((a) => a.startsWith(prefix));\n return a?.replace(prefix, '') || '';\n }\n\n protected disconnecting?: 'telegram' | 'viber' | 'whatsapp';\n\n protected disconnect(provider: 'telegram'): void {\n if (\n !confirm(\n 'Are you sure you want to disconnect Telegram login from your account?',\n )\n ) {\n return;\n }\n this.disconnecting = provider;\n this.sneatApiService\n .delete('auth/disconnect?provider=' + provider)\n .subscribe({\n next: () => {\n this.disconnecting = undefined;\n alert('Disconnected!');\n },\n error: this.errorLogger.logErrorHandler('Failed to disconnect'),\n });\n }\n}\n","<ion-card>\n <!--\t<ion-item color=\"light\" lines=\"full\">-->\n <!--\t\t<ion-label color=\"medium\"-->\n <!--\t\t\t><h2 style=\"font-weight: bold\">Authentication</h2></ion-label-->\n <!--\t\t>-->\n <!--\t</ion-item>-->\n <!--\t<ion-accordion-group [value]=\"integrations\">-->\n <!--\t\t<ion-accordion value=\"messaging-apps\">-->\n <!--\t\t\t<ion-item slot=\"header\" color=\"light\">-->\n <!--\t\t\t\t<ion-label>First Accordion</ion-label>-->\n <!--\t\t\t</ion-item>-->\n <!--\t\t\t<div class=\"ion-padding\" slot=\"content\">First Content</div>-->\n <!--\t\t</ion-accordion>-->\n <!--\t\t<ion-accordion value=\"quick-logins\">-->\n <!--\t\t\t<ion-item slot=\"header\" color=\"light\">-->\n <!--\t\t\t\t<ion-label>Second Accordion</ion-label>-->\n <!--\t\t\t</ion-item>-->\n <!--\t\t\t<div class=\"ion-padding\" slot=\"content\">Second Content</div>-->\n <!--\t\t</ion-accordion>-->\n <!--\t</ion-accordion-group>-->\n <!--\t<ion-item>-->\n <!--\t\t<ion-segment [(ngModel)]=\"integrations\" style=\"margin-bottom: 0.5em\">-->\n <!--\t\t\t<ion-segment-button value=\"messaging-apps\"-->\n <!--\t\t\t\t>Messaging Apps-->\n <!--\t\t\t</ion-segment-button>-->\n <!--\t\t\t<ion-segment-button value=\"quick-logins\">Quick logins</ion-segment-button>-->\n <!--\t\t</ion-segment>-->\n <!--\t</ion-item>-->\n <ion-list>\n <ion-item-divider color=\"light\">\n <ion-label color=\"medium\" style=\"font-weight: bold\"\n >Quick logins</ion-label\n >\n </ion-item-divider>\n <sneat-user-auth-provider-status\n providerID=\"google.com\"\n [signingInWith]=\"signingInWith()\"\n (signingInWithChange)=\"signingInWith.set($event)\"\n />\n <sneat-user-auth-provider-status\n providerID=\"apple.com\"\n [signingInWith]=\"signingInWith()\"\n (signingInWithChange)=\"signingInWith.set($event)\"\n />\n <sneat-user-auth-provider-status\n providerID=\"microsoft.com\"\n [signingInWith]=\"signingInWith()\"\n (signingInWithChange)=\"signingInWith.set($event)\"\n />\n </ion-list>\n <ion-list>\n <ion-item-divider color=\"light\">\n <ion-label color=\"medium\" style=\"font-weight: bold\"\n >Messaging apps</ion-label\n >\n </ion-item-divider>\n\n <ion-item>\n <ion-icon slot=\"start\" name=\"paper-plane\" color=\"primary\"></ion-icon>\n @if (!$userRecord()) {\n <ion-label>\n <h3>Telegram</h3>\n <p>Checking....</p>\n </ion-label>\n } @else if (hasAccount(\"telegram\")) {\n <ion-label>\n <h3 style=\"font-weight: bold\">Telegram</h3>\n <ion-text color=\"success\" [title]=\"getAccountID('telegram')\"\n >Connected!\n </ion-text>\n </ion-label>\n <ion-buttons slot=\"end\">\n <ion-button\n [disabled]=\"disconnecting\"\n color=\"warning\"\n fill=\"solid\"\n (click)=\"disconnect('telegram')\"\n >\n <ion-icon name=\"close-outline\" slot=\"start\"></ion-icon>\n <ion-label>Disconnect</ion-label>\n </ion-button>\n </ion-buttons>\n } @else {\n <ion-label>\n <h3>Telegram</h3>\n <p>Not connected yet.</p>\n </ion-label>\n <ion-buttons slot=\"end\">\n <sneat-login-with-telegram [isUserAuthenticated]=\"true\" />\n </ion-buttons>\n }\n </ion-item>\n <ion-item>\n <ion-icon slot=\"start\" name=\"logo-whatsapp\"></ion-icon>\n <ion-label color=\"medium\">\n <h3 style=\"font-weight: bold\">WhatsApp</h3>\n <p>Not implemented yet - coming soon!</p>\n </ion-label>\n <!--\t\t<ion-buttons slot=\"end\">-->\n <!--\t\t\t<ion-button color=\"danger\">-->\n <!--\t\t\t\t<ion-icon name=\"close-circle-outline\" slot=\"start\"></ion-icon>-->\n <!--\t\t\t\t<ion-label>I have no WhatsApp</ion-label>-->\n <!--\t\t\t</ion-button>-->\n <!--\t\t</ion-buttons>-->\n </ion-item>\n <ion-item>\n <ion-icon slot=\"start\" name=\"logo-whatsapp\"></ion-icon>\n <!-- TODO: place Viber logo here -->\n <ion-label color=\"medium\">\n <h3 style=\"font-weight: bold\">Viber</h3>\n <p>Not implemented yet - coming soon!</p>\n </ion-label>\n </ion-item>\n </ion-list>\n <ion-card-content>\n <p>\n You'll get much more out of Sneat.app if you integrate it with messaging\n apps you use. Benefits:\n </p>\n <ul>\n <li>Easily add contacts</li>\n <li>Get reminders</li>\n <li>Add todo/to_buy from your messenger</li>\n <li>etc.</li>\n </ul>\n </ion-card-content>\n</ion-card>\n"]}
1
+ {"version":3,"file":"user-auth-accounts.component.js","sourceRoot":"","sources":["../../../../../../../../libs/auth/ui/src/lib/components/user-auth-providers/user-auth-accounts.component.ts","../../../../../../../../libs/auth/ui/src/lib/components/user-auth-providers/user-auth-accounts.component.html"],"names":[],"mappings":"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","sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n signal,\n inject,\n} from '@angular/core';\nimport { FormsModule } from '@angular/forms';\nimport {\n IonButton,\n IonButtons,\n IonCard,\n IonCardContent,\n IonIcon,\n IonItem,\n IonItemDivider,\n IonLabel,\n IonList,\n IonText,\n} from '@ionic/angular/standalone';\nimport { SneatApiService } from '@sneat/api';\nimport { AuthProviderID, SneatUserService } from '@sneat/auth-core';\nimport { IUserRecord } from '@sneat/auth-models';\nimport { ClassName, SneatBaseComponent } from '@sneat/ui';\nimport { LoginWithTelegramComponent } from '../../pages/login-page/login-with-telegram.component';\nimport { UserAuthAProviderStatusComponent } from './user-auth-provider-status';\n\n@Component({\n selector: 'sneat-user-auth-accounts',\n templateUrl: './user-auth-accounts.component.html',\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [\n LoginWithTelegramComponent,\n FormsModule,\n UserAuthAProviderStatusComponent,\n IonCard,\n IonList,\n IonItemDivider,\n IonLabel,\n IonItem,\n IonIcon,\n IonText,\n IonButtons,\n IonButton,\n IonCardContent,\n ],\n providers: [\n {\n provide: ClassName,\n useValue: 'UserAuthAccountsComponent',\n },\n ],\n})\nexport class UserAuthAccountsComponent extends SneatBaseComponent {\n private readonly sneatUserService = inject(SneatUserService);\n private readonly sneatApiService = inject(SneatApiService);\n\n protected readonly $userRecord = signal<IUserRecord | undefined>(undefined);\n\n protected readonly signingInWith = signal<AuthProviderID | undefined>(\n undefined,\n );\n\n constructor() {\n super();\n this.sneatUserService.userState.pipe(this.takeUntilDestroyed()).subscribe({\n next: (user) => {\n this.$userRecord.set(user.record || undefined);\n },\n });\n }\n\n protected hasAccount(provider: 'telegram' | 'viber' | 'whatsapp'): boolean {\n provider = provider + ':';\n for (const account of this.$userRecord()?.accounts || []) {\n if (account.startsWith(provider)) {\n return true;\n }\n }\n return false;\n }\n\n protected getAccountID(provider: 'telegram'): string {\n const prefix = provider + '::';\n const a = this.$userRecord()?.accounts?.find((a) => a.startsWith(prefix));\n return a?.replace(prefix, '') || '';\n }\n\n protected readonly disconnecting = signal<\n 'telegram' | 'viber' | 'whatsapp' | undefined\n >(undefined);\n\n protected disconnect(provider: 'telegram'): void {\n if (\n !confirm(\n 'Are you sure you want to disconnect Telegram login from your account?',\n )\n ) {\n return;\n }\n this.disconnecting.set(provider);\n this.sneatApiService\n .delete('auth/disconnect?provider=' + provider)\n .subscribe({\n next: () => {\n this.disconnecting.set(undefined);\n alert('Disconnected!');\n },\n error: this.errorLogger.logErrorHandler('Failed to disconnect'),\n });\n }\n}\n","<ion-card>\n <!--\t<ion-item color=\"light\" lines=\"full\">-->\n <!--\t\t<ion-label color=\"medium\"-->\n <!--\t\t\t><h2 style=\"font-weight: bold\">Authentication</h2></ion-label-->\n <!--\t\t>-->\n <!--\t</ion-item>-->\n <!--\t<ion-accordion-group [value]=\"integrations\">-->\n <!--\t\t<ion-accordion value=\"messaging-apps\">-->\n <!--\t\t\t<ion-item slot=\"header\" color=\"light\">-->\n <!--\t\t\t\t<ion-label>First Accordion</ion-label>-->\n <!--\t\t\t</ion-item>-->\n <!--\t\t\t<div class=\"ion-padding\" slot=\"content\">First Content</div>-->\n <!--\t\t</ion-accordion>-->\n <!--\t\t<ion-accordion value=\"quick-logins\">-->\n <!--\t\t\t<ion-item slot=\"header\" color=\"light\">-->\n <!--\t\t\t\t<ion-label>Second Accordion</ion-label>-->\n <!--\t\t\t</ion-item>-->\n <!--\t\t\t<div class=\"ion-padding\" slot=\"content\">Second Content</div>-->\n <!--\t\t</ion-accordion>-->\n <!--\t</ion-accordion-group>-->\n <!--\t<ion-item>-->\n <!--\t\t<ion-segment [(ngModel)]=\"integrations\" style=\"margin-bottom: 0.5em\">-->\n <!--\t\t\t<ion-segment-button value=\"messaging-apps\"-->\n <!--\t\t\t\t>Messaging Apps-->\n <!--\t\t\t</ion-segment-button>-->\n <!--\t\t\t<ion-segment-button value=\"quick-logins\">Quick logins</ion-segment-button>-->\n <!--\t\t</ion-segment>-->\n <!--\t</ion-item>-->\n <ion-list>\n <ion-item-divider color=\"light\">\n <ion-label color=\"medium\" style=\"font-weight: bold\"\n >Quick logins</ion-label\n >\n </ion-item-divider>\n <sneat-user-auth-provider-status\n providerID=\"google.com\"\n [signingInWith]=\"signingInWith()\"\n (signingInWithChange)=\"signingInWith.set($event)\"\n />\n <sneat-user-auth-provider-status\n providerID=\"apple.com\"\n [signingInWith]=\"signingInWith()\"\n (signingInWithChange)=\"signingInWith.set($event)\"\n />\n <sneat-user-auth-provider-status\n providerID=\"microsoft.com\"\n [signingInWith]=\"signingInWith()\"\n (signingInWithChange)=\"signingInWith.set($event)\"\n />\n </ion-list>\n <ion-list>\n <ion-item-divider color=\"light\">\n <ion-label color=\"medium\" style=\"font-weight: bold\"\n >Messaging apps</ion-label\n >\n </ion-item-divider>\n\n <ion-item>\n <ion-icon slot=\"start\" name=\"paper-plane\" color=\"primary\"></ion-icon>\n @if (!$userRecord()) {\n <ion-label>\n <h3>Telegram</h3>\n <p>Checking....</p>\n </ion-label>\n } @else if (hasAccount(\"telegram\")) {\n <ion-label>\n <h3 style=\"font-weight: bold\">Telegram</h3>\n <ion-text color=\"success\" [title]=\"getAccountID('telegram')\"\n >Connected!\n </ion-text>\n </ion-label>\n <ion-buttons slot=\"end\">\n <ion-button\n [disabled]=\"disconnecting()\"\n color=\"warning\"\n fill=\"solid\"\n (click)=\"disconnect('telegram')\"\n >\n <ion-icon name=\"close-outline\" slot=\"start\"></ion-icon>\n <ion-label>Disconnect</ion-label>\n </ion-button>\n </ion-buttons>\n } @else {\n <ion-label>\n <h3>Telegram</h3>\n <p>Not connected yet.</p>\n </ion-label>\n <ion-buttons slot=\"end\">\n <sneat-login-with-telegram [isUserAuthenticated]=\"true\" />\n </ion-buttons>\n }\n </ion-item>\n <ion-item>\n <ion-icon slot=\"start\" name=\"logo-whatsapp\"></ion-icon>\n <ion-label color=\"medium\">\n <h3 style=\"font-weight: bold\">WhatsApp</h3>\n <p>Not implemented yet - coming soon!</p>\n </ion-label>\n <!--\t\t<ion-buttons slot=\"end\">-->\n <!--\t\t\t<ion-button color=\"danger\">-->\n <!--\t\t\t\t<ion-icon name=\"close-circle-outline\" slot=\"start\"></ion-icon>-->\n <!--\t\t\t\t<ion-label>I have no WhatsApp</ion-label>-->\n <!--\t\t\t</ion-button>-->\n <!--\t\t</ion-buttons>-->\n </ion-item>\n <ion-item>\n <ion-icon slot=\"start\" name=\"logo-whatsapp\"></ion-icon>\n <!-- TODO: place Viber logo here -->\n <ion-label color=\"medium\">\n <h3 style=\"font-weight: bold\">Viber</h3>\n <p>Not implemented yet - coming soon!</p>\n </ion-label>\n </ion-item>\n </ion-list>\n <ion-card-content>\n <p>\n You'll get much more out of Sneat.app if you integrate it with messaging\n apps you use. Benefits:\n </p>\n <ul>\n <li>Easily add contacts</li>\n <li>Get reminders</li>\n <li>Add todo/to_buy from your messenger</li>\n <li>etc.</li>\n </ul>\n </ion-card-content>\n</ion-card>\n"]}
@@ -1,4 +1,4 @@
1
- import { Component, EventEmitter, Output, ViewChild, inject, } from '@angular/core';
1
+ import { ChangeDetectionStrategy, Component, EventEmitter, Output, inject, signal, viewChild, } from '@angular/core';
2
2
  // import { getApp } from '@angular/fire/app';
3
3
  // import { getAuth } from '@angular/fire/auth';
4
4
  import { Auth, sendPasswordResetEmail, sendSignInLinkToEmail, } from '@angular/fire/auth';
@@ -24,38 +24,42 @@ export class EmailLoginFormComponent {
24
24
  this.randomIdService = inject(RandomIdService);
25
25
  this.sneatApiService = inject(SneatApiService);
26
26
  this.userRecordService = inject(UserRecordService);
27
- this.sign = 'up'; // TODO: document here what 'in' & 'up' means
28
- this.email = '';
29
- this.password = '';
30
- this.firstName = '';
31
- this.lastName = '';
32
- this.spaceTitle = '';
33
- this.wrongPassword = false;
27
+ this.sign = signal('up', ...(ngDevMode ? [{ debugName: "sign" }] : [])); // TODO: document here what 'in' & 'up' means
28
+ this.email = signal('', ...(ngDevMode ? [{ debugName: "email" }] : []));
29
+ this.password = signal('', ...(ngDevMode ? [{ debugName: "password" }] : []));
30
+ this.firstName = signal('', ...(ngDevMode ? [{ debugName: "firstName" }] : []));
31
+ this.lastName = signal('', ...(ngDevMode ? [{ debugName: "lastName" }] : []));
32
+ this.spaceTitle = signal('', ...(ngDevMode ? [{ debugName: "spaceTitle" }] : []));
33
+ this.wrongPassword = signal(false, ...(ngDevMode ? [{ debugName: "wrongPassword" }] : []));
34
+ this.signingWith = signal(undefined, ...(ngDevMode ? [{ debugName: "signingWith" }] : []));
34
35
  this.signingWithChange = new EventEmitter();
35
36
  this.loggedIn = new EventEmitter();
37
+ this.emailInput = viewChild('emailInput', ...(ngDevMode ? [{ debugName: "emailInput" }] : []));
38
+ this.spaceTitleInput = viewChild('spaceTitleInput', ...(ngDevMode ? [{ debugName: "spaceTitleInput" }] : []));
36
39
  this.setFocusToInput = createSetFocusToInput(this.errorLogger);
37
- this.email = localStorage.getItem('emailForSignIn') || '';
38
- if (this.email) {
39
- this.sign = 'in';
40
+ const email = localStorage.getItem('emailForSignIn') || '';
41
+ this.email.set(email);
42
+ if (email) {
43
+ this.sign.set('in');
40
44
  }
41
45
  }
42
46
  get validEmail() {
43
- const email = this.email, i = email?.indexOf('@');
47
+ const email = this.email(), i = email?.indexOf('@');
44
48
  return i > 0 && i < email.length - 1;
45
49
  }
46
50
  getFirebaseAuth() {
47
51
  return this.afAuth; // TODO: pending https://github.com/angular/angularfire/pull/3402
48
52
  }
49
53
  async signUp() {
50
- if (!this.firstName) {
54
+ if (!this.firstName()) {
51
55
  // this.toaster.showToast('Full name is required');
52
56
  return;
53
57
  }
54
58
  // this.signingWith = 'email';
55
- this.email = this.email.trim();
56
- const email = this.email;
57
- const firstName = this.firstName.trim();
58
- const lastName = this.lastName.trim();
59
+ const email = this.email().trim();
60
+ this.email.set(email);
61
+ const firstName = this.firstName().trim();
62
+ const lastName = this.lastName().trim();
59
63
  if (!email) {
60
64
  alert('Email is a required field');
61
65
  return;
@@ -68,8 +72,8 @@ export class EmailLoginFormComponent {
68
72
  alert('Last name is a required field');
69
73
  return;
70
74
  }
71
- this.spaceTitle = this.spaceTitle.trim();
72
- const spaceTitle = this.spaceTitle;
75
+ const spaceTitle = this.spaceTitle().trim();
76
+ this.spaceTitle.set(spaceTitle);
73
77
  if (this.appInfo.requiredSpaceType && !spaceTitle) {
74
78
  alert('Company title is a required field');
75
79
  this.setFocusToSpaceTitle();
@@ -117,7 +121,7 @@ export class EmailLoginFormComponent {
117
121
  }
118
122
  }
119
123
  keyupEnter() {
120
- switch (this.sign) {
124
+ switch (this.sign()) {
121
125
  case 'in':
122
126
  this.signIn();
123
127
  break;
@@ -128,31 +132,31 @@ export class EmailLoginFormComponent {
128
132
  }
129
133
  signIn() {
130
134
  this.setSigningWith('email');
131
- this.email = this.email.trim();
132
- this.wrongPassword = false;
135
+ this.email.set(this.email().trim());
136
+ this.wrongPassword.set(false);
133
137
  this.saveEmailForReuse();
134
138
  // const auth = getAuth(getApp());
135
139
  const auth = this.getFirebaseAuth();
136
- signInWithEmailAndPassword(auth, this.email, this.password)
140
+ signInWithEmailAndPassword(auth, this.email(), this.password())
137
141
  .then((userCredential) => {
138
142
  this.onLoggedIn(userCredential); // TODO: add analytics event
139
143
  })
140
144
  .catch(this.errorHandler('Failed to sign in with email & password', 'email'));
141
145
  }
142
146
  saveEmailForReuse() {
143
- localStorage.setItem('emailForSignIn', this.email);
147
+ localStorage.setItem('emailForSignIn', this.email());
144
148
  }
145
149
  sendSignInLink() {
146
150
  this.setSigningWith('emailLink');
147
- this.email = this.email.trim();
151
+ this.email.set(this.email().trim());
148
152
  this.saveEmailForReuse();
149
- sendSignInLinkToEmail(this.afAuth, this.email, {
153
+ sendSignInLinkToEmail(this.afAuth, this.email(), {
150
154
  // url: 'https://dailyscrum.app/pwa/sign-in',
151
155
  url: document.baseURI + 'sign-in-from-email-link',
152
156
  handleCodeInApp: true,
153
157
  })
154
158
  .then(() => {
155
- this.showToast(`Sign-in link has been sent to email: ${this.email}`);
159
+ this.showToast(`Sign-in link has been sent to email: ${this.email()}`);
156
160
  this.setSigningWith(undefined);
157
161
  })
158
162
  .catch(this.errorHandler('Failed to send sign in link to email', 'FailedToSendSignInLinkToEmail'));
@@ -176,10 +180,10 @@ export class EmailLoginFormComponent {
176
180
  }
177
181
  resetPassword() {
178
182
  this.setSigningWith('resetPassword');
179
- sendPasswordResetEmail(this.afAuth, this.email)
183
+ sendPasswordResetEmail(this.afAuth, this.email())
180
184
  .then(() => {
181
185
  this.setSigningWith(undefined);
182
- this.showToast(`Password reset link has been sent to email: ${this.email}`);
186
+ this.showToast(`Password reset link has been sent to email: ${this.email()}`);
183
187
  })
184
188
  .catch(this.errorHandler('Failed to send password reset email', 'FailedToSendPasswordResetEmail'));
185
189
  }
@@ -205,7 +209,7 @@ export class EmailLoginFormComponent {
205
209
  this.analyticsService.logEvent(eventName, eventParams);
206
210
  }
207
211
  if (err.code === 'auth/wrong-password') {
208
- this.wrongPassword = true;
212
+ this.wrongPassword.set(true);
209
213
  return;
210
214
  }
211
215
  this.errorLogger.logError(err, m, {
@@ -213,7 +217,7 @@ export class EmailLoginFormComponent {
213
217
  });
214
218
  }
215
219
  setSigningWith(signingWith) {
216
- this.signingWith = signingWith;
220
+ this.signingWith.set(signingWith);
217
221
  this.signingWithChange.emit(signingWith);
218
222
  }
219
223
  signChanged() {
@@ -229,11 +233,11 @@ export class EmailLoginFormComponent {
229
233
  this.setFocusToInput(undefined /*this.spaceTitleInput*/);
230
234
  }
231
235
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: EmailLoginFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
232
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.0", type: EmailLoginFormComponent, isStandalone: true, selector: "sneat-email-login-form", outputs: { signingWithChange: "signingWithChange", loggedIn: "loggedIn" }, viewQueries: [{ propertyName: "emailInput", first: true, predicate: ["emailInput"], descendants: true, static: true }, { propertyName: "spaceTitleInput", first: true, predicate: ["spaceTitleInput"], descendants: true }], ngImport: i0, template: "<div class=\"ion-padding-horizontal\"></div>\n<ion-card>\n <ion-item-divider color=\"light\" class=\"ion-no-padding\">\n <ion-segment [(ngModel)]=\"sign\" (ionChange)=\"signChanged()\">\n <ion-segment-button value=\"up\">\n <ion-icon name=\"person-add\" class=\"ion-margin-end\"></ion-icon>\n <ion-label>Sign up</ion-label>\n </ion-segment-button>\n <ion-segment-button value=\"in\">\n <ion-icon name=\"enter-outline\" />\n <ion-label>Sign in</ion-label>\n </ion-segment-button>\n </ion-segment>\n </ion-item-divider>\n <!--\t<ion-item-divider color=\"light\">-->\n <!--\t\t<ion-label color=\"medium\" style=\"text-align: center; width: 100%\">-->\n <!--\t\t\tOr login with email-->\n <!--\t\t</ion-label>-->\n <!--\t</ion-item-divider>-->\n <ion-card-content class=\"ion-no-padding\">\n <ion-item>\n <ion-label class=\"ion-margin-end\">\n <ion-icon name=\"mail-outline\" />\n </ion-label>\n <ion-input\n [disabled]=\"!!signingWith\"\n [(ngModel)]=\"email\"\n email\n type=\"email\"\n name=\"email\"\n id=\"email\"\n required\n placeholder=\"my@work-or-personal.email\"\n (keyup.enter)=\"keyupEnter()\"\n />\n </ion-item>\n @switch (sign) {\n @case (\"up\") {\n <ion-item>\n <ion-label class=\"ion-margin-end\">\n <ion-icon name=\"person-add-outline\" />\n </ion-label>\n <ion-input\n name=\"first_name\"\n placeholder=\"First name\"\n [(ngModel)]=\"firstName\"\n type=\"text\"\n required\n (keyup.enter)=\"keyupEnter()\"\n [disabled]=\"!!signingWith\"\n />\n <ion-input\n name=\"last_name\"\n placeholder=\"Last name\"\n [(ngModel)]=\"lastName\"\n type=\"text\"\n required\n (keyup.enter)=\"keyupEnter()\"\n [disabled]=\"!!signingWith\"\n />\n </ion-item>\n @if (appInfo.requiredSpaceType === \"company\") {\n <ion-item>\n <ion-label position=\"stacked\">Company name</ion-label>\n <ion-input\n #teamTitleInput\n placeholder=\"required\"\n required\n [(ngModel)]=\"spaceTitle\"\n />\n </ion-item>\n }\n }\n @case (\"in\") {\n <ion-item>\n <ion-label class=\"ion-margin-end\">\n <ion-icon name=\"key-outline\" />\n </ion-label>\n <ion-input\n [(ngModel)]=\"password\"\n placeholder=\"Password\"\n type=\"password\"\n required\n (keyup.enter)=\"keyupEnter()\"\n [disabled]=\"!!signingWith\"\n />\n <ion-buttons slot=\"end\">\n <ion-button\n color=\"danger\"\n [disabled]=\"!validEmail\"\n (click)=\"resetPassword()\"\n title=\"Send email with a link to reset password \"\n >\n <ion-label>Forgot? Reset!</ion-label>\n </ion-button>\n </ion-buttons>\n </ion-item>\n @if (wrongPassword) {\n <ion-item>\n <ion-label color=\"danger\">Wrong password</ion-label>\n </ion-item>\n }\n }\n }\n </ion-card-content>\n <ion-card-content>\n @switch (sign) {\n @case (\"up\") {\n <ion-button\n [disabled]=\"!!signingWith || !validEmail || (!firstName && !lastName)\"\n (click)=\"signUp()\"\n >\n <ion-icon name=\"enter-outline\" slot=\"start\" />\n @if (signingWith === \"email\") {\n <ion-label>Signing up...</ion-label>\n <ion-spinner\n class=\"ion-margin-start\"\n slot=\"end\"\n name=\"lines-small\"\n />\n } @else {\n <ion-label>Sign up</ion-label>\n }\n </ion-button>\n }\n @case (\"in\") {\n <ion-button\n [disabled]=\"!!signingWith || !validEmail || !password\"\n (click)=\"signIn()\"\n >\n <ion-icon name=\"enter-outline\" slot=\"start\" />\n @if (signingWith === \"email\") {\n <ion-label>Signing in...</ion-label>\n <ion-spinner\n class=\"ion-margin-start\"\n slot=\"end\"\n name=\"lines-small\"\n />\n } @else {\n <ion-label>\n <b>Sign in</b>&nbsp;<ion-text\n color=\"light\"\n style=\"text-transform: none\"\n >with password\n </ion-text>\n </ion-label>\n }\n </ion-button>\n <ion-button disabled=\"disabled\" fill=\"clear\" color=\"medium\">\n or\n </ion-button>\n <ion-button\n size=\"small\"\n [disabled]=\"!validEmail || signingWith\"\n (click)=\"sendSignInLink()\"\n fill=\"outline\"\n color=\"tertiary\"\n >\n <ion-icon name=\"mail-outline\" slot=\"start\" />\n <ion-label>Get sign-in link</ion-label>\n </ion-button>\n }\n }\n </ion-card-content>\n</ion-card>\n", dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1.EmailValidator, selector: "[email][formControlName],[email][formControl],[email][ngModel]", inputs: ["email"] }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { 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: IonSegment, selector: "ion-segment", inputs: ["color", "disabled", "mode", "scrollable", "selectOnFocus", "swipeGesture", "value"] }, { kind: "component", type: IonSegmentButton, selector: "ion-segment-button", inputs: ["contentId", "disabled", "layout", "mode", "type", "value"] }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: IonLabel, selector: "ion-label", inputs: ["color", "mode", "position"] }, { kind: "component", type: IonCardContent, selector: "ion-card-content", inputs: ["mode"] }, { 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: IonInput, selector: "ion-input", inputs: ["accept", "autocapitalize", "autocomplete", "autocorrect", "autofocus", "clearInput", "clearOnEdit", "color", "counter", "counterFormatter", "debounce", "disabled", "enterkeyhint", "errorText", "fill", "helperText", "inputmode", "label", "labelPlacement", "max", "maxlength", "min", "minlength", "mode", "multiple", "name", "pattern", "placeholder", "readonly", "required", "shape", "size", "spellcheck", "step", "type", "value"] }, { kind: "component", type: IonSpinner, selector: "ion-spinner", inputs: ["color", "duration", "name", "paused"] }, { kind: "component", type: IonText, selector: "ion-text", 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"] }] }); }
236
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.0", type: EmailLoginFormComponent, isStandalone: true, selector: "sneat-email-login-form", outputs: { signingWithChange: "signingWithChange", loggedIn: "loggedIn" }, viewQueries: [{ propertyName: "emailInput", first: true, predicate: ["emailInput"], descendants: true, isSignal: true }, { propertyName: "spaceTitleInput", first: true, predicate: ["spaceTitleInput"], descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"ion-padding-horizontal\"></div>\n<ion-card>\n <ion-item-divider color=\"light\" class=\"ion-no-padding\">\n <ion-segment [ngModel]=\"sign()\" (ngModelChange)=\"sign.set($event)\" (ionChange)=\"signChanged()\">\n <ion-segment-button value=\"up\">\n <ion-icon name=\"person-add\" class=\"ion-margin-end\"></ion-icon>\n <ion-label>Sign up</ion-label>\n </ion-segment-button>\n <ion-segment-button value=\"in\">\n <ion-icon name=\"enter-outline\" />\n <ion-label>Sign in</ion-label>\n </ion-segment-button>\n </ion-segment>\n </ion-item-divider>\n <!--\t<ion-item-divider color=\"light\">-->\n <!--\t\t<ion-label color=\"medium\" style=\"text-align: center; width: 100%\">-->\n <!--\t\t\tOr login with email-->\n <!--\t\t</ion-label>-->\n <!--\t</ion-item-divider>-->\n <ion-card-content class=\"ion-no-padding\">\n <ion-item>\n <ion-label class=\"ion-margin-end\">\n <ion-icon name=\"mail-outline\" />\n </ion-label>\n <ion-input\n [disabled]=\"!!signingWith()\"\n [ngModel]=\"email()\" (ngModelChange)=\"email.set($event)\"\n email\n type=\"email\"\n name=\"email\"\n id=\"email\"\n required\n placeholder=\"my@work-or-personal.email\"\n (keyup.enter)=\"keyupEnter()\"\n />\n </ion-item>\n @switch (sign()) {\n @case (\"up\") {\n <ion-item>\n <ion-label class=\"ion-margin-end\">\n <ion-icon name=\"person-add-outline\" />\n </ion-label>\n <ion-input\n name=\"first_name\"\n placeholder=\"First name\"\n [ngModel]=\"firstName()\" (ngModelChange)=\"firstName.set($event)\"\n type=\"text\"\n required\n (keyup.enter)=\"keyupEnter()\"\n [disabled]=\"!!signingWith()\"\n />\n <ion-input\n name=\"last_name\"\n placeholder=\"Last name\"\n [ngModel]=\"lastName()\" (ngModelChange)=\"lastName.set($event)\"\n type=\"text\"\n required\n (keyup.enter)=\"keyupEnter()\"\n [disabled]=\"!!signingWith()\"\n />\n </ion-item>\n @if (appInfo.requiredSpaceType === \"company\") {\n <ion-item>\n <ion-label position=\"stacked\">Company name</ion-label>\n <ion-input\n #teamTitleInput\n placeholder=\"required\"\n required\n [ngModel]=\"spaceTitle()\" (ngModelChange)=\"spaceTitle.set($event)\"\n />\n </ion-item>\n }\n }\n @case (\"in\") {\n <ion-item>\n <ion-label class=\"ion-margin-end\">\n <ion-icon name=\"key-outline\" />\n </ion-label>\n <ion-input\n [ngModel]=\"password()\" (ngModelChange)=\"password.set($event)\"\n placeholder=\"Password\"\n type=\"password\"\n required\n (keyup.enter)=\"keyupEnter()\"\n [disabled]=\"!!signingWith()\"\n />\n <ion-buttons slot=\"end\">\n <ion-button\n color=\"danger\"\n [disabled]=\"!validEmail\"\n (click)=\"resetPassword()\"\n title=\"Send email with a link to reset password \"\n >\n <ion-label>Forgot? Reset!</ion-label>\n </ion-button>\n </ion-buttons>\n </ion-item>\n @if (wrongPassword()) {\n <ion-item>\n <ion-label color=\"danger\">Wrong password</ion-label>\n </ion-item>\n }\n }\n }\n </ion-card-content>\n <ion-card-content>\n @switch (sign()) {\n @case (\"up\") {\n <ion-button\n [disabled]=\"!!signingWith() || !validEmail || (!firstName() && !lastName())\"\n (click)=\"signUp()\"\n >\n <ion-icon name=\"enter-outline\" slot=\"start\" />\n @if (signingWith() === \"email\") {\n <ion-label>Signing up...</ion-label>\n <ion-spinner\n class=\"ion-margin-start\"\n slot=\"end\"\n name=\"lines-small\"\n />\n } @else {\n <ion-label>Sign up</ion-label>\n }\n </ion-button>\n }\n @case (\"in\") {\n <ion-button\n [disabled]=\"!!signingWith() || !validEmail || !password()\"\n (click)=\"signIn()\"\n >\n <ion-icon name=\"enter-outline\" slot=\"start\" />\n @if (signingWith() === \"email\") {\n <ion-label>Signing in...</ion-label>\n <ion-spinner\n class=\"ion-margin-start\"\n slot=\"end\"\n name=\"lines-small\"\n />\n } @else {\n <ion-label>\n <b>Sign in</b>&nbsp;<ion-text\n color=\"light\"\n style=\"text-transform: none\"\n >with password\n </ion-text>\n </ion-label>\n }\n </ion-button>\n <ion-button disabled=\"disabled\" fill=\"clear\" color=\"medium\">\n or\n </ion-button>\n <ion-button\n size=\"small\"\n [disabled]=\"!validEmail || signingWith()\"\n (click)=\"sendSignInLink()\"\n fill=\"outline\"\n color=\"tertiary\"\n >\n <ion-icon name=\"mail-outline\" slot=\"start\" />\n <ion-label>Get sign-in link</ion-label>\n </ion-button>\n }\n }\n </ion-card-content>\n</ion-card>\n", dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1.EmailValidator, selector: "[email][formControlName],[email][formControl],[email][ngModel]", inputs: ["email"] }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { 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: IonSegment, selector: "ion-segment", inputs: ["color", "disabled", "mode", "scrollable", "selectOnFocus", "swipeGesture", "value"] }, { kind: "component", type: IonSegmentButton, selector: "ion-segment-button", inputs: ["contentId", "disabled", "layout", "mode", "type", "value"] }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: IonLabel, selector: "ion-label", inputs: ["color", "mode", "position"] }, { kind: "component", type: IonCardContent, selector: "ion-card-content", inputs: ["mode"] }, { 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: IonInput, selector: "ion-input", inputs: ["accept", "autocapitalize", "autocomplete", "autocorrect", "autofocus", "clearInput", "clearOnEdit", "color", "counter", "counterFormatter", "debounce", "disabled", "enterkeyhint", "errorText", "fill", "helperText", "inputmode", "label", "labelPlacement", "max", "maxlength", "min", "minlength", "mode", "multiple", "name", "pattern", "placeholder", "readonly", "required", "shape", "size", "spellcheck", "step", "type", "value"] }, { kind: "component", type: IonSpinner, selector: "ion-spinner", inputs: ["color", "duration", "name", "paused"] }, { kind: "component", type: IonText, selector: "ion-text", 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"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
233
237
  }
234
238
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: EmailLoginFormComponent, decorators: [{
235
239
  type: Component,
236
- args: [{ selector: 'sneat-email-login-form', imports: [
240
+ args: [{ selector: 'sneat-email-login-form', changeDetection: ChangeDetectionStrategy.OnPush, imports: [
237
241
  FormsModule,
238
242
  IonCard,
239
243
  IonItemDivider,
@@ -248,16 +252,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
248
252
  IonText,
249
253
  IonButton,
250
254
  IonButtons,
251
- ], template: "<div class=\"ion-padding-horizontal\"></div>\n<ion-card>\n <ion-item-divider color=\"light\" class=\"ion-no-padding\">\n <ion-segment [(ngModel)]=\"sign\" (ionChange)=\"signChanged()\">\n <ion-segment-button value=\"up\">\n <ion-icon name=\"person-add\" class=\"ion-margin-end\"></ion-icon>\n <ion-label>Sign up</ion-label>\n </ion-segment-button>\n <ion-segment-button value=\"in\">\n <ion-icon name=\"enter-outline\" />\n <ion-label>Sign in</ion-label>\n </ion-segment-button>\n </ion-segment>\n </ion-item-divider>\n <!--\t<ion-item-divider color=\"light\">-->\n <!--\t\t<ion-label color=\"medium\" style=\"text-align: center; width: 100%\">-->\n <!--\t\t\tOr login with email-->\n <!--\t\t</ion-label>-->\n <!--\t</ion-item-divider>-->\n <ion-card-content class=\"ion-no-padding\">\n <ion-item>\n <ion-label class=\"ion-margin-end\">\n <ion-icon name=\"mail-outline\" />\n </ion-label>\n <ion-input\n [disabled]=\"!!signingWith\"\n [(ngModel)]=\"email\"\n email\n type=\"email\"\n name=\"email\"\n id=\"email\"\n required\n placeholder=\"my@work-or-personal.email\"\n (keyup.enter)=\"keyupEnter()\"\n />\n </ion-item>\n @switch (sign) {\n @case (\"up\") {\n <ion-item>\n <ion-label class=\"ion-margin-end\">\n <ion-icon name=\"person-add-outline\" />\n </ion-label>\n <ion-input\n name=\"first_name\"\n placeholder=\"First name\"\n [(ngModel)]=\"firstName\"\n type=\"text\"\n required\n (keyup.enter)=\"keyupEnter()\"\n [disabled]=\"!!signingWith\"\n />\n <ion-input\n name=\"last_name\"\n placeholder=\"Last name\"\n [(ngModel)]=\"lastName\"\n type=\"text\"\n required\n (keyup.enter)=\"keyupEnter()\"\n [disabled]=\"!!signingWith\"\n />\n </ion-item>\n @if (appInfo.requiredSpaceType === \"company\") {\n <ion-item>\n <ion-label position=\"stacked\">Company name</ion-label>\n <ion-input\n #teamTitleInput\n placeholder=\"required\"\n required\n [(ngModel)]=\"spaceTitle\"\n />\n </ion-item>\n }\n }\n @case (\"in\") {\n <ion-item>\n <ion-label class=\"ion-margin-end\">\n <ion-icon name=\"key-outline\" />\n </ion-label>\n <ion-input\n [(ngModel)]=\"password\"\n placeholder=\"Password\"\n type=\"password\"\n required\n (keyup.enter)=\"keyupEnter()\"\n [disabled]=\"!!signingWith\"\n />\n <ion-buttons slot=\"end\">\n <ion-button\n color=\"danger\"\n [disabled]=\"!validEmail\"\n (click)=\"resetPassword()\"\n title=\"Send email with a link to reset password \"\n >\n <ion-label>Forgot? Reset!</ion-label>\n </ion-button>\n </ion-buttons>\n </ion-item>\n @if (wrongPassword) {\n <ion-item>\n <ion-label color=\"danger\">Wrong password</ion-label>\n </ion-item>\n }\n }\n }\n </ion-card-content>\n <ion-card-content>\n @switch (sign) {\n @case (\"up\") {\n <ion-button\n [disabled]=\"!!signingWith || !validEmail || (!firstName && !lastName)\"\n (click)=\"signUp()\"\n >\n <ion-icon name=\"enter-outline\" slot=\"start\" />\n @if (signingWith === \"email\") {\n <ion-label>Signing up...</ion-label>\n <ion-spinner\n class=\"ion-margin-start\"\n slot=\"end\"\n name=\"lines-small\"\n />\n } @else {\n <ion-label>Sign up</ion-label>\n }\n </ion-button>\n }\n @case (\"in\") {\n <ion-button\n [disabled]=\"!!signingWith || !validEmail || !password\"\n (click)=\"signIn()\"\n >\n <ion-icon name=\"enter-outline\" slot=\"start\" />\n @if (signingWith === \"email\") {\n <ion-label>Signing in...</ion-label>\n <ion-spinner\n class=\"ion-margin-start\"\n slot=\"end\"\n name=\"lines-small\"\n />\n } @else {\n <ion-label>\n <b>Sign in</b>&nbsp;<ion-text\n color=\"light\"\n style=\"text-transform: none\"\n >with password\n </ion-text>\n </ion-label>\n }\n </ion-button>\n <ion-button disabled=\"disabled\" fill=\"clear\" color=\"medium\">\n or\n </ion-button>\n <ion-button\n size=\"small\"\n [disabled]=\"!validEmail || signingWith\"\n (click)=\"sendSignInLink()\"\n fill=\"outline\"\n color=\"tertiary\"\n >\n <ion-icon name=\"mail-outline\" slot=\"start\" />\n <ion-label>Get sign-in link</ion-label>\n </ion-button>\n }\n }\n </ion-card-content>\n</ion-card>\n" }]
255
+ ], template: "<div class=\"ion-padding-horizontal\"></div>\n<ion-card>\n <ion-item-divider color=\"light\" class=\"ion-no-padding\">\n <ion-segment [ngModel]=\"sign()\" (ngModelChange)=\"sign.set($event)\" (ionChange)=\"signChanged()\">\n <ion-segment-button value=\"up\">\n <ion-icon name=\"person-add\" class=\"ion-margin-end\"></ion-icon>\n <ion-label>Sign up</ion-label>\n </ion-segment-button>\n <ion-segment-button value=\"in\">\n <ion-icon name=\"enter-outline\" />\n <ion-label>Sign in</ion-label>\n </ion-segment-button>\n </ion-segment>\n </ion-item-divider>\n <!--\t<ion-item-divider color=\"light\">-->\n <!--\t\t<ion-label color=\"medium\" style=\"text-align: center; width: 100%\">-->\n <!--\t\t\tOr login with email-->\n <!--\t\t</ion-label>-->\n <!--\t</ion-item-divider>-->\n <ion-card-content class=\"ion-no-padding\">\n <ion-item>\n <ion-label class=\"ion-margin-end\">\n <ion-icon name=\"mail-outline\" />\n </ion-label>\n <ion-input\n [disabled]=\"!!signingWith()\"\n [ngModel]=\"email()\" (ngModelChange)=\"email.set($event)\"\n email\n type=\"email\"\n name=\"email\"\n id=\"email\"\n required\n placeholder=\"my@work-or-personal.email\"\n (keyup.enter)=\"keyupEnter()\"\n />\n </ion-item>\n @switch (sign()) {\n @case (\"up\") {\n <ion-item>\n <ion-label class=\"ion-margin-end\">\n <ion-icon name=\"person-add-outline\" />\n </ion-label>\n <ion-input\n name=\"first_name\"\n placeholder=\"First name\"\n [ngModel]=\"firstName()\" (ngModelChange)=\"firstName.set($event)\"\n type=\"text\"\n required\n (keyup.enter)=\"keyupEnter()\"\n [disabled]=\"!!signingWith()\"\n />\n <ion-input\n name=\"last_name\"\n placeholder=\"Last name\"\n [ngModel]=\"lastName()\" (ngModelChange)=\"lastName.set($event)\"\n type=\"text\"\n required\n (keyup.enter)=\"keyupEnter()\"\n [disabled]=\"!!signingWith()\"\n />\n </ion-item>\n @if (appInfo.requiredSpaceType === \"company\") {\n <ion-item>\n <ion-label position=\"stacked\">Company name</ion-label>\n <ion-input\n #teamTitleInput\n placeholder=\"required\"\n required\n [ngModel]=\"spaceTitle()\" (ngModelChange)=\"spaceTitle.set($event)\"\n />\n </ion-item>\n }\n }\n @case (\"in\") {\n <ion-item>\n <ion-label class=\"ion-margin-end\">\n <ion-icon name=\"key-outline\" />\n </ion-label>\n <ion-input\n [ngModel]=\"password()\" (ngModelChange)=\"password.set($event)\"\n placeholder=\"Password\"\n type=\"password\"\n required\n (keyup.enter)=\"keyupEnter()\"\n [disabled]=\"!!signingWith()\"\n />\n <ion-buttons slot=\"end\">\n <ion-button\n color=\"danger\"\n [disabled]=\"!validEmail\"\n (click)=\"resetPassword()\"\n title=\"Send email with a link to reset password \"\n >\n <ion-label>Forgot? Reset!</ion-label>\n </ion-button>\n </ion-buttons>\n </ion-item>\n @if (wrongPassword()) {\n <ion-item>\n <ion-label color=\"danger\">Wrong password</ion-label>\n </ion-item>\n }\n }\n }\n </ion-card-content>\n <ion-card-content>\n @switch (sign()) {\n @case (\"up\") {\n <ion-button\n [disabled]=\"!!signingWith() || !validEmail || (!firstName() && !lastName())\"\n (click)=\"signUp()\"\n >\n <ion-icon name=\"enter-outline\" slot=\"start\" />\n @if (signingWith() === \"email\") {\n <ion-label>Signing up...</ion-label>\n <ion-spinner\n class=\"ion-margin-start\"\n slot=\"end\"\n name=\"lines-small\"\n />\n } @else {\n <ion-label>Sign up</ion-label>\n }\n </ion-button>\n }\n @case (\"in\") {\n <ion-button\n [disabled]=\"!!signingWith() || !validEmail || !password()\"\n (click)=\"signIn()\"\n >\n <ion-icon name=\"enter-outline\" slot=\"start\" />\n @if (signingWith() === \"email\") {\n <ion-label>Signing in...</ion-label>\n <ion-spinner\n class=\"ion-margin-start\"\n slot=\"end\"\n name=\"lines-small\"\n />\n } @else {\n <ion-label>\n <b>Sign in</b>&nbsp;<ion-text\n color=\"light\"\n style=\"text-transform: none\"\n >with password\n </ion-text>\n </ion-label>\n }\n </ion-button>\n <ion-button disabled=\"disabled\" fill=\"clear\" color=\"medium\">\n or\n </ion-button>\n <ion-button\n size=\"small\"\n [disabled]=\"!validEmail || signingWith()\"\n (click)=\"sendSignInLink()\"\n fill=\"outline\"\n color=\"tertiary\"\n >\n <ion-icon name=\"mail-outline\" slot=\"start\" />\n <ion-label>Get sign-in link</ion-label>\n </ion-button>\n }\n }\n </ion-card-content>\n</ion-card>\n" }]
252
256
  }], ctorParameters: () => [], propDecorators: { signingWithChange: [{
253
257
  type: Output
254
258
  }], loggedIn: [{
255
259
  type: Output
256
- }], emailInput: [{
257
- type: ViewChild,
258
- args: ['emailInput', { static: true }]
259
- }], spaceTitleInput: [{
260
- type: ViewChild,
261
- args: ['spaceTitleInput', { static: false }]
262
- }] } });
260
+ }], emailInput: [{ type: i0.ViewChild, args: ['emailInput', { isSignal: true }] }], spaceTitleInput: [{ type: i0.ViewChild, args: ['spaceTitleInput', { isSignal: true }] }] } });
263
261
  //# sourceMappingURL=email-login-form.component.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"email-login-form.component.js","sourceRoot":"","sources":["../../../../../../../../../libs/auth/ui/src/lib/pages/login-page/email-login-form/email-login-form.component.ts","../../../../../../../../../libs/auth/ui/src/lib/pages/login-page/email-login-form/email-login-form.component.html"],"names":[],"mappings":"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","sourcesContent":["import {\n Component,\n EventEmitter,\n Output,\n ViewChild,\n inject,\n} from '@angular/core';\n// import { getApp } from '@angular/fire/app';\n// import { getAuth } from '@angular/fire/auth';\nimport {\n Auth,\n sendPasswordResetEmail,\n sendSignInLinkToEmail,\n} from '@angular/fire/auth';\nimport { FormsModule } from '@angular/forms';\nimport {\n ToastController,\n IonButton,\n IonButtons,\n IonCard,\n IonCardContent,\n IonIcon,\n IonInput,\n IonItem,\n IonItemDivider,\n IonLabel,\n IonSegment,\n IonSegmentButton,\n IonSpinner,\n IonText,\n} from '@ionic/angular/standalone';\nimport { SneatApiService } from '@sneat/api';\nimport { IInitUserRecordRequest, UserRecordService } from '@sneat/auth-core';\nimport { createSetFocusToInput } from '@sneat/ui';\nimport {\n AnalyticsService,\n APP_INFO,\n IAnalyticsService,\n IAppInfo,\n} from '@sneat/core';\nimport { ErrorLogger, IErrorLogger } from '@sneat/core';\nimport { RandomIdService } from '@sneat/random';\nimport { UserCredential, sendEmailVerification } from 'firebase/auth';\nimport { FirebaseError } from 'firebase/app';\n\nexport type EmailFormSigningWith = 'email' | 'emailLink' | 'resetPassword';\nimport {\n createUserWithEmailAndPassword,\n signInWithEmailAndPassword,\n} from 'firebase/auth';\n\n@Component({\n selector: 'sneat-email-login-form',\n templateUrl: 'email-login-form.component.html',\n imports: [\n FormsModule,\n IonCard,\n IonItemDivider,\n IonSegment,\n IonSegmentButton,\n IonIcon,\n IonLabel,\n IonCardContent,\n IonItem,\n IonInput,\n IonSpinner,\n IonText,\n IonButton,\n IonButtons,\n ],\n})\nexport class EmailLoginFormComponent {\n readonly appInfo = inject<IAppInfo>(APP_INFO);\n private readonly analyticsService =\n inject<IAnalyticsService>(AnalyticsService);\n private readonly errorLogger = inject<IErrorLogger>(ErrorLogger);\n private readonly toastController = inject(ToastController);\n private readonly afAuth = inject(Auth);\n private readonly randomIdService = inject(RandomIdService);\n private readonly sneatApiService = inject(SneatApiService);\n private readonly userRecordService = inject(UserRecordService);\n\n protected sign: 'in' | 'up' = 'up'; // TODO: document here what 'in' & 'up' means\n protected email = '';\n protected password = '';\n protected firstName = '';\n protected lastName = '';\n protected spaceTitle = '';\n protected wrongPassword = false;\n\n protected signingWith?: EmailFormSigningWith;\n\n @Output() readonly signingWithChange = new EventEmitter<\n EmailFormSigningWith | undefined\n >();\n @Output() readonly loggedIn = new EventEmitter<UserCredential>();\n\n @ViewChild('emailInput', { static: true }) emailInput?: IonInput;\n @ViewChild('spaceTitleInput', { static: false }) spaceTitleInput?: IonInput;\n\n public readonly setFocusToInput = createSetFocusToInput(this.errorLogger);\n\n constructor() {\n this.email = localStorage.getItem('emailForSignIn') || '';\n if (this.email) {\n this.sign = 'in';\n }\n }\n\n public get validEmail(): boolean {\n const email = this.email,\n i = email?.indexOf('@');\n return i > 0 && i < email.length - 1;\n }\n\n public getFirebaseAuth(): Auth {\n return this.afAuth as unknown as Auth; // TODO: pending https://github.com/angular/angularfire/pull/3402\n }\n\n public async signUp(): Promise<void> {\n if (!this.firstName) {\n // this.toaster.showToast('Full name is required');\n return;\n }\n // this.signingWith = 'email';\n this.email = this.email.trim();\n const email = this.email;\n const firstName = this.firstName.trim();\n const lastName = this.lastName.trim();\n if (!email) {\n alert('Email is a required field');\n return;\n }\n if (!firstName) {\n alert('First name is a required field');\n return;\n }\n if (!lastName) {\n alert('Last name is a required field');\n return;\n }\n this.spaceTitle = this.spaceTitle.trim();\n const spaceTitle = this.spaceTitle;\n if (this.appInfo.requiredSpaceType && !spaceTitle) {\n alert('Company title is a required field');\n this.setFocusToSpaceTitle();\n return;\n }\n localStorage.setItem('emailForSignIn', email);\n const password = this.randomIdService.newRandomId({ len: 9 });\n\n this.setSigningWith('email');\n try {\n // const auth = getAuth(getApp());\n const auth = this.getFirebaseAuth();\n const userCredential = await createUserWithEmailAndPassword(\n auth,\n email,\n password,\n );\n this.sendVerificationEmail(userCredential);\n userCredential.user\n ?.getIdToken()\n .then((token) => {\n this.sneatApiService.setApiAuthToken(token);\n const request: IInitUserRecordRequest = {\n authProvider: 'password',\n email,\n ianaTimezone: Intl.DateTimeFormat().resolvedOptions().timeZone,\n names: { firstName, lastName },\n space: this.appInfo.requiredSpaceType\n ? {\n type: this.appInfo.requiredSpaceType,\n title: spaceTitle,\n }\n : undefined,\n };\n this.userRecordService.initUserRecord(request).subscribe({\n next: () => this.onLoggedIn(userCredential),\n error: (err) => {\n this.analyticsService.logEvent('FailedToSetUserTitle');\n this.errorLogger.logError(err, 'Failed to set user title', {\n feedback: false,\n });\n this.onLoggedIn(userCredential);\n },\n });\n })\n .catch(\n this.errorHandler(\n 'Failed to get Firebase ID token',\n 'FirebaseGetIdTokenFailed',\n ),\n );\n } catch (e) {\n this.handleError(\n e,\n 'Failed to sign up with email',\n 'FailedToSignUpWithEmail',\n );\n }\n }\n\n public keyupEnter(): void {\n switch (this.sign) {\n case 'in':\n this.signIn();\n break;\n case 'up':\n this.signUp().catch(() => this.errorHandler('Failed to sign up'));\n break;\n }\n }\n\n public signIn(): void {\n this.setSigningWith('email');\n this.email = this.email.trim();\n this.wrongPassword = false;\n this.saveEmailForReuse();\n // const auth = getAuth(getApp());\n const auth = this.getFirebaseAuth();\n signInWithEmailAndPassword(auth, this.email, this.password)\n .then((userCredential) => {\n this.onLoggedIn(userCredential); // TODO: add analytics event\n })\n .catch(\n this.errorHandler('Failed to sign in with email & password', 'email'),\n );\n }\n\n private saveEmailForReuse(): void {\n localStorage.setItem('emailForSignIn', this.email);\n }\n\n public sendSignInLink(): void {\n this.setSigningWith('emailLink');\n this.email = this.email.trim();\n this.saveEmailForReuse();\n sendSignInLinkToEmail(this.afAuth, this.email, {\n // url: 'https://dailyscrum.app/pwa/sign-in',\n url: document.baseURI + 'sign-in-from-email-link',\n handleCodeInApp: true,\n })\n .then(() => {\n this.showToast(`Sign-in link has been sent to email: ${this.email}`);\n this.setSigningWith(undefined);\n })\n .catch(\n this.errorHandler(\n 'Failed to send sign in link to email',\n 'FailedToSendSignInLinkToEmail',\n ),\n );\n }\n\n private showToast(message: string): void {\n this.toastController\n .create({\n message,\n position: 'middle',\n keyboardClose: true,\n duration: 3000,\n color: 'tertiary',\n icon: 'send-outline',\n buttons: [{ icon: 'close', role: 'cancel' }],\n })\n .then((toast) => {\n toast\n .present()\n .catch(\n this.errorLogger.logErrorHandler(\n 'Failed to present toast about password reset email sent success',\n ),\n );\n });\n }\n\n public resetPassword(): void {\n this.setSigningWith('resetPassword');\n sendPasswordResetEmail(this.afAuth, this.email)\n .then(() => {\n this.setSigningWith(undefined);\n this.showToast(\n `Password reset link has been sent to email: ${this.email}`,\n );\n })\n .catch(\n this.errorHandler(\n 'Failed to send password reset email',\n 'FailedToSendPasswordResetEmail',\n ),\n );\n }\n\n private sendVerificationEmail(userCredential: UserCredential): void {\n setTimeout(async () => {\n try {\n await sendEmailVerification(userCredential.user);\n } catch (e) {\n this.handleError(e, 'Failed to send verification email');\n }\n });\n }\n\n private onLoggedIn(userCredential: UserCredential): void {\n this.loggedIn.emit(userCredential);\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 this.setSigningWith(undefined);\n if (eventName) {\n this.analyticsService.logEvent(eventName, eventParams);\n }\n if ((err as FirebaseError).code === 'auth/wrong-password') {\n this.wrongPassword = true;\n return;\n }\n this.errorLogger.logError(err, m, {\n report: !(err as { code: unknown }).code,\n });\n }\n\n private setSigningWith(signingWith?: EmailFormSigningWith): void {\n this.signingWith = signingWith;\n this.signingWithChange.emit(signingWith);\n }\n\n signChanged(): void {\n this.setFocusToEmail();\n }\n\n ionViewDidEnter(): void {\n this.setFocusToEmail();\n }\n\n private setFocusToEmail(): void {\n this.setFocusToInput(undefined /*this.emailInput*/);\n }\n\n private setFocusToSpaceTitle(): void {\n this.setFocusToInput(undefined /*this.spaceTitleInput*/);\n }\n}\n","<div class=\"ion-padding-horizontal\"></div>\n<ion-card>\n <ion-item-divider color=\"light\" class=\"ion-no-padding\">\n <ion-segment [(ngModel)]=\"sign\" (ionChange)=\"signChanged()\">\n <ion-segment-button value=\"up\">\n <ion-icon name=\"person-add\" class=\"ion-margin-end\"></ion-icon>\n <ion-label>Sign up</ion-label>\n </ion-segment-button>\n <ion-segment-button value=\"in\">\n <ion-icon name=\"enter-outline\" />\n <ion-label>Sign in</ion-label>\n </ion-segment-button>\n </ion-segment>\n </ion-item-divider>\n <!--\t<ion-item-divider color=\"light\">-->\n <!--\t\t<ion-label color=\"medium\" style=\"text-align: center; width: 100%\">-->\n <!--\t\t\tOr login with email-->\n <!--\t\t</ion-label>-->\n <!--\t</ion-item-divider>-->\n <ion-card-content class=\"ion-no-padding\">\n <ion-item>\n <ion-label class=\"ion-margin-end\">\n <ion-icon name=\"mail-outline\" />\n </ion-label>\n <ion-input\n [disabled]=\"!!signingWith\"\n [(ngModel)]=\"email\"\n email\n type=\"email\"\n name=\"email\"\n id=\"email\"\n required\n placeholder=\"my@work-or-personal.email\"\n (keyup.enter)=\"keyupEnter()\"\n />\n </ion-item>\n @switch (sign) {\n @case (\"up\") {\n <ion-item>\n <ion-label class=\"ion-margin-end\">\n <ion-icon name=\"person-add-outline\" />\n </ion-label>\n <ion-input\n name=\"first_name\"\n placeholder=\"First name\"\n [(ngModel)]=\"firstName\"\n type=\"text\"\n required\n (keyup.enter)=\"keyupEnter()\"\n [disabled]=\"!!signingWith\"\n />\n <ion-input\n name=\"last_name\"\n placeholder=\"Last name\"\n [(ngModel)]=\"lastName\"\n type=\"text\"\n required\n (keyup.enter)=\"keyupEnter()\"\n [disabled]=\"!!signingWith\"\n />\n </ion-item>\n @if (appInfo.requiredSpaceType === \"company\") {\n <ion-item>\n <ion-label position=\"stacked\">Company name</ion-label>\n <ion-input\n #teamTitleInput\n placeholder=\"required\"\n required\n [(ngModel)]=\"spaceTitle\"\n />\n </ion-item>\n }\n }\n @case (\"in\") {\n <ion-item>\n <ion-label class=\"ion-margin-end\">\n <ion-icon name=\"key-outline\" />\n </ion-label>\n <ion-input\n [(ngModel)]=\"password\"\n placeholder=\"Password\"\n type=\"password\"\n required\n (keyup.enter)=\"keyupEnter()\"\n [disabled]=\"!!signingWith\"\n />\n <ion-buttons slot=\"end\">\n <ion-button\n color=\"danger\"\n [disabled]=\"!validEmail\"\n (click)=\"resetPassword()\"\n title=\"Send email with a link to reset password \"\n >\n <ion-label>Forgot? Reset!</ion-label>\n </ion-button>\n </ion-buttons>\n </ion-item>\n @if (wrongPassword) {\n <ion-item>\n <ion-label color=\"danger\">Wrong password</ion-label>\n </ion-item>\n }\n }\n }\n </ion-card-content>\n <ion-card-content>\n @switch (sign) {\n @case (\"up\") {\n <ion-button\n [disabled]=\"!!signingWith || !validEmail || (!firstName && !lastName)\"\n (click)=\"signUp()\"\n >\n <ion-icon name=\"enter-outline\" slot=\"start\" />\n @if (signingWith === \"email\") {\n <ion-label>Signing up...</ion-label>\n <ion-spinner\n class=\"ion-margin-start\"\n slot=\"end\"\n name=\"lines-small\"\n />\n } @else {\n <ion-label>Sign up</ion-label>\n }\n </ion-button>\n }\n @case (\"in\") {\n <ion-button\n [disabled]=\"!!signingWith || !validEmail || !password\"\n (click)=\"signIn()\"\n >\n <ion-icon name=\"enter-outline\" slot=\"start\" />\n @if (signingWith === \"email\") {\n <ion-label>Signing in...</ion-label>\n <ion-spinner\n class=\"ion-margin-start\"\n slot=\"end\"\n name=\"lines-small\"\n />\n } @else {\n <ion-label>\n <b>Sign in</b>&nbsp;<ion-text\n color=\"light\"\n style=\"text-transform: none\"\n >with password\n </ion-text>\n </ion-label>\n }\n </ion-button>\n <ion-button disabled=\"disabled\" fill=\"clear\" color=\"medium\">\n or\n </ion-button>\n <ion-button\n size=\"small\"\n [disabled]=\"!validEmail || signingWith\"\n (click)=\"sendSignInLink()\"\n fill=\"outline\"\n color=\"tertiary\"\n >\n <ion-icon name=\"mail-outline\" slot=\"start\" />\n <ion-label>Get sign-in link</ion-label>\n </ion-button>\n }\n }\n </ion-card-content>\n</ion-card>\n"]}
1
+ {"version":3,"file":"email-login-form.component.js","sourceRoot":"","sources":["../../../../../../../../../libs/auth/ui/src/lib/pages/login-page/email-login-form/email-login-form.component.ts","../../../../../../../../../libs/auth/ui/src/lib/pages/login-page/email-login-form/email-login-form.component.html"],"names":[],"mappings":"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","sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n EventEmitter,\n Output,\n inject,\n signal,\n viewChild,\n} from '@angular/core';\n// import { getApp } from '@angular/fire/app';\n// import { getAuth } from '@angular/fire/auth';\nimport {\n Auth,\n sendPasswordResetEmail,\n sendSignInLinkToEmail,\n} from '@angular/fire/auth';\nimport { FormsModule } from '@angular/forms';\nimport {\n ToastController,\n IonButton,\n IonButtons,\n IonCard,\n IonCardContent,\n IonIcon,\n IonInput,\n IonItem,\n IonItemDivider,\n IonLabel,\n IonSegment,\n IonSegmentButton,\n IonSpinner,\n IonText,\n} from '@ionic/angular/standalone';\nimport { SneatApiService } from '@sneat/api';\nimport { IInitUserRecordRequest, UserRecordService } from '@sneat/auth-core';\nimport { createSetFocusToInput } from '@sneat/ui';\nimport {\n AnalyticsService,\n APP_INFO,\n IAnalyticsService,\n IAppInfo,\n} from '@sneat/core';\nimport { ErrorLogger, IErrorLogger } from '@sneat/core';\nimport { RandomIdService } from '@sneat/random';\nimport { UserCredential, sendEmailVerification } from 'firebase/auth';\nimport { FirebaseError } from 'firebase/app';\n\nexport type EmailFormSigningWith = 'email' | 'emailLink' | 'resetPassword';\nimport {\n createUserWithEmailAndPassword,\n signInWithEmailAndPassword,\n} from 'firebase/auth';\n\n@Component({\n selector: 'sneat-email-login-form',\n templateUrl: 'email-login-form.component.html',\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [\n FormsModule,\n IonCard,\n IonItemDivider,\n IonSegment,\n IonSegmentButton,\n IonIcon,\n IonLabel,\n IonCardContent,\n IonItem,\n IonInput,\n IonSpinner,\n IonText,\n IonButton,\n IonButtons,\n ],\n})\nexport class EmailLoginFormComponent {\n readonly appInfo = inject<IAppInfo>(APP_INFO);\n private readonly analyticsService =\n inject<IAnalyticsService>(AnalyticsService);\n private readonly errorLogger = inject<IErrorLogger>(ErrorLogger);\n private readonly toastController = inject(ToastController);\n private readonly afAuth = inject(Auth);\n private readonly randomIdService = inject(RandomIdService);\n private readonly sneatApiService = inject(SneatApiService);\n private readonly userRecordService = inject(UserRecordService);\n\n protected readonly sign = signal<'in' | 'up'>('up'); // TODO: document here what 'in' & 'up' means\n protected readonly email = signal('');\n protected readonly password = signal('');\n protected readonly firstName = signal('');\n protected readonly lastName = signal('');\n protected readonly spaceTitle = signal('');\n protected readonly wrongPassword = signal(false);\n\n protected readonly signingWith = signal<EmailFormSigningWith | undefined>(\n undefined,\n );\n\n @Output() readonly signingWithChange = new EventEmitter<\n EmailFormSigningWith | undefined\n >();\n @Output() readonly loggedIn = new EventEmitter<UserCredential>();\n\n protected readonly emailInput = viewChild<IonInput>('emailInput');\n protected readonly spaceTitleInput = viewChild<IonInput>('spaceTitleInput');\n\n public readonly setFocusToInput = createSetFocusToInput(this.errorLogger);\n\n constructor() {\n const email = localStorage.getItem('emailForSignIn') || '';\n this.email.set(email);\n if (email) {\n this.sign.set('in');\n }\n }\n\n public get validEmail(): boolean {\n const email = this.email(),\n i = email?.indexOf('@');\n return i > 0 && i < email.length - 1;\n }\n\n public getFirebaseAuth(): Auth {\n return this.afAuth as unknown as Auth; // TODO: pending https://github.com/angular/angularfire/pull/3402\n }\n\n public async signUp(): Promise<void> {\n if (!this.firstName()) {\n // this.toaster.showToast('Full name is required');\n return;\n }\n // this.signingWith = 'email';\n const email = this.email().trim();\n this.email.set(email);\n const firstName = this.firstName().trim();\n const lastName = this.lastName().trim();\n if (!email) {\n alert('Email is a required field');\n return;\n }\n if (!firstName) {\n alert('First name is a required field');\n return;\n }\n if (!lastName) {\n alert('Last name is a required field');\n return;\n }\n const spaceTitle = this.spaceTitle().trim();\n this.spaceTitle.set(spaceTitle);\n if (this.appInfo.requiredSpaceType && !spaceTitle) {\n alert('Company title is a required field');\n this.setFocusToSpaceTitle();\n return;\n }\n localStorage.setItem('emailForSignIn', email);\n const password = this.randomIdService.newRandomId({ len: 9 });\n\n this.setSigningWith('email');\n try {\n // const auth = getAuth(getApp());\n const auth = this.getFirebaseAuth();\n const userCredential = await createUserWithEmailAndPassword(\n auth,\n email,\n password,\n );\n this.sendVerificationEmail(userCredential);\n userCredential.user\n ?.getIdToken()\n .then((token) => {\n this.sneatApiService.setApiAuthToken(token);\n const request: IInitUserRecordRequest = {\n authProvider: 'password',\n email,\n ianaTimezone: Intl.DateTimeFormat().resolvedOptions().timeZone,\n names: { firstName, lastName },\n space: this.appInfo.requiredSpaceType\n ? {\n type: this.appInfo.requiredSpaceType,\n title: spaceTitle,\n }\n : undefined,\n };\n this.userRecordService.initUserRecord(request).subscribe({\n next: () => this.onLoggedIn(userCredential),\n error: (err) => {\n this.analyticsService.logEvent('FailedToSetUserTitle');\n this.errorLogger.logError(err, 'Failed to set user title', {\n feedback: false,\n });\n this.onLoggedIn(userCredential);\n },\n });\n })\n .catch(\n this.errorHandler(\n 'Failed to get Firebase ID token',\n 'FirebaseGetIdTokenFailed',\n ),\n );\n } catch (e) {\n this.handleError(\n e,\n 'Failed to sign up with email',\n 'FailedToSignUpWithEmail',\n );\n }\n }\n\n public keyupEnter(): void {\n switch (this.sign()) {\n case 'in':\n this.signIn();\n break;\n case 'up':\n this.signUp().catch(() => this.errorHandler('Failed to sign up'));\n break;\n }\n }\n\n public signIn(): void {\n this.setSigningWith('email');\n this.email.set(this.email().trim());\n this.wrongPassword.set(false);\n this.saveEmailForReuse();\n // const auth = getAuth(getApp());\n const auth = this.getFirebaseAuth();\n signInWithEmailAndPassword(auth, this.email(), this.password())\n .then((userCredential) => {\n this.onLoggedIn(userCredential); // TODO: add analytics event\n })\n .catch(\n this.errorHandler('Failed to sign in with email & password', 'email'),\n );\n }\n\n private saveEmailForReuse(): void {\n localStorage.setItem('emailForSignIn', this.email());\n }\n\n public sendSignInLink(): void {\n this.setSigningWith('emailLink');\n this.email.set(this.email().trim());\n this.saveEmailForReuse();\n sendSignInLinkToEmail(this.afAuth, this.email(), {\n // url: 'https://dailyscrum.app/pwa/sign-in',\n url: document.baseURI + 'sign-in-from-email-link',\n handleCodeInApp: true,\n })\n .then(() => {\n this.showToast(`Sign-in link has been sent to email: ${this.email()}`);\n this.setSigningWith(undefined);\n })\n .catch(\n this.errorHandler(\n 'Failed to send sign in link to email',\n 'FailedToSendSignInLinkToEmail',\n ),\n );\n }\n\n private showToast(message: string): void {\n this.toastController\n .create({\n message,\n position: 'middle',\n keyboardClose: true,\n duration: 3000,\n color: 'tertiary',\n icon: 'send-outline',\n buttons: [{ icon: 'close', role: 'cancel' }],\n })\n .then((toast) => {\n toast\n .present()\n .catch(\n this.errorLogger.logErrorHandler(\n 'Failed to present toast about password reset email sent success',\n ),\n );\n });\n }\n\n public resetPassword(): void {\n this.setSigningWith('resetPassword');\n sendPasswordResetEmail(this.afAuth, this.email())\n .then(() => {\n this.setSigningWith(undefined);\n this.showToast(\n `Password reset link has been sent to email: ${this.email()}`,\n );\n })\n .catch(\n this.errorHandler(\n 'Failed to send password reset email',\n 'FailedToSendPasswordResetEmail',\n ),\n );\n }\n\n private sendVerificationEmail(userCredential: UserCredential): void {\n setTimeout(async () => {\n try {\n await sendEmailVerification(userCredential.user);\n } catch (e) {\n this.handleError(e, 'Failed to send verification email');\n }\n });\n }\n\n private onLoggedIn(userCredential: UserCredential): void {\n this.loggedIn.emit(userCredential);\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 this.setSigningWith(undefined);\n if (eventName) {\n this.analyticsService.logEvent(eventName, eventParams);\n }\n if ((err as FirebaseError).code === 'auth/wrong-password') {\n this.wrongPassword.set(true);\n return;\n }\n this.errorLogger.logError(err, m, {\n report: !(err as { code: unknown }).code,\n });\n }\n\n private setSigningWith(signingWith?: EmailFormSigningWith): void {\n this.signingWith.set(signingWith);\n this.signingWithChange.emit(signingWith);\n }\n\n signChanged(): void {\n this.setFocusToEmail();\n }\n\n ionViewDidEnter(): void {\n this.setFocusToEmail();\n }\n\n private setFocusToEmail(): void {\n this.setFocusToInput(undefined /*this.emailInput*/);\n }\n\n private setFocusToSpaceTitle(): void {\n this.setFocusToInput(undefined /*this.spaceTitleInput*/);\n }\n}\n","<div class=\"ion-padding-horizontal\"></div>\n<ion-card>\n <ion-item-divider color=\"light\" class=\"ion-no-padding\">\n <ion-segment [ngModel]=\"sign()\" (ngModelChange)=\"sign.set($event)\" (ionChange)=\"signChanged()\">\n <ion-segment-button value=\"up\">\n <ion-icon name=\"person-add\" class=\"ion-margin-end\"></ion-icon>\n <ion-label>Sign up</ion-label>\n </ion-segment-button>\n <ion-segment-button value=\"in\">\n <ion-icon name=\"enter-outline\" />\n <ion-label>Sign in</ion-label>\n </ion-segment-button>\n </ion-segment>\n </ion-item-divider>\n <!--\t<ion-item-divider color=\"light\">-->\n <!--\t\t<ion-label color=\"medium\" style=\"text-align: center; width: 100%\">-->\n <!--\t\t\tOr login with email-->\n <!--\t\t</ion-label>-->\n <!--\t</ion-item-divider>-->\n <ion-card-content class=\"ion-no-padding\">\n <ion-item>\n <ion-label class=\"ion-margin-end\">\n <ion-icon name=\"mail-outline\" />\n </ion-label>\n <ion-input\n [disabled]=\"!!signingWith()\"\n [ngModel]=\"email()\" (ngModelChange)=\"email.set($event)\"\n email\n type=\"email\"\n name=\"email\"\n id=\"email\"\n required\n placeholder=\"my@work-or-personal.email\"\n (keyup.enter)=\"keyupEnter()\"\n />\n </ion-item>\n @switch (sign()) {\n @case (\"up\") {\n <ion-item>\n <ion-label class=\"ion-margin-end\">\n <ion-icon name=\"person-add-outline\" />\n </ion-label>\n <ion-input\n name=\"first_name\"\n placeholder=\"First name\"\n [ngModel]=\"firstName()\" (ngModelChange)=\"firstName.set($event)\"\n type=\"text\"\n required\n (keyup.enter)=\"keyupEnter()\"\n [disabled]=\"!!signingWith()\"\n />\n <ion-input\n name=\"last_name\"\n placeholder=\"Last name\"\n [ngModel]=\"lastName()\" (ngModelChange)=\"lastName.set($event)\"\n type=\"text\"\n required\n (keyup.enter)=\"keyupEnter()\"\n [disabled]=\"!!signingWith()\"\n />\n </ion-item>\n @if (appInfo.requiredSpaceType === \"company\") {\n <ion-item>\n <ion-label position=\"stacked\">Company name</ion-label>\n <ion-input\n #teamTitleInput\n placeholder=\"required\"\n required\n [ngModel]=\"spaceTitle()\" (ngModelChange)=\"spaceTitle.set($event)\"\n />\n </ion-item>\n }\n }\n @case (\"in\") {\n <ion-item>\n <ion-label class=\"ion-margin-end\">\n <ion-icon name=\"key-outline\" />\n </ion-label>\n <ion-input\n [ngModel]=\"password()\" (ngModelChange)=\"password.set($event)\"\n placeholder=\"Password\"\n type=\"password\"\n required\n (keyup.enter)=\"keyupEnter()\"\n [disabled]=\"!!signingWith()\"\n />\n <ion-buttons slot=\"end\">\n <ion-button\n color=\"danger\"\n [disabled]=\"!validEmail\"\n (click)=\"resetPassword()\"\n title=\"Send email with a link to reset password \"\n >\n <ion-label>Forgot? Reset!</ion-label>\n </ion-button>\n </ion-buttons>\n </ion-item>\n @if (wrongPassword()) {\n <ion-item>\n <ion-label color=\"danger\">Wrong password</ion-label>\n </ion-item>\n }\n }\n }\n </ion-card-content>\n <ion-card-content>\n @switch (sign()) {\n @case (\"up\") {\n <ion-button\n [disabled]=\"!!signingWith() || !validEmail || (!firstName() && !lastName())\"\n (click)=\"signUp()\"\n >\n <ion-icon name=\"enter-outline\" slot=\"start\" />\n @if (signingWith() === \"email\") {\n <ion-label>Signing up...</ion-label>\n <ion-spinner\n class=\"ion-margin-start\"\n slot=\"end\"\n name=\"lines-small\"\n />\n } @else {\n <ion-label>Sign up</ion-label>\n }\n </ion-button>\n }\n @case (\"in\") {\n <ion-button\n [disabled]=\"!!signingWith() || !validEmail || !password()\"\n (click)=\"signIn()\"\n >\n <ion-icon name=\"enter-outline\" slot=\"start\" />\n @if (signingWith() === \"email\") {\n <ion-label>Signing in...</ion-label>\n <ion-spinner\n class=\"ion-margin-start\"\n slot=\"end\"\n name=\"lines-small\"\n />\n } @else {\n <ion-label>\n <b>Sign in</b>&nbsp;<ion-text\n color=\"light\"\n style=\"text-transform: none\"\n >with password\n </ion-text>\n </ion-label>\n }\n </ion-button>\n <ion-button disabled=\"disabled\" fill=\"clear\" color=\"medium\">\n or\n </ion-button>\n <ion-button\n size=\"small\"\n [disabled]=\"!validEmail || signingWith()\"\n (click)=\"sendSignInLink()\"\n fill=\"outline\"\n color=\"tertiary\"\n >\n <ion-icon name=\"mail-outline\" slot=\"start\" />\n <ion-label>Get sign-in link</ion-label>\n </ion-button>\n }\n }\n </ion-card-content>\n</ion-card>\n"]}