Repository: msupply-foundation/open-msupply
Pull request #6910: 6889 enable insurance tab even when program module off
Author: login: GeronimoJohn
Labels: name: feature: dispensing
Created: 2025-03-12T03:22:33Z | Merged: 2025-03-14T00:52:16Z

<!-- IMPORTANT!
  - Every PR must reference an issue; this helps to explain the intent of the PR
 -->

Fixes #6889 

# 👩🏻‍💻 What does this PR do?

If insuranceProviders are available, the tab should show for insurance, even if the Uses Program Module is turned off.

<!-- Explain the changes you made -->

<!-- why are the changes needed -->

<!-- Add a screenshot if there are UI changes  -->

## 💌 Any notes for the reviewer?

<!-- Do you have any specific questions for the reviewer? -->

<!-- Is there a high risk/complicated change they should focus on? -->

<!-- any general areas of the codebase touched? any side effects caused? -->

<!-- Anything half cooked but going to be finished off in a different PR? -->

Side Quest: I've moved `PatientDetailView` to its own file. `PatientView` had a lot going on for it, navigating can be a bit overwhelming

# 🧪 Testing

<!-- Explain the steps you'd take to test the changes of this PR manually -->

If you have insurance providers in your store and programs module is on
- [ ] Turn off `Open mSupply: Uses Program Module` within legacy mSupply for your store
- [ ] Navigate to a Patient
- [ ] Should be able to see any Programs related component
   - [ ] E.g. programs tab, encounter button in dropdown of `AddButton` 
- [ ] Should be able to navigate to insurance tab and add insurance

If you don't have insurance providers in your store and programs module is off
- [ ] Turn off `Open mSupply: Uses Program Module` within legacy mSupply for your store
- [ ] Navigate to a Patient
- [ ] Should not be able to see any programs related component
- [ ] Should not be able to add insurance or visit insurance tab

If you don't have insurance providers in your store but programs module is on
- [ ] Navigate to a Patient
- [ ] Should be able to see any Programs related component
   - [ ] E.g. programs tab, encounter button in dropdown of `AddButton` 
- [ ] Should not be able to navigate to insurance tab or add insurance

# 📃 Documentation

- [ ] **Part of an epic**: documentation will be completed for the feature as a whole
- [ ] **No documentation required**: no user facing changes or a bug fix which isn't a change in behaviour
- [ ] **These areas should be updated or checked**: <!-- _(e.g.)_ New `issued` column in `Requisitions` indicates stock quantity already in shipments -->
  1.
  2.


# 📃 Reviewer Checklist

The PR Reviewer(s) should fill out this section before approving the PR

**Breaking Changes**
- [ ] No Breaking Changes in the Graphql API
- [ ] Technically some Breaking Changes but not expected to impact any integrations

**Issue Review**
- [ ] All requirements in original issue have been covered
- [ ] A follow up issue(s) have been created to cover additional requirements

**Tests Pass**
- [ ] Postgres
- [ ] SQLite
- [ ] Frontend



Linked issue #6889: Patient Insurance isn't available without the `uses Om Program Module` store pref
## What went wrong? 😲

There's a note in the code but we obviously missed it :(

```
      {/* Only show tabs if program module is on and patient is saved.
      TODO: Prescription tab? - would need tab refactoring since also seems useful in programs
      */}
      {!createNewPatient && store?.preferences.omProgramModule ? (
        <DetailTabs tabs={tabs} requiresConfirmation={requiresConfirmation} />
      ) : (
        <PatientDetailView onEdit={setIsDirtyPatient} />
      )}
```


![Image](https://github.com/user-attachments/assets/ea376af9-9255-4a51-8bd5-2081d22cd919)

## Expected behaviour 🤔

If insuranceProviders are available, the tab should show for insurance, even if the `Uses Program Module` is turned off

## How to Reproduce 🔨

Steps to reproduce the behaviour:

1. Turn off `Open mSupply: Uses Program Module`
2. Go to Patients
3. Try to add Insurnace

## Your environment 🌱

<!-- e.g. 1.2.3 -->

- Open mSupply Version: 2.6.0
- Legacy mSupply Central Server Version:
<!-- e.g. android, browser (extra points if you tell us which one), desktop (windows), desktop (macOS), server (windows) -->
- Platform:
<!-- PostgreSQL or SQLite3 -->
- Database type:

Linked issue comments: user: login: alainsussol
created_at: 2025-03-14T22:16:38Z
body: If you have insurance providers in your store and programs module is on 
- [x] Navigate to a Patient
- [x] Should be able to see any Programs related component **-PASS-**
   - [x] E.g. programs tab, encounter button in dropdown of `AddButton`  
- [x] Should be able to navigate to insurance tab and add insurance **-PASS-**

If you have insurance providers in your store and programs module is off 
- [x] Navigate to a Patient
- [x] Shouldn't be able to see any Programs related component **-PASS-**
   - [x] E.g. programs tab, encounter button in dropdown of `AddButton`  
- [x] Should be able to navigate to insurance tab and add insurance **-PASS-**

If you don't have insurance providers in your store and programs module is off
- [x] Navigate to a Patient
- [x] Should not be able to see any programs related component **-PASS-**
- [x] Should not be able to add insurance or visit insurance tab **-PASS-**
 
If you don't have insurance providers in your store but programs module is on
- [x] Navigate to a Patient
- [x] Should be able to see any Programs related component  **-PASS-**
   - [x] E.g. programs tab, encounter button in dropdown of `AddButton` 
- [x] Should not be able to navigate to insurance tab or add insurance **-PASS-**

author_association: NONE

Diff:
diff --git a/client/packages/system/src/Patient/PatientView/AddButton.tsx b/client/packages/system/src/Patient/PatientView/AddButton.tsx
index d15eb87de64..311952decbd 100644
--- a/client/packages/system/src/Patient/PatientView/AddButton.tsx
+++ b/client/packages/system/src/Patient/PatientView/AddButton.tsx
@@ -5,77 +5,91 @@ import {
   SplitButtonOption,
   PlusCircleIcon,
   useUrlQuery,
+  UserStoreNodeFragment,
 } from '@openmsupply-client/common';
 import {
   PatientModal,
   usePatientModalStore,
+  usePatientStore,
 } from '@openmsupply-client/programs';
 import { PatientTabValue } from './PatientView';
+import { useInsuranceProviders } from '../apiModern';
 
 interface AddButtonProps {
   /** Disable the whole control */
   disabled: boolean;
   disableEncounterButton: boolean;
+  store?: UserStoreNodeFragment;
 }
 
 export const AddButton: React.FC<AddButtonProps> = ({
   disabled,
   disableEncounterButton,
+  store,
 }) => {
   const t = useTranslation();
   const { urlQuery, updateQuery } = useUrlQuery();
   const currentUrlTab = urlQuery['tab'];
+  const { createNewPatient } = usePatientStore();
   const { setModal: selectModal, reset } = usePatientModalStore();
+  const {
+    query: { data: insuranceProvidersData },
+  } = useInsuranceProviders();
 
-  const options: [
-    SplitButtonOption<PatientModal>,
-    SplitButtonOption<PatientModal>,
-    SplitButtonOption<PatientModal>,
-    SplitButtonOption<PatientModal>,
-  ] = useMemo(
-    () => [
-      {
-        value: PatientModal.ProgramSearch,
-        label: t('button.add-program'),
-        isDisabled: false,
-      },
-      {
-        value: PatientModal.Encounter,
-        label: t('button.add-encounter'),
-        isDisabled: disableEncounterButton,
-      },
-      {
-        value: PatientModal.ContactTraceSearch,
-        label: t('button.add-contact-trace'),
-      },
-      { value: PatientModal.Insurance, label: t('button.add-insurance') },
-    ],
-    [disableEncounterButton, t]
-  );
-  const [programOption, encounterOption, contactTraceOption, insuranceOption] =
-    options;
+  const options: SplitButtonOption<PatientModal>[] = useMemo(() => {
+    const baseOptions: SplitButtonOption<PatientModal>[] = [];
+
+    if (store?.preferences.omProgramModule) {
+      baseOptions.push(
+        {
+          value: PatientModal.ProgramSearch,
+          label: t('button.add-program'),
+          isDisabled: false,
+        },
+        {
+          value: PatientModal.Encounter,
+          label: t('button.add-encounter'),
+          isDisabled: disableEncounterButton,
+        },
+        {
+          value: PatientModal.ContactTraceSearch,
+          label: t('button.add-contact-trace'),
+        }
+      );
+    }
+
+    if (insuranceProvidersData?.length > 0) {
+      baseOptions.push({
+        value: PatientModal.Insurance,
+        label: t('button.add-insurance'),
+      });
+    }
+
+    return baseOptions;
+  }, [disableEncounterButton, t, store, insuranceProvidersData]);
 
   const [selectedOption, setSelectedOption] = useState<
-    SplitButtonOption<PatientModal>
+    SplitButtonOption<PatientModal> | undefined
   >(options[0]);
 
+  const optionMap: Partial<Record<PatientTabValue, PatientModal>> = {
+    [PatientTabValue.Programs]: PatientModal.ProgramSearch,
+    [PatientTabValue.Vaccinations]: PatientModal.ProgramSearch,
+    [PatientTabValue.Encounters]: PatientModal.Encounter,
+    [PatientTabValue.ContactTracing]: PatientModal.ContactTraceSearch,
+    [PatientTabValue.Insurance]: PatientModal.Insurance,
+  };
+
   useEffect(() => {
-    switch (currentUrlTab) {
-      case PatientTabValue.Programs:
-      case PatientTabValue.Vaccinations:
-        setSelectedOption(programOption);
-        break;
-      case PatientTabValue.Encounters:
-        setSelectedOption(encounterOption);
-        break;
-      case PatientTabValue.ContactTracing:
-        setSelectedOption(contactTraceOption);
-        break;
-      case PatientTabValue.Insurance:
-        setSelectedOption(insuranceOption);
-        break;
-    }
-  }, [contactTraceOption, currentUrlTab, encounterOption, programOption]);
+    if (options.length === 0) return;
+
+    setSelectedOption(
+      options.find(
+        option => option.value === optionMap[currentUrlTab as PatientTabValue]
+      ) || options[0]
+    );
+    // eslint-disable-next-line react-hooks/exhaustive-deps
+  }, [currentUrlTab, options]);
 
   const onSelectOption = (option: SplitButtonOption<PatientModal>) => {
     updateQuery({ insuranceId: undefined });
@@ -90,18 +104,16 @@ export const AddButton: React.FC<AddButtonProps> = ({
     selectModal(selectedOption?.value);
   };
 
-  return (
-    <>
-      <SplitButton
-        color="primary"
-        openFrom={'bottom'}
-        isDisabled={disabled}
-        options={options}
-        selectedOption={selectedOption}
-        onSelectOption={onSelectOption}
-        Icon={<PlusCircleIcon />}
-        onClick={onClick}
-      />
-    </>
-  );
+  return options.length > 0 && selectedOption && !createNewPatient ? (
+    <SplitButton
+      color="primary"
+      openFrom={'bottom'}
+      isDisabled={disabled}
+      options={options}
+      selectedOption={selectedOption}
+      onSelectOption={onSelectOption}
+      Icon={<PlusCircleIcon />}
+      onClick={onClick}
+    />
+  ) : null;
 };
diff --git a/client/packages/system/src/Patient/PatientView/AppBarButtons.tsx b/client/packages/system/src/Patient/PatientView/AppBarButtons.tsx
index 641e18494a0..d81cb6a539f 100644
--- a/client/packages/system/src/Patient/PatientView/AppBarButtons.tsx
+++ b/client/packages/system/src/Patient/PatientView/AppBarButtons.tsx
@@ -36,26 +36,26 @@ export const AppBarButtons: FC<{
     },
   });
   const disableEncounterButton = enrolmentData?.nodes?.length === 0;
