keycloakify 6.12.7-rc.0 → 6.12.7

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.
@@ -6,6 +6,180 @@ import { useConstCallback } from "./tools/useConstCallback";
6
6
  import { id } from "tsafe/id";
7
7
  import { emailRegexp } from "./tools/emailRegExp";
8
8
 
9
+ /** @deprecated: Will be removed in the next major. Use this instead:
10
+ * import { useFormValidation } from "keycloakify/lib/pages/shares/UserProfileCommons";
11
+ *
12
+ * The API is the same only the returned value formValidationReducer have been renamed formValidationDispatch
13
+ * (a it should have been named from the beginning 😬)
14
+ */
15
+ export function useFormValidationSlice(params: {
16
+ kcContext: {
17
+ messagesPerField: Pick<KcContextBase.Common["messagesPerField"], "existsError" | "get">;
18
+ profile: {
19
+ attributes: Attribute[];
20
+ };
21
+ passwordRequired?: boolean;
22
+ realm: { registrationEmailAsUsername: boolean };
23
+ };
24
+ /** NOTE: Try to avoid passing a new ref every render for better performances. */
25
+ passwordValidators?: Validators;
26
+ i18n: I18nBase;
27
+ }) {
28
+ const {
29
+ kcContext,
30
+ passwordValidators = {
31
+ "length": {
32
+ "ignore.empty.value": true,
33
+ "min": "4"
34
+ }
35
+ },
36
+ i18n
37
+ } = params;
38
+
39
+ const attributesWithPassword = useMemo(
40
+ () =>
41
+ !kcContext.passwordRequired
42
+ ? kcContext.profile.attributes
43
+ : (() => {
44
+ const name = kcContext.realm.registrationEmailAsUsername ? "email" : "username";
45
+
46
+ return kcContext.profile.attributes.reduce<Attribute[]>(
47
+ (prev, curr) => [
48
+ ...prev,
49
+ ...(curr.name !== name
50
+ ? [curr]
51
+ : [
52
+ curr,
53
+ id<Attribute>({
54
+ "name": "password",
55
+ "displayName": id<`\${${MessageKeyBase}}`>("${password}"),
56
+ "required": true,
57
+ "readOnly": false,
58
+ "validators": passwordValidators,
59
+ "annotations": {},
60
+ "groupAnnotations": {},
61
+ "autocomplete": "new-password"
62
+ }),
63
+ id<Attribute>({
64
+ "name": "password-confirm",
65
+ "displayName": id<`\${${MessageKeyBase}}`>("${passwordConfirm}"),
66
+ "required": true,
67
+ "readOnly": false,
68
+ "validators": {
69
+ "_compareToOther": {
70
+ "name": "password",
71
+ "ignore.empty.value": true,
72
+ "shouldBe": "equal",
73
+ "error-message": id<`\${${MessageKeyBase}}`>("${invalidPasswordConfirmMessage}")
74
+ }
75
+ },
76
+ "annotations": {},
77
+ "groupAnnotations": {},
78
+ "autocomplete": "new-password"
79
+ })
80
+ ])
81
+ ],
82
+ []
83
+ );
84
+ })(),
85
+ [kcContext, passwordValidators]
86
+ );
87
+
88
+ const { getErrors } = useGetErrors({
89
+ "kcContext": {
90
+ "messagesPerField": kcContext.messagesPerField,
91
+ "profile": {
92
+ "attributes": attributesWithPassword
93
+ }
94
+ },
95
+ i18n
96
+ });
97
+
98
+ const initialInternalState = useMemo(
99
+ () =>
100
+ Object.fromEntries(
101
+ attributesWithPassword
102
+ .map(attribute => ({
103
+ attribute,
104
+ "errors": getErrors({
105
+ "name": attribute.name,
106
+ "fieldValueByAttributeName": Object.fromEntries(
107
+ attributesWithPassword.map(({ name, value }) => [name, { "value": value ?? "" }])
108
+ )
109
+ })
110
+ }))
111
+ .map(({ attribute, errors }) => [
112
+ attribute.name,
113
+ {
114
+ "value": attribute.value ?? "",
115
+ errors,
116
+ "doDisplayPotentialErrorMessages": errors.length !== 0
117
+ }
118
+ ])
119
+ ),
120
+ [attributesWithPassword]
121
+ );
122
+
123
+ type InternalState = typeof initialInternalState;
124
+
125
+ const [formValidationInternalState, formValidationReducer] = useReducer(
126
+ (
127
+ state: InternalState,
128
+ params:
129
+ | {
130
+ action: "update value";
131
+ name: string;
132
+ newValue: string;
133
+ }
134
+ | {
135
+ action: "focus lost";
136
+ name: string;
137
+ }
138
+ ): InternalState => ({
139
+ ...state,
140
+ [params.name]: {
141
+ ...state[params.name],
142
+ ...(() => {
143
+ switch (params.action) {
144
+ case "focus lost":
145
+ return { "doDisplayPotentialErrorMessages": true };
146
+ case "update value":
147
+ return {
148
+ "value": params.newValue,
149
+ "errors": getErrors({
150
+ "name": params.name,
151
+ "fieldValueByAttributeName": {
152
+ ...state,
153
+ [params.name]: { "value": params.newValue }
154
+ }
155
+ })
156
+ };
157
+ }
158
+ })()
159
+ }
160
+ }),
161
+ initialInternalState
162
+ );
163
+
164
+ const formValidationState = useMemo(
165
+ () => ({
166
+ "fieldStateByAttributeName": Object.fromEntries(
167
+ Object.entries(formValidationInternalState).map(([name, { value, errors, doDisplayPotentialErrorMessages }]) => [
168
+ name,
169
+ { value, "displayableErrors": doDisplayPotentialErrorMessages ? errors : [] }
170
+ ])
171
+ ),
172
+ "isFormSubmittable": Object.entries(formValidationInternalState).every(
173
+ ([name, { value, errors }]) =>
174
+ errors.length === 0 && (value !== "" || !attributesWithPassword.find(attribute => attribute.name === name)!.required)
175
+ )
176
+ }),
177
+ [formValidationInternalState, attributesWithPassword]
178
+ );
179
+
180
+ return { formValidationState, formValidationReducer, attributesWithPassword };
181
+ }
182
+
9
183
  /** Expect to be used in a component wrapped within a <I18nProvider> */
