@sneat/auth-ui 0.6.1 → 0.7.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.
- package/esm2022/lib/components/user-auth-providers/user-auth-accounts.component.js +5 -4
- package/esm2022/lib/components/user-auth-providers/user-auth-accounts.component.js.map +1 -1
- package/esm2022/lib/pages/login-page/email-login-form/email-login-form.component.js +39 -41
- package/esm2022/lib/pages/login-page/email-login-form/email-login-form.component.js.map +1 -1
- package/esm2022/lib/pages/sign-in-from-email-link/sign-in-from-email-link-page.component.js +15 -13
- package/esm2022/lib/pages/sign-in-from-email-link/sign-in-from-email-link-page.component.js.map +1 -1
- package/lib/components/user-auth-providers/user-auth-accounts.component.d.ts +1 -1
- package/lib/pages/login-page/email-login-form/email-login-form.component.d.ts +10 -10
- package/lib/pages/sign-in-from-email-link/sign-in-from-email-link-page.component.d.ts +3 -3
- package/package.json +1 -1
- package/tsconfig.lib.prod.tsbuildinfo +1 -1
|
@@ -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
|
|
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
|
|
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":"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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 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,
|
|
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
|
-
|
|
38
|
-
|
|
39
|
-
|
|
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
|
-
|
|
56
|
-
|
|
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
|
-
|
|
72
|
-
|
|
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
|
|
132
|
-
this.wrongPassword
|
|
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
|
|
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
|
|
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
|
|
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,
|
|
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> <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 [
|
|
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> <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> <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> <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"]}
|