diff --git a/aidbox-forms-smart-launch-2/src/app/(authorized)/questionnaires/[id]/page.tsx b/aidbox-forms-smart-launch-2/src/app/(authorized)/questionnaires/[id]/page.tsx new file mode 100644 index 0000000..5963759 --- /dev/null +++ b/aidbox-forms-smart-launch-2/src/app/(authorized)/questionnaires/[id]/page.tsx @@ -0,0 +1,46 @@ +import { getCurrentAidbox } from "@/lib/server/smart"; +import { PageHeader } from "@/components/page-header"; +import { Questionnaire } from "fhir/r4"; +import { QuestionnaireEditor } from "@/components/questionnaire-editor"; + +interface PageProps { + params: Promise<{ + id: string; + }>; +} + +export default async function QuestionnairesPage({ params }: PageProps) { + const aidbox = await getCurrentAidbox(); + const { id } = await params; + + const questionnaire = await aidbox + .get(`fhir/Questionnaire/${id}`, {}) + .json(); + + async function saveQuestionnaire(questionnaire: Questionnaire) { + "use server"; + + const aidbox = await getCurrentAidbox(); + return aidbox + .put(`fhir/Questionnaire/${id}`, { + json: questionnaire, + }) + .json(); + } + + return ( + <> + + + + ); +} diff --git a/aidbox-forms-smart-launch-2/src/components/forms-builder.tsx b/aidbox-forms-smart-launch-2/src/components/forms-builder.tsx new file mode 100644 index 0000000..5237c22 --- /dev/null +++ b/aidbox-forms-smart-launch-2/src/components/forms-builder.tsx @@ -0,0 +1,57 @@ +"use client"; + +import { useEffect, useRef } from "react"; +import { useAwaiter } from "@/hooks/use-awaiter"; +import { Questionnaire } from "fhir/r4"; + +export function FormsBuilder({ + questionnaire, + onChange, +}: { + questionnaire: Questionnaire; + onChange?: (questionnaire: Questionnaire) => void; +}) { + const ref = useRef(null); + + useEffect(() => { + const current = ref.current; + + if (current) { + const handler = (e: Event) => { + onChange?.((e as CustomEvent).detail); + }; + + current.addEventListener("change", handler); + + return () => { + current.removeEventListener("change", handler); + }; + } + }, [onChange]); + + useAwaiter(ref); + + return ( + + ); +} diff --git a/aidbox-forms-smart-launch-2/src/components/forms-renderer.tsx b/aidbox-forms-smart-launch-2/src/components/forms-renderer.tsx index c341615..3df0e9c 100644 --- a/aidbox-forms-smart-launch-2/src/components/forms-renderer.tsx +++ b/aidbox-forms-smart-launch-2/src/components/forms-renderer.tsx @@ -1,13 +1,13 @@ import { useEffect, useRef } from "react"; import { useAwaiter } from "@/hooks/use-awaiter"; -import { Questionnaire } from "fhir/r4"; +import { Questionnaire, QuestionnaireResponse } from "fhir/r4"; export function FormsRenderer({ questionnaire, onChange, }: { questionnaire: Questionnaire; - onChange?: (questionnaire: Questionnaire) => void; + onChange?: (questionnaireResponse: QuestionnaireResponse) => void; }) { const ref = useRef(null); @@ -16,7 +16,7 @@ export function FormsRenderer({ if (current) { const handler = (e: Event) => { - onChange?.((e as CustomEvent).detail); + onChange?.((e as CustomEvent).detail); }; current.addEventListener("change", handler); diff --git a/aidbox-forms-smart-launch-2/src/components/questionnaire-editor.tsx b/aidbox-forms-smart-launch-2/src/components/questionnaire-editor.tsx new file mode 100644 index 0000000..6149f2f --- /dev/null +++ b/aidbox-forms-smart-launch-2/src/components/questionnaire-editor.tsx @@ -0,0 +1,35 @@ +"use client"; + +import { FormsBuilder } from "@/components/forms-builder"; +import { Questionnaire } from "fhir/r4"; +import { Suspense, useTransition } from "react"; +import { Spinner } from "@/components/spinner"; + +interface QuestionnaireEditorProps { + questionnaire: Questionnaire; + onSaveAction: (questionnaire: Questionnaire) => Promise; +} + +export function QuestionnaireEditor({ + questionnaire, + onSaveAction, +}: QuestionnaireEditorProps) { + const [, startTransition] = useTransition(); + + return ( + }> + { + startTransition(async () => { + try { + await onSaveAction(updatedQuestionnaire); + } catch (error) { + console.error("Failed to save questionnaire:", error); + } + }); + }} + /> + + ); +} diff --git a/aidbox-forms-smart-launch-2/src/components/questionnaires-actions.tsx b/aidbox-forms-smart-launch-2/src/components/questionnaires-actions.tsx index e750736..33eea9d 100644 --- a/aidbox-forms-smart-launch-2/src/components/questionnaires-actions.tsx +++ b/aidbox-forms-smart-launch-2/src/components/questionnaires-actions.tsx @@ -108,7 +108,7 @@ export function QuestionnairesActions({ Preview {viewing && ( - }> + }> { diff --git a/aidbox-forms-smart-launch-2/src/components/spinner.tsx b/aidbox-forms-smart-launch-2/src/components/spinner.tsx index 9192a5a..f4fa7bb 100644 --- a/aidbox-forms-smart-launch-2/src/components/spinner.tsx +++ b/aidbox-forms-smart-launch-2/src/components/spinner.tsx @@ -1,6 +1,6 @@ import { type SVGProps } from "react"; -export function Spinner(props: SVGProps & { expand?: boolean }) { +export function Spinner(props: SVGProps & { expand?: string }) { const svg = ( & { questionnaire?: string; }; + "aidbox-form-builder": React.DetailedHTMLProps< + React.IframeHTMLAttributes, + HTMLIFrameElement + > & { + "hide-back"?: boolean; + "show-share"?: boolean; + "hide-population"?: boolean; + "hide-extraction"?: boolean; + "hide-publish"?: boolean; + "hide-add-theme"?: boolean; + "hide-edit-theme"?: boolean; + "hide-save-theme"?: boolean; + "hide-convert"?: boolean; + "hide-save"?: boolean; + "disable-save"?: boolean; + value?: string; + }; } } }