@thunderid/react 1.13.0 → 1.14.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.
Files changed (61) hide show
  1. package/dist/api/auth/executeEmbeddedSelfFlow.d.ts +36 -0
  2. package/dist/api/auth/executeEmbeddedSelfFlow.d.ts.map +1 -0
  3. package/dist/api/auth/executeEmbeddedSelfFlow.js +30 -0
  4. package/dist/api/auth/executeEmbeddedSelfFlow.js.map +1 -0
  5. package/dist/cjs/api/auth/executeEmbeddedSelfFlow.cjs +32 -0
  6. package/dist/cjs/api/auth/executeEmbeddedSelfFlow.cjs.map +1 -0
  7. package/dist/cjs/components/account/UserProfile/BaseUserProfile.cjs +195 -46
  8. package/dist/cjs/components/account/UserProfile/BaseUserProfile.cjs.map +1 -1
  9. package/dist/cjs/components/account/UserProfile/BaseUserProfile.styles.cjs +57 -4
  10. package/dist/cjs/components/account/UserProfile/BaseUserProfile.styles.cjs.map +1 -1
  11. package/dist/cjs/components/account/UserProfile/UserProfile.cjs +13 -1
  12. package/dist/cjs/components/account/UserProfile/UserProfile.cjs.map +1 -1
  13. package/dist/cjs/components/account/VerifyAttribute/BaseVerifyAttribute.cjs +358 -0
  14. package/dist/cjs/components/account/VerifyAttribute/BaseVerifyAttribute.cjs.map +1 -0
  15. package/dist/cjs/components/account/VerifyAttribute/BaseVerifyAttribute.styles.cjs +84 -0
  16. package/dist/cjs/components/account/VerifyAttribute/BaseVerifyAttribute.styles.cjs.map +1 -0
  17. package/dist/cjs/components/account/VerifyAttribute/VerifyAttribute.cjs +94 -0
  18. package/dist/cjs/components/account/VerifyAttribute/VerifyAttribute.cjs.map +1 -0
  19. package/dist/cjs/components/auth/flow/AuthOptionFactory.cjs +20 -0
  20. package/dist/cjs/components/auth/flow/AuthOptionFactory.cjs.map +1 -1
  21. package/dist/cjs/contexts/ComponentRenderer/ComponentRendererContext.cjs.map +1 -1
  22. package/dist/cjs/contexts/ThunderID/ThunderIDProvider.cjs +14 -0
  23. package/dist/cjs/contexts/ThunderID/ThunderIDProvider.cjs.map +1 -1
  24. package/dist/cjs/index.cjs +30 -0
  25. package/dist/components/account/UserProfile/BaseUserProfile.d.ts +27 -1
  26. package/dist/components/account/UserProfile/BaseUserProfile.d.ts.map +1 -1
  27. package/dist/components/account/UserProfile/BaseUserProfile.js +197 -48
  28. package/dist/components/account/UserProfile/BaseUserProfile.js.map +1 -1
  29. package/dist/components/account/UserProfile/BaseUserProfile.styles.d.ts.map +1 -1
  30. package/dist/components/account/UserProfile/BaseUserProfile.styles.js +57 -4
  31. package/dist/components/account/UserProfile/BaseUserProfile.styles.js.map +1 -1
  32. package/dist/components/account/UserProfile/UserProfile.d.ts +7 -1
  33. package/dist/components/account/UserProfile/UserProfile.d.ts.map +1 -1
  34. package/dist/components/account/UserProfile/UserProfile.js +14 -2
  35. package/dist/components/account/UserProfile/UserProfile.js.map +1 -1
  36. package/dist/components/account/VerifyAttribute/BaseVerifyAttribute.d.ts +113 -0
  37. package/dist/components/account/VerifyAttribute/BaseVerifyAttribute.d.ts.map +1 -0
  38. package/dist/components/account/VerifyAttribute/BaseVerifyAttribute.js +354 -0
  39. package/dist/components/account/VerifyAttribute/BaseVerifyAttribute.js.map +1 -0
  40. package/dist/components/account/VerifyAttribute/BaseVerifyAttribute.styles.d.ts +10 -0
  41. package/dist/components/account/VerifyAttribute/BaseVerifyAttribute.styles.d.ts.map +1 -0
  42. package/dist/components/account/VerifyAttribute/BaseVerifyAttribute.styles.js +82 -0
  43. package/dist/components/account/VerifyAttribute/BaseVerifyAttribute.styles.js.map +1 -0
  44. package/dist/components/account/VerifyAttribute/VerifyAttribute.d.ts +41 -0
  45. package/dist/components/account/VerifyAttribute/VerifyAttribute.d.ts.map +1 -0
  46. package/dist/components/account/VerifyAttribute/VerifyAttribute.js +90 -0
  47. package/dist/components/account/VerifyAttribute/VerifyAttribute.js.map +1 -0
  48. package/dist/components/auth/flow/AuthOptionFactory.d.ts +5 -1
  49. package/dist/components/auth/flow/AuthOptionFactory.d.ts.map +1 -1
  50. package/dist/components/auth/flow/AuthOptionFactory.js +20 -1
  51. package/dist/components/auth/flow/AuthOptionFactory.js.map +1 -1
  52. package/dist/contexts/ComponentRenderer/ComponentRendererContext.d.ts +1 -1
  53. package/dist/contexts/ComponentRenderer/ComponentRendererContext.d.ts.map +1 -1
  54. package/dist/contexts/ComponentRenderer/ComponentRendererContext.js.map +1 -1
  55. package/dist/contexts/ThunderID/ThunderIDProvider.d.ts.map +1 -1
  56. package/dist/contexts/ThunderID/ThunderIDProvider.js +14 -0
  57. package/dist/contexts/ThunderID/ThunderIDProvider.js.map +1 -1
  58. package/dist/index.d.ts +7 -1
  59. package/dist/index.d.ts.map +1 -1
  60. package/dist/index.js +5 -2
  61. package/package.json +2 -2
