@redacto.io/consent-sdk-react 9.2.0-beta.1 → 9.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +24 -0
- package/dist/privacy-center.d.mts +6 -10
- package/dist/privacy-center.d.ts +6 -10
- package/dist/privacy-center.js +208 -850
- package/dist/privacy-center.mjs +208 -850
- package/package.json +1 -1
- package/src/RedactoPrivacyCenter/components/DataRequest/ProductSelectionSection.tsx +4 -4
- package/src/RedactoPrivacyCenter/components/Form.tsx +214 -866
- package/src/RedactoPrivacyCenter/components/RequestSubmit.tsx +44 -219
- package/src/RedactoPrivacyCenter/components/types.ts +14 -20
- package/src/RedactoPrivacyCenter/lib/api.ts +23 -58
- package/src/RedactoPrivacyCenter/lib/types.ts +0 -31
- package/src/RedactoPrivacyCenter/locales/as/translation.json +2 -2
- package/src/RedactoPrivacyCenter/locales/bho/translation.json +2 -2
- package/src/RedactoPrivacyCenter/locales/bn/translation.json +2 -2
- package/src/RedactoPrivacyCenter/locales/brx/translation.json +2 -2
- package/src/RedactoPrivacyCenter/locales/doi/translation.json +2 -2
- package/src/RedactoPrivacyCenter/locales/en/translation.json +2 -2
- package/src/RedactoPrivacyCenter/locales/gom/translation.json +2 -2
- package/src/RedactoPrivacyCenter/locales/gu/translation.json +2 -2
- package/src/RedactoPrivacyCenter/locales/hi/translation.json +2 -2
- package/src/RedactoPrivacyCenter/locales/kn/translation.json +2 -2
- package/src/RedactoPrivacyCenter/locales/ks/translation.json +2 -2
- package/src/RedactoPrivacyCenter/locales/mai/translation.json +2 -2
- package/src/RedactoPrivacyCenter/locales/ml/translation.json +2 -2
- package/src/RedactoPrivacyCenter/locales/mni-Mtei/translation.json +2 -2
- package/src/RedactoPrivacyCenter/locales/mr/translation.json +2 -2
- package/src/RedactoPrivacyCenter/locales/ne/translation.json +2 -2
- package/src/RedactoPrivacyCenter/locales/or/translation.json +2 -2
- package/src/RedactoPrivacyCenter/locales/pa/translation.json +2 -2
- package/src/RedactoPrivacyCenter/locales/sa/translation.json +2 -2
- package/src/RedactoPrivacyCenter/locales/sat/translation.json +2 -2
- package/src/RedactoPrivacyCenter/locales/sd/translation.json +2 -2
- package/src/RedactoPrivacyCenter/locales/ta/translation.json +2 -2
- package/src/RedactoPrivacyCenter/locales/te/translation.json +2 -2
- package/src/RedactoPrivacyCenter/locales/ur/translation.json +2 -2
- package/tests/Form.test.tsx +123 -149
- package/tests/ProductSelectionSection.test.tsx +39 -4
- package/tests/RequestSubmit.test.tsx +27 -187
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { CSSProperties, ReactNode } from 'react';
|
|
2
1
|
import character from '../assets/character.svg';
|
|
3
2
|
import greenTick from '../assets/greenTick.svg';
|
|
4
3
|
import sentImg from '../assets/sentImg.svg';
|
|
@@ -10,234 +9,25 @@ import { Mail } from 'lucide-react';
|
|
|
10
9
|
|
|
11
10
|
const getVar = (varName: string): string => `var(${varName})`;
|
|
12
11
|
|
|
13
|
-
type SummaryCardProps = Readonly<{
|
|
14
|
-
children: ReactNode;
|
|
15
|
-
backgroundColor?: CSSProperties['backgroundColor'];
|
|
16
|
-
borderColor?: CSSProperties['borderColor'];
|
|
17
|
-
}>;
|
|
18
|
-
|
|
19
12
|
/**
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
* defaults).
|
|
24
|
-
*/
|
|
25
|
-
const SummaryCard = ({
|
|
26
|
-
children,
|
|
27
|
-
backgroundColor,
|
|
28
|
-
borderColor,
|
|
29
|
-
}: SummaryCardProps) => (
|
|
30
|
-
<div
|
|
31
|
-
style={{
|
|
32
|
-
marginTop: pcStyles.mtMd.marginTop,
|
|
33
|
-
padding: pcStyles.pSm.padding,
|
|
34
|
-
...(backgroundColor === undefined
|
|
35
|
-
? pcStyles.bgSecondary
|
|
36
|
-
: { backgroundColor }),
|
|
37
|
-
borderRadius: pcStyles.borderRadiusMd,
|
|
38
|
-
border: `1px solid ${borderColor ?? pcStyles.borderColor}`,
|
|
39
|
-
}}
|
|
40
|
-
>
|
|
41
|
-
{children}
|
|
42
|
-
</div>
|
|
43
|
-
);
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Success / partial-success surface shown after a case (or batch of cases)
|
|
47
|
-
* is submitted. See `RequestSubmitProps` for the shape contract.
|
|
13
|
+
* Success surface shown after a case is submitted. Always renders a
|
|
14
|
+
* single Case-ID card — the form's 1-form -> 1-case contract means
|
|
15
|
+
* there is no fan-out and no partial-failure surface to maintain.
|
|
48
16
|
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
* - More than one succeeded entry → list of `product_name: case_id`
|
|
54
|
-
* rows under a "{n} cases created" header.
|
|
55
|
-
* - Any failed entries → a separate "Some requests failed" block with
|
|
56
|
-
* a per-row Retry button that calls `onRetry(product_uuid)`.
|
|
17
|
+
* The product label above the case ID is rendered only when the
|
|
18
|
+
* result carries one (product-scoped request types: ACCESS / ERASURE
|
|
19
|
+
* / CORRECTION). Nomination and grievance leave the field empty and
|
|
20
|
+
* the label is omitted.
|
|
57
21
|
*/
|
|
58
22
|
export default function RequestSubmit({
|
|
59
23
|
result,
|
|
60
24
|
contact,
|
|
61
25
|
onCreateRequest,
|
|
62
|
-
onRetry,
|
|
63
|
-
retryingGroupKeys,
|
|
64
26
|
revokeConsentOnFulfilment,
|
|
65
27
|
revokedPurposeNames,
|
|
66
28
|
}: RequestSubmitProps) {
|
|
67
29
|
const { t } = useTranslation();
|
|
68
30
|
|
|
69
|
-
const succeeded = result.succeeded;
|
|
70
|
-
const failed = result.failed;
|
|
71
|
-
const successCount = succeeded.length;
|
|
72
|
-
const hasFailures = failed.length > 0;
|
|
73
|
-
const isSingleCase = successCount === 1 && !hasFailures;
|
|
74
|
-
|
|
75
|
-
const renderCaseList = () => {
|
|
76
|
-
if (successCount === 0) {
|
|
77
|
-
return null;
|
|
78
|
-
}
|
|
79
|
-
if (isSingleCase) {
|
|
80
|
-
const only = succeeded[0];
|
|
81
|
-
return (
|
|
82
|
-
<SummaryCard>
|
|
83
|
-
{only.product_name !== '' && (
|
|
84
|
-
<PCText
|
|
85
|
-
size="sm"
|
|
86
|
-
weight="medium"
|
|
87
|
-
style={{
|
|
88
|
-
marginBottom: pcStyles.mbXs.marginBottom,
|
|
89
|
-
wordBreak: 'break-word',
|
|
90
|
-
}}
|
|
91
|
-
>
|
|
92
|
-
{only.product_name}
|
|
93
|
-
</PCText>
|
|
94
|
-
)}
|
|
95
|
-
<PCText
|
|
96
|
-
size="base"
|
|
97
|
-
weight="bold"
|
|
98
|
-
style={{
|
|
99
|
-
color: pcStyles.primary,
|
|
100
|
-
wordBreak: 'break-word',
|
|
101
|
-
marginBottom: pcStyles.mbXs.marginBottom,
|
|
102
|
-
}}
|
|
103
|
-
className="pc-text-responsive"
|
|
104
|
-
>
|
|
105
|
-
{t('caseID')}: {only.case_id}
|
|
106
|
-
</PCText>
|
|
107
|
-
<PCText size="xs" weight="medium" color="secondary">
|
|
108
|
-
{t('saveThisID')}.
|
|
109
|
-
</PCText>
|
|
110
|
-
</SummaryCard>
|
|
111
|
-
);
|
|
112
|
-
}
|
|
113
|
-
return (
|
|
114
|
-
<SummaryCard>
|
|
115
|
-
<PCText
|
|
116
|
-
size="sm"
|
|
117
|
-
weight="semibold"
|
|
118
|
-
style={{
|
|
119
|
-
color: pcStyles.primary,
|
|
120
|
-
marginBottom: pcStyles.mbSm.marginBottom,
|
|
121
|
-
}}
|
|
122
|
-
>
|
|
123
|
-
{t('casesCreatedCount', { count: successCount })}
|
|
124
|
-
</PCText>
|
|
125
|
-
<ul
|
|
126
|
-
style={{
|
|
127
|
-
margin: 0,
|
|
128
|
-
padding: 0,
|
|
129
|
-
listStyle: 'none',
|
|
130
|
-
display: 'flex',
|
|
131
|
-
flexDirection: 'column',
|
|
132
|
-
gap: getVar('--pc-spacing-xs'),
|
|
133
|
-
}}
|
|
134
|
-
>
|
|
135
|
-
{succeeded.map((entry) => (
|
|
136
|
-
<li
|
|
137
|
-
key={`${entry.group_key}:${entry.case_id}`}
|
|
138
|
-
style={{ wordBreak: 'break-word' }}
|
|
139
|
-
>
|
|
140
|
-
<PCText size="sm" weight="medium">
|
|
141
|
-
{entry.product_name}
|
|
142
|
-
</PCText>
|
|
143
|
-
<PCText
|
|
144
|
-
size="sm"
|
|
145
|
-
weight="bold"
|
|
146
|
-
style={{ color: pcStyles.primary, wordBreak: 'break-word' }}
|
|
147
|
-
>
|
|
148
|
-
{t('caseID')}: {entry.case_id}
|
|
149
|
-
</PCText>
|
|
150
|
-
</li>
|
|
151
|
-
))}
|
|
152
|
-
</ul>
|
|
153
|
-
<PCText
|
|
154
|
-
size="xs"
|
|
155
|
-
weight="medium"
|
|
156
|
-
color="secondary"
|
|
157
|
-
style={{ marginTop: pcStyles.mtSm.marginTop }}
|
|
158
|
-
>
|
|
159
|
-
{t('saveThisID')}.
|
|
160
|
-
</PCText>
|
|
161
|
-
</SummaryCard>
|
|
162
|
-
);
|
|
163
|
-
};
|
|
164
|
-
|
|
165
|
-
const renderFailures = () => {
|
|
166
|
-
if (!hasFailures) {
|
|
167
|
-
return null;
|
|
168
|
-
}
|
|
169
|
-
return (
|
|
170
|
-
<SummaryCard
|
|
171
|
-
backgroundColor={pcStyles.warningBg}
|
|
172
|
-
borderColor={pcStyles.warningBorder}
|
|
173
|
-
>
|
|
174
|
-
<PCText
|
|
175
|
-
size="sm"
|
|
176
|
-
weight="semibold"
|
|
177
|
-
style={{
|
|
178
|
-
color: pcStyles.warningText,
|
|
179
|
-
marginBottom: pcStyles.mbSm.marginBottom,
|
|
180
|
-
}}
|
|
181
|
-
>
|
|
182
|
-
{t('someRequestsFailed')}
|
|
183
|
-
</PCText>
|
|
184
|
-
<ul
|
|
185
|
-
style={{
|
|
186
|
-
margin: 0,
|
|
187
|
-
padding: 0,
|
|
188
|
-
listStyle: 'none',
|
|
189
|
-
display: 'flex',
|
|
190
|
-
flexDirection: 'column',
|
|
191
|
-
gap: getVar('--pc-spacing-sm'),
|
|
192
|
-
}}
|
|
193
|
-
>
|
|
194
|
-
{failed.map((entry) => {
|
|
195
|
-
const isRetrying =
|
|
196
|
-
retryingGroupKeys?.has(entry.group_key) === true;
|
|
197
|
-
return (
|
|
198
|
-
<li
|
|
199
|
-
key={entry.group_key}
|
|
200
|
-
style={{
|
|
201
|
-
display: 'flex',
|
|
202
|
-
alignItems: 'flex-start',
|
|
203
|
-
justifyContent: 'space-between',
|
|
204
|
-
gap: getVar('--pc-spacing-sm'),
|
|
205
|
-
flexWrap: 'wrap',
|
|
206
|
-
}}
|
|
207
|
-
>
|
|
208
|
-
<div
|
|
209
|
-
style={{
|
|
210
|
-
minWidth: 0,
|
|
211
|
-
flex: 1,
|
|
212
|
-
wordBreak: 'break-word',
|
|
213
|
-
}}
|
|
214
|
-
>
|
|
215
|
-
<PCText size="sm" weight="medium">
|
|
216
|
-
{entry.product_name}
|
|
217
|
-
</PCText>
|
|
218
|
-
<PCText size="xs" weight="medium" color="secondary">
|
|
219
|
-
{entry.error}
|
|
220
|
-
</PCText>
|
|
221
|
-
</div>
|
|
222
|
-
{onRetry !== undefined && (
|
|
223
|
-
<PCButton
|
|
224
|
-
variant="outline"
|
|
225
|
-
size="sm"
|
|
226
|
-
onClick={() => onRetry(entry.group_key)}
|
|
227
|
-
disabled={isRetrying}
|
|
228
|
-
isLoading={isRetrying}
|
|
229
|
-
>
|
|
230
|
-
{isRetrying ? t('retrying') : t('retry')}
|
|
231
|
-
</PCButton>
|
|
232
|
-
)}
|
|
233
|
-
</li>
|
|
234
|
-
);
|
|
235
|
-
})}
|
|
236
|
-
</ul>
|
|
237
|
-
</SummaryCard>
|
|
238
|
-
);
|
|
239
|
-
};
|
|
240
|
-
|
|
241
31
|
return (
|
|
242
32
|
<div style={{ marginTop: pcStyles.mtMd.marginTop, position: 'relative' }}>
|
|
243
33
|
<img
|
|
@@ -325,8 +115,43 @@ export default function RequestSubmit({
|
|
|
325
115
|
>
|
|
326
116
|
{t('thankYouForSubmittingYourRequest')}.
|
|
327
117
|
</PCText>
|
|
328
|
-
|
|
329
|
-
|
|
118
|
+
<div
|
|
119
|
+
style={{
|
|
120
|
+
marginTop: pcStyles.mtMd.marginTop,
|
|
121
|
+
padding: pcStyles.pSm.padding,
|
|
122
|
+
...pcStyles.bgSecondary,
|
|
123
|
+
borderRadius: pcStyles.borderRadiusMd,
|
|
124
|
+
border: `1px solid ${pcStyles.borderColor}`,
|
|
125
|
+
}}
|
|
126
|
+
>
|
|
127
|
+
{result.product_name !== '' && (
|
|
128
|
+
<PCText
|
|
129
|
+
size="sm"
|
|
130
|
+
weight="medium"
|
|
131
|
+
style={{
|
|
132
|
+
marginBottom: pcStyles.mbXs.marginBottom,
|
|
133
|
+
wordBreak: 'break-word',
|
|
134
|
+
}}
|
|
135
|
+
>
|
|
136
|
+
{result.product_name}
|
|
137
|
+
</PCText>
|
|
138
|
+
)}
|
|
139
|
+
<PCText
|
|
140
|
+
size="base"
|
|
141
|
+
weight="bold"
|
|
142
|
+
style={{
|
|
143
|
+
color: pcStyles.primary,
|
|
144
|
+
wordBreak: 'break-word',
|
|
145
|
+
marginBottom: pcStyles.mbXs.marginBottom,
|
|
146
|
+
}}
|
|
147
|
+
className="pc-text-responsive"
|
|
148
|
+
>
|
|
149
|
+
{t('caseID')}: {result.case_id}
|
|
150
|
+
</PCText>
|
|
151
|
+
<PCText size="xs" weight="medium" color="secondary">
|
|
152
|
+
{t('saveThisID')}.
|
|
153
|
+
</PCText>
|
|
154
|
+
</div>
|
|
330
155
|
<div
|
|
331
156
|
style={{
|
|
332
157
|
...pcStyles.flex,
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { ReactNode } from 'react';
|
|
2
2
|
import type {
|
|
3
|
-
BatchCaseSubmitResult,
|
|
4
3
|
CaseRequest,
|
|
5
4
|
ConsentModalRecord,
|
|
6
5
|
} from '../lib/types';
|
|
@@ -31,29 +30,24 @@ export type CaseDetailsModalProps = {
|
|
|
31
30
|
};
|
|
32
31
|
|
|
33
32
|
/**
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
* 2. The legacy single-case path (nomination / grievance / non-grouped
|
|
41
|
-
* fallback), which wraps its lone response into a synthetic
|
|
42
|
-
* `BatchCaseSubmitResult` with one `succeeded` entry and an empty
|
|
43
|
-
* `failed` list. The same UI logic renders both shapes.
|
|
44
|
-
*
|
|
45
|
-
* Retry is keyed by `group_key` (productGroupKey on the source group),
|
|
46
|
-
* NOT `product_uuid`, so that a product picked both directly AND via a
|
|
47
|
-
* nominator can be retried independently. `retryingGroupKeys` lets the
|
|
48
|
-
* parent indicate which rows are currently mid-retry (button shows the
|
|
49
|
-
* retrying spinner copy and is disabled).
|
|
33
|
+
* Single-case success surface. The Form's 1-form -> 1-case contract
|
|
34
|
+
* means there is no fan-out and no partial-failure UI — every submit
|
|
35
|
+
* produces exactly one `case_id`. `product_name` / `product_uuid` are
|
|
36
|
+
* populated for product-scoped request types (ACCESS / ERASURE /
|
|
37
|
+
* CORRECTION) and empty strings for org-level types (NOMINATION /
|
|
38
|
+
* GRIEVANCE), in which case the success card omits the product label.
|
|
50
39
|
*/
|
|
40
|
+
export type RequestSubmitResult = Readonly<{
|
|
41
|
+
case_id: string;
|
|
42
|
+
uuid: string;
|
|
43
|
+
product_name: string;
|
|
44
|
+
product_uuid: string;
|
|
45
|
+
}>;
|
|
46
|
+
|
|
51
47
|
export type RequestSubmitProps = Readonly<{
|
|
52
|
-
result:
|
|
48
|
+
result: RequestSubmitResult;
|
|
53
49
|
contact: string;
|
|
54
50
|
onCreateRequest: () => void;
|
|
55
|
-
onRetry?: (groupKey: string) => void;
|
|
56
|
-
retryingGroupKeys?: ReadonlySet<string>;
|
|
57
51
|
revokeConsentOnFulfilment?: boolean;
|
|
58
52
|
revokedPurposeNames?: string;
|
|
59
53
|
}>;
|
|
@@ -174,17 +174,13 @@ export const getFormData = async (
|
|
|
174
174
|
};
|
|
175
175
|
|
|
176
176
|
/**
|
|
177
|
-
*
|
|
178
|
-
*
|
|
179
|
-
* `
|
|
180
|
-
*
|
|
181
|
-
*
|
|
182
|
-
*
|
|
183
|
-
* NOT exported at the package boundary (`privacy-center.ts`) — public
|
|
184
|
-
* consumers should use `createCaseRequest` below, which preserves the
|
|
185
|
-
* documented `Promise<CreateCaseResponse | null>` contract.
|
|
177
|
+
* Public helper for creating a case request. Returns `null` on any
|
|
178
|
+
* non-auth error (preserves the documented
|
|
179
|
+
* `Promise<CreateCaseResponse | null>` contract the SDK exposes to
|
|
180
|
+
* consumers) — does NOT throw. Auth errors trigger a single token
|
|
181
|
+
* refresh + retry before falling through.
|
|
186
182
|
*/
|
|
187
|
-
export const
|
|
183
|
+
export const createCaseRequest = async (
|
|
188
184
|
organizationId: string,
|
|
189
185
|
workspaceId: string,
|
|
190
186
|
data: UserDataRequest,
|
|
@@ -219,55 +215,24 @@ export const createCaseRequestUnsafe = async (
|
|
|
219
215
|
if (shouldRetry) {
|
|
220
216
|
// Read from sessionStorage first (synchronously updated) then fall back to context
|
|
221
217
|
const newAuthToken = sessionStorage.getItem('access_token') || authContext?.accessToken || '';
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
218
|
+
try {
|
|
219
|
+
return await createCaseRequestServer(
|
|
220
|
+
organizationId,
|
|
221
|
+
workspaceId,
|
|
222
|
+
data,
|
|
223
|
+
newAuthToken,
|
|
224
|
+
false,
|
|
225
|
+
consentClient
|
|
226
|
+
);
|
|
227
|
+
} catch (retryError) {
|
|
228
|
+
// The post-refresh retry can still fail (network blip, 5xx,
|
|
229
|
+
// expired-again token). Honor the documented `Promise<… | null>`
|
|
230
|
+
// contract by swallowing here rather than letting the rethrow
|
|
231
|
+
// escape — callers (e.g. Form.tsx) rely on null-on-error.
|
|
232
|
+
console.error('Error creating case request after auth refresh:', retryError);
|
|
233
|
+
return null;
|
|
234
|
+
}
|
|
230
235
|
}
|
|
231
|
-
// P2-SDK-3/4 of TECH-3712. Rethrow non-auth errors so the batch path's
|
|
232
|
-
// `Promise.allSettled` can surface the backend's `[status] message` to
|
|
233
|
-
// the data principal (e.g. `[400] invalid_data_principal`) via the
|
|
234
|
-
// `failed[].error` field.
|
|
235
|
-
console.error('Error creating case request:', error);
|
|
236
|
-
throw error;
|
|
237
|
-
}
|
|
238
|
-
};
|
|
239
|
-
|
|
240
|
-
/**
|
|
241
|
-
* Public helper for creating a case request. Returns `null` on error
|
|
242
|
-
* (preserves the original `Promise<CreateCaseResponse | null>` contract
|
|
243
|
-
* the SDK exposes to consumers) — does NOT throw. Internally wraps
|
|
244
|
-
* `createCaseRequestUnsafe` and swallows non-auth errors.
|
|
245
|
-
*
|
|
246
|
-
* The batch-submission path in Form.tsx uses `createCaseRequestUnsafe`
|
|
247
|
-
* directly so partial-failure UI can surface per-row backend messages;
|
|
248
|
-
* everywhere else (including the legacy single-case path) should use
|
|
249
|
-
* this helper.
|
|
250
|
-
*/
|
|
251
|
-
export const createCaseRequest = async (
|
|
252
|
-
organizationId: string,
|
|
253
|
-
workspaceId: string,
|
|
254
|
-
data: UserDataRequest,
|
|
255
|
-
isPopup?: boolean,
|
|
256
|
-
useSessionAuth?: boolean,
|
|
257
|
-
authContext?: AuthContext,
|
|
258
|
-
consentClient?: BaseUrlContextValue['consentClient']
|
|
259
|
-
): Promise<CreateCaseResponse | null> => {
|
|
260
|
-
try {
|
|
261
|
-
return await createCaseRequestUnsafe(
|
|
262
|
-
organizationId,
|
|
263
|
-
workspaceId,
|
|
264
|
-
data,
|
|
265
|
-
isPopup,
|
|
266
|
-
useSessionAuth,
|
|
267
|
-
authContext,
|
|
268
|
-
consentClient,
|
|
269
|
-
);
|
|
270
|
-
} catch (error) {
|
|
271
236
|
console.error('Error creating case request:', error);
|
|
272
237
|
return null;
|
|
273
238
|
}
|
|
@@ -204,37 +204,6 @@ export type CreateCaseResponse = {
|
|
|
204
204
|
};
|
|
205
205
|
};
|
|
206
206
|
|
|
207
|
-
/**
|
|
208
|
-
* Aggregated result of submitting one case per product in a multi-product
|
|
209
|
-
* form submission.
|
|
210
|
-
*
|
|
211
|
-
* Phase 2 of TECH-3712. The backend has no batch endpoint; the SDK Form
|
|
212
|
-
* fans `createCaseRequest` calls out via `Promise.allSettled` and the
|
|
213
|
-
* consumer (P2-SDK-3) aggregates the outcomes into this shape so the UI
|
|
214
|
-
* can render partial-success states clearly.
|
|
215
|
-
*
|
|
216
|
-
* `group_key` is the stable selection key for the source consent group
|
|
217
|
-
* (encodes `product_uuid` and, for nominated groups, the nominator uuid).
|
|
218
|
-
* Use it — not `product_uuid` — to address an entry for retry/update,
|
|
219
|
-
* since the same product can appear in both `succeeded` and `failed`
|
|
220
|
-
* when picked directly AND via a nominator.
|
|
221
|
-
*/
|
|
222
|
-
export type BatchCaseSubmitResult = {
|
|
223
|
-
succeeded: Array<{
|
|
224
|
-
group_key: string;
|
|
225
|
-
product_uuid: string;
|
|
226
|
-
product_name: string;
|
|
227
|
-
case_id: string;
|
|
228
|
-
uuid: string;
|
|
229
|
-
}>;
|
|
230
|
-
failed: Array<{
|
|
231
|
-
group_key: string;
|
|
232
|
-
product_uuid: string;
|
|
233
|
-
product_name: string;
|
|
234
|
-
error: string;
|
|
235
|
-
}>;
|
|
236
|
-
};
|
|
237
|
-
|
|
238
207
|
export type OtpResponse = {
|
|
239
208
|
uuid: string;
|
|
240
209
|
to: string;
|
|
@@ -314,8 +314,8 @@
|
|
|
314
314
|
"selectProductsForRequestGeneric": "Select one or more products to continue",
|
|
315
315
|
"yourData": "Your data",
|
|
316
316
|
"actingOnBehalfOf": "Acting on behalf of {{nominator}}",
|
|
317
|
-
"activePurposes_one": "{{count}}
|
|
318
|
-
"activePurposes_other": "{{count}}
|
|
317
|
+
"activePurposes_one": "{{count}} উদ্দেশ্য",
|
|
318
|
+
"activePurposes_other": "{{count}} উদ্দেশ্য",
|
|
319
319
|
"autoSelected": "Auto-selected",
|
|
320
320
|
"noProductsAvailable": "No products available",
|
|
321
321
|
"noProductsAvailableDescription": "You have no consents to manage yet.",
|
|
@@ -314,8 +314,8 @@
|
|
|
314
314
|
"selectProductsForRequestGeneric": "Select one or more products to continue",
|
|
315
315
|
"yourData": "Your data",
|
|
316
316
|
"actingOnBehalfOf": "Acting on behalf of {{nominator}}",
|
|
317
|
-
"activePurposes_one": "{{count}}
|
|
318
|
-
"activePurposes_other": "{{count}}
|
|
317
|
+
"activePurposes_one": "{{count}} उद्देश्य",
|
|
318
|
+
"activePurposes_other": "{{count}} उद्देश्य",
|
|
319
319
|
"autoSelected": "Auto-selected",
|
|
320
320
|
"noProductsAvailable": "No products available",
|
|
321
321
|
"noProductsAvailableDescription": "You have no consents to manage yet.",
|
|
@@ -314,8 +314,8 @@
|
|
|
314
314
|
"selectProductsForRequestGeneric": "Select one or more products to continue",
|
|
315
315
|
"yourData": "Your data",
|
|
316
316
|
"actingOnBehalfOf": "Acting on behalf of {{nominator}}",
|
|
317
|
-
"activePurposes_one": "{{count}}
|
|
318
|
-
"activePurposes_other": "{{count}}
|
|
317
|
+
"activePurposes_one": "{{count}} উদ্দেশ্য",
|
|
318
|
+
"activePurposes_other": "{{count}} উদ্দেশ্য",
|
|
319
319
|
"autoSelected": "Auto-selected",
|
|
320
320
|
"noProductsAvailable": "No products available",
|
|
321
321
|
"noProductsAvailableDescription": "You have no consents to manage yet.",
|
|
@@ -314,8 +314,8 @@
|
|
|
314
314
|
"selectProductsForRequestGeneric": "Select one or more products to continue",
|
|
315
315
|
"yourData": "Your data",
|
|
316
316
|
"actingOnBehalfOf": "Acting on behalf of {{nominator}}",
|
|
317
|
-
"activePurposes_one": "{{count}}
|
|
318
|
-
"activePurposes_other": "{{count}}
|
|
317
|
+
"activePurposes_one": "{{count}} उद्देश्य",
|
|
318
|
+
"activePurposes_other": "{{count}} उद्देश्य",
|
|
319
319
|
"autoSelected": "Auto-selected",
|
|
320
320
|
"noProductsAvailable": "No products available",
|
|
321
321
|
"noProductsAvailableDescription": "You have no consents to manage yet.",
|
|
@@ -314,8 +314,8 @@
|
|
|
314
314
|
"selectProductsForRequestGeneric": "Select one or more products to continue",
|
|
315
315
|
"yourData": "Your data",
|
|
316
316
|
"actingOnBehalfOf": "Acting on behalf of {{nominator}}",
|
|
317
|
-
"activePurposes_one": "{{count}}
|
|
318
|
-
"activePurposes_other": "{{count}}
|
|
317
|
+
"activePurposes_one": "{{count}} उद्देश्य",
|
|
318
|
+
"activePurposes_other": "{{count}} उद्देश्य",
|
|
319
319
|
"autoSelected": "Auto-selected",
|
|
320
320
|
"noProductsAvailable": "No products available",
|
|
321
321
|
"noProductsAvailableDescription": "You have no consents to manage yet.",
|
|
@@ -329,8 +329,8 @@
|
|
|
329
329
|
"selectProductsForRequestGeneric": "Select a product to continue",
|
|
330
330
|
"yourData": "Your data",
|
|
331
331
|
"actingOnBehalfOf": "Acting on behalf of {{nominator}}",
|
|
332
|
-
"activePurposes_one": "{{count}}
|
|
333
|
-
"activePurposes_other": "{{count}}
|
|
332
|
+
"activePurposes_one": "{{count}} purpose",
|
|
333
|
+
"activePurposes_other": "{{count}} purposes",
|
|
334
334
|
"autoSelected": "Auto-selected",
|
|
335
335
|
"noProductsAvailable": "No products available",
|
|
336
336
|
"noProductsAvailableDescription": "You have no consents to manage yet.",
|
|
@@ -314,8 +314,8 @@
|
|
|
314
314
|
"selectProductsForRequestGeneric": "Select one or more products to continue",
|
|
315
315
|
"yourData": "Your data",
|
|
316
316
|
"actingOnBehalfOf": "Acting on behalf of {{nominator}}",
|
|
317
|
-
"activePurposes_one": "{{count}}
|
|
318
|
-
"activePurposes_other": "{{count}}
|
|
317
|
+
"activePurposes_one": "{{count}} उद्देश",
|
|
318
|
+
"activePurposes_other": "{{count}} उद्देश",
|
|
319
319
|
"autoSelected": "Auto-selected",
|
|
320
320
|
"noProductsAvailable": "No products available",
|
|
321
321
|
"noProductsAvailableDescription": "You have no consents to manage yet.",
|
|
@@ -314,8 +314,8 @@
|
|
|
314
314
|
"selectProductsForRequestGeneric": "Select one or more products to continue",
|
|
315
315
|
"yourData": "Your data",
|
|
316
316
|
"actingOnBehalfOf": "Acting on behalf of {{nominator}}",
|
|
317
|
-
"activePurposes_one": "{{count}}
|
|
318
|
-
"activePurposes_other": "{{count}}
|
|
317
|
+
"activePurposes_one": "{{count}} હેતુ",
|
|
318
|
+
"activePurposes_other": "{{count}} હેતુઓ",
|
|
319
319
|
"autoSelected": "Auto-selected",
|
|
320
320
|
"noProductsAvailable": "No products available",
|
|
321
321
|
"noProductsAvailableDescription": "You have no consents to manage yet.",
|
|
@@ -317,8 +317,8 @@
|
|
|
317
317
|
"selectProductsForRequestGeneric": "Select one or more products to continue",
|
|
318
318
|
"yourData": "Your data",
|
|
319
319
|
"actingOnBehalfOf": "Acting on behalf of {{nominator}}",
|
|
320
|
-
"activePurposes_one": "{{count}}
|
|
321
|
-
"activePurposes_other": "{{count}}
|
|
320
|
+
"activePurposes_one": "{{count}} उद्देश्य",
|
|
321
|
+
"activePurposes_other": "{{count}} उद्देश्य",
|
|
322
322
|
"autoSelected": "Auto-selected",
|
|
323
323
|
"noProductsAvailable": "No products available",
|
|
324
324
|
"noProductsAvailableDescription": "You have no consents to manage yet.",
|
|
@@ -314,8 +314,8 @@
|
|
|
314
314
|
"selectProductsForRequestGeneric": "Select one or more products to continue",
|
|
315
315
|
"yourData": "Your data",
|
|
316
316
|
"actingOnBehalfOf": "Acting on behalf of {{nominator}}",
|
|
317
|
-
"activePurposes_one": "{{count}}
|
|
318
|
-
"activePurposes_other": "{{count}}
|
|
317
|
+
"activePurposes_one": "{{count}} ಉದ್ದೇಶ",
|
|
318
|
+
"activePurposes_other": "{{count}} ಉದ್ದೇಶಗಳು",
|
|
319
319
|
"autoSelected": "Auto-selected",
|
|
320
320
|
"noProductsAvailable": "No products available",
|
|
321
321
|
"noProductsAvailableDescription": "You have no consents to manage yet.",
|
|
@@ -314,8 +314,8 @@
|
|
|
314
314
|
"selectProductsForRequestGeneric": "Select one or more products to continue",
|
|
315
315
|
"yourData": "Your data",
|
|
316
316
|
"actingOnBehalfOf": "Acting on behalf of {{nominator}}",
|
|
317
|
-
"activePurposes_one": "{{count}}
|
|
318
|
-
"activePurposes_other": "{{count}}
|
|
317
|
+
"activePurposes_one": "{{count}} مقصد",
|
|
318
|
+
"activePurposes_other": "{{count}} مقاصد",
|
|
319
319
|
"autoSelected": "Auto-selected",
|
|
320
320
|
"noProductsAvailable": "No products available",
|
|
321
321
|
"noProductsAvailableDescription": "You have no consents to manage yet.",
|
|
@@ -314,8 +314,8 @@
|
|
|
314
314
|
"selectProductsForRequestGeneric": "Select one or more products to continue",
|
|
315
315
|
"yourData": "Your data",
|
|
316
316
|
"actingOnBehalfOf": "Acting on behalf of {{nominator}}",
|
|
317
|
-
"activePurposes_one": "{{count}}
|
|
318
|
-
"activePurposes_other": "{{count}}
|
|
317
|
+
"activePurposes_one": "{{count}} उद्देश्य",
|
|
318
|
+
"activePurposes_other": "{{count}} उद्देश्य",
|
|
319
319
|
"autoSelected": "Auto-selected",
|
|
320
320
|
"noProductsAvailable": "No products available",
|
|
321
321
|
"noProductsAvailableDescription": "You have no consents to manage yet.",
|
|
@@ -314,8 +314,8 @@
|
|
|
314
314
|
"selectProductsForRequestGeneric": "Select one or more products to continue",
|
|
315
315
|
"yourData": "Your data",
|
|
316
316
|
"actingOnBehalfOf": "Acting on behalf of {{nominator}}",
|
|
317
|
-
"activePurposes_one": "{{count}}
|
|
318
|
-
"activePurposes_other": "{{count}}
|
|
317
|
+
"activePurposes_one": "{{count}} ഉദ്ദേശ്യം",
|
|
318
|
+
"activePurposes_other": "{{count}} ഉദ്ദേശ്യങ്ങൾ",
|
|
319
319
|
"autoSelected": "Auto-selected",
|
|
320
320
|
"noProductsAvailable": "No products available",
|
|
321
321
|
"noProductsAvailableDescription": "You have no consents to manage yet.",
|
|
@@ -314,8 +314,8 @@
|
|
|
314
314
|
"selectProductsForRequestGeneric": "Select one or more products to continue",
|
|
315
315
|
"yourData": "Your data",
|
|
316
316
|
"actingOnBehalfOf": "Acting on behalf of {{nominator}}",
|
|
317
|
-
"activePurposes_one": "{{count}}
|
|
318
|
-
"activePurposes_other": "{{count}}
|
|
317
|
+
"activePurposes_one": "{{count}} ꯄꯥꯟꯗꯝ",
|
|
318
|
+
"activePurposes_other": "{{count}} ꯄꯥꯟꯗꯝ",
|
|
319
319
|
"autoSelected": "Auto-selected",
|
|
320
320
|
"noProductsAvailable": "No products available",
|
|
321
321
|
"noProductsAvailableDescription": "You have no consents to manage yet.",
|