@welshare/questionnaire 0.2.0 → 0.2.2
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 +305 -60
- package/dist/esm/components/bmi-form.d.ts.map +1 -1
- package/dist/esm/components/legal-consent-form.d.ts +123 -0
- package/dist/esm/components/legal-consent-form.d.ts.map +1 -0
- package/dist/esm/components/legal-consent-form.js +97 -0
- package/dist/esm/components/media-attachment.d.ts +21 -0
- package/dist/esm/components/media-attachment.d.ts.map +1 -0
- package/dist/esm/components/media-attachment.js +22 -0
- package/dist/esm/components/question-renderer.d.ts.map +1 -1
- package/dist/esm/components/question-renderer.js +9 -4
- package/dist/esm/components/questions/boolean-question.d.ts +4 -4
- package/dist/esm/components/questions/boolean-question.d.ts.map +1 -1
- package/dist/esm/components/questions/boolean-question.js +6 -6
- package/dist/esm/components/questions/choice-question.d.ts +4 -4
- package/dist/esm/components/questions/choice-question.d.ts.map +1 -1
- package/dist/esm/components/questions/choice-question.js +19 -11
- package/dist/esm/components/questions/multiple-choice-question.d.ts.map +1 -1
- package/dist/esm/components/questions/multiple-choice-question.js +19 -11
- package/dist/esm/contexts/questionnaire-context.d.ts.map +1 -1
- package/dist/esm/contexts/questionnaire-context.js +4 -22
- package/dist/esm/index.d.ts +4 -2
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +2 -1
- package/dist/esm/lib/bmi-helpers.d.ts.map +1 -1
- package/dist/esm/lib/constants.d.ts +12 -0
- package/dist/esm/lib/constants.d.ts.map +1 -1
- package/dist/esm/lib/constants.js +12 -0
- package/dist/esm/lib/questionnaire-utils.d.ts +15 -1
- package/dist/esm/lib/questionnaire-utils.d.ts.map +1 -1
- package/dist/esm/lib/questionnaire-utils.js +26 -0
- package/dist/esm/types/fhir.d.ts +25 -5
- package/dist/esm/types/fhir.d.ts.map +1 -1
- package/dist/esm/types/fhir.js +3 -1
- package/dist/esm/types/index.d.ts.map +1 -1
- package/dist/styles.css +153 -0
- package/package.json +2 -2
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState, useCallback } from "react";
|
|
3
|
+
const DEFAULT_TERMS_URL = "https://www.welshare.health/terms-hpmp";
|
|
4
|
+
const DEFAULT_PRIVACY_URL = "https://www.welshare.health/privacy-hpmp";
|
|
5
|
+
/**
|
|
6
|
+
* Legal Consent Form Component
|
|
7
|
+
*
|
|
8
|
+
* A self-contained form component for collecting user consent for:
|
|
9
|
+
* 1. Terms & Conditions and Privacy Policy (required)
|
|
10
|
+
* 2. Study invitation notifications (optional)
|
|
11
|
+
*
|
|
12
|
+
* **Usage Pattern:**
|
|
13
|
+
* This component provides the content for a consent dialog. Applications
|
|
14
|
+
* should wrap this component in their own Dialog/Modal component, similar
|
|
15
|
+
* to how BmiForm is used.
|
|
16
|
+
*
|
|
17
|
+
* **Customization:**
|
|
18
|
+
* - Provide custom checkbox renderer via `renderCheckbox` prop
|
|
19
|
+
* - Customize document URLs via `documentLinks` prop
|
|
20
|
+
* - Style with CSS classes using `className` prop
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```tsx
|
|
24
|
+
* <Dialog open={showConsent} onOpenChange={setShowConsent}>
|
|
25
|
+
* <DialogContent>
|
|
26
|
+
* <DialogHeader>
|
|
27
|
+
* <DialogTitle>Health Data Storage Consent</DialogTitle>
|
|
28
|
+
* </DialogHeader>
|
|
29
|
+
* <LegalConsentForm
|
|
30
|
+
* renderCheckbox={({ id, checked, onCheckedChange, className }) => (
|
|
31
|
+
* <Checkbox
|
|
32
|
+
* id={id}
|
|
33
|
+
* checked={checked}
|
|
34
|
+
* onCheckedChange={onCheckedChange}
|
|
35
|
+
* className={className}
|
|
36
|
+
* />
|
|
37
|
+
* )}
|
|
38
|
+
* onConfirm={(result) => {
|
|
39
|
+
* handleConsent(result);
|
|
40
|
+
* setShowConsent(false);
|
|
41
|
+
* }}
|
|
42
|
+
* onCancel={() => setShowConsent(false)}
|
|
43
|
+
* />
|
|
44
|
+
* </DialogContent>
|
|
45
|
+
* </Dialog>
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
export const LegalConsentForm = ({ initialValues, documentLinks, onConfirm, onCancel, onChange, renderCheckbox, confirmButtonLabel = "Confirm & Continue", cancelButtonLabel = "Cancel", className = "", }) => {
|
|
49
|
+
// Consent state
|
|
50
|
+
const [termsAccepted, setTermsAccepted] = useState(initialValues?.termsAccepted ?? false);
|
|
51
|
+
const [studyConsentAccepted, setStudyConsentAccepted] = useState(initialValues?.studyConsentAccepted ?? false);
|
|
52
|
+
// Resolve document URLs
|
|
53
|
+
const termsUrl = documentLinks?.termsUrl ?? DEFAULT_TERMS_URL;
|
|
54
|
+
const privacyUrl = documentLinks?.privacyUrl ?? DEFAULT_PRIVACY_URL;
|
|
55
|
+
// Handle terms acceptance change
|
|
56
|
+
const handleTermsChange = useCallback((checked) => {
|
|
57
|
+
setTermsAccepted(checked);
|
|
58
|
+
onChange?.({
|
|
59
|
+
termsAccepted: checked,
|
|
60
|
+
studyConsentAccepted,
|
|
61
|
+
});
|
|
62
|
+
}, [onChange, studyConsentAccepted]);
|
|
63
|
+
// Handle study consent change
|
|
64
|
+
const handleStudyConsentChange = useCallback((checked) => {
|
|
65
|
+
setStudyConsentAccepted(checked);
|
|
66
|
+
onChange?.({
|
|
67
|
+
termsAccepted,
|
|
68
|
+
studyConsentAccepted: checked,
|
|
69
|
+
});
|
|
70
|
+
}, [onChange, termsAccepted]);
|
|
71
|
+
// Handle confirm
|
|
72
|
+
const handleConfirm = useCallback(() => {
|
|
73
|
+
if (termsAccepted && onConfirm) {
|
|
74
|
+
onConfirm({
|
|
75
|
+
termsAccepted,
|
|
76
|
+
studyConsentAccepted,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
}, [termsAccepted, studyConsentAccepted, onConfirm]);
|
|
80
|
+
// Handle cancel
|
|
81
|
+
const handleCancel = useCallback(() => {
|
|
82
|
+
onCancel?.();
|
|
83
|
+
}, [onCancel]);
|
|
84
|
+
// Render checkbox - use custom renderer or fallback to native
|
|
85
|
+
const renderCheckboxElement = (id, checked, onCheckedChange) => {
|
|
86
|
+
if (renderCheckbox) {
|
|
87
|
+
return renderCheckbox({
|
|
88
|
+
id,
|
|
89
|
+
checked,
|
|
90
|
+
onCheckedChange,
|
|
91
|
+
className: "wq-legal-checkbox",
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
return (_jsx("input", { type: "checkbox", id: id, checked: checked, onChange: (e) => onCheckedChange(e.target.checked), className: "wq-legal-checkbox" }));
|
|
95
|
+
};
|
|
96
|
+
return (_jsxs("div", { className: `wq-legal-consent-form ${className}`, children: [_jsxs("div", { className: "wq-legal-consent-sections", children: [_jsxs("div", { className: "wq-legal-consent-section", children: [_jsx("h3", { className: "wq-legal-consent-heading", children: "1. Agree to T&Cs & Privacy Policy" }), _jsxs("div", { className: "wq-legal-consent-checkbox-row", children: [renderCheckboxElement("terms", termsAccepted, handleTermsChange), _jsxs("label", { htmlFor: "terms", className: "wq-legal-consent-label", children: ["I agree to the", " ", _jsx("a", { href: termsUrl, target: "_blank", rel: "noopener noreferrer", className: "wq-legal-consent-link", children: "Terms & Conditions" }), " ", "and", " ", _jsx("a", { href: privacyUrl, target: "_blank", rel: "noopener noreferrer", className: "wq-legal-consent-link", children: "Privacy Policy" }), "."] })] })] }), _jsxs("div", { className: "wq-legal-consent-section", children: [_jsx("h3", { className: "wq-legal-consent-heading", children: "2. Consent for study invitations / recruitment notifications (optional)" }), _jsx("p", { className: "wq-legal-consent-subtitle", children: "Receive study invitations (optional)" }), _jsx("p", { className: "wq-legal-consent-description", children: "If you opt in, you may be contacted about relevant studies. We will not share your contact or identity with a sponsor unless you explicitly accept a specific invitation." }), _jsxs("div", { className: "wq-legal-consent-info-box", children: [_jsx("p", { className: "wq-legal-consent-info-title", children: "What happens if I opt in?" }), _jsxs("ul", { className: "wq-legal-consent-info-list", children: [_jsx("li", { children: "You may receive emails/in-app messages about studies that match your profile." }), _jsx("li", { children: "If you click \"I'm interested\", we'll show you the details and ask for separate consent to share your contact or to pre-screen you \u2014 you control this per study." }), _jsx("li", { children: "You can opt out of invitations at any time." })] })] }), _jsxs("div", { className: "wq-legal-consent-checkbox-row", children: [renderCheckboxElement("study-consent", studyConsentAccepted, handleStudyConsentChange), _jsx("label", { htmlFor: "study-consent", className: "wq-legal-consent-label", children: "I consent to receive study invitations from Welshare. I can opt out anytime." })] })] })] }), _jsxs("div", { className: "wq-legal-consent-actions", children: [_jsx("button", { type: "button", className: "wq-button wq-button-outline", onClick: handleCancel, children: cancelButtonLabel }), _jsx("button", { type: "button", className: "wq-button wq-button-primary", onClick: handleConfirm, disabled: !termsAccepted, children: confirmButtonLabel })] })] }));
|
|
97
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { Attachment } from "../types/fhir.js";
|
|
2
|
+
export interface MediaAttachmentProps {
|
|
3
|
+
attachment: Attachment;
|
|
4
|
+
alt: string;
|
|
5
|
+
className?: string;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Renders a single media attachment (image) if it has a URL and is an image type
|
|
9
|
+
*/
|
|
10
|
+
export declare const MediaAttachment: ({ attachment, alt, className, }: MediaAttachmentProps) => import("react/jsx-runtime").JSX.Element | null;
|
|
11
|
+
export interface MediaAttachmentsProps {
|
|
12
|
+
attachments: Attachment[];
|
|
13
|
+
baseAlt?: string;
|
|
14
|
+
className?: string;
|
|
15
|
+
containerClassName?: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Renders multiple media attachments in a container
|
|
19
|
+
*/
|
|
20
|
+
export declare const MediaAttachments: ({ attachments, baseAlt, className, containerClassName, }: MediaAttachmentsProps) => import("react/jsx-runtime").JSX.Element | null;
|
|
21
|
+
//# sourceMappingURL=media-attachment.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"media-attachment.d.ts","sourceRoot":"","sources":["../../../src/components/media-attachment.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnD,MAAM,WAAW,oBAAoB;IACnC,UAAU,EAAE,UAAU,CAAC;IACvB,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,eAAO,MAAM,eAAe,GAAI,iCAI7B,oBAAoB,mDAkBtB,CAAC;AAEF,MAAM,WAAW,qBAAqB;IACpC,WAAW,EAAE,UAAU,EAAE,CAAC;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED;;GAEG;AACH,eAAO,MAAM,gBAAgB,GAAI,0DAK9B,qBAAqB,mDAevB,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* Renders a single media attachment (image) if it has a URL and is an image type
|
|
4
|
+
*/
|
|
5
|
+
export const MediaAttachment = ({ attachment, alt, className = "", }) => {
|
|
6
|
+
// Only render if URL exists
|
|
7
|
+
if (!attachment.url)
|
|
8
|
+
return null;
|
|
9
|
+
// Check if it's an image (or assume image if no contentType)
|
|
10
|
+
const isImage = !attachment.contentType || attachment.contentType.startsWith("image/");
|
|
11
|
+
if (!isImage)
|
|
12
|
+
return null;
|
|
13
|
+
return (_jsx("img", { src: attachment.url, alt: alt, className: className, title: attachment.title }));
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Renders multiple media attachments in a container
|
|
17
|
+
*/
|
|
18
|
+
export const MediaAttachments = ({ attachments, baseAlt = "Image", className = "", containerClassName = "", }) => {
|
|
19
|
+
if (attachments.length === 0)
|
|
20
|
+
return null;
|
|
21
|
+
return (_jsx("div", { className: containerClassName, children: attachments.map((attachment, index) => (_jsx(MediaAttachment, { attachment: attachment, alt: attachment.title || `${baseAlt} ${index + 1}`, className: className }, index))) }));
|
|
22
|
+
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"question-renderer.d.ts","sourceRoot":"","sources":["../../../src/components/question-renderer.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"question-renderer.d.ts","sourceRoot":"","sources":["../../../src/components/question-renderer.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAkB1D,OAAO,EACL,eAAe,EACf,kBAAkB,EAClB,kBAAkB,EACnB,MAAM,mBAAmB,CAAC;AAE3B,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,iBAAiB,CAAC;IACxB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,gBAAgB,CAAC,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,SAAS,CAAC;IACzD;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,mBAAmB,CAAC,EAAE,CAAC,KAAK,EAAE,kBAAkB,KAAK,SAAS,CAAC;IAC/D;;;OAGG;IACH,mBAAmB,CAAC,EAAE,CAAC,KAAK,EAAE,kBAAkB,KAAK,SAAS,CAAC;CAChE;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,gBAAgB,GAAI,eAAe,qBAAqB,4CAyBpE,CAAC"}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useQuestionnaire } from "../contexts/questionnaire-context.js";
|
|
3
|
-
import { isQuestionEnabled } from "../lib/questionnaire-utils.js";
|
|
4
|
-
import { FHIR_EXTENSIONS, WELSHARE_EXTENSIONS, FHIR_CODE_SYSTEMS } from "../lib/constants.js";
|
|
3
|
+
import { isQuestionEnabled, getItemMedia } from "../lib/questionnaire-utils.js";
|
|
4
|
+
import { FHIR_EXTENSIONS, WELSHARE_EXTENSIONS, FHIR_CODE_SYSTEMS, } from "../lib/constants.js";
|
|
5
5
|
import { DebugSection } from "./debug-section.js";
|
|
6
|
+
import { MediaAttachments } from "./media-attachment.js";
|
|
6
7
|
import { ChoiceQuestion } from "./questions/choice-question.js";
|
|
7
8
|
import { MultipleChoiceQuestion } from "./questions/multiple-choice-question.js";
|
|
8
9
|
import { IntegerQuestion } from "./questions/integer-question.js";
|
|
9
|
-
import { DecimalQuestion, getDecimalHelperTriggerProps } from "./questions/decimal-question.js";
|
|
10
|
+
import { DecimalQuestion, getDecimalHelperTriggerProps, } from "./questions/decimal-question.js";
|
|
10
11
|
import { StringQuestion } from "./questions/string-question.js";
|
|
11
12
|
import { BooleanQuestion } from "./questions/boolean-question.js";
|
|
12
13
|
/**
|
|
@@ -166,7 +167,9 @@ const QuestionRendererInternal = ({ item, className = "", inputClassName = "", c
|
|
|
166
167
|
const sliderConfig = getSliderConfig();
|
|
167
168
|
const renderQuestion = () => {
|
|
168
169
|
switch (item.type) {
|
|
170
|
+
// FHIR R4 uses 'choice', R5 uses 'coding' - both render the same way
|
|
169
171
|
case "choice":
|
|
172
|
+
case "coding":
|
|
170
173
|
// Multi-select with checkboxes when repeats is true
|
|
171
174
|
if (item.repeats) {
|
|
172
175
|
return (_jsx(MultipleChoiceQuestion, { item: item, currentAnswers: currentAnswers, onMultipleChoiceToggle: handleMultipleChoiceToggle, choiceClassName: choiceClassName, renderCheckboxInput: renderCheckboxInput }));
|
|
@@ -190,5 +193,7 @@ const QuestionRendererInternal = ({ item, className = "", inputClassName = "", c
|
|
|
190
193
|
const helperTriggerProps = item.type === "decimal"
|
|
191
194
|
? getDecimalHelperTriggerProps(item, currentAnswer, handleDecimalChange)
|
|
192
195
|
: null;
|
|
193
|
-
|
|
196
|
+
// Get media attachments for this question
|
|
197
|
+
const mediaAttachments = getItemMedia(item);
|
|
198
|
+
return (_jsxs("div", { className: `wq-question-container ${hasError ? "wq-has-error" : ""} ${className}`, children: [_jsx(MediaAttachments, { attachments: mediaAttachments, baseAlt: "Question image", className: "wq-question-image", containerClassName: "wq-question-media" }), _jsxs("div", { className: "wq-question-label-row", children: [_jsxs("div", { className: "wq-question-text", children: [item.text, item.required && _jsx("span", { className: "wq-required-indicator", children: "*" })] }), helperTriggerProps && renderHelperTrigger && (_jsx("div", { className: "wq-question-helper-trigger", children: renderHelperTrigger(helperTriggerProps) }))] }), renderQuestion()] }));
|
|
194
199
|
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { type ReactNode } from
|
|
2
|
-
import type { QuestionnaireItem, QuestionnaireResponseAnswer } from
|
|
3
|
-
import { RadioInputProps } from
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
import type { QuestionnaireItem, QuestionnaireResponseAnswer } from "../../types/fhir.js";
|
|
3
|
+
import { RadioInputProps } from "@/types/index.js";
|
|
4
4
|
export interface BooleanQuestionProps {
|
|
5
5
|
item: QuestionnaireItem;
|
|
6
6
|
currentAnswer?: QuestionnaireResponseAnswer;
|
|
@@ -11,5 +11,5 @@ export interface BooleanQuestionProps {
|
|
|
11
11
|
/**
|
|
12
12
|
* Renders a boolean question with Yes/No radio buttons
|
|
13
13
|
*/
|
|
14
|
-
export declare const BooleanQuestion: ({ item, currentAnswer, onBooleanChange, choiceClassName, renderRadioInput }: BooleanQuestionProps) => import("react/jsx-runtime").JSX.Element;
|
|
14
|
+
export declare const BooleanQuestion: ({ item, currentAnswer, onBooleanChange, choiceClassName, renderRadioInput, }: BooleanQuestionProps) => import("react/jsx-runtime").JSX.Element;
|
|
15
15
|
//# sourceMappingURL=boolean-question.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"boolean-question.d.ts","sourceRoot":"","sources":["../../../../src/components/questions/boolean-question.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"boolean-question.d.ts","sourceRoot":"","sources":["../../../../src/components/questions/boolean-question.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,KAAK,EACV,iBAAiB,EACjB,2BAA2B,EAC5B,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAEnD,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,iBAAiB,CAAC;IACxB,aAAa,CAAC,EAAE,2BAA2B,CAAC;IAC5C,eAAe,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IAC1C,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,gBAAgB,CAAC,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,SAAS,CAAC;CAC1D;AAED;;GAEG;AACH,eAAO,MAAM,eAAe,GAAI,8EAM7B,oBAAoB,4CAoDtB,CAAC"}
|
|
@@ -2,18 +2,18 @@ import { Fragment as _Fragment, jsxs as _jsxs, jsx as _jsx } from "react/jsx-run
|
|
|
2
2
|
/**
|
|
3
3
|
* Renders a boolean question with Yes/No radio buttons
|
|
4
4
|
*/
|
|
5
|
-
export const BooleanQuestion = ({ item, currentAnswer, onBooleanChange, choiceClassName =
|
|
5
|
+
export const BooleanQuestion = ({ item, currentAnswer, onBooleanChange, choiceClassName = "", renderRadioInput, }) => {
|
|
6
6
|
return (_jsx("div", { className: `wq-question-choice ${choiceClassName}`, children: renderRadioInput ? (_jsxs(_Fragment, { children: [renderRadioInput({
|
|
7
7
|
linkId: item.linkId,
|
|
8
8
|
checked: currentAnswer?.valueBoolean === true,
|
|
9
9
|
onChange: () => onBooleanChange(true),
|
|
10
|
-
label:
|
|
11
|
-
index: 0
|
|
10
|
+
label: "Yes",
|
|
11
|
+
index: 0,
|
|
12
12
|
}), renderRadioInput({
|
|
13
13
|
linkId: item.linkId,
|
|
14
14
|
checked: currentAnswer?.valueBoolean === false,
|
|
15
15
|
onChange: () => onBooleanChange(false),
|
|
16
|
-
label:
|
|
17
|
-
index: 1
|
|
18
|
-
})] })) : (_jsxs(_Fragment, { children: [_jsxs("label", { className: `wq-choice-option ${currentAnswer?.valueBoolean === true ?
|
|
16
|
+
label: "No",
|
|
17
|
+
index: 1,
|
|
18
|
+
})] })) : (_jsxs(_Fragment, { children: [_jsxs("label", { className: `wq-choice-option ${currentAnswer?.valueBoolean === true ? "wq-selected" : ""}`, children: [_jsx("input", { type: "radio", name: item.linkId, checked: currentAnswer?.valueBoolean === true, onChange: () => onBooleanChange(true), "data-wq-input": "radio", "data-wq-selected": currentAnswer?.valueBoolean === true }), _jsx("span", { className: "wq-choice-label", children: "Yes" })] }), _jsxs("label", { className: `wq-choice-option ${currentAnswer?.valueBoolean === false ? "wq-selected" : ""}`, children: [_jsx("input", { type: "radio", name: item.linkId, checked: currentAnswer?.valueBoolean === false, onChange: () => onBooleanChange(false), "data-wq-input": "radio", "data-wq-selected": currentAnswer?.valueBoolean === false }), _jsx("span", { className: "wq-choice-label", children: "No" })] })] })) }));
|
|
19
19
|
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { type ReactNode } from
|
|
2
|
-
import type { QuestionnaireItem, QuestionnaireResponseAnswer } from
|
|
3
|
-
import { RadioInputProps } from
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
import type { QuestionnaireItem, QuestionnaireResponseAnswer } from "../../types/fhir.js";
|
|
3
|
+
import { RadioInputProps } from "@/types/index.js";
|
|
4
4
|
export interface ChoiceQuestionProps {
|
|
5
5
|
item: QuestionnaireItem;
|
|
6
6
|
currentAnswer?: QuestionnaireResponseAnswer;
|
|
@@ -15,5 +15,5 @@ export interface ChoiceQuestionProps {
|
|
|
15
15
|
/**
|
|
16
16
|
* Renders a single-select choice question with radio buttons
|
|
17
17
|
*/
|
|
18
|
-
export declare const ChoiceQuestion: ({ item, currentAnswer, onChoiceChange, choiceClassName, renderRadioInput }: ChoiceQuestionProps) => import("react/jsx-runtime").JSX.Element;
|
|
18
|
+
export declare const ChoiceQuestion: ({ item, currentAnswer, onChoiceChange, choiceClassName, renderRadioInput, }: ChoiceQuestionProps) => import("react/jsx-runtime").JSX.Element;
|
|
19
19
|
//# sourceMappingURL=choice-question.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"choice-question.d.ts","sourceRoot":"","sources":["../../../../src/components/questions/choice-question.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"choice-question.d.ts","sourceRoot":"","sources":["../../../../src/components/questions/choice-question.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,KAAK,EACV,iBAAiB,EACjB,2BAA2B,EAC5B,MAAM,qBAAqB,CAAC;AAG7B,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAEnD,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,iBAAiB,CAAC;IACxB,aAAa,CAAC,EAAE,2BAA2B,CAAC;IAC5C,cAAc,EAAE,CACd,WAAW,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,EACjE,YAAY,CAAC,EAAE,MAAM,KAClB,IAAI,CAAC;IACV,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,gBAAgB,CAAC,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,SAAS,CAAC;CAC1D;AAED;;GAEG;AACH,eAAO,MAAM,cAAc,GAAI,6EAM5B,mBAAmB,4CA4ErB,CAAC"}
|
|
@@ -1,23 +1,31 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { getAnswerOptionMedia } from "../../lib/questionnaire-utils.js";
|
|
3
|
+
import { MediaAttachment } from "../media-attachment.js";
|
|
2
4
|
/**
|
|
3
5
|
* Renders a single-select choice question with radio buttons
|
|
4
6
|
*/
|
|
5
|
-
export const ChoiceQuestion = ({ item, currentAnswer, onChoiceChange, choiceClassName =
|
|
7
|
+
export const ChoiceQuestion = ({ item, currentAnswer, onChoiceChange, choiceClassName = "", renderRadioInput, }) => {
|
|
6
8
|
return (_jsx("div", { className: `wq-question-choice ${choiceClassName}`, children: item.answerOption?.map((option, index) => {
|
|
7
9
|
const isSelected = currentAnswer?.valueCoding?.code === option.valueCoding?.code;
|
|
10
|
+
// Get media attachment for this answer option
|
|
11
|
+
const mediaAttachment = getAnswerOptionMedia(option);
|
|
8
12
|
// Use custom renderer if provided
|
|
9
13
|
if (renderRadioInput) {
|
|
10
|
-
return (
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
14
|
+
return (_jsxs("div", { className: "wq-choice-option-wrapper", children: [mediaAttachment && (_jsx(MediaAttachment, { attachment: mediaAttachment, alt: mediaAttachment.title ||
|
|
15
|
+
option.valueCoding?.display ||
|
|
16
|
+
`Option ${index + 1}`, className: "wq-choice-option-image" })), renderRadioInput({
|
|
17
|
+
linkId: item.linkId,
|
|
18
|
+
valueCoding: option.valueCoding,
|
|
19
|
+
valueInteger: option.valueInteger,
|
|
20
|
+
checked: isSelected,
|
|
21
|
+
onChange: () => onChoiceChange(option.valueCoding || {}, option.valueInteger),
|
|
22
|
+
label: option.valueCoding?.display || "",
|
|
23
|
+
index,
|
|
24
|
+
})] }, index));
|
|
19
25
|
}
|
|
20
26
|
// Default rendering
|
|
21
|
-
return (_jsxs("
|
|
27
|
+
return (_jsxs("div", { className: "wq-choice-option-wrapper", children: [mediaAttachment && (_jsx(MediaAttachment, { attachment: mediaAttachment, alt: mediaAttachment.title ||
|
|
28
|
+
option.valueCoding?.display ||
|
|
29
|
+
`Option ${index + 1}`, className: "wq-choice-option-image" })), _jsxs("label", { className: `wq-choice-option ${isSelected ? "wq-selected" : ""}`, children: [_jsx("input", { type: "radio", name: item.linkId, value: option.valueCoding?.code, checked: isSelected, onChange: () => onChoiceChange(option.valueCoding || {}, option.valueInteger), "data-wq-input": "radio", "data-wq-selected": isSelected }), _jsx("span", { className: "wq-choice-label", children: option.valueCoding?.display })] })] }, index));
|
|
22
30
|
}) }));
|
|
23
31
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"multiple-choice-question.d.ts","sourceRoot":"","sources":["../../../../src/components/questions/multiple-choice-question.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,KAAK,EACV,iBAAiB,EACjB,2BAA2B,EAC5B,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"multiple-choice-question.d.ts","sourceRoot":"","sources":["../../../../src/components/questions/multiple-choice-question.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,KAAK,EACV,iBAAiB,EACjB,2BAA2B,EAC5B,MAAM,qBAAqB,CAAC;AAI7B,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAE1D,MAAM,WAAW,2BAA2B;IAC1C,IAAI,EAAE,iBAAiB,CAAC;IACxB,cAAc,EAAE,2BAA2B,EAAE,CAAC;IAC9C,sBAAsB,EAAE,CACtB,WAAW,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,EACjE,YAAY,CAAC,EAAE,MAAM,KAClB,IAAI,CAAC;IACV,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,mBAAmB,CAAC,EAAE,CAAC,KAAK,EAAE,kBAAkB,KAAK,SAAS,CAAC;CAChE;AAED;;;GAGG;AACH,eAAO,MAAM,sBAAsB,GAAI,yFAMpC,2BAA2B,4CAkH7B,CAAC"}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { WELSHARE_EXTENSIONS } from "../../lib/constants.js";
|
|
3
|
+
import { getAnswerOptionMedia } from "../../lib/questionnaire-utils.js";
|
|
4
|
+
import { MediaAttachment } from "../media-attachment.js";
|
|
3
5
|
/**
|
|
4
6
|
* Renders a multi-select choice question with checkboxes
|
|
5
7
|
* Supports exclusive options and maxAnswers limits
|
|
@@ -20,20 +22,26 @@ export const MultipleChoiceQuestion = ({ item, currentAnswers, onMultipleChoiceT
|
|
|
20
22
|
return (_jsxs("div", { className: `wq-question-choice ${choiceClassName}`, children: [optionsToShow?.map((option, index) => {
|
|
21
23
|
const isSelected = currentAnswers.some((answer) => answer.valueCoding?.code === option.valueCoding?.code);
|
|
22
24
|
const isDisabled = !isSelected && atMaxAnswers;
|
|
25
|
+
// Get media attachment for this answer option
|
|
26
|
+
const mediaAttachment = getAnswerOptionMedia(option);
|
|
23
27
|
// Use custom renderer if provided
|
|
24
28
|
if (renderCheckboxInput) {
|
|
25
|
-
return (
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
29
|
+
return (_jsxs("div", { className: "wq-choice-option-wrapper", children: [mediaAttachment && (_jsx(MediaAttachment, { attachment: mediaAttachment, alt: mediaAttachment.title ||
|
|
30
|
+
option.valueCoding?.display ||
|
|
31
|
+
`Option ${index + 1}`, className: "wq-choice-option-image" })), renderCheckboxInput({
|
|
32
|
+
linkId: item.linkId,
|
|
33
|
+
valueCoding: option.valueCoding,
|
|
34
|
+
valueInteger: option.valueInteger,
|
|
35
|
+
checked: isSelected,
|
|
36
|
+
disabled: isDisabled,
|
|
37
|
+
onChange: () => onMultipleChoiceToggle(option.valueCoding || {}, option.valueInteger),
|
|
38
|
+
label: option.valueCoding?.display || "",
|
|
39
|
+
index,
|
|
40
|
+
})] }, index));
|
|
35
41
|
}
|
|
36
42
|
// Default rendering
|
|
37
|
-
return (_jsxs("
|
|
43
|
+
return (_jsxs("div", { className: "wq-choice-option-wrapper", children: [mediaAttachment && (_jsx(MediaAttachment, { attachment: mediaAttachment, alt: mediaAttachment.title ||
|
|
44
|
+
option.valueCoding?.display ||
|
|
45
|
+
`Option ${index + 1}`, className: "wq-choice-option-image" })), _jsxs("label", { className: `wq-choice-option ${isSelected ? "wq-selected" : ""} ${isDisabled ? "wq-disabled" : ""}`, children: [_jsx("input", { type: "checkbox", name: item.linkId, value: option.valueCoding?.code, checked: isSelected, disabled: isDisabled, onChange: () => onMultipleChoiceToggle(option.valueCoding || {}, option.valueInteger), "data-wq-input": "checkbox", "data-wq-selected": isSelected }), _jsx("span", { className: "wq-choice-label", children: option.valueCoding?.display })] })] }, index));
|
|
38
46
|
}), item.maxAnswers && (_jsxs("div", { className: "wq-max-answers-hint", children: ["Selected: ", currentAnswers.length, " / ", item.maxAnswers] }))] }));
|
|
39
47
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"questionnaire-context.d.ts","sourceRoot":"","sources":["../../../src/contexts/questionnaire-context.tsx"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AACf,OAAO,KAAK,EACV,aAAa,EACb,iBAAiB,EACjB,qBAAqB,EACrB,2BAA2B,EAE5B,MAAM,kBAAkB,CAAC;AAM1B,MAAM,WAAW,wBAAwB;IACvC,aAAa,EAAE,aAAa,CAAC;IAC7B,QAAQ,EAAE,qBAAqB,CAAC;IAChC,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,2BAA2B,KAAK,IAAI,CAAC;IAC5E,qBAAqB,EAAE,CACrB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,2BAA2B,EAAE,KACnC,IAAI,CAAC;IACV,SAAS,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,2BAA2B,GAAG,SAAS,CAAC;IACvE,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,2BAA2B,EAAE,CAAC;IAC9D,WAAW,EAAE,CAAC,SAAS,EAAE,iBAAiB,EAAE,KAAK,OAAO,CAAC;IACzD,oBAAoB,EAAE,CAAC,SAAS,EAAE,iBAAiB,EAAE,KAAK,iBAAiB,EAAE,CAAC;IAC9E,8BAA8B,EAAE,CAC9B,SAAS,EAAE,iBAAiB,EAAE,KAC3B,iBAAiB,EAAE,CAAC;IACzB,oBAAoB,EAAE,CAAC,SAAS,EAAE,iBAAiB,EAAE,KAAK,IAAI,CAAC;IAC/D,qBAAqB,EAAE,MAAM,IAAI,CAAC;IAClC,kBAAkB,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC;IAChD,SAAS,EAAE,OAAO,CAAC;IACnB,eAAe,EAAE,MAAM,IAAI,CAAC;CAC7B;AAMD,eAAO,MAAM,gBAAgB,gCAQ5B,CAAC;AAEF,MAAM,WAAW,0BAA0B;IACzC,QAAQ,EAAE,SAAS,CAAC;IACpB;;;OAGG;IACH,aAAa,EAAE,aAAa,CAAC;IAC7B;;;;OAIG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B;AAED,eAAO,MAAM,qBAAqB,GAAI,mEAKnC,0BAA0B,
|
|
1
|
+
{"version":3,"file":"questionnaire-context.d.ts","sourceRoot":"","sources":["../../../src/contexts/questionnaire-context.tsx"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AACf,OAAO,KAAK,EACV,aAAa,EACb,iBAAiB,EACjB,qBAAqB,EACrB,2BAA2B,EAE5B,MAAM,kBAAkB,CAAC;AAM1B,MAAM,WAAW,wBAAwB;IACvC,aAAa,EAAE,aAAa,CAAC;IAC7B,QAAQ,EAAE,qBAAqB,CAAC;IAChC,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,2BAA2B,KAAK,IAAI,CAAC;IAC5E,qBAAqB,EAAE,CACrB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,2BAA2B,EAAE,KACnC,IAAI,CAAC;IACV,SAAS,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,2BAA2B,GAAG,SAAS,CAAC;IACvE,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,2BAA2B,EAAE,CAAC;IAC9D,WAAW,EAAE,CAAC,SAAS,EAAE,iBAAiB,EAAE,KAAK,OAAO,CAAC;IACzD,oBAAoB,EAAE,CAAC,SAAS,EAAE,iBAAiB,EAAE,KAAK,iBAAiB,EAAE,CAAC;IAC9E,8BAA8B,EAAE,CAC9B,SAAS,EAAE,iBAAiB,EAAE,KAC3B,iBAAiB,EAAE,CAAC;IACzB,oBAAoB,EAAE,CAAC,SAAS,EAAE,iBAAiB,EAAE,KAAK,IAAI,CAAC;IAC/D,qBAAqB,EAAE,MAAM,IAAI,CAAC;IAClC,kBAAkB,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC;IAChD,SAAS,EAAE,OAAO,CAAC;IACnB,eAAe,EAAE,MAAM,IAAI,CAAC;CAC7B;AAMD,eAAO,MAAM,gBAAgB,gCAQ5B,CAAC;AAEF,MAAM,WAAW,0BAA0B;IACzC,QAAQ,EAAE,SAAS,CAAC;IACpB;;;OAGG;IACH,aAAa,EAAE,aAAa,CAAC;IAC7B;;;;OAIG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B;AAED,eAAO,MAAM,qBAAqB,GAAI,mEAKnC,0BAA0B,4CAuZ5B,CAAC"}
|
|
@@ -91,10 +91,7 @@ export const QuestionnaireProvider = ({ children, questionnaire, questionnaireId
|
|
|
91
91
|
}
|
|
92
92
|
// If this item has nested items, search within them
|
|
93
93
|
if (item.item && item.item.length > 0) {
|
|
94
|
-
return {
|
|
95
|
-
...item,
|
|
96
|
-
item: updateNestedItem(item.item),
|
|
97
|
-
};
|
|
94
|
+
return { ...item, item: updateNestedItem(item.item) };
|
|
98
95
|
}
|
|
99
96
|
return item;
|
|
100
97
|
});
|
|
@@ -122,13 +119,7 @@ export const QuestionnaireProvider = ({ children, questionnaire, questionnaireId
|
|
|
122
119
|
}
|
|
123
120
|
else {
|
|
124
121
|
// Create new item
|
|
125
|
-
return [
|
|
126
|
-
...items,
|
|
127
|
-
{
|
|
128
|
-
linkId,
|
|
129
|
-
answer: [answer],
|
|
130
|
-
},
|
|
131
|
-
];
|
|
122
|
+
return [...items, { linkId, answer: [answer] }];
|
|
132
123
|
}
|
|
133
124
|
};
|
|
134
125
|
newResponse.item = findOrCreateItem(newResponse.item);
|
|
@@ -161,10 +152,7 @@ export const QuestionnaireProvider = ({ children, questionnaire, questionnaireId
|
|
|
161
152
|
}
|
|
162
153
|
// If this item has nested items, search within them
|
|
163
154
|
if (item.item && item.item.length > 0) {
|
|
164
|
-
return {
|
|
165
|
-
...item,
|
|
166
|
-
item: updateNestedItem(item.item),
|
|
167
|
-
};
|
|
155
|
+
return { ...item, item: updateNestedItem(item.item) };
|
|
168
156
|
}
|
|
169
157
|
return item;
|
|
170
158
|
});
|
|
@@ -190,13 +178,7 @@ export const QuestionnaireProvider = ({ children, questionnaire, questionnaireId
|
|
|
190
178
|
return updated;
|
|
191
179
|
}
|
|
192
180
|
else {
|
|
193
|
-
return [
|
|
194
|
-
...items,
|
|
195
|
-
{
|
|
196
|
-
linkId,
|
|
197
|
-
answer: answers,
|
|
198
|
-
},
|
|
199
|
-
];
|
|
181
|
+
return [...items, { linkId, answer: answers }];
|
|
200
182
|
}
|
|
201
183
|
};
|
|
202
184
|
newResponse.item = findOrCreateItem(newResponse.item);
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -2,10 +2,12 @@ export { QuestionRenderer } from "./components/question-renderer.js";
|
|
|
2
2
|
export type { QuestionRendererProps } from "./components/question-renderer.js";
|
|
3
3
|
export { BmiForm } from "./components/bmi-form.js";
|
|
4
4
|
export type { BmiFormProps } from "./components/bmi-form.js";
|
|
5
|
+
export { LegalConsentForm } from "./components/legal-consent-form.js";
|
|
6
|
+
export type { LegalConsentFormProps, LegalConsentResult, LegalCheckboxProps, LegalDocumentLinks, } from "./components/legal-consent-form.js";
|
|
5
7
|
export { QuestionnaireProvider, useQuestionnaire, type QuestionnaireContextType, type QuestionnaireProviderProps, } from "./contexts/questionnaire-context.js";
|
|
6
|
-
export type { Coding, Extension, Questionnaire, QuestionnaireItem, QuestionnaireItemAnswerOption, QuestionnaireResponse, QuestionnaireResponseAnswer, QuestionnaireResponseItem, } from "./types/fhir.js";
|
|
8
|
+
export type { Attachment, Coding, Extension, Questionnaire, QuestionnaireItem, QuestionnaireItemAnswerOption, QuestionnaireResponse, QuestionnaireResponseAnswer, QuestionnaireResponseItem, } from "./types/fhir.js";
|
|
7
9
|
export type { RadioInputProps, CheckboxInputProps, InputHelperConfig, HelperTriggerProps, } from "./types/index.js";
|
|
8
|
-
export { calculateProgress, findQuestionnaireItem, getAllQuestionsFromPage, getExclusiveOptionCode, getInputHelper, getVisiblePages, hasAnswerValue, isQuestionHidden, } from "./lib/questionnaire-utils.js";
|
|
10
|
+
export { calculateProgress, findQuestionnaireItem, getAllQuestionsFromPage, getAnswerOptionMedia, getExclusiveOptionCode, getInputHelper, getItemMedia, getVisiblePages, hasAnswerValue, isQuestionHidden, } from "./lib/questionnaire-utils.js";
|
|
9
11
|
export { calculateBmi } from "./lib/bmi-helpers.js";
|
|
10
12
|
export { FHIR_EXTENSIONS, WELSHARE_EXTENSIONS, WELSHARE_CODE_SYSTEMS, FHIR_CODE_SYSTEMS, } from "./lib/constants.js";
|
|
11
13
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/esm/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AACrE,YAAY,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AACrE,YAAY,EAAE,qBAAqB,EAAE,MAAM,mCAAmC,CAAC;AAE/E,OAAO,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAC;AACnD,YAAY,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAE7D,OAAO,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AACtE,YAAY,EACV,qBAAqB,EACrB,kBAAkB,EAClB,kBAAkB,EAClB,kBAAkB,GACnB,MAAM,oCAAoC,CAAC;AAG5C,OAAO,EACL,qBAAqB,EACrB,gBAAgB,EAChB,KAAK,wBAAwB,EAC7B,KAAK,0BAA0B,GAChC,MAAM,qCAAqC,CAAC;AAG7C,YAAY,EACV,UAAU,EACV,MAAM,EACN,SAAS,EACT,aAAa,EACb,iBAAiB,EACjB,6BAA6B,EAC7B,qBAAqB,EACrB,2BAA2B,EAC3B,yBAAyB,GAC1B,MAAM,iBAAiB,CAAC;AAEzB,YAAY,EACV,eAAe,EACf,kBAAkB,EAClB,iBAAiB,EACjB,kBAAkB,GACnB,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EACL,iBAAiB,EACjB,qBAAqB,EACrB,uBAAuB,EACvB,oBAAoB,EACpB,sBAAsB,EACtB,cAAc,EACd,YAAY,EACZ,eAAe,EACf,cAAc,EACd,gBAAgB,GACjB,MAAM,8BAA8B,CAAC;AAEtC,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAGpD,OAAO,EACL,eAAe,EACf,mBAAmB,EACnB,qBAAqB,EACrB,iBAAiB,GAClB,MAAM,oBAAoB,CAAC"}
|
package/dist/esm/index.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
// Components
|
|
2
2
|
export { QuestionRenderer } from "./components/question-renderer.js";
|
|
3
3
|
export { BmiForm } from "./components/bmi-form.js";
|
|
4
|
+
export { LegalConsentForm } from "./components/legal-consent-form.js";
|
|
4
5
|
// Contexts
|
|
5
6
|
export { QuestionnaireProvider, useQuestionnaire, } from "./contexts/questionnaire-context.js";
|
|
6
7
|
// Utils
|
|
7
|
-
export { calculateProgress, findQuestionnaireItem, getAllQuestionsFromPage, getExclusiveOptionCode, getInputHelper, getVisiblePages, hasAnswerValue, isQuestionHidden, } from "./lib/questionnaire-utils.js";
|
|
8
|
+
export { calculateProgress, findQuestionnaireItem, getAllQuestionsFromPage, getAnswerOptionMedia, getExclusiveOptionCode, getInputHelper, getItemMedia, getVisiblePages, hasAnswerValue, isQuestionHidden, } from "./lib/questionnaire-utils.js";
|
|
8
9
|
export { calculateBmi } from "./lib/bmi-helpers.js";
|
|
9
10
|
// Constants
|
|
10
11
|
export { FHIR_EXTENSIONS, WELSHARE_EXTENSIONS, WELSHARE_CODE_SYSTEMS, FHIR_CODE_SYSTEMS, } from "./lib/constants.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bmi-helpers.d.ts","sourceRoot":"","sources":["../../../src/lib/bmi-helpers.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;GAEG;AACH,eAAO,MAAM,WAAW,OAAO,CAAC;AAChC,eAAO,MAAM,eAAe,KAAK,CAAC;AAClC,eAAO,MAAM,SAAS,aAAa,CAAC;AAEpC;;GAEG;AACH,wBAAgB,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAE7C;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEjD;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAGtE;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,MAAM,GAAG;
|
|
1
|
+
{"version":3,"file":"bmi-helpers.d.ts","sourceRoot":"","sources":["../../../src/lib/bmi-helpers.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;GAEG;AACH,eAAO,MAAM,WAAW,OAAO,CAAC;AAChC,eAAO,MAAM,eAAe,KAAK,CAAC;AAClC,eAAO,MAAM,SAAS,aAAa,CAAC;AAEpC;;GAEG;AACH,wBAAgB,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAE7C;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEjD;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAGtE;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,MAAM,GAAG;IAC7C,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB,CAKA;AAED;;GAEG;AACH,wBAAgB,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAE1C;AAED;;GAEG;AACH,wBAAgB,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE3C;AAED;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAOvE"}
|
|
@@ -9,6 +9,18 @@ export declare const FHIR_EXTENSIONS: {
|
|
|
9
9
|
* @see http://hl7.org/fhir/StructureDefinition/questionnaire-hidden
|
|
10
10
|
*/
|
|
11
11
|
readonly QUESTIONNAIRE_HIDDEN: "http://hl7.org/fhir/StructureDefinition/questionnaire-hidden";
|
|
12
|
+
/**
|
|
13
|
+
* SDC extension for attaching media (images, audio, video) to questionnaire items
|
|
14
|
+
* Type: Attachment with contentType, url, title, etc.
|
|
15
|
+
* @see http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-itemMedia
|
|
16
|
+
*/
|
|
17
|
+
readonly ITEM_MEDIA: "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-itemMedia";
|
|
18
|
+
/**
|
|
19
|
+
* SDC extension for attaching media to specific answer options
|
|
20
|
+
* Type: Attachment with contentType, url, title, etc.
|
|
21
|
+
* @see http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-itemAnswerMedia
|
|
22
|
+
*/
|
|
23
|
+
readonly ITEM_ANSWER_MEDIA: "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-itemAnswerMedia";
|
|
12
24
|
};
|
|
13
25
|
/**
|
|
14
26
|
* Welshare Custom Extension URLs
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../src/lib/constants.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,eAAO,MAAM,eAAe;IAC1B;;;;OAIG;;
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../src/lib/constants.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,eAAO,MAAM,eAAe;IAC1B;;;;OAIG;;IAIH;;;;OAIG;;IAIH;;;;OAIG;;CAGK,CAAC;AAEX;;;;GAIG;AACH,eAAO,MAAM,mBAAmB;IAC9B;;;;;;;;;;;OAWG;;IAIH;;;;;;;;;;;;;;;;;OAiBG;;IAIH;;;;;;;;;;;;;;;;OAgBG;;CAGK,CAAC;AAEX;;;GAGG;AACH,eAAO,MAAM,qBAAqB;IAChC;;;;OAIG;;CAEK,CAAC;AAEX;;;GAGG;AACH,eAAO,MAAM,iBAAiB;IAC5B;;;;OAIG;;CAEK,CAAC"}
|
|
@@ -9,6 +9,18 @@ export const FHIR_EXTENSIONS = {
|
|
|
9
9
|
* @see http://hl7.org/fhir/StructureDefinition/questionnaire-hidden
|
|
10
10
|
*/
|
|
11
11
|
QUESTIONNAIRE_HIDDEN: "http://hl7.org/fhir/StructureDefinition/questionnaire-hidden",
|
|
12
|
+
/**
|
|
13
|
+
* SDC extension for attaching media (images, audio, video) to questionnaire items
|
|
14
|
+
* Type: Attachment with contentType, url, title, etc.
|
|
15
|
+
* @see http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-itemMedia
|
|
16
|
+
*/
|
|
17
|
+
ITEM_MEDIA: "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-itemMedia",
|
|
18
|
+
/**
|
|
19
|
+
* SDC extension for attaching media to specific answer options
|
|
20
|
+
* Type: Attachment with contentType, url, title, etc.
|
|
21
|
+
* @see http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-itemAnswerMedia
|
|
22
|
+
*/
|
|
23
|
+
ITEM_ANSWER_MEDIA: "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-itemAnswerMedia",
|
|
12
24
|
};
|
|
13
25
|
/**
|
|
14
26
|
* Welshare Custom Extension URLs
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Questionnaire, QuestionnaireItem, QuestionnaireResponseAnswer } from "../types/fhir.js";
|
|
1
|
+
import type { Questionnaire, QuestionnaireItem, QuestionnaireResponseAnswer, QuestionnaireItemAnswerOption, Attachment } from "../types/fhir.js";
|
|
2
2
|
/**
|
|
3
3
|
* Get visible pages from a questionnaire (excludes hidden groups)
|
|
4
4
|
*/
|
|
@@ -50,4 +50,18 @@ export declare const getInputHelper: (item: QuestionnaireItem) => InputHelperCon
|
|
|
50
50
|
* @returns true if the question should be enabled, false otherwise
|
|
51
51
|
*/
|
|
52
52
|
export declare const isQuestionEnabled: (item: QuestionnaireItem, getAnswer: (linkId: string) => QuestionnaireResponseAnswer | undefined) => boolean;
|
|
53
|
+
/**
|
|
54
|
+
* Extract media attachments from a questionnaire item's extensions
|
|
55
|
+
* Returns all itemMedia extensions as an array of Attachments
|
|
56
|
+
* @param item The questionnaire item to extract media from
|
|
57
|
+
* @returns Array of Attachment objects (can be empty if no media found)
|
|
58
|
+
*/
|
|
59
|
+
export declare const getItemMedia: (item: QuestionnaireItem) => Attachment[];
|
|
60
|
+
/**
|
|
61
|
+
* Extract media attachment from an answer option's extensions
|
|
62
|
+
* Returns the first itemAnswerMedia extension found
|
|
63
|
+
* @param option The answer option to extract media from
|
|
64
|
+
* @returns Attachment object or undefined if no media found
|
|
65
|
+
*/
|
|
66
|
+
export declare const getAnswerOptionMedia: (option: QuestionnaireItemAnswerOption) => Attachment | undefined;
|
|
53
67
|
//# sourceMappingURL=questionnaire-utils.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"questionnaire-utils.d.ts","sourceRoot":"","sources":["../../../src/lib/questionnaire-utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,aAAa,EACb,iBAAiB,EACjB,2BAA2B,
|
|
1
|
+
{"version":3,"file":"questionnaire-utils.d.ts","sourceRoot":"","sources":["../../../src/lib/questionnaire-utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,aAAa,EACb,iBAAiB,EACjB,2BAA2B,EAC3B,6BAA6B,EAC7B,UAAU,EACX,MAAM,kBAAkB,CAAC;AAG1B;;GAEG;AACH,eAAO,MAAM,eAAe,GAC1B,eAAe,aAAa,KAC3B,iBAAiB,EAcnB,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,GAC5B,kBAAkB,MAAM,EACxB,YAAY,MAAM,KACjB,MAGF,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,uBAAuB,GAClC,UAAU,iBAAiB,KAC1B,iBAAiB,EAsBnB,CAAC;AAEF;;GAEG;AACH,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,iBAAiB,EAAE,GAAG,SAAS,EACtC,MAAM,EAAE,MAAM,GACb,iBAAiB,GAAG,IAAI,CAe1B;AAED;;GAEG;AACH,eAAO,MAAM,cAAc,GAAI,QAAQ,GAAG,KAAG,OAe5C,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,gBAAgB,GAAI,MAAM,iBAAiB,KAAG,OAQ1D,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,sBAAsB,GACjC,MAAM,iBAAiB,KACtB,MAAM,GAAG,SAKX,CAAC;AAEF;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;GAGG;AACH,eAAO,MAAM,cAAc,GACzB,MAAM,iBAAiB,KACtB,iBAAiB,GAAG,IAatB,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,GAC5B,MAAM,iBAAiB,EACvB,WAAW,CAAC,MAAM,EAAE,MAAM,KAAK,2BAA2B,GAAG,SAAS,KACrE,OAkEF,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,YAAY,GAAI,MAAM,iBAAiB,KAAG,UAAU,EAOhE,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,GAC/B,QAAQ,6BAA6B,KACpC,UAAU,GAAG,SAQf,CAAC"}
|
|
@@ -178,3 +178,29 @@ export const isQuestionEnabled = (item, getAnswer) => {
|
|
|
178
178
|
}
|
|
179
179
|
return false;
|
|
180
180
|
};
|
|
181
|
+
/**
|
|
182
|
+
* Extract media attachments from a questionnaire item's extensions
|
|
183
|
+
* Returns all itemMedia extensions as an array of Attachments
|
|
184
|
+
* @param item The questionnaire item to extract media from
|
|
185
|
+
* @returns Array of Attachment objects (can be empty if no media found)
|
|
186
|
+
*/
|
|
187
|
+
export const getItemMedia = (item) => {
|
|
188
|
+
if (!item.extension)
|
|
189
|
+
return [];
|
|
190
|
+
return item.extension
|
|
191
|
+
.filter((ext) => ext.url === FHIR_EXTENSIONS.ITEM_MEDIA)
|
|
192
|
+
.map((ext) => ext.valueAttachment)
|
|
193
|
+
.filter((attachment) => attachment !== undefined);
|
|
194
|
+
};
|
|
195
|
+
/**
|
|
196
|
+
* Extract media attachment from an answer option's extensions
|
|
197
|
+
* Returns the first itemAnswerMedia extension found
|
|
198
|
+
* @param option The answer option to extract media from
|
|
199
|
+
* @returns Attachment object or undefined if no media found
|
|
200
|
+
*/
|
|
201
|
+
export const getAnswerOptionMedia = (option) => {
|
|
202
|
+
if (!option.extension)
|
|
203
|
+
return undefined;
|
|
204
|
+
const mediaExt = option.extension.find((ext) => ext.url === FHIR_EXTENSIONS.ITEM_ANSWER_MEDIA);
|
|
205
|
+
return mediaExt?.valueAttachment;
|
|
206
|
+
};
|