@@ -103,6 +103,9 @@ const require_User$1 = require('./components/account/User/User.cjs');
103
103
  const require_MultiInput = require('./components/primitives/MultiInput/MultiInput.cjs');
104
104
  const require_BaseUserProfile = require('./components/account/UserProfile/BaseUserProfile.cjs');
105
105
  const require_updateMeProfile = require('./api/account/updateMeProfile.cjs');
106
+ const require_BaseVerifyAttribute = require('./components/account/VerifyAttribute/BaseVerifyAttribute.cjs');
107
+ const require_executeEmbeddedSelfFlow = require('./api/auth/executeEmbeddedSelfFlow.cjs');
108
+ const require_VerifyAttribute = require('./components/account/VerifyAttribute/VerifyAttribute.cjs');
106
109
  const require_UserProfile = require('./components/account/UserProfile/UserProfile.cjs');
107
110
  const require_DataTable = require('./components/primitives/DataTable/DataTable.cjs');
108
111
  const require_BaseUserList = require('./components/admin/UserList/BaseUserList.cjs');
@@ -241,6 +244,12 @@ Object.defineProperty(exports, 'ApplicationQueryKeys', {
241
244
  return __thunderid_browser.ApplicationQueryKeys;
242
245
  }
243
246
  });
247
+ Object.defineProperty(exports, 'AttributeVerificationConstants', {
248
+ enumerable: true,
249
+ get: function () {
250
+ return __thunderid_browser.AttributeVerificationConstants;
251
+ }
252
+ });
244
253
  exports.Attribution = require_Attribution.default;
245
254
  exports.AuthFlowSelect = require_AuthFlowSelect.default;
246
255
  exports.BaseAcceptInvite = require_BaseAcceptInvite.default;
@@ -277,6 +286,7 @@ exports.BaseUserList = require_BaseUserList.default;
277
286
  exports.BaseUserProfile = require_BaseUserProfile.default;
278
287
  exports.BaseUserSelect = require_BaseUserSelect.default;
279
288
  exports.BaseUserTypeSelect = require_BaseUserTypeSelect.default;
289
+ exports.BaseVerifyAttribute = require_BaseVerifyAttribute.default;
280
290
  exports.BuildingAlt = require_BuildingAlt.default;
281
291
  exports.Button = require_Button.default;
282
292
  exports.CONSENT_DETAIL_DISPLAY_LIMITS = require_getConsentDetailLayout.CONSENT_DETAIL_DISPLAY_LIMITS;
@@ -348,6 +358,12 @@ Object.defineProperty(exports, 'EmbeddedRecoveryFlowType', {
348
358
  return __thunderid_browser.EmbeddedRecoveryFlowType;
349
359
  }
350
360
  });
