@sneat/auth-ui 0.1.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/eslint.config.cjs +7 -0
- package/ng-package.json +7 -0
- package/package.json +19 -0
- package/project.json +38 -0
- package/src/index.ts +3 -0
- package/src/lib/components/auth-menu-item/auth-menu-item.component.html +59 -0
- package/src/lib/components/auth-menu-item/auth-menu-item.component.spec.ts +5 -0
- package/src/lib/components/auth-menu-item/auth-menu-item.component.ts +116 -0
- package/src/lib/components/index.ts +3 -0
- package/src/lib/components/user-auth-providers/user-auth-accounts.component.html +127 -0
- package/src/lib/components/user-auth-providers/user-auth-accounts.component.spec.ts +47 -0
- package/src/lib/components/user-auth-providers/user-auth-accounts.component.ts +109 -0
- package/src/lib/components/user-auth-providers/user-auth-provider-status.html +42 -0
- package/src/lib/components/user-auth-providers/user-auth-provider-status.ts +172 -0
- package/src/lib/components/user-required-fields/index.ts +2 -0
- package/src/lib/components/user-required-fields/user-required-fields-modal.component.html +64 -0
- package/src/lib/components/user-required-fields/user-required-fields-modal.component.spec.ts +45 -0
- package/src/lib/components/user-required-fields/user-required-fields-modal.component.ts +141 -0
- package/src/lib/components/user-required-fields/user-required-fields.service.spec.ts +335 -0
- package/src/lib/components/user-required-fields/user-required-fields.service.ts +23 -0
- package/src/lib/pages/login-page/email-login-form/email-login-form.component.html +165 -0
- package/src/lib/pages/login-page/email-login-form/email-login-form.component.spec.ts +59 -0
- package/src/lib/pages/login-page/email-login-form/email-login-form.component.ts +356 -0
- package/src/lib/pages/login-page/index.ts +3 -0
- package/src/lib/pages/login-page/login-page.component.html +146 -0
- package/src/lib/pages/login-page/login-page.component.spec.ts +5 -0
- package/src/lib/pages/login-page/login-page.component.ts +209 -0
- package/src/lib/pages/login-page/login-with-telegram.component.spec.ts +42 -0
- package/src/lib/pages/login-page/login-with-telegram.component.ts +82 -0
- package/src/lib/pages/login-page/sneat-auth-with-telegram.service.spec.ts +31 -0
- package/src/lib/pages/login-page/sneat-auth-with-telegram.service.ts +56 -0
- package/src/lib/pages/sign-in-from-email-link/sign-in-from-email-link-page.component.html +35 -0
- package/src/lib/pages/sign-in-from-email-link/sign-in-from-email-link-page.component.spec.ts +43 -0
- package/src/lib/pages/sign-in-from-email-link/sign-in-from-email-link-page.component.ts +70 -0
- package/src/lib/pages/sneat-auth-routing.module.ts +25 -0
- package/src/lib/pipes/person-names.pipe.spec.ts +317 -0
- package/src/lib/pipes/person-names.pipe.ts +31 -0
- package/src/test-setup.ts +3 -0
- package/tsconfig.json +13 -0
- package/tsconfig.lib.json +19 -0
- package/tsconfig.lib.prod.json +7 -0
- package/tsconfig.spec.json +31 -0
- package/vite.config.mts +10 -0
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
import { PersonNamesPipe, personNames } from './person-names.pipe';
|
|
2
|
+
import { IPersonNames } from '@sneat/auth-models';
|
|
3
|
+
|
|
4
|
+
describe('PersonNamesPipe', () => {
|
|
5
|
+
let pipe: PersonNamesPipe;
|
|
6
|
+
|
|
7
|
+
beforeEach(() => {
|
|
8
|
+
pipe = new PersonNamesPipe();
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
it('should create', () => {
|
|
12
|
+
expect(pipe).toBeTruthy();
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
describe('transform', () => {
|
|
16
|
+
it('should return undefined when names is undefined', () => {
|
|
17
|
+
const result = pipe.transform(undefined);
|
|
18
|
+
expect(result).toBeUndefined();
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('should return undefined when names is null', () => {
|
|
22
|
+
const result = pipe.transform(undefined);
|
|
23
|
+
expect(result).toBeUndefined();
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('should return fullName when it exists', () => {
|
|
27
|
+
const names: IPersonNames = { fullName: 'John Michael Doe' };
|
|
28
|
+
const result = pipe.transform(names);
|
|
29
|
+
expect(result).toBe('John Michael Doe');
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('should prefer fullName over other name fields', () => {
|
|
33
|
+
const names: IPersonNames = {
|
|
34
|
+
fullName: 'John Michael Doe',
|
|
35
|
+
firstName: 'John',
|
|
36
|
+
lastName: 'Doe',
|
|
37
|
+
middleName: 'Michael',
|
|
38
|
+
nickName: 'Johnny',
|
|
39
|
+
};
|
|
40
|
+
const result = pipe.transform(names);
|
|
41
|
+
expect(result).toBe('John Michael Doe');
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('should return firstName + lastName when both exist and fullName is not provided', () => {
|
|
45
|
+
const names: IPersonNames = {
|
|
46
|
+
firstName: 'John',
|
|
47
|
+
lastName: 'Doe',
|
|
48
|
+
};
|
|
49
|
+
const result = pipe.transform(names);
|
|
50
|
+
expect(result).toBe('John Doe');
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it('should return firstName + lastName when both exist along with other fields but no fullName', () => {
|
|
54
|
+
const names: IPersonNames = {
|
|
55
|
+
firstName: 'John',
|
|
56
|
+
lastName: 'Doe',
|
|
57
|
+
middleName: 'Michael',
|
|
58
|
+
nickName: 'Johnny',
|
|
59
|
+
};
|
|
60
|
+
const result = pipe.transform(names);
|
|
61
|
+
expect(result).toBe('John Doe');
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it('should return JSON.stringify when only firstName exists', () => {
|
|
65
|
+
const names: IPersonNames = { firstName: 'John' };
|
|
66
|
+
const result = pipe.transform(names);
|
|
67
|
+
expect(result).toBe(JSON.stringify(names));
|
|
68
|
+
expect(result).toBe('{"firstName":"John"}');
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it('should return JSON.stringify when only lastName exists', () => {
|
|
72
|
+
const names: IPersonNames = { lastName: 'Doe' };
|
|
73
|
+
const result = pipe.transform(names);
|
|
74
|
+
expect(result).toBe(JSON.stringify(names));
|
|
75
|
+
expect(result).toBe('{"lastName":"Doe"}');
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it('should return JSON.stringify when only middleName exists', () => {
|
|
79
|
+
const names: IPersonNames = { middleName: 'Michael' };
|
|
80
|
+
const result = pipe.transform(names);
|
|
81
|
+
expect(result).toBe(JSON.stringify(names));
|
|
82
|
+
expect(result).toBe('{"middleName":"Michael"}');
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it('should return JSON.stringify when only nickName exists', () => {
|
|
86
|
+
const names: IPersonNames = { nickName: 'Johnny' };
|
|
87
|
+
const result = pipe.transform(names);
|
|
88
|
+
expect(result).toBe(JSON.stringify(names));
|
|
89
|
+
expect(result).toBe('{"nickName":"Johnny"}');
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it('should return JSON.stringify for empty object', () => {
|
|
93
|
+
const names: IPersonNames = {};
|
|
94
|
+
const result = pipe.transform(names);
|
|
95
|
+
expect(result).toBe('{}');
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it('should handle empty strings in firstName and lastName', () => {
|
|
99
|
+
const names: IPersonNames = {
|
|
100
|
+
firstName: '',
|
|
101
|
+
lastName: '',
|
|
102
|
+
};
|
|
103
|
+
const result = pipe.transform(names);
|
|
104
|
+
expect(result).toBe(JSON.stringify(names));
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it('should handle whitespace-only firstName and lastName', () => {
|
|
108
|
+
const names: IPersonNames = {
|
|
109
|
+
firstName: ' ',
|
|
110
|
+
lastName: ' ',
|
|
111
|
+
};
|
|
112
|
+
const result = pipe.transform(names);
|
|
113
|
+
// Since ' ' is truthy, this should combine them with a space in between
|
|
114
|
+
expect(result).toBe(' '); // ' ' + ' ' + ' ' = 7 spaces
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
describe('personNames function', () => {
|
|
120
|
+
it('should return undefined when names is undefined', () => {
|
|
121
|
+
const result = personNames(undefined);
|
|
122
|
+
expect(result).toBeUndefined();
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
it('should return fullName when it exists', () => {
|
|
126
|
+
const names: IPersonNames = { fullName: 'John Michael Doe' };
|
|
127
|
+
const result = personNames(names);
|
|
128
|
+
expect(result).toBe('John Michael Doe');
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it('should prefer fullName over all other fields', () => {
|
|
132
|
+
const names: IPersonNames = {
|
|
133
|
+
fullName: 'John Michael Doe',
|
|
134
|
+
firstName: 'John',
|
|
135
|
+
lastName: 'Doe',
|
|
136
|
+
middleName: 'Michael',
|
|
137
|
+
nickName: 'Johnny',
|
|
138
|
+
};
|
|
139
|
+
const result = personNames(names);
|
|
140
|
+
expect(result).toBe('John Michael Doe');
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
it('should return firstName + lastName when both exist and no nickName or middleName', () => {
|
|
144
|
+
const names: IPersonNames = {
|
|
145
|
+
firstName: 'John',
|
|
146
|
+
lastName: 'Doe',
|
|
147
|
+
};
|
|
148
|
+
const result = personNames(names);
|
|
149
|
+
expect(result).toBe('John Doe');
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
it('should return nickName when firstName and lastName exist along with nickName', () => {
|
|
153
|
+
const names: IPersonNames = {
|
|
154
|
+
firstName: 'John',
|
|
155
|
+
lastName: 'Doe',
|
|
156
|
+
nickName: 'Johnny',
|
|
157
|
+
};
|
|
158
|
+
const result = personNames(names);
|
|
159
|
+
expect(result).toBe('Johnny');
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
it('should return nickName when firstName and lastName exist along with middleName', () => {
|
|
163
|
+
const names: IPersonNames = {
|
|
164
|
+
firstName: 'John',
|
|
165
|
+
lastName: 'Doe',
|
|
166
|
+
middleName: 'Michael',
|
|
167
|
+
};
|
|
168
|
+
const result = personNames(names);
|
|
169
|
+
expect(result).toBe('John');
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
it('should return nickName as first priority when available', () => {
|
|
173
|
+
const names: IPersonNames = {
|
|
174
|
+
nickName: 'Johnny',
|
|
175
|
+
firstName: 'John',
|
|
176
|
+
lastName: 'Doe',
|
|
177
|
+
middleName: 'Michael',
|
|
178
|
+
};
|
|
179
|
+
const result = personNames(names);
|
|
180
|
+
expect(result).toBe('Johnny');
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
it('should return firstName when only firstName is available', () => {
|
|
184
|
+
const names: IPersonNames = { firstName: 'John' };
|
|
185
|
+
const result = personNames(names);
|
|
186
|
+
expect(result).toBe('John');
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
it('should return firstName when nickName is not available but firstName is', () => {
|
|
190
|
+
const names: IPersonNames = {
|
|
191
|
+
firstName: 'John',
|
|
192
|
+
lastName: 'Doe',
|
|
193
|
+
middleName: 'Michael',
|
|
194
|
+
};
|
|
195
|
+
const result = personNames(names);
|
|
196
|
+
expect(result).toBe('John');
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
it('should return lastName when only lastName is available', () => {
|
|
200
|
+
const names: IPersonNames = { lastName: 'Doe' };
|
|
201
|
+
const result = personNames(names);
|
|
202
|
+
expect(result).toBe('Doe');
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
it('should return lastName when nickName and firstName are not available', () => {
|
|
206
|
+
const names: IPersonNames = {
|
|
207
|
+
lastName: 'Doe',
|
|
208
|
+
middleName: 'Michael',
|
|
209
|
+
};
|
|
210
|
+
const result = personNames(names);
|
|
211
|
+
expect(result).toBe('Doe');
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
it('should return middleName when only middleName is available', () => {
|
|
215
|
+
const names: IPersonNames = { middleName: 'Michael' };
|
|
216
|
+
const result = personNames(names);
|
|
217
|
+
expect(result).toBe('Michael');
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
it('should return middleName as last priority', () => {
|
|
221
|
+
const names: IPersonNames = {
|
|
222
|
+
middleName: 'Michael',
|
|
223
|
+
};
|
|
224
|
+
const result = personNames(names);
|
|
225
|
+
expect(result).toBe('Michael');
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
it('should return undefined for empty object', () => {
|
|
229
|
+
const names: IPersonNames = {};
|
|
230
|
+
const result = personNames(names);
|
|
231
|
+
expect(result).toBeUndefined();
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
it('should handle empty strings and return undefined', () => {
|
|
235
|
+
const names: IPersonNames = {
|
|
236
|
+
firstName: '',
|
|
237
|
+
lastName: '',
|
|
238
|
+
middleName: '',
|
|
239
|
+
nickName: '',
|
|
240
|
+
fullName: '',
|
|
241
|
+
};
|
|
242
|
+
const result = personNames(names);
|
|
243
|
+
// Empty strings are falsy in the OR chain
|
|
244
|
+
expect(result).toBe('');
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
it('should prioritize nickName over firstName', () => {
|
|
248
|
+
const names: IPersonNames = {
|
|
249
|
+
nickName: 'JD',
|
|
250
|
+
firstName: 'John',
|
|
251
|
+
};
|
|
252
|
+
const result = personNames(names);
|
|
253
|
+
expect(result).toBe('JD');
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
it('should return firstName + lastName when nickName is empty string', () => {
|
|
257
|
+
const names: IPersonNames = {
|
|
258
|
+
firstName: 'John',
|
|
259
|
+
lastName: 'Doe',
|
|
260
|
+
nickName: '',
|
|
261
|
+
};
|
|
262
|
+
const result = personNames(names);
|
|
263
|
+
// Empty string is falsy, and no middleName, so firstName + lastName is used
|
|
264
|
+
expect(result).toBe('John Doe');
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
it('should prioritize lastName over middleName', () => {
|
|
268
|
+
const names: IPersonNames = {
|
|
269
|
+
lastName: 'Doe',
|
|
270
|
+
middleName: 'Michael',
|
|
271
|
+
};
|
|
272
|
+
const result = personNames(names);
|
|
273
|
+
expect(result).toBe('Doe');
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
describe('edge cases', () => {
|
|
277
|
+
it('should handle all fields with nickName priority', () => {
|
|
278
|
+
const names: IPersonNames = {
|
|
279
|
+
fullName: '',
|
|
280
|
+
nickName: 'Johnny',
|
|
281
|
+
firstName: 'John',
|
|
282
|
+
lastName: 'Doe',
|
|
283
|
+
middleName: 'Michael',
|
|
284
|
+
};
|
|
285
|
+
const result = personNames(names);
|
|
286
|
+
expect(result).toBe('Johnny');
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
it('should handle whitespace-only fullName as falsy', () => {
|
|
290
|
+
const names: IPersonNames = {
|
|
291
|
+
fullName: ' ',
|
|
292
|
+
firstName: 'John',
|
|
293
|
+
};
|
|
294
|
+
const result = personNames(names);
|
|
295
|
+
// ' ' is truthy, so fullName should be returned
|
|
296
|
+
expect(result).toBe(' ');
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
it('should handle special characters in names', () => {
|
|
300
|
+
const names: IPersonNames = {
|
|
301
|
+
firstName: "O'Brien",
|
|
302
|
+
lastName: 'Smith-Jones',
|
|
303
|
+
};
|
|
304
|
+
const result = personNames(names);
|
|
305
|
+
expect(result).toBe("O'Brien Smith-Jones");
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
it('should handle unicode characters', () => {
|
|
309
|
+
const names: IPersonNames = {
|
|
310
|
+
firstName: '张',
|
|
311
|
+
lastName: '伟',
|
|
312
|
+
};
|
|
313
|
+
const result = personNames(names);
|
|
314
|
+
expect(result).toBe('张 伟');
|
|
315
|
+
});
|
|
316
|
+
});
|
|
317
|
+
});
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Pipe, PipeTransform } from '@angular/core';
|
|
2
|
+
import { IPersonNames } from '@sneat/auth-models';
|
|
3
|
+
|
|
4
|
+
@Pipe({ name: 'personNames' })
|
|
5
|
+
export class PersonNamesPipe implements PipeTransform {
|
|
6
|
+
transform(names?: IPersonNames): string | undefined {
|
|
7
|
+
if (!names) {
|
|
8
|
+
return undefined;
|
|
9
|
+
}
|
|
10
|
+
if (names.fullName) {
|
|
11
|
+
return names.fullName;
|
|
12
|
+
}
|
|
13
|
+
if (!!names.firstName && !!names.lastName) {
|
|
14
|
+
return `${names.firstName} ${names.lastName}`;
|
|
15
|
+
}
|
|
16
|
+
return JSON.stringify(names);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function personNames(name?: IPersonNames): string | undefined {
|
|
21
|
+
if (!name) {
|
|
22
|
+
return undefined;
|
|
23
|
+
}
|
|
24
|
+
if (name.fullName) {
|
|
25
|
+
return name.fullName;
|
|
26
|
+
}
|
|
27
|
+
if (name.firstName && name.lastName && !name.nickName && !name.middleName) {
|
|
28
|
+
return `${name.firstName} ${name.lastName}`;
|
|
29
|
+
}
|
|
30
|
+
return name.nickName || name.firstName || name.lastName || name.middleName;
|
|
31
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "../../../tsconfig.lib.base.json",
|
|
3
|
+
"exclude": [
|
|
4
|
+
"vite.config.ts",
|
|
5
|
+
"vite.config.mts",
|
|
6
|
+
"vitest.config.ts",
|
|
7
|
+
"vitest.config.mts",
|
|
8
|
+
"src/**/*.test.ts",
|
|
9
|
+
"src/**/*.spec.ts",
|
|
10
|
+
"src/**/*.test.tsx",
|
|
11
|
+
"src/**/*.spec.tsx",
|
|
12
|
+
"src/**/*.test.js",
|
|
13
|
+
"src/**/*.spec.js",
|
|
14
|
+
"src/**/*.test.jsx",
|
|
15
|
+
"src/**/*.spec.jsx",
|
|
16
|
+
"src/test-setup.ts",
|
|
17
|
+
"src/lib/testing/**/*"
|
|
18
|
+
]
|
|
19
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "./tsconfig.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"outDir": "../../../dist/out-tsc",
|
|
5
|
+
"types": [
|
|
6
|
+
"vitest/globals",
|
|
7
|
+
"vitest/importMeta",
|
|
8
|
+
"vite/client",
|
|
9
|
+
"node",
|
|
10
|
+
"vitest"
|
|
11
|
+
]
|
|
12
|
+
},
|
|
13
|
+
"include": [
|
|
14
|
+
"vite.config.ts",
|
|
15
|
+
"vite.config.mts",
|
|
16
|
+
"vitest.config.ts",
|
|
17
|
+
"vitest.config.mts",
|
|
18
|
+
"src/**/*.test.ts",
|
|
19
|
+
"src/**/*.spec.ts",
|
|
20
|
+
"src/**/*.test.tsx",
|
|
21
|
+
"src/**/*.spec.tsx",
|
|
22
|
+
"src/**/*.test.js",
|
|
23
|
+
"src/**/*.spec.js",
|
|
24
|
+
"src/**/*.test.jsx",
|
|
25
|
+
"src/**/*.spec.jsx",
|
|
26
|
+
"src/**/*.d.ts"
|
|
27
|
+
],
|
|
28
|
+
"files": [
|
|
29
|
+
"src/test-setup.ts"
|
|
30
|
+
]
|
|
31
|
+
}
|
package/vite.config.mts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/// <reference types='vitest' />
|
|
2
|
+
import { defineConfig } from 'vitest/config';
|
|
3
|
+
import { createBaseViteConfig } from '../../../vite.config.base';
|
|
4
|
+
|
|
5
|
+
export default defineConfig(() =>
|
|
6
|
+
createBaseViteConfig({
|
|
7
|
+
dirname: __dirname,
|
|
8
|
+
name: 'auth-ui',
|
|
9
|
+
}),
|
|
10
|
+
);
|