10
184
  export function useGetErrors(params: {
11
185
  kcContext: {
@@ -303,175 +477,3 @@ export function useGetErrors(params: {
303
477
 
304
478
  return { getErrors };
305
479
  }
306
-
307
- /**
308
- * NOTE: The attributesWithPassword returned is actually augmented with
309
- * artificial password related attributes only if kcContext.passwordRequired === true
310
- */
311
- export function useFormValidationSlice(params: {
312
- kcContext: {
313
- messagesPerField: Pick<KcContextBase.Common["messagesPerField"], "existsError" | "get">;
314
- profile: {
315
- attributes: Attribute[];
316
- };
317
- passwordRequired?: boolean;
318
- realm: { registrationEmailAsUsername: boolean };
319
- };
320
- /** NOTE: Try to avoid passing a new ref every render for better performances. */
321
- passwordValidators?: Validators;
322
- i18n: I18nBase;
323
- }) {
324
- const {
325
- kcContext,
326
- passwordValidators = {
327
- "length": {
328
- "ignore.empty.value": true,
329
- "min": "4"
330
- }
331
- },
332
- i18n
333
- } = params;
334
-
335
- const attributesWithPassword = useMemo(
336
- () =>
337
- !kcContext.passwordRequired
338
- ? kcContext.profile.attributes
339
- : (() => {
340
- const name = kcContext.realm.registrationEmailAsUsername ? "email" : "username";
341
-
342
- return kcContext.profile.attributes.reduce<Attribute[]>(
343
- (prev, curr) => [
344
- ...prev,
345
- ...(curr.name !== name
346
- ? [curr]
347
- : [
348
- curr,
349
- id<Attribute>({
350
- "name": "password",
351
- "displayName": id<`\${${MessageKeyBase}}`>("${password}"),
352
- "required": true,
353
- "readOnly": false,
354
- "validators": passwordValidators,
355
- "annotations": {},
356
- "groupAnnotations": {},
357
- "autocomplete": "new-password"
358
- }),
359
- id<Attribute>({
360
- "name": "password-confirm",
361
- "displayName": id<`\${${MessageKeyBase}}`>("${passwordConfirm}"),
362
- "required": true,
363
- "readOnly": false,
364
- "validators": {
365
- "_compareToOther": {
366
- "name": "password",
367
- "ignore.empty.value": true,
368
- "shouldBe": "equal",
369
- "error-message": id<`\${${MessageKeyBase}}`>("${invalidPasswordConfirmMessage}")
370
- }
371
- },
372
- "annotations": {},
373
- "groupAnnotations": {},
374
- "autocomplete": "new-password"
375
- })
376
- ])
377
- ],
378
- []
379
- );
380
- })(),
381
- [kcContext, passwordValidators]
382
- );
383
-
384
- const { getErrors } = useGetErrors({
385
- "kcContext": {
386
- "messagesPerField": kcContext.messagesPerField,
387
- "profile": {
388
- "attributes": attributesWithPassword
389
- }
390
- },
391
- i18n
392
- });
393
-
394
- const initialInternalState = useMemo(
395
- () =>
396
- Object.fromEntries(
397
- attributesWithPassword
398
- .map(attribute => ({
399
- attribute,
400
- "errors": getErrors({
401
- "name": attribute.name,
402
- "fieldValueByAttributeName": Object.fromEntries(
403
- attributesWithPassword.map(({ name, value }) => [name, { "value": value ?? "" }])
404
- )
405
- })
406
- }))
407
- .map(({ attribute, errors }) => [
408
- attribute.name,
409
- {
410
- "value": attribute.value ?? "",
411
- errors,
412
- "doDisplayPotentialErrorMessages": errors.length !== 0
413
- }
414
- ])
415
- ),
416
- [attributesWithPassword]
417
- );
418
-
419
- type InternalState = typeof initialInternalState;
420
-
421
- const [formValidationInternalState, formValidationReducer] = useReducer(
422
- (
423
- state: InternalState,
424
- params:
425
- | {
426
- action: "update value";
427
- name: string;
428
- newValue: string;
429
- }
430
- | {
431
- action: "focus lost";
432
- name: string;
433
- }
434
- ): InternalState => ({
435
- ...state,
436
- [params.name]: {
437
- ...state[params.name],
438
- ...(() => {
439
- switch (params.action) {
440
- case "focus lost":
441
- return { "doDisplayPotentialErrorMessages": true };
442
- case "update value":
443
- return {
444
- "value": params.newValue,
445
- "errors": getErrors({
446
- "name": params.name,
447
- "fieldValueByAttributeName": {
448
- ...state,
449
- [params.name]: { "value": params.newValue }
450
- }
451
- })
452
- };
453
- }
454
- })()
455
- }
456
- }),
457
- initialInternalState
458
- );
459
-
460
- const formValidationState = useMemo(
461
- () => ({
462
- "fieldStateByAttributeName": Object.fromEntries(
463
- Object.entries(formValidationInternalState).map(([name, { value, errors, doDisplayPotentialErrorMessages }]) => [
464
- name,
465
- { value, "displayableErrors": doDisplayPotentialErrorMessages ? errors : [] }
466
- ])
467
- ),
468
- "isFormSubmittable": Object.entries(formValidationInternalState).every(
469
- ([name, { value, errors }]) =>
470
- errors.length === 0 && (value !== "" || !attributesWithPassword.find(attribute => attribute.name === name)!.required)
471
- )
472
- }),
473
- [formValidationInternalState, attributesWithPassword]
474
- );
475
-
476
- return { formValidationState, formValidationReducer, attributesWithPassword };
477
- }