Repository: ohcnetwork/care_fe
Pull request #11817: Questionnaire Download & Import
Author: login: amjithtitus09
Labels: name: Tested
name: reviewed
description: reviewed by a core member
Created: 2025-04-08T13:57:43Z | Merged: 2025-04-09T16:57:05Z

## Proposed Changes

- Partially fixes https://github.com/ohcnetwork/care_fe/issues/11812
- Does the Import and Download without the sync function since BE needs to add support for versioning first

@ohcnetwork/care-fe-code-reviewers

## Merge Checklist

- [ ] Add specs that demonstrate bug / test a new feature.
- [ ] Update [product documentation](https://docs.ohc.network).
- [ ] Ensure that UI text is kept in I18n files.
- [ ] Prep screenshot or demo video for changelog entry, and attach it to issue.
- [ ] Request for Peer Reviews
- [ ] Completion of QA in Mobile Devices
- [ ] Completion of QA in Desktop Devices


<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

- **New Features**
  - Added improved language support to provide clearer feedback during questionnaire import operations.
  - Introduced an intuitive dialog that allows users to import questionnaires from a URL with preview and confirmation.
  - Enabled users to download their current questionnaire as a JSON file for easier management.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->


Diff:
diff --git a/public/locale/en.json b/public/locale/en.json
index 5cdef4cd62a..70cae4d38b8 100644
--- a/public/locale/en.json
+++ b/public/locale/en.json
@@ -1327,6 +1327,7 @@
   "facility_updated_success": "Facility updated successfully",
   "facility_updated_successfully": "Facility updated successfully",
   "failed_to_create_appointment": "Failed to create an appointment",
+  "failed_to_import_questionnaire": "Failed to import questionnaire",
   "failed_to_link_abha_number": "Failed to link ABHA Number. Please try again later.",
   "failed_to_send_message": "Failed to send message",
   "false": "False",
@@ -1450,6 +1451,11 @@
   "icmr_specimen_referral_form": "ICMR Specimen Referral Form",
   "identifier": "Identifier",
   "immunisation-records": "Immunisation",
+  "import": "Import",
+  "import_form": "Import Form",
+  "import_from_url": "Import from URL",
+  "import_questionnaire": "Import Questionnaire",
+  "importing": "Importing",
   "in_consultation": "In-Consultation",
   "in_progress": "In Progress",
   "inactive": "Inactive",
@@ -1492,6 +1498,7 @@
   "invalid_pincode_msg": "Please enter valid pincode",
   "invalid_reset": "Invalid Reset",
   "invalid_url": "Please enter a valid url",
+  "invalid_url_format": "Invalid URL format",
   "invalid_url_http_https": "URL should start with http:// or https://",
   "invalid_url_javascript": "URL should not include javascript, please enter a valid URL.",
   "invalid_username": "Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.",
@@ -2095,6 +2102,7 @@
   "planned_reserved_cannot_be_in_past": "Planned/Reserved cannot be in the past",
   "play": "Play",
   "play_audio": "Play Audio",
+  "please enter a valid url": "Please enter a valid URL",
   "please_assign_bed_to_patient": "Please assign a bed to this patient",
   "please_check_your_messages": "Please check your messages",
   "please_confirm_password": "Please confirm your new password.",
@@ -2231,6 +2239,9 @@
   "questionnaire_diagnosis_no_encounter": "Diagnosis cannot be recorded without an active encounter",
   "questionnaire_error_loading": "Error loading questionnaire",
   "questionnaire_files_no_encounter": "Create an encounter first to upload files",
+  "questionnaire_imported_successfully": "Questionnaire Imported Successfully",
+  "questionnaire_json_url": "Questionnaire JSON URL",
+  "questionnaire_json_url_placeholder": "https://example.com/questionnaire.json",
   "questionnaire_medication_request_no_encounter": "Medication requests cannot be recorded without an active encounter",
   "questionnaire_medication_statement_no_encounter": "Medication statements cannot be recorded without an active encounter",
   "questionnaire_no_encounter": "Create an encounter first in order to update it",
@@ -2243,6 +2254,7 @@
   "questionnaire_symptom_no_encounter": "Symptoms cannot be recorded without an active encounter",
   "questionniare_load_error": "Failed to load questionnaire. Please try again later.",
   "questions": "Questions",
+  "questions_count": "Question count",
   "quick_access": "Quick Access",
   "quick_actions": "Quick Actions",
   "quick_actions_description": "Schedule an appointment or create a new encounter",
@@ -2912,6 +2924,7 @@
   "upload_headings__supporting_info": "Upload Supporting Info",
   "upload_report": "Upload Report",
   "uploading": "Uploading",
+  "url_required": "URL required",
   "use": "Use",
   "use_address_as_permanent": "Use this address for permanent address",
   "use_auth_app": "Use authenticator app",
diff --git a/src/components/Questionnaire/QuestionnaireEditor.tsx b/src/components/Questionnaire/QuestionnaireEditor.tsx
index c59dd3be0f4..67583deeaf4 100644
--- a/src/components/Questionnaire/QuestionnaireEditor.tsx
+++ b/src/components/Questionnaire/QuestionnaireEditor.tsx
@@ -29,6 +29,13 @@ import {
   CollapsibleContent,
   CollapsibleTrigger,
 } from "@/components/ui/collapsible";
+import {
+  Dialog,
+  DialogContent,
+  DialogFooter,
+  DialogHeader,
+  DialogTitle,
+} from "@/components/ui/dialog";
 import {
   DropdownMenu,
   DropdownMenuContent,
@@ -194,6 +201,11 @@ export default function QuestionnaireEditor({ id }: QuestionnaireEditorProps) {
   const [orgSearchQuery, setOrgSearchQuery] = useState("");
   const [tagSearchQuery, setTagSearchQuery] = useState("");
   const [orgError, setOrgError] = useState<string | undefined>();
+  const [importUrl, setImportUrl] = useState("");
+  const [showImportDialog, setShowImportDialog] = useState(false);
+  const [importedData, setImportedData] = useState<QuestionnaireDetail | null>(
+    null,
+  );
   const queryClient = useQueryClient();
 
   const {
@@ -279,6 +291,24 @@ export default function QuestionnaireEditor({ id }: QuestionnaireEditorProps) {
       toast.error("Failed to update questionnaire");
     },
   });
+
+  const { mutate: importQuestionnaire, isPending: isImporting } = useMutation({
+    mutationFn: async (url: string) => {
+      const response = await fetch(url);
+      if (!response.ok) throw new Error("Failed to fetch questionnaire");
+      return response.json();
+    },
+    onSuccess: (data) => {
+      setImportedData(data);
+      toast.success(t("questionnaire_imported_successfully"));
+    },
+    onError: () => {
+      toast.error(t("failed_to_import_questionnaire"));
+    },
+  });
+
+  const urlSchema = z.string().url(t("please enter a valid url"));
+
   const QuestionnaireFormPartialSchema = z.object({
     title: z.string().trim().min(1, t("field_required")),
     slug: z
@@ -409,6 +439,71 @@ export default function QuestionnaireEditor({ id }: QuestionnaireEditorProps) {
     navigate("/admin/questionnaire");
   };
 
+  const handleDownload = () => {
+    const dataStr = JSON.stringify(questionnaire, null, 2);
+    const dataUri = `data:application/json;charset=utf-8,${encodeURIComponent(dataStr)}`;
+    const exportFileDefaultName = `${questionnaire.slug || "questionnaire"}.json`;
+
+    const linkElement = document.createElement("a");
+    linkElement.setAttribute("href", dataUri);
+    linkElement.setAttribute("download", exportFileDefaultName);
+    linkElement.click();
+  };
+
+  const handleImport = async () => {
+    if (!importUrl) {
+      toast.error(t("url_required"));
+      return;
+    }
+
+    try {
+      urlSchema.parse(importUrl);
+      importQuestionnaire(importUrl);
+    } catch (error) {
+      if (error instanceof z.ZodError) {
+        toast.error(error.errors[0].message);
+      }
+    }
+  };
+
+  const handleImportConfirm = () => {
+    if (!importedData) return;
+
+    // Map only the necessary fields, ignoring id, created_by, tags etc.
+    const mappedData: Partial<QuestionnaireDetail> = {
+      title: importedData.title,
+      description: importedData.description,
+      status: "draft",
+      version: "1.0",
+      subject_type: importedData.subject_type || "patient",
+      questions:
+        importedData.questions?.map((q: Question) => ({
+          ...q,
+          id: crypto.randomUUID(), // Generate new IDs for questions
+          questions: q.questions?.map((sq: Question) => ({
+            ...sq,
+            id: crypto.randomUUID(), // Generate new IDs for sub-questions
+          })),
+        })) || [],
+      slug: importedData.slug,
+    };
+
+    setQuestionnaire({
+      ...questionnaire,
+      ...mappedData,
+    } as QuestionnaireDetail);
+    form.reset({
+      title: mappedData.title || "",
+      slug: mappedData.slug || "",
+      description: mappedData.description || "",
+    });
+
+    setShowImportDialog(false);
+    setImportUrl("");
+    setImportedData(null);
+    toast.success(t("questionnaire_imported_successfully"));
+  };
+
   const toggleQuestionExpanded = (questionId: string) => {
     setExpandedQuestions((prev) => {
       const next = new Set(prev);
@@ -455,7 +550,7 @@ export default function QuestionnaireEditor({ id }: QuestionnaireEditorProps) {
 
   return (
     <div className="container mx-auto px-4 py-6">
-      <div className="mb-4 flex items-center justify-between">
+      <div className="mb-4 flex flex-col md:flex-row items-center justify-between gap-2">
         <div>
           <h1 className="text-2xl font-bold">
             {id
@@ -468,6 +563,18 @@ export default function QuestionnaireEditor({ id }: QuestionnaireEditorProps) {
           <Button variant="outline" onClick={handleCancel}>
             {t("cancel")}
           </Button>
+          {id && (
+            <Button variant="outline" onClick={handleDownload}>
+              <CareIcon icon="l-import" className="mr-1 size-4" />
+              {t("download")}
+            </Button>
+          )}
+          {!id && (
+            <Button variant="outline" onClick={() => setShowImportDialog(true)}>
+              <CareIcon icon="l-import" className="mr-1 size-4" />
+              {t("import_from_url")}
+            </Button>
+          )}
           <Button onClick={handleSave} disabled={isCreating || isUpdating}>
             <CareIcon icon="l-save" className="mr-2 size-4" />
             {id ? t("save") : t("create")}
@@ -823,6 +930,56 @@ export default function QuestionnaireEditor({ id }: QuestionnaireEditorProps) {
           </Card>
         </TabsContent>
       </Tabs>
+      <Dialog open={showImportDialog} onOpenChange={setShowImportDialog}>
+        <DialogContent>
+          <DialogHeader>
+            <DialogTitle>{t("import_questionnaire")}</DialogTitle>
+          </DialogHeader>
+          <div className="space-y-4">
+            <div className="space-y-2">
+              <Label>{t("questionnaire_json_url")}</Label>
+              <Input
+                value={importUrl}
+                onChange={(e) => setImportUrl(e.target.value)}
+                placeholder={t("questionnaire_json_url_placeholder")}
+              />
+            </div>
+            {importedData && (
+              <div className="space-y-2">
+                <Label>{t("preview")}</Label>
+                <div className="p-4 border rounded-lg">
+                  <p className="font-medium">{importedData.title}</p>
+                  <p className="text-sm text-gray-500">
+                    {importedData.description}
+                  </p>
+                  <p className="text-sm mt-2">
+                    {t("questions_count")} :{" "}
+                    {importedData.questions?.length || 0}
+                  </p>
+                </div>
+              </div>
+            )}
+          </div>
+          <DialogFooter>
+            <Button
+              variant="outline"
+              onClick={() => setShowImportDialog(false)}
+            >
+              {t("cancel")}
+            </Button>
+            {!importedData ? (
+              <Button
+                onClick={handleImport}
+                disabled={!importUrl || isImporting}
+              >
+                {isImporting ? t("importing") : t("import")}
+              </Button>
+            ) : (
+              <Button onClick={handleImportConfirm}>{t("import_form")}</Button>
+            )}
+          </DialogFooter>
+        </DialogContent>
+      </Dialog>
     </div>
   );
 }


Reviews:
user: login: coderabbitai[bot]
body: **Actionable comments posted: 1**

<details>
<summary>🧹 Nitpick comments (2)</summary><blockquote>

<details>
<summary>public/locale/en.json (1)</summary><blockquote>

`1454-1458`: **New Import Action and Label Keys Introduced**  
The keys `"import"`, `"import_form"`, `"import_from_url"`, `"import_questionnaire"`, and `"importing"` are succinct and effectively capture the actions and labels required for the new questionnaire import functionality. One optional refinement to consider is whether the generic key `"import"` might be made more specific (for example, `"questionnaire_import_action"`) to reduce potential ambiguity in larger projects; however, if the context is clear across the codebase, this is acceptable.

</blockquote></details>
<details>
<summary>src/components/Questionnaire/QuestionnaireEditor.tsx (1)</summary><blockquote>

`425-434`: **Consider adding error handling to download functionality**

The download implementation works well for typical cases, but lacks error handling for potential failures.

```diff
 const handleDownload = () => {
-  const dataStr = JSON.stringify(questionnaire, null, 2);
-  const dataUri = `data:application/json;charset=utf-8,${encodeURIComponent(dataStr)}`;
-  const exportFileDefaultName = `${questionnaire.slug || "questionnaire"}.json`;
-
-  const linkElement = document.createElement("a");
-  linkElement.setAttribute("href", dataUri);
-  linkElement.setAttribute("download", exportFileDefaultName);
-  linkElement.click();
+  try {
+    const dataStr = JSON.stringify(questionnaire, null, 2);
+    const dataUri = `data:application/json;charset=utf-8,${encodeURIComponent(dataStr)}`;
+    const exportFileDefaultName = `${questionnaire.slug || "questionnaire"}.json`;
+
+    const linkElement = document.createElement("a");
+    linkElement.setAttribute("href", dataUri);
+    linkElement.setAttribute("download", exportFileDefaultName);
+    linkElement.click();
+    toast.success(t("questionnaire_downloaded_successfully"));
+  } catch (error) {
+    toast.error(t("failed_to_download_questionnaire"));
+    console.error("Download error:", error);
+  }
 };
```

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between bf73e5c2425d29c7736fadfc7ba821e1fb29392c and b7cf302bc1d41d9c75f3174d9cc00989bfca62ee.

</details>

<details>
<summary>📒 Files selected for processing (2)</summary>

* `public/locale/en.json` (4 hunks)
* `src/components/Questionnaire/QuestionnaireEditor.tsx` (6 hunks)

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>🧬 Code Definitions (1)</summary>

<details>
<summary>src/components/Questionnaire/QuestionnaireEditor.tsx (5)</summary><blockquote>

<details>
<summary>src/types/questionnaire/questionnaire.ts (1)</summary>

* `QuestionnaireDetail` (9-20)

</details>
<details>
<summary>src/types/questionnaire/question.ts (1)</summary>

* `Question` (126-158)

</details>
<details>
<summary>src/components/ui/button.tsx (1)</summary>

* `Button` (84-84)

</details>
<details>
<summary>src/components/ui/label.tsx (1)</summary>

* `Label` (24-24)

</details>
<details>
<summary>src/components/ui/input.tsx (1)</summary>

* `Input` (28-28)

</details>

</blockquote></details>

</details>

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms (1)</summary>

* GitHub Check: cypress-run (1)

</details>

<details>
<summary>🔇 Additional comments (8)</summary><blockquote>

<details>
<summary>public/locale/en.json (3)</summary>

`1330-1330`: **New Import Failure Message Key Added**  
The new key `"failed_to_import_questionnaire"` with the value `"Failed to import questionnaire"` is clear and consistent with other error messages in the file. Please ensure that its usage in the UI properly reflects the desired error condition during import failures.

---

`2240-2242`: **New Questionnaire Download Keys Added**  
The keys `"questionnaire_imported_successfully"`, `"questionnaire_json_url"`, and `"questionnaire_json_url_placeholder"` have been introduced to support feedback and functionality for the questionnaire download/import process. Their messages are clear. As a minor suggestion, double-check that the placeholder URL (`"https://example.com/questionnaire.json"`) aligns with actual expected formats or is updated prior to production deployment.

---

`2255-2255`: **New Question Count Key Introduced**  
The key `"questions_count"` with the value `"Question count"` is added to support the display of the total number of questions. This key follows the naming convention used in the localization file. Verify that its usage in the UI correctly handles pluralization or any dynamic formatting if needed.

</details>
<details>
<summary>src/components/Questionnaire/QuestionnaireEditor.tsx (5)</summary>

`32-38`: **Component imports look good**

Added Dialog component imports necessary for the new questionnaire import feature.

---

`204-209`: **Well-structured state management for import functionality**

The state variables are appropriately named and typed. Using separate state variables for URL, dialog visibility, imported data, and loading state follows React best practices by keeping state granular and focused.

---

`454-487`: **Good implementation of import mapping with UUID regeneration**

The import confirmation function correctly maps only necessary fields from the imported data, and regenerates UUIDs for questions and sub-questions to prevent ID conflicts. The cleanup of import-related state after confirmation is also well-handled.


One minor suggestion: consider adding more robust validation for the imported data structure, especially for required fields such as `title` and `questions`.

---

`535-559`: **Good conditional rendering of import/download buttons**

The UI logic correctly shows the download button only when editing an existing questionnaire (ID exists) and the import button only when creating a new one. This ensures users don't accidentally overwrite existing data when editing.

---

`915-964`: **Well-structured import dialog with preview functionality**

The import dialog provides a good user experience by allowing URL input, previewing the imported data before confirmation, and providing appropriate buttons for different states (import/cancel when no data is loaded, import/cancel when data is previewed).


Consider adding a character limit display for the URL input field and perhaps a spinner or progress indicator during loading to enhance user feedback.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-08T14:07:33Z
user: login: rithviknishad
body: LGTM, minor thing
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-09T06:23:49Z
user: login: amjithtitus09
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-09T08:26:14Z
user: login: coderabbitai[bot]
body: **Actionable comments posted: 1**

<details>
<summary>🧹 Nitpick comments (2)</summary><blockquote>

<details>
<summary>src/components/Questionnaire/QuestionnaireEditor.tsx (2)</summary><blockquote>

`453-467`: **Enhance error handling for the import operation.**

While the basic validation is in place, the error handling could be more specific to help users understand what went wrong.

```diff
 const handleImport = async () => {
   if (!importUrl) {
     toast.error(t("url_required"));
     return;
   }

   try {
     urlSchema.parse(importUrl);
     importQuestionnaire(importUrl);
   } catch (error) {
     if (error instanceof z.ZodError) {
       toast.error(error.errors[0].message);
+    } else if (error instanceof Error) {
+      toast.error(`${t("failed_to_import_questionnaire")}: ${error.message}`);
     }
   }
 };
```

---

`933-982`: **Well-structured import dialog with preview capability.**

The dialog implementation provides a good user experience with:
- Clear title and instructions
- Input field for the URL
- Preview of what will be imported
- Appropriate buttons based on the current state

Consider adding a loading indicator during the import operation for better feedback.

```diff
 <DialogFooter>
   <Button
     variant="outline"
     onClick={() => setShowImportDialog(false)}
   >
     {t("cancel")}
   </Button>
   {!importedData ? (
     <Button
       onClick={handleImport}
       disabled={!importUrl || isImporting}
     >
-      {isImporting ? t("importing") : t("import")}
+      {isImporting ? (
+        <>
+          <CareIcon icon="l-spinner" className="mr-2 size-4 animate-spin" />
+          {t("importing")}
+        </>
+      ) : (
+        t("import")
+      )}
     </Button>
   ) : (
     <Button onClick={handleImportConfirm}>{t("import_form")}</Button>
   )}
 </DialogFooter>
```

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between b7cf302bc1d41d9c75f3174d9cc00989bfca62ee and 6b7011f99f6c81ff0fb3bb3350639b774c2daa89.

</details>

<details>
<summary>📒 Files selected for processing (2)</summary>

* `public/locale/en.json` (7 hunks)
* `src/components/Questionnaire/QuestionnaireEditor.tsx` (7 hunks)

</details>

<details>
<summary>🚧 Files skipped from review as they are similar to previous changes (1)</summary>

* public/locale/en.json

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms (1)</summary>

* GitHub Check: cypress-run (1)

</details>

<details>
<summary>🔇 Additional comments (6)</summary><blockquote>

<details>
<summary>src/components/Questionnaire/QuestionnaireEditor.tsx (6)</summary>

`32-38`: **Good addition of Dialog UI components for the import modal.**

The addition of Dialog component imports is appropriate for implementing the questionnaire import functionality.

---

`204-209`: **State management for the import functionality looks good.**

These state variables are well-designed for managing the import process:
- `importUrl` stores the URL input
- `showImportDialog` controls dialog visibility
- `importedData` tracks the imported questionnaire data

---

`310-311`: **Good URL validation with proper error messages.**

Using Zod for URL validation is a robust approach that integrates well with the internationalization system.

---

`442-451`: **Well-implemented download functionality.**

The download implementation follows best practices for browser-based file downloads:
- Creates proper JSON content
- Sets appropriate MIME type
- Generates a meaningful filename based on the questionnaire slug

---

`469-505`: **Good implementation of import confirmation with proper data handling.**

The import confirmation function does a good job of:
- Mapping only necessary fields from imported data
- Generating new IDs to avoid conflicts
- Maintaining data structure integrity
- Cleaning up after the import

---

`566-577`: **Clear UI for download and import actions.**

The implementation appropriately shows different actions based on context:
- Download button for existing questionnaires
- Import button for new questionnaires
Each with relevant icons and translated labels.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-09T08:33:57Z
user: login: rithviknishad
state: APPROVED
author_association: MEMBER
submitted_at: 2025-04-09T10:45:32Z

Review comments:
diff_hunk: @@ -409,6 +422,70 @@ export default function QuestionnaireEditor({ id }: QuestionnaireEditorProps) {
     navigate("/admin/questionnaire");
   };
 
+  const handleDownload = () => {
+    const dataStr = JSON.stringify(questionnaire, null, 2);
+    const dataUri = `data:application/json;charset=utf-8,${encodeURIComponent(dataStr)}`;
+    const exportFileDefaultName = `${questionnaire.slug || "questionnaire"}.json`;
+
+    const linkElement = document.createElement("a");
+    linkElement.setAttribute("href", dataUri);
+    linkElement.setAttribute("download", exportFileDefaultName);
+    linkElement.click();
+  };
+
+  const handleImport = async () => {
+    if (!importUrl) return;
+
+    setIsLoadingImport(true);
+    try {
+      const response = await fetch(importUrl);
+      if (!response.ok) throw new Error("Failed to fetch questionnaire");
+
+      const data = await response.json();
+      setImportedData(data);
+      toast.success(t("questionnaire_imported_successfully"));
+    } catch (_error) {
+      toast.error(t("failed_to_import_questionnaire"));
+    } finally {
+      setIsLoadingImport(false);
+    }
+  };
path: src/components/Questionnaire/QuestionnaireEditor.tsx
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**Add URL validation before import**

The current implementation doesn't validate the URL format before attempting to fetch data, which could lead to unnecessary network requests or errors.

```diff
 const handleImport = async () => {
-  if (!importUrl) return;
+  if (!importUrl) return;
+  
+  // Basic URL validation
+  try {
+    new URL(importUrl);
+  } catch (error) {
+    toast.error(t("invalid_url_format"));
+    return;
+  }

   setIsLoadingImport(true);
   try {
     const response = await fetch(importUrl);
     if (!response.ok) throw new Error("Failed to fetch questionnaire");

     const data = await response.json();
+    // Basic validation of imported data structure
+    if (!data.title || !Array.isArray(data.questions)) {
+      throw new Error("Invalid questionnaire format");
+    }
     setImportedData(data);
     toast.success(t("questionnaire_imported_successfully"));
   } catch (_error) {
     toast.error(t("failed_to_import_questionnaire"));
   } finally {
     setIsLoadingImport(false);
   }
 };
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
  const handleImport = async () => {
    if (!importUrl) return;
  
    // Basic URL validation
    try {
      new URL(importUrl);
    } catch (error) {
      toast.error(t("invalid_url_format"));
      return;
    }
  
    setIsLoadingImport(true);
    try {
      const response = await fetch(importUrl);
      if (!response.ok) throw new Error("Failed to fetch questionnaire");
  
      const data = await response.json();
      // Basic validation of imported data structure
      if (!data.title || !Array.isArray(data.questions)) {
        throw new Error("Invalid questionnaire format");
      }
      setImportedData(data);
      toast.success(t("questionnaire_imported_successfully"));
    } catch (_error) {
      toast.error(t("failed_to_import_questionnaire"));
    } finally {
      setIsLoadingImport(false);
    }
  };
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated comment by CodeRabbit -->

✅ Addressed in commits e0c56f6 to 6b7011f
created_at: 2025-04-08T14:07:32Z
author_association: CONTRIBUTOR
diff_hunk: @@ -409,6 +422,70 @@ export default function QuestionnaireEditor({ id }: QuestionnaireEditorProps) {
     navigate("/admin/questionnaire");
   };
 
+  const handleDownload = () => {
+    const dataStr = JSON.stringify(questionnaire, null, 2);
+    const dataUri = `data:application/json;charset=utf-8,${encodeURIComponent(dataStr)}`;
+    const exportFileDefaultName = `${questionnaire.slug || "questionnaire"}.json`;
+
+    const linkElement = document.createElement("a");
+    linkElement.setAttribute("href", dataUri);
+    linkElement.setAttribute("download", exportFileDefaultName);
+    linkElement.click();
+  };
+
+  const handleImport = async () => {
+    if (!importUrl) return;
+
+    setIsLoadingImport(true);
+    try {
+      const response = await fetch(importUrl);
+      if (!response.ok) throw new Error("Failed to fetch questionnaire");
+
+      const data = await response.json();
+      setImportedData(data);
+      toast.success(t("questionnaire_imported_successfully"));
+    } catch (_error) {
+      toast.error(t("failed_to_import_questionnaire"));
+    } finally {
+      setIsLoadingImport(false);
+    }
+  };
path: src/components/Questionnaire/QuestionnaireEditor.tsx
user: login: rithviknishad
body: can we make this to use `useMutation` instead? 🤔 


created_at: 2025-04-09T06:23:08Z
author_association: MEMBER
diff_hunk: @@ -409,6 +422,70 @@ export default function QuestionnaireEditor({ id }: QuestionnaireEditorProps) {
     navigate("/admin/questionnaire");
   };
 
+  const handleDownload = () => {
+    const dataStr = JSON.stringify(questionnaire, null, 2);
+    const dataUri = `data:application/json;charset=utf-8,${encodeURIComponent(dataStr)}`;
+    const exportFileDefaultName = `${questionnaire.slug || "questionnaire"}.json`;
+
+    const linkElement = document.createElement("a");
+    linkElement.setAttribute("href", dataUri);
+    linkElement.setAttribute("download", exportFileDefaultName);
+    linkElement.click();
+  };
+
+  const handleImport = async () => {
+    if (!importUrl) return;
+
+    setIsLoadingImport(true);
+    try {
+      const response = await fetch(importUrl);
+      if (!response.ok) throw new Error("Failed to fetch questionnaire");
+
+      const data = await response.json();
+      setImportedData(data);
+      toast.success(t("questionnaire_imported_successfully"));
+    } catch (_error) {
+      toast.error(t("failed_to_import_questionnaire"));
+    } finally {
+      setIsLoadingImport(false);
+    }
+  };
path: src/components/Questionnaire/QuestionnaireEditor.tsx
user: login: amjithtitus09
body: Yeah, done
created_at: 2025-04-09T08:26:14Z
author_association: MEMBER
diff_hunk: @@ -279,6 +291,24 @@ export default function QuestionnaireEditor({ id }: QuestionnaireEditorProps) {
       toast.error("Failed to update questionnaire");
     },
   });
+
+  const { mutate: importQuestionnaire, isPending: isImporting } = useMutation({
+    mutationFn: async (url: string) => {
+      const response = await fetch(url);
+      if (!response.ok) throw new Error("Failed to fetch questionnaire");
+      return response.json();
+    },
+    onSuccess: (data) => {
+      setImportedData(data);
+      toast.success(t("questionnaire_imported_successfully"));
+    },
+    onError: () => {
+      toast.error(t("failed_to_import_questionnaire"));
+    },
+  });
path: src/components/Questionnaire/QuestionnaireEditor.tsx
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**Consider adding enhanced validation for the imported data.**

The mutation correctly handles the basic fetch operation, but there's limited validation of the response structure beyond HTTP status.

```diff
 const { mutate: importQuestionnaire, isPending: isImporting } = useMutation({
   mutationFn: async (url: string) => {
     const response = await fetch(url);
     if (!response.ok) throw new Error("Failed to fetch questionnaire");
-    return response.json();
+    const data = await response.json();
+    
+    // Validate the essential structure of imported data
+    if (!data.title || !data.slug || !Array.isArray(data.questions)) {
+      throw new Error("Invalid questionnaire format");
+    }
+    
+    return data;
   },
   onSuccess: (data) => {
     setImportedData(data);
     toast.success(t("questionnaire_imported_successfully"));
   },
   onError: () => {
     toast.error(t("failed_to_import_questionnaire"));
   },
 });
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
  const { mutate: importQuestionnaire, isPending: isImporting } = useMutation({
    mutationFn: async (url: string) => {
      const response = await fetch(url);
      if (!response.ok) throw new Error("Failed to fetch questionnaire");
      const data = await response.json();
      
      // Validate the essential structure of imported data
      if (!data.title || !data.slug || !Array.isArray(data.questions)) {
        throw new Error("Invalid questionnaire format");
      }
      
      return data;
    },
    onSuccess: (data) => {
      setImportedData(data);
      toast.success(t("questionnaire_imported_successfully"));
    },
    onError: () => {
      toast.error(t("failed_to_import_questionnaire"));
    },
  });
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-09T08:33:57Z
author_association: CONTRIBUTOR

PR comments:
user: login: netlify[bot]
created_at: 2025-04-08T13:58:29Z
body: ### <span aria-hidden="true">✅</span> Deploy Preview for *care-ohc* ready!


|  Name | Link |
|:-:|------------------------|
|<span aria-hidden="true">🔨</span> Latest commit | 6eae90cfa2f5a3fc20cae11ea788c6f1f5638b45 |
|<span aria-hidden="true">🔍</span> Latest deploy log | https://app.netlify.com/sites/care-ohc/deploys/67f6632220e44300089a065a |
|<span aria-hidden="true">😎</span> Deploy Preview | [https://deploy-preview-11817.preview.ohc.network](https://deploy-preview-11817.preview.ohc.network) |
|<span aria-hidden="true">📱</span> Preview on mobile | <details><summary> Toggle QR Code... </summary><br /><br />![QR Code](https://app.netlify.com/qr-code/eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1cmwiOiJodHRwczovL2RlcGxveS1wcmV2aWV3LTExODE3LnByZXZpZXcub2hjLm5ldHdvcmsifQ.H6TUQ2DC-3xkNDzao5AZcmqPuhkk_-7G1PbExvjTUFU)<br /><br />_Use your smartphone camera to open QR code link._</details> |
---
<!-- [care-ohc Preview](https://deploy-preview-11817.preview.ohc.network) -->
_To edit notification comments on pull requests, go to your [Netlify site configuration](https://app.netlify.com/sites/care-ohc/configuration/notifications#deploy-webhooks)._
author_association: NONE
user: login: coderabbitai[bot]
created_at: 2025-04-08T14:01:17Z
body: <!-- This is an auto-generated comment: summarize by coderabbit.ai -->
<!-- walkthrough_start -->

## Walkthrough
This pull request enhances the localization and questionnaire editor modules. In the localization file, new keys are added to support messages and UI elements related to importing questionnaires. In the questionnaire editor, new state variables and functions are introduced to handle importing questionnaires from a URL and downloading the current questionnaire as a JSON file. A dialog component is also added to improve the user experience during the import process.

## Changes

| File(s)                                  | Change Summary                                                                                                                                                                                                                                                                                                         |
|------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| public/locale/en.json                    | Added new localization keys: "failed_to_import_questionnaire", "import", "import_form", "import_from_url", "import_questionnaire", "importing", "questionnaire_imported_successfully", "questionnaire_json_url", "questionnaire_json_url_placeholder", "questions_count".                                       |
| src/components/Questionnaire/QuestionnaireEditor.tsx | Introduced new state variables and methods (handleDownload, handleImport, handleImportConfirm) to support importing questionnaires from a URL and downloading the current questionnaire as JSON; added an import dialog component and conditional button rendering.                                          |

## Sequence Diagram(s)

```mermaid
sequenceDiagram
    participant U as User
    participant QE as QuestionnaireEditor
    participant S as Server

    U->>QE: Clicks "Import" button
    QE->>U: Displays import dialog
    U->>QE: Enters URL and confirms import
    QE->>S: Fetches questionnaire JSON from provided URL
    S-->>QE: Returns questionnaire data (or error)
    QE->>QE: Updates state and shows toast notification
```

```mermaid
sequenceDiagram
    participant U as User
    participant QE as QuestionnaireEditor

    U->>QE: Clicks "Download" button
    QE->>QE: Generates JSON file from questionnaire data
    QE->>U: Triggers file download prompt
```

## Assessment against linked issues

| Objective                                                        | Addressed | Explanation                                                     |
|------------------------------------------------------------------|-----------|-----------------------------------------------------------------|
| Download Questionnaire as JSON [#11812]                          | ✅        |                                                                 |
| Import Questionnaire from URL [#11812]                           | ✅        |                                                                 |
| Sync imported Questionnaire with override confirmation [#11812]   | ❌        | Sync button and override confirmation have not been implemented. |

## Poem
> I'm a little rabbit on a coding spree,  
> Hopping through JSON keys so merrily.  
> With clicks and dialogs, imports take flight,  
> And downloads flow in the soft moonlight.  
> Code carrots crunch—oh what delight!  
> Happy hops to updates shining bright!

<!-- walkthrough_end -->


---

<details>
<summary>📜 Recent review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 6b7011f99f6c81ff0fb3bb3350639b774c2daa89 and a6188ccde42b93c3a0b5e663e00088502b0d6dc5.

</details>

<details>
<summary>📒 Files selected for processing (1)</summary>

* `public/locale/en.json` (7 hunks)

</details>

<details>
<summary>🚧 Files skipped from review as they are similar to previous changes (1)</summary>

* public/locale/en.json

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms (8)</summary>

* GitHub Check: Redirect rules - care-ohc
* GitHub Check: Header rules - care-ohc
* GitHub Check: Pages changed - care-ohc
* GitHub Check: CodeQL-Build
* GitHub Check: Test
* GitHub Check: OSSAR-Scan
* GitHub Check: cypress-run (1)
* GitHub Check: OSSAR-Scan

</details>

</details>
<!-- internal state start -->


<!-- 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= -->

<!-- internal state end -->
<!-- tips_start -->

---



<details>
<summary>🪧 Tips</summary>

### Chat

There are 3 ways to chat with [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=ohcnetwork/care_fe&utm_content=11817):

- Review comments: Directly reply to a review comment made by CodeRabbit. Example:
  - `I pushed a fix in commit <commit_id>, please review it.`
  - `Generate unit testing code for this file.`
  - `Open a follow-up GitHub issue for this discussion.`
- Files and specific lines of code (under the "Files changed" tab): Tag `@coderabbitai` in a new review comment at the desired location with your query. Examples:
  - `@coderabbitai generate unit testing code for this file.`
  -	`@coderabbitai modularize this function.`
- PR comments: Tag `@coderabbitai` in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
  - `@coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.`
  - `@coderabbitai read src/utils.ts and generate unit testing code.`
  - `@coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.`
  - `@coderabbitai help me debug CodeRabbit configuration file.`

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

### CodeRabbit Commands (Invoked using PR comments)

- `@coderabbitai pause` to pause the reviews on a PR.
- `@coderabbitai resume` to resume the paused reviews.
- `@coderabbitai review` to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
- `@coderabbitai full review` to do a full review from scratch and review all the files again.
- `@coderabbitai summary` to regenerate the summary of the PR.
- `@coderabbitai generate docstrings` to [generate docstrings](https://docs.coderabbit.ai/finishing-touches/docstrings) for this PR.
- `@coderabbitai resolve` resolve all the CodeRabbit review comments.
- `@coderabbitai plan` to trigger planning for file edits and PR creation.
- `@coderabbitai configuration` to show the current CodeRabbit configuration for the repository.
- `@coderabbitai help` to get help.

### Other keywords and placeholders

- Add `@coderabbitai ignore` anywhere in the PR description to prevent this PR from being reviewed.
- Add `@coderabbitai summary` to generate the high-level summary at a specific location in the PR description.
- Add `@coderabbitai` anywhere in the PR title to generate the title automatically.

### CodeRabbit Configuration File (`.coderabbit.yaml`)

- You can programmatically configure CodeRabbit by adding a `.coderabbit.yaml` file to the root of your repository.
- Please see the [configuration documentation](https://docs.coderabbit.ai/guides/configure-coderabbit) for more information.
- If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: `# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json`

### Documentation and Community

- Visit our [Documentation](https://docs.coderabbit.ai) for detailed information on how to use CodeRabbit.
- Join our [Discord Community](http://discord.gg/coderabbit) to get help, request features, and share feedback.
- Follow us on [X/Twitter](https://twitter.com/coderabbitai) for updates and announcements.

</details>

<!-- tips_end -->
author_association: CONTRIBUTOR
user: login: cypress[bot]
created_at: 2025-04-08T14:17:09Z
body: 
<h3>
  <a href="https://cloud.cypress.io/projects/wf7d2m?utm_source=github&utm_medium=failed&utm_campaign=project">CARE</a>&nbsp;
  <img src="https://assets.cypress.io/github-pr-comment-icons/chevron.svg" alt="" height="14" width="14" />&nbsp;
  <a href="https://cloud.cypress.io/projects/wf7d2m/runs/5761/overview?utm_source=github&utm_medium=failed&utm_campaign=run%20number">Run #5761</a>
</h3>

<details>
  <summary>
    <strong>Run Properties:</strong>&nbsp;
    <code><img src="https://assets.cypress.io/github-pr-comment-icons/failed.svg" alt="status check failed" height="10" width="10" />&nbsp;Failed&nbsp;<a href="https://cloud.cypress.io/projects/wf7d2m/runs/5761/overview?utm_source=github&utm_medium=failed&utm_campaign=run%20number">#5761</a></code> &nbsp;&bull;&nbsp;
    <code><img src="https://assets.cypress.io/github-pr-comment-icons/git-commit.svg" alt="git commit" width="10" height="10" /> <a href="https://github.com/ohcnetwork/care_fe/commit/6eae90cfa2f5a3fc20cae11ea788c6f1f5638b45">6eae90cfa2</a>: Questionnaire Download & Import</code>
  </summary><br />

  <table width="744">
    <tbody>
      <tr />
      <tr height="48">
        <td width="224">
          <strong>Project</strong>
        </td>
        <td width="520">
          <code><a href="https://cloud.cypress.io/projects/wf7d2m?utm_source=github&utm_medium=failed&utm_campaign=project">CARE</a></code>
        </td>
      </tr>
      <tr />
      <tr height="48">
        <td width="224">
          <strong>Branch Review</strong>
        </th>
        <td>
          <code><a href="https://cloud.cypress.io/projects/wf7d2m/branches/questionnaire-import/review?utm_source=github&utm_medium=failed&utm_campaign=review%20changes&changeRequest=11817">questionnaire-import</a></code>
        </td>
      </tr>
      <tr />
      <tr height="48">
        <td><strong>Run status</strong></td>
        <td>
          <code><img src="https://assets.cypress.io/github-pr-comment-icons/failed.svg" alt="status check failed" height="10" width="10" />&nbsp;Failed&nbsp;<a href="https://cloud.cypress.io/projects/wf7d2m/runs/5761/overview?utm_source=github&utm_medium=failed&utm_campaign=run%20number">#5761</a></code>
        </td>
      </tr>
      <tr />
      <tr height="48">
        <td><strong>Run duration</strong></td>
        <td><code>16m 02s</code></td>
      </tr>
      <tr />
      <tr height="48">
        <td><strong>Commit</strong></td>
        <td>
          <code><img src="https://assets.cypress.io/github-pr-comment-icons/git-commit.svg" alt="git commit" width="10" height="10" /> <a href="https://github.com/ohcnetwork/care_fe/commit/6eae90cfa2f5a3fc20cae11ea788c6f1f5638b45">6eae90cfa2</a>: Questionnaire Download & Import</code>
        </td>
      </tr>
      <tr />
      <tr height="48">
        <td><strong>Committer</strong></td>
        <td><code>Amjith Titus</code></td>
      </tr>
    </tbody>
    <tfoot>
      <tr />
      <tr height="48">
        <td colspan="2">
          <a href="https://cloud.cypress.io/projects/wf7d2m/runs/5761/properties?utm_source=github&utm_medium=failed&utm_campaign=properties">View all properties for this run ↗︎</a>
        </td>
      </tr>
    </tfoot>
  </table>
  <hr />
</details>

<table width="744">
  <thead>
    <tr />
    <tr height="48">
      <th colspan="2" align="left" width="744">Test results</th>
    </tr>
  </thead>
  <tbody>
    <tr height="48">
      <td width="224">
        <img src="https://assets.cypress.io/github-pr-comment-icons/failed.svg" alt="Tests that failed" width="10" height="10" />&nbsp;
        <a href="https://cloud.cypress.io/projects/wf7d2m/runs/5761/overview?reviewViewBy=FAILED&utm_source=github&utm_medium=failed&utm_campaign=failed%20tests">
          <strong>Failures</strong>
        </a>
      </td>
      <td>
        <code><strong>1</strong></code>
      </td>
    </tr>
    <tr />
    <tr height="48">
      <td width="224">
        <img src="https://assets.cypress.io/github-pr-comment-icons/flaky-v3.svg" alt="Tests that were flaky" width="10" height="10" />&nbsp;
        <a href="https://cloud.cypress.io/projects/wf7d2m/runs/5761/overview?reviewViewBy=FLAKY&utm_source=github&utm_medium=failed&utm_campaign=flaky%20tests">
          <strong>Flaky</strong>
        </a>
      </td>
      <td>
        <code><strong>0</strong></code>
      </td>
    </tr>
    <tr />
    <tr height="48">
      <td width="224">
        <img src="https://assets.cypress.io/github-pr-comment-icons/pending.svg" alt="Tests that did not run due to a developer annotating a test with .skip" width="10" height="10" />&nbsp;
        <a href="https://cloud.cypress.io/projects/wf7d2m/runs/5761/test-results?utm_source=github&utm_medium=failed&utm_campaign=pending%20tests&statuses=%5B%7B%22value%22%3A%22PENDING%22%2C%22label%22%3A%22PENDING%22%7D%5D">
          <strong>Pending</strong>
        </a>
      </td>
      <td>
        <code><strong>0</strong></code>
      </td>
    </tr>
    <tr />
    <tr height="48">
      <td width="224">
        <img src="https://assets.cypress.io/github-pr-comment-icons/skipped-v3.svg" alt="Tests that did not run due to a failure in a mocha hook" width="10" height="10" />&nbsp;
        <a href="https://cloud.cypress.io/projects/wf7d2m/runs/5761/test-results?utm_source=github&utm_medium=failed&utm_campaign=skipped%20tests&statuses=%5B%7B%22value%22%3A%22SKIPPED%22%2C%22label%22%3A%22SKIPPED%22%7D%5D">
          <strong>Skipped</strong>
        </a>
      </td>
      <td>
        <code><strong>0</strong></code>
      </td>
    </tr>
    <tr />
    <tr height="48">
      <td width="224">
        <img src="https://assets.cypress.io/github-pr-comment-icons/passed.svg" alt="Tests that passed" width="10" height="10" />&nbsp;
        <a href="https://cloud.cypress.io/projects/wf7d2m/runs/5761/overview?utm_source=github&utm_medium=failed&utm_campaign=passed%20tests">
          <strong>Passing</strong>
        </a>
      </td>
      <td>
        <code><strong>24</strong></code>
      </td>
    </tr><tfoot>
    <tr height="48"><td colspan="2"><a href="https://cloud.cypress.io/projects/wf7d2m/branches/questionnaire-import/review?utm_source=github&utm_medium=failed&utm_campaign=review%20changes&changeRequest=11817">View all changes introduced in this branch ↗︎</a></td></tr></tfoot>
  </tbody>
</table>


<hr></hr>
<h3>
  Tests for review
</h3>
<details>
  <summary><img src="https://assets.cypress.io/github-pr-comment-icons/failed.svg" width="12" height="12" alt="Failed" />&nbsp; <b> cypress/e2e/patient_spec/patient_notes.cy.ts</b> • 1 failed test  </summary>

  <a href='https://cloud.cypress.io/projects/wf7d2m/runs/5761/test-results?utm_source=github&utm_medium=failed&utm_campaign=view%20spec&specs=%5B%7B%22value%22%3A%22%5B%5C%228c24f2af-4b2e-4147-adac-6d552bf78021%5C%22%5D%22%2C%22label%22%3A%22cypress%2Fe2e%2Fpatient_spec%2Fpatient_notes.cy.ts%22%7D%5D'><code>View</code></a> <a href='https://cloud.cypress.io/projects/wf7d2m/runs/5761/test-results/instance/8c24f2af-4b2e-4147-adac-6d552bf78021/stdout?utm_source=github&utm_medium=failed&utm_campaign=view%20spec%20stdout'><code>Output</code></a> 

  <table>
    <tr>
      <th align="left" colspan="2" style="width: 100%">
      Test
      </th>
      <th>Artifacts</th>
    </tr>
      <tr>
        <td colspan="2">
          <a href="https://cloud.cypress.io/projects/wf7d2m/runs/5761/overview/3a39b979-9dcc-4b67-b03d-5df72107c818?reviewViewBy=FAILED&utm_source=github&utm_medium=failed&utm_campaign=view%20test">
            Encounter Notes > Create multiple threads and verify the messages are multi-user contribution supported
          </a>
        </td>
        <td>
          <a href="https://cloud.cypress.io/projects/wf7d2m/runs/5761/test-results/3a39b979-9dcc-4b67-b03d-5df72107c818/replay?utm_source=github&utm_medium=failed&utm_campaign=view%20Test%20Replay">
            <code><b>Test Replay</b></code>
          </a> <a href="https://cloud.cypress.io/projects/wf7d2m/runs/5761/overview/3a39b979-9dcc-4b67-b03d-5df72107c818/screenshots?reviewViewBy=FAILED&utm_source=github&utm_medium=failed&utm_campaign=view%20test%20screenshots">
            <code>Screenshots</code>
          </a>
        </td>
      </tr></table>
  </details>


author_association: NONE
user: login: github-actions[bot]
created_at: 2025-04-09T16:57:17Z
body: @amjithtitus09 Your efforts have helped advance digital healthcare and TeleICU systems. :rocket: Thank you for taking the time out to make CARE better. We hope you continue to innovate and contribute; your impact is immense! :raised_hands:
author_association: NONE