-  if (!store?.preferences.omProgramModule) return null;
 
   return (
     <AppBarButtonsPortal>
       <Grid container gap={1}>
+        <AddButton
+          disabled={disabled}
+          disableEncounterButton={disableEncounterButton}
+          store={store}
+        />
         {store?.preferences.omProgramModule && (
-          <AddButton
-            disabled={disabled}
-            disableEncounterButton={disableEncounterButton}
-          />
+          <ReportSelector context={ReportContext.Patient} onPrint={printReport}>
+            <LoadingButton
+              disabled={disabled}
+              variant="outlined"
+              startIcon={<PrinterIcon />}
+              isLoading={isPrinting}
+              label={t('button.print')}
+            />
+          </ReportSelector>
         )}
-        <ReportSelector context={ReportContext.Patient} onPrint={printReport}>
-          <LoadingButton
-            disabled={disabled}
-            variant="outlined"
-            startIcon={<PrinterIcon />}
-            isLoading={isPrinting}
-            label={t('button.print')}
-          />
-        </ReportSelector>
       </Grid>
     </AppBarButtonsPortal>
   );
diff --git a/client/packages/system/src/Patient/PatientView/PatientDetailView.tsx b/client/packages/system/src/Patient/PatientView/PatientDetailView.tsx
new file mode 100644
index 00000000000..6874161c05f
--- /dev/null
+++ b/client/packages/system/src/Patient/PatientView/PatientDetailView.tsx
@@ -0,0 +1,284 @@
+import React, { useCallback, useEffect, useMemo } from 'react';
+import {
+  useConfirmationModal,
+  Box,
+  useTranslation,
+  InsertPatientInput,
+  UpdatePatientInput,
+  BasicSpinner,
+  DocumentRegistryCategoryNode,
+  useNavigate,
+  RouteBuilder,
+  FnUtils,
+  useUrlQuery,
+} from '@openmsupply-client/common';
+import { AppRoute } from '@openmsupply-client/config';
+import { usePatient } from '../api';
+import {
+  JsonFormData,
+  FormInputData,
+  SaveDocumentMutation,
+  SavedDocument,
+  SchemaData,
+  useDocumentRegistry,
+  useJsonFormsHandler,
+  usePatientStore,
+  PatientSchema,
+} from '@openmsupply-client/programs';
+import { Footer } from './Footer';
+
+import defaultPatientSchema from './DefaultPatientSchema.json';
+import defaultPatientUISchema from './DefaultPatientUISchema.json';
+import { usePrescription } from '@openmsupply-client/invoices/src/Prescriptions';
+
+const DEFAULT_SCHEMA: SchemaData = {
+  formSchemaId: undefined,
+  jsonSchema: defaultPatientSchema,
+  uiSchema: defaultPatientUISchema,
+};
+
+const useUpsertPatient = (
+  create: boolean
+): ((input: unknown) => Promise<void>) => {
+  const { mutateAsync: insertPatient } = usePatient.document.insert();
+  const { mutateAsync: updatePatient } = usePatient.document.update();
+  return async (input: unknown) => {
+    if (create) {
+      await insertPatient(input as InsertPatientInput);
+    } else {
+      await updatePatient(input as UpdatePatientInput);
+    }
+  };
+};
+
+const useUpsertProgramPatient = (): SaveDocumentMutation => {
+  const { mutateAsync: insertPatient } =
+    usePatient.document.insertProgramPatient();
+  const { mutateAsync: updatePatient } =
+    usePatient.document.updateProgramPatient();
+  return async (jsonData: unknown, schemaId: string, parent?: string) => {
+    if (parent === undefined) {
+      const result = await insertPatient({
+        data: jsonData,
+        schemaId,
+      });
+      if (!result.document) throw Error('Inserted document not set!');
+      return result.document;
+    } else {
+      const result = await updatePatient({
+        data: jsonData,
+        parent,
+        schemaId,
+      });
+      if (!result.document) throw Error('Inserted document not set!');
+      return result.document;
+    }
+  };
+};
+
+export const PatientDetailView = ({
+  onEdit,
+}: {
+  onEdit: (isDirty: boolean) => void;
+}) => {
+  const t = useTranslation();
+  const {
+    documentName,
+    setDocumentName,
+    createNewPatient,
+    setCreateNewPatient,
+  } = usePatientStore();
+
+  const navigate = useNavigate();
+  const { urlQuery } = useUrlQuery();
+  const fromPrescription = urlQuery['previousPath'] === AppRoute.Prescription;
+
+  const patientId = usePatient.utils.id();
+  const { data: currentPatient, isLoading: isCurrentPatientLoading } =
+    usePatient.document.get(patientId);
+  const { data: patientRegistries, isLoading: isPatientRegistryLoading } =
+    useDocumentRegistry.get.documentRegistries({
+      filter: {
+        category: { equalTo: DocumentRegistryCategoryNode.Patient },
+      },
+    });
+  const {
+    create: { create: createPrescription },
+  } = usePrescription();
+
+  const isLoading = isCurrentPatientLoading || isPatientRegistryLoading;
+
+  const patientRegistry = patientRegistries?.nodes[0];
+  const isCreatingPatient = !!createNewPatient;
+  // we have to memo the data to avoid an infinite render loop
+  const inputData = useMemo<FormInputData | undefined>(() => {
+    if (!!createNewPatient) {
+      // Use the unsaved patient information from createNewPatient, i.e. from a "create patient"
+      // request
+      return {
+        schema: patientRegistry ?? DEFAULT_SCHEMA,
+        data: {
+          id: createNewPatient.id,
+          code: createNewPatient.code,
+          code2: createNewPatient.code2,
+          firstName: createNewPatient.firstName,
+          lastName: createNewPatient.lastName,
+          gender: createNewPatient.gender,
+          dateOfBirth: createNewPatient.dateOfBirth,
+          phone: createNewPatient.phone,
+          address1: createNewPatient.address1,
+          isDeceased: createNewPatient.isDeceased,
+          dateOfDeath: createNewPatient.dateOfDeath,
+          extension: {},
+        },
+        isCreating: true,
+      };
+    } else if (!!currentPatient && !currentPatient.document) {
+      // The loaded patient doesn't has a document. Use the information we got
+      // (from the name table).
+      return {
+        schema: patientRegistry ?? DEFAULT_SCHEMA,
+        data: {
+          id: currentPatient.id,
+          code: currentPatient.code,
+          code2: currentPatient.code2 ?? undefined,
+          firstName: currentPatient.firstName ?? undefined,
+          lastName: currentPatient.lastName ?? undefined,
+          gender: currentPatient.gender ?? undefined,
+          dateOfBirth: currentPatient.dateOfBirth ?? undefined,
+          dateOfDeath: currentPatient.dateOfDeath ?? undefined,
+          isDeceased: currentPatient.isDeceased ?? undefined,
+          phone: currentPatient.phone ?? undefined,
+          address1: currentPatient.address1 ?? undefined,
+          nextOfKin:
+            currentPatient.nextOfKinId || currentPatient.nextOfKinName
+              ? {
+                  id: currentPatient.nextOfKinId ?? undefined,
+                  name: currentPatient.nextOfKinName ?? undefined,
+                }
+              : undefined,
+          extension: {},
+        },
+        isCreating: false,
+      };
+    } else if (currentPatient?.document) {
+      // Take the data from the document
+      return {
+        schema: patientRegistry ?? DEFAULT_SCHEMA,
+        data: currentPatient.documentDraft,
+        isCreating: false,
+      };
+    }
+  }, [createNewPatient, currentPatient, patientRegistry]);
+
+  const handleProgramPatientSave = useUpsertProgramPatient();
+  const handlePatientSave = useUpsertPatient(isCreatingPatient);
+
+  const accessor: JsonFormData<SavedDocument | void> = patientRegistry
+    ? {
+        loadedData: inputData?.data,
+        isLoading: false,
+        error: undefined,
+        isCreating: isCreatingPatient,
+        schema: patientRegistry,
+        save: async (data: unknown) => {
+          await handleProgramPatientSave(
+            data,
+            patientRegistry.formSchemaId,
+            currentPatient?.document?.id
+          );
+        },
+      }
+    : {
+        loadedData: inputData?.data,
+        isLoading: false,
+        error: undefined,
+        isCreating: isCreatingPatient,
+        schema: DEFAULT_SCHEMA,
+        save: async (data: unknown) => {
+          const patientData = data as PatientSchema;
+          const newData = Object.fromEntries(
+            Object.entries(data ?? {}).filter(
+              ([key]) =>
+                key !== 'dateOfBirthIsEstimated' &&
+                key !== 'nextOfKin' &&
+                key !== 'extension'
+            )
+          );
+          // map nextOfKin object to individual fields
+          await handlePatientSave({
+            ...newData,
+            nextOfKinId: patientData?.nextOfKin?.id,
+            nextOfKinName: patientData?.nextOfKin?.name,
+          });
+        },
+      };
+
+  const { JsonForm, saveData, isSaving, isDirty, validationError } =
+    useJsonFormsHandler(
+      {
+        documentName: createNewPatient ? undefined : documentName,
+        patientId: patientId,
+      },
+      accessor
+    );
+
+  useEffect(() => {
+    return () => setCreateNewPatient(undefined);
+  }, [setCreateNewPatient]);
+
+  const save = useCallback(async () => {
+    const savedDocument = await saveData();
+    // patient has been created => unset the create request data
+    setCreateNewPatient(undefined);
+    if (savedDocument) {
+      setDocumentName(savedDocument.name);
+    }
+    // Creates a new prescription and redirects to the prescriptions page
+    // if the patient was created from there.
+    if (fromPrescription) {
+      const invoiceNumber = await createPrescription({
+        id: FnUtils.generateUUID(),
+        patientId,
+      });
+      navigate(
+        RouteBuilder.create(AppRoute.Dispensary)
+          .addPart(AppRoute.Prescription)
+          .addPart(String(invoiceNumber))
+          .build()
+      );
+    }
+  }, [saveData, setCreateNewPatient, setDocumentName]);
+
+  useEffect(() => {
+    if (!documentName && currentPatient) {
+      setDocumentName(currentPatient?.document?.name);
+    }
+  }, [currentPatient, documentName, setDocumentName]);
+
+  useEffect(() => {
+    onEdit(isDirty);
+  }, [isDirty, onEdit]);
+
+  const showSaveConfirmation = useConfirmationModal({
+    onConfirm: save,
+    message: t('messages.confirm-save-generic'),
+    title: t('heading.are-you-sure'),
+  });
+
+  if (isLoading) return <BasicSpinner />;
+
+  return (
+    <Box flex={1} display="flex" justifyContent="center">
+      <Box style={{ maxWidth: 1200, flex: 1 }}>{JsonForm}</Box>
+      <Footer
+        documentName={documentName}
+        isSaving={isSaving}
+        isDirty={isDirty}
+        validationError={validationError}
+        inputData={inputData}
+        showSaveConfirmation={showSaveConfirmation}
+      />
+    </Box>
+  );
+};
diff --git a/client/packages/system/src/Patient/PatientView/PatientView.tsx b/client/packages/system/src/Patient/PatientView/PatientView.tsx
index 04761897e1c..33cdf1766ea 100644
--- a/client/packages/system/src/Patient/PatientView/PatientView.tsx
+++ b/client/packages/system/src/Patient/PatientView/PatientView.tsx
@@ -1,304 +1,31 @@
-import React, { useCallback, useEffect, useMemo, useState } from 'react';
+import React, { useEffect, useState } from 'react';
 import {
   DetailTabs,
   DetailViewSkeleton,
-  useConfirmationModal,
-  Box,
-  useTranslation,
   EncounterSortFieldInput,
   ProgramEnrolmentSortFieldInput,
   useAuthContext,
-  InsertPatientInput,
   ContactTraceSortFieldInput,
-  UpdatePatientInput,
-  BasicSpinner,
-  DocumentRegistryCategoryNode,
-  useNavigate,
-  RouteBuilder,
-  FnUtils,
-  useUrlQuery,
+  TabDefinition,
 } from '@openmsupply-client/common';
