@sneat/auth-ui 0.1.3 → 0.1.4

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.
Files changed (88) hide show
  1. package/esm2022/index.js +4 -0
  2. package/esm2022/index.js.map +1 -0
  3. package/esm2022/lib/components/auth-menu-item/auth-menu-item.component.js +82 -0
  4. package/esm2022/lib/components/auth-menu-item/auth-menu-item.component.js.map +1 -0
  5. package/esm2022/lib/components/index.js +4 -0
  6. package/esm2022/lib/components/index.js.map +1 -0
  7. package/esm2022/lib/components/user-auth-providers/user-auth-accounts.component.js +83 -0
  8. package/esm2022/lib/components/user-auth-providers/user-auth-accounts.component.js.map +1 -0
  9. package/esm2022/lib/components/user-auth-providers/user-auth-provider-status.js +118 -0
  10. package/esm2022/lib/components/user-auth-providers/user-auth-provider-status.js.map +1 -0
  11. package/esm2022/lib/components/user-required-fields/index.js +3 -0
  12. package/esm2022/lib/components/user-required-fields/index.js.map +1 -0
  13. package/esm2022/lib/components/user-required-fields/user-required-fields-modal.component.js +111 -0
  14. package/esm2022/lib/components/user-required-fields/user-required-fields-modal.component.js.map +1 -0
  15. package/esm2022/lib/components/user-required-fields/user-required-fields.service.js +29 -0
  16. package/esm2022/lib/components/user-required-fields/user-required-fields.service.js.map +1 -0
  17. package/esm2022/lib/pages/login-page/email-login-form/email-login-form.component.js +263 -0
  18. package/esm2022/lib/pages/login-page/email-login-form/email-login-form.component.js.map +1 -0
  19. package/esm2022/lib/pages/login-page/login-page.component.js +143 -0
  20. package/esm2022/lib/pages/login-page/login-page.component.js.map +1 -0
  21. package/esm2022/lib/pages/login-page/login-with-telegram.component.js +93 -0
  22. package/esm2022/lib/pages/login-page/login-with-telegram.component.js.map +1 -0
  23. package/esm2022/lib/pages/login-page/sneat-auth-with-telegram.service.js +31 -0
  24. package/esm2022/lib/pages/login-page/sneat-auth-with-telegram.service.js.map +1 -0
  25. package/esm2022/lib/pages/sign-in-from-email-link/sign-in-from-email-link-page.component.js +52 -0
  26. package/esm2022/lib/pages/sign-in-from-email-link/sign-in-from-email-link-page.component.js.map +1 -0
  27. package/esm2022/lib/pages/sneat-auth-routing.module.js +27 -0
  28. package/esm2022/lib/pages/sneat-auth-routing.module.js.map +1 -0
  29. package/esm2022/lib/pipes/person-names.pipe.js +35 -0
  30. package/esm2022/lib/pipes/person-names.pipe.js.map +1 -0
  31. package/esm2022/sneat-auth-ui.js +5 -0
  32. package/esm2022/sneat-auth-ui.js.map +1 -0
  33. package/lib/components/auth-menu-item/auth-menu-item.component.d.ts +24 -0
  34. package/lib/components/user-auth-providers/user-auth-accounts.component.d.ts +17 -0
  35. package/lib/components/user-auth-providers/user-auth-provider-status.d.ts +31 -0
  36. package/lib/components/user-required-fields/user-required-fields-modal.component.d.ts +31 -0
  37. package/lib/components/user-required-fields/user-required-fields.service.d.ts +7 -0
  38. package/lib/pages/login-page/email-login-form/email-login-form.component.d.ts +51 -0
  39. package/lib/pages/login-page/login-page.component.d.ts +30 -0
  40. package/lib/pages/login-page/login-with-telegram.component.d.ts +17 -0
  41. package/lib/pages/login-page/sneat-auth-with-telegram.service.d.ts +18 -0
  42. package/lib/pages/sign-in-from-email-link/sign-in-from-email-link-page.component.d.ts +13 -0
  43. package/lib/pages/sneat-auth-routing.module.d.ts +9 -0
  44. package/lib/pipes/person-names.pipe.d.ts +9 -0
  45. package/package.json +14 -2
  46. package/sneat-auth-ui.d.ts +5 -0
  47. package/eslint.config.cjs +0 -7
  48. package/ng-package.json +0 -7
  49. package/project.json +0 -38
  50. package/src/lib/components/auth-menu-item/auth-menu-item.component.html +0 -59
  51. package/src/lib/components/auth-menu-item/auth-menu-item.component.spec.ts +0 -5
  52. package/src/lib/components/auth-menu-item/auth-menu-item.component.ts +0 -116
  53. package/src/lib/components/user-auth-providers/user-auth-accounts.component.html +0 -127
  54. package/src/lib/components/user-auth-providers/user-auth-accounts.component.spec.ts +0 -47
  55. package/src/lib/components/user-auth-providers/user-auth-accounts.component.ts +0 -109
  56. package/src/lib/components/user-auth-providers/user-auth-provider-status.html +0 -42
  57. package/src/lib/components/user-auth-providers/user-auth-provider-status.ts +0 -172
  58. package/src/lib/components/user-required-fields/user-required-fields-modal.component.html +0 -64
  59. package/src/lib/components/user-required-fields/user-required-fields-modal.component.spec.ts +0 -45
  60. package/src/lib/components/user-required-fields/user-required-fields-modal.component.ts +0 -141
  61. package/src/lib/components/user-required-fields/user-required-fields.service.spec.ts +0 -335
  62. package/src/lib/components/user-required-fields/user-required-fields.service.ts +0 -23
  63. package/src/lib/pages/login-page/email-login-form/email-login-form.component.html +0 -165
  64. package/src/lib/pages/login-page/email-login-form/email-login-form.component.spec.ts +0 -59
  65. package/src/lib/pages/login-page/email-login-form/email-login-form.component.ts +0 -356
  66. package/src/lib/pages/login-page/index.ts +0 -3
  67. package/src/lib/pages/login-page/login-page.component.html +0 -146
  68. package/src/lib/pages/login-page/login-page.component.spec.ts +0 -5
  69. package/src/lib/pages/login-page/login-page.component.ts +0 -209
  70. package/src/lib/pages/login-page/login-with-telegram.component.spec.ts +0 -42
  71. package/src/lib/pages/login-page/login-with-telegram.component.ts +0 -82
  72. package/src/lib/pages/login-page/sneat-auth-with-telegram.service.spec.ts +0 -31
  73. package/src/lib/pages/login-page/sneat-auth-with-telegram.service.ts +0 -56
  74. package/src/lib/pages/sign-in-from-email-link/sign-in-from-email-link-page.component.html +0 -35
  75. package/src/lib/pages/sign-in-from-email-link/sign-in-from-email-link-page.component.spec.ts +0 -43
  76. package/src/lib/pages/sign-in-from-email-link/sign-in-from-email-link-page.component.ts +0 -70
  77. package/src/lib/pages/sneat-auth-routing.module.ts +0 -25
  78. package/src/lib/pipes/person-names.pipe.spec.ts +0 -317
  79. package/src/lib/pipes/person-names.pipe.ts +0 -31
  80. package/src/test-setup.ts +0 -3
  81. package/tsconfig.json +0 -13
  82. package/tsconfig.lib.json +0 -19
  83. package/tsconfig.lib.prod.json +0 -7
  84. package/tsconfig.spec.json +0 -31
  85. package/vite.config.mts +0 -10
  86. /package/{src/index.ts → index.d.ts} +0 -0
  87. /package/{src/lib/components/index.ts → lib/components/index.d.ts} +0 -0
  88. /package/{src/lib/components/user-required-fields/index.ts → lib/components/user-required-fields/index.d.ts} +0 -0
