@welshare/questionnaire 0.1.2 → 0.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.
Files changed (96) hide show
  1. package/README.md +151 -0
  2. package/dist/esm/components/bmi-form.d.ts +68 -0
  3. package/dist/esm/components/bmi-form.d.ts.map +1 -0
  4. package/dist/esm/components/bmi-form.js +138 -0
  5. package/dist/esm/components/question-renderer.d.ts +6 -1
  6. package/dist/esm/components/question-renderer.d.ts.map +1 -1
  7. package/dist/esm/components/question-renderer.js +25 -14
  8. package/dist/esm/components/questions/decimal-question.d.ts +8 -1
  9. package/dist/esm/components/questions/decimal-question.d.ts.map +1 -1
  10. package/dist/esm/components/questions/decimal-question.js +19 -1
  11. package/dist/esm/components/questions/multiple-choice-question.d.ts.map +1 -1
  12. package/dist/esm/components/questions/multiple-choice-question.js +2 -2
  13. package/dist/esm/contexts/questionnaire-context.d.ts.map +1 -1
  14. package/dist/esm/contexts/questionnaire-context.js +3 -2
  15. package/dist/esm/index.d.ts +6 -2
  16. package/dist/esm/index.d.ts.map +1 -1
  17. package/dist/esm/index.js +5 -1
  18. package/dist/esm/lib/bmi-helpers.d.ts +50 -0
  19. package/dist/esm/lib/bmi-helpers.d.ts.map +1 -0
  20. package/dist/esm/lib/bmi-helpers.js +69 -0
  21. package/dist/esm/lib/constants.d.ts +94 -0
  22. package/dist/esm/lib/constants.d.ts.map +1 -0
  23. package/dist/esm/lib/constants.js +93 -0
  24. package/dist/esm/lib/questionnaire-utils.d.ts +21 -1
  25. package/dist/esm/lib/questionnaire-utils.d.ts.map +1 -1
  26. package/dist/esm/lib/questionnaire-utils.js +85 -4
  27. package/dist/esm/types/fhir.d.ts +1 -0
  28. package/dist/esm/types/fhir.d.ts.map +1 -1
  29. package/dist/esm/types/index.d.ts +25 -0
  30. package/dist/esm/types/index.d.ts.map +1 -1
  31. package/dist/styles.css +108 -0
  32. package/package.json +17 -6
  33. package/dist/node_modules/@welshare/questionnaire/.tshy/build.json +0 -8
  34. package/dist/node_modules/@welshare/questionnaire/.tshy/esm.json +0 -16
  35. package/dist/node_modules/@welshare/questionnaire/LICENSE +0 -7
  36. package/dist/node_modules/@welshare/questionnaire/README.md +0 -173
  37. package/dist/node_modules/@welshare/questionnaire/dist/esm/components/debug-section.d.ts +0 -44
  38. package/dist/node_modules/@welshare/questionnaire/dist/esm/components/debug-section.d.ts.map +0 -1
  39. package/dist/node_modules/@welshare/questionnaire/dist/esm/components/debug-section.js +0 -28
  40. package/dist/node_modules/@welshare/questionnaire/dist/esm/components/question-renderer.d.ts +0 -80
  41. package/dist/node_modules/@welshare/questionnaire/dist/esm/components/question-renderer.d.ts.map +0 -1
  42. package/dist/node_modules/@welshare/questionnaire/dist/esm/components/question-renderer.js +0 -183
  43. package/dist/node_modules/@welshare/questionnaire/dist/esm/components/questions/boolean-question.d.ts +0 -15
  44. package/dist/node_modules/@welshare/questionnaire/dist/esm/components/questions/boolean-question.d.ts.map +0 -1
  45. package/dist/node_modules/@welshare/questionnaire/dist/esm/components/questions/boolean-question.js +0 -19
  46. package/dist/node_modules/@welshare/questionnaire/dist/esm/components/questions/choice-question.d.ts +0 -19
  47. package/dist/node_modules/@welshare/questionnaire/dist/esm/components/questions/choice-question.d.ts.map +0 -1
  48. package/dist/node_modules/@welshare/questionnaire/dist/esm/components/questions/choice-question.js +0 -23
  49. package/dist/node_modules/@welshare/questionnaire/dist/esm/components/questions/decimal-question.d.ts +0 -12
  50. package/dist/node_modules/@welshare/questionnaire/dist/esm/components/questions/decimal-question.d.ts.map +0 -1
  51. package/dist/node_modules/@welshare/questionnaire/dist/esm/components/questions/decimal-question.js +0 -7
  52. package/dist/node_modules/@welshare/questionnaire/dist/esm/components/questions/integer-question.d.ts +0 -18
  53. package/dist/node_modules/@welshare/questionnaire/dist/esm/components/questions/integer-question.d.ts.map +0 -1
  54. package/dist/node_modules/@welshare/questionnaire/dist/esm/components/questions/integer-question.js +0 -24
  55. package/dist/node_modules/@welshare/questionnaire/dist/esm/components/questions/multiple-choice-question.d.ts +0 -20
  56. package/dist/node_modules/@welshare/questionnaire/dist/esm/components/questions/multiple-choice-question.d.ts.map +0 -1
  57. package/dist/node_modules/@welshare/questionnaire/dist/esm/components/questions/multiple-choice-question.js +0 -39
  58. package/dist/node_modules/@welshare/questionnaire/dist/esm/components/questions/string-question.d.ts +0 -12
  59. package/dist/node_modules/@welshare/questionnaire/dist/esm/components/questions/string-question.d.ts.map +0 -1
  60. package/dist/node_modules/@welshare/questionnaire/dist/esm/components/questions/string-question.js +0 -7
  61. package/dist/node_modules/@welshare/questionnaire/dist/esm/contexts/questionnaire-context.d.ts +0 -41
  62. package/dist/node_modules/@welshare/questionnaire/dist/esm/contexts/questionnaire-context.d.ts.map +0 -1
  63. package/dist/node_modules/@welshare/questionnaire/dist/esm/contexts/questionnaire-context.js +0 -350
  64. package/dist/node_modules/@welshare/questionnaire/dist/esm/index.d.ts +0 -7
  65. package/dist/node_modules/@welshare/questionnaire/dist/esm/index.d.ts.map +0 -1
  66. package/dist/node_modules/@welshare/questionnaire/dist/esm/index.js +0 -6
  67. package/dist/node_modules/@welshare/questionnaire/dist/esm/lib/questionnaire-utils.d.ts +0 -33
  68. package/dist/node_modules/@welshare/questionnaire/dist/esm/lib/questionnaire-utils.d.ts.map +0 -1
  69. package/dist/node_modules/@welshare/questionnaire/dist/esm/lib/questionnaire-utils.js +0 -99
  70. package/dist/node_modules/@welshare/questionnaire/dist/esm/package.json +0 -3
  71. package/dist/node_modules/@welshare/questionnaire/dist/esm/types/fhir.d.ts +0 -117
  72. package/dist/node_modules/@welshare/questionnaire/dist/esm/types/fhir.d.ts.map +0 -1
  73. package/dist/node_modules/@welshare/questionnaire/dist/esm/types/fhir.js +0 -3
  74. package/dist/node_modules/@welshare/questionnaire/dist/esm/types/index.d.ts +0 -51
  75. package/dist/node_modules/@welshare/questionnaire/dist/esm/types/index.d.ts.map +0 -1
  76. package/dist/node_modules/@welshare/questionnaire/dist/esm/types/index.js +0 -1
  77. package/dist/node_modules/@welshare/questionnaire/dist/styles.css +0 -467
  78. package/dist/node_modules/@welshare/questionnaire/dist/tokens.css +0 -130
  79. package/dist/node_modules/@welshare/questionnaire/package.json +0 -85
  80. package/dist/node_modules/@welshare/questionnaire/src/components/debug-section.tsx +0 -116
  81. package/dist/node_modules/@welshare/questionnaire/src/components/question-renderer.tsx +0 -391
  82. package/dist/node_modules/@welshare/questionnaire/src/components/questionnaire-styles.css +0 -467
  83. package/dist/node_modules/@welshare/questionnaire/src/components/questionnaire-tokens.css +0 -130
  84. package/dist/node_modules/@welshare/questionnaire/src/components/questions/boolean-question.tsx +0 -72
  85. package/dist/node_modules/@welshare/questionnaire/src/components/questions/choice-question.tsx +0 -68
  86. package/dist/node_modules/@welshare/questionnaire/src/components/questions/decimal-question.tsx +0 -32
  87. package/dist/node_modules/@welshare/questionnaire/src/components/questions/integer-question.tsx +0 -87
  88. package/dist/node_modules/@welshare/questionnaire/src/components/questions/multiple-choice-question.tsx +0 -119
  89. package/dist/node_modules/@welshare/questionnaire/src/components/questions/string-question.tsx +0 -31
  90. package/dist/node_modules/@welshare/questionnaire/src/contexts/questionnaire-context.tsx +0 -499
  91. package/dist/node_modules/@welshare/questionnaire/src/index.ts +0 -41
  92. package/dist/node_modules/@welshare/questionnaire/src/lib/__tests__/questionnaire-utils.test.ts +0 -578
  93. package/dist/node_modules/@welshare/questionnaire/src/lib/questionnaire-utils.ts +0 -122
  94. package/dist/node_modules/@welshare/questionnaire/src/types/fhir.ts +0 -126
  95. package/dist/node_modules/@welshare/questionnaire/src/types/index.ts +0 -44
  96. package/dist/node_modules/@welshare/questionnaire/tsconfig.json +0 -16
