@redacto.io/consent-sdk-react 3.5.0 → 3.6.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 (152) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/LICENSE +176 -0
  3. package/dist/index.d.mts +51 -4
  4. package/dist/index.d.ts +51 -4
  5. package/dist/index.js +1891 -243
  6. package/dist/index.mjs +1890 -243
  7. package/dist/privacy-center.d.mts +566 -0
  8. package/dist/privacy-center.d.ts +566 -0
  9. package/dist/privacy-center.js +17174 -0
  10. package/dist/privacy-center.mjs +17136 -0
  11. package/package.json +47 -3
  12. package/src/RedactoNoticeConsent/RedactoNoticeConsent.test.tsx +201 -118
  13. package/src/RedactoNoticeConsent/RedactoNoticeConsent.tsx +1194 -93
  14. package/src/RedactoNoticeConsent/api/index.ts +335 -206
  15. package/src/RedactoNoticeConsent/api/types.ts +140 -16
  16. package/src/RedactoNoticeConsent/components/DigiLockerCallback.tsx +602 -0
  17. package/src/RedactoNoticeConsent/components/index.ts +7 -0
  18. package/src/RedactoNoticeConsent/injectStyles.ts +11 -0
  19. package/src/RedactoNoticeConsent/language-codes.ts +61 -0
  20. package/src/RedactoNoticeConsent/services/storage.ts +122 -0
  21. package/src/RedactoNoticeConsent/types.ts +2 -0
  22. package/src/RedactoPrivacyCenter/PrivacyCenterActivityPage.tsx +19 -0
  23. package/src/RedactoPrivacyCenter/PrivacyCenterConsentManagerPage.tsx +17 -0
  24. package/src/RedactoPrivacyCenter/PrivacyCenterFormPage.tsx +79 -0
  25. package/src/RedactoPrivacyCenter/PrivacyCenterHomePage.tsx +27 -0
  26. package/src/RedactoPrivacyCenter/PrivacyCenterLayout.tsx +142 -0
  27. package/src/RedactoPrivacyCenter/RedactoPrivacyCenter.tsx +51 -0
  28. package/src/RedactoPrivacyCenter/api/actions.ts +444 -0
  29. package/src/RedactoPrivacyCenter/api/client.ts +413 -0
  30. package/src/RedactoPrivacyCenter/api/config.ts +33 -0
  31. package/src/RedactoPrivacyCenter/api/fetcher.ts +181 -0
  32. package/src/RedactoPrivacyCenter/api/upload.ts +93 -0
  33. package/src/RedactoPrivacyCenter/assets/character.svg +31 -0
  34. package/src/RedactoPrivacyCenter/assets/fileAttach.svg +9 -0
  35. package/src/RedactoPrivacyCenter/assets/greenTick.svg +4 -0
  36. package/src/RedactoPrivacyCenter/assets/mail.svg +3 -0
  37. package/src/RedactoPrivacyCenter/assets/poweredByRedacto.svg +9 -0
  38. package/src/RedactoPrivacyCenter/assets/sentImg.svg +9 -0
  39. package/src/RedactoPrivacyCenter/assets/uploadFileIcon.svg +9 -0
  40. package/src/RedactoPrivacyCenter/components/ActivitiesList.tsx +272 -0
  41. package/src/RedactoPrivacyCenter/components/CaseDetailsModal.tsx +468 -0
  42. package/src/RedactoPrivacyCenter/components/CaseHistory.tsx +433 -0
  43. package/src/RedactoPrivacyCenter/components/ConsentManager.tsx +726 -0
  44. package/src/RedactoPrivacyCenter/components/ConsentManagerColumns.tsx +239 -0
  45. package/src/RedactoPrivacyCenter/components/ConsentManagerConstants.ts +7 -0
  46. package/src/RedactoPrivacyCenter/components/ConsentManagerTableSkeleton.tsx +155 -0
  47. package/src/RedactoPrivacyCenter/components/DataRequest/CorrectionDataSection.tsx +189 -0
  48. package/src/RedactoPrivacyCenter/components/DataRequest/GrievanceDataSection.tsx +118 -0
  49. package/src/RedactoPrivacyCenter/components/DataRequest/NominationDataSection.tsx +66 -0
  50. package/src/RedactoPrivacyCenter/components/DataRequest/PurposeSelectionSection.tsx +305 -0
  51. package/src/RedactoPrivacyCenter/components/Form.tsx +1455 -0
  52. package/src/RedactoPrivacyCenter/components/GrievanceTable.tsx +176 -0
  53. package/src/RedactoPrivacyCenter/components/GrievanceTablePagination.tsx +330 -0
  54. package/src/RedactoPrivacyCenter/components/ModifyConsentModal.tsx +329 -0
  55. package/src/RedactoPrivacyCenter/components/Pagination.tsx +140 -0
  56. package/src/RedactoPrivacyCenter/components/PrivacyCenterLayout.tsx +302 -0
  57. package/src/RedactoPrivacyCenter/components/RequestSubmit.tsx +218 -0
  58. package/src/RedactoPrivacyCenter/components/SideMenuBarPC/SideBarPC.tsx +475 -0
  59. package/src/RedactoPrivacyCenter/components/SideMenuBarPC/SideMenuPC.tsx +412 -0
  60. package/src/RedactoPrivacyCenter/components/SideMenuBarPC/constants.tsx +42 -0
  61. package/src/RedactoPrivacyCenter/components/SideMenuBarPC/menuItemsPC.tsx +1 -0
  62. package/src/RedactoPrivacyCenter/components/SideMenuBarPC/types.ts +40 -0
  63. package/src/RedactoPrivacyCenter/components/SideMenuBarPC/utils.ts +38 -0
  64. package/src/RedactoPrivacyCenter/components/ThemeTransitionOverlay.tsx +85 -0
  65. package/src/RedactoPrivacyCenter/components/activitiesColumns.tsx +141 -0
  66. package/src/RedactoPrivacyCenter/components/caseHistoryColumns.tsx +179 -0
  67. package/src/RedactoPrivacyCenter/components/constant.ts +20 -0
  68. package/src/RedactoPrivacyCenter/components/types.ts +68 -0
  69. package/src/RedactoPrivacyCenter/components/utils.tsx +10 -0
  70. package/src/RedactoPrivacyCenter/config/routes.ts +9 -0
  71. package/src/RedactoPrivacyCenter/config/table.ts +25 -0
  72. package/src/RedactoPrivacyCenter/context/AuthContext.tsx +123 -0
  73. package/src/RedactoPrivacyCenter/context/BaseUrlContext.tsx +44 -0
  74. package/src/RedactoPrivacyCenter/context/LocaleContext.tsx +11 -0
  75. package/src/RedactoPrivacyCenter/context/NavigationContext.tsx +64 -0
  76. package/src/RedactoPrivacyCenter/context/OrganizationContext.tsx +30 -0
  77. package/src/RedactoPrivacyCenter/context/PageChromeContext.tsx +60 -0
  78. package/src/RedactoPrivacyCenter/context/theme.tsx +127 -0
  79. package/src/RedactoPrivacyCenter/lib/api.ts +468 -0
  80. package/src/RedactoPrivacyCenter/lib/consent-manager/utils.tsx +63 -0
  81. package/src/RedactoPrivacyCenter/lib/constants.ts +116 -0
  82. package/src/RedactoPrivacyCenter/lib/i18n.ts +81 -0
  83. package/src/RedactoPrivacyCenter/lib/locales.ts +105 -0
  84. package/src/RedactoPrivacyCenter/lib/queries.ts +30 -0
  85. package/src/RedactoPrivacyCenter/lib/types.ts +346 -0
  86. package/src/RedactoPrivacyCenter/lib/useCurrentLanguage.ts +37 -0
  87. package/src/RedactoPrivacyCenter/lib/utils.ts +625 -0
  88. package/src/RedactoPrivacyCenter/locales/as/translation.json +188 -0
  89. package/src/RedactoPrivacyCenter/locales/bho/translation.json +188 -0
  90. package/src/RedactoPrivacyCenter/locales/bn/translation.json +188 -0
  91. package/src/RedactoPrivacyCenter/locales/brx/translation.json +188 -0
  92. package/src/RedactoPrivacyCenter/locales/doi/translation.json +188 -0
  93. package/src/RedactoPrivacyCenter/locales/en/translation.json +188 -0
  94. package/src/RedactoPrivacyCenter/locales/gom/translation.json +188 -0
  95. package/src/RedactoPrivacyCenter/locales/gu/translation.json +188 -0
  96. package/src/RedactoPrivacyCenter/locales/hi/translation.json +188 -0
  97. package/src/RedactoPrivacyCenter/locales/kn/translation.json +188 -0
  98. package/src/RedactoPrivacyCenter/locales/ks/translation.json +188 -0
  99. package/src/RedactoPrivacyCenter/locales/mai/translation.json +188 -0
  100. package/src/RedactoPrivacyCenter/locales/ml/translation.json +188 -0
  101. package/src/RedactoPrivacyCenter/locales/mni-Mtei/translation.json +188 -0
  102. package/src/RedactoPrivacyCenter/locales/mr/translation.json +188 -0
  103. package/src/RedactoPrivacyCenter/locales/ne/translation.json +188 -0
  104. package/src/RedactoPrivacyCenter/locales/or/translation.json +188 -0
  105. package/src/RedactoPrivacyCenter/locales/pa/translation.json +188 -0
  106. package/src/RedactoPrivacyCenter/locales/sa/translation.json +188 -0
  107. package/src/RedactoPrivacyCenter/locales/sat/translation.json +188 -0
  108. package/src/RedactoPrivacyCenter/locales/sd/translation.json +188 -0
  109. package/src/RedactoPrivacyCenter/locales/ta/translation.json +188 -0
  110. package/src/RedactoPrivacyCenter/locales/te/translation.json +188 -0
  111. package/src/RedactoPrivacyCenter/locales/ur/translation.json +188 -0
  112. package/src/RedactoPrivacyCenter/styles/base.css +117 -0
  113. package/src/RedactoPrivacyCenter/styles/injectStyles.ts +1000 -0
  114. package/src/RedactoPrivacyCenter/styles/pcStyles.ts +819 -0
  115. package/src/RedactoPrivacyCenter/styles/responsive.ts +138 -0
  116. package/src/RedactoPrivacyCenter/styles/variables.css +133 -0
  117. package/src/RedactoPrivacyCenter/table/AdvancedTable.tsx +365 -0
  118. package/src/RedactoPrivacyCenter/table/AdvancedTablePagination.tsx +479 -0
  119. package/src/RedactoPrivacyCenter/table/index.ts +2 -0
  120. package/src/RedactoPrivacyCenter/types/images.d.ts +29 -0
  121. package/src/RedactoPrivacyCenter/ui/Footer.tsx +73 -0
  122. package/src/RedactoPrivacyCenter/ui/FormBlockWrapper.tsx +54 -0
  123. package/src/RedactoPrivacyCenter/ui/PCAccordion.tsx +87 -0
  124. package/src/RedactoPrivacyCenter/ui/PCActionIcon.tsx +47 -0
  125. package/src/RedactoPrivacyCenter/ui/PCAvatar.tsx +69 -0
  126. package/src/RedactoPrivacyCenter/ui/PCBadge.tsx +48 -0
  127. package/src/RedactoPrivacyCenter/ui/PCButton.tsx +77 -0
  128. package/src/RedactoPrivacyCenter/ui/PCCheckbox.tsx +55 -0
  129. package/src/RedactoPrivacyCenter/ui/PCCollapse.tsx +97 -0
  130. package/src/RedactoPrivacyCenter/ui/PCEmpty.tsx +35 -0
  131. package/src/RedactoPrivacyCenter/ui/PCInput.tsx +128 -0
  132. package/src/RedactoPrivacyCenter/ui/PCLoader.tsx +30 -0
  133. package/src/RedactoPrivacyCenter/ui/PCModal.tsx +104 -0
  134. package/src/RedactoPrivacyCenter/ui/PCPopover.tsx +175 -0
  135. package/src/RedactoPrivacyCenter/ui/PCSelect.tsx +381 -0
  136. package/src/RedactoPrivacyCenter/ui/PCTable.tsx +137 -0
  137. package/src/RedactoPrivacyCenter/ui/PCText.tsx +39 -0
  138. package/src/RedactoPrivacyCenter/ui/PCTextarea.tsx +43 -0
  139. package/src/RedactoPrivacyCenter/ui/PCTitle.tsx +37 -0
  140. package/src/RedactoPrivacyCenter/ui/PCTooltip.tsx +119 -0
  141. package/src/RedactoPrivacyCenter/ui/SimpleBar.tsx +25 -0
  142. package/src/RedactoPrivacyCenter/ui/StatusBadge.tsx +55 -0
  143. package/src/RedactoPrivacyCenter/ui/ThemeToggle.tsx +70 -0
  144. package/src/RedactoPrivacyCenter/ui/index.ts +18 -0
  145. package/src/RedactoPrivacyCenter/utils/cn.ts +28 -0
  146. package/src/RedactoPrivacyCenter/utils/date.ts +48 -0
  147. package/src/RedactoPrivacyCenter/utils/status.ts +111 -0
  148. package/src/RedactoPrivacyCenter/utils/toast.ts +130 -0
  149. package/src/index.ts +10 -0
  150. package/src/privacy-center.ts +107 -0
  151. package/tsconfig.json +2 -0
  152. package/tsup.config.ts +16 -1
package/dist/index.js CHANGED
@@ -20,6 +20,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/index.ts
21
21
  var src_exports = {};
22
22
  __export(src_exports, {
23
+ DigiLockerCallback: () => DigiLockerCallback,
23
24
  RedactoNoticeConsent: () => RedactoNoticeConsent,
24
25
  RedactoNoticeConsentInline: () => RedactoConsentInline
25
26
  });
