From 131cd1c162078f72a52bce98422be4bb3b985d05 Mon Sep 17 00:00:00 2001
From: Paul Derscheid <paul.derscheid@lmscloud.de>
Date: Mon, 16 Sep 2024 12:17:55 +0000
Subject: [PATCH] Bug 37911: (follow-up) Move store initialisation into
 hydrate's idle callback

- Additionally:
    - Use a type instead of an interface.
        - Add JSDoc to it.
    - Use optional chaining when checking for existence and length of config.

Signed-off-by: Matt Blenkinsop <matt.blenkinsop@ptfs-europe.com>
---
 .../prog/js/vue/modules/islands.ts            | 93 ++++++++++---------
 1 file changed, 48 insertions(+), 45 deletions(-)

diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/modules/islands.ts b/koha-tmpl/intranet-tmpl/prog/js/vue/modules/islands.ts
index 1571d2ced6..c5e04a183a 100644
--- a/koha-tmpl/intranet-tmpl/prog/js/vue/modules/islands.ts
+++ b/koha-tmpl/intranet-tmpl/prog/js/vue/modules/islands.ts
@@ -4,54 +4,51 @@ import { useMainStore } from "../stores/main";
 import { useNavigationStore } from "../stores/navigation";
 
 /**
- * A registry for Vue components.
- * @type {Map<string, () => Promise<Component>>}
+ * Represents a web component with an import function and optional configuration.
+ * @typedef {Object} WebComponentDynamicImport
+ * @property {function(): Promise<Component>} importFn - A function that imports the component dynamically.
+ * @property {Object} [config] - An optional configuration object for the web component.
+ * @property {Array<string>} [config.stores] - An optional array of strings representing store names associated with the component.
  */
-interface WebComponent {
+type WebComponentDynamicImport = {
     importFn: () => Promise<Component>;
-    config?: {
-        stores: string[];
-    };
-}
-export const componentRegistry: Map<string, WebComponent> = new Map([
-    [
-        "hello-islands",
-        {
-            importFn: async () => {
-                const module = await import(
-                    /* webpackChunkName: "hello-islands" */
-                    "../components/HelloIslands.vue"
-                );
-                return module.default;
-            },
-            config: {
-                stores: ["mainStore", "navigationStore"],
+    config?: Record<"stores", Array<string>>;
+};
+
+/**
+ * A registry for Vue components.
+ * @type {Map<string, WebComponentDynamicImport>}
+ */
+export const componentRegistry: Map<string, WebComponentDynamicImport> =
+    new Map([
+        [
+            "hello-islands",
+            {
+                importFn: async () => {
+                    const module = await import(
+                        /* webpackChunkName: "hello-islands" */
+                        "../components/HelloIslands.vue"
+                    );
+                    return module.default;
+                },
+                config: {
+                    stores: ["mainStore", "navigationStore"],
+                },
             },
-        },
-    ],
-    [
-        "hello-world",
-        {
-            importFn: async () => {
-                const module = await import(
-                    /* webpackChunkName: "hello-world" */
-                    "../components/HelloWorld.vue"
-                );
-                return module.default;
+        ],
+        [
+            "hello-world",
+            {
+                importFn: async () => {
+                    const module = await import(
+                        /* webpackChunkName: "hello-world" */
+                        "../components/HelloWorld.vue"
+                    );
+                    return module.default;
+                },
             },
-        },
-    ],
-]);
-
-const pinia = createPinia();
-
-const mainStore = useMainStore(pinia);
-const navigationStore = useNavigationStore(pinia);
-
-const storesMatrix = {
-    mainStore,
-    navigationStore,
-};
+        ],
+    ]);
 
 /**
  * Hydrates custom elements by scanning the document and loading only necessary components.
@@ -59,6 +56,12 @@ const storesMatrix = {
  */
 export function hydrate(): void {
     window.requestIdleCallback(async () => {
+        const pinia = createPinia();
+        const storesMatrix = {
+            mainStore: useMainStore(pinia),
+            navigationStore: useNavigationStore(pinia),
+        };
+
         const islandTagNames = Array.from(componentRegistry.keys()).join(", ");
         const requestedIslands = new Set(
             Array.from(document.querySelectorAll(islandTagNames)).map(element =>
@@ -79,7 +82,7 @@ export function hydrate(): void {
                     shadowRoot: false,
                     ...(config && {
                         configureApp(app) {
-                            if (config.stores && config.stores.length > 0) {
+                            if (config.stores?.length > 0) {
                                 app.use(pinia);
                                 config.stores.forEach(store => {
                                     app.provide(store, storesMatrix[store]);
-- 
2.49.0