Skip to main content

6. Build the weekly wellness reflection

What we are building​

A short, app-owned FHIR Questionnaire with one self-report question for each domain. Ovok Native renders the Questionnaire, validates required answers and saves a FHIR QuestionnaireResponse for the signed-in Patient.

What you should already have​

The implementation​

This is an example of an app-owned reflection, not a validated psychological, sleep, nutrition or clinical instrument. Keep it brief and neutral. Create and publish this resource once in the sandbox using an authorized project workflow; the mobile member flow should read the published resource, not create a new Questionnaire on every launch.

const reflectionOptions = [
"Much less than I wanted",
"A little less than I wanted",
"About as I expected",
"A little more than I expected",
"Much more than I expected",
];

export const weeklyWellnessQuestionnaire = {
resourceType: "Questionnaire" as const,
status: "active",
title: "Weekly wellbeing reflection",
subjectType: ["Patient"],
item: [
{
linkId: "sleep",
text: "How did your sleep feel this week?",
type: "choice" as const,
required: true,
answerOption: ["Very difficult", "Difficult", "Mixed", "Good", "Very good"].map(
(value) => ({ valueString: value }),
),
},
{
linkId: "movement",
text: "How did your movement compare with what you wanted for yourself?",
type: "choice" as const,
required: true,
answerOption: reflectionOptions.map((value) => ({ valueString: value })),
},
{
linkId: "nutrition",
text: "How did your eating habits feel this week?",
type: "choice" as const,
required: true,
answerOption: reflectionOptions.map((value) => ({ valueString: value })),
},
{
linkId: "stress",
text: "How would you describe your stress this week?",
type: "choice" as const,
required: true,
answerOption: ["Very high", "High", "Mixed", "Low", "Very low"].map(
(value) => ({ valueString: value }),
),
},
{
linkId: "recovery",
text: "How did your energy and sense of recovery feel this week?",
type: "choice" as const,
required: true,
answerOption: ["Very low", "Low", "Mixed", "Good", "Very good"].map(
(value) => ({ valueString: value }),
),
},
{
linkId: "week-note",
text: "What would you like to discuss with your coach?",
type: "string" as const,
},
],
};

Load the active Questionnaire from the project, then render it with the SDK-managed persistence path:

import { QuestionnaireForm } from "@ovok/native";

export function WeeklyReflectionForm({
questionnaire,
onCompleted,
}: {
questionnaire: Parameters<typeof QuestionnaireForm>[0]["questionnaire"];
onCompleted: (responseId: string) => void;
}) {
return (
<QuestionnaireForm
questionnaire={questionnaire}
onSuccess={(response) => {
if (response.id) onCompleted(response.id);
}}
onError={(error) => console.error("Reflection save failed", error)}
>
<QuestionnaireForm.Header />
<QuestionnaireForm.Content>
<QuestionnaireForm.Content.Item />
<QuestionnaireForm.Content.Error />
</QuestionnaireForm.Content>
<QuestionnaireForm.Navigation>
<QuestionnaireForm.Navigation.PreviousButton />
<QuestionnaireForm.Navigation.NextButton />
<QuestionnaireForm.Navigation.SubmitButton>
Save this reflection
</QuestionnaireForm.Navigation.SubmitButton>
</QuestionnaireForm.Navigation>
</QuestionnaireForm>
);
}

With onSuccess / onError and no app-owned onSubmit, the component creates a QuestionnaireResponse using the active Patient and the Questionnaire. A stable identifier prevents duplicate writes while a submission is pending; after a successful save, a later submission is a new response. Start a clean form for each weekly check-in rather than editing a completed response in place.

The example answer choices are ordinary app-owned reflection options, not a validated scale. The Questionnaire's item text is FHIR content; create a reviewed Questionnaire for each supported language rather than assuming CMS translation automatically rewrites FHIR resource content.

Important Ovok decisions​

  • Use stable linkId values so a question can be matched across responses and languages.
  • Keep the Questionnaire resource as the question definition and each QuestionnaireResponse as a distinct historical completion.
  • No score, diagnosis, psychological assessment or recommendation is calculated.
  • $populate and $extract are not required for this simple reflection. Use them only for a workflow that actually needs their documented behavior; see Ovok primitives.
  • App-owned labels and navigation are localized through CMS; Questionnaire content is managed as FHIR data.

Expected result​

A member can complete the weekly reflection and the SDK saves a QuestionnaireResponse linked to that Patient and Questionnaire. Failed saves remain visible and can be retried.

Common errors and troubleshooting​

SymptomCheck
The form cannot render an itemConfirm the Questionnaire uses item types supported by the current QuestionnaireForm.
Submission says no profile is availableMount the form after sign-in and successful Patient profile loading.
A retry creates duplicate responsesKeep the form instance mounted while the same submission is retried; mount a new instance only for a new check-in.
A language switch changes buttons but not question textPublish a matching localized FHIR Questionnaire resource and load that version.
The form starts to look like a clinical assessmentKeep the questions neutral and clearly identify them as self-reflections.

Previous / next​