@@ -66,73 +67,66 @@ var fetchConsentContent = async ({
66
67
  validate_against = "all",
67
68
  include_fully_consented_data = false,
68
69
  signal
69
- // AbortSignal for request cancellation
70
70
  }) => {
71
- try {
72
- if (!noticeId || !accessToken || !validate_against) {
73
- throw new Error("noticeId and accessToken are required");
74
- }
75
- const decodedToken = decodeTokenSafely(accessToken);
76
- if (!decodedToken) {
77
- throw new Error("Invalid access token");
78
- }
79
- const { organisation_uuid: ORGANISATION_UUID, workspace_uuid: WORKSPACE_UUID } = decodedToken;
80
- if (!ORGANISATION_UUID || !WORKSPACE_UUID) {
81
- throw new Error("Invalid token: missing organization or workspace UUID");
82
- }
83
- const apiBaseUrl = baseUrl || BASE_URL;
84
- const cacheKey = `${accessToken}-${noticeId}-${validate_against}-${language}-${specific_uuid || ""}-${include_fully_consented_data}`;
85
- if (validate_against === "all" && !specific_uuid) {
86
- const cachedData = getCachedData(cacheKey);
87
- if (cachedData) {
88
- return cachedData;
89
- }
90
- }
91
- const url = new URL(
92
- `${apiBaseUrl}/public/organisations/${ORGANISATION_UUID}/workspaces/${WORKSPACE_UUID}/notices/${noticeId}`
93
- );
94
- if (specific_uuid) {
95
- url.searchParams.append("specific_uuid", specific_uuid);
96
- }
97
- url.searchParams.append("validate_against", validate_against);
98
- if (include_fully_consented_data) {
99
- url.searchParams.append("include_fully_consented_data", "true");
100
- }
101
- const response = await fetch(url.toString(), {
102
- method: "GET",
103
- headers: {
104
- Authorization: `Bearer ${accessToken}`,
105
- "Accept-Language": language,
106
- "Content-Type": "application/json"
107
- },
108
- signal
109
- // Add abort signal for request cancellation
110
- });
111
- if (!response.ok) {
112
- let errorMessage = `Failed to fetch consent content: ${response.status} ${response.statusText}`;
113
- if (response.status === 401) {
114
- errorMessage = "Unauthorized: Invalid or expired token";
115
- } else if (response.status === 403) {
116
- errorMessage = "Forbidden: Access denied";
117
- } else if (response.status === 404) {
118
- errorMessage = "Notice not found";
119
- } else if (response.status === 409) {
120
- errorMessage = "User has already provided consent";
121
- } else if (response.status >= 500) {
122
- errorMessage = "Server error: Please try again later";
123
- }
124
- const error = new Error(errorMessage);
125
- error.status = response.status;
126
- throw error;
71
+ if (!noticeId || !accessToken || !validate_against) {
72
+ throw new Error("noticeId and accessToken are required");
73
+ }
74
+ const decodedToken = decodeTokenSafely(accessToken);
75
+ if (!decodedToken) {
76
+ throw new Error("Invalid access token");
77
+ }
78
+ const { organisation_uuid: ORGANISATION_UUID, workspace_uuid: WORKSPACE_UUID } = decodedToken;
79
+ if (!ORGANISATION_UUID || !WORKSPACE_UUID) {
80
+ throw new Error("Invalid token: missing organization or workspace UUID");
81
+ }
82
+ const apiBaseUrl = baseUrl || BASE_URL;
83
+ const cacheKey = `${accessToken}-${noticeId}-${validate_against}-${language}-${specific_uuid || ""}-${include_fully_consented_data}`;
84
+ if (validate_against === "all" && !specific_uuid) {
85
+ const cachedData = getCachedData(cacheKey);
86
+ if (cachedData) {
87
+ return cachedData;
127
88
  }
128
- const data = await response.json();
129
- if (validate_against === "all" && !specific_uuid) {
130
- setCachedData(cacheKey, data);
89
+ }
90
+ const url = new URL(
91
+ `${apiBaseUrl}/public/organisations/${ORGANISATION_UUID}/workspaces/${WORKSPACE_UUID}/notices/${noticeId}`
92
+ );
93
+ if (specific_uuid) {
94
+ url.searchParams.append("specific_uuid", specific_uuid);
95
+ }
96
+ url.searchParams.append("validate_against", validate_against);
97
+ if (include_fully_consented_data) {
98
+ url.searchParams.append("include_fully_consented_data", "true");
99
+ }
100
+ const response = await fetch(url.toString(), {
101
+ method: "GET",
102
+ headers: {
103
+ Authorization: `Bearer ${accessToken}`,
104
+ "Accept-Language": language
105
+ },
106
+ signal
107
+ });
108
+ if (!response.ok) {
109
+ let errorMessage = `Failed to fetch consent content: ${response.status} ${response.statusText}`;
110
+ if (response.status === 401) {
111
+ errorMessage = "Unauthorized: Invalid or expired token";
112
+ } else if (response.status === 403) {
113
+ errorMessage = "Forbidden: Access denied";
114
+ } else if (response.status === 404) {
115
+ errorMessage = "Notice not found";
116
+ } else if (response.status === 409) {
117
+ errorMessage = "User has already provided consent";
118
+ } else if (response.status >= 500) {
119
+ errorMessage = "Server error: Please try again later";
131
120
  }
132
- return data;
133
- } catch (error) {
121
+ const error = new Error(errorMessage);
122
+ error.status = response.status;
134
123
  throw error;
135
124
  }
125
+ const data = await response.json();
126
+ if (validate_against === "all" && !specific_uuid) {
127
+ setCachedData(cacheKey, data);
128
+ }
129
+ return data;
136
130
  };
137
131
  var submitConsentEvent = async ({
138
132
  accessToken,
@@ -140,101 +134,154 @@ var submitConsentEvent = async ({
140
134
  noticeUuid,
141
135
  purposes,
142
136
  declined,
137
+ language,
143
138
  meta_data,
139
+ guardianVerificationReference,
140
+ selfDeclaredAdult,
144
141
  signal
145
- // AbortSignal for request cancellation
146
142
  }) => {
147
- try {
148
- if (!noticeUuid || !accessToken || !Array.isArray(purposes)) {
149
- throw new Error("noticeUuid, accessToken, and purposes array are required");
150
- }
151
- const decodedToken = decodeTokenSafely(accessToken);
152
- if (!decodedToken) {
153
- throw new Error("Invalid access token");
154
- }
155
- const { organisation_uuid: ORGANISATION_UUID, workspace_uuid: WORKSPACE_UUID } = decodedToken;
156
- if (!ORGANISATION_UUID || !WORKSPACE_UUID) {
157
- throw new Error("Invalid token: missing organization or workspace UUID");
143
+ if (!noticeUuid || !accessToken || !Array.isArray(purposes)) {
144
+ throw new Error("noticeUuid, accessToken, and purposes array are required");
145
+ }
146
+ const decodedToken = decodeTokenSafely(accessToken);
147
+ if (!decodedToken) {
148
+ throw new Error("Invalid access token");
149
+ }
150
+ const { organisation_uuid: ORGANISATION_UUID, workspace_uuid: WORKSPACE_UUID } = decodedToken;
151
+ if (!ORGANISATION_UUID || !WORKSPACE_UUID) {
152
+ throw new Error("Invalid token: missing organization or workspace UUID");
153
+ }
154
+ const apiBaseUrl = baseUrl || BASE_URL;
155
+ const validatedPurposes = purposes.map((purpose) => {
156
+ if (!purpose.uuid) {
157
+ throw new Error(`Invalid purpose data: missing uuid`);
158
158
  }
159
- const apiBaseUrl = baseUrl || BASE_URL;
160
- const validatedPurposes = purposes.map((purpose) => {
161
- if (!purpose.uuid) {
162
- throw new Error(`Invalid purpose data: missing uuid`);
163
- }
164
- const dataElements = (purpose.data_elements || []).filter((element) => element.enabled).map((element) => ({
165
- uuid: element.uuid,
166
- selected: element.required ? true : Boolean(element.selected)
167
- }));
168
- return {
169
- purpose_uuid: purpose.uuid,
170
- selected: Boolean(purpose.selected),
171
- data_elements: dataElements.length > 0 ? dataElements : void 0
172
- };
173
- });
174
- const payload = {
175
- notice_uuid: noticeUuid,
176
- purposes: validatedPurposes,
177
- select_all_mandatory: false,
178
- source: "WEB",
179
- declined: Boolean(declined),
180
- meta_data: meta_data ? { specific_uuid: meta_data.specific_uuid } : void 0
159
+ const dataElements = (purpose.data_elements || []).filter((element) => element.enabled).map((element) => ({
160
+ uuid: element.uuid,
161
+ selected: element.required ? true : Boolean(element.selected)
162
+ }));
163
+ return {
164
+ purpose_uuid: purpose.uuid,
165
+ selected: Boolean(purpose.selected),
166
+ data_elements: dataElements.length > 0 ? dataElements : void 0
181
167
  };
182
- const response = await fetch(
183
- `${apiBaseUrl}/public/organisations/${ORGANISATION_UUID}/workspaces/${WORKSPACE_UUID}/submit-consent`,
184
- {
185
- method: "POST",
186
- headers: {
187
- Authorization: `Bearer ${accessToken}`,
188
- "Content-Type": "application/json"
189
- },
190
- body: JSON.stringify(payload),
191
- signal
192
- // Add abort signal for request cancellation
193
- }
194
- );
195
- if (!response.ok) {
196
- let errorMessage = `Failed to submit consent: ${response.status} ${response.statusText}`;
197
- if (response.status === 400) {
168
+ });
169
+ const payload = {
170
+ notice_uuid: noticeUuid,
171
+ purposes: validatedPurposes,
172
+ select_all_mandatory: false,
173
+ source: "WEB",
174
+ declined: Boolean(declined),
175
+ language: language || void 0,
176
+ meta_data: meta_data ? { specific_uuid: meta_data.specific_uuid, minor_age: meta_data.minor_age } : void 0,
177
+ guardian_verification_reference: guardianVerificationReference,
178
+ self_declared_adult: selfDeclaredAdult
179
+ };
180
+ const response = await fetch(
181
+ `${apiBaseUrl}/public/organisations/${ORGANISATION_UUID}/workspaces/${WORKSPACE_UUID}/submit-consent`,
182
+ {
183
+ method: "POST",
184
+ headers: {
185
+ Authorization: `Bearer ${accessToken}`,
186
+ "Content-Type": "application/json"
187
+ },
188
+ body: JSON.stringify(payload),
189
+ signal
190
+ }
191
+ );
192
+ if (!response.ok) {
193
+ let errorMessage = `Failed to submit consent: ${response.status} ${response.statusText}`;
194
+ if (response.status === 400) {
195
+ try {
196
+ const errorData = await response.json();
197
+ errorMessage = errorData.message || "Invalid request data";
198
+ } catch {
198
199
  errorMessage = "Invalid request data";
199
- } else if (response.status === 401) {
200
- errorMessage = "Unauthorized: Invalid or expired token";
201
- } else if (response.status === 403) {
202
- errorMessage = "Forbidden: Access denied";
203
- } else if (response.status === 404) {
204
- errorMessage = "Notice not found";
205
- } else if (response.status >= 500) {
206
- errorMessage = "Server error: Please try again later";
207
200
  }
208
- const error = new Error(errorMessage);
209
- error.status = response.status;
210
- throw error;
201
+ } else if (response.status === 401) {
202
+ errorMessage = "Unauthorized: Invalid or expired token";
203
+ } else if (response.status === 403) {
204
+ errorMessage = "Forbidden: Access denied";
205
+ } else if (response.status === 404) {
206
+ errorMessage = "Notice not found";
207
+ } else if (response.status >= 500) {
208
+ errorMessage = "Server error: Please try again later";
211
209
  }
212
- apiCache.clear();
213
- } catch (error) {
210
+ const error = new Error(errorMessage);
211
+ error.status = response.status;
214
212
  throw error;
215
213
  }
214
+ apiCache.clear();
216
215
  };
217
- var submitGuardianInfo = async ({
216
+ var fetchTTSAudioUrls = async ({
217
+ accessToken,
218
+ baseUrl,
219
+ noticeUuid,
220
+ language,
221
+ signal
222
+ }) => {
223
+ if (!accessToken || !noticeUuid || !language) {
224
+ throw new Error("accessToken, noticeUuid, and language are required");
225
+ }
226
+ const decodedToken = decodeTokenSafely(accessToken);
227
+ if (!decodedToken) {
228
+ throw new Error("Invalid access token");
229
+ }
230
+ const { organisation_uuid: ORGANISATION_UUID, workspace_uuid: WORKSPACE_UUID } = decodedToken;
231
+ if (!ORGANISATION_UUID || !WORKSPACE_UUID) {
232
+ throw new Error("Invalid token: missing organization or workspace UUID");
233
+ }
234
+ const apiBaseUrl = baseUrl || BASE_URL;
235
+ const url = `${apiBaseUrl}/public/organisations/${ORGANISATION_UUID}/workspaces/${WORKSPACE_UUID}/notices/${noticeUuid}/audio/${language}`;
236
+ const response = await fetch(url, {
237
+ method: "GET",
238
+ headers: {
239
+ Authorization: `Bearer ${accessToken}`,
240
+ Accept: "application/json"
241
+ },
242
+ signal
243
+ });
244
+ if (!response.ok) {
245
+ let errorMessage = `Failed to fetch TTS audio URLs: ${response.status} ${response.statusText}`;
246
+ if (response.status === 401) {
247
+ errorMessage = "Unauthorized: Invalid or expired token";
248
+ } else if (response.status === 403) {
249
+ errorMessage = "Forbidden: Access denied";
250
+ } else if (response.status === 404) {
251
+ errorMessage = "Notice or audio not found";
252
+ } else if (response.status >= 500) {
253
+ errorMessage = "Server error: Please try again later";
254
+ }
255
+ const error = new Error(errorMessage);
256
+ error.status = response.status;
257
+ throw error;
258
+ }
259
+ const data = await response.json();
260
+ return data;
261
+ };
262
+ var initiateGuardianVerification = async ({
218
263
  accessToken,
219
264
  baseUrl,
220
265
  guardianName,
221
266
  guardianContact,
222
267
  guardianRelationship,
268
+ frontendCallbackUrl,
269
+ metadata,
223
270
  signal
224
- // AbortSignal for request cancellation
225
271
  }) => {
272
+ var _a;
226
273
  try {
227
274
  if (!accessToken) {
228
275
  throw new Error("accessToken is required");
229
276
  }
230
277
  if (!(guardianName == null ? void 0 : guardianName.trim())) {
231
- throw new Error("guardianName is required and cannot be empty");
278
+ throw new Error("Guardian name is required");
232
279
  }
233
280
  if (!(guardianContact == null ? void 0 : guardianContact.trim())) {
234
- throw new Error("guardianContact is required and cannot be empty");
281
+ throw new Error("Guardian contact is required");
235
282
  }
236
283
  if (!(guardianRelationship == null ? void 0 : guardianRelationship.trim())) {
237
- throw new Error("guardianRelationship is required and cannot be empty");
284
+ throw new Error("Guardian relationship is required");
238
285
  }
239
286
  const decodedToken = decodeTokenSafely(accessToken);
240
287
  if (!decodedToken) {
@@ -244,14 +291,20 @@ var submitGuardianInfo = async ({
244
291
  if (!ORGANISATION_UUID || !WORKSPACE_UUID) {
245
292
  throw new Error("Invalid token: missing organization or workspace UUID");
246
293
  }
294
+ const apiBaseUrl = baseUrl || BASE_URL;
247
295
  const payload = {
248
296
  guardian_name: guardianName.trim(),
249
297
  guardian_contact: guardianContact.trim(),
250
298
  guardian_relationship: guardianRelationship.trim()
251
299
  };
252
- const apiBaseUrl = baseUrl || BASE_URL;
300
+ if (frontendCallbackUrl) {
301
+ payload.frontend_callback_url = frontendCallbackUrl;
302
+ }
303
+ if (metadata) {
304
+ payload.metadata = metadata;
305
+ }
253
306
  const response = await fetch(
254
- `${apiBaseUrl}/public/organisations/${ORGANISATION_UUID}/workspaces/${WORKSPACE_UUID}/guardian-info`,
307
+ `${apiBaseUrl}/public/organisations/${ORGANISATION_UUID}/workspaces/${WORKSPACE_UUID}/guardian/initiate-verification`,
255
308
  {
256
309
  method: "POST",
257
310
  headers: {
@@ -260,24 +313,26 @@ var submitGuardianInfo = async ({
260
313
  },
261
314
  body: JSON.stringify(payload),
262
315
  signal
263
- // Add abort signal for request cancellation
264
316
  }
265
317
  );
266
318
  if (!response.ok) {
267
- let errorMessage = `Failed to submit guardian info: ${response.status} ${response.statusText}`;
319
+ let errorMessage = `Failed to initiate verification: ${response.status} ${response.statusText}`;
268
320
  if (response.status === 400) {
269
- errorMessage = "Invalid request data";
321
+ try {
322
+ const errorData = await response.json();
323
+ errorMessage = errorData.message || "Invalid request data";
324
+ } catch {
325
+ errorMessage = "Invalid request data";
326
+ }
270
327
  } else if (response.status === 401) {
271
328
  errorMessage = "Unauthorized: Invalid or expired token";
272
- } else if (response.status === 403) {
273
- errorMessage = "Forbidden: Access denied";
274
329
  } else if (response.status === 404) {
275
330
  errorMessage = "Organization or workspace not found";
276
331
  } else if (response.status === 422) {
277
332
  try {
278
333
  const errorData = await response.json();
279
- errorMessage = errorData.message || "Validation error";
280
- } catch (parseError) {
334
+ errorMessage = errorData.message || "Validation error: Please check your input";
335
+ } catch {
281
336
  errorMessage = "Validation error: Please check your input";
282
337
  }
283
338
  } else if (response.status >= 500) {
@@ -287,63 +342,98 @@ var submitGuardianInfo = async ({
287
342
  error.status = response.status;
288
343
  throw error;
289
344
  }
345
+ const responseData = await response.json();
346
+ const detail = responseData.detail || responseData;
347
+ if (detail.already_verified) {
348
+ return {
349
+ success: true,
350
+ guardian_info_uuid: detail.guardian_info_uuid,
351
+ already_verified: true,
352
+ verification_reference: detail.verification_reference
353
+ };
354
+ }
355
+ if (!detail.session_token || !detail.digilocker_redirect_url) {
356
+ throw new Error("Invalid response: missing session_token or digilocker_redirect_url");
357
+ }
358
+ return {
359
+ success: (_a = detail.success) != null ? _a : true,
360
+ guardian_info_uuid: detail.guardian_info_uuid,
361
+ already_verified: false,
362
+ session_token: detail.session_token,
363
+ digilocker_redirect_url: detail.digilocker_redirect_url,
364
+ expires_at: detail.expires_at
365
+ };
290
366
  } catch (error) {
291
- console.error("Error submitting guardian info:", error instanceof Error ? error.message : error);
367
+ console.error("Error initiating guardian verification:", error instanceof Error ? error.message : error);
292
368
  throw error;
293
369
  }
294
370
  };
295
- var fetchTTSAudioUrls = async ({
371
+ var verifyGuardianStatus = async ({
296
372
  accessToken,
297
373
  baseUrl,
298
- noticeUuid,
299
- language,
374
+ sessionToken,
300
375
  signal
301
- // AbortSignal for request cancellation
302
376
  }) => {
303
- try {
304
- if (!accessToken || !noticeUuid || !language) {
305
- throw new Error("accessToken, noticeUuid, and language are required");
306
- }
307
- const decodedToken = decodeTokenSafely(accessToken);
308
- if (!decodedToken) {
309
- throw new Error("Invalid access token");
310
- }
311
- const { organisation_uuid: ORGANISATION_UUID, workspace_uuid: WORKSPACE_UUID } = decodedToken;
312
- if (!ORGANISATION_UUID || !WORKSPACE_UUID) {
313
- throw new Error("Invalid token: missing organization or workspace UUID");
314
- }
315
- const apiBaseUrl = baseUrl || BASE_URL;
316
- const url = `${apiBaseUrl}/public/organisations/${ORGANISATION_UUID}/workspaces/${WORKSPACE_UUID}/notices/${noticeUuid}/audio/${language}`;
317
- const response = await fetch(url, {
318
- method: "GET",
377
+ var _a, _b, _c, _d, _e, _f, _g, _h;
378
+ if (!accessToken || !sessionToken) {
379
+ throw new Error("accessToken and sessionToken are required");
380
+ }
381
+ const decodedToken = decodeTokenSafely(accessToken);
382
+ if (!decodedToken) {
383
+ throw new Error("Invalid access token");
384
+ }
385
+ const { organisation_uuid: ORGANISATION_UUID, workspace_uuid: WORKSPACE_UUID } = decodedToken;
386
+ if (!ORGANISATION_UUID || !WORKSPACE_UUID) {
387
+ throw new Error("Invalid token: missing organization or workspace UUID");
388
+ }
389
+ const apiBaseUrl = baseUrl || BASE_URL;
390
+ const response = await fetch(
391
+ `${apiBaseUrl}/public/organisations/${ORGANISATION_UUID}/workspaces/${WORKSPACE_UUID}/guardian/verify-status`,
392
+ {
393
+ method: "POST",
319
394
  headers: {
320
395
  Authorization: `Bearer ${accessToken}`,
321
- Accept: "application/json",
322
396
  "Content-Type": "application/json"
323
397
  },
398
+ body: JSON.stringify({
399
+ session_token: sessionToken
400
+ }),
324
401
  signal
325
- // Add abort signal for request cancellation
326
- });
327
- if (!response.ok) {
328
- let errorMessage = `Failed to fetch TTS audio URLs: ${response.status} ${response.statusText}`;
329
- if (response.status === 401) {
330
- errorMessage = "Unauthorized: Invalid or expired token";
331
- } else if (response.status === 403) {
332
- errorMessage = "Forbidden: Access denied";
333
- } else if (response.status === 404) {
334
- errorMessage = "Notice or audio not found";
335
- } else if (response.status >= 500) {
336
- errorMessage = "Server error: Please try again later";
402
+ }
403
+ );
404
+ if (!response.ok) {
405
+ let errorMessage = `Failed to check verification status: ${response.status} ${response.statusText}`;
406
+ if (response.status === 400) {
407
+ try {
408
+ const errorData = await response.json();
409
+ errorMessage = errorData.message || ((_a = errorData.detail) == null ? void 0 : _a.message) || "Invalid session token";
410
+ } catch {
411
+ errorMessage = "Invalid session token";
337
412
  }
338
- const error = new Error(errorMessage);
339
- error.status = response.status;
340
- throw error;
413
+ } else if (response.status === 401) {
414
+ errorMessage = "Unauthorized: Invalid or expired token";
415
+ } else if (response.status === 404) {
416
+ errorMessage = "Verification session not found or expired. Please restart the verification process.";
417
+ } else if (response.status === 410) {
418
+ errorMessage = "Verification session has expired. Please restart the verification process.";
419
+ } else if (response.status >= 500) {
420
+ errorMessage = "Server error: Please try again later";
341
421
  }
342
- const data = await response.json();
343
- return data;
344
- } catch (error) {
422
+ const error = new Error(errorMessage);
423
+ error.status = response.status;
345
424
  throw error;
346
425
  }
426
+ const responseData = await response.json();
427
+ const detail = responseData.detail || responseData;
428
+ return {
429
+ status: (_b = detail.status) != null ? _b : "in_progress",
430
+ guardian_info_uuid: (_c = detail.guardian_info_uuid) != null ? _c : null,
431
+ verification_reference: (_d = detail.verification_reference) != null ? _d : null,
432
+ guardian_details: (_e = detail.guardian_details) != null ? _e : null,
433
+ error: (_f = detail.error) != null ? _f : null,
434
+ error_code: (_g = detail.error_code) != null ? _g : null,
435
+ can_retry: (_h = detail.can_retry) != null ? _h : true
436
+ };
347
437
  };
348
438
 
349
439
  // src/RedactoNoticeConsent/assets/redacto-logo.png
@@ -361,6 +451,52 @@ var DPO_AUDIO_ELEMENT_MAP = [
361
451
  { audioKey: "dpo_anchor_text_audio_url", elementId: "dpo-dpo-link" }
362
452
  ];
363
453
 
454
+ // src/RedactoNoticeConsent/language-codes.ts
455
+ var LANGUAGE_NAME_TO_BCP47 = {
456
+ English: "en",
457
+ Assamese: "as",
458
+ Bengali: "bn",
459
+ Bodo: "brx",
460
+ Dogri: "doi",
461
+ Gujarati: "gu",
462
+ Hindi: "hi",
463
+ Kannada: "kn",
464
+ Kashmiri: "ks",
465
+ Konkani: "gom",
466
+ Maithili: "mai",
467
+ Malayalam: "ml",
468
+ Manipuri: "mni-Mtei",
469
+ Marathi: "mr",
470
+ Nepali: "ne",
471
+ Odia: "or",
472
+ Punjabi: "pa",
473
+ Sanskrit: "sa",
474
+ Santali: "sat",
475
+ Sindhi: "sd",
476
+ Tamil: "ta",
477
+ Telugu: "te",
478
+ Urdu: "ur"
479
+ };
480
+ var KNOWN_BCP47_CODES = new Set(Object.values(LANGUAGE_NAME_TO_BCP47));
481
+ var toBcp47Code = (language) => {
482
+ if (LANGUAGE_NAME_TO_BCP47[language]) {
483
+ return LANGUAGE_NAME_TO_BCP47[language];
484
+ }
485
+ if (KNOWN_BCP47_CODES.has(language)) {
486
+ return language;
487
+ }
488
+ const lower = language.toLowerCase();
489
+ for (const [name, code] of Object.entries(LANGUAGE_NAME_TO_BCP47)) {
490
+ if (name.toLowerCase() === lower) {
491
+ return code;
492
+ }
493
+ }
494
+ if (/^[A-Za-z]{2,3}(?:-[A-Za-z0-9]{2,8})*$/.test(language)) {
495
+ return language;
496
+ }
497
+ return "en";
498
+ };
499
+
364
500
  // src/RedactoNoticeConsent/injectStyles.ts
365
501
  var stylesInjected = false;
366
502
  var injectCheckboxStyles = () => {
@@ -491,6 +627,17 @@ var injectCheckboxStyles = () => {
491
627
  outline: 3px solid #FFF9C4 !important;
492
628
  outline-offset: 2px !important;
493
629
  }
630
+
631
+ /* Spinner animation for verification screens */
632
+ @keyframes spin {
633
+ from { transform: rotate(0deg); }
634
+ to { transform: rotate(360deg); }
635
+ }
636
+
637
+ /* DigiLocker callback retry button hover */
638
+ .redacto-dl-retry-btn:hover {
639
+ background-color: #2563eb !important;
640
+ }
494
641
  `;
495
642
  document.head.appendChild(style);
496
643
  stylesInjected = true;
@@ -873,6 +1020,69 @@ var useMediaQuery = (query) => {
873
1020
  return matches;
874
1021
  };
875
1022
 
1023
+ // src/RedactoNoticeConsent/services/storage.ts
1024
+ var STORAGE_KEY = "redacto_consent_sdk_state";
1025
+ var STATE_EXPIRY_MS = 30 * 60 * 1e3;
1026
+ var isBrowser = () => {
1027
+ return typeof window !== "undefined" && typeof window.sessionStorage !== "undefined";
1028
+ };
1029
+ var saveConsentState = (state) => {
1030
+ if (!isBrowser()) {
1031
+ console.warn("SessionStorage not available - state not persisted");
1032
+ return;
1033
+ }
1034
+ try {
1035
+ const stateWithTimestamp = {
1036
+ ...state,
1037
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
1038
+ };
1039
+ sessionStorage.setItem(STORAGE_KEY, JSON.stringify(stateWithTimestamp));
1040
+ } catch (error) {
1041
+ console.error("Failed to save consent state:", error);
1042
+ }
1043
+ };
1044
+ var getConsentState = () => {
1045
+ if (!isBrowser()) {
1046
+ return null;
1047
+ }
1048
+ try {
1049
+ const savedState = sessionStorage.getItem(STORAGE_KEY);
1050
+ if (!savedState) {
1051
+ return null;
1052
+ }
1053
+ const parsed = JSON.parse(savedState);
1054
+ const stateAge = Date.now() - new Date(parsed.timestamp).getTime();
1055
+ if (stateAge > STATE_EXPIRY_MS) {
1056
+ clearConsentState();
1057
+ return null;
1058
+ }
1059
+ return parsed;
1060
+ } catch (error) {
1061
+ console.error("Failed to get consent state:", error);
1062
+ return null;
1063
+ }
1064
+ };
1065
+ var clearConsentState = () => {
1066
+ if (!isBrowser()) {
1067
+ return;
1068
+ }
1069
+ try {
1070
+ sessionStorage.removeItem(STORAGE_KEY);
1071
+ } catch (error) {
1072
+ console.error("Failed to clear consent state:", error);
1073
+ }
1074
+ };
1075
+ var updateConsentState = (updates) => {
1076
+ const currentState = getConsentState();
1077
+ if (currentState) {
1078
+ saveConsentState({
1079
+ ...currentState,
1080
+ ...updates,
1081
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
1082
+ });
1083
+ }
1084
+ };
1085
+
876
1086
  // src/RedactoNoticeConsent/RedactoNoticeConsent.tsx
877
1087
  var import_jsx_runtime = require("react/jsx-runtime");
878
1088
  var PurposeItem = ({
@@ -1180,6 +1390,12 @@ var PurposeItem = ({
1180
1390
  )
1181
1391
  ] }, purpose.uuid);
1182
1392
  };
1393
+ var RELATIONSHIP_OPTIONS = [
1394
+ { value: "Father", label: "Father" },
1395
+ { value: "Mother", label: "Mother" },
1396
+ { value: "Legal Guardian", label: "Legal Guardian" },
1397
+ { value: "Grandparent", label: "Grandparent" }
1398
+ ];
1183
1399
  var GuardianForm = ({
1184
1400
  formData,
1185
1401
  errors,
@@ -1196,34 +1412,128 @@ var GuardianForm = ({
1196
1412
  declineButtonStyle,
1197
1413
  logoUrl
1198
1414
  }) => {
1415
+ var _a, _b, _c, _d, _e;
1416
+ const [isDropdownOpen, setIsDropdownOpen] = (0, import_react2.useState)(false);
1417
+ const [focusedIndex, setFocusedIndex] = (0, import_react2.useState)(-1);
1418
+ const [openUpward, setOpenUpward] = (0, import_react2.useState)(false);
1419
+ const dropdownRef = (0, import_react2.useRef)(null);
1420
+ const optionsRef = (0, import_react2.useRef)(null);
1421
+ (0, import_react2.useEffect)(() => {
1422
+ if (!isDropdownOpen) return;
1423
+ const handleClickOutside = (e) => {
1424
+ if (dropdownRef.current && !dropdownRef.current.contains(e.target)) {
1425
+ setIsDropdownOpen(false);
1426
+ setFocusedIndex(-1);
1427
+ }
1428
+ };
1429
+ document.addEventListener("mousedown", handleClickOutside);
1430
+ return () => document.removeEventListener("mousedown", handleClickOutside);
1431
+ }, [isDropdownOpen]);
1432
+ (0, import_react2.useEffect)(() => {
1433
+ if (!isDropdownOpen || !dropdownRef.current) return;
1434
+ const rect = dropdownRef.current.getBoundingClientRect();
1435
+ const spaceBelow = window.innerHeight - rect.bottom;
1436
+ const dropdownHeight = 220;
1437
+ setOpenUpward(spaceBelow < dropdownHeight && rect.top > dropdownHeight);
1438
+ }, [isDropdownOpen]);
1439
+ const handleSelect = (value) => {
1440
+ onChange("guardianRelationship", value);
1441
+ setIsDropdownOpen(false);
1442
+ setFocusedIndex(-1);
1443
+ };
1444
+ const handleKeyDown = (e) => {
1445
+ if (!isDropdownOpen) {
1446
+ if (e.key === "Enter" || e.key === " " || e.key === "ArrowDown") {
1447
+ e.preventDefault();
1448
+ setIsDropdownOpen(true);
1449
+ setFocusedIndex(0);
1450
+ }
1451
+ return;
1452
+ }
1453
+ switch (e.key) {
1454
+ case "ArrowDown":
1455
+ e.preventDefault();
1456
+ setFocusedIndex((prev) => Math.min(prev + 1, RELATIONSHIP_OPTIONS.length - 1));
1457
+ break;
1458
+ case "ArrowUp":
1459
+ e.preventDefault();
1460
+ setFocusedIndex((prev) => Math.max(prev - 1, 0));
1461
+ break;
1462
+ case "Enter":
1463
+ case " ":
1464
+ e.preventDefault();
1465
+ if (focusedIndex >= 0) handleSelect(RELATIONSHIP_OPTIONS[focusedIndex].value);
1466
+ break;
1467
+ case "Escape":
1468
+ case "Tab":
1469
+ setIsDropdownOpen(false);
1470
+ setFocusedIndex(-1);
1471
+ break;
1472
+ }
1473
+ };
1474
+ (0, import_react2.useEffect)(() => {
1475
+ var _a2;
1476
+ if (focusedIndex >= 0 && optionsRef.current) {
1477
+ const option = optionsRef.current.children[focusedIndex];
1478
+ (_a2 = option == null ? void 0 : option.scrollIntoView) == null ? void 0 : _a2.call(option, { block: "nearest" });
1479
+ }
1480
+ }, [focusedIndex]);
1481
+ const borderColor = (settings == null ? void 0 : settings.borderColor) || "#d0d5dd";
1482
+ const textColor = (settings == null ? void 0 : settings.textColor) || "#344054";
1483
+ const bgColor = (settings == null ? void 0 : settings.backgroundColor) || "#ffffff";
1484
+ const radius = (settings == null ? void 0 : settings.borderRadius) || "8px";
1485
+ const font = (settings == null ? void 0 : settings.font) || "inherit";
1199
1486
  const inputStyle = {
1200
1487
  width: "100%",
1201
1488
  padding: "10px 12px",
1202
- border: `1px solid ${(settings == null ? void 0 : settings.borderColor) || "#d0d5dd"}`,
1203
- borderRadius: (settings == null ? void 0 : settings.borderRadius) || "8px",
1489
+ border: `1px solid ${borderColor}`,
1490
+ borderRadius: radius,
1204
1491
  fontSize: "13px",
1205
- fontFamily: (settings == null ? void 0 : settings.font) || "inherit",
1206
- color: (settings == null ? void 0 : settings.textColor) || "#344054",
1207
- backgroundColor: (settings == null ? void 0 : settings.backgroundColor) || "#ffffff",
1208
- marginBottom: "4px",
1209
- boxSizing: "border-box"
1492
+ fontFamily: font,
1493
+ color: textColor,
1494
+ backgroundColor: bgColor,
1495
+ marginBottom: "2px",
1496
+ boxSizing: "border-box",
1497
+ outline: "none"
1210
1498
  };
1211
1499
  const errorStyle = {
1212
1500
  color: "#DC2626",
1213
- fontSize: "12px",
1501
+ fontSize: "11px",
1214
1502
  marginTop: "4px",
1215
- marginBottom: "16px"
1503
+ marginBottom: "0px"
1216
1504
  };
1217
1505
  const labelStyle = {
1218
1506
  ...componentTextStyle,
1219
1507
  fontSize: "13px",
1220
1508
  fontWeight: "500",
1221
- marginBottom: "6px",
1509
+ marginBottom: "4px",
1222
1510
  display: "block"
1223
1511
  };
1512
+ const hintStyle = {
1513
+ fontSize: "11px",
1514
+ color: "#667085",
1515
+ marginTop: "2px",
1516
+ marginBottom: "0px",
1517
+ lineHeight: "1.4"
1518
+ };
1519
+ const infoBannerStyle = {
1520
+ display: "flex",
1521
+ alignItems: "flex-start",
1522
+ gap: "8px",
1523
+ padding: "10px 12px",
1524
+ backgroundColor: "#EFF6FF",
1525
+ border: "1px solid #BFDBFE",
1526
+ borderRadius: radius,
1527
+ marginBottom: "16px",
1528
+ fontSize: "12px",
1529
+ lineHeight: "1.5",
1530
+ color: "#1E40AF"
1531
+ };
1532
+ const selectedLabel = (_a = RELATIONSHIP_OPTIONS.find((o) => o.value === formData.guardianRelationship)) == null ? void 0 : _a.label;
1533
+ const hasError = Boolean(errors.guardianRelationship);
1224
1534
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
1225
1535
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { ...styles3.topSection, ...componentTextStyle }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles3.topLeft, children: [
1226
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("img", { style: styles3.logo, src: logoUrl, alt: "Redacto Logo" }),
1536
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("img", { style: styles3.logo, src: logoUrl, alt: "Logo" }),
1227
1537
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1228
1538
  "h2",
1229
1539
  {
@@ -1235,7 +1545,7 @@ var GuardianForm = ({
1235
1545
  fontSize: "16px",
1236
1546
  fontWeight: 600
1237
1547
  },
1238
- children: "Guardian Information Required"
1548
+ children: "Guardian Verification"
1239
1549
  }
1240
1550
  )
1241
1551
  ] }) }),
@@ -1255,31 +1565,49 @@ var GuardianForm = ({
1255
1565
  ...styles3.privacyText,
1256
1566
  ...responsiveStyles.privacyText,
1257
1567
  ...componentTextStyle,
1258
- fontSize: "14px",
1259
- lineHeight: "1.4"
1568
+ fontSize: "13px",
1569
+ lineHeight: "1.5",
1570
+ marginBottom: "12px"
1260
1571
  },
1261
- children: "As you are under the age of consent, we need to collect information about your legal guardian to proceed."
1572
+ children: "Since you are under the age of consent, a legal guardian must verify their identity via DigiLocker before you can proceed."
1262
1573
  }
1263
1574
  ),
1575
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: infoBannerStyle, children: [
1576
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1577
+ "svg",
1578
+ {
1579
+ width: "16",
1580
+ height: "16",
1581
+ viewBox: "0 0 24 24",
1582
+ fill: "none",
1583
+ stroke: "#2563EB",
1584
+ strokeWidth: "2",
1585
+ strokeLinecap: "round",
1586
+ strokeLinejoin: "round",
1587
+ style: { flexShrink: 0, marginTop: "1px" },
1588
+ children: [
1589
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "12", cy: "12", r: "10" }),
1590
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "12", y1: "16", x2: "12", y2: "12" }),
1591
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "12", y1: "8", x2: "12.01", y2: "8" })
1592
+ ]
1593
+ }
1594
+ ),
1595
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: "The guardian's name will be matched against their DigiLocker identity document (e.g. Aadhaar). Please enter the name exactly as it appears on the document." })
1596
+ ] }),
1264
1597
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1265
1598
  "div",
1266
1599
  {
1267
1600
  style: {
1268
1601
  display: "flex",
1269
1602
  flexDirection: "column",
1270
- gap: "12px",
1271
- marginTop: "16px"
1603
+ gap: "14px"
1272
1604
  },
1273
1605
  children: [
1274
1606
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
1275
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1276
- "label",
1277
- {
1278
- htmlFor: "guardianName",
1279
- style: { ...labelStyle, marginBottom: "8px", display: "block" },
1280
- children: "Name of Guardian *"
1281
- }
1282
- ),
1607
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { htmlFor: "guardianName", style: labelStyle, children: [
1608
+ "Guardian's Full Name ",
1609
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { color: "#DC2626" }, children: "*" })
1610
+ ] }),
1283
1611
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1284
1612
  "input",
1285
1613
  {
@@ -1289,62 +1617,170 @@ var GuardianForm = ({
1289
1617
  onChange: (e) => onChange("guardianName", e.target.value),
1290
1618
  style: {
1291
1619
  ...inputStyle,
1292
- borderColor: errors.guardianName ? "#DC2626" : inputStyle.border
1620
+ borderColor: errors.guardianName ? "#DC2626" : borderColor
1293
1621
  },
1294
- placeholder: "Enter guardian's full name"
1622
+ placeholder: "e.g. Rajesh Kumar",
1623
+ autoComplete: "name",
1624
+ "aria-describedby": "guardianName-hint"
1295
1625
  }
1296
1626
  ),
1297
- errors.guardianName && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: errorStyle, children: errors.guardianName })
1627
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { id: "guardianName-hint", style: hintStyle, children: "Enter the full name as per government ID (Aadhaar, PAN, etc.)" }),
1628
+ errors.guardianName && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: errorStyle, role: "alert", children: errors.guardianName })
1298
1629
  ] }),
1299
1630
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
1300
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1301
- "label",
1302
- {
1303
- htmlFor: "guardianContact",
1304
- style: { ...labelStyle, marginBottom: "8px", display: "block" },
1305
- children: "Contact of Guardian *"
1306
- }
1307
- ),
1631
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { htmlFor: "guardianContact", style: labelStyle, children: [
1632
+ "Guardian's Phone Number ",
1633
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { color: "#DC2626" }, children: "*" })
1634
+ ] }),
1308
1635
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1309
1636
  "input",
1310
1637
  {
1311
1638
  id: "guardianContact",
1312
- type: "text",
1639
+ type: "tel",
1640
+ inputMode: "tel",
1313
1641
  value: formData.guardianContact,
1314
1642
  onChange: (e) => onChange("guardianContact", e.target.value),
1315
1643
  style: {
1316
1644
  ...inputStyle,
1317
- borderColor: errors.guardianContact ? "#DC2626" : inputStyle.border
1645
+ borderColor: errors.guardianContact ? "#DC2626" : borderColor
1318
1646
  },
1319
- placeholder: "Enter guardian's email or phone number"
1647
+ placeholder: "e.g. 9876543210",
1648
+ autoComplete: "tel",
1649
+ "aria-describedby": "guardianContact-hint"
1320
1650
  }
1321
1651
  ),
1322
- errors.guardianContact && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: errorStyle, children: errors.guardianContact })
1652
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { id: "guardianContact-hint", style: hintStyle, children: "Mobile number linked to guardian's Aadhaar" }),
1653
+ errors.guardianContact && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: errorStyle, role: "alert", children: errors.guardianContact })
1323
1654
  ] }),
1324
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
1325
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1326
- "label",
1655
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { ref: dropdownRef, style: { position: "relative" }, children: [
1656
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { id: "guardianRelationship-label", style: labelStyle, children: [
1657
+ "Relationship ",
1658
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { color: "#DC2626" }, children: "*" })
1659
+ ] }),
1660
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1661
+ "div",
1327
1662
  {
1328
- htmlFor: "guardianRelationship",
1329
- style: { ...labelStyle, marginBottom: "8px", display: "block" },
1330
- children: "Relationship to Guardian *"
1663
+ role: "combobox",
1664
+ "aria-expanded": isDropdownOpen,
1665
+ "aria-haspopup": "listbox",
1666
+ "aria-labelledby": "guardianRelationship-label",
1667
+ "aria-controls": "guardianRelationship-listbox",
1668
+ "aria-activedescendant": focusedIndex >= 0 ? `guardianRelationship-option-${focusedIndex}` : void 0,
1669
+ tabIndex: 0,
1670
+ onClick: () => {
1671
+ setIsDropdownOpen((prev) => !prev);
1672
+ setFocusedIndex(-1);
1673
+ },
1674
+ onKeyDown: handleKeyDown,
1675
+ style: {
1676
+ ...inputStyle,
1677
+ borderColor: hasError ? "#DC2626" : isDropdownOpen ? ((_c = (_b = settings == null ? void 0 : settings.button) == null ? void 0 : _b.accept) == null ? void 0 : _c.backgroundColor) || "#3b82f6" : borderColor,
1678
+ boxShadow: isDropdownOpen ? `0 0 0 1px ${((_e = (_d = settings == null ? void 0 : settings.button) == null ? void 0 : _d.accept) == null ? void 0 : _e.backgroundColor) || "#3b82f6"}` : "none",
1679
+ color: selectedLabel ? textColor : "#9CA3AF",
1680
+ cursor: "pointer",
1681
+ display: "flex",
1682
+ alignItems: "center",
1683
+ justifyContent: "space-between",
1684
+ userSelect: "none",
1685
+ transition: "border-color 0.15s, box-shadow 0.15s"
1686
+ },
1687
+ children: [
1688
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }, children: selectedLabel || "Select relationship" }),
1689
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1690
+ "svg",
1691
+ {
1692
+ width: "14",
1693
+ height: "14",
1694
+ viewBox: "0 0 24 24",
1695
+ fill: "none",
1696
+ stroke: "#667085",
1697
+ strokeWidth: "2",
1698
+ strokeLinecap: "round",
1699
+ strokeLinejoin: "round",
1700
+ style: {
1701
+ flexShrink: 0,
1702
+ marginLeft: "8px",
1703
+ transform: isDropdownOpen ? "rotate(180deg)" : "rotate(0deg)",
1704
+ transition: "transform 0.2s"
1705
+ },
1706
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("polyline", { points: "6 9 12 15 18 9" })
1707
+ }
1708
+ )
1709
+ ]
1331
1710
  }
1332
1711
  ),
1333
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1334
- "input",
1712
+ isDropdownOpen && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1713
+ "div",
1335
1714
  {
1336
- id: "guardianRelationship",
1337
- type: "text",
1338
- value: formData.guardianRelationship,
1339
- onChange: (e) => onChange("guardianRelationship", e.target.value),
1715
+ ref: optionsRef,
1716
+ id: "guardianRelationship-listbox",
1717
+ role: "listbox",
1718
+ "aria-labelledby": "guardianRelationship-label",
1340
1719
  style: {
1341
- ...inputStyle,
1342
- borderColor: errors.guardianRelationship ? "#DC2626" : inputStyle.border
1720
+ position: "absolute",
1721
+ ...openUpward ? { bottom: "calc(100% + 4px)" } : { top: "calc(100% + 4px)" },
1722
+ left: 0,
1723
+ right: 0,
1724
+ backgroundColor: bgColor,
1725
+ border: `1px solid ${borderColor}`,
1726
+ borderRadius: radius,
1727
+ boxShadow: openUpward ? "0 -4px 12px rgba(0, 0, 0, 0.1), 0 -1px 3px rgba(0, 0, 0, 0.06)" : "0 4px 12px rgba(0, 0, 0, 0.1), 0 1px 3px rgba(0, 0, 0, 0.06)",
1728
+ zIndex: 50,
1729
+ overflow: "hidden",
1730
+ padding: "4px 0",
1731
+ maxHeight: "220px",
1732
+ overflowY: "auto"
1343
1733
  },
1344
- placeholder: "e.g., Parent, Legal Guardian, etc."
1734
+ children: RELATIONSHIP_OPTIONS.map((option, index) => {
1735
+ var _a2, _b2;
1736
+ const isSelected = formData.guardianRelationship === option.value;
1737
+ const isFocused = focusedIndex === index;
1738
+ const accentColor = ((_b2 = (_a2 = settings == null ? void 0 : settings.button) == null ? void 0 : _a2.accept) == null ? void 0 : _b2.backgroundColor) || "#3b82f6";
1739
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1740
+ "div",
1741
+ {
1742
+ id: `guardianRelationship-option-${index}`,
1743
+ role: "option",
1744
+ "aria-selected": isSelected,
1745
+ onClick: () => handleSelect(option.value),
1746
+ onMouseEnter: () => setFocusedIndex(index),
1747
+ style: {
1748
+ padding: "9px 12px",
1749
+ fontSize: "13px",
1750
+ fontFamily: font,
1751
+ color: isSelected ? accentColor : textColor,
1752
+ backgroundColor: isFocused ? "#F3F4F6" : "transparent",
1753
+ cursor: "pointer",
1754
+ display: "flex",
1755
+ alignItems: "center",
1756
+ justifyContent: "space-between",
1757
+ transition: "background-color 0.1s"
1758
+ },
1759
+ children: [
1760
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: option.label }),
1761
+ isSelected && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1762
+ "svg",
1763
+ {
1764
+ width: "14",
1765
+ height: "14",
1766
+ viewBox: "0 0 24 24",
1767
+ fill: "none",
1768
+ stroke: accentColor,
1769
+ strokeWidth: "2.5",
1770
+ strokeLinecap: "round",
1771
+ strokeLinejoin: "round",
1772
+ style: { flexShrink: 0 },
1773
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("polyline", { points: "20 6 9 17 4 12" })
1774
+ }
1775
+ )
1776
+ ]
1777
+ },
1778
+ option.value
1779
+ );
1780
+ })
1345
1781
  }
1346
1782
  ),
1347
- errors.guardianRelationship && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: errorStyle, children: errors.guardianRelationship })
1783
+ errors.guardianRelationship && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: errorStyle, role: "alert", children: errors.guardianRelationship })
1348
1784
  ] })
1349
1785
  ]
1350
1786
  }
@@ -1355,7 +1791,7 @@ var GuardianForm = ({
1355
1791
  role: "alert",
1356
1792
  style: {
1357
1793
  color: "#DC2626",
1358
- fontSize: "14px",
1794
+ fontSize: "13px",
1359
1795
  marginTop: "16px",
1360
1796
  padding: "12px",
1361
1797
  borderRadius: "6px",
@@ -1391,8 +1827,8 @@ var GuardianForm = ({
1391
1827
  onClick: onNext,
1392
1828
  disabled: isSubmitting,
1393
1829
  type: "button",
1394
- "aria-label": isSubmitting ? "Submitting guardian information" : "Submit guardian information and proceed",
1395
- children: isSubmitting ? "Submitting..." : "Next"
1830
+ "aria-label": isSubmitting ? "Verifying guardian identity" : "Proceed to guardian verification",
1831
+ children: isSubmitting ? "Verifying..." : "Verify via DigiLocker"
1396
1832
  }
1397
1833
  ),
1398
1834
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
@@ -1406,7 +1842,7 @@ var GuardianForm = ({
1406
1842
  },
1407
1843
  onClick: onDecline,
1408
1844
  type: "button",
1409
- "aria-label": "Cancel guardian information form",
1845
+ "aria-label": "Cancel",
1410
1846
  children: "Cancel"
1411
1847
  }
1412
1848
  )
@@ -1415,6 +1851,266 @@ var GuardianForm = ({
1415
1851
  )
1416
1852
  ] });
1417
1853
  };
1854
+ var VerificationScreen = ({
1855
+ onBack,
1856
+ onContinue,
1857
+ isInitiating,
1858
+ isPolling,
1859
+ isVerificationComplete,
1860
+ isAutoTransitioning,
1861
+ error,
1862
+ errorCode,
1863
+ canRetry,
1864
+ styles: styles3,
1865
+ responsiveStyles,
1866
+ settings,
1867
+ componentHeadingStyle,
1868
+ componentTextStyle,
1869
+ acceptButtonStyle,
1870
+ declineButtonStyle,
1871
+ logoUrl
1872
+ }) => {
1873
+ var _a, _b;
1874
+ const errorStyle = {
1875
+ color: "#DC2626",
1876
+ fontSize: "14px",
1877
+ marginTop: "16px",
1878
+ padding: "12px",
1879
+ borderRadius: "6px",
1880
+ border: "1px solid #FCA5A5",
1881
+ backgroundColor: "#FEF2F2",
1882
+ textAlign: "center"
1883
+ };
1884
+ const statusStyle = {
1885
+ color: "#059669",
1886
+ fontSize: "14px",
1887
+ marginTop: "16px",
1888
+ padding: "12px",
1889
+ borderRadius: "6px",
1890
+ border: "1px solid #A7F3D0",
1891
+ backgroundColor: "#D1FAE5",
1892
+ textAlign: "center"
1893
+ };
1894
+ const spinnerStyle = {
1895
+ width: "48px",
1896
+ height: "48px",
1897
+ border: "4px solid #e5e7eb",
1898
+ borderTopColor: ((_b = (_a = settings == null ? void 0 : settings.button) == null ? void 0 : _a.accept) == null ? void 0 : _b.backgroundColor) || "#3b82f6",
1899
+ borderRadius: "50%",
1900
+ animation: "spin 1s linear infinite",
1901
+ margin: "24px auto"
1902
+ };
1903
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
1904
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { ...styles3.topSection, ...componentTextStyle }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles3.topLeft, children: [
1905
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("img", { style: styles3.logo, src: logoUrl, alt: "Logo" }),
1906
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1907
+ "h2",
1908
+ {
1909
+ id: "verification-title",
1910
+ style: {
1911
+ ...styles3.title,
1912
+ ...responsiveStyles.title,
1913
+ ...componentHeadingStyle,
1914
+ fontSize: "16px",
1915
+ fontWeight: 600
1916
+ },
1917
+ children: "Guardian Verification"
1918
+ }
1919
+ )
1920
+ ] }) }),
1921
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1922
+ "div",
1923
+ {
1924
+ style: {
1925
+ ...styles3.middleSection,
1926
+ ...responsiveStyles.middleSection,
1927
+ ...componentTextStyle,
1928
+ textAlign: "center"
1929
+ },
1930
+ children: [
1931
+ isVerificationComplete && !error ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1932
+ "div",
1933
+ {
1934
+ style: {
1935
+ display: "flex",
1936
+ flexDirection: "column",
1937
+ alignItems: "center",
1938
+ justifyContent: "center",
1939
+ flex: 1
1940
+ },
1941
+ children: [
1942
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1943
+ "div",
1944
+ {
1945
+ style: {
1946
+ width: "64px",
1947
+ height: "64px",
1948
+ borderRadius: "50%",
1949
+ backgroundColor: "#D1FAE5",
1950
+ display: "flex",
1951
+ alignItems: "center",
1952
+ justifyContent: "center"
1953
+ },
1954
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1955
+ "svg",
1956
+ {
1957
+ width: "32",
1958
+ height: "32",
1959
+ viewBox: "0 0 24 24",
1960
+ fill: "none",
1961
+ stroke: "#059669",
1962
+ strokeWidth: "2",
1963
+ strokeLinecap: "round",
1964
+ strokeLinejoin: "round",
1965
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("polyline", { points: "20 6 9 17 4 12" })
1966
+ }
1967
+ )
1968
+ }
1969
+ ),
1970
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1971
+ "p",
1972
+ {
1973
+ style: {
1974
+ ...componentHeadingStyle,
1975
+ fontSize: "16px",
1976
+ fontWeight: 600,
1977
+ lineHeight: "1.5",
1978
+ marginTop: "12px",
1979
+ marginBottom: "24px"
1980
+ },
1981
+ children: "Verification Completed"
1982
+ }
1983
+ )
1984
+ ]
1985
+ }
1986
+ ) : (isInitiating || isPolling) && !error ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
1987
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: spinnerStyle }),
1988
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: statusStyle, children: isInitiating ? "Opening DigiLocker in a new tab..." : "Please complete the verification in the DigiLocker tab. This page will update automatically when verification is complete." })
1989
+ ] }) : null,
1990
+ error && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
1991
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1992
+ "div",
1993
+ {
1994
+ style: {
1995
+ width: "64px",
1996
+ height: "64px",
1997
+ borderRadius: "50%",
1998
+ backgroundColor: "#fee2e2",
1999
+ display: "flex",
2000
+ alignItems: "center",
2001
+ justifyContent: "center",
2002
+ margin: "24px auto"
2003
+ },
2004
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
2005
+ "svg",
2006
+ {
2007
+ width: "32",
2008
+ height: "32",
2009
+ viewBox: "0 0 24 24",
2010
+ fill: "none",
2011
+ stroke: "#dc2626",
2012
+ strokeWidth: "2",
2013
+ strokeLinecap: "round",
2014
+ strokeLinejoin: "round",
2015
+ children: [
2016
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
2017
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
2018
+ ]
2019
+ }
2020
+ )
2021
+ }
2022
+ ),
2023
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2024
+ "p",
2025
+ {
2026
+ style: {
2027
+ ...styles3.privacyText,
2028
+ ...responsiveStyles.privacyText,
2029
+ ...componentTextStyle,
2030
+ fontSize: "14px",
2031
+ lineHeight: "1.5",
2032
+ marginBottom: "12px"
2033
+ },
2034
+ children: "Verification failed"
2035
+ }
2036
+ ),
2037
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: errorStyle, children: error })
2038
+ ] })
2039
+ ]
2040
+ }
2041
+ ),
2042
+ isAutoTransitioning ? null : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2043
+ "div",
2044
+ {
2045
+ style: {
2046
+ ...styles3.bottomSection,
2047
+ ...responsiveStyles.bottomSection,
2048
+ ...componentTextStyle,
2049
+ paddingTop: "12px",
2050
+ display: "flex",
2051
+ gap: "12px",
2052
+ justifyContent: "center"
2053
+ },
2054
+ children: isVerificationComplete && !error ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2055
+ "button",
2056
+ {
2057
+ style: {
2058
+ ...styles3.button,
2059
+ ...responsiveStyles.button,
2060
+ ...acceptButtonStyle
2061
+ },
2062
+ onClick: onContinue,
2063
+ type: "button",
2064
+ "aria-label": "Continue to consent form",
2065
+ children: "Continue"
2066
+ }
2067
+ ) : error && canRetry ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2068
+ "button",
2069
+ {
2070
+ style: {
2071
+ ...styles3.button,
2072
+ ...responsiveStyles.button,
2073
+ ...styles3.acceptButton,
2074
+ ...acceptButtonStyle
2075
+ },
2076
+ onClick: () => onBack(errorCode === "GUARDIAN_UNDER_18"),
2077
+ type: "button",
2078
+ "aria-label": errorCode === "GUARDIAN_UNDER_18" ? "Change guardian details" : "Try verification again",
2079
+ children: errorCode === "GUARDIAN_UNDER_18" ? "Change Guardian" : "Try Again"
2080
+ }
2081
+ ) : error ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2082
+ "button",
2083
+ {
2084
+ style: {
2085
+ ...styles3.button,
2086
+ ...responsiveStyles.button,
2087
+ ...styles3.cancelButton,
2088
+ ...declineButtonStyle
2089
+ },
2090
+ onClick: () => onBack(false),
2091
+ type: "button",
2092
+ "aria-label": "Go back",
2093
+ children: "Go Back"
2094
+ }
2095
+ ) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2096
+ "button",
2097
+ {
2098
+ style: {
2099
+ ...styles3.button,
2100
+ ...responsiveStyles.button,
2101
+ ...styles3.cancelButton,
2102
+ ...declineButtonStyle
2103
+ },
2104
+ onClick: () => onBack(false),
2105
+ type: "button",
2106
+ "aria-label": "Cancel verification",
2107
+ children: "Cancel"
2108
+ }
2109
+ )
2110
+ }
2111
+ )
2112
+ ] });
2113
+ };
1418
2114
  var AgeVerification = ({
1419
2115
  onYes,
1420
2116
  onNo,
@@ -1577,6 +2273,10 @@ var RedactoNoticeConsent = ({
1577
2273
  settings,
1578
2274
  applicationId,
1579
2275
  validateAgainst = "all",
2276
+ digilockerMode = "redirect",
2277
+ // Default to full page redirect (DigiLocker blocks iframe embedding)
2278
+ digilockerCallbackUrl = "/digilocker-callback",
2279
+ // Default callback path
1580
2280
  includeFullyConsentedData = false,
1581
2281
  reviewModeButtonText = "Continue"
1582
2282
  }) => {
@@ -1632,6 +2332,8 @@ var RedactoNoticeConsent = ({
1632
2332
  const [currentAudioIndex, setCurrentAudioIndex] = (0, import_react2.useState)(0);
1633
2333
  const [highlightedElementId, setHighlightedElementId] = (0, import_react2.useState)(null);
1634
2334
  const [showAgeVerification, setShowAgeVerification] = (0, import_react2.useState)(false);
2335
+ const [isMinorFlow, setIsMinorFlow] = (0, import_react2.useState)(false);
2336
+ const [selfDeclaredAdult, setSelfDeclaredAdult] = (0, import_react2.useState)(false);
1635
2337
  const [showGuardianForm, setShowGuardianForm] = (0, import_react2.useState)(false);
1636
2338
  const [isSubmittingGuardian, setIsSubmittingGuardian] = (0, import_react2.useState)(false);
1637
2339
  const [guardianFormData, setGuardianFormData] = (0, import_react2.useState)({
@@ -1640,12 +2342,32 @@ var RedactoNoticeConsent = ({
1640
2342
  guardianRelationship: ""
1641
2343
  });
1642
2344
  const [guardianFormErrors, setGuardianFormErrors] = (0, import_react2.useState)({});
2345
+ const [showVerificationScreen, setShowVerificationScreen] = (0, import_react2.useState)(false);
2346
+ const [verificationReference, setVerificationReference] = (0, import_react2.useState)(null);
2347
+ const [isInitiatingVerification, setIsInitiatingVerification] = (0, import_react2.useState)(false);
2348
+ const [verificationError, setVerificationError] = (0, import_react2.useState)(
2349
+ null
2350
+ );
2351
+ const [verificationErrorCode, setVerificationErrorCode] = (0, import_react2.useState)(null);
2352
+ const [canRetryVerification, setCanRetryVerification] = (0, import_react2.useState)(false);
2353
+ const [isPollingStatus, setIsPollingStatus] = (0, import_react2.useState)(false);
2354
+ const [isVerificationComplete, setIsVerificationComplete] = (0, import_react2.useState)(false);
2355
+ const [isAutoTransitioning, setIsAutoTransitioning] = (0, import_react2.useState)(false);
1643
2356
  const modalRef = (0, import_react2.useRef)(null);
1644
2357
  const firstFocusableRef = (0, import_react2.useRef)(null);
1645
2358
  const lastFocusableRef = (0, import_react2.useRef)(null);
1646
2359
  const abortControllerRef = (0, import_react2.useRef)(null);
1647
2360
  const isRequestInProgressRef = (0, import_react2.useRef)(false);
1648
2361
  const currentAudioRef = (0, import_react2.useRef)(null);
2362
+ const popupCheckIntervalRef = (0, import_react2.useRef)(null);
2363
+ const statusPollIntervalRef = (0, import_react2.useRef)(null);
2364
+ const verificationPopupRef = (0, import_react2.useRef)(null);
2365
+ const pollingCleanupRef = (0, import_react2.useRef)(null);
2366
+ const autoTransitionTimerRef = (0, import_react2.useRef)(null);
2367
+ const digilockerRedirectTimeoutRef = (0, import_react2.useRef)(null);
2368
+ const isInitialMountRef = (0, import_react2.useRef)(true);
2369
+ const isPollingStatusRef = (0, import_react2.useRef)(false);
2370
+ const verificationSessionTokenRef = (0, import_react2.useRef)(null);
1649
2371
  const isMobile = useMediaQuery("(max-width: 768px)");
1650
2372
  const responsiveStyles = (0, import_react2.useMemo)(
1651
2373
  () => ({
@@ -1753,6 +2475,7 @@ var RedactoNoticeConsent = ({
1753
2475
  }, [content, selectedDataElements]);
1754
2476
  const acceptDisabled = isSubmitting || !areAllRequiredElementsChecked;
1755
2477
  (0, import_react2.useEffect)(() => {
2478
+ var _a2, _b2;
1756
2479
  clearApiCache();
1757
2480
  isRequestInProgressRef.current = false;
1758
2481
  setContent(null);
@@ -1768,6 +2491,8 @@ var RedactoNoticeConsent = ({
1768
2491
  setIsSubmittingAccept(false);
1769
2492
  setIsSubmittingDecline(false);
1770
2493
  setShowAgeVerification(false);
2494
+ setIsMinorFlow(false);
2495
+ setSelfDeclaredAdult(false);
1771
2496
  setShowGuardianForm(false);
1772
2497
  setIsSubmittingGuardian(false);
1773
2498
  setGuardianFormData({
@@ -1776,6 +2501,41 @@ var RedactoNoticeConsent = ({
1776
2501
  guardianRelationship: ""
1777
2502
  });
1778
2503
  setGuardianFormErrors({});
2504
+ setShowVerificationScreen(false);
2505
+ setVerificationReference(null);
2506
+ setIsInitiatingVerification(false);
2507
+ setVerificationError(null);
2508
+ setVerificationErrorCode(null);
2509
+ setCanRetryVerification(false);
2510
+ setIsVerificationComplete(false);
2511
+ setIsAutoTransitioning(false);
2512
+ setIsPollingStatus(false);
2513
+ isPollingStatusRef.current = false;
2514
+ verificationSessionTokenRef.current = null;
2515
+ if (popupCheckIntervalRef.current) {
2516
+ clearInterval(popupCheckIntervalRef.current);
2517
+ popupCheckIntervalRef.current = null;
2518
+ }
2519
+ if (statusPollIntervalRef.current) {
2520
+ clearTimeout(statusPollIntervalRef.current);
2521
+ statusPollIntervalRef.current = null;
2522
+ }
2523
+ (_a2 = pollingCleanupRef.current) == null ? void 0 : _a2.call(pollingCleanupRef);
2524
+ pollingCleanupRef.current = null;
2525
+ (_b2 = verificationPopupRef.current) == null ? void 0 : _b2.close();
2526
+ verificationPopupRef.current = null;
2527
+ if (autoTransitionTimerRef.current) {
2528
+ clearTimeout(autoTransitionTimerRef.current);
2529
+ autoTransitionTimerRef.current = null;
2530
+ }
2531
+ if (digilockerRedirectTimeoutRef.current) {
2532
+ clearTimeout(digilockerRedirectTimeoutRef.current);
2533
+ digilockerRedirectTimeoutRef.current = null;
2534
+ }
2535
+ if (!isInitialMountRef.current) {
2536
+ clearConsentState();
2537
+ }
2538
+ isInitialMountRef.current = false;
1779
2539
  }, [accessToken]);
1780
2540
  (0, import_react2.useEffect)(() => {
1781
2541
  if (hasAlreadyConsented) {
@@ -1984,7 +2744,11 @@ var RedactoNoticeConsent = ({
1984
2744
  setInitialDataElementSelections({});
1985
2745
  }
1986
2746
  if (consentContentData.detail.is_minor) {
1987
- setShowAgeVerification(true);
2747
+ setIsMinorFlow(true);
2748
+ const persistedState = getConsentState();
2749
+ if (!(persistedState == null ? void 0 : persistedState.sessionToken) && !(persistedState == null ? void 0 : persistedState.verificationReference)) {
2750
+ setShowAgeVerification(true);
2751
+ }
1988
2752
  }
1989
2753
  setIsLoading(false);
1990
2754
  } catch (err) {
@@ -2083,6 +2847,10 @@ var RedactoNoticeConsent = ({
2083
2847
  const handleAccept = async () => {
2084
2848
  const submitController = new AbortController();
2085
2849
  try {
2850
+ if (isMinorFlow && !verificationReference) {
2851
+ setErrorMessage("Guardian verification is required before consent can be submitted.");
2852
+ return;
2853
+ }
2086
2854
  setIsSubmittingAccept(true);
2087
2855
  setIsSubmitting(true);
2088
2856
  setErrorMessage(null);
@@ -2117,7 +2885,10 @@ var RedactoNoticeConsent = ({
2117
2885
  };
2118
2886
  }),
2119
2887
  declined: false,
2888
+ language: toBcp47Code(selectedLanguage),
2120
2889
  meta_data: applicationId ? { specific_uuid: applicationId } : void 0,
2890
+ guardianVerificationReference: verificationReference || void 0,
2891
+ selfDeclaredAdult: selfDeclaredAdult || void 0,
2121
2892
  signal: submitController.signal
2122
2893
  });
2123
2894
  }
@@ -2182,17 +2953,102 @@ var RedactoNoticeConsent = ({
2182
2953
  try {
2183
2954
  setIsSubmittingGuardian(true);
2184
2955
  setGuardianFormErrors({});
2185
- await submitGuardianInfo({
2956
+ setVerificationError(null);
2957
+ const callbackUrl = digilockerMode === "popup" ? new URL(digilockerCallbackUrl, window.location.origin).href : void 0;
2958
+ const response = await initiateGuardianVerification({
2186
2959
  accessToken,
2187
2960
  baseUrl,
2188
2961
  guardianName: guardianFormData.guardianName,
2189
2962
  guardianContact: guardianFormData.guardianContact,
2190
2963
  guardianRelationship: guardianFormData.guardianRelationship,
2964
+ frontendCallbackUrl: callbackUrl,
2965
+ // Only for popup mode
2191
2966
  signal: guardianController.signal
2192
2967
  });
2968
+ setIsSubmittingGuardian(false);
2969
+ if (response.already_verified && response.verification_reference) {
2970
+ setVerificationReference(response.verification_reference);
2971
+ setShowGuardianForm(false);
2972
+ setShowVerificationScreen(true);
2973
+ setIsInitiatingVerification(false);
2974
+ setIsVerificationComplete(true);
2975
+ setIsAutoTransitioning(true);
2976
+ autoTransitionTimerRef.current = setTimeout(() => {
2977
+ setShowVerificationScreen(false);
2978
+ setIsVerificationComplete(false);
2979
+ setIsAutoTransitioning(false);
2980
+ autoTransitionTimerRef.current = null;
2981
+ }, 1e3);
2982
+ return;
2983
+ }
2984
+ if (!response.session_token || !response.digilocker_redirect_url) {
2985
+ throw new Error("Invalid response from server: missing required fields");
2986
+ }
2193
2987
  setShowGuardianForm(false);
2988
+ setShowVerificationScreen(true);
2989
+ setIsInitiatingVerification(true);
2990
+ if (digilockerMode === "redirect") {
2991
+ saveConsentState({
2992
+ flowState: "digilocker-pending",
2993
+ sessionToken: response.session_token,
2994
+ guardianInfoUuid: response.guardian_info_uuid,
2995
+ selectedPurposes,
2996
+ selectedDataElements,
2997
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
2998
+ originalUrl: window.location.href,
2999
+ noticeId,
3000
+ baseUrl
3001
+ });
3002
+ try {
3003
+ const openedWindow = window.open(
3004
+ response.digilocker_redirect_url,
3005
+ "_blank"
3006
+ );
3007
+ if (!openedWindow) {
3008
+ console.warn("Popup blocked \u2014 cannot open DigiLocker in new tab");
3009
+ setIsInitiatingVerification(false);
3010
+ setVerificationError(
3011
+ "Unable to open DigiLocker in a new tab. Please allow popups for this site and try again."
3012
+ );
3013
+ return;
3014
+ }
3015
+ try {
3016
+ openedWindow.opener = null;
3017
+ } catch {
3018
+ }
3019
+ } catch (error) {
3020
+ console.error("Failed to open DigiLocker in new tab:", error);
3021
+ setIsInitiatingVerification(false);
3022
+ setVerificationError(
3023
+ "Unable to open DigiLocker. Please allow popups for this site and try again."
3024
+ );
3025
+ return;
3026
+ }
3027
+ setIsInitiatingVerification(false);
3028
+ setIsPollingStatus(true);
3029
+ isPollingStatusRef.current = true;
3030
+ startStatusPolling(response.session_token);
3031
+ } else {
3032
+ setIsInitiatingVerification(true);
3033
+ const popup = window.open(
3034
+ response.digilocker_redirect_url,
3035
+ "digilocker_verification",
3036
+ "width=600,height=700,scrollbars=yes,resizable=yes"
3037
+ );
3038
+ if (popup) {
3039
+ verificationPopupRef.current = popup;
3040
+ startPopupMonitoring(popup);
3041
+ startStatusPolling(response.session_token);
3042
+ } else {
3043
+ setIsInitiatingVerification(false);
3044
+ setVerificationError(
3045
+ "Popup blocked. Please allow popups for this site or use redirect mode."
3046
+ );
3047
+ }
3048
+ }
2194
3049
  } catch (error) {
2195
3050
  const err = error;
3051
+ setIsInitiatingVerification(false);
2196
3052
  if (err.status === 422) {
2197
3053
  if (err.message.includes("guardian_contact")) {
2198
3054
  setGuardianFormErrors({ guardianContact: err.message });
@@ -2203,23 +3059,265 @@ var RedactoNoticeConsent = ({
2203
3059
  } else {
2204
3060
  setGuardianFormErrors({ general: err.message });
2205
3061
  }
3062
+ setShowVerificationScreen(false);
3063
+ setShowGuardianForm(true);
2206
3064
  } else {
2207
3065
  setGuardianFormErrors({
2208
- general: err.message || "Failed to submit guardian information. Please try again."
3066
+ general: err.message || "Failed to initiate verification. Please try again."
2209
3067
  });
3068
+ setShowVerificationScreen(false);
3069
+ setShowGuardianForm(true);
2210
3070
  onError == null ? void 0 : onError(err);
2211
3071
  }
2212
3072
  } finally {
2213
3073
  setIsSubmittingGuardian(false);
2214
3074
  }
2215
- }, [accessToken, baseUrl, guardianFormData, onError]);
3075
+ }, [accessToken, baseUrl, guardianFormData, digilockerMode, digilockerCallbackUrl, selectedPurposes, selectedDataElements, noticeId, onError]);
2216
3076
  const handleAgeVerificationYes = (0, import_react2.useCallback)(() => {
2217
3077
  setShowAgeVerification(false);
3078
+ setIsMinorFlow(false);
3079
+ setSelfDeclaredAdult(true);
2218
3080
  }, []);
2219
3081
  const handleAgeVerificationNo = (0, import_react2.useCallback)(() => {
2220
3082
  setShowAgeVerification(false);
2221
3083
  setShowGuardianForm(true);
2222
3084
  }, []);
3085
+ const handleVerificationContinue = (0, import_react2.useCallback)(() => {
3086
+ setShowVerificationScreen(false);
3087
+ setIsVerificationComplete(false);
3088
+ }, []);
3089
+ const handlePopupClosed = (0, import_react2.useCallback)(async () => {
3090
+ var _a2, _b2;
3091
+ if (popupCheckIntervalRef.current) {
3092
+ clearInterval(popupCheckIntervalRef.current);
3093
+ popupCheckIntervalRef.current = null;
3094
+ }
3095
+ if (statusPollIntervalRef.current) {
3096
+ clearTimeout(statusPollIntervalRef.current);
3097
+ statusPollIntervalRef.current = null;
3098
+ }
3099
+ (_a2 = pollingCleanupRef.current) == null ? void 0 : _a2.call(pollingCleanupRef);
3100
+ pollingCleanupRef.current = null;
3101
+ verificationPopupRef.current = null;
3102
+ if (!isPollingStatusRef.current) return;
3103
+ const sessionToken = verificationSessionTokenRef.current;
3104
+ if (sessionToken) {
3105
+ try {
3106
+ const response = await verifyGuardianStatus({
3107
+ accessToken,
3108
+ baseUrl,
3109
+ sessionToken
3110
+ });
3111
+ if (response.status === "verified") {
3112
+ const ref = response.verification_reference || ((_b2 = response.guardian_details) == null ? void 0 : _b2.verification_reference);
3113
+ if (ref) {
3114
+ setVerificationReference(ref);
3115
+ setIsVerificationComplete(true);
3116
+ setIsPollingStatus(false);
3117
+ isPollingStatusRef.current = false;
3118
+ setIsInitiatingVerification(false);
3119
+ clearConsentState();
3120
+ return;
3121
+ }
3122
+ }
3123
+ } catch {
3124
+ }
3125
+ }
3126
+ setVerificationError(
3127
+ "Verification window was closed. Please try again."
3128
+ );
3129
+ setIsPollingStatus(false);
3130
+ isPollingStatusRef.current = false;
3131
+ setIsInitiatingVerification(false);
3132
+ }, [accessToken, baseUrl]);
3133
+ const startPopupMonitoring = (0, import_react2.useCallback)((popup) => {
3134
+ popupCheckIntervalRef.current = window.setInterval(() => {
3135
+ if (popup.closed) {
3136
+ handlePopupClosed();
3137
+ }
3138
+ }, 500);
3139
+ }, [handlePopupClosed]);
3140
+ const getVerificationErrorMessage = (0, import_react2.useCallback)(
3141
+ (errorCode, fallbackError) => {
3142
+ switch (errorCode) {
3143
+ case "GUARDIAN_UNDER_18":
3144
+ return "The guardian must be 18 years or older. Please provide details of a different guardian.";
3145
+ case "TOKEN_FAILED":
3146
+ return "DigiLocker verification could not be completed. Please try again.";
3147
+ case "DIGILOCKER_AUTH_FAILED":
3148
+ return "DigiLocker authorization was cancelled or failed. Please try again.";
3149
+ case "NO_AUTH_CODE":
3150
+ return "DigiLocker did not return an authorization code. Please try again.";
3151
+ case "SESSION_EXPIRED":
3152
+ return "Verification session has expired. Please try again.";
3153
+ default:
3154
+ return fallbackError || "Verification failed. Please try again.";
3155
+ }
3156
+ },
3157
+ []
3158
+ );
3159
+ const startStatusPolling = (0, import_react2.useCallback)(
3160
+ (token) => {
3161
+ verificationSessionTokenRef.current = token;
3162
+ setIsPollingStatus(true);
3163
+ isPollingStatusRef.current = true;
3164
+ setVerificationError(null);
3165
+ setVerificationErrorCode(null);
3166
+ setCanRetryVerification(false);
3167
+ let attempts = 0;
3168
+ let consecutiveErrors = 0;
3169
+ let paused = false;
3170
+ const MAX_ATTEMPTS = 40;
3171
+ const MAX_CONSECUTIVE_ERRORS = 3;
3172
+ const POLL_INTERVAL = 3e3;
3173
+ const stopPolling = () => {
3174
+ var _a2;
3175
+ if (statusPollIntervalRef.current) {
3176
+ clearTimeout(statusPollIntervalRef.current);
3177
+ statusPollIntervalRef.current = null;
3178
+ }
3179
+ if (popupCheckIntervalRef.current) {
3180
+ clearInterval(popupCheckIntervalRef.current);
3181
+ popupCheckIntervalRef.current = null;
3182
+ }
3183
+ (_a2 = verificationPopupRef.current) == null ? void 0 : _a2.close();
3184
+ verificationPopupRef.current = null;
3185
+ document.removeEventListener("visibilitychange", onVisibilityChange);
3186
+ pollingCleanupRef.current = null;
3187
+ setIsPollingStatus(false);
3188
+ isPollingStatusRef.current = false;
3189
+ setIsInitiatingVerification(false);
3190
+ };
3191
+ const setError = (message, errorCode, canRetry) => {
3192
+ stopPolling();
3193
+ setVerificationError(message);
3194
+ setVerificationErrorCode(errorCode);
3195
+ setCanRetryVerification(canRetry);
3196
+ };
3197
+ const poll = async () => {
3198
+ var _a2;
3199
+ if (paused) return;
3200
+ attempts++;
3201
+ if (attempts > MAX_ATTEMPTS) {
3202
+ setError(
3203
+ "Verification is taking longer than expected. Please try again.",
3204
+ "SESSION_EXPIRED",
3205
+ true
3206
+ );
3207
+ return;
3208
+ }
3209
+ try {
3210
+ const response = await verifyGuardianStatus({
3211
+ accessToken,
3212
+ baseUrl,
3213
+ sessionToken: token
3214
+ });
3215
+ consecutiveErrors = 0;
3216
+ if (response.status === "verified") {
3217
+ stopPolling();
3218
+ const ref = response.verification_reference || ((_a2 = response.guardian_details) == null ? void 0 : _a2.verification_reference);
3219
+ if (!ref) {
3220
+ setError(
3221
+ "Verification completed but no reference received. Please try again.",
3222
+ null,
3223
+ true
3224
+ );
3225
+ return;
3226
+ }
3227
+ setVerificationReference(ref);
3228
+ setIsVerificationComplete(true);
3229
+ clearConsentState();
3230
+ return;
3231
+ }
3232
+ if (response.status === "failed" || response.status === "expired") {
3233
+ setError(
3234
+ getVerificationErrorMessage(response.error_code, response.error),
3235
+ response.error_code,
3236
+ response.can_retry
3237
+ );
3238
+ return;
3239
+ }
3240
+ if (!paused) {
3241
+ statusPollIntervalRef.current = window.setTimeout(poll, POLL_INTERVAL);
3242
+ }
3243
+ } catch (error) {
3244
+ const err = error;
3245
+ if (err.status === 404 || err.status === 410) {
3246
+ setError(
3247
+ "Verification session not found or expired. Please try again.",
3248
+ "SESSION_EXPIRED",
3249
+ true
3250
+ );
3251
+ return;
3252
+ }
3253
+ consecutiveErrors++;
3254
+ if (consecutiveErrors >= MAX_CONSECUTIVE_ERRORS) {
3255
+ setError(
3256
+ err.message || "Unable to check verification status. Please try again.",
3257
+ null,
3258
+ true
3259
+ );
3260
+ return;
3261
+ }
3262
+ statusPollIntervalRef.current = window.setTimeout(poll, POLL_INTERVAL);
3263
+ }
3264
+ };
3265
+ const onVisibilityChange = () => {
3266
+ if (document.hidden) {
3267
+ paused = true;
3268
+ if (statusPollIntervalRef.current) {
3269
+ clearTimeout(statusPollIntervalRef.current);
3270
+ statusPollIntervalRef.current = null;
3271
+ }
3272
+ } else {
3273
+ paused = false;
3274
+ poll();
3275
+ }
3276
+ };
3277
+ document.addEventListener("visibilitychange", onVisibilityChange);
3278
+ pollingCleanupRef.current = () => {
3279
+ document.removeEventListener("visibilitychange", onVisibilityChange);
3280
+ };
3281
+ statusPollIntervalRef.current = window.setTimeout(poll, POLL_INTERVAL);
3282
+ },
3283
+ [accessToken, baseUrl, getVerificationErrorMessage]
3284
+ );
3285
+ const handleBackToGuardianForm = (0, import_react2.useCallback)((clearName = false) => {
3286
+ var _a2, _b2;
3287
+ (_a2 = verificationPopupRef.current) == null ? void 0 : _a2.close();
3288
+ verificationPopupRef.current = null;
3289
+ if (popupCheckIntervalRef.current) {
3290
+ clearInterval(popupCheckIntervalRef.current);
3291
+ popupCheckIntervalRef.current = null;
3292
+ }
3293
+ if (statusPollIntervalRef.current) {
3294
+ clearTimeout(statusPollIntervalRef.current);
3295
+ statusPollIntervalRef.current = null;
3296
+ }
3297
+ if (autoTransitionTimerRef.current) {
3298
+ clearTimeout(autoTransitionTimerRef.current);
3299
+ autoTransitionTimerRef.current = null;
3300
+ }
3301
+ if (digilockerRedirectTimeoutRef.current) {
3302
+ clearTimeout(digilockerRedirectTimeoutRef.current);
3303
+ digilockerRedirectTimeoutRef.current = null;
3304
+ }
3305
+ (_b2 = pollingCleanupRef.current) == null ? void 0 : _b2.call(pollingCleanupRef);
3306
+ pollingCleanupRef.current = null;
3307
+ setShowVerificationScreen(false);
3308
+ setShowGuardianForm(true);
3309
+ setVerificationError(null);
3310
+ setVerificationErrorCode(null);
3311
+ setCanRetryVerification(false);
3312
+ setIsInitiatingVerification(false);
3313
+ setIsPollingStatus(false);
3314
+ isPollingStatusRef.current = false;
3315
+ setIsVerificationComplete(false);
3316
+ if (clearName) {
3317
+ setGuardianFormData((prev) => ({ ...prev, guardianName: "" }));
3318
+ }
3319
+ clearConsentState();
3320
+ }, []);
2223
3321
  const availableLanguages = (0, import_react2.useMemo)(() => {
2224
3322
  if (!content) return [language];
2225
3323
  const languages = ["English"];
@@ -2629,12 +3727,67 @@ var RedactoNoticeConsent = ({
2629
3727
  }, [content, stopAudio]);
2630
3728
  (0, import_react2.useEffect)(() => {
2631
3729
  return () => {
3730
+ var _a2, _b2;
2632
3731
  if (abortControllerRef.current) {
2633
3732
  abortControllerRef.current.abort();
2634
3733
  }
2635
3734
  stopAudio();
3735
+ if (popupCheckIntervalRef.current) {
3736
+ clearInterval(popupCheckIntervalRef.current);
3737
+ }
3738
+ if (statusPollIntervalRef.current) {
3739
+ clearTimeout(statusPollIntervalRef.current);
3740
+ }
3741
+ (_a2 = pollingCleanupRef.current) == null ? void 0 : _a2.call(pollingCleanupRef);
3742
+ pollingCleanupRef.current = null;
3743
+ (_b2 = verificationPopupRef.current) == null ? void 0 : _b2.close();
3744
+ if (autoTransitionTimerRef.current) {
3745
+ clearTimeout(autoTransitionTimerRef.current);
3746
+ autoTransitionTimerRef.current = null;
3747
+ }
3748
+ if (digilockerRedirectTimeoutRef.current) {
3749
+ clearTimeout(digilockerRedirectTimeoutRef.current);
3750
+ digilockerRedirectTimeoutRef.current = null;
3751
+ }
2636
3752
  };
2637
3753
  }, [stopAudio]);
3754
+ (0, import_react2.useEffect)(() => {
3755
+ const persistedState = getConsentState();
3756
+ if (!persistedState) return;
3757
+ if (persistedState.noticeId && persistedState.noticeId !== noticeId) {
3758
+ clearConsentState();
3759
+ return;
3760
+ }
3761
+ const REDIRECT_STATE_MAX_AGE_MS = 15 * 60 * 1e3;
3762
+ if (persistedState.timestamp) {
3763
+ const stateAge = Date.now() - new Date(persistedState.timestamp).getTime();
3764
+ if (stateAge > REDIRECT_STATE_MAX_AGE_MS) {
3765
+ clearConsentState();
3766
+ return;
3767
+ }
3768
+ }
3769
+ if (persistedState.flowState === "digilocker-pending" && persistedState.sessionToken) {
3770
+ setShowVerificationScreen(true);
3771
+ setShowGuardianForm(false);
3772
+ setShowAgeVerification(false);
3773
+ startStatusPolling(persistedState.sessionToken);
3774
+ } else if (persistedState.verificationResult === "verified" && persistedState.verificationReference) {
3775
+ setVerificationReference(persistedState.verificationReference);
3776
+ setShowVerificationScreen(true);
3777
+ setIsVerificationComplete(true);
3778
+ setShowGuardianForm(false);
3779
+ setShowAgeVerification(false);
3780
+ clearConsentState();
3781
+ } else if (persistedState.verificationResult === "failed" || persistedState.verificationResult === "expired") {
3782
+ setShowVerificationScreen(true);
3783
+ setShowGuardianForm(false);
3784
+ setShowAgeVerification(false);
3785
+ setVerificationError(
3786
+ persistedState.verificationResult === "expired" ? "Verification session has expired. Please try again." : "Verification failed. Please try again."
3787
+ );
3788
+ clearConsentState();
3789
+ }
3790
+ }, [startStatusPolling, noticeId]);
2638
3791
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: hasAlreadyConsented ? null : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
2639
3792
  blockUI && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2640
3793
  "div",
@@ -2820,6 +3973,27 @@ var RedactoNoticeConsent = ({
2820
3973
  declineButtonStyle,
2821
3974
  logoUrl: (content == null ? void 0 : content.logo_url) || redacto_logo_default
2822
3975
  }
3976
+ ) }) : showVerificationScreen ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { ...styles.content, ...responsiveStyles.content }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
3977
+ VerificationScreen,
3978
+ {
3979
+ onBack: handleBackToGuardianForm,
3980
+ onContinue: handleVerificationContinue,
3981
+ isInitiating: isInitiatingVerification,
3982
+ isPolling: isPollingStatus,
3983
+ isVerificationComplete,
3984
+ isAutoTransitioning,
3985
+ error: verificationError,
3986
+ errorCode: verificationErrorCode,
3987
+ canRetry: canRetryVerification,
3988
+ styles,
3989
+ responsiveStyles,
3990
+ settings,
3991
+ componentHeadingStyle,
3992
+ componentTextStyle,
3993
+ acceptButtonStyle,
3994
+ declineButtonStyle,
3995
+ logoUrl: (content == null ? void 0 : content.logo_url) || redacto_logo_default
3996
+ }
2823
3997
  ) }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { ...styles.content, ...responsiveStyles.content }, children: [
2824
3998
  errorMessage && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
2825
3999
  "div",
@@ -4423,8 +5597,482 @@ var RedactoConsentInlineComponent = ({
4423
5597
  };
4424
5598
  RedactoConsentInlineComponent.displayName = "RedactoConsentInline";
4425
5599
  var RedactoConsentInline = (0, import_react4.memo)(RedactoConsentInlineComponent);
5600
+
5601
+ // src/RedactoNoticeConsent/components/DigiLockerCallback.tsx
5602
+ var import_react5 = require("react");
5603
+ var import_jsx_runtime3 = require("react/jsx-runtime");
5604
+ var DigiLockerCallback = ({
5605
+ accessToken: propAccessToken,
5606
+ baseUrl,
5607
+ onSuccess,
5608
+ onError
5609
+ }) => {
5610
+ const [status, setStatus] = (0, import_react5.useState)("processing");
5611
+ const [message, setMessage] = (0, import_react5.useState)("Verifying your guardian...");
5612
+ const [errorDetail, setErrorDetail] = (0, import_react5.useState)(null);
5613
+ const retryTimeoutRef = (0, import_react5.useRef)(null);
5614
+ const redirectTimeoutRef = (0, import_react5.useRef)(null);
5615
+ const isMountedRef = (0, import_react5.useRef)(true);
5616
+ const getErrorMessage = (errorCode) => {
5617
+ switch (errorCode) {
5618
+ case "GUARDIAN_UNDER_18":
5619
+ return "Guardian verification failed: The guardian must be 18 years or older.";
5620
+ case "SESSION_EXPIRED":
5621
+ return "Verification session has expired. Please restart the verification process.";
5622
+ case "TOKEN_FAILED":
5623
+ return "DigiLocker authentication failed. Please try again.";
5624
+ case "DIGILOCKER_AUTH_FAILED":
5625
+ return "DigiLocker authorization was cancelled or failed. Please try again.";
5626
+ case "NO_AUTH_CODE":
5627
+ return "Missing authorization code from DigiLocker. Please try again.";
5628
+ default:
5629
+ return "Verification failed. Please try again.";
5630
+ }
5631
+ };
5632
+ const redirectToOriginalPage = (0, import_react5.useCallback)(
5633
+ (originalUrl, verificationResult, verificationReference) => {
5634
+ updateConsentState({
5635
+ verificationResult,
5636
+ verificationReference,
5637
+ flowState: verificationResult === "verified" ? "consent-form" : "error"
5638
+ });
5639
+ redirectTimeoutRef.current = setTimeout(() => {
5640
+ window.location.href = originalUrl;
5641
+ }, 1500);
5642
+ },
5643
+ []
5644
+ );
5645
+ const handleCallback = (0, import_react5.useCallback)(async () => {
5646
+ var _a, _b;
5647
+ try {
5648
+ const params = new URLSearchParams(window.location.search);
5649
+ const sessionToken = params.get("session_token");
5650
+ const urlStatus = params.get("status");
5651
+ const verificationReference = params.get("verification_reference");
5652
+ const errorCode = params.get("error_code");
5653
+ const persistedState = getConsentState();
5654
+ const originalUrl = (persistedState == null ? void 0 : persistedState.originalUrl) || "/";
5655
+ const storedBaseUrl = persistedState == null ? void 0 : persistedState.baseUrl;
5656
+ const storedSessionToken = persistedState == null ? void 0 : persistedState.sessionToken;
5657
+ const accessToken = propAccessToken;
5658
+ if (!accessToken) {
5659
+ throw new Error("Access token not provided. Please pass accessToken as a prop.");
5660
+ }
5661
+ const activeSessionToken = sessionToken || storedSessionToken;
5662
+ if (!activeSessionToken) {
5663
+ throw new Error("Session token not found. Please restart the verification process.");
5664
+ }
5665
+ let isInIframe = false;
5666
+ try {
5667
+ isInIframe = window.self !== window.top;
5668
+ } catch {
5669
+ isInIframe = true;
5670
+ }
5671
+ if (urlStatus === "verified" && verificationReference) {
5672
+ setStatus("success");
5673
+ setMessage("Guardian verified successfully! Redirecting...");
5674
+ onSuccess == null ? void 0 : onSuccess(verificationReference);
5675
+ if (isInIframe && window.parent) {
5676
+ window.parent.postMessage(
5677
+ {
5678
+ type: "DIGILOCKER_VERIFICATION_STATUS",
5679
+ status: "verified",
5680
+ verificationReference
5681
+ },
5682
+ window.location.origin
5683
+ );
5684
+ return;
5685
+ }
5686
+ redirectToOriginalPage(originalUrl, "verified", verificationReference);
5687
+ return;
5688
+ }
5689
+ if (urlStatus === "failed" || urlStatus === "expired") {
5690
+ const urlErrorCode = errorCode != null ? errorCode : void 0;
5691
+ const errorMessage = getErrorMessage(urlErrorCode);
5692
+ setStatus("error");
5693
+ setMessage("Verification failed");
5694
+ setErrorDetail(errorMessage);
5695
+ onError == null ? void 0 : onError(new Error(errorMessage), urlErrorCode);
5696
+ if (isInIframe && window.parent) {
5697
+ window.parent.postMessage(
5698
+ {
5699
+ type: "DIGILOCKER_VERIFICATION_STATUS",
5700
+ status: urlStatus,
5701
+ errorCode: urlErrorCode,
5702
+ error: errorMessage
5703
+ },
5704
+ window.location.origin
5705
+ );
5706
+ return;
5707
+ }
5708
+ redirectToOriginalPage(originalUrl, urlStatus);
5709
+ return;
5710
+ }
5711
+ setMessage("Processing verification...");
5712
+ const apiBaseUrl = baseUrl || storedBaseUrl;
5713
+ const response = await verifyGuardianStatus({
5714
+ accessToken,
5715
+ baseUrl: apiBaseUrl,
5716
+ sessionToken: activeSessionToken
5717
+ });
5718
+ if (!isMountedRef.current) return;
5719
+ if (response.status === "verified") {
5720
+ const verificationRef = response.verification_reference || ((_a = response.guardian_details) == null ? void 0 : _a.verification_reference) || void 0;
5721
+ if (!verificationRef) {
5722
+ setStatus("error");
5723
+ setMessage("Verification failed");
5724
+ setErrorDetail("Verification completed but no reference received. Please try again.");
5725
+ onError == null ? void 0 : onError(new Error("Verification completed but no reference received."));
5726
+ redirectToOriginalPage(originalUrl, "failed");
5727
+ return;
5728
+ }
5729
+ setStatus("success");
5730
+ setMessage("Guardian verified successfully! Redirecting...");
5731
+ onSuccess == null ? void 0 : onSuccess(verificationRef);
5732
+ if (isInIframe && window.parent) {
5733
+ window.parent.postMessage(
5734
+ {
5735
+ type: "DIGILOCKER_VERIFICATION_STATUS",
5736
+ status: "verified",
5737
+ verificationReference: verificationRef
5738
+ },
5739
+ window.location.origin
5740
+ );
5741
+ return;
5742
+ }
5743
+ redirectToOriginalPage(originalUrl, "verified", verificationRef);
5744
+ } else if (response.status === "failed" || response.status === "expired") {
5745
+ const responseErrorCode = (_b = response.error_code) != null ? _b : void 0;
5746
+ const errorMessage = response.error || getErrorMessage(responseErrorCode);
5747
+ setStatus("error");
5748
+ setMessage("Verification failed");
5749
+ setErrorDetail(errorMessage);
5750
+ onError == null ? void 0 : onError(new Error(errorMessage), responseErrorCode);
5751
+ if (isInIframe && window.parent) {
5752
+ window.parent.postMessage(
5753
+ {
5754
+ type: "DIGILOCKER_VERIFICATION_STATUS",
5755
+ status: response.status,
5756
+ errorCode: responseErrorCode,
5757
+ error: errorMessage
5758
+ },
5759
+ window.location.origin
5760
+ );
5761
+ return;
5762
+ }
5763
+ redirectToOriginalPage(originalUrl, response.status);
5764
+ } else {
5765
+ setMessage("Verification is still in progress. Please wait...");
5766
+ const MAX_RETRIES = 3;
5767
+ let retryCount = 0;
5768
+ const attemptRetry = () => {
5769
+ retryCount++;
5770
+ const delay = 3e3 * Math.pow(2, retryCount - 1);
5771
+ retryTimeoutRef.current = setTimeout(async () => {
5772
+ var _a2, _b2;
5773
+ if (!isMountedRef.current) return;
5774
+ try {
5775
+ const retryResponse = await verifyGuardianStatus({
5776
+ accessToken,
5777
+ baseUrl: apiBaseUrl,
5778
+ sessionToken: activeSessionToken
5779
+ });
5780
+ if (!isMountedRef.current) return;
5781
+ const retryRef = retryResponse.verification_reference || ((_a2 = retryResponse.guardian_details) == null ? void 0 : _a2.verification_reference) || void 0;
5782
+ if (retryResponse.status === "verified" && retryRef) {
5783
+ setStatus("success");
5784
+ setMessage("Guardian verified successfully! Redirecting...");
5785
+ onSuccess == null ? void 0 : onSuccess(retryRef);
5786
+ if (isInIframe && window.parent) {
5787
+ window.parent.postMessage(
5788
+ {
5789
+ type: "DIGILOCKER_VERIFICATION_STATUS",
5790
+ status: "verified",
5791
+ verificationReference: retryRef
5792
+ },
5793
+ window.location.origin
5794
+ );
5795
+ return;
5796
+ }
5797
+ redirectToOriginalPage(originalUrl, "verified", retryRef);
5798
+ } else if (retryResponse.status === "failed" || retryResponse.status === "expired") {
5799
+ const retryErrorCode = (_b2 = retryResponse.error_code) != null ? _b2 : void 0;
5800
+ const retryErrorMessage = retryResponse.error || getErrorMessage(retryErrorCode) || "Verification could not be completed. Please try again.";
5801
+ setStatus("error");
5802
+ setMessage("Verification failed");
5803
+ setErrorDetail(retryErrorMessage);
5804
+ onError == null ? void 0 : onError(new Error(retryErrorMessage), retryErrorCode);
5805
+ if (isInIframe && window.parent) {
5806
+ window.parent.postMessage(
5807
+ {
5808
+ type: "DIGILOCKER_VERIFICATION_STATUS",
5809
+ status: retryResponse.status,
5810
+ errorCode: retryErrorCode,
5811
+ error: retryErrorMessage
5812
+ },
5813
+ window.location.origin
5814
+ );
5815
+ return;
5816
+ }
5817
+ redirectToOriginalPage(originalUrl, retryResponse.status);
5818
+ } else if (retryCount < MAX_RETRIES) {
5819
+ setMessage("Verification taking longer than expected. Please wait...");
5820
+ attemptRetry();
5821
+ } else {
5822
+ const timeoutMessage = "Verification could not be completed in time. Please try again.";
5823
+ setStatus("error");
5824
+ setMessage("Verification failed");
5825
+ setErrorDetail(timeoutMessage);
5826
+ onError == null ? void 0 : onError(new Error(timeoutMessage));
5827
+ redirectToOriginalPage(originalUrl, "failed");
5828
+ }
5829
+ } catch (retryErr) {
5830
+ if (!isMountedRef.current) return;
5831
+ if (retryCount < MAX_RETRIES) {
5832
+ attemptRetry();
5833
+ } else {
5834
+ setStatus("error");
5835
+ setMessage("Verification failed");
5836
+ setErrorDetail(retryErr.message);
5837
+ onError == null ? void 0 : onError(retryErr);
5838
+ redirectToOriginalPage(originalUrl, "failed");
5839
+ }
5840
+ }
5841
+ }, delay);
5842
+ };
5843
+ attemptRetry();
5844
+ }
5845
+ } catch (error) {
5846
+ console.error("DigiLocker callback error:", error);
5847
+ setStatus("error");
5848
+ const err = error;
5849
+ setMessage("Verification failed");
5850
+ setErrorDetail(err.message || "An error occurred during verification");
5851
+ onError == null ? void 0 : onError(err);
5852
+ const persistedState = getConsentState();
5853
+ if (persistedState == null ? void 0 : persistedState.originalUrl) {
5854
+ redirectTimeoutRef.current = setTimeout(() => {
5855
+ redirectToOriginalPage(persistedState.originalUrl, "failed");
5856
+ }, 3e3);
5857
+ }
5858
+ }
5859
+ }, [propAccessToken, baseUrl, onSuccess, onError, redirectToOriginalPage]);
5860
+ (0, import_react5.useEffect)(() => {
5861
+ injectCheckboxStyles();
5862
+ handleCallback();
5863
+ return () => {
5864
+ isMountedRef.current = false;
5865
+ if (retryTimeoutRef.current) clearTimeout(retryTimeoutRef.current);
5866
+ if (redirectTimeoutRef.current) clearTimeout(redirectTimeoutRef.current);
5867
+ };
5868
+ }, [handleCallback]);
5869
+ const handleRetry = (0, import_react5.useCallback)(() => {
5870
+ const persistedState = getConsentState();
5871
+ if (persistedState == null ? void 0 : persistedState.originalUrl) {
5872
+ clearConsentState();
5873
+ window.location.href = persistedState.originalUrl;
5874
+ } else {
5875
+ window.location.href = "/";
5876
+ }
5877
+ }, []);
5878
+ const containerStyle = {
5879
+ display: "flex",
5880
+ alignItems: "center",
5881
+ justifyContent: "center",
5882
+ minHeight: "100vh",
5883
+ backgroundColor: "#f8fafc",
5884
+ fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif',
5885
+ padding: "24px",
5886
+ boxSizing: "border-box"
5887
+ };
5888
+ const cardStyle = {
5889
+ backgroundColor: "#ffffff",
5890
+ borderRadius: "16px",
5891
+ boxShadow: "0 1px 3px rgba(0, 0, 0, 0.08), 0 8px 30px rgba(0, 0, 0, 0.06)",
5892
+ padding: "48px 40px 40px",
5893
+ textAlign: "center",
5894
+ maxWidth: "420px",
5895
+ width: "100%"
5896
+ };
5897
+ const spinnerContainerStyle = {
5898
+ width: "72px",
5899
+ height: "72px",
5900
+ margin: "0 auto 28px",
5901
+ position: "relative"
5902
+ };
5903
+ const spinnerStyle = {
5904
+ width: "72px",
5905
+ height: "72px",
5906
+ border: "3px solid #e5e7eb",
5907
+ borderTopColor: "#4f87ff",
5908
+ borderRadius: "50%",
5909
+ animation: "redacto-dl-spin 0.8s linear infinite",
5910
+ boxSizing: "border-box"
5911
+ };
5912
+ const iconContainerStyle = {
5913
+ width: "72px",
5914
+ height: "72px",
5915
+ borderRadius: "50%",
5916
+ display: "flex",
5917
+ alignItems: "center",
5918
+ justifyContent: "center",
5919
+ margin: "0 auto 28px",
5920
+ animation: "redacto-dl-pop 0.4s cubic-bezier(0.34, 1.56, 0.64, 1) forwards",
5921
+ position: "relative"
5922
+ };
5923
+ const successIconStyle = {
5924
+ ...iconContainerStyle,
5925
+ backgroundColor: "#d1fae5",
5926
+ color: "#059669"
5927
+ };
5928
+ const errorIconStyle = {
5929
+ ...iconContainerStyle,
5930
+ backgroundColor: "#fee2e2",
5931
+ color: "#dc2626"
5932
+ };
5933
+ const titleStyle = {
5934
+ fontSize: "22px",
5935
+ fontWeight: 700,
5936
+ color: "#111827",
5937
+ margin: "0 0 8px 0",
5938
+ letterSpacing: "-0.01em"
5939
+ };
5940
+ const messageStyle = {
5941
+ fontSize: "14px",
5942
+ color: "#6b7280",
5943
+ marginBottom: "0",
5944
+ lineHeight: 1.6
5945
+ };
5946
+ const subtextStyle = {
5947
+ fontSize: "13px",
5948
+ color: "#9ca3af",
5949
+ marginTop: "16px",
5950
+ lineHeight: 1.5
5951
+ };
5952
+ const errorDetailStyle = {
5953
+ fontSize: "13px",
5954
+ color: "#dc2626",
5955
+ marginTop: "16px",
5956
+ padding: "12px 16px",
5957
+ backgroundColor: "#fef2f2",
5958
+ borderRadius: "10px",
5959
+ border: "1px solid #fecaca",
5960
+ lineHeight: 1.5,
5961
+ textAlign: "left"
5962
+ };
5963
+ const buttonStyle = {
5964
+ marginTop: "24px",
5965
+ padding: "12px 28px",
5966
+ backgroundColor: "#4f87ff",
5967
+ color: "#ffffff",
5968
+ border: "none",
5969
+ borderRadius: "10px",
5970
+ fontSize: "15px",
5971
+ fontWeight: 600,
5972
+ cursor: "pointer",
5973
+ transition: "background-color 0.2s, transform 0.15s",
5974
+ width: "100%"
5975
+ };
5976
+ const keyframesStyle = `
5977
+ @keyframes redacto-dl-spin {
5978
+ to { transform: rotate(360deg); }
5979
+ }
5980
+ @keyframes redacto-dl-pop {
5981
+ 0% { transform: scale(0.3); opacity: 0; }
5982
+ 60% { transform: scale(1.08); opacity: 1; }
5983
+ 100% { transform: scale(1); opacity: 1; }
5984
+ }
5985
+ @keyframes redacto-dl-check {
5986
+ 0% { stroke-dashoffset: 24; }
5987
+ 100% { stroke-dashoffset: 0; }
5988
+ }
5989
+ @keyframes redacto-dl-pulse {
5990
+ 0%, 100% { transform: scale(1); opacity: 0.6; }
5991
+ 50% { transform: scale(1.15); opacity: 0; }
5992
+ }
5993
+ .redacto-dl-retry-btn:hover {
5994
+ background-color: #3d6fdb !important;
5995
+ transform: translateY(-1px);
5996
+ }
5997
+ .redacto-dl-retry-btn:active {
5998
+ transform: translateY(0);
5999
+ }
6000
+ `;
6001
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
6002
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("style", { dangerouslySetInnerHTML: { __html: keyframesStyle } }),
6003
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: containerStyle, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: cardStyle, children: [
6004
+ status === "processing" && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
6005
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: spinnerContainerStyle, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: spinnerStyle }) }),
6006
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h2", { style: titleStyle, children: "Processing Verification" }),
6007
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { style: messageStyle, children: message }),
6008
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { style: subtextStyle, children: "Please wait while we verify your guardian's identity..." })
6009
+ ] }),
6010
+ status === "success" && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
6011
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { position: "relative", width: "72px", height: "72px", margin: "0 auto 28px" }, children: [
6012
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: {
6013
+ position: "absolute",
6014
+ inset: "-8px",
6015
+ borderRadius: "50%",
6016
+ border: "2px solid #d1fae5",
6017
+ animation: "redacto-dl-pulse 1.5s ease-out infinite"
6018
+ } }),
6019
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: successIconStyle, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
6020
+ "svg",
6021
+ {
6022
+ width: "30",
6023
+ height: "30",
6024
+ viewBox: "0 0 24 24",
6025
+ fill: "none",
6026
+ stroke: "currentColor",
6027
+ strokeWidth: "2.5",
6028
+ strokeLinecap: "round",
6029
+ strokeLinejoin: "round",
6030
+ style: { strokeDasharray: 24, animation: "redacto-dl-check 0.4s ease-out 0.3s forwards", strokeDashoffset: 24 },
6031
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("polyline", { points: "20 6 9 17 4 12" })
6032
+ }
6033
+ ) })
6034
+ ] }),
6035
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h2", { style: titleStyle, children: "Verification Successful" }),
6036
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { style: messageStyle, children: message }),
6037
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { style: subtextStyle, children: "You will be redirected automatically." })
6038
+ ] }),
6039
+ status === "error" && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
6040
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: errorIconStyle, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
6041
+ "svg",
6042
+ {
6043
+ width: "30",
6044
+ height: "30",
6045
+ viewBox: "0 0 24 24",
6046
+ fill: "none",
6047
+ stroke: "currentColor",
6048
+ strokeWidth: "2.5",
6049
+ strokeLinecap: "round",
6050
+ strokeLinejoin: "round",
6051
+ children: [
6052
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
6053
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
6054
+ ]
6055
+ }
6056
+ ) }),
6057
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h2", { style: titleStyle, children: "Verification Failed" }),
6058
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { style: messageStyle, children: message }),
6059
+ errorDetail && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { style: errorDetailStyle, children: errorDetail }),
6060
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
6061
+ "button",
6062
+ {
6063
+ className: "redacto-dl-retry-btn",
6064
+ style: buttonStyle,
6065
+ onClick: handleRetry,
6066
+ children: "Try Again"
6067
+ }
6068
+ )
6069
+ ] })
6070
+ ] }) })
6071
+ ] });
6072
+ };
4426
6073
  // Annotate the CommonJS export names for ESM import in node:
4427
6074
  0 && (module.exports = {
6075
+ DigiLockerCallback,
4428
6076
  RedactoNoticeConsent,
4429
6077
  RedactoNoticeConsentInline
4430
6078
  });