@@ -1,356 +0,0 @@
1
- import {
2
- Component,
3
- EventEmitter,
4
- Output,
5
- ViewChild,
6
- inject,
7
- } from '@angular/core';
8
- // import { getApp } from '@angular/fire/app';
9
- // import { getAuth } from '@angular/fire/auth';
10
- import {
11
- Auth,
12
- sendPasswordResetEmail,
13
- sendSignInLinkToEmail,
14
- } from '@angular/fire/auth';
15
- import { FormsModule } from '@angular/forms';
16
- import {
17
- ToastController,
18
- IonButton,
19
- IonButtons,
20
- IonCard,
21
- IonCardContent,
22
- IonIcon,
23
- IonInput,
24
- IonItem,
25
- IonItemDivider,
26
- IonLabel,
27
- IonSegment,
28
- IonSegmentButton,
29
- IonSpinner,
30
- IonText,
31
- } from '@ionic/angular/standalone';
32
- import { SneatApiService } from '@sneat/api';
33
- import { IInitUserRecordRequest, UserRecordService } from '@sneat/auth-core';
34
- import { createSetFocusToInput } from '@sneat/ui';
35
- import {
36
- AnalyticsService,
37
- APP_INFO,
38
- IAnalyticsService,
39
- IAppInfo,
40
- } from '@sneat/core';
41
- import { ErrorLogger, IErrorLogger } from '@sneat/core';
42
- import { RandomIdService } from '@sneat/random';
43
- import { UserCredential, sendEmailVerification } from 'firebase/auth';
44
- import { FirebaseError } from 'firebase/app';
45
-
46
- export type EmailFormSigningWith = 'email' | 'emailLink' | 'resetPassword';
47
- import {
48
- createUserWithEmailAndPassword,
49
- signInWithEmailAndPassword,
50
- } from 'firebase/auth';
51
-
52
- @Component({
53
- selector: 'sneat-email-login-form',
54
- templateUrl: 'email-login-form.component.html',
55
- imports: [
56
- FormsModule,
57
- IonCard,
58
- IonItemDivider,
59
- IonSegment,
60
- IonSegmentButton,
61
- IonIcon,
62
- IonLabel,
63
- IonCardContent,
64
- IonItem,
65
- IonInput,
66
- IonSpinner,
67
- IonText,
68
- IonButton,
69
- IonButtons,
70
- ],
71
- })
72
- export class EmailLoginFormComponent {
73
- readonly appInfo = inject<IAppInfo>(APP_INFO);
74
- private readonly analyticsService =
75
- inject<IAnalyticsService>(AnalyticsService);
76
- private readonly errorLogger = inject<IErrorLogger>(ErrorLogger);
77
- private readonly toastController = inject(ToastController);
78
- private readonly afAuth = inject(Auth);
79
- private readonly randomIdService = inject(RandomIdService);
80
- private readonly sneatApiService = inject(SneatApiService);
81
- private readonly userRecordService = inject(UserRecordService);
82
-
83
- protected sign: 'in' | 'up' = 'up'; // TODO: document here what 'in' & 'up' means
84
- protected email = '';
85
- protected password = '';
86
- protected firstName = '';
87
- protected lastName = '';
88
- protected spaceTitle = '';
89
- protected wrongPassword = false;
90
-
91
- protected signingWith?: EmailFormSigningWith;
92
-
93
- @Output() readonly signingWithChange = new EventEmitter<
94
- EmailFormSigningWith | undefined
95
- >();
96
- @Output() readonly loggedIn = new EventEmitter<UserCredential>();
97
-
98
- @ViewChild('emailInput', { static: true }) emailInput?: IonInput;
99
- @ViewChild('spaceTitleInput', { static: false }) spaceTitleInput?: IonInput;
100
-
101
- public readonly setFocusToInput = createSetFocusToInput(this.errorLogger);
102
-
103
- constructor() {
104
- this.email = localStorage.getItem('emailForSignIn') || '';
105
- if (this.email) {
106
- this.sign = 'in';
107
- }
108
- }
109
-
110
- public get validEmail(): boolean {
111
- const email = this.email,
112
- i = email?.indexOf('@');
113
- return i > 0 && i < email.length - 1;
114
- }
115
-
116
- public getFirebaseAuth(): Auth {
117
- return this.afAuth as unknown as Auth; // TODO: pending https://github.com/angular/angularfire/pull/3402
118
- }
119
-
120
- public async signUp(): Promise<void> {
121
- if (!this.firstName) {
122
- // this.toaster.showToast('Full name is required');
123
- return;
124
- }
125
- // this.signingWith = 'email';
126
- this.email = this.email.trim();
127
- const email = this.email;
128
- const firstName = this.firstName.trim();
129
- const lastName = this.lastName.trim();
130
- if (!email) {
131
- alert('Email is a required field');
132
- return;
133
- }
134
- if (!firstName) {
135
- alert('First name is a required field');
136
- return;
137
- }
138
- if (!lastName) {
139
- alert('Last name is a required field');
140
- return;
141
- }
142
- this.spaceTitle = this.spaceTitle.trim();
143
- const spaceTitle = this.spaceTitle;
144
- if (this.appInfo.requiredSpaceType && !spaceTitle) {
145
- alert('Company title is a required field');
146
- this.setFocusToSpaceTitle();
147
- return;
148
- }
149
- localStorage.setItem('emailForSignIn', email);
150
- const password = this.randomIdService.newRandomId({ len: 9 });
151
-
152
- this.setSigningWith('email');
153
- try {
154
- // const auth = getAuth(getApp());
155
- const auth = this.getFirebaseAuth();
156
- const userCredential = await createUserWithEmailAndPassword(
157
- auth,
158
- email,
159
- password,
160
- );
161
- this.sendVerificationEmail(userCredential);
162
- userCredential.user
163
- ?.getIdToken()
164
- .then((token) => {
165
- this.sneatApiService.setApiAuthToken(token);
166
- const request: IInitUserRecordRequest = {
167
- authProvider: 'password',
168
- email,
169
- ianaTimezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
170
- names: { firstName, lastName },
171
- space: this.appInfo.requiredSpaceType
172
- ? {
173
- type: this.appInfo.requiredSpaceType,
174
- title: spaceTitle,
175
- }
176
- : undefined,
177
- };
178
- this.userRecordService.initUserRecord(request).subscribe({
179
- next: () => this.onLoggedIn(userCredential),
180
- error: (err) => {
181
- this.analyticsService.logEvent('FailedToSetUserTitle');
182
- this.errorLogger.logError(err, 'Failed to set user title', {
183
- feedback: false,
184
- });
185
- this.onLoggedIn(userCredential);
186
- },
187
- });
188
- })
189
- .catch(
190
- this.errorHandler(
191
- 'Failed to get Firebase ID token',
192
- 'FirebaseGetIdTokenFailed',
193
- ),
194
- );
195
- } catch (e) {
196
- this.handleError(
197
- e,
198
- 'Failed to sign up with email',
199
- 'FailedToSignUpWithEmail',
200
- );
201
- }
202
- }
203
-
204
- public keyupEnter(): void {
205
- switch (this.sign) {
206
- case 'in':
207
- this.signIn();
208
- break;
209
- case 'up':
210
- this.signUp().catch(() => this.errorHandler('Failed to sign up'));
211
- break;
212
- }
213
- }
214
-
215
- public signIn(): void {
216
- this.setSigningWith('email');
217
- this.email = this.email.trim();
218
- this.wrongPassword = false;
219
- this.saveEmailForReuse();
220
- // const auth = getAuth(getApp());
221
- const auth = this.getFirebaseAuth();
222
- signInWithEmailAndPassword(auth, this.email, this.password)
223
- .then((userCredential) => {
224
- this.onLoggedIn(userCredential); // TODO: add analytics event
225
- })
226
- .catch(
227
- this.errorHandler('Failed to sign in with email & password', 'email'),
228
- );
229
- }
230
-
231
- private saveEmailForReuse(): void {
232
- localStorage.setItem('emailForSignIn', this.email);
233
- }
234
-
235
- public sendSignInLink(): void {
236
- this.setSigningWith('emailLink');
237
- this.email = this.email.trim();
238
- this.saveEmailForReuse();
239
- sendSignInLinkToEmail(this.afAuth, this.email, {
240
- // url: 'https://dailyscrum.app/pwa/sign-in',
241
- url: document.baseURI + 'sign-in-from-email-link',
242
- handleCodeInApp: true,
243
- })
244
- .then(() => {
245
- this.showToast(`Sign-in link has been sent to email: ${this.email}`);
246
- this.setSigningWith(undefined);
247
- })
248
- .catch(
249
- this.errorHandler(
250
- 'Failed to send sign in link to email',
251
- 'FailedToSendSignInLinkToEmail',
252
- ),
253
- );
254
- }
255
-
256
- private showToast(message: string): void {
257
- this.toastController
258
- .create({
259
- message,
260
- position: 'middle',
261
- keyboardClose: true,
262
- duration: 3000,
263
- color: 'tertiary',
264
- icon: 'send-outline',
265
- buttons: [{ icon: 'close', role: 'cancel' }],
266
- })
267
- .then((toast) => {
268
- toast
269
- .present()
270
- .catch(
271
- this.errorLogger.logErrorHandler(
272
- 'Failed to present toast about password reset email sent success',
273
- ),
274
- );
275
- });
276
- }
277
-
278
- public resetPassword(): void {
279
- this.setSigningWith('resetPassword');
280
- sendPasswordResetEmail(this.afAuth, this.email)
281
- .then(() => {
282
- this.setSigningWith(undefined);
283
- this.showToast(
284
- `Password reset link has been sent to email: ${this.email}`,
285
- );
286
- })
287
- .catch(
288
- this.errorHandler(
289
- 'Failed to send password reset email',
290
- 'FailedToSendPasswordResetEmail',
291
- ),
292
- );
293
- }
294
-
295
- private sendVerificationEmail(userCredential: UserCredential): void {
296
- setTimeout(async () => {
297
- try {
298
- await sendEmailVerification(userCredential.user);
299
- } catch (e) {
300
- this.handleError(e, 'Failed to send verification email');
301
- }
302
- });
303
- }
304
-
305
- private onLoggedIn(userCredential: UserCredential): void {
306
- this.loggedIn.emit(userCredential);
307
- }
308
-
309
- private errorHandler(
310
- m: string,
311
- eventName?: string,
312
- eventParams?: Record<string, string>,
313
- ): (err: unknown) => void {
314
- return (err) => this.handleError(err, m, eventName, eventParams);
315
- }
316
-
317
- private handleError(
318
- err: unknown,
319
- m: string,
320
- eventName?: string,
321
- eventParams?: Record<string, string>,
322
- ): void {
323
- this.setSigningWith(undefined);
324
- if (eventName) {
325
- this.analyticsService.logEvent(eventName, eventParams);
326
- }
327
- if ((err as FirebaseError).code === 'auth/wrong-password') {
328
- this.wrongPassword = true;
329
- return;
330
- }
331
- this.errorLogger.logError(err, m, {
332
- report: !(err as { code: unknown }).code,
333
- });
334
- }
335
-
336
- private setSigningWith(signingWith?: EmailFormSigningWith): void {
337
- this.signingWith = signingWith;
338
- this.signingWithChange.emit(signingWith);
339
- }
340
-
341
- signChanged(): void {
342
- this.setFocusToEmail();
343
- }
344
-
345
- ionViewDidEnter(): void {
346
- this.setFocusToEmail();
347
- }
348
-
349
- private setFocusToEmail(): void {
350
- this.setFocusToInput(undefined /*this.emailInput*/);
351
- }
352
-
353
- private setFocusToSpaceTitle(): void {
354
- this.setFocusToInput(undefined /*this.spaceTitleInput*/);
355
- }
356
- }
@@ -1,3 +0,0 @@
1
- export * from './login-page.component';
2
- export * from './login-page.component.module';
3
- export * from './login-page.routing.module';
@@ -1,146 +0,0 @@
1
- <ion-header>
2
- <ion-toolbar color="light">
3
- <ion-buttons slot="start">
4
- <ion-back-button />
5
- </ion-buttons>
6
- <ion-title>Login &#64; {{ appTitle }}</ion-title>
7
- </ion-toolbar>
8
- </ion-header>
9
-
10
- <ion-content id="main-content">
11
- @if (to) {
12
- <ion-card color="tertiary">
13
- <ion-card-content>
14
- <p>Please sign in to join a team</p>
15
- </ion-card-content>
16
- </ion-card>
17
- }
18
-
19
- <p style="text-align: center; font-size: smaller">
20
- <ion-text color="medium">
21
- This app is free to use &
22
- <a target="_blank" href="https://github.com/sneat-co">open source</a>.
23
- </ion-text>
24
- </p>
25
-
26
- <sneat-email-login-form
27
- (signingWithChange)="onEmailFormStatusChanged()"
28
- (loggedIn)="onLoggedIn($event)"
29
- />
30
-
31
- <ion-card>
32
- <ion-item-divider color="light">
33
- <ion-label
34
- color="medium"
35
- style="text-align: center; width: 100%; font-weight: bold"
36
- >
37
- Quick login
38
- </ion-label>
39
- </ion-item-divider>
40
- <ion-grid class="ion-grid-layout">
41
- @if (!isNativePlatform) {
42
- <ion-row>
43
- <ion-col>
44
- <div class="ion-padding" style="text-align: center">
45
- <sneat-login-with-telegram />
46
- </div>
47
- </ion-col>
48
- </ion-row>
49
- }
50
- <ion-row>
51
- <ion-col size="12" size-md="6">
52
- <ion-list lines="none">
53
- <ion-item
54
- (click)="loginWith('google.com')"
55
- tappable
56
- [disabled]="!!signingWith()"
57
- >
58
- @if (signingWith() === "google.com") {
59
- <ion-spinner slot="start" name="lines-small" />
60
- } @else {
61
- <ion-icon color="danger" name="logo-google" slot="start" />
62
- }
63
- <ion-label color="danger"> Login with Google</ion-label>
64
- </ion-item>
65
- </ion-list>
66
- </ion-col>
67
- <ion-col size="12" size-md="6">
68
- <ion-list lines="none">
69
- <ion-item
70
- (click)="loginWith('apple.com')"
71
- tappable
72
- [disabled]="!!signingWith()"
73
- >
74
- @if (signingWith() === "apple.com") {
75
- <ion-spinner slot="start" name="lines-small" />
76
- } @else {
77
- <ion-icon color="dark" name="logo-apple" slot="start" />
78
- }
79
-
80
- <ion-label color="dark"> Login with Apple</ion-label>
81
- </ion-item>
82
- </ion-list>
83
- </ion-col>
84
- </ion-row>
85
- <ion-row>
86
- <ion-col size="12" size-md="6">
87
- <ion-list lines="none">
88
- <ion-item
89
- (click)="loginWith('microsoft.com')"
90
- tappable
91
- [disabled]="!!signingWith()"
92
- >
93
- @if (signingWith() === "microsoft.com") {
94
- <ion-spinner
95
- slot="start"
96
- color="secondary"
97
- name="lines-small"
98
- />
99
- } @else {
100
- <ion-icon slot="start" color="secondary" name="logo-windows" />
101
- }
102
- <ion-label color="secondary">Login with Microsoft</ion-label>
103
- </ion-item>
104
- </ion-list>
105
- </ion-col>
106
- <ion-col size="12" size-md="6">
107
- <ion-list lines="none">
108
- <ion-item
109
- (click)="loginWith('facebook.com')"
110
- tappable
111
- [disabled]="!!signingWith()"
112
- >
113
- @if (signingWith() === "facebook.com") {
114
- <ion-spinner slot="start" color="primary" name="lines-small" />
115
- } @else {
116
- <ion-icon slot="start" color="primary" name="logo-facebook" />
117
- }
118
- <ion-label color="primary">Login with Facebook</ion-label>
119
- </ion-item>
120
- </ion-list>
121
- </ion-col>
122
- </ion-row>
123
- </ion-grid>
124
- <!-- <ion-item-->
125
- <!-- (click)="loginWith('github.com')"-->
126
- <!-- tappable-->
127
- <!-- [disabled]="!!signingWith()"-->
128
- <!-- >-->
129
- <!-- @if (signingWith() === "github.com") {-->
130
- <!-- <ion-spinner slot="start" color="tertiary" name="lines-small" />-->
131
- <!-- } @else {-->
132
- <!-- <ion-icon slot="start" color="tertiary" name="logo-github" />-->
133
- <!-- }-->
134
- <!-- <ion-label color="tertiary">Login with GitHub</ion-label>-->
135
- <!-- </ion-item>-->
136
- </ion-card>
137
-
138
- <p style="text-align: center; font-size: smaller">
139
- <ion-text color="medium">
140
- If any issues get
141
- <a href="mailto:help@sneat.app?subject=Problem+with+login+at+Sneat.app"
142
- >help&#64;sneat.app</a
143
- >
144
- </ion-text>
145
- </p>
146
- </ion-content>
@@ -1,5 +0,0 @@
1
- describe('LoginPage', () => {
2
- it('should create', () => {
3
- expect(true).toBeTruthy();
4
- });
5
- });