-import { AppRoute } from '@openmsupply-client/config';
 import { usePatient } from '../api';
 import { AppBarButtons } from './AppBarButtons';
 import { PatientSummary } from './PatientSummary';
 import { ProgramDetailModal, ProgramListView } from '../ProgramEnrolment';
 import { CreateEncounterModal, EncounterListView } from '../Encounter';
 import {
-  JsonFormData,
-  FormInputData,
   PatientModal,
   ProgramSearchModal,
-  SaveDocumentMutation,
-  SavedDocument,
-  SchemaData,
-  useDocumentRegistry,
-  useJsonFormsHandler,
   usePatientModalStore,
   usePatientStore,
   useProgramEnrolments,
-  PatientSchema,
 } from '@openmsupply-client/programs';
-import { Footer } from './Footer';
 import { ContactTraceListView, CreateContactTraceModal } from '../ContactTrace';
 
-import defaultPatientSchema from './DefaultPatientSchema.json';
-import defaultPatientUISchema from './DefaultPatientUISchema.json';
 import { VaccinationCardsListView } from '../VaccinationCard/ListView';
-import { usePrescription } from '@openmsupply-client/invoices/src/Prescriptions';
 import { InsuranceListView, InsuranceModal } from '../Insurance';
-
-const DEFAULT_SCHEMA: SchemaData = {
-  formSchemaId: undefined,
-  jsonSchema: defaultPatientSchema,
-  uiSchema: defaultPatientUISchema,
-};
-
-const useUpsertPatient = (
-  create: boolean
-): ((input: unknown) => Promise<void>) => {
-  const { mutateAsync: insertPatient } = usePatient.document.insert();
-  const { mutateAsync: updatePatient } = usePatient.document.update();
-  return async (input: unknown) => {
-    if (create) {
-      await insertPatient(input as InsertPatientInput);
-    } else {
-      await updatePatient(input as UpdatePatientInput);
-    }
-  };
-};
-
-const useUpsertProgramPatient = (): SaveDocumentMutation => {
-  const { mutateAsync: insertPatient } =
-    usePatient.document.insertProgramPatient();
-  const { mutateAsync: updatePatient } =
-    usePatient.document.updateProgramPatient();
-  return async (jsonData: unknown, schemaId: string, parent?: string) => {
-    if (parent === undefined) {
-      const result = await insertPatient({
-        data: jsonData,
-        schemaId,
-      });
-      if (!result.document) throw Error('Inserted document not set!');
-      return result.document;
-    } else {
-      const result = await updatePatient({
-        data: jsonData,
-        parent,
-        schemaId,
-      });
-      if (!result.document) throw Error('Inserted document not set!');
-      return result.document;
-    }
-  };
-};
-
-const PatientDetailView = ({
-  onEdit,
-}: {
-  onEdit: (isDirty: boolean) => void;
-}) => {
-  const t = useTranslation();
-  const {
-    documentName,
-    setDocumentName,
-    createNewPatient,
-    setCreateNewPatient,
-  } = usePatientStore();
-
-  const navigate = useNavigate();
-  const { urlQuery } = useUrlQuery();
-  const fromPrescription = urlQuery['previousPath'] === AppRoute.Prescription;
-
-  const patientId = usePatient.utils.id();
-  const { data: currentPatient, isLoading: isCurrentPatientLoading } =
-    usePatient.document.get(patientId);
-  const { data: patientRegistries, isLoading: isPatientRegistryLoading } =
-    useDocumentRegistry.get.documentRegistries({
-      filter: {
-        category: { equalTo: DocumentRegistryCategoryNode.Patient },
-      },
-    });
-  const {
-    create: { create: createPrescription },
-  } = usePrescription();
-
-  const isLoading = isCurrentPatientLoading || isPatientRegistryLoading;
-
-  const patientRegistry = patientRegistries?.nodes[0];
-  const isCreatingPatient = !!createNewPatient;
-  // we have to memo the data to avoid an infinite render loop
-  const inputData = useMemo<FormInputData | undefined>(() => {
-    if (!!createNewPatient) {
-      // Use the unsaved patient information from createNewPatient, i.e. from a "create patient"
-      // request
-      return {
-        schema: patientRegistry ?? DEFAULT_SCHEMA,
-        data: {
-          id: createNewPatient.id,
-          code: createNewPatient.code,
-          code2: createNewPatient.code2,
-          firstName: createNewPatient.firstName,
-          lastName: createNewPatient.lastName,
-          gender: createNewPatient.gender,
-          dateOfBirth: createNewPatient.dateOfBirth,
-          phone: createNewPatient.phone,
-          address1: createNewPatient.address1,
-          isDeceased: createNewPatient.isDeceased,
-          dateOfDeath: createNewPatient.dateOfDeath,
-          extension: {},
-        },
-        isCreating: true,
-      };
-    } else if (!!currentPatient && !currentPatient.document) {
-      // The loaded patient doesn't has a document. Use the information we got
-      // (from the name table).
-      return {
-        schema: patientRegistry ?? DEFAULT_SCHEMA,
-        data: {
-          id: currentPatient.id,
-          code: currentPatient.code,
-          code2: currentPatient.code2 ?? undefined,
-          firstName: currentPatient.firstName ?? undefined,
-          lastName: currentPatient.lastName ?? undefined,
-          gender: currentPatient.gender ?? undefined,
-          dateOfBirth: currentPatient.dateOfBirth ?? undefined,
-          dateOfDeath: currentPatient.dateOfDeath ?? undefined,
-          isDeceased: currentPatient.isDeceased ?? undefined,
-          phone: currentPatient.phone ?? undefined,
-          address1: currentPatient.address1 ?? undefined,
-          nextOfKin:
-            currentPatient.nextOfKinId || currentPatient.nextOfKinName
-              ? {
-                  id: currentPatient.nextOfKinId ?? undefined,
-                  name: currentPatient.nextOfKinName ?? undefined,
-                }
-              : undefined,
-          extension: {},
-        },
-        isCreating: false,
-      };
-    } else if (currentPatient?.document) {
-      // Take the data from the document
-      return {
-        schema: patientRegistry ?? DEFAULT_SCHEMA,
-        data: currentPatient.documentDraft,
-        isCreating: false,
-      };
-    }
-  }, [createNewPatient, currentPatient, patientRegistry]);
-
-  const handleProgramPatientSave = useUpsertProgramPatient();
-  const handlePatientSave = useUpsertPatient(isCreatingPatient);
-
-  const accessor: JsonFormData<SavedDocument | void> = patientRegistry
-    ? {
-        loadedData: inputData?.data,
-        isLoading: false,
-        error: undefined,
-        isCreating: isCreatingPatient,
-        schema: patientRegistry,
-        save: async (data: unknown) => {
-          await handleProgramPatientSave(
-            data,
-            patientRegistry.formSchemaId,
-            currentPatient?.document?.id
-          );
-        },
-      }
-    : {
-        loadedData: inputData?.data,
-        isLoading: false,
-        error: undefined,
-        isCreating: isCreatingPatient,
-        schema: DEFAULT_SCHEMA,
-        save: async (data: unknown) => {
-          const patientData = data as PatientSchema;
-          const newData = Object.fromEntries(
-            Object.entries(data ?? {}).filter(
-              ([key]) =>
-                key !== 'dateOfBirthIsEstimated' &&
-                key !== 'nextOfKin' &&
-                key !== 'extension'
-            )
-          );
-          // map nextOfKin object to individual fields
-          await handlePatientSave({
-            ...newData,
-            nextOfKinId: patientData?.nextOfKin?.id,
-            nextOfKinName: patientData?.nextOfKin?.name,
-          });
-        },
-      };
-
-  const { JsonForm, saveData, isSaving, isDirty, validationError } =
-    useJsonFormsHandler(
-      {
-        documentName: createNewPatient ? undefined : documentName,
-        patientId: patientId,
-      },
-      accessor
-    );
-
-  useEffect(() => {
-    return () => setCreateNewPatient(undefined);
-  }, [setCreateNewPatient]);
-
-  const save = useCallback(async () => {
-    const savedDocument = await saveData();
-    // patient has been created => unset the create request data
-    setCreateNewPatient(undefined);
-    if (savedDocument) {
-      setDocumentName(savedDocument.name);
-    }
-    // Creates a new prescription and redirects to the prescriptions page
-    // if the patient was created from there.
-    if (fromPrescription) {
-      const invoiceNumber = await createPrescription({
-        id: FnUtils.generateUUID(),
-        patientId,
-      });
-      navigate(
-        RouteBuilder.create(AppRoute.Dispensary)
-          .addPart(AppRoute.Prescription)
-          .addPart(String(invoiceNumber))
-          .build()
-      );
-    }
-  }, [saveData, setCreateNewPatient, setDocumentName]);
-
-  useEffect(() => {
-    if (!documentName && currentPatient) {
-      setDocumentName(currentPatient?.document?.name);
-    }
-  }, [currentPatient, documentName, setDocumentName]);
-
-  useEffect(() => {
-    onEdit(isDirty);
-  }, [isDirty, onEdit]);
-
-  const showSaveConfirmation = useConfirmationModal({
-    onConfirm: save,
-    message: t('messages.confirm-save-generic'),
-    title: t('heading.are-you-sure'),
-  });
-
-  if (isLoading) return <BasicSpinner />;
-
-  return (
-    <Box flex={1} display="flex" justifyContent="center">
-      <Box style={{ maxWidth: 1200, flex: 1 }}>{JsonForm}</Box>
-      <Footer
-        documentName={documentName}
-        isSaving={isSaving}
-        isDirty={isDirty}
-        validationError={validationError}
-        inputData={inputData}
-        showSaveConfirmation={showSaveConfirmation}
-      />
-    </Box>
-  );
-};
+import { PatientDetailView } from './PatientDetailView';
+import { useInsuranceProviders } from '../apiModern';
 
 export enum PatientTabValue {
   Details = 'details',
@@ -309,9 +36,6 @@ export enum PatientTabValue {
   Insurance = 'insurance',
 }
 
-/**
- * Main patient view containing patient details and program tabs
- */
 export const PatientView = () => {
   const { current, setCreationModal, reset } = usePatientModalStore();
   const patientId = usePatient.utils.id();
@@ -323,6 +47,10 @@ export const PatientView = () => {
   const [isDirtyPatient, setIsDirtyPatient] = useState(false);
   const { store, storeId } = useAuthContext();
 
+  const {
+    query: { data: insuranceProvidersData },
+  } = useInsuranceProviders();
+
   const requiresConfirmation = (tab: string) => {
     return tab === PatientTabValue.Details && isDirtyPatient;
   };
@@ -332,12 +60,7 @@ export const PatientView = () => {
     setCurrentPatient(currentPatient);
   }, [currentPatient, setCurrentPatient]);
 
-  const tabs = [
-    {
-      Component: <PatientDetailView onEdit={setIsDirtyPatient} />,
-      value: PatientTabValue.Details,
-      confirmOnLeaving: isDirtyPatient,
-    },
+  const programTabs: TabDefinition[] = [
     {
       Component: <ProgramListView />,
       value: PatientTabValue.Programs,
@@ -370,16 +93,38 @@ export const PatientView = () => {
         dir: 'desc' as 'desc' | 'asc',
       },
     },
+  ];
+
+  const tabs: TabDefinition[] = [
     {
-      Component: <InsuranceListView />,
-      value: PatientTabValue.Insurance,
+      Component: <PatientDetailView onEdit={setIsDirtyPatient} />,
+      value: PatientTabValue.Details,
+      confirmOnLeaving: isDirtyPatient,
     },
   ];
 
-  // Note: unmount modals when not used because they have some internal state
-  // that shouldn't be reused across calls.
+  // Display program tabs only if the Program module is enabled and the patient is saved
+  if (store?.preferences.omProgramModule) tabs.push(...programTabs);
+
+  // Display insurance tab only if insurance providers are available and the patient is saved
+  if (insuranceProvidersData.length > 0)
+    tabs.push({
+      Component: <InsuranceListView />,
+      value: PatientTabValue.Insurance,
+    });
+
   return (
     <React.Suspense fallback={<DetailViewSkeleton />}>
+      <AppBarButtons disabled={!!createNewPatient} store={store} />
+      <PatientSummary />
+      {/* Renders specific tabs on specific cases */}
+      {!createNewPatient ? (
+        <DetailTabs tabs={tabs} requiresConfirmation={requiresConfirmation} />
+      ) : (
+        <PatientDetailView onEdit={setIsDirtyPatient} />
+      )}
+      {/* Note: unmount modals when not used because they have some internal
+      state that shouldn't be reused across calls. */}
       {current === PatientModal.Program ? <ProgramDetailModal /> : null}
       {current === PatientModal.Encounter ? <CreateEncounterModal /> : null}
       {current === PatientModal.ProgramSearch ? (
@@ -409,17 +154,6 @@ export const PatientView = () => {
         <CreateContactTraceModal />
       ) : null}
       {current === PatientModal.Insurance ? <InsuranceModal /> : null}
-
-      <AppBarButtons disabled={!!createNewPatient} store={store} />
-      <PatientSummary />
-      {/* Only show tabs if program module is on and patient is saved.
-      TODO: Prescription tab? - would need tab refactoring since also seems useful in programs
-      */}
-      {!createNewPatient && store?.preferences.omProgramModule ? (
-        <DetailTabs tabs={tabs} requiresConfirmation={requiresConfirmation} />
-      ) : (
-        <PatientDetailView onEdit={setIsDirtyPatient} />
-      )}
     </React.Suspense>
   );
 };


Reviews:
user: login: GeronimoJohn
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-12T03:23:26Z
user: login: GeronimoJohn
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-12T03:29:32Z
user: login: CarlosNZ
body: Looking good, @GeronimoJohn -- working as intended. Couple of minor stylistic comments, up to you really.
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-12T21:09:36Z
user: login: GeronimoJohn
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-12T21:26:34Z
user: login: GeronimoJohn
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-12T22:37:16Z
user: login: CarlosNZ
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-12T23:47:36Z
user: login: CarlosNZ
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-12T23:48:28Z
user: login: GeronimoJohn
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-13T21:08:42Z
user: login: CarlosNZ
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-13T22:19:15Z
user: login: CarlosNZ
body: LGTM! Thanks @GeronimoJohn 

(P.S. I think you could put the `optionsMap` outside the function if it were at the top, but it's not a big deal either way)
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-03-13T22:24:40Z

Review comments:
path: client/packages/system/src/Patient/PatientView/PatientDetailView.tsx
user: login: GeronimoJohn
body: Extracted `PatientDetailView` into it's own file as `PatientView` can be a bit overwhelming to navigate
created_at: 2025-03-12T03:23:26Z
author_association: CONTRIBUTOR
diff_hunk: @@ -5,77 +5,98 @@ import {
   SplitButtonOption,
   PlusCircleIcon,
   useUrlQuery,
+  UserStoreNodeFragment,
 } from '@openmsupply-client/common';
 import {
   PatientModal,
   usePatientModalStore,
+  usePatientStore,
 } from '@openmsupply-client/programs';
 import { PatientTabValue } from './PatientView';
+import { useInsuranceProviders } from '../apiModern';
 
 interface AddButtonProps {
   /** Disable the whole control */
   disabled: boolean;
   disableEncounterButton: boolean;
+  store?: UserStoreNodeFragment;
 }
 
 export const AddButton: React.FC<AddButtonProps> = ({
   disabled,
   disableEncounterButton,
+  store,
 }) => {
   const t = useTranslation();
   const { urlQuery, updateQuery } = useUrlQuery();
   const currentUrlTab = urlQuery['tab'];
+  const { createNewPatient } = usePatientStore();
   const { setModal: selectModal, reset } = usePatientModalStore();
+  const {
+    query: { data: InsuranceProvidersData },
+  } = useInsuranceProviders();
 
-  const options: [
-    SplitButtonOption<PatientModal>,
-    SplitButtonOption<PatientModal>,
-    SplitButtonOption<PatientModal>,
-    SplitButtonOption<PatientModal>,
-  ] = useMemo(
-    () => [
-      {
-        value: PatientModal.ProgramSearch,
-        label: t('button.add-program'),
-        isDisabled: false,
-      },
-      {
-        value: PatientModal.Encounter,
-        label: t('button.add-encounter'),
-        isDisabled: disableEncounterButton,
-      },
-      {
-        value: PatientModal.ContactTraceSearch,
-        label: t('button.add-contact-trace'),
-      },
-      { value: PatientModal.Insurance, label: t('button.add-insurance') },
-    ],
-    [disableEncounterButton, t]
-  );
-  const [programOption, encounterOption, contactTraceOption, insuranceOption] =
-    options;
+  const options: SplitButtonOption<PatientModal>[] = useMemo(() => {
+    const baseOptions: SplitButtonOption<PatientModal>[] = [];
+
+    if (store?.preferences.omProgramModule) {
+      baseOptions.push(
+        {
+          value: PatientModal.ProgramSearch,
+          label: t('button.add-program'),
+          isDisabled: false,
+        },
+        {
+          value: PatientModal.Encounter,
+          label: t('button.add-encounter'),
+          isDisabled: disableEncounterButton,
+        },
+        {
+          value: PatientModal.ContactTraceSearch,
+          label: t('button.add-contact-trace'),
+        }
+      );
+    }
+
+    if (InsuranceProvidersData?.length > 0) {
+      baseOptions.push({
+        value: PatientModal.Insurance,
+        label: t('button.add-insurance'),
+      });
+    }
path: client/packages/system/src/Patient/PatientView/AddButton.tsx
user: login: GeronimoJohn
body: Added to support the case for adding an insurance policy to a patient. Even when Programs Module is off.
created_at: 2025-03-12T03:29:32Z
author_association: CONTRIBUTOR
diff_hunk: @@ -5,77 +5,98 @@ import {
   SplitButtonOption,
   PlusCircleIcon,
   useUrlQuery,
+  UserStoreNodeFragment,
 } from '@openmsupply-client/common';
 import {
   PatientModal,
   usePatientModalStore,
+  usePatientStore,
 } from '@openmsupply-client/programs';
 import { PatientTabValue } from './PatientView';
+import { useInsuranceProviders } from '../apiModern';
 
 interface AddButtonProps {
   /** Disable the whole control */
   disabled: boolean;
   disableEncounterButton: boolean;
+  store?: UserStoreNodeFragment;
 }
 
 export const AddButton: React.FC<AddButtonProps> = ({
   disabled,
   disableEncounterButton,
+  store,
 }) => {
   const t = useTranslation();
   const { urlQuery, updateQuery } = useUrlQuery();
   const currentUrlTab = urlQuery['tab'];
+  const { createNewPatient } = usePatientStore();
   const { setModal: selectModal, reset } = usePatientModalStore();
+  const {
+    query: { data: InsuranceProvidersData },
+  } = useInsuranceProviders();
 
-  const options: [
-    SplitButtonOption<PatientModal>,
-    SplitButtonOption<PatientModal>,
-    SplitButtonOption<PatientModal>,
-    SplitButtonOption<PatientModal>,
-  ] = useMemo(
-    () => [
-      {
-        value: PatientModal.ProgramSearch,
-        label: t('button.add-program'),
-        isDisabled: false,
-      },
-      {
-        value: PatientModal.Encounter,
-        label: t('button.add-encounter'),
-        isDisabled: disableEncounterButton,
-      },
-      {
-        value: PatientModal.ContactTraceSearch,
-        label: t('button.add-contact-trace'),
-      },
-      { value: PatientModal.Insurance, label: t('button.add-insurance') },
-    ],
-    [disableEncounterButton, t]
-  );
-  const [programOption, encounterOption, contactTraceOption, insuranceOption] =
-    options;
+  const options: SplitButtonOption<PatientModal>[] = useMemo(() => {
+    const baseOptions: SplitButtonOption<PatientModal>[] = [];
+
+    if (store?.preferences.omProgramModule) {
+      baseOptions.push(
+        {
+          value: PatientModal.ProgramSearch,
+          label: t('button.add-program'),
+          isDisabled: false,
+        },
+        {
+          value: PatientModal.Encounter,
+          label: t('button.add-encounter'),
+          isDisabled: disableEncounterButton,
+        },
+        {
+          value: PatientModal.ContactTraceSearch,
+          label: t('button.add-contact-trace'),
+        }
+      );
+    }
+
+    if (InsuranceProvidersData?.length > 0) {
path: client/packages/system/src/Patient/PatientView/AddButton.tsx
user: login: CarlosNZ
body: Super nit-picky, but why the capital initial? I think we only use Capitals for Types and React components. 
E.g. see "StatusChangeButton" -- it's `insuranceProvidersData` (and from your code 😜)
created_at: 2025-03-12T20:50:02Z
author_association: CONTRIBUTOR
diff_hunk: @@ -5,77 +5,98 @@ import {
   SplitButtonOption,
   PlusCircleIcon,
   useUrlQuery,
+  UserStoreNodeFragment,
 } from '@openmsupply-client/common';
 import {
   PatientModal,
   usePatientModalStore,
+  usePatientStore,
 } from '@openmsupply-client/programs';
 import { PatientTabValue } from './PatientView';
+import { useInsuranceProviders } from '../apiModern';
 
 interface AddButtonProps {
   /** Disable the whole control */
   disabled: boolean;
   disableEncounterButton: boolean;
+  store?: UserStoreNodeFragment;
 }
 
 export const AddButton: React.FC<AddButtonProps> = ({
   disabled,
   disableEncounterButton,
+  store,
 }) => {
   const t = useTranslation();
   const { urlQuery, updateQuery } = useUrlQuery();
   const currentUrlTab = urlQuery['tab'];
+  const { createNewPatient } = usePatientStore();
   const { setModal: selectModal, reset } = usePatientModalStore();
+  const {
+    query: { data: InsuranceProvidersData },
+  } = useInsuranceProviders();
 
-  const options: [
-    SplitButtonOption<PatientModal>,
-    SplitButtonOption<PatientModal>,
-    SplitButtonOption<PatientModal>,
-    SplitButtonOption<PatientModal>,
-  ] = useMemo(
-    () => [
-      {
-        value: PatientModal.ProgramSearch,
-        label: t('button.add-program'),
-        isDisabled: false,
-      },
-      {
-        value: PatientModal.Encounter,
-        label: t('button.add-encounter'),
-        isDisabled: disableEncounterButton,
-      },
-      {
-        value: PatientModal.ContactTraceSearch,
-        label: t('button.add-contact-trace'),
-      },
-      { value: PatientModal.Insurance, label: t('button.add-insurance') },
-    ],
-    [disableEncounterButton, t]
-  );
-  const [programOption, encounterOption, contactTraceOption, insuranceOption] =
-    options;
+  const options: SplitButtonOption<PatientModal>[] = useMemo(() => {
+    const baseOptions: SplitButtonOption<PatientModal>[] = [];
+
+    if (store?.preferences.omProgramModule) {
+      baseOptions.push(
+        {
+          value: PatientModal.ProgramSearch,
+          label: t('button.add-program'),
+          isDisabled: false,
+        },
+        {
+          value: PatientModal.Encounter,
+          label: t('button.add-encounter'),
+          isDisabled: disableEncounterButton,
+        },
+        {
+          value: PatientModal.ContactTraceSearch,
+          label: t('button.add-contact-trace'),
+        }
+      );
+    }
+
+    if (InsuranceProvidersData?.length > 0) {
+      baseOptions.push({
+        value: PatientModal.Insurance,
+        label: t('button.add-insurance'),
+      });
+    }
+
+    return baseOptions;
+  }, [disableEncounterButton, t, store, InsuranceProvidersData]);
 
   const [selectedOption, setSelectedOption] = useState<
-    SplitButtonOption<PatientModal>
+    SplitButtonOption<PatientModal> | undefined
   >(options[0]);
 
   useEffect(() => {
-    switch (currentUrlTab) {
-      case PatientTabValue.Programs:
-      case PatientTabValue.Vaccinations:
-        setSelectedOption(programOption);
-        break;
-      case PatientTabValue.Encounters:
-        setSelectedOption(encounterOption);
-        break;
-      case PatientTabValue.ContactTracing:
-        setSelectedOption(contactTraceOption);
-        break;
-      case PatientTabValue.Insurance:
-        setSelectedOption(insuranceOption);
-        break;
-    }
-  }, [contactTraceOption, currentUrlTab, encounterOption, programOption]);
+    if (options.length === 0) return;
+
+    const optionMap: {
+      [key: string]: SplitButtonOption<PatientModal> | undefined;
+    } = {
+      [PatientTabValue.Programs]: options.find(
+        option => option.value === PatientModal.ProgramSearch
+      ),
+      [PatientTabValue.Vaccinations]: options.find(
+        option => option.value === PatientModal.ProgramSearch
+      ),
+      [PatientTabValue.Encounters]: options.find(
+        option => option.value === PatientModal.Encounter
+      ),
+      [PatientTabValue.ContactTracing]: options.find(
+        option => option.value === PatientModal.ContactTraceSearch
+      ),
+      [PatientTabValue.Insurance]: options.find(
+        option => option.value === PatientModal.Insurance
+      ),
+    };
+
+    setSelectedOption(optionMap[currentUrlTab as string] || options[0]);
path: client/packages/system/src/Patient/PatientView/AddButton.tsx
user: login: CarlosNZ
body: Any particular reason to change from the `switch` block?

I like the "map" approach in general, but in this case it seems unnecessarily complicated (with the `.find()`in every value.
created_at: 2025-03-12T21:02:12Z
author_association: CONTRIBUTOR
diff_hunk: @@ -92,16 +113,18 @@ export const AddButton: React.FC<AddButtonProps> = ({
 
   return (
     <>
path: client/packages/system/src/Patient/PatientView/AddButton.tsx
user: login: CarlosNZ
body: I'm not usually a fan of the single node inside a fragment (99% of the time it's a mistake), but this might be cleaner in this case. I'd probably go for a ternary here (`return condition ? <SplitButton> : null`), but you decide which you think is tidier.
created_at: 2025-03-12T21:08:55Z
author_association: CONTRIBUTOR
diff_hunk: @@ -5,77 +5,98 @@ import {
   SplitButtonOption,
   PlusCircleIcon,
   useUrlQuery,
+  UserStoreNodeFragment,
 } from '@openmsupply-client/common';
 import {
   PatientModal,
   usePatientModalStore,
+  usePatientStore,
 } from '@openmsupply-client/programs';
 import { PatientTabValue } from './PatientView';
+import { useInsuranceProviders } from '../apiModern';
 
 interface AddButtonProps {
   /** Disable the whole control */
   disabled: boolean;
   disableEncounterButton: boolean;
+  store?: UserStoreNodeFragment;
 }
 
 export const AddButton: React.FC<AddButtonProps> = ({
   disabled,
   disableEncounterButton,
+  store,
 }) => {
   const t = useTranslation();
   const { urlQuery, updateQuery } = useUrlQuery();
   const currentUrlTab = urlQuery['tab'];
+  const { createNewPatient } = usePatientStore();
   const { setModal: selectModal, reset } = usePatientModalStore();
+  const {
+    query: { data: InsuranceProvidersData },
+  } = useInsuranceProviders();
 
-  const options: [
-    SplitButtonOption<PatientModal>,
-    SplitButtonOption<PatientModal>,
-    SplitButtonOption<PatientModal>,
-    SplitButtonOption<PatientModal>,
-  ] = useMemo(
-    () => [
-      {
-        value: PatientModal.ProgramSearch,
-        label: t('button.add-program'),
-        isDisabled: false,
-      },
-      {
-        value: PatientModal.Encounter,
-        label: t('button.add-encounter'),
-        isDisabled: disableEncounterButton,
-      },
-      {
-        value: PatientModal.ContactTraceSearch,
-        label: t('button.add-contact-trace'),
-      },
-      { value: PatientModal.Insurance, label: t('button.add-insurance') },
-    ],
-    [disableEncounterButton, t]
-  );
-  const [programOption, encounterOption, contactTraceOption, insuranceOption] =
-    options;
+  const options: SplitButtonOption<PatientModal>[] = useMemo(() => {
+    const baseOptions: SplitButtonOption<PatientModal>[] = [];
+
+    if (store?.preferences.omProgramModule) {
+      baseOptions.push(
+        {
+          value: PatientModal.ProgramSearch,
+          label: t('button.add-program'),
+          isDisabled: false,
+        },
+        {
+          value: PatientModal.Encounter,
+          label: t('button.add-encounter'),
+          isDisabled: disableEncounterButton,
+        },
+        {
+          value: PatientModal.ContactTraceSearch,
+          label: t('button.add-contact-trace'),
+        }
+      );
+    }
+
+    if (InsuranceProvidersData?.length > 0) {
path: client/packages/system/src/Patient/PatientView/AddButton.tsx
user: login: GeronimoJohn
body: woops missed that, typo right there 😁 
created_at: 2025-03-12T21:26:34Z
author_association: CONTRIBUTOR
diff_hunk: @@ -5,77 +5,98 @@ import {
   SplitButtonOption,
   PlusCircleIcon,
   useUrlQuery,
+  UserStoreNodeFragment,
 } from '@openmsupply-client/common';
 import {
   PatientModal,
   usePatientModalStore,
+  usePatientStore,
 } from '@openmsupply-client/programs';
 import { PatientTabValue } from './PatientView';
+import { useInsuranceProviders } from '../apiModern';
 
 interface AddButtonProps {
   /** Disable the whole control */
   disabled: boolean;
   disableEncounterButton: boolean;
+  store?: UserStoreNodeFragment;
 }
 
 export const AddButton: React.FC<AddButtonProps> = ({
   disabled,
   disableEncounterButton,
+  store,
 }) => {
   const t = useTranslation();
   const { urlQuery, updateQuery } = useUrlQuery();
   const currentUrlTab = urlQuery['tab'];
+  const { createNewPatient } = usePatientStore();
   const { setModal: selectModal, reset } = usePatientModalStore();
+  const {
+    query: { data: InsuranceProvidersData },
+  } = useInsuranceProviders();
 
-  const options: [
-    SplitButtonOption<PatientModal>,
-    SplitButtonOption<PatientModal>,
-    SplitButtonOption<PatientModal>,
-    SplitButtonOption<PatientModal>,
-  ] = useMemo(
-    () => [
-      {
-        value: PatientModal.ProgramSearch,
-        label: t('button.add-program'),
-        isDisabled: false,
-      },
-      {
-        value: PatientModal.Encounter,
-        label: t('button.add-encounter'),
-        isDisabled: disableEncounterButton,
-      },
-      {
-        value: PatientModal.ContactTraceSearch,
-        label: t('button.add-contact-trace'),
-      },
-      { value: PatientModal.Insurance, label: t('button.add-insurance') },
-    ],
-    [disableEncounterButton, t]
-  );
-  const [programOption, encounterOption, contactTraceOption, insuranceOption] =
-    options;
+  const options: SplitButtonOption<PatientModal>[] = useMemo(() => {
+    const baseOptions: SplitButtonOption<PatientModal>[] = [];
+
+    if (store?.preferences.omProgramModule) {
+      baseOptions.push(
+        {
+          value: PatientModal.ProgramSearch,
+          label: t('button.add-program'),
+          isDisabled: false,
+        },
+        {
+          value: PatientModal.Encounter,
+          label: t('button.add-encounter'),
+          isDisabled: disableEncounterButton,
+        },
+        {
+          value: PatientModal.ContactTraceSearch,
+          label: t('button.add-contact-trace'),
+        }
+      );
+    }
+
+    if (InsuranceProvidersData?.length > 0) {
+      baseOptions.push({
+        value: PatientModal.Insurance,
+        label: t('button.add-insurance'),
+      });
+    }
+
+    return baseOptions;
+  }, [disableEncounterButton, t, store, InsuranceProvidersData]);
 
   const [selectedOption, setSelectedOption] = useState<
-    SplitButtonOption<PatientModal>
+    SplitButtonOption<PatientModal> | undefined
   >(options[0]);
 
   useEffect(() => {
-    switch (currentUrlTab) {
-      case PatientTabValue.Programs:
-      case PatientTabValue.Vaccinations:
-        setSelectedOption(programOption);
-        break;
-      case PatientTabValue.Encounters:
-        setSelectedOption(encounterOption);
-        break;
-      case PatientTabValue.ContactTracing:
-        setSelectedOption(contactTraceOption);
-        break;
-      case PatientTabValue.Insurance:
-        setSelectedOption(insuranceOption);
-        break;
-    }
-  }, [contactTraceOption, currentUrlTab, encounterOption, programOption]);
+    if (options.length === 0) return;
+
+    const optionMap: {
+      [key: string]: SplitButtonOption<PatientModal> | undefined;
+    } = {
+      [PatientTabValue.Programs]: options.find(
+        option => option.value === PatientModal.ProgramSearch
+      ),
+      [PatientTabValue.Vaccinations]: options.find(
+        option => option.value === PatientModal.ProgramSearch
+      ),
+      [PatientTabValue.Encounters]: options.find(
+        option => option.value === PatientModal.Encounter
+      ),
+      [PatientTabValue.ContactTracing]: options.find(
+        option => option.value === PatientModal.ContactTraceSearch
+      ),
+      [PatientTabValue.Insurance]: options.find(
+        option => option.value === PatientModal.Insurance
+      ),
+    };
+
+    setSelectedOption(optionMap[currentUrlTab as string] || options[0]);
path: client/packages/system/src/Patient/PatientView/AddButton.tsx
user: login: GeronimoJohn
body: I initially tried sticking with the existing `switch` statement, but due to the dynamic nature of the options array, which now change based on conditions, accessing the values by their index pretty much was not reliable. Before we could do this:

`const [programOption, encounterOption, contactTraceOption, insuranceOption] = options`

And directly pass values in the `switch` statement. But now, the order of options can change. Meaning `programOption` or index 0 might actually be an insurance option. So I thought map might be a better approach.

Though very open for thoughts/improvements. I do think theres a bit going on in the map
created_at: 2025-03-12T22:37:16Z
author_association: CONTRIBUTOR
diff_hunk: @@ -5,77 +5,98 @@ import {
   SplitButtonOption,
   PlusCircleIcon,
   useUrlQuery,
+  UserStoreNodeFragment,
 } from '@openmsupply-client/common';
 import {
   PatientModal,
   usePatientModalStore,
+  usePatientStore,
 } from '@openmsupply-client/programs';
 import { PatientTabValue } from './PatientView';
+import { useInsuranceProviders } from '../apiModern';
 
 interface AddButtonProps {
   /** Disable the whole control */
   disabled: boolean;
   disableEncounterButton: boolean;
+  store?: UserStoreNodeFragment;
 }
 
 export const AddButton: React.FC<AddButtonProps> = ({
   disabled,
   disableEncounterButton,
+  store,
 }) => {
   const t = useTranslation();
   const { urlQuery, updateQuery } = useUrlQuery();
   const currentUrlTab = urlQuery['tab'];
+  const { createNewPatient } = usePatientStore();
   const { setModal: selectModal, reset } = usePatientModalStore();
+  const {
+    query: { data: InsuranceProvidersData },
+  } = useInsuranceProviders();
 
-  const options: [
-    SplitButtonOption<PatientModal>,
-    SplitButtonOption<PatientModal>,
-    SplitButtonOption<PatientModal>,
-    SplitButtonOption<PatientModal>,
-  ] = useMemo(
-    () => [
-      {
-        value: PatientModal.ProgramSearch,
-        label: t('button.add-program'),
-        isDisabled: false,
-      },
-      {
-        value: PatientModal.Encounter,
-        label: t('button.add-encounter'),
-        isDisabled: disableEncounterButton,
-      },
-      {
-        value: PatientModal.ContactTraceSearch,
-        label: t('button.add-contact-trace'),
-      },
-      { value: PatientModal.Insurance, label: t('button.add-insurance') },
-    ],
-    [disableEncounterButton, t]
-  );
-  const [programOption, encounterOption, contactTraceOption, insuranceOption] =
-    options;
+  const options: SplitButtonOption<PatientModal>[] = useMemo(() => {
+    const baseOptions: SplitButtonOption<PatientModal>[] = [];
+
+    if (store?.preferences.omProgramModule) {
+      baseOptions.push(
+        {
+          value: PatientModal.ProgramSearch,
+          label: t('button.add-program'),
+          isDisabled: false,
+        },
+        {
+          value: PatientModal.Encounter,
+          label: t('button.add-encounter'),
+          isDisabled: disableEncounterButton,
+        },
+        {
+          value: PatientModal.ContactTraceSearch,
+          label: t('button.add-contact-trace'),
+        }
+      );
+    }
+
+    if (InsuranceProvidersData?.length > 0) {
+      baseOptions.push({
+        value: PatientModal.Insurance,
+        label: t('button.add-insurance'),
+      });
+    }
+
+    return baseOptions;
+  }, [disableEncounterButton, t, store, InsuranceProvidersData]);
 
   const [selectedOption, setSelectedOption] = useState<
-    SplitButtonOption<PatientModal>
+    SplitButtonOption<PatientModal> | undefined
   >(options[0]);
 
   useEffect(() => {
-    switch (currentUrlTab) {
-      case PatientTabValue.Programs:
-      case PatientTabValue.Vaccinations:
-        setSelectedOption(programOption);
-        break;
-      case PatientTabValue.Encounters:
-        setSelectedOption(encounterOption);
-        break;
-      case PatientTabValue.ContactTracing:
-        setSelectedOption(contactTraceOption);
-        break;
-      case PatientTabValue.Insurance:
-        setSelectedOption(insuranceOption);
-        break;
-    }
-  }, [contactTraceOption, currentUrlTab, encounterOption, programOption]);
+    if (options.length === 0) return;
+
+    const optionMap: {
+      [key: string]: SplitButtonOption<PatientModal> | undefined;
+    } = {
+      [PatientTabValue.Programs]: options.find(
+        option => option.value === PatientModal.ProgramSearch
+      ),
+      [PatientTabValue.Vaccinations]: options.find(
+        option => option.value === PatientModal.ProgramSearch
+      ),
+      [PatientTabValue.Encounters]: options.find(
+        option => option.value === PatientModal.Encounter
+      ),
+      [PatientTabValue.ContactTracing]: options.find(
+        option => option.value === PatientModal.ContactTraceSearch
+      ),
+      [PatientTabValue.Insurance]: options.find(
+        option => option.value === PatientModal.Insurance
+      ),
+    };
+
+    setSelectedOption(optionMap[currentUrlTab as string] || options[0]);
path: client/packages/system/src/Patient/PatientView/AddButton.tsx
user: login: CarlosNZ
body: Maybe it'd be a little nicer to just have a static map between PatientTabValue and PatientModal value, and then just one "find" function, something like:
```ts
const optionMap: {
      [key: PatientTabValue]: SplitButtonOption<PatientModal> | undefined;
    } = {
      [PatientTabValue.Programs]: PatientModal.ProgramSearch,
      [PatientTabValue.Vaccinations]: PatientModal.ProgramSearch,
      [PatientTabValue.Encounters]: PatientModal.Encounter,
      [PatientTabValue.ContactTracing]: PatientModal.ContactTraceSearch ,
      [PatientTabValue.Insurance]: PatientModal.Insurance,
    };

setSelectedOption(options.find(option => option.value === optionMap[currentTab])
```

That's untested, but you get the idea. (Also, I think you can properly type the `key` of the map and avoid having to use `as string`
created_at: 2025-03-12T23:47:36Z
author_association: CONTRIBUTOR
diff_hunk: @@ -5,77 +5,98 @@ import {
   SplitButtonOption,
   PlusCircleIcon,
   useUrlQuery,
+  UserStoreNodeFragment,
 } from '@openmsupply-client/common';
 import {
   PatientModal,
   usePatientModalStore,
+  usePatientStore,
 } from '@openmsupply-client/programs';
 import { PatientTabValue } from './PatientView';
+import { useInsuranceProviders } from '../apiModern';
 
 interface AddButtonProps {
   /** Disable the whole control */
   disabled: boolean;
   disableEncounterButton: boolean;
+  store?: UserStoreNodeFragment;
 }
 
 export const AddButton: React.FC<AddButtonProps> = ({
   disabled,
   disableEncounterButton,
+  store,
 }) => {
   const t = useTranslation();
   const { urlQuery, updateQuery } = useUrlQuery();
   const currentUrlTab = urlQuery['tab'];
+  const { createNewPatient } = usePatientStore();
   const { setModal: selectModal, reset } = usePatientModalStore();
+  const {
+    query: { data: InsuranceProvidersData },
+  } = useInsuranceProviders();
 
-  const options: [
-    SplitButtonOption<PatientModal>,
-    SplitButtonOption<PatientModal>,
-    SplitButtonOption<PatientModal>,
-    SplitButtonOption<PatientModal>,
-  ] = useMemo(
-    () => [
-      {
-        value: PatientModal.ProgramSearch,
-        label: t('button.add-program'),
-        isDisabled: false,
-      },
-      {
-        value: PatientModal.Encounter,
-        label: t('button.add-encounter'),
-        isDisabled: disableEncounterButton,
-      },
-      {
-        value: PatientModal.ContactTraceSearch,
-        label: t('button.add-contact-trace'),
-      },
-      { value: PatientModal.Insurance, label: t('button.add-insurance') },
-    ],
-    [disableEncounterButton, t]
-  );
-  const [programOption, encounterOption, contactTraceOption, insuranceOption] =
-    options;
+  const options: SplitButtonOption<PatientModal>[] = useMemo(() => {
+    const baseOptions: SplitButtonOption<PatientModal>[] = [];
+
+    if (store?.preferences.omProgramModule) {
+      baseOptions.push(
+        {
+          value: PatientModal.ProgramSearch,
+          label: t('button.add-program'),
+          isDisabled: false,
+        },
+        {
+          value: PatientModal.Encounter,
+          label: t('button.add-encounter'),
+          isDisabled: disableEncounterButton,
+        },
+        {
+          value: PatientModal.ContactTraceSearch,
+          label: t('button.add-contact-trace'),
+        }
+      );
+    }
+
+    if (InsuranceProvidersData?.length > 0) {
+      baseOptions.push({
+        value: PatientModal.Insurance,
+        label: t('button.add-insurance'),
+      });
+    }
+
+    return baseOptions;
+  }, [disableEncounterButton, t, store, InsuranceProvidersData]);
 
   const [selectedOption, setSelectedOption] = useState<
-    SplitButtonOption<PatientModal>
+    SplitButtonOption<PatientModal> | undefined
   >(options[0]);
 
   useEffect(() => {
-    switch (currentUrlTab) {
-      case PatientTabValue.Programs:
-      case PatientTabValue.Vaccinations:
-        setSelectedOption(programOption);
-        break;
-      case PatientTabValue.Encounters:
-        setSelectedOption(encounterOption);
-        break;
-      case PatientTabValue.ContactTracing:
-        setSelectedOption(contactTraceOption);
-        break;
-      case PatientTabValue.Insurance:
-        setSelectedOption(insuranceOption);
-        break;
-    }
-  }, [contactTraceOption, currentUrlTab, encounterOption, programOption]);
+    if (options.length === 0) return;
+
+    const optionMap: {
+      [key: string]: SplitButtonOption<PatientModal> | undefined;
+    } = {
+      [PatientTabValue.Programs]: options.find(
+        option => option.value === PatientModal.ProgramSearch
+      ),
+      [PatientTabValue.Vaccinations]: options.find(
+        option => option.value === PatientModal.ProgramSearch
+      ),
+      [PatientTabValue.Encounters]: options.find(
+        option => option.value === PatientModal.Encounter
+      ),
+      [PatientTabValue.ContactTracing]: options.find(
+        option => option.value === PatientModal.ContactTraceSearch
+      ),
+      [PatientTabValue.Insurance]: options.find(
+        option => option.value === PatientModal.Insurance
+      ),
+    };
+
+    setSelectedOption(optionMap[currentUrlTab as string] || options[0]);
path: client/packages/system/src/Patient/PatientView/AddButton.tsx
user: login: CarlosNZ
body: Also, you should be able to define the optionMap outside the component to avoid recreating a new instance every render.
created_at: 2025-03-12T23:48:28Z
author_association: CONTRIBUTOR
diff_hunk: @@ -5,77 +5,98 @@ import {
   SplitButtonOption,
   PlusCircleIcon,
   useUrlQuery,
+  UserStoreNodeFragment,
 } from '@openmsupply-client/common';
 import {
   PatientModal,
   usePatientModalStore,
+  usePatientStore,
 } from '@openmsupply-client/programs';
 import { PatientTabValue } from './PatientView';
+import { useInsuranceProviders } from '../apiModern';
 
 interface AddButtonProps {
   /** Disable the whole control */
   disabled: boolean;
   disableEncounterButton: boolean;
+  store?: UserStoreNodeFragment;
 }
 
 export const AddButton: React.FC<AddButtonProps> = ({
   disabled,
   disableEncounterButton,
+  store,
 }) => {
   const t = useTranslation();
   const { urlQuery, updateQuery } = useUrlQuery();
   const currentUrlTab = urlQuery['tab'];
+  const { createNewPatient } = usePatientStore();
   const { setModal: selectModal, reset } = usePatientModalStore();
+  const {
+    query: { data: InsuranceProvidersData },
+  } = useInsuranceProviders();
 
-  const options: [
-    SplitButtonOption<PatientModal>,
-    SplitButtonOption<PatientModal>,
-    SplitButtonOption<PatientModal>,
-    SplitButtonOption<PatientModal>,
-  ] = useMemo(
-    () => [
-      {
-        value: PatientModal.ProgramSearch,
-        label: t('button.add-program'),
-        isDisabled: false,
-      },
-      {
-        value: PatientModal.Encounter,
-        label: t('button.add-encounter'),
-        isDisabled: disableEncounterButton,
-      },
-      {
-        value: PatientModal.ContactTraceSearch,
-        label: t('button.add-contact-trace'),
-      },
-      { value: PatientModal.Insurance, label: t('button.add-insurance') },
-    ],
-    [disableEncounterButton, t]
-  );
-  const [programOption, encounterOption, contactTraceOption, insuranceOption] =
-    options;
+  const options: SplitButtonOption<PatientModal>[] = useMemo(() => {
+    const baseOptions: SplitButtonOption<PatientModal>[] = [];
+
+    if (store?.preferences.omProgramModule) {
+      baseOptions.push(
+        {
+          value: PatientModal.ProgramSearch,
+          label: t('button.add-program'),
+          isDisabled: false,
+        },
+        {
+          value: PatientModal.Encounter,
+          label: t('button.add-encounter'),
+          isDisabled: disableEncounterButton,
+        },
+        {
+          value: PatientModal.ContactTraceSearch,
+          label: t('button.add-contact-trace'),
+        }
+      );
+    }
+
+    if (InsuranceProvidersData?.length > 0) {
+      baseOptions.push({
+        value: PatientModal.Insurance,
+        label: t('button.add-insurance'),
+      });
+    }
+
+    return baseOptions;
+  }, [disableEncounterButton, t, store, InsuranceProvidersData]);
 
   const [selectedOption, setSelectedOption] = useState<
-    SplitButtonOption<PatientModal>
+    SplitButtonOption<PatientModal> | undefined
   >(options[0]);
 
   useEffect(() => {
-    switch (currentUrlTab) {
-      case PatientTabValue.Programs:
-      case PatientTabValue.Vaccinations:
-        setSelectedOption(programOption);
-        break;
-      case PatientTabValue.Encounters:
-        setSelectedOption(encounterOption);
-        break;
-      case PatientTabValue.ContactTracing:
-        setSelectedOption(contactTraceOption);
-        break;
-      case PatientTabValue.Insurance:
-        setSelectedOption(insuranceOption);
-        break;
-    }
-  }, [contactTraceOption, currentUrlTab, encounterOption, programOption]);
+    if (options.length === 0) return;
+
+    const optionMap: {
+      [key: string]: SplitButtonOption<PatientModal> | undefined;
+    } = {
+      [PatientTabValue.Programs]: options.find(
+        option => option.value === PatientModal.ProgramSearch
+      ),
+      [PatientTabValue.Vaccinations]: options.find(
+        option => option.value === PatientModal.ProgramSearch
+      ),
+      [PatientTabValue.Encounters]: options.find(
+        option => option.value === PatientModal.Encounter
+      ),
+      [PatientTabValue.ContactTracing]: options.find(
+        option => option.value === PatientModal.ContactTraceSearch
+      ),
+      [PatientTabValue.Insurance]: options.find(
+        option => option.value === PatientModal.Insurance
+      ),
+    };
+
+    setSelectedOption(optionMap[currentUrlTab as string] || options[0]);
path: client/packages/system/src/Patient/PatientView/AddButton.tsx
user: login: GeronimoJohn
body: That way of mapping is much cleanerrr. Thanks @CarlosNZ please see changes here: https://github.com/msupply-foundation/open-msupply/pull/6910/commits/98db54624fdb647b6665265e4dcb656bf87ef26a

I've tested and seems to be running the same. And I also tried moving `optionsMap` outside of the component, but JavaScript threw an error indicating that it couldn't access values in it before they were initialised or populated.
created_at: 2025-03-13T21:08:42Z
author_association: CONTRIBUTOR
diff_hunk: @@ -5,77 +5,98 @@ import {
   SplitButtonOption,
   PlusCircleIcon,
   useUrlQuery,
+  UserStoreNodeFragment,
 } from '@openmsupply-client/common';
 import {
   PatientModal,
   usePatientModalStore,
+  usePatientStore,
 } from '@openmsupply-client/programs';
 import { PatientTabValue } from './PatientView';
+import { useInsuranceProviders } from '../apiModern';
 
 interface AddButtonProps {
   /** Disable the whole control */
   disabled: boolean;
   disableEncounterButton: boolean;
+  store?: UserStoreNodeFragment;
 }
 
 export const AddButton: React.FC<AddButtonProps> = ({
   disabled,
   disableEncounterButton,
+  store,
 }) => {
   const t = useTranslation();
   const { urlQuery, updateQuery } = useUrlQuery();
   const currentUrlTab = urlQuery['tab'];
+  const { createNewPatient } = usePatientStore();
   const { setModal: selectModal, reset } = usePatientModalStore();
+  const {
+    query: { data: InsuranceProvidersData },
+  } = useInsuranceProviders();
 
-  const options: [
-    SplitButtonOption<PatientModal>,
-    SplitButtonOption<PatientModal>,
-    SplitButtonOption<PatientModal>,
-    SplitButtonOption<PatientModal>,
-  ] = useMemo(
-    () => [
-      {
-        value: PatientModal.ProgramSearch,
-        label: t('button.add-program'),
-        isDisabled: false,
-      },
-      {
-        value: PatientModal.Encounter,
-        label: t('button.add-encounter'),
-        isDisabled: disableEncounterButton,
-      },
-      {
-        value: PatientModal.ContactTraceSearch,
-        label: t('button.add-contact-trace'),
-      },
-      { value: PatientModal.Insurance, label: t('button.add-insurance') },
-    ],
-    [disableEncounterButton, t]
-  );
-  const [programOption, encounterOption, contactTraceOption, insuranceOption] =
-    options;
+  const options: SplitButtonOption<PatientModal>[] = useMemo(() => {
+    const baseOptions: SplitButtonOption<PatientModal>[] = [];
+
+    if (store?.preferences.omProgramModule) {
+      baseOptions.push(
+        {
+          value: PatientModal.ProgramSearch,
+          label: t('button.add-program'),
+          isDisabled: false,
+        },
+        {
+          value: PatientModal.Encounter,
+          label: t('button.add-encounter'),
+          isDisabled: disableEncounterButton,
+        },
+        {
+          value: PatientModal.ContactTraceSearch,
+          label: t('button.add-contact-trace'),
+        }
+      );
+    }
+
+    if (InsuranceProvidersData?.length > 0) {
+      baseOptions.push({
+        value: PatientModal.Insurance,
+        label: t('button.add-insurance'),
+      });
+    }
+
+    return baseOptions;
+  }, [disableEncounterButton, t, store, InsuranceProvidersData]);
 
   const [selectedOption, setSelectedOption] = useState<
-    SplitButtonOption<PatientModal>
+    SplitButtonOption<PatientModal> | undefined
   >(options[0]);
 
   useEffect(() => {
-    switch (currentUrlTab) {
-      case PatientTabValue.Programs:
-      case PatientTabValue.Vaccinations:
-        setSelectedOption(programOption);
-        break;
-      case PatientTabValue.Encounters:
-        setSelectedOption(encounterOption);
-        break;
-      case PatientTabValue.ContactTracing:
-        setSelectedOption(contactTraceOption);
-        break;
-      case PatientTabValue.Insurance:
-        setSelectedOption(insuranceOption);
-        break;
-    }
-  }, [contactTraceOption, currentUrlTab, encounterOption, programOption]);
+    if (options.length === 0) return;
+
+    const optionMap: {
+      [key: string]: SplitButtonOption<PatientModal> | undefined;
+    } = {
+      [PatientTabValue.Programs]: options.find(
+        option => option.value === PatientModal.ProgramSearch
+      ),
+      [PatientTabValue.Vaccinations]: options.find(
+        option => option.value === PatientModal.ProgramSearch
+      ),
+      [PatientTabValue.Encounters]: options.find(
+        option => option.value === PatientModal.Encounter
+      ),
+      [PatientTabValue.ContactTracing]: options.find(
+        option => option.value === PatientModal.ContactTraceSearch
+      ),
+      [PatientTabValue.Insurance]: options.find(
+        option => option.value === PatientModal.Insurance
+      ),
+    };
+
+    setSelectedOption(optionMap[currentUrlTab as string] || options[0]);
path: client/packages/system/src/Patient/PatientView/AddButton.tsx
user: login: CarlosNZ
body: > And I also tried moving `optionsMap` outside of the component, but JavaScript threw an error indicating that it couldn't access values in it before they were initialised or populated.

Even if the `optionsMap` is up the top? (just under the `interface`)
created_at: 2025-03-13T22:19:14Z
author_association: CONTRIBUTOR

PR comments:
user: login: github-actions[bot]
created_at: 2025-03-12T03:27:47Z
body: <!-- GITHUB_ACTION_COMMENT_PR -->
## Bundle size difference
Comparing this PR to `main`

|Old size      | New size     | Diff                     |
|:------------ |:-------------|:-------------------------|
|5.98 MB         |5.98 MB         | 518 B (0.01%) |

author_association: CONTRIBUTOR
user: login: GeronimoJohn
created_at: 2025-03-12T22:38:15Z
body: Thanks @CarlosNZ 😃, worked on those changes: https://github.com/msupply-foundation/open-msupply/pull/6910/commits/6534b426bab36869a76420609257c0adb6d99ba7
author_association: CONTRIBUTOR
user: login: GeronimoJohn
created_at: 2025-03-13T22:48:25Z
body: > LGTM! Thanks @GeronimoJohn
> 
> (P.S. I think you could put the `optionsMap` outside the function if it were at the top, but it's not a big deal either way)

Thanks @CarlosNZ, I gave it a go again of moving `optionsMap` above and under the `interface`. Yea it seems to be `undefined` during initialisation which make sense I think. Then gets populated after.  

<img width="620" alt="Screenshot 2025-03-14 at 11 42 45 AM" src="https://github.com/user-attachments/assets/560403d6-4d2d-43b0-a7f9-767096fad4dd" />

Error it returns when defined outside of component

<img width="579" alt="Screenshot 2025-03-14 at 11 31 05 AM" src="https://github.com/user-attachments/assets/b3edcef3-fea8-43bf-99cb-7d8c773f86f2" />

Hoping it's not just my machine kinda thing 😅 
author_association: CONTRIBUTOR