From 52e6ca9c03ed88adc39f9bdc7bf008f900cdbee1 Mon Sep 17 00:00:00 2001
From: Jan-Hendrik Willms <tleilax+github@gmail.com>
Date: Wed, 29 May 2024 21:50:53 +0200
Subject: [PATCH] wip

---
 app/controllers/my_courses.php                |  6 ++
 lib/classes/StudipController.php              | 39 ++++++++++++
 lib/classes/VueApp.php                        | 63 +++++++++++++++++++
 resources/assets/javascripts/bootstrap/vue.js |  2 +-
 .../assets/javascripts/lib/studip-vue.js      | 42 +++++++++----
 5 files changed, 139 insertions(+), 13 deletions(-)
 create mode 100644 lib/classes/VueApp.php

diff --git a/app/controllers/my_courses.php b/app/controllers/my_courses.php
index 8205c12c743..c5c10dd27d1 100644
--- a/app/controllers/my_courses.php
+++ b/app/controllers/my_courses.php
@@ -120,6 +120,12 @@ class MyCoursesController extends AuthenticatedController
             ['type' => 'text/javascript'],
             'window.STUDIP.MyCoursesData = ' . json_encode($data) . ';'
         );
+
+        $this->render_vue_app(
+            Studip\VueApp::create('MyCourses')
+                ->withStore('MyCoursesStore')
+                ->withStoreData('mycourses', $data)
+        );
     }
 
     /**
diff --git a/lib/classes/StudipController.php b/lib/classes/StudipController.php
index a908a477c37..ad6a4811291 100644
--- a/lib/classes/StudipController.php
+++ b/lib/classes/StudipController.php
@@ -588,6 +588,45 @@ abstract class StudipController extends Trails\Controller
         $this->render_text($form->render());
     }
 
+    public function render_vue_app(\Studip\VueApp $app): void
+    {
+        $attributes = [
+            'data-vue-app' => json_encode([
+                'components' => [$app->getBaseComponent()],
+                'store'      => $app->getStore(),
+            ]),
+            'is' => $app->getBaseComponent(),
+
+            ...$app->getProps(),
+        ];
+
+        $content = '';
+
+        if ($app->getStoreData()) {
+            $content .= '<script>';
+            foreach ($app->getStoreData() as $key => $data) {
+                $content .= sprintf(
+                    "window.STUDIP.Vue.setStoreData('%s', %s);",
+                    $key,
+                    json_encode($data),
+                );
+            }
+            $content .= '</script>';
+        }
+
+        $content .= '<div ' . arrayToHtmlAttributes($attributes) . '></div>';
+
+
+        if ($this->layout) {
+            $content = $this->get_template_factory()->render(
+                $this->layout,
+                ['content_for_layout' => $content]
+            );
+        }
+
+        $this->render_text($content);
+    }
+
     /**
      * relays current request to another controller and returns the response
      * the other controller is given all assigned properties, additional parameters are passed
diff --git a/lib/classes/VueApp.php b/lib/classes/VueApp.php
new file mode 100644
index 00000000000..6c40c9e9763
--- /dev/null
+++ b/lib/classes/VueApp.php
@@ -0,0 +1,63 @@
+<?php
+namespace Studip;
+
+class VueApp
+{
+    public static function create(string $base_component, array $props = []): VueApp
+    {
+        return new self($base_component, $props);
+    }
+
+    protected ?string $store = null;
+    protected array $storeData = [];
+
+    public function __construct(
+        protected string $base_component,
+        protected array $props = []
+    ) {
+    }
+
+    public function withBaseComponent(string $base_component): VueApp
+    {
+        $this->base_component = $base_component;
+        return $this;
+    }
+
+    public function getBaseComponent(): string
+    {
+        return $this->base_component;
+    }
+
+    public function withProps(array $props): VueApp
+    {
+        $this->props = $props;
+        return $this;
+    }
+
+    public function getProps(): array
+    {
+        return $this->props;
+    }
+
+    public function withStore(?string $store): VueApp
+    {
+        $this->store = $store;
+        return $this;
+    }
+
+    public function getStore(): ?string
+    {
+        return $this->store;
+    }
+
+    public function withStoreData(string $key, array $data): VueApp
+    {
+        $this->storeData[$key] = $data;
+        return $this;
+    }
+
+    public function getStoreData(): array
+    {
+        return $this->storeData;
+    }
+}
diff --git a/resources/assets/javascripts/bootstrap/vue.js b/resources/assets/javascripts/bootstrap/vue.js
index b8c938d2904..b3341d06da0 100644
--- a/resources/assets/javascripts/bootstrap/vue.js
+++ b/resources/assets/javascripts/bootstrap/vue.js
@@ -33,7 +33,7 @@ STUDIP.ready(() => {
                 const storeConfig = await import(`../../../vue/store/${config.store}.js`);
                 console.log('store', storeConfig.default);
 
-                store.registerModule(config.id, storeConfig.default, {root: true});
+                store.registerModule(config.id, storeConfig.default);
 
                 Object.keys(data).forEach(command => {
                     store.commit(`${config.id}/${command}`, data[command]);
diff --git a/resources/assets/javascripts/lib/studip-vue.js b/resources/assets/javascripts/lib/studip-vue.js
index c7cf89a2924..395add9d141 100644
--- a/resources/assets/javascripts/lib/studip-vue.js
+++ b/resources/assets/javascripts/lib/studip-vue.js
@@ -1,15 +1,33 @@
-const load = async function () {
-    return STUDIP.loadChunk('vue');
-};
+class Vue
+{
+    static #storeData = {};
 
-const on = async function (...args) {
-    const { eventBus } = await load();
-    eventBus.on(...args);
-};
+    static async load()
+    {
+        return STUDIP.loadChunk('vue');
+    }
 
-const emit = async function (...args) {
-    const { eventBus } = await load();
-    eventBus.emit(...args);
-};
+    static async on(...args)
+    {
+        const { eventBus } = await this.load();
+        eventBus.on(...args);
+    }
 
-export default { load, on, emit };
+    static async emit(...args)
+    {
+        const { eventBus } = await this.load();
+        eventBus.emit(...args);
+    }
+
+    static setStoreData(key, data)
+    {
+        this.#storeData[key] = data;
+    }
+
+    static getStoreData(key)
+    {
+        return this.#storeData[key] ?? null;
+    }
+}
+
+export default Vue;
-- 
GitLab