@amalaika/form-sdk-package 1.0.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/README.md +342 -0
- package/dist/cjs/client/__tests__/client.spec.d.ts +2 -0
- package/dist/cjs/client/__tests__/client.spec.d.ts.map +1 -0
- package/dist/cjs/client/__tests__/client.spec.js +300 -0
- package/dist/cjs/client/__tests__/client.spec.js.map +1 -0
- package/dist/cjs/client/index.d.ts +26 -0
- package/dist/cjs/client/index.d.ts.map +1 -0
- package/dist/cjs/client/index.js +179 -0
- package/dist/cjs/client/index.js.map +1 -0
- package/dist/cjs/client.d.ts +22 -0
- package/dist/cjs/client.d.ts.map +1 -0
- package/dist/cjs/client.js +111 -0
- package/dist/cjs/client.js.map +1 -0
- package/dist/cjs/index.d.ts +4 -0
- package/dist/cjs/index.d.ts.map +1 -0
- package/dist/cjs/index.js +10 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/package.json +1 -0
- package/dist/cjs/types/index.d.ts +91 -0
- package/dist/cjs/types/index.d.ts.map +1 -0
- package/dist/cjs/types/index.js +3 -0
- package/dist/cjs/types/index.js.map +1 -0
- package/dist/cjs/types.d.ts +78 -0
- package/dist/cjs/types.d.ts.map +1 -0
- package/dist/cjs/types.js +3 -0
- package/dist/cjs/types.js.map +1 -0
- package/dist/cjs/utils/__tests__/utils.spec.d.ts +2 -0
- package/dist/cjs/utils/__tests__/utils.spec.d.ts.map +1 -0
- package/dist/cjs/utils/__tests__/utils.spec.js +172 -0
- package/dist/cjs/utils/__tests__/utils.spec.js.map +1 -0
- package/dist/cjs/utils/index.d.ts +5 -0
- package/dist/cjs/utils/index.d.ts.map +1 -0
- package/dist/cjs/utils/index.js +45 -0
- package/dist/cjs/utils/index.js.map +1 -0
- package/dist/cjs/utils.d.ts +5 -0
- package/dist/cjs/utils.d.ts.map +1 -0
- package/dist/cjs/utils.js +45 -0
- package/dist/cjs/utils.js.map +1 -0
- package/dist/esm/client/__tests__/client.spec.d.ts +2 -0
- package/dist/esm/client/__tests__/client.spec.d.ts.map +1 -0
- package/dist/esm/client/__tests__/client.spec.js +355 -0
- package/dist/esm/client/__tests__/client.spec.js.map +1 -0
- package/dist/esm/client/index.d.ts +26 -0
- package/dist/esm/client/index.d.ts.map +1 -0
- package/dist/esm/client/index.js +175 -0
- package/dist/esm/client/index.js.map +1 -0
- package/dist/esm/client.d.ts +22 -0
- package/dist/esm/client.d.ts.map +1 -0
- package/dist/esm/client.js +107 -0
- package/dist/esm/client.js.map +1 -0
- package/dist/esm/index.d.ts +4 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +3 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/types/index.d.ts +91 -0
- package/dist/esm/types/index.d.ts.map +1 -0
- package/dist/esm/types/index.js +2 -0
- package/dist/esm/types/index.js.map +1 -0
- package/dist/esm/types.d.ts +78 -0
- package/dist/esm/types.d.ts.map +1 -0
- package/dist/esm/types.js +2 -0
- package/dist/esm/types.js.map +1 -0
- package/dist/esm/utils/__tests__/utils.spec.d.ts +2 -0
- package/dist/esm/utils/__tests__/utils.spec.d.ts.map +1 -0
- package/dist/esm/utils/__tests__/utils.spec.js +182 -0
- package/dist/esm/utils/__tests__/utils.spec.js.map +1 -0
- package/dist/esm/utils/index.d.ts +5 -0
- package/dist/esm/utils/index.d.ts.map +1 -0
- package/dist/esm/utils/index.js +40 -0
- package/dist/esm/utils/index.js.map +1 -0
- package/dist/esm/utils.d.ts +5 -0
- package/dist/esm/utils.d.ts.map +1 -0
- package/dist/esm/utils.js +40 -0
- package/dist/esm/utils.js.map +1 -0
- package/package.json +54 -0
package/README.md
ADDED
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
# @amalaika/form-sdk-package
|
|
2
|
+
|
|
3
|
+
Framework-agnostic SDK for integrating the event registration form system. Handles data fetching, conditional visibility, file uploads, and form submission — no UI rendering included.
|
|
4
|
+
|
|
5
|
+
Works with React, Vue, Angular, Svelte, vanilla JS, or any environment with the Fetch API.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @amalaika/form-sdk-package
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
For local development (monorepo):
|
|
14
|
+
|
|
15
|
+
```json
|
|
16
|
+
{
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"@amalaika/form-sdk-package": "file:../form-sdk-package"
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Quick Start
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
import { EventFormClient, getAllFields, isFieldVisible } from "@amalaika/form-sdk-package";
|
|
27
|
+
|
|
28
|
+
const client = new EventFormClient({
|
|
29
|
+
apiKey: "Am_550e8400-e29b-41d4-a716-446655440000",
|
|
30
|
+
resourceType: "ticketing",
|
|
31
|
+
locale: "en", // default locale for all requests
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
// All calls automatically use "en" — no locale param needed
|
|
35
|
+
const tickets = await client.fetchTickets();
|
|
36
|
+
const form = await client.fetchForm(tickets[0].id);
|
|
37
|
+
const fields = getAllFields(form.schema);
|
|
38
|
+
|
|
39
|
+
// Switch language without reinstantiating
|
|
40
|
+
client.setLocale("fr");
|
|
41
|
+
const ticketsFr = await client.fetchTickets(); // now uses "fr"
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## API Reference
|
|
45
|
+
|
|
46
|
+
### Constructor
|
|
47
|
+
|
|
48
|
+
```ts
|
|
49
|
+
const client = new EventFormClient(config: EventFormConfig);
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
| Parameter | Type | Required | Description |
|
|
53
|
+
|-----------|------|----------|-------------|
|
|
54
|
+
| `apiKey` | `string` | Yes | Event API key (e.g. `"Am_550e8400-..."`) |
|
|
55
|
+
| `resourceType` | `"ticketing" \| "accommodation" \| "exhibition"` | Yes | Resource type for submissions |
|
|
56
|
+
| `apiBaseUrl` | `string` | No | API base URL. Defaults to `"https://api.eventsfactory.rw/api"` |
|
|
57
|
+
| `locale` | `string` | No | Default locale for all requests. Can be changed later via `setLocale()` |
|
|
58
|
+
| `errorMessages` | `Partial<ErrorMessages>` | No | Custom error messages — override any or all defaults |
|
|
59
|
+
|
|
60
|
+
### Locale Management
|
|
61
|
+
|
|
62
|
+
Set a default locale on the constructor so you don't have to pass it on every method call:
|
|
63
|
+
|
|
64
|
+
```ts
|
|
65
|
+
const client = new EventFormClient({
|
|
66
|
+
apiKey: "Am_550e8400-...",
|
|
67
|
+
resourceType: "ticketing",
|
|
68
|
+
locale: "fr",
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
// All calls automatically use "fr" — no need to pass locale
|
|
72
|
+
const tickets = await client.fetchTickets();
|
|
73
|
+
const form = await client.fetchForm(tickets[0].id);
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Switch locale at any time without reinstantiating:
|
|
77
|
+
|
|
78
|
+
```ts
|
|
79
|
+
client.setLocale("en");
|
|
80
|
+
// All subsequent calls now use "en"
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Read the current locale:
|
|
84
|
+
|
|
85
|
+
```ts
|
|
86
|
+
client.getLocale(); // "en"
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Per-call locale still overrides the default when needed:
|
|
90
|
+
|
|
91
|
+
```ts
|
|
92
|
+
// Uses "de" for this call only, default remains "en"
|
|
93
|
+
const tickets = await client.fetchTickets({ locale: "de" });
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### Methods
|
|
97
|
+
|
|
98
|
+
#### `client.fetchTickets(options?)`
|
|
99
|
+
|
|
100
|
+
Fetch all published tickets for the event.
|
|
101
|
+
|
|
102
|
+
```ts
|
|
103
|
+
const tickets = await client.fetchTickets({ locale: "fr", name: "VIP" });
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
| Option | Type | Description |
|
|
107
|
+
|--------|------|-------------|
|
|
108
|
+
| `locale` | `string` | Locale code for translations (also sent as `Accept-Language`) |
|
|
109
|
+
| `name` | `string` | Filter tickets by name |
|
|
110
|
+
|
|
111
|
+
Returns `Promise<Ticket[]>`.
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
#### `client.fetchTicketById(id, locale?)`
|
|
116
|
+
|
|
117
|
+
Fetch a single ticket by ID.
|
|
118
|
+
|
|
119
|
+
```ts
|
|
120
|
+
const ticket = await client.fetchTicketById(42, "en");
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Returns `Promise<Ticket>`.
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
#### `client.fetchLanguages()`
|
|
128
|
+
|
|
129
|
+
Fetch available languages for the event. Returns codes sorted with the default language first.
|
|
130
|
+
|
|
131
|
+
```ts
|
|
132
|
+
const languages = await client.fetchLanguages();
|
|
133
|
+
// ["en", "fr", "ar"]
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Returns `Promise<string[]>`.
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
#### `client.fetchForm(ticketId, locale?)`
|
|
141
|
+
|
|
142
|
+
Fetch the form linked to a ticket.
|
|
143
|
+
|
|
144
|
+
```ts
|
|
145
|
+
const form = await client.fetchForm(1, "fr");
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
Returns `Promise<FormData>`. The `form.schema` contains the field definitions used to render the form.
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
#### `client.authorizeUpload(formId, fieldId, file, locale?)`
|
|
153
|
+
|
|
154
|
+
Step 1 of file upload — request an upload token.
|
|
155
|
+
|
|
156
|
+
```ts
|
|
157
|
+
const token = await client.authorizeUpload(form.id, "resume", file);
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
Returns `Promise<string>` (the upload token).
|
|
161
|
+
|
|
162
|
+
---
|
|
163
|
+
|
|
164
|
+
#### `client.uploadFile(formId, token, file, locale?)`
|
|
165
|
+
|
|
166
|
+
Step 2 of file upload — upload the file using the token.
|
|
167
|
+
|
|
168
|
+
```ts
|
|
169
|
+
const fileUrl = await client.uploadFile(form.id, token, file);
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
Returns `Promise<string>` (the uploaded file URL to include in submission data).
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
#### `client.submitForm(formId, data, context)`
|
|
177
|
+
|
|
178
|
+
Submit form data.
|
|
179
|
+
|
|
180
|
+
```ts
|
|
181
|
+
await client.submitForm(form.id, submissionData, {
|
|
182
|
+
eventId: form.eventId,
|
|
183
|
+
ticketId: 1,
|
|
184
|
+
locale: "en",
|
|
185
|
+
});
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
| Context Field | Type | Required | Description |
|
|
189
|
+
|---------------|------|----------|-------------|
|
|
190
|
+
| `eventId` | `number` | Yes | Event ID (from `form.eventId`) |
|
|
191
|
+
| `ticketId` | `number` | Yes | Ticket ID used to fetch the form |
|
|
192
|
+
| `locale` | `string` | No | Locale for `Accept-Language` header |
|
|
193
|
+
|
|
194
|
+
The `resourceType` is automatically sent from the constructor config.
|
|
195
|
+
|
|
196
|
+
Returns `Promise<void>`.
|
|
197
|
+
|
|
198
|
+
### Utility Functions
|
|
199
|
+
|
|
200
|
+
Pure functions for working with form schemas and conditional visibility. Import directly:
|
|
201
|
+
|
|
202
|
+
```ts
|
|
203
|
+
import { getAllFields, isFieldVisible, getVisibleFieldIds } from "@amalaika/form-sdk-package";
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
#### `getAllFields(schema)`
|
|
207
|
+
|
|
208
|
+
Extracts all fields from a `FormSchema`, whether flat or stepped.
|
|
209
|
+
|
|
210
|
+
```ts
|
|
211
|
+
const fields = getAllFields(form.schema);
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
Returns `FieldDefinition[]`.
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
#### `isFieldVisible(field, formValues, allFields)`
|
|
219
|
+
|
|
220
|
+
Checks whether a field should be visible based on the current form values. Supports cascading visibility (if a parent field is hidden, its dependents are too).
|
|
221
|
+
|
|
222
|
+
```ts
|
|
223
|
+
if (isFieldVisible(field, currentValues, allFields)) {
|
|
224
|
+
// render this field
|
|
225
|
+
}
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
Returns `boolean`.
|
|
229
|
+
|
|
230
|
+
**Supported operators:**
|
|
231
|
+
|
|
232
|
+
| Operator | Visible when |
|
|
233
|
+
|----------|-------------|
|
|
234
|
+
| `equals` | `formValues[dependsOn] === value` |
|
|
235
|
+
| `not_equals` | `formValues[dependsOn] !== value` |
|
|
236
|
+
| `in` | Any overlap between selected values and target values |
|
|
237
|
+
|
|
238
|
+
---
|
|
239
|
+
|
|
240
|
+
#### `getVisibleFieldIds(allFields, formValues)`
|
|
241
|
+
|
|
242
|
+
Returns the set of field IDs that are currently visible. Use this to filter submission data — only submit visible fields.
|
|
243
|
+
|
|
244
|
+
```ts
|
|
245
|
+
const visibleIds = getVisibleFieldIds(allFields, formValues);
|
|
246
|
+
|
|
247
|
+
const submissionData = {};
|
|
248
|
+
for (const [key, val] of Object.entries(formValues)) {
|
|
249
|
+
if (visibleIds.has(key)) submissionData[key] = val;
|
|
250
|
+
}
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
Returns `Set<string>`.
|
|
254
|
+
|
|
255
|
+
## Full Example
|
|
256
|
+
|
|
257
|
+
```ts
|
|
258
|
+
import {
|
|
259
|
+
EventFormClient,
|
|
260
|
+
getAllFields,
|
|
261
|
+
getVisibleFieldIds,
|
|
262
|
+
} from "@amalaika/form-sdk-package";
|
|
263
|
+
|
|
264
|
+
const client = new EventFormClient({
|
|
265
|
+
apiKey: "Am_550e8400-e29b-41d4-a716-446655440000",
|
|
266
|
+
resourceType: "ticketing",
|
|
267
|
+
locale: "en",
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
// 1. Fetch tickets and pick one (uses default locale "en")
|
|
271
|
+
const tickets = await client.fetchTickets();
|
|
272
|
+
const ticket = tickets[0];
|
|
273
|
+
|
|
274
|
+
// 2. Fetch the form (uses default locale "en")
|
|
275
|
+
const form = await client.fetchForm(ticket.id);
|
|
276
|
+
const allFields = getAllFields(form.schema);
|
|
277
|
+
|
|
278
|
+
// 3. Collect user input into formValues (your UI handles this)
|
|
279
|
+
const formValues: Record<string, unknown> = {
|
|
280
|
+
first_name: "Jane",
|
|
281
|
+
last_name: "Doe",
|
|
282
|
+
email: "jane@example.com",
|
|
283
|
+
role: "speaker",
|
|
284
|
+
talk_title: "Building Dynamic Forms",
|
|
285
|
+
};
|
|
286
|
+
|
|
287
|
+
// 4. Filter to visible fields only
|
|
288
|
+
const visibleIds = getVisibleFieldIds(allFields, formValues);
|
|
289
|
+
const submissionData: Record<string, unknown> = {};
|
|
290
|
+
for (const [key, val] of Object.entries(formValues)) {
|
|
291
|
+
if (visibleIds.has(key)) submissionData[key] = val;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// 5. Handle file uploads (if any)
|
|
295
|
+
const resumeFile = new File(["..."], "resume.pdf", { type: "application/pdf" });
|
|
296
|
+
const token = await client.authorizeUpload(form.id, "resume", resumeFile);
|
|
297
|
+
const fileUrl = await client.uploadFile(form.id, token, resumeFile);
|
|
298
|
+
submissionData["resume"] = fileUrl;
|
|
299
|
+
|
|
300
|
+
// 6. Submit (locale comes from constructor default)
|
|
301
|
+
await client.submitForm(form.id, submissionData, {
|
|
302
|
+
eventId: form.eventId!,
|
|
303
|
+
ticketId: ticket.id,
|
|
304
|
+
});
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
## Exported Types
|
|
308
|
+
|
|
309
|
+
```ts
|
|
310
|
+
import type {
|
|
311
|
+
ErrorMessages,
|
|
312
|
+
EventFormConfig,
|
|
313
|
+
FieldOption,
|
|
314
|
+
FieldDefinition,
|
|
315
|
+
StepDefinition,
|
|
316
|
+
FormSchema,
|
|
317
|
+
FormData,
|
|
318
|
+
ApiResponse,
|
|
319
|
+
TicketTranslation,
|
|
320
|
+
Ticket,
|
|
321
|
+
} from "@amalaika/form-sdk-package";
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
## Development
|
|
325
|
+
|
|
326
|
+
```bash
|
|
327
|
+
# Install dependencies
|
|
328
|
+
npm install
|
|
329
|
+
|
|
330
|
+
# Build (ESM + CJS)
|
|
331
|
+
npm run build
|
|
332
|
+
|
|
333
|
+
# Run tests
|
|
334
|
+
npm test
|
|
335
|
+
|
|
336
|
+
# Lint
|
|
337
|
+
npm run lint
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
## License
|
|
341
|
+
|
|
342
|
+
MIT
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.spec.d.ts","sourceRoot":"","sources":["../../../../src/client/__tests__/client.spec.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const __1 = require("..");
|
|
4
|
+
// ---------------------------------------------------------------------------
|
|
5
|
+
// Fetch mock helpers
|
|
6
|
+
// ---------------------------------------------------------------------------
|
|
7
|
+
const mockFetch = jest.fn();
|
|
8
|
+
global.fetch = mockFetch;
|
|
9
|
+
function jsonResponse(data, status = 200) {
|
|
10
|
+
const body = { statusCode: status, message: "OK", data };
|
|
11
|
+
return {
|
|
12
|
+
ok: status >= 200 && status < 300,
|
|
13
|
+
status,
|
|
14
|
+
json: () => Promise.resolve(body),
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
function errorResponse(message, status = 400) {
|
|
18
|
+
return {
|
|
19
|
+
ok: false,
|
|
20
|
+
status,
|
|
21
|
+
json: () => Promise.resolve({ statusCode: status, message }),
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
// ---------------------------------------------------------------------------
|
|
25
|
+
// Fixtures
|
|
26
|
+
// ---------------------------------------------------------------------------
|
|
27
|
+
const API_BASE = "https://test.api/api";
|
|
28
|
+
const API_KEY = "Am_test-key";
|
|
29
|
+
function createClient() {
|
|
30
|
+
return new __1.EventFormClient({
|
|
31
|
+
apiKey: API_KEY,
|
|
32
|
+
resourceType: "ticketing",
|
|
33
|
+
apiBaseUrl: API_BASE,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
const sampleTicket = {
|
|
37
|
+
id: 1,
|
|
38
|
+
eventId: 10,
|
|
39
|
+
price: "50.00",
|
|
40
|
+
currency: "USD",
|
|
41
|
+
attendanceType: "PHYSICAL",
|
|
42
|
+
virtualPrice: null,
|
|
43
|
+
physicalPrice: null,
|
|
44
|
+
quantityTotal: 200,
|
|
45
|
+
salesStartAt: null,
|
|
46
|
+
salesEndAt: null,
|
|
47
|
+
discountPercentage: null,
|
|
48
|
+
discountEndAt: null,
|
|
49
|
+
isActive: true,
|
|
50
|
+
createdBy: 1,
|
|
51
|
+
name: "General Admission",
|
|
52
|
+
};
|
|
53
|
+
const sampleForm = {
|
|
54
|
+
id: 6,
|
|
55
|
+
title: "Registration",
|
|
56
|
+
description: null,
|
|
57
|
+
eventId: 10,
|
|
58
|
+
schema: {
|
|
59
|
+
fields: [
|
|
60
|
+
{ id: "first_name", type: "text", required: true },
|
|
61
|
+
{ id: "email", type: "email", required: true },
|
|
62
|
+
],
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
// ---------------------------------------------------------------------------
|
|
66
|
+
// Tests
|
|
67
|
+
// ---------------------------------------------------------------------------
|
|
68
|
+
beforeEach(() => {
|
|
69
|
+
mockFetch.mockReset();
|
|
70
|
+
});
|
|
71
|
+
describe("EventFormClient", () => {
|
|
72
|
+
describe("constructor", () => {
|
|
73
|
+
it("uses default API base when none provided", () => {
|
|
74
|
+
const client = new __1.EventFormClient({
|
|
75
|
+
apiKey: API_KEY,
|
|
76
|
+
resourceType: "ticketing",
|
|
77
|
+
});
|
|
78
|
+
mockFetch.mockResolvedValueOnce(jsonResponse([sampleTicket]));
|
|
79
|
+
client.fetchTickets();
|
|
80
|
+
expect(mockFetch).toHaveBeenCalledWith(expect.stringContaining("https://api.eventsfactory.rw/api/"), expect.anything());
|
|
81
|
+
});
|
|
82
|
+
it("strips trailing slash from custom API base", () => {
|
|
83
|
+
const client = new __1.EventFormClient({
|
|
84
|
+
apiKey: API_KEY,
|
|
85
|
+
resourceType: "ticketing",
|
|
86
|
+
apiBaseUrl: "https://custom.api/api/",
|
|
87
|
+
});
|
|
88
|
+
mockFetch.mockResolvedValueOnce(jsonResponse([sampleTicket]));
|
|
89
|
+
client.fetchTickets();
|
|
90
|
+
expect(mockFetch).toHaveBeenCalledWith(expect.stringContaining("https://custom.api/api/events/"), expect.anything());
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
// -------------------------------------------------------------------------
|
|
94
|
+
// fetchTickets
|
|
95
|
+
// -------------------------------------------------------------------------
|
|
96
|
+
describe("fetchTickets", () => {
|
|
97
|
+
it("calls the correct endpoint with API key", async () => {
|
|
98
|
+
mockFetch.mockResolvedValueOnce(jsonResponse([sampleTicket]));
|
|
99
|
+
const client = createClient();
|
|
100
|
+
const tickets = await client.fetchTickets();
|
|
101
|
+
expect(mockFetch).toHaveBeenCalledWith(expect.stringContaining(`/events/tickets/event/${API_KEY}/public`), expect.objectContaining({ headers: {} }));
|
|
102
|
+
expect(tickets).toEqual([sampleTicket]);
|
|
103
|
+
});
|
|
104
|
+
it("passes locale as query param and Accept-Language header", async () => {
|
|
105
|
+
mockFetch.mockResolvedValueOnce(jsonResponse([sampleTicket]));
|
|
106
|
+
const client = createClient();
|
|
107
|
+
await client.fetchTickets({ locale: "fr" });
|
|
108
|
+
const [url, opts] = mockFetch.mock.calls[0];
|
|
109
|
+
expect(url).toContain("locale=fr");
|
|
110
|
+
expect(opts.headers).toEqual({ "Accept-Language": "fr" });
|
|
111
|
+
});
|
|
112
|
+
it("passes name as query param", async () => {
|
|
113
|
+
mockFetch.mockResolvedValueOnce(jsonResponse([sampleTicket]));
|
|
114
|
+
const client = createClient();
|
|
115
|
+
await client.fetchTickets({ name: "VIP" });
|
|
116
|
+
const [url] = mockFetch.mock.calls[0];
|
|
117
|
+
expect(url).toContain("name=VIP");
|
|
118
|
+
});
|
|
119
|
+
it("throws on non-OK response", async () => {
|
|
120
|
+
mockFetch.mockResolvedValueOnce(errorResponse("Not found", 404));
|
|
121
|
+
const client = createClient();
|
|
122
|
+
await expect(client.fetchTickets()).rejects.toThrow("Failed to fetch tickets (404)");
|
|
123
|
+
});
|
|
124
|
+
});
|
|
125
|
+
// -------------------------------------------------------------------------
|
|
126
|
+
// fetchTicketById
|
|
127
|
+
// -------------------------------------------------------------------------
|
|
128
|
+
describe("fetchTicketById", () => {
|
|
129
|
+
it("calls the correct endpoint", async () => {
|
|
130
|
+
mockFetch.mockResolvedValueOnce(jsonResponse(sampleTicket));
|
|
131
|
+
const client = createClient();
|
|
132
|
+
const ticket = await client.fetchTicketById(1);
|
|
133
|
+
expect(mockFetch).toHaveBeenCalledWith(`${API_BASE}/events/tickets/1`, expect.objectContaining({ headers: {} }));
|
|
134
|
+
expect(ticket).toEqual(sampleTicket);
|
|
135
|
+
});
|
|
136
|
+
it("sends Accept-Language header when locale is provided", async () => {
|
|
137
|
+
mockFetch.mockResolvedValueOnce(jsonResponse(sampleTicket));
|
|
138
|
+
const client = createClient();
|
|
139
|
+
await client.fetchTicketById(1, "en");
|
|
140
|
+
const [, opts] = mockFetch.mock.calls[0];
|
|
141
|
+
expect(opts.headers).toEqual({ "Accept-Language": "en" });
|
|
142
|
+
});
|
|
143
|
+
it("throws on non-OK response", async () => {
|
|
144
|
+
mockFetch.mockResolvedValueOnce(errorResponse("Not found", 404));
|
|
145
|
+
const client = createClient();
|
|
146
|
+
await expect(client.fetchTicketById(999)).rejects.toThrow("Ticket not found (404)");
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
// -------------------------------------------------------------------------
|
|
150
|
+
// fetchLanguages
|
|
151
|
+
// -------------------------------------------------------------------------
|
|
152
|
+
describe("fetchLanguages", () => {
|
|
153
|
+
it("returns sorted language codes with default first", async () => {
|
|
154
|
+
mockFetch.mockResolvedValueOnce(jsonResponse([
|
|
155
|
+
{ id: 2, languageCode: "fr", isDefault: false },
|
|
156
|
+
{ id: 1, languageCode: "en", isDefault: true },
|
|
157
|
+
]));
|
|
158
|
+
const client = createClient();
|
|
159
|
+
const langs = await client.fetchLanguages();
|
|
160
|
+
expect(langs).toEqual(["en", "fr"]);
|
|
161
|
+
expect(mockFetch).toHaveBeenCalledWith(`${API_BASE}/events/onboarding/main-info/${API_KEY}/languages`);
|
|
162
|
+
});
|
|
163
|
+
it("throws on non-OK response", async () => {
|
|
164
|
+
mockFetch.mockResolvedValueOnce(errorResponse("Not found", 404));
|
|
165
|
+
const client = createClient();
|
|
166
|
+
await expect(client.fetchLanguages()).rejects.toThrow("Failed to fetch languages (404)");
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
// -------------------------------------------------------------------------
|
|
170
|
+
// fetchForm
|
|
171
|
+
// -------------------------------------------------------------------------
|
|
172
|
+
describe("fetchForm", () => {
|
|
173
|
+
it("calls the correct endpoint and returns form data", async () => {
|
|
174
|
+
mockFetch.mockResolvedValueOnce(jsonResponse(sampleForm));
|
|
175
|
+
const client = createClient();
|
|
176
|
+
const form = await client.fetchForm(1);
|
|
177
|
+
expect(mockFetch).toHaveBeenCalledWith(`${API_BASE}/application/forms/ticketing/1/public`, expect.objectContaining({ headers: {} }));
|
|
178
|
+
expect(form).toEqual(sampleForm);
|
|
179
|
+
});
|
|
180
|
+
it("sends Accept-Language when locale provided", async () => {
|
|
181
|
+
mockFetch.mockResolvedValueOnce(jsonResponse(sampleForm));
|
|
182
|
+
const client = createClient();
|
|
183
|
+
await client.fetchForm(1, "fr");
|
|
184
|
+
const [, opts] = mockFetch.mock.calls[0];
|
|
185
|
+
expect(opts.headers).toEqual({ "Accept-Language": "fr" });
|
|
186
|
+
});
|
|
187
|
+
it("throws on non-OK response", async () => {
|
|
188
|
+
mockFetch.mockResolvedValueOnce(errorResponse("Not found", 404));
|
|
189
|
+
const client = createClient();
|
|
190
|
+
await expect(client.fetchForm(999)).rejects.toThrow("Form not found (404)");
|
|
191
|
+
});
|
|
192
|
+
});
|
|
193
|
+
// -------------------------------------------------------------------------
|
|
194
|
+
// authorizeUpload
|
|
195
|
+
// -------------------------------------------------------------------------
|
|
196
|
+
describe("authorizeUpload", () => {
|
|
197
|
+
const file = new File(["content"], "resume.pdf", { type: "application/pdf" });
|
|
198
|
+
it("sends correct payload and returns upload token", async () => {
|
|
199
|
+
mockFetch.mockResolvedValueOnce(jsonResponse({ uploadToken: "tok-123" }));
|
|
200
|
+
const client = createClient();
|
|
201
|
+
const token = await client.authorizeUpload(6, "resume", file);
|
|
202
|
+
expect(token).toBe("tok-123");
|
|
203
|
+
const [url, opts] = mockFetch.mock.calls[0];
|
|
204
|
+
expect(url).toBe(`${API_BASE}/application/forms/6/submissions/authorize-upload`);
|
|
205
|
+
expect(opts.method).toBe("POST");
|
|
206
|
+
const body = JSON.parse(opts.body);
|
|
207
|
+
expect(body).toEqual({
|
|
208
|
+
fieldId: "resume",
|
|
209
|
+
mimeType: "application/pdf",
|
|
210
|
+
fileSize: file.size,
|
|
211
|
+
fileName: "resume.pdf",
|
|
212
|
+
});
|
|
213
|
+
});
|
|
214
|
+
it("throws with server error message on failure", async () => {
|
|
215
|
+
mockFetch.mockResolvedValueOnce(errorResponse("File type not allowed", 400));
|
|
216
|
+
const client = createClient();
|
|
217
|
+
await expect(client.authorizeUpload(6, "resume", file)).rejects.toThrow("File type not allowed");
|
|
218
|
+
});
|
|
219
|
+
});
|
|
220
|
+
// -------------------------------------------------------------------------
|
|
221
|
+
// uploadFile
|
|
222
|
+
// -------------------------------------------------------------------------
|
|
223
|
+
describe("uploadFile", () => {
|
|
224
|
+
const file = new File(["content"], "resume.pdf", { type: "application/pdf" });
|
|
225
|
+
it("sends multipart form data and returns URL", async () => {
|
|
226
|
+
mockFetch.mockResolvedValueOnce(jsonResponse({ url: "https://files.example.com/resume.pdf" }));
|
|
227
|
+
const client = createClient();
|
|
228
|
+
const url = await client.uploadFile(6, "tok-123", file);
|
|
229
|
+
expect(url).toBe("https://files.example.com/resume.pdf");
|
|
230
|
+
const [fetchUrl, opts] = mockFetch.mock.calls[0];
|
|
231
|
+
expect(fetchUrl).toBe(`${API_BASE}/application/forms/6/submissions/upload`);
|
|
232
|
+
expect(opts.method).toBe("POST");
|
|
233
|
+
expect(opts.body).toBeInstanceOf(FormData);
|
|
234
|
+
});
|
|
235
|
+
it("throws on non-OK response", async () => {
|
|
236
|
+
mockFetch.mockResolvedValueOnce(errorResponse("Token expired", 401));
|
|
237
|
+
const client = createClient();
|
|
238
|
+
await expect(client.uploadFile(6, "bad-tok", file)).rejects.toThrow("File upload failed");
|
|
239
|
+
});
|
|
240
|
+
});
|
|
241
|
+
// -------------------------------------------------------------------------
|
|
242
|
+
// submitForm
|
|
243
|
+
// -------------------------------------------------------------------------
|
|
244
|
+
describe("submitForm", () => {
|
|
245
|
+
it("sends correct payload with resourceType from constructor", async () => {
|
|
246
|
+
mockFetch.mockResolvedValueOnce({
|
|
247
|
+
ok: true,
|
|
248
|
+
status: 201,
|
|
249
|
+
json: () => Promise.resolve({ statusCode: 201, message: "Created" }),
|
|
250
|
+
});
|
|
251
|
+
const client = createClient();
|
|
252
|
+
await client.submitForm(6, { first_name: "Jane", email: "jane@test.com" }, {
|
|
253
|
+
eventId: 10,
|
|
254
|
+
ticketId: 1,
|
|
255
|
+
});
|
|
256
|
+
const [url, opts] = mockFetch.mock.calls[0];
|
|
257
|
+
expect(url).toBe(`${API_BASE}/application/forms/6/submissions`);
|
|
258
|
+
expect(opts.method).toBe("POST");
|
|
259
|
+
const body = JSON.parse(opts.body);
|
|
260
|
+
expect(body).toEqual({
|
|
261
|
+
data: { first_name: "Jane", email: "jane@test.com" },
|
|
262
|
+
eventId: 10,
|
|
263
|
+
resourceType: "ticketing",
|
|
264
|
+
resourceId: 1,
|
|
265
|
+
});
|
|
266
|
+
});
|
|
267
|
+
it("sends Accept-Language header when locale is in context", async () => {
|
|
268
|
+
mockFetch.mockResolvedValueOnce({
|
|
269
|
+
ok: true,
|
|
270
|
+
status: 201,
|
|
271
|
+
json: () => Promise.resolve({ statusCode: 201, message: "Created" }),
|
|
272
|
+
});
|
|
273
|
+
const client = createClient();
|
|
274
|
+
await client.submitForm(6, {}, { eventId: 10, ticketId: 1, locale: "fr" });
|
|
275
|
+
const [, opts] = mockFetch.mock.calls[0];
|
|
276
|
+
expect(opts.headers).toEqual(expect.objectContaining({ "Accept-Language": "fr" }));
|
|
277
|
+
});
|
|
278
|
+
it("throws with server error message on failure", async () => {
|
|
279
|
+
mockFetch.mockResolvedValueOnce(errorResponse("Duplicate email", 400));
|
|
280
|
+
const client = createClient();
|
|
281
|
+
await expect(client.submitForm(6, {}, { eventId: 10, ticketId: 1 })).rejects.toThrow("Duplicate email");
|
|
282
|
+
});
|
|
283
|
+
it("uses different resourceType when configured", async () => {
|
|
284
|
+
mockFetch.mockResolvedValueOnce({
|
|
285
|
+
ok: true,
|
|
286
|
+
status: 201,
|
|
287
|
+
json: () => Promise.resolve({ statusCode: 201, message: "Created" }),
|
|
288
|
+
});
|
|
289
|
+
const client = new __1.EventFormClient({
|
|
290
|
+
apiKey: API_KEY,
|
|
291
|
+
resourceType: "accommodation",
|
|
292
|
+
apiBaseUrl: API_BASE,
|
|
293
|
+
});
|
|
294
|
+
await client.submitForm(6, {}, { eventId: 10, ticketId: 1 });
|
|
295
|
+
const body = JSON.parse(mockFetch.mock.calls[0][1].body);
|
|
296
|
+
expect(body.resourceType).toBe("accommodation");
|
|
297
|
+
});
|
|
298
|
+
});
|
|
299
|
+
});
|
|
300
|
+
//# sourceMappingURL=client.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.spec.js","sourceRoot":"","sources":["../../../../src/client/__tests__/client.spec.ts"],"names":[],"mappings":"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"}
|