@@ -1,578 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
- import type { Questionnaire, QuestionnaireItem } from "../../types/fhir.js";
3
- import { getVisiblePages, getAllQuestionsFromPage } from "../questionnaire-utils.js";
4
-
5
- describe("questionnaire-utils", () => {
6
- describe("getVisiblePages", () => {
7
- it("should return empty array for questionnaire without items", () => {
8
- const questionnaire: Questionnaire = {
9
- resourceType: "Questionnaire",
10
- id: "test-1",
11
- status: "active",
12
- };
13
-
14
- const result = getVisiblePages(questionnaire);
15
- expect(result).toEqual([]);
16
- });
17
-
18
- it("should return empty array for questionnaire with null items", () => {
19
- const questionnaire: Questionnaire = {
20
- resourceType: "Questionnaire",
21
- id: "test-2",
22
- status: "active",
23
- item: undefined,
24
- };
25
-
26
- const result = getVisiblePages(questionnaire);
27
- expect(result).toEqual([]);
28
- });
29
-
30
- it("should return visible group items only", () => {
31
- const questionnaire: Questionnaire = {
32
- resourceType: "Questionnaire",
33
- id: "test-3",
34
- status: "active",
35
- item: [
36
- {
37
- linkId: "page1",
38
- type: "group",
39
- text: "Page 1",
40
- },
41
- {
42
- linkId: "page2",
43
- type: "group",
44
- text: "Page 2",
45
- },
46
- {
47
- linkId: "q1",
48
- type: "string",
49
- text: "Question 1",
50
- },
51
- ],
52
- };
53
-
54
- const result = getVisiblePages(questionnaire);
55
- expect(result).toHaveLength(2);
56
- expect(result[0].linkId).toBe("page1");
57
- expect(result[1].linkId).toBe("page2");
58
- });
59
-
60
- it("should exclude hidden group items", () => {
61
- const questionnaire: Questionnaire = {
62
- resourceType: "Questionnaire",
63
- id: "test-4",
64
- status: "active",
65
- item: [
66
- {
67
- linkId: "page1",
68
- type: "group",
69
- text: "Page 1",
70
- },
71
- {
72
- linkId: "page2",
73
- type: "group",
74
- text: "Page 2",
75
- extension: [
76
- {
77
- url: "http://hl7.org/fhir/StructureDefinition/questionnaire-hidden",
78
- valueBoolean: true,
79
- },
80
- ],
81
- },
82
- {
83
- linkId: "page3",
84
- type: "group",
85
- text: "Page 3",
86
- },
87
- ],
88
- };
89
-
90
- const result = getVisiblePages(questionnaire);
91
- expect(result).toHaveLength(2);
92
- expect(result[0].linkId).toBe("page1");
93
- expect(result[1].linkId).toBe("page3");
94
- });
95
-
96
- it("should exclude non-group items", () => {
97
- const questionnaire: Questionnaire = {
98
- resourceType: "Questionnaire",
99
- id: "test-5",
100
- status: "active",
101
- item: [
102
- {
103
- linkId: "page1",
104
- type: "group",
105
- text: "Page 1",
106
- },
107
- {
108
- linkId: "q1",
109
- type: "string",
110
- text: "Question 1",
111
- },
112
- {
113
- linkId: "q2",
114
- type: "boolean",
115
- text: "Question 2",
116
- },
117
- ],
118
- };
119
-
120
- const result = getVisiblePages(questionnaire);
121
- expect(result).toHaveLength(1);
122
- expect(result[0].linkId).toBe("page1");
123
- });
124
-
125
- it("should handle group with hidden extension set to false", () => {
126
- const questionnaire: Questionnaire = {
127
- resourceType: "Questionnaire",
128
- id: "test-6",
129
- status: "active",
130
- item: [
131
- {
132
- linkId: "page1",
133
- type: "group",
134
- text: "Page 1",
135
- extension: [
136
- {
137
- url: "http://hl7.org/fhir/StructureDefinition/questionnaire-hidden",
138
- valueBoolean: false,
139
- },
140
- ],
141
- },
142
- ],
143
- };
144
-
145
- const result = getVisiblePages(questionnaire);
146
- expect(result).toHaveLength(1);
147
- expect(result[0].linkId).toBe("page1");
148
- });
149
-
150
- it("should handle nested group structures", () => {
151
- const questionnaire: Questionnaire = {
152
- resourceType: "Questionnaire",
153
- id: "test-7",
154
- status: "active",
155
- item: [
156
- {
157
- linkId: "page1",
158
- type: "group",
159
- text: "Page 1",
160
- item: [
161
- {
162
- linkId: "nested-group",
163
- type: "group",
164
- text: "Nested Group",
165
- },
166
- ],
167
- },
168
- {
169
- linkId: "page2",
170
- type: "group",
171
- text: "Page 2",
172
- },
173
- ],
174
- };
175
-
176
- const result = getVisiblePages(questionnaire);
177
- expect(result).toHaveLength(2);
178
- expect(result[0].linkId).toBe("page1");
179
- expect(result[1].linkId).toBe("page2");
180
- });
181
- });
182
-
183
- describe("getAllQuestionsFromPage", () => {
184
- it("should return empty array for page without items", () => {
185
- const pageItem: QuestionnaireItem = {
186
- linkId: "page1",
187
- type: "group",
188
- text: "Page 1",
189
- };
190
-
191
- const result = getAllQuestionsFromPage(pageItem);
192
- expect(result).toEqual([]);
193
- });
194
-
195
- it("should return empty array for page with null items", () => {
196
- const pageItem: QuestionnaireItem = {
197
- linkId: "page1",
198
- type: "group",
199
- text: "Page 1",
200
- item: undefined,
201
- };
202
-
203
- const result = getAllQuestionsFromPage(pageItem);
204
- expect(result).toEqual([]);
205
- });
206
-
207
- it("should return all questions from a flat page", () => {
208
- const pageItem: QuestionnaireItem = {
209
- linkId: "page1",
210
- type: "group",
211
- text: "Page 1",
212
- item: [
213
- {
214
- linkId: "q1",
215
- type: "string",
216
- text: "Question 1",
217
- },
218
- {
219
- linkId: "q2",
220
- type: "boolean",
221
- text: "Question 2",
222
- },
223
- {
224
- linkId: "q3",
225
- type: "integer",
226
- text: "Question 3",
227
- },
228
- ],
229
- };
230
-
231
- const result = getAllQuestionsFromPage(pageItem);
232
- expect(result).toHaveLength(3);
233
- expect(result[0].linkId).toBe("q1");
234
- expect(result[1].linkId).toBe("q2");
235
- expect(result[2].linkId).toBe("q3");
236
- });
237
-
238
- it("should exclude display items", () => {
239
- const pageItem: QuestionnaireItem = {
240
- linkId: "page1",
241
- type: "group",
242
- text: "Page 1",
243
- item: [
244
- {
245
- linkId: "display1",
246
- type: "display",
247
- text: "This is a display item",
248
- },
249
- {
250
- linkId: "q1",
251
- type: "string",
252
- text: "Question 1",
253
- },
254
- {
255
- linkId: "display2",
256
- type: "display",
257
- text: "Another display item",
258
- },
259
- {
260
- linkId: "q2",
261
- type: "boolean",
262
- text: "Question 2",
263
- },
264
- ],
265
- };
266
-
267
- const result = getAllQuestionsFromPage(pageItem);
268
- expect(result).toHaveLength(2);
269
- expect(result[0].linkId).toBe("q1");
270
- expect(result[1].linkId).toBe("q2");
271
- });
272
-
273
- it("should flatten questions from nested groups", () => {
274
- const pageItem: QuestionnaireItem = {
275
- linkId: "page1",
276
- type: "group",
277
- text: "Page 1",
278
- item: [
279
- {
280
- linkId: "q1",
281
- type: "string",
282
- text: "Question 1",
283
- },
284
- {
285
- linkId: "nested-group",
286
- type: "group",
287
- text: "Nested Group",
288
- item: [
289
- {
290
- linkId: "q2",
291
- type: "boolean",
292
- text: "Question 2",
293
- },
294
- {
295
- linkId: "q3",
296
- type: "integer",
297
- text: "Question 3",
298
- },
299
- ],
300
- },
301
- {
302
- linkId: "q4",
303
- type: "decimal",
304
- text: "Question 4",
305
- },
306
- ],
307
- };
308
-
309
- const result = getAllQuestionsFromPage(pageItem);
310
- expect(result).toHaveLength(4);
311
- expect(result[0].linkId).toBe("q1");
312
- expect(result[1].linkId).toBe("q2");
313
- expect(result[2].linkId).toBe("q3");
314
- expect(result[3].linkId).toBe("q4");
315
- });
316
-
317
- it("should handle deeply nested groups", () => {
318
- const pageItem: QuestionnaireItem = {
319
- linkId: "page1",
320
- type: "group",
321
- text: "Page 1",
322
- item: [
323
- {
324
- linkId: "q1",
325
- type: "string",
326
- text: "Question 1",
327
- },
328
- {
329
- linkId: "level1-group",
330
- type: "group",
331
- text: "Level 1 Group",
332
- item: [
333
- {
334
- linkId: "q2",
335
- type: "boolean",
336
- text: "Question 2",
337
- },
338
- {
339
- linkId: "level2-group",
340
- type: "group",
341
- text: "Level 2 Group",
342
- item: [
343
- {
344
- linkId: "q3",
345
- type: "integer",
346
- text: "Question 3",
347
- },
348
- {
349
- linkId: "level3-group",
350
- type: "group",
351
- text: "Level 3 Group",
352
- item: [
353
- {
354
- linkId: "q4",
355
- type: "decimal",
356
- text: "Question 4",
357
- },
358
- ],
359
- },
360
- ],
361
- },
362
- ],
363
- },
364
- {
365
- linkId: "q5",
366
- type: "date",
367
- text: "Question 5",
368
- },
369
- ],
370
- };
371
-
372
- const result = getAllQuestionsFromPage(pageItem);
373
- expect(result).toHaveLength(5);
374
- expect(result[0].linkId).toBe("q1");
375
- expect(result[1].linkId).toBe("q2");
376
- expect(result[2].linkId).toBe("q3");
377
- expect(result[3].linkId).toBe("q4");
378
- expect(result[4].linkId).toBe("q5");
379
- });
380
-
381
- it("should exclude display items from nested groups", () => {
382
- const pageItem: QuestionnaireItem = {
383
- linkId: "page1",
384
- type: "group",
385
- text: "Page 1",
386
- item: [
387
- {
388
- linkId: "q1",
389
- type: "string",
390
- text: "Question 1",
391
- },
392
- {
393
- linkId: "nested-group",
394
- type: "group",
395
- text: "Nested Group",
396
- item: [
397
- {
398
- linkId: "display1",
399
- type: "display",
400
- text: "Display in nested group",
401
- },
402
- {
403
- linkId: "q2",
404
- type: "boolean",
405
- text: "Question 2",
406
- },
407
- ],
408
- },
409
- ],
410
- };
411
-
412
- const result = getAllQuestionsFromPage(pageItem);
413
- expect(result).toHaveLength(2);
414
- expect(result[0].linkId).toBe("q1");
415
- expect(result[1].linkId).toBe("q2");
416
- });
417
-
418
- it("should handle mixed nested groups and questions", () => {
419
- const pageItem: QuestionnaireItem = {
420
- linkId: "page1",
421
- type: "group",
422
- text: "Page 1",
423
- item: [
424
- {
425
- linkId: "section1",
426
- type: "group",
427
- text: "Section 1",
428
- item: [
429
- {
430
- linkId: "q1",
431
- type: "string",
432
- text: "Question 1",
433
- },
434
- {
435
- linkId: "q2",
436
- type: "boolean",
437
- text: "Question 2",
438
- },
439
- ],
440
- },
441
- {
442
- linkId: "q3",
443
- type: "integer",
444
- text: "Question 3",
445
- },
446
- {
447
- linkId: "section2",
448
- type: "group",
449
- text: "Section 2",
450
- item: [
451
- {
452
- linkId: "subsection",
453
- type: "group",
454
- text: "Subsection",
455
- item: [
456
- {
457
- linkId: "q4",
458
- type: "decimal",
459
- text: "Question 4",
460
- },
461
- ],
462
- },
463
- {
464
- linkId: "q5",
465
- type: "date",
466
- text: "Question 5",
467
- },
468
- ],
469
- },
470
- ],
471
- };
472
-
473
- const result = getAllQuestionsFromPage(pageItem);
474
- expect(result).toHaveLength(5);
475
- expect(result.map((q) => q.linkId)).toEqual(["q1", "q2", "q3", "q4", "q5"]);
476
- });
477
-
478
- it("should handle all question types", () => {
479
- const pageItem: QuestionnaireItem = {
480
- linkId: "page1",
481
- type: "group",
482
- text: "Page 1",
483
- item: [
484
- {
485
- linkId: "q1",
486
- type: "boolean",
487
- text: "Boolean question",
488
- },
489
- {
490
- linkId: "q2",
491
- type: "decimal",
492
- text: "Decimal question",
493
- },
494
- {
495
- linkId: "q3",
496
- type: "integer",
497
- text: "Integer question",
498
- },
499
- {
500
- linkId: "q4",
501
- type: "date",
502
- text: "Date question",
503
- },
504
- {
505
- linkId: "q5",
506
- type: "dateTime",
507
- text: "DateTime question",
508
- },
509
- {
510
- linkId: "q6",
511
- type: "time",
512
- text: "Time question",
513
- },
514
- {
515
- linkId: "q7",
516
- type: "string",
517
- text: "String question",
518
- },
519
- {
520
- linkId: "q8",
521
- type: "text",
522
- text: "Text question",
523
- },
524
- {
525
- linkId: "q9",
526
- type: "url",
527
- text: "URL question",
528
- },
529
- {
530
- linkId: "q10",
531
- type: "choice",
532
- text: "Choice question",
533
- },
534
- {
535
- linkId: "q11",
536
- type: "open-choice",
537
- text: "Open choice question",
538
- },
539
- {
540
- linkId: "q12",
541
- type: "attachment",
542
- text: "Attachment question",
543
- },
544
- {
545
- linkId: "q13",
546
- type: "reference",
547
- text: "Reference question",
548
- },
549
- {
550
- linkId: "q14",
551
- type: "quantity",
552
- text: "Quantity question",
553
- },
554
- ],
555
- };
556
-
557
- const result = getAllQuestionsFromPage(pageItem);
558
- expect(result).toHaveLength(14);
559
- expect(result.map((q) => q.type)).toEqual([
560
- "boolean",
561
- "decimal",
562
- "integer",
563
- "date",
564
- "dateTime",
565
- "time",
566
- "string",
567
- "text",
568
- "url",
569
- "choice",
570
- "open-choice",
571
- "attachment",
572
- "reference",
573
- "quantity",
574
- ]);
575
- });
576
- });
577
- });
578
-
@@ -1,122 +0,0 @@
1
- import type { Questionnaire, QuestionnaireItem } from "../types/fhir.js";
2
-
3
- /**
4
- * Get visible pages from a questionnaire (excludes hidden groups)
5
- */
6
- export const getVisiblePages = (questionnaire: Questionnaire): QuestionnaireItem[] => {
7
- if (!questionnaire.item) return [];
8
-
9
- return questionnaire.item.filter((item) => {
10
- // Check if hidden
11
- const isHidden = item.extension?.some(
12
- (ext) =>
13
- ext.url === "http://hl7.org/fhir/StructureDefinition/questionnaire-hidden" &&
14
- ext.valueBoolean === true
15
- );
16
-
17
- // Only include visible group items
18
- return item.type === "group" && !isHidden;
19
- });
20
- };
21
-
22
- /**
23
- * Calculate progress percentage
24
- * @param currentPageIndex 0-based page index
25
- * @param totalPages Total number of pages
26
- * @returns Progress percentage (0-100)
27
- */
28
- export const calculateProgress = (currentPageIndex: number, totalPages: number): number => {
29
- if (totalPages === 0) return 0;
30
- return ((currentPageIndex + 1) / totalPages) * 100;
31
- };
32
-
33
- /**
34
- * Get all questions from a page (flattens nested groups)
35
- */
36
- export const getAllQuestionsFromPage = (pageItem: QuestionnaireItem): QuestionnaireItem[] => {
37
- const questions: QuestionnaireItem[] = [];
38
-
39
- const collectQuestions = (items?: QuestionnaireItem[]) => {
40
- if (!items) return;
41
-
42
- for (const item of items) {
43
- if (item.type === "group" && item.item) {
44
- // Recursively collect from nested groups
45
- collectQuestions(item.item);
46
- } else if (item.type !== "display") {
47
- // Add non-display items (actual questions)
48
- questions.push(item);
49
- }
50
- }
51
- };
52
-
53
- if (pageItem.item) {
54
- collectQuestions(pageItem.item);
55
- }
56
-
57
- return questions;
58
- };
59
-
60
- /**
61
- * Recursively searches for a questionnaire item by linkId
62
- */
63
- export function findQuestionnaireItem(
64
- items: QuestionnaireItem[] | undefined,
65
- linkId: string
66
- ): QuestionnaireItem | null {
67
- if (!items) return null;
68
-
69
- for (const item of items) {
70
- if (item.linkId === linkId) {
71
- return item;
72
- }
73
- // Recursively search nested items
74
- if (item.item && item.item.length > 0) {
75
- const found = findQuestionnaireItem(item.item, linkId);
76
- if (found) return found;
77
- }
78
- }
79
-
80
- return null;
81
- }
82
-
83
- /**
84
- * Check if a question has any answer value
85
- */
86
- export const hasAnswerValue = (answer: any): boolean => {
87
- if (!answer) return false;
88
-
89
- return (
90
- answer.valueBoolean !== undefined ||
91
- answer.valueInteger !== undefined ||
92
- answer.valueDecimal !== undefined ||
93
- answer.valueString !== undefined ||
94
- answer.valueCoding !== undefined ||
95
- answer.valueDate !== undefined ||
96
- answer.valueDateTime !== undefined ||
97
- answer.valueTime !== undefined ||
98
- answer.valueUri !== undefined ||
99
- answer.valueQuantity !== undefined
100
- );
101
- };
102
-
103
- /**
104
- * Check if a question item should be hidden based on extensions
105
- */
106
- export const isQuestionHidden = (item: QuestionnaireItem): boolean => {
107
- return item.extension?.some(
108
- (ext) =>
109
- ext.url === "http://hl7.org/fhir/StructureDefinition/questionnaire-hidden" &&
110
- ext.valueBoolean === true
111
- ) ?? false;
112
- };
113
-
114
- /**
115
- * Get the exclusive option code from a question item (if any)
116
- */
117
- export const getExclusiveOptionCode = (item: QuestionnaireItem): string | undefined => {
118
- const exclusiveExt = item.extension?.find(
119
- (ext) => ext.url === "http://codes.welshare.app/StructureDefinition/questionnaire-exclusive-option"
120
- );
121
- return exclusiveExt?.valueString;
122
- };