361
+ Object.defineProperty(exports, 'EmbeddedSelfFlowStatus', {
362
+ enumerable: true,
363
+ get: function () {
364
+ return __thunderid_browser.EmbeddedSelfFlowStatus;
365
+ }
366
+ });
351
367
  Object.defineProperty(exports, 'EmbeddedSignInFlowStatus', {
352
368
  enumerable: true,
353
369
  get: function () {
@@ -469,6 +485,7 @@ Object.defineProperty(exports, 'UserSelectConstants', {
469
485
  }
470
486
  });
471
487
  exports.UserTypeSelect = require_UserTypeSelect.default;
488
+ exports.VerifyAttribute = require_VerifyAttribute.default;
472
489
  Object.defineProperty(exports, 'addGroupMembers', {
473
490
  enumerable: true,
474
491
  get: function () {
@@ -824,6 +841,7 @@ Object.defineProperty(exports, 'executeAdministrationFlow', {
824
841
  return __thunderid_browser.executeAdministrationFlow;
825
842
  }
826
843
  });
844
+ exports.executeEmbeddedSelfFlow = require_executeEmbeddedSelfFlow.default;
827
845
  Object.defineProperty(exports, 'exportConfiguration', {
828
846
  enumerable: true,
829
847
  get: function () {
@@ -1352,6 +1370,12 @@ Object.defineProperty(exports, 'getVariables', {
1352
1370
  return __thunderid_browser.getVariables;
1353
1371
  }
1354
1372
  });
1373
+ Object.defineProperty(exports, 'getVerifiedAttributes', {
1374
+ enumerable: true,
1375
+ get: function () {
1376
+ return __thunderid_browser.getVerifiedAttributes;
1377
+ }
1378
+ });
1355
1379
  Object.defineProperty(exports, 'hasPermission', {
1356
1380
  enumerable: true,
1357
1381
  get: function () {
@@ -1385,6 +1409,12 @@ Object.defineProperty(exports, 'isEmojiUri', {
1385
1409
  return __thunderid_browser.isEmojiUri;
1386
1410
  }
1387
1411
  });
1412
+ Object.defineProperty(exports, 'isVerifiableAttribute', {
1413
+ enumerable: true,
1414
+ get: function () {
1415
+ return __thunderid_browser.isVerifiableAttribute;
1416
+ }
1417
+ });
1388
1418
  Object.defineProperty(exports, 'navigate', {
1389
1419
  enumerable: true,
1390
1420
  get: function () {
@@ -1,5 +1,5 @@
1
1
  import { User, Preferences, AttributeSchema } from '@thunderid/browser';
2
- import { FC, ReactElement } from 'react';
2
+ import { FC, ReactElement, ReactNode } from 'react';
3
3
  export interface BaseUserProfileProps {
4
4
  attributeMapping?: {
5
5
  [key: string]: string | string[] | undefined;
@@ -28,10 +28,36 @@ export interface BaseUserProfileProps {
28
28
  */
29
29
  preferences?: Preferences;
30
30
  profile?: User;
31
+ /**
32
+ * Renders the verification panel for an attribute. When omitted, or when the profile is not
33
+ * editable, verification statuses are shown without a Verify action.
34
+ */
35
+ renderVerification?: (props: BaseUserProfileVerificationRenderProps) => ReactNode;
31
36
  showFields?: string[];
32
37
  title?: string;
33
38
  userSchema?: Record<string, AttributeSchema> | null;
34
39
  }
40
+ /**
41
+ * Props passed to `renderVerification`.
42
+ */
43
+ export interface BaseUserProfileVerificationRenderProps {
44
+ /**
45
+ * Name of the attribute to verify.
46
+ */
47
+ attribute: string;
48
+ /**
49
+ * Label of the attribute.
50
+ */
51
+ attributeDisplayName: string;
52
+ /**
53
+ * Closes the panel.
54
+ */
55
+ onCancel: () => void;
56
+ /**
57
+ * Closes the panel and confirms the recorded verification.
58
+ */
59
+ onComplete: () => void;
60
+ }
35
61
  declare const BaseUserProfile: FC<BaseUserProfileProps>;
36
62
  export default BaseUserProfile;
37
63
  //# sourceMappingURL=BaseUserProfile.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"BaseUserProfile.d.ts","sourceRoot":"","sources":["../../../../src/components/account/UserProfile/BaseUserProfile.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAC,IAAI,EAAiC,WAAW,EAAa,eAAe,EAAC,MAAM,oBAAoB,CAAC;AAChH,OAAO,EAAC,EAAE,EAAE,YAAY,EAAmC,MAAM,OAAO,CAAC;AAyCzE,MAAM,WAAW,oBAAoB;IACnC,gBAAgB,CAAC,EAAE;QACjB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC;QAC7C,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;QAC9B,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;QAC7B,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;QAC5B,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;KAC9B,CAAC;IACF,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,qBAAqB,CAAC,EAAE,MAAM,EAAE,CAAC;IACjC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,QAAQ,CAAC,EAAE,YAAY,GAAG,IAAI,CAAC;IAC/B,gBAAgB,CAAC,EAAE,IAAI,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,IAAI,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC;IAC1B,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACvC,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3C,IAAI,CAAC,EAAE,OAAO,CAAC;IACf;;;;OAIG;IACH,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,OAAO,CAAC,EAAE,IAAI,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IAEtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,GAAG,IAAI,CAAC;CACrD;AA+BD,QAAA,MAAM,eAAe,EAAE,EAAE,CAAC,oBAAoB,CAopB7C,CAAC;AAEF,eAAe,eAAe,CAAC"}
1
+ {"version":3,"file":"BaseUserProfile.d.ts","sourceRoot":"","sources":["../../../../src/components/account/UserProfile/BaseUserProfile.tsx"],"names":[],"mappings":"AAGA,OAAO,EACL,IAAI,EAGJ,WAAW,EAEX,eAAe,EAKhB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAC,EAAE,EAAE,YAAY,EAAE,SAAS,EAA4C,MAAM,OAAO,CAAC;AA0C7F,MAAM,WAAW,oBAAoB;IACnC,gBAAgB,CAAC,EAAE;QACjB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC;QAC7C,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;QAC9B,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;QAC7B,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;QAC5B,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;KAC9B,CAAC;IACF,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,qBAAqB,CAAC,EAAE,MAAM,EAAE,CAAC;IACjC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,QAAQ,CAAC,EAAE,YAAY,GAAG,IAAI,CAAC;IAC/B,gBAAgB,CAAC,EAAE,IAAI,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,IAAI,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC;IAC1B,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACvC,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3C,IAAI,CAAC,EAAE,OAAO,CAAC;IACf;;;;OAIG;IACH,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,OAAO,CAAC,EAAE,IAAI,CAAC;IACf;;;OAGG;IACH,kBAAkB,CAAC,EAAE,CAAC,KAAK,EAAE,sCAAsC,KAAK,SAAS,CAAC;IAClF,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IAEtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,GAAG,IAAI,CAAC;CACrD;AAED;;GAEG;AACH,MAAM,WAAW,sCAAsC;IACrD;;OAEG;IACH,SAAS,EAAE,MAAM,CAAC;IAClB;;OAEG;IACH,oBAAoB,EAAE,MAAM,CAAC;IAC7B;;OAEG;IACH,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB;;OAEG;IACH,UAAU,EAAE,MAAM,IAAI,CAAC;CACxB;AAsCD,QAAA,MAAM,eAAe,EAAE,EAAE,CAAC,oBAAoB,CAo3B7C,CAAC;AAEF,eAAe,eAAe,CAAC"}
@@ -4,6 +4,8 @@ import useTranslation_default from "../../../hooks/useTranslation.js";
4
4
  import Button_default from "../../primitives/Button/Button.js";
5
5
  import Typography_default from "../../primitives/Typography/Typography.js";
6
6
  import Card_default from "../../primitives/Card/Card.js";
7
+ import CircleAlert_default from "../../primitives/Icons/CircleAlert.js";
8
+ import CircleCheck_default from "../../primitives/Icons/CircleCheck.js";
7
9
  import Alert_default from "../../primitives/Alert/Alert.js";
8
10
  import TextField_default from "../../primitives/TextField/TextField.js";
9
11
  import Checkbox_default from "../../primitives/Checkbox/Checkbox.js";
@@ -15,8 +17,8 @@ import getDisplayName_default from "../../../utils/getDisplayName.js";
15
17
  import { Avatar } from "../../primitives/Avatar/Avatar.js";
16
18
  import Dialog_default from "../../primitives/Dialog/Dialog.js";
17
19
  import MultiInput_default from "../../primitives/MultiInput/MultiInput.js";
18
- import { bem, startCase, withVendorCSSClassPrefix } from "@thunderid/browser";
19
- import { useCallback, useEffect, useState } from "react";
20
+ import { AttributeVerificationConstants, bem, getVerifiedAttributes, isVerifiableAttribute, startCase, withVendorCSSClassPrefix } from "@thunderid/browser";
21
+ import { useCallback, useEffect, useMemo, useState } from "react";
20
22
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
21
23
 
22
24
  //#region src/components/account/UserProfile/BaseUserProfile.tsx
@@ -42,7 +44,8 @@ const fieldsToSkip = [
42
44
  "attributes",
43
45
  "picture",
44
46
  "isReadOnly",
45
- "isReadonly"
47
+ "isReadonly",
48
+ AttributeVerificationConstants.VERIFIED_ATTRIBUTES_KEY
46
49
  ];
47
50
  const readonlyFields = [
48
51
  "attributes",
@@ -52,12 +55,44 @@ const readonlyFields = [
52
55
  "username",
53
56
  "sub"
54
57
  ];
55
- const BaseUserProfile = ({ fallback = null, className = "", cardLayout = true, profile, flattenedProfile, userSchema, mode = "inline", title, attributeMapping = {}, editable = true, onOpenChange, onUpdate, open = false, error = null, isLoading = false, preferences, showFields = [], hideFields = [], displayNameAttributes = [] }) => {
58
+ const isStatusType = (type) => !!type && AttributeVerificationConstants.VERIFIABLE_ATTRIBUTE_TYPES.includes(type.toLowerCase());
59
+ const isVerifiedAfterSave = (type) => !!type && AttributeVerificationConstants.VERIFY_AFTER_SAVE_ATTRIBUTE_TYPES.includes(type.toLowerCase());
60
+ const BaseUserProfile = ({ fallback = null, className = "", cardLayout = true, profile, flattenedProfile, userSchema, mode = "inline", title, attributeMapping = {}, editable = true, onOpenChange, onUpdate, open = false, error = null, isLoading = false, preferences, showFields = [], hideFields = [], displayNameAttributes = [], renderVerification = void 0 }) => {
56
61
  const { theme, colorScheme } = useTheme_default();
57
62
  const [editedUser, setEditedUser] = useState(flattenedProfile || profile);
58
63
  const [editingFields, setEditingFields] = useState({});
59
64
  const [fieldErrors, setFieldErrors] = useState({});
60
- const { t } = useTranslation_default(preferences?.i18n);
65
+ const [verifyingField, setVerifyingField] = useState(null);
66
+ const [verifiedNotice, setVerifiedNotice] = useState(null);
67
+ const [pendingVerification, setPendingVerification] = useState(null);
68
+ const [savingFields, setSavingFields] = useState({});
69
+ const { t, currentLanguage } = useTranslation_default(preferences?.i18n);
70
+ const reportedVerifiedAttributes = useMemo(() => getVerifiedAttributes(profile ?? flattenedProfile), [profile, flattenedProfile]);
71
+ const supportsVerification = reportedVerifiedAttributes !== void 0;
72
+ const verifiedAttributes = useMemo(() => reportedVerifiedAttributes ?? {}, [reportedVerifiedAttributes]);
73
+ useEffect(() => {
74
+ if (!pendingVerification) return;
75
+ if (error) {
76
+ setPendingVerification(null);
77
+ return;
78
+ }
79
+ const { name, previousValue } = pendingVerification;
80
+ const storedUser = flattenedProfile ?? profile;
81
+ const storedValue = (storedUser?.["attributes"])?.[name] ?? storedUser?.[name];
82
+ if (storedValue === previousValue) return;
83
+ if (supportsVerification && typeof storedValue === "string" && storedValue.trim() !== "" && !verifiedAttributes[name]) {
84
+ setVerifiedNotice(null);
85
+ setVerifyingField(name);
86
+ }
87
+ setPendingVerification(null);
88
+ }, [
89
+ pendingVerification,
90
+ flattenedProfile,
91
+ profile,
92
+ error,
93
+ verifiedAttributes,
94
+ supportsVerification
95
+ ]);
61
96
  useEffect(() => {
62
97
  const nextUser = flattenedProfile ?? profile;
63
98
  if (!nextUser) return;
@@ -112,6 +147,7 @@ const BaseUserProfile = ({ fallback = null, className = "", cardLayout = true, p
112
147
  }, [t]);
113
148
  const formatLabel = useCallback((key) => key.split(/(?=[A-Z])|_/).map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join(" "), []);
114
149
  const styles = BaseUserProfile_styles_default(theme, colorScheme);
150
+ const verificationStyles = styles;
115
151
  const ObjectDisplay = ({ data }) => {
116
152
  if (!data || typeof data !== "object") return null;
117
153
  return /* @__PURE__ */ jsx("table", {
@@ -172,15 +208,32 @@ const BaseUserProfile = ({ fallback = null, className = "", cardLayout = true, p
172
208
  });
173
209
  let payload = {};
174
210
  set(payload, fieldName, fieldValue);
175
- onUpdate(payload);
211
+ setSavingFields((prev) => ({
212
+ ...prev,
213
+ [fieldName]: true
214
+ }));
215
+ Promise.resolve(onUpdate(payload)).catch(() => setPendingVerification(null)).finally(() => setSavingFields((prev) => {
216
+ const next = { ...prev };
217
+ delete next[fieldName];
218
+ return next;
219
+ }));
176
220
  toggleFieldEdit(fieldName);
221
+ const savedUser = flattenedProfile ?? profile;
222
+ const storedValue = (savedUser?.["attributes"])?.[fieldName] ?? savedUser?.[fieldName];
223
+ if (renderVerification && isVerifiedAfterSave(schema.type) && isVerifiableAttribute(userSchema, fieldName) && typeof fieldValue === "string" && fieldValue.trim() !== "" && fieldValue !== storedValue) setPendingVerification({
224
+ name: fieldName,
225
+ previousValue: storedValue
226
+ });
227
+ else setPendingVerification(null);
177
228
  }, [
178
229
  editedUser,
179
230
  flattenedProfile,
180
231
  profile,
181
232
  onUpdate,
182
233
  toggleFieldEdit,
183
- t
234
+ t,
235
+ renderVerification,
236
+ userSchema
184
237
  ]);
185
238
  const handleFieldCancel = useCallback((fieldName) => {
186
239
  const currentUser$1 = flattenedProfile || profile;
@@ -359,53 +412,142 @@ const BaseUserProfile = ({ fallback = null, className = "", cardLayout = true, p
359
412
  }) : displayValue
360
413
  })] });
361
414
  };
415
+ const renderVerificationStatus = (schema) => {
416
+ const verification = verifiedAttributes[schema.name];
417
+ let verifiedAtTitle;
418
+ if (verification?.verifiedAt) {
419
+ const verifiedAt = new Date(verification.verifiedAt);
420
+ verifiedAtTitle = t("user.verification.status.verified_at", { date: Number.isNaN(verifiedAt.getTime()) ? verification.verifiedAt : verifiedAt.toLocaleString(currentLanguage) });
421
+ }
422
+ return /* @__PURE__ */ jsxs("span", {
423
+ className: cx(withVendorCSSClassPrefix(bem("user-profile", "verification-status")), withVendorCSSClassPrefix(bem("user-profile", "verification-status", verification ? "verified" : "unverified")), verificationStyles["verificationStatus"], verification ? verificationStyles["verified"] : verificationStyles["unverified"]),
424
+ title: verifiedAtTitle,
425
+ "data-testid": `thunderid-verification-status-${schema.name}`,
426
+ children: [
427
+ verification ? /* @__PURE__ */ jsx(CircleCheck_default, {
428
+ width: 12,
429
+ height: 12,
430
+ "aria-hidden": "true"
431
+ }) : /* @__PURE__ */ jsx(CircleAlert_default, {
432
+ width: 12,
433
+ height: 12,
434
+ "aria-hidden": "true"
435
+ }),
436
+ verification ? t("user.verification.status.verified") : t("user.verification.status.unverified"),
437
+ verifiedAtTitle && /* @__PURE__ */ jsx("span", {
438
+ className: verificationStyles["visuallyHidden"],
439
+ children: ` (${verifiedAtTitle})`
440
+ })
441
+ ]
442
+ });
443
+ };
444
+ const renderVerificationPanel = (schema) => {
445
+ if (!renderVerification || !schema.name || verifyingField !== schema.name) return null;
446
+ const attributeDisplayName = schema.displayName ?? startCase(schema.name);
447
+ const panel = /* @__PURE__ */ jsx("div", {
448
+ className: cx(withVendorCSSClassPrefix(bem("user-profile", "verification")), verificationStyles["verification"], mode === "popup" ? verificationStyles["verificationInline"] : ""),
449
+ children: renderVerification({
450
+ attribute: schema.name,
451
+ attributeDisplayName,
452
+ onCancel: () => setVerifyingField(null),
453
+ onComplete: () => {
454
+ setVerifyingField(null);
455
+ setVerifiedNotice(attributeDisplayName);
456
+ }
457
+ })
458
+ });
459
+ if (mode === "popup") return panel;
460
+ return /* @__PURE__ */ jsx(Dialog_default, {
461
+ open: true,
462
+ onOpenChange: (isOpen) => {
463
+ if (!isOpen) setVerifyingField(null);
464
+ },
465
+ children: /* @__PURE__ */ jsx(Dialog_default.Content, {
466
+ "aria-label": t("user.verification.heading", { attribute: attributeDisplayName }),
467
+ children: /* @__PURE__ */ jsx("div", {
468
+ className: verificationStyles["verificationDialog"],
469
+ children: panel
470
+ })
471
+ })
472
+ });
473
+ };
362
474
  const renderUserInfo = (schema) => {
363
475
  if (!schema?.name) return null;
364
476
  const hasValue = schema.value !== void 0 && schema.value !== "" && schema.value !== null;
365
477
  const isFieldEditing = editingFields[schema.name];
366
478
  const isReadonlyField = readonlyFields.includes(schema.name);
367
479
  if (!(hasValue || isFieldEditing || editable && schema.mutability === "READ_WRITE")) return null;
480
+ const storedUser = flattenedProfile ?? profile;
481
+ const storedValue = (storedUser?.["attributes"])?.[schema.name] ?? storedUser?.[schema.name];
482
+ const showsVerificationStatus = supportsVerification && !!hasValue && !isFieldEditing && !savingFields[schema.name] && schema.value === storedValue && isStatusType(schema.type);
483
+ const canVerify = editable && !!renderVerification && showsVerificationStatus && !verifiedAttributes[schema.name] && verifyingField !== schema.name && isVerifiableAttribute(userSchema, schema.name) && typeof schema.value === "string";
368
484
  return /* @__PURE__ */ jsxs("div", {
369
485
  className: styles.field,
370
- children: [/* @__PURE__ */ jsxs("div", {
371
- className: styles.fieldInner,
372
- children: [renderSchemaField(schema, isFieldEditing, (value) => {
373
- const tempEditedUser = { ...editedUser };
374
- tempEditedUser[schema.name] = value;
375
- setEditedUser(tempEditedUser);
376
- }, () => toggleFieldEdit(schema.name)), fieldErrors[schema.name] && /* @__PURE__ */ jsx("div", {
377
- style: {
378
- color: "#d32f2f",
379
- fontSize: "0.8rem",
380
- marginTop: "4px",
381
- fontWeight: 500
382
- },
383
- children: fieldErrors[schema.name]
384
- })]
385
- }), editable && schema.mutability !== "READ_ONLY" && !isReadonlyField && /* @__PURE__ */ jsxs("div", {
386
- className: styles.fieldActions,
387
- children: [isFieldEditing && /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(Button_default, {
388
- size: "small",
389
- color: "primary",
390
- variant: "solid",
391
- onClick: () => handleFieldSave(schema),
392
- children: "Save"
393
- }), /* @__PURE__ */ jsx(Button_default, {
394
- size: "small",
395
- color: "secondary",
396
- variant: "solid",
397
- onClick: () => handleFieldCancel(schema.name),
398
- children: "Cancel"
399
- })] }), !isFieldEditing && hasValue && /* @__PURE__ */ jsx(Button_default, {
400
- size: "small",
401
- color: "tertiary",
402
- variant: "icon",
403
- onClick: () => toggleFieldEdit(schema.name),
404
- title: "Edit",
405
- className: styles.editButton,
406
- children: /* @__PURE__ */ jsx(PencilIcon, {})
407
- })]
408
- })]
486
+ children: [
487
+ /* @__PURE__ */ jsxs("div", {
488
+ className: styles.fieldInner,
489
+ children: [
490
+ renderSchemaField(schema, isFieldEditing, (value) => {
491
+ const tempEditedUser = { ...editedUser };
492
+ tempEditedUser[schema.name] = value;
493
+ setEditedUser(tempEditedUser);
494
+ }, () => toggleFieldEdit(schema.name)),
495
+ showsVerificationStatus && renderVerificationStatus(schema),
496
+ fieldErrors[schema.name] && /* @__PURE__ */ jsx("div", {
497
+ style: {
498
+ color: "#d32f2f",
499
+ fontSize: "0.8rem",
500
+ marginTop: "4px",
501
+ fontWeight: 500
502
+ },
503
+ children: fieldErrors[schema.name]
504
+ })
505
+ ]
506
+ }),
507
+ canVerify && /* @__PURE__ */ jsx("div", {
508
+ className: verificationStyles["fieldActions"],
509
+ children: /* @__PURE__ */ jsx(Button_default, {
510
+ size: "small",
511
+ color: "primary",
512
+ variant: "outline",
513
+ onClick: () => {
514
+ setVerifiedNotice(null);
515
+ setVerifyingField(schema.name);
516
+ },
517
+ className: withVendorCSSClassPrefix(bem("user-profile", "verify-button")),
518
+ "data-testid": `thunderid-verify-${schema.name}`,
519
+ children: t("user.verification.buttons.verify.text")
520
+ })
521
+ }),
522
+ editable && schema.mutability !== "READ_ONLY" && !isReadonlyField && /* @__PURE__ */ jsxs("div", {
523
+ className: styles.fieldActions,
524
+ children: [isFieldEditing && /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(Button_default, {
525
+ size: "small",
526
+ color: "primary",
527
+ variant: "solid",
528
+ onClick: () => handleFieldSave(schema),
529
+ children: "Save"
530
+ }), /* @__PURE__ */ jsx(Button_default, {
531
+ size: "small",
532
+ color: "secondary",
533
+ variant: "solid",
534
+ onClick: () => handleFieldCancel(schema.name),
535
+ children: "Cancel"
536
+ })] }), !isFieldEditing && hasValue && /* @__PURE__ */ jsx(Button_default, {
537
+ size: "small",
538
+ color: "tertiary",
539
+ variant: "icon",
540
+ onClick: () => {
541
+ if (verifyingField === schema.name) setVerifyingField(null);
542
+ setVerifiedNotice(null);
543
+ toggleFieldEdit(schema.name);
544
+ },
545
+ title: "Edit",
546
+ className: styles.editButton,
547
+ children: /* @__PURE__ */ jsx(PencilIcon, {})
548
+ })]
549
+ })
550
+ ]
409
551
  });
410
552
  };
411
553
  if (!profile && !flattenedProfile) return fallback;
@@ -444,6 +586,13 @@ const BaseUserProfile = ({ fallback = null, className = "", cardLayout = true, p
444
586
  };
445
587
  });
446
588
  return /* @__PURE__ */ jsxs(Fragment$1, { children: [
589
+ verifiedNotice && /* @__PURE__ */ jsx(Alert_default, {
590
+ variant: "success",
591
+ role: "status",
592
+ className: cx(withVendorCSSClassPrefix(bem("user-profile", "verification-notice")), verificationStyles["alert"]),
593
+ "data-testid": "thunderid-verification-notice",
594
+ children: /* @__PURE__ */ jsx(Alert_default.Description, { children: t("user.verification.success", { attribute: verifiedNotice }) })
595
+ }),
447
596
  /* @__PURE__ */ jsxs("div", {
448
597
  className: styles.profileSummary,
449
598
  children: [
@@ -467,9 +616,9 @@ const BaseUserProfile = ({ fallback = null, className = "", cardLayout = true, p
467
616
  ]
468
617
  }),
469
618
  /* @__PURE__ */ jsx(Divider_default, {}),
470
- schemaItems.map((schemaWithValue) => /* @__PURE__ */ jsx("div", {
619
+ schemaItems.map((schemaWithValue) => /* @__PURE__ */ jsxs("div", {
471
620
  className: styles.info,
472
- children: renderUserInfo(schemaWithValue)
621
+ children: [renderUserInfo(schemaWithValue), renderVerificationPanel(schemaWithValue)]
473
622
  }, schemaWithValue.name))
474
623
  ] });
475
624
  };