From 938f61aad47d65f9e09a8d5606b1ac9696d33adc Mon Sep 17 00:00:00 2001
From: Matt Blenkinsop <matt.blenkinsop@ptfs-europe.com>
Date: Wed, 15 Jan 2025 10:40:07 +0000
Subject: [PATCH] Bug 38899: Add a sticky toolbar

This patch adds a sticky toolbar to the vendors form

Test plan:
N.B: This patchset will not work on a sandbox

1) Navigate to Acquisitions and click New vendor
2) The toolbar should appear at the top of the page underneath Add vendor
3) Scroll down, the toolbar should stick and be given the 'floating' class
4) Scroll back up and the toolbar should unstick and lose the 'floating' class
---
 .../prog/js/vue/components/Toolbar.vue        | 30 +++++++++++-
 .../vue/components/Vendors/VendorFormAdd.vue  | 48 ++++++++++---------
 .../prog/js/vue/modules/acquisitions.ts       |  4 +-
 3 files changed, 57 insertions(+), 25 deletions(-)

diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/components/Toolbar.vue b/koha-tmpl/intranet-tmpl/prog/js/vue/components/Toolbar.vue
index cd968c2029a..3db1eee90b3 100644
--- a/koha-tmpl/intranet-tmpl/prog/js/vue/components/Toolbar.vue
+++ b/koha-tmpl/intranet-tmpl/prog/js/vue/components/Toolbar.vue
@@ -1,5 +1,9 @@
 <template>
-    <div id="toolbar" class="btn-toolbar">
+    <div
+        id="toolbar"
+        :class="sticky ? 'btn-toolbar sticky' : 'btn-toolbar'"
+        ref="toolbar"
+    >
         <slot />
     </div>
 </template>
@@ -7,5 +11,29 @@
 <script>
 export default {
     name: "Toolbar",
+    props: {
+        sticky: {
+            type: Boolean,
+            default: false,
+        },
+    },
+    data() {
+        return {
+            observer: null,
+        };
+    },
+    methods: {
+        stickyToolbar([e]) {
+            e.target.classList.toggle("floating", e.intersectionRatio < 1);
+        },
+    },
+    mounted() {
+        if (this.sticky) {
+            this.observer = new IntersectionObserver(this.stickyToolbar, {
+                threshold: [1],
+            });
+            this.observer.observe(this.$refs.toolbar);
+        }
+    },
 };
 </script>
diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/components/Vendors/VendorFormAdd.vue b/koha-tmpl/intranet-tmpl/prog/js/vue/components/Vendors/VendorFormAdd.vue
index 3c042ca82d6..d5f0ac5b2cf 100644
--- a/koha-tmpl/intranet-tmpl/prog/js/vue/components/Vendors/VendorFormAdd.vue
+++ b/koha-tmpl/intranet-tmpl/prog/js/vue/components/Vendors/VendorFormAdd.vue
@@ -1,32 +1,30 @@
 <template>
     <div v-if="!initialized">{{ $__("Loading") }}</div>
-    <div v-else id="vendor_add">
+    <template v-else>
         <h1 v-if="vendor.id">
             {{ $__("Edit vendor #%s").format(vendor.id) }}
         </h1>
         <h1 v-else>{{ $__("Add vendor") }}</h1>
-        <div>
-            <form @submit="onSubmit($event)">
-                <VendorDetails :vendor="vendor" />
-                <VendorContacts :vendor="vendor" />
-                <VendorInterfaces :vendor="vendor" />
-                <VendorOrderingInformation
-                    :vendor="vendor"
-                    :verifyDiscountValue="verifyDiscountValue"
-                    :discountValid="discountValid"
-                />
-                <fieldset class="action">
-                    <ButtonSubmit />
-                    <router-link
-                        :to="{ name: 'VendorList' }"
-                        role="button"
-                        class="cancel"
-                        >{{ $__("Cancel") }}</router-link
-                    >
-                </fieldset>
-            </form>
-        </div>
-    </div>
+        <form @submit="onSubmit($event)" id="add_vendor">
+            <Toolbar :sticky="true">
+                <ButtonSubmit :text="$__('Save')" />
+                <ToolbarButton
+                    :to="{ name: 'VendorList' }"
+                    :title="$__('Cancel')"
+                    icon="times"
+                >
+                </ToolbarButton>
+            </Toolbar>
+            <VendorDetails :vendor="vendor" />
+            <VendorContacts :vendor="vendor" />
+            <VendorInterfaces :vendor="vendor" />
+            <VendorOrderingInformation
+                :vendor="vendor"
+                :verifyDiscountValue="verifyDiscountValue"
+                :discountValid="discountValid"
+            />
+        </form>
+    </template>
 </template>
 
 <script>
@@ -37,6 +35,8 @@ import VendorDetails from "./VendorDetails.vue";
 import VendorContacts from "./VendorContacts.vue";
 import VendorOrderingInformation from "./VendorOrderingInformation.vue";
 import VendorInterfaces from "./VendorInterfaces.vue";
+import Toolbar from "../Toolbar.vue";
+import ToolbarButton from "../ToolbarButton.vue";
 
 export default {
     data() {
@@ -193,6 +193,8 @@ export default {
         VendorContacts,
         VendorOrderingInformation,
         VendorInterfaces,
+        Toolbar,
+        ToolbarButton,
     },
     name: "VendorFormAdd",
 };
diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/modules/acquisitions.ts b/koha-tmpl/intranet-tmpl/prog/js/vue/modules/acquisitions.ts
index 8772607f04c..c24ca4c26b7 100644
--- a/koha-tmpl/intranet-tmpl/prog/js/vue/modules/acquisitions.ts
+++ b/koha-tmpl/intranet-tmpl/prog/js/vue/modules/acquisitions.ts
@@ -12,6 +12,7 @@ import {
     faPlus,
     faSpinner,
     faTrash,
+    faTimes,
 } from "@fortawesome/free-solid-svg-icons";
 import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
 import vSelect from "vue-select";
@@ -24,7 +25,8 @@ library.add(
     faPencil,
     faPlus,
     faSpinner,
-    faTrash
+    faTrash,
+    faTimes
 );
 
 import App from "../components/Vendors/Main.vue";
-- 
2.48.1