dauth-context-react 6.2.0 → 6.3.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dauth-context-react",
3
- "version": "6.2.0",
3
+ "version": "6.3.0",
4
4
  "description": "React provider and hook for passwordless authentication via the Dauth service (BFF pattern with httpOnly cookies)",
5
5
  "license": "MIT",
6
6
  "author": "David T. Pizarro Frick",
@@ -314,6 +314,12 @@ export function DauthProfileModal({
314
314
  const [lastname, setLastname] = useState('');
315
315
  const [nickname, setNickname] = useState('');
316
316
  const [country, setCountry] = useState('');
317
+ const [telPrefix, setTelPrefix] = useState('');
318
+ const [telSuffix, setTelSuffix] = useState('');
319
+ const [birthDate, setBirthDate] = useState('');
320
+ const [customFieldValues, setCustomFieldValues] = useState<
321
+ Record<string, string>
322
+ >({});
317
323
  const [populated, setPopulated] = useState(false);
318
324
 
319
325
  // Status
@@ -352,6 +358,20 @@ export function DauthProfileModal({
352
358
  setLastname(user.lastname || '');
353
359
  setNickname(user.nickname || '');
354
360
  setCountry(user.country || '');
361
+ setTelPrefix(user.telPrefix || '');
362
+ setTelSuffix(user.telSuffix || '');
363
+ setBirthDate(
364
+ user.birthDate
365
+ ? new Date(user.birthDate)
366
+ .toISOString()
367
+ .split('T')[0]
368
+ : ''
369
+ );
370
+ const cf: Record<string, string> = {};
371
+ for (const f of domain.customFields ?? []) {
372
+ cf[f.key] = user.customFields?.[f.key] ?? '';
373
+ }
374
+ setCustomFieldValues(cf);
355
375
  setPopulated(true);
356
376
  }
357
377
  if (!open) {
@@ -414,13 +434,36 @@ export function DauthProfileModal({
414
434
 
415
435
  const hasChanges = useMemo(() => {
416
436
  if (!user?._id) return false;
437
+ const origBirthDate = user.birthDate
438
+ ? new Date(user.birthDate).toISOString().split('T')[0]
439
+ : '';
440
+ const cfChanged = (domain.customFields ?? []).some(
441
+ (f) =>
442
+ (customFieldValues[f.key] ?? '') !==
443
+ (user.customFields?.[f.key] ?? '')
444
+ );
417
445
  return (
418
446
  name !== (user.name || '') ||
419
447
  lastname !== (user.lastname || '') ||
420
448
  nickname !== (user.nickname || '') ||
421
- country !== (user.country || '')
449
+ country !== (user.country || '') ||
450
+ telPrefix !== (user.telPrefix || '') ||
451
+ telSuffix !== (user.telSuffix || '') ||
452
+ birthDate !== origBirthDate ||
453
+ cfChanged
422
454
  );
423
- }, [name, lastname, nickname, country, user]);
455
+ }, [
456
+ name,
457
+ lastname,
458
+ nickname,
459
+ country,
460
+ telPrefix,
461
+ telSuffix,
462
+ birthDate,
463
+ customFieldValues,
464
+ user,
465
+ domain.customFields,
466
+ ]);
424
467
 
425
468
  const canSave =
426
469
  name.trim().length > 0 && hasChanges && !saving;
@@ -428,10 +471,18 @@ export function DauthProfileModal({
428
471
  const handleSave = useCallback(async () => {
429
472
  setSaving(true);
430
473
  setStatus(null);
431
- const fields: Record<string, string> = { name };
474
+ const fields: Record<string, any> = { name };
432
475
  if (hasField('lastname')) fields.lastname = lastname;
433
476
  if (hasField('nickname')) fields.nickname = nickname;
434
477
  if (hasField('country')) fields.country = country;
478
+ if (hasField('tel_prefix'))
479
+ fields.telPrefix = telPrefix;
480
+ if (hasField('tel_suffix'))
481
+ fields.telSuffix = telSuffix;
482
+ if (hasField('birth_date') && birthDate)
483
+ fields.birthDate = birthDate;
484
+ if ((domain.customFields ?? []).length > 0)
485
+ fields.customFields = customFieldValues;
435
486
  const ok = await updateUser(fields);
436
487
  setSaving(false);
437
488
  if (ok) {
@@ -445,7 +496,19 @@ export function DauthProfileModal({
445
496
  message: 'Something went wrong. Please try again.',
446
497
  });
447
498
  }
448
- }, [name, lastname, nickname, country, hasField, updateUser]);
499
+ }, [
500
+ name,
501
+ lastname,
502
+ nickname,
503
+ country,
504
+ telPrefix,
505
+ telSuffix,
506
+ birthDate,
507
+ customFieldValues,
508
+ hasField,
509
+ updateUser,
510
+ domain.customFields,
511
+ ]);
449
512
 
450
513
  const handleDelete = useCallback(async () => {
451
514
  setDeleting(true);
@@ -862,6 +925,133 @@ export function DauthProfileModal({
862
925
  />
863
926
  </div>
864
927
  )}
928
+
929
+ {(hasField('tel_prefix') ||
930
+ hasField('tel_suffix')) && (
931
+ <div style={fieldGroup}>
932
+ <div style={label}>
933
+ Phone
934
+ {isRequired('tel_prefix') ||
935
+ isRequired('tel_suffix')
936
+ ? ' *'
937
+ : ''}
938
+ </div>
939
+ <div
940
+ style={{
941
+ display: 'flex',
942
+ gap: 8,
943
+ }}
944
+ >
945
+ {hasField('tel_prefix') && (
946
+ <input
947
+ id="dauth-tel-prefix"
948
+ type="text"
949
+ value={telPrefix}
950
+ onChange={(e) =>
951
+ setTelPrefix(e.target.value)
952
+ }
953
+ placeholder="+34"
954
+ disabled={saving}
955
+ style={{
956
+ ...input,
957
+ width: 80,
958
+ flexShrink: 0,
959
+ }}
960
+ onFocus={inputFocusHandler}
961
+ onBlur={inputBlurHandler}
962
+ aria-label="Phone prefix"
963
+ />
964
+ )}
965
+ {hasField('tel_suffix') && (
966
+ <input
967
+ id="dauth-tel-suffix"
968
+ type="tel"
969
+ value={telSuffix}
970
+ onChange={(e) =>
971
+ setTelSuffix(e.target.value)
972
+ }
973
+ placeholder="612 345 678"
974
+ disabled={saving}
975
+ style={{
976
+ ...input,
977
+ flex: 1,
978
+ }}
979
+ onFocus={inputFocusHandler}
980
+ onBlur={inputBlurHandler}
981
+ aria-label="Phone number"
982
+ />
983
+ )}
984
+ </div>
985
+ </div>
986
+ )}
987
+
988
+ {hasField('birth_date') && (
989
+ <div style={fieldGroup}>
990
+ <label
991
+ htmlFor="dauth-birthdate"
992
+ style={label}
993
+ >
994
+ Birth date
995
+ {isRequired('birth_date')
996
+ ? ' *'
997
+ : ''}
998
+ </label>
999
+ <input
1000
+ id="dauth-birthdate"
1001
+ type="date"
1002
+ value={birthDate}
1003
+ onChange={(e) =>
1004
+ setBirthDate(e.target.value)
1005
+ }
1006
+ disabled={saving}
1007
+ style={input}
1008
+ onFocus={inputFocusHandler}
1009
+ onBlur={inputBlurHandler}
1010
+ />
1011
+ </div>
1012
+ )}
1013
+
1014
+ {(domain.customFields ?? []).length >
1015
+ 0 && (
1016
+ <>
1017
+ <hr style={separator} />
1018
+ {domain.customFields!.map((cf) => (
1019
+ <div
1020
+ key={cf.key}
1021
+ style={fieldGroup}
1022
+ >
1023
+ <label
1024
+ htmlFor={`dauth-cf-${cf.key}`}
1025
+ style={label}
1026
+ >
1027
+ {cf.label}
1028
+ {cf.required ? ' *' : ''}
1029
+ </label>
1030
+ <input
1031
+ id={`dauth-cf-${cf.key}`}
1032
+ type="text"
1033
+ value={
1034
+ customFieldValues[cf.key] ??
1035
+ ''
1036
+ }
1037
+ onChange={(e) =>
1038
+ setCustomFieldValues(
1039
+ (prev) => ({
1040
+ ...prev,
1041
+ [cf.key]:
1042
+ e.target.value,
1043
+ })
1044
+ )
1045
+ }
1046
+ disabled={saving}
1047
+ style={input}
1048
+ onFocus={inputFocusHandler}
1049
+ onBlur={inputBlurHandler}
1050
+ />
1051
+ </div>
1052
+ ))}
1053
+ </>
1054
+ )}
865
1055
  </div>
866
1056
 
867
1057
  {/* Language selector */}
package/src/index.tsx CHANGED
@@ -17,6 +17,7 @@ import type {
17
17
  IDauthAuthMethods,
18
18
  IDauthUser,
19
19
  IFormField,
20
+ ICustomField,
20
21
  IModalTheme,
21
22
  IPasskeyCredential,
22
23
  DauthProfileModalProps,
@@ -27,6 +28,7 @@ export type {
27
28
  IDauthProviderProps,
28
29
  IDauthAuthMethods,
29
30
  IFormField,
31
+ ICustomField,
30
32
  IModalTheme,
31
33
  IPasskeyCredential,
32
34
  DauthProfileModalProps,
package/src/interfaces.ts CHANGED
@@ -16,6 +16,7 @@ export interface IDauthUser {
16
16
  birthDate?: Date;
17
17
  country?: string;
18
18
  metadata?: Record<string, unknown>;
19
+ customFields?: Record<string, string>;
19
20
  createdAt: Date;
20
21
  updatedAt: Date;
21
22
  lastLogin: Date;
@@ -36,6 +37,12 @@ export interface IFormField {
36
37
  required: boolean;
37
38
  }
38
39
 
40
+ export interface ICustomField {
41
+ key: string;
42
+ label: string;
43
+ required: boolean;
44
+ }
45
+
39
46
  export interface IModalTheme {
40
47
  accent?: string;
41
48
  accentHover?: string;
@@ -53,6 +60,7 @@ export interface IDauthDomainState {
53
60
  allowedOrigins: string[];
54
61
  authMethods?: IDauthAuthMethods;
55
62
  formFields?: IFormField[];
63
+ customFields?: ICustomField[];
56
64
  modalTheme?: IModalTheme;
57
65
  }
58
66