Bug 32030: Use fetch.js, improve messages handling, remove top level modules
authorJonathan Druart <jonathan.druart@bugs.koha-community.org>
Wed, 11 May 2022 13:24:20 +0000 (15:24 +0200)
committerTomas Cohen Arazi <tomascohen@theke.io>
Tue, 8 Nov 2022 12:43:49 +0000 (09:43 -0300)
Signed-off-by: Jonathan Field <jonathan.field@ptfs-europe.com>
Signed-off-by: Martin Renvoize <martin.renvoize@ptfs-europe.com>
Signed-off-by: Kyle M Hall <kyle@bywatersolutions.com>
Signed-off-by: Tomas Cohen Arazi <tomascohen@theke.io>
18 files changed:
koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/AgreementLicenses.vue
koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/AgreementPeriods.vue
koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/AgreementUserRoles.vue
koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/AgreementsFormAdd.vue
koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/AgreementsFormConfirmDelete.vue
koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/AgreementsList.vue
koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/AgreementsShow.vue
koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/Dialog.vue
koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/ERMMain.vue
koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/LicensesFormAdd.vue
koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/LicensesFormConfirmDelete.vue
koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/LicensesList.vue
koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/LicensesShow.vue
koha-tmpl/intranet-tmpl/prog/js/vue/fetch.js
koha-tmpl/intranet-tmpl/prog/js/vue/main-erm.ts
koha-tmpl/intranet-tmpl/prog/js/vue/messages.js [new file with mode: 0644]
koha-tmpl/intranet-tmpl/prog/js/vue/routes.js
koha-tmpl/intranet-tmpl/prog/js/vue/stores/main.js

index 70a7d50..b59838f 100644 (file)
 </template>
 
 <script>
+import { fetchLicenses } from '../../fetch'
 export default {
     name: 'AgreementLicenses',
     data() {
@@ -114,20 +115,8 @@ export default {
         av_agreement_license_location: Array,
         agreement_licenses: Array,
     },
-    beforeCreate() {
-        // FIXME it's not called on setup, but setup() does not have 'this'.
-        const apiUrl = "/api/v1/erm/licenses"
-
-        fetch(apiUrl)
-            .then((res) => res.json())
-            .then(
-                (result) => {
-                    this.licenses = result
-                },
-                (error) => {
-                    this.$emit("set-error", error)
-                }
-            )
+    beforeCreate(){
+        fetchLicenses().then((licenses) => this.licenses = licenses )
     },
     methods: {
         addLicense() {
index 7ff66eb..df28f5e 100644 (file)
@@ -76,9 +76,7 @@ export default {
     props: {
         periods: Array
     },
-    beforeUpdate() {
-        if (!this.periods) return
-
+    beforeCreate() {
         if (!this.dates_fixed) {
             this.periods.forEach(p => {
                 p.started_on = $date(p.started_on)
index 5fd66a6..5bb1279 100644 (file)
 </template>
 
 <script>
-import { useMainStore } from "../../stores/main"
+import { fetchPatron } from "../../fetch"
+
 export default {
-    setup() {
-        const mainStore = useMainStore()
-        const { setError } = mainStore
-        return { setError }
-    },
     name: 'AgreementUserRoles',
     props: {
         av_agreement_user_roles: Array,
         user_roles: Array,
     },
-    beforeUpdate() {
-        if (!this.user_roles) return
-
+    beforeCreate() {
         this.user_roles.forEach(u => {
             u.patron_str = $patron_to_html(u.patron)
         })
@@ -102,19 +96,15 @@ export default {
         newUserSelected(e) {
             let c = e.currentTarget.counter
             let selected_patron_id = document.getElementById("selected_patron_id").value
-            fetch('/api/v1/patrons/' + selected_patron_id)
-                .then(res => res.json())
-                .then(
-                    (result) => {
-                        this.user_roles[c].patron = result
-                        this.user_roles[c].patron_str = $patron_to_html(result)
-                        this.user_roles[c].user_id = result.patron_id
-                    }).catch(
-                        (error) => {
-                            this.setError(error)
-                        }
-                )
-        }
+            let patron
+            // FIXME We are missing a "loading..."
+            fetchPatron(selected_patron_id).then((p) => {
+                patron = p
+                this.user_roles[c].patron = patron
+                this.user_roles[c].patron_str = $patron_to_html(patron)
+                this.user_roles[c].user_id = patron.patron_id
+            })
+        },
     },
 }
 </script>
index 933ad30..4733576 100644 (file)
@@ -201,7 +201,7 @@ import AgreementUserRoles from './AgreementUserRoles.vue'
 import AgreementLicenses from './AgreementLicenses.vue'
 import { useVendorStore } from "../../stores/vendors"
 import { useAVStore } from "../../stores/authorised_values"
-import { useMainStore } from "../../stores/main"
+import { setMessage, setError } from "../../messages"
 import { fetchAgreement } from '../../fetch'
 import { storeToRefs } from "pinia"
 
@@ -219,9 +219,6 @@ export default {
             av_agreement_license_location,
         } = storeToRefs(AVStore)
 
-        const mainStore = useMainStore()
-        const { setMessage, setError, resetMessages } = mainStore
-
         return {
             vendors,
             av_agreement_statuses,
@@ -230,7 +227,6 @@ export default {
             av_agreement_user_roles,
             av_agreement_license_statuses,
             av_agreement_license_location,
-            setMessage, setError, resetMessages,
         }
     },
     data() {
@@ -306,12 +302,12 @@ export default {
                 .then(response => {
                     if (response.status == 200) {
                         this.$router.push("/cgi-bin/koha/erm/agreements")
-                        this.setMessage('Agreement updated')
+                        setMessage('Agreement updated')
                     } else if (response.status == 201) {
                         this.$router.push("/cgi-bin/koha/erm/agreements")
-                        this.setMessage('Agreement created')
+                        setMessage('Agreement created')
                     } else {
-                        this.setError(response.message || response.statusText)
+                        setError(response.message || response.statusText)
                     }
                 }).catch(
                     (error) => {
index 02346a0..160683a 100644 (file)
 </template>
 
 <script>
-import { useMainStore } from "../../stores/main"
 import { fetchAgreement } from "../../fetch"
+import { setMessage, setError } from "../../messages"
 
 export default {
-    setup() {
-        const mainStore = useMainStore()
-        const { setMessage, setError } = mainStore
-        return {
-            setMessage, setError,
-        }
-    },
     data() {
         return {
             agreement: {},
@@ -55,7 +48,7 @@ export default {
     },
     beforeRouteEnter(to, from, next) {
         next(vm => {
-            vm.agreement = vm.getAgreement(to.params.agreement_id)
+            vm.getAgreement(to.params.agreement_id)
         })
     },
     methods: {
@@ -67,7 +60,7 @@ export default {
         onSubmit(e) {
             e.preventDefault()
 
-            let apiUrl = '/api/v1/erm/agreements/' + this.agreement_id
+            let apiUrl = '/api/v1/erm/agreements/' + this.agreement.agreement_id
 
             const options = {
                 method: 'DELETE',
@@ -80,22 +73,19 @@ export default {
                 .then(
                     (response) => {
                         if (response.status == 204) {
-                            this.setMessage("Agreement deleted")
+                            setMessage("Agreement deleted")
                             this.$router.push("/cgi-bin/koha/erm/agreements")
                         } else {
-                            this.setError(response.message || response.statusText)
+                            setError(response.message || response.statusText)
                         }
                     }
                 ).catch(
                     (error) => {
-                        this.setError(error)
+                        setError(error)
                     }
                 )
         }
     },
-    props: {
-        agreement_id: Number
-    },
     name: "AgreementsFormConfirmDelete",
 }
 </script>
index d536255..c195444 100644 (file)
@@ -1,6 +1,7 @@
 <template>
     <div v-if="!this.initialized">Loading...</div>
     <div v-else>
+        <Toolbar />
         <table v-if="agreements.length" id="agreement_list"></table>
         <div v-else-if="this.initialized" class="dialog message">
             There are no agreements defined.
@@ -9,9 +10,10 @@
 </template>
 
 <script>
+import Toolbar from "./AgreementsToolbar.vue"
 import ButtonEdit from "./ButtonEdit.vue"
 import ButtonDelete from "./ButtonDelete.vue"
-import { createVNode, defineComponent, render, resolveComponent } from 'vue'
+import { createVNode, render } from 'vue'
 import { useVendorStore } from "../../stores/vendors"
 import { useAVStore } from "../../stores/authorised_values"
 import { storeToRefs } from "pinia"
@@ -32,21 +34,11 @@ export default {
             av_agreement_renewal_priorities,
         }
     },
-    created() {
-        const apiUrl = '/api/v1/erm/agreements'
-
-        fetch(apiUrl)
-            .then(res => res.json())
-            .then(
-                (result) => {
-                    this.agreements = result
-                    this.initialized = true
-                },
-            ).catch(
-                (error) => {
-                    this.setError(error)
-                }
-            )
+    data: function () {
+        return {
+            agreements: [],
+            initialized: false,
+        }
     },
     beforeRouteEnter(to, from, next) {
         next(vm => {
@@ -57,6 +49,16 @@ export default {
         async getAgreements() {
             const agreements = await fetchAgreements()
             this.agreements = agreements
+            this.initialized = true
+        },
+        show_agreement: function (agreement_id) {
+            this.$router.push("/cgi-bin/koha/erm/agreements/" + agreement_id)
+        },
+        edit_agreement: function (agreement_id) {
+            this.$router.push("/cgi-bin/koha/erm/agreements/edit/" + agreement_id)
+        },
+        delete_agreement: function (agreement_id) {
+            this.$router.push("/cgi-bin/koha/erm/agreements/delete/" + agreement_id)
         },
     },
     updated() {
@@ -234,25 +236,7 @@ export default {
             .DataTable()
             .destroy(true)
     },
-    data: function () {
-        return {
-            agreements: [],
-            initialized: false,
-        }
-    },
-    methods: {
-        show_agreement: function (agreement_id) {
-            this.$router.push("/cgi-bin/koha/erm/agreements/" + agreement_id)
-        },
-        edit_agreement: function (agreement_id) {
-            this.$router.push("/cgi-bin/koha/erm/agreements/edit/" + agreement_id)
-        },
-        delete_agreement: function (agreement_id) {
-            this.$router.push("/cgi-bin/koha/erm/agreements/delete/" + agreement_id)
-        },
-    },
-    props: {
-    },
+    components: {Toolbar},
     name: "AgreementsList",
 }
 </script>
index d96a29a..7e751a5 100644 (file)
@@ -185,7 +185,6 @@ import AgreementPeriods from './AgreementPeriods.vue'
 import AgreementUserRoles from './AgreementUserRoles.vue'
 import { useVendorStore } from "../../stores/vendors"
 import { useAVStore } from "../../stores/authorised_values"
-import { useMainStore } from "../../stores/main"
 import { fetchAgreement } from "../../fetch"
 import { storeToRefs } from "pinia"
 
@@ -212,8 +211,6 @@ export default {
             av_agreement_license_location,
         } = storeToRefs(AVStore)
 
-        const mainStore = useMainStore()
-        const { setError } = mainStore
         return {
             format_date,
             patron_to_html,
@@ -225,7 +222,6 @@ export default {
             av_agreement_user_roles,
             av_agreement_license_statuses,
             av_agreement_license_location,
-            setError,
         }
     },
     data() {
index ba665d5..be910a4 100644 (file)
@@ -5,17 +5,13 @@
 
 <script>
 import { storeToRefs } from "pinia"
-import { useMainStore } from '../../stores/main';
+import { useMainStore } from "../../stores/main"
 
 export default {
     setup(){
         const mainStore = useMainStore()
         const { message, error } = storeToRefs(mainStore)
-        const { removeMessages } = mainStore
-        return { message, error, removeMessages }
+        return { message, error }
     },
-    beforeUnmount() {
-        this.removeMessages()
-    }
 };
 </script>
\ No newline at end of file
index 4a8e3cf..f9e8f41 100644 (file)
@@ -4,6 +4,7 @@
         <div class="row">
             <div class="col-sm-10 col-sm-push-2">
                 <main>
+                    <Dialog />
                     <router-view />
                 </main>
             </div>
 
 <script>
 import Breadcrumb from "./Breadcrumb.vue"
+import Dialog from "./Dialog.vue"
 import { useVendorStore } from "../../stores/vendors"
 import { useAVStore } from "../../stores/authorised_values"
-import { reactive, computed } from "vue"
+import { fetchVendors } from "../../fetch"
 
 export default {
     setup() {
@@ -68,26 +70,11 @@ export default {
         }
     },
     beforeCreate() {
-        const apiUrl = "/api/v1/acquisitions/vendors"
-
-        fetch(apiUrl)
-            .then((res) => res.json())
-            .then(
-                (result) => {
-                    this.vendorStore.vendors = result
-                },
-                (error) => {
-                    this.$emit("set-error", error)
-                }
-            )
-    },
-    methods: {
-        switchComponent(component) {
-            this.component = component
-        },
+        fetchVendors().then((vendors) => this.vendorStore.vendors = vendors)
     },
     components: {
         Breadcrumb,
+        Dialog,
     },
 };
 </script>
index 8f3dda8..880e484 100644 (file)
 <script>
 import flatPickr from 'vue-flatpickr-component'
 import { useAVStore } from "../../stores/authorised_values"
-import { useMainStore } from "../../stores/main"
+import { setMessage, setError } from "../../messages"
 import { fetchLicense } from '../../fetch'
 import { storeToRefs } from "pinia"
 
@@ -131,13 +131,9 @@ export default {
             av_license_statuses,
         } = storeToRefs(AVStore)
 
-        const mainStore = useMainStore()
-        const { setMessage, setError, resetMessages } = mainStore
-
         return {
             av_license_types,
             av_license_statuses,
-            setMessage, setError, resetMessages,
         }
     },
     data() {
@@ -206,15 +202,15 @@ export default {
                 .then(response => {
                     if (response.status == 200) {
                         this.$router.push("/cgi-bin/koha/erm/licenses")
-                        this.setMessage('License updated')
+                        setMessage('License updated')
                     } else if (response.status == 201) {
                         this.$router.push("/cgi-bin/koha/erm/licenses")
-                        this.setMessage('License created')
+                        setMessage('License created')
                     } else {
-                        this.setError(response.message || response.statusText)
+                        setError(response.message || response.statusText)
                     }
                 }, (error) => {
-                    this.setError(error)
+                    setError(error)
                 }).catch(e => { console.log(e) })
         },
     },
index 5f859a7..091d79a 100644 (file)
 </template>
 
 <script>
-import { useMainStore } from "../../stores/main"
 import { fetchLicense } from "../../fetch"
+import { setMessage, setError } from "../../messages"
 
 export default {
-    setup() {
-        const mainStore = useMainStore()
-        const { setMessage, setError } = mainStore
-        return {
-            setMessage, setError,
-        }
-    },
     data() {
         return {
             license: {},
@@ -67,7 +60,7 @@ export default {
         onSubmit(e) {
             e.preventDefault()
 
-            let apiUrl = '/api/v1/erm/licenses/' + this.license_id
+            let apiUrl = '/api/v1/erm/licenses/' + this.license.license_id
 
             const options = {
                 method: 'DELETE',
@@ -80,15 +73,15 @@ export default {
                 .then(
                     (response) => {
                         if (response.status == 204) {
-                            this.$router.push("/cgi-bin/koha/erm/agreements")
-                            this.setMessage("License deleted")
+                            this.$router.push("/cgi-bin/koha/erm/licenses")
+                            setMessage("License deleted")
                         } else {
-                            this.setError(response.message || response.statusText)
+                            setError(response.message || response.statusText)
                         }
                     }
                 ).catch(
                     (error) => {
-                        this.setError(error)
+                        setError(error)
                     }
                 )
         }
index 4bd893a..85ca7f3 100644 (file)
@@ -1,6 +1,7 @@
 <template>
     <div v-if="!this.initialized">Loading...</div>
     <div v-else>
+        <Toolbar />
         <table v-if="licenses.length" id="license_list"></table>
         <div v-else-if="this.initialized" class="dialog message">
             There are no licenses defined.
 </template>
 
 <script>
+import Toolbar from "./LicensesToolbar.vue"
 import ButtonEdit from "./ButtonEdit.vue"
 import ButtonDelete from "./ButtonDelete.vue"
-import { createVNode, defineComponent, render, resolveComponent } from 'vue'
+import { createVNode, render } from 'vue'
 import { useAVStore } from "../../stores/authorised_values"
 import { storeToRefs } from "pinia"
+import { fetchLicenses } from "../../fetch"
 
 export default {
     setup() {
@@ -28,21 +31,6 @@ export default {
             av_license_statuses,
         }
     },
-    created() {
-        const apiUrl = '/api/v1/erm/licenses'
-
-        fetch(apiUrl)
-            .then(res => res.json())
-            .then(
-                (result) => {
-                    this.licenses = result
-                    this.initialized = true
-                },
-                (error) => {
-                    this.setError(error)
-                }
-            )
-    },
     updated() {
         let show_license = this.show_license
         let edit_license = this.edit_license
@@ -193,7 +181,17 @@ export default {
             initialized: false,
         }
     },
+    beforeRouteEnter(to, from, next) {
+        next(vm => {
+            vm.getLicenses()
+        })
+    },
     methods: {
+        async getLicenses() {
+            const licenses = await fetchLicenses()
+            this.licenses = licenses
+            this.initialized = true
+        },
         show_license: function (license_id) {
             this.$router.push("/cgi-bin/koha/erm/licenses/" + license_id)
         },
@@ -208,6 +206,7 @@ export default {
         av_license_types: Array,
         av_license_statuses: Array,
     },
+    components: { Toolbar },
     name: "LicensesList",
 }
 </script>
index 8908c78..23a95b8 100644 (file)
@@ -55,7 +55,6 @@
 
 <script>
 import { useAVStore } from "../../stores/authorised_values"
-import { useMainStore } from "../../stores/main"
 import { storeToRefs } from "pinia"
 import { fetchLicense } from "../../fetch"
 
@@ -75,15 +74,11 @@ export default {
             av_license_statuses,
         } = storeToRefs(AVStore)
 
-        const mainStore = useMainStore()
-        const { setError } = mainStore
-
         return {
             format_date,
             get_lib_from_av,
             av_license_types,
             av_license_statuses,
-            setError,
         }
     },
     data() {
index a03e612..1b02ba5 100644 (file)
@@ -1,3 +1,5 @@
+import { setError } from "./messages";
+
 export const fetchAgreement = async function (agreement_id) {
     if (!agreement_id) return;
     const apiUrl = "/api/v1/erm/agreements/" + agreement_id;
@@ -14,14 +16,14 @@ export const fetchAgreement = async function (agreement_id) {
                 agreement = result;
             },
             (error) => {
-                this.setError(error);
+                setError(error);
             }
         );
     return agreement;
 };
 
 export const fetchAgreements = async function () {
-    const apiUrl = "/api/v1/erm/agreements"
+    const apiUrl = "/api/v1/erm/agreements";
     let agreements;
     await fetch(apiUrl)
         .then((res) => res.json())
@@ -30,7 +32,7 @@ export const fetchAgreements = async function () {
                 agreements = result;
             },
             (error) => {
-                this.setError(error);
+                setError(error);
             }
         );
     return agreements;
@@ -47,8 +49,57 @@ export const fetchLicense = async function (license_id) {
                 license = result;
             },
             (error) => {
-                this.setError(error);
+                setError(error);
             }
         );
     return license;
 };
+
+export const fetchLicenses = async function () {
+    const apiUrl = "/api/v1/erm/licenses";
+    let licenses;
+    await fetch(apiUrl)
+        .then((res) => res.json())
+        .then(
+            (result) => {
+                licenses = result;
+            },
+            (error) => {
+                setError(error);
+            }
+        );
+    return licenses;
+};
+
+export const fetchPatron = async function (patron_id) {
+    if (!patron_id) return;
+    const apiUrl = "/api/v1/patrons/" + patron_id;
+    let patron;
+    await fetch(apiUrl)
+        .then((res) => res.json())
+        .then(
+            (result) => {
+                patron = result;
+            },
+            (error) => {
+                setError(error);
+            }
+        );
+    return patron;
+};
+
+export const fetchVendors = async function () {
+    const apiUrl = "/api/v1/acquisitions/vendors";
+    let vendors;
+    await fetch(apiUrl)
+        .then((res) => res.json())
+        .then(
+            (result) => {
+                vendors = result;
+            },
+            (error) => {
+                setError(error);
+            }
+        );
+    return vendors;
+};
index 3189be8..123cfde 100644 (file)
@@ -14,8 +14,15 @@ import { routes } from "./routes";
 
 const router = createRouter({ history: createWebHistory(), routes });
 
+import { useMainStore } from "./stores/main";
 createApp(App)
     .use(createPinia())
     .use(router)
     .component("font-awesome-icon", FontAwesomeIcon)
     .mount("#erm");
+
+const mainStore = useMainStore();
+const { removeMessages } = mainStore;
+router.beforeEach((to, from) => {
+    removeMessages(); // This will actually flag the messages as displayed already
+});
diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/messages.js b/koha-tmpl/intranet-tmpl/prog/js/vue/messages.js
new file mode 100644 (file)
index 0000000..7d22908
--- /dev/null
@@ -0,0 +1,19 @@
+import { useMainStore } from "./stores/main";
+import { storeToRefs } from "pinia";
+
+export const setError = function (new_error) {
+    const mainStore = useMainStore();
+    const { setError } = mainStore;
+    setError("Something went wrong: " + new_error);
+};
+
+export const setMessage = function (message) {
+    const mainStore = useMainStore();
+    const { setMessage } = mainStore;
+    setMessage(message);
+};
+export const removeMessages = function () {
+    const mainStore = useMainStore();
+    const { removeMessages } = mainStore;
+    removeMessages();
+};
index 0d1a722..af5a56e 100644 (file)
@@ -1,9 +1,9 @@
 import ERMHome from "./components/ERM/ERMHome.vue";
-import Agreements from "./components/ERM/Agreements.vue";
+import AgreementsList from "./components/ERM/AgreementsList.vue";
 import AgreementsShow from "./components/ERM/AgreementsShow.vue";
 import AgreementsFormAdd from "./components/ERM/AgreementsFormAdd.vue";
 import AgreementsFormConfirmDelete from "./components/ERM/AgreementsFormConfirmDelete.vue";
-import Licenses from "./components/ERM/Licenses.vue";
+import LicensesList from "./components/ERM/LicensesList.vue";
 import LicensesShow from "./components/ERM/LicensesShow.vue";
 import LicensesFormAdd from "./components/ERM/LicensesFormAdd.vue";
 import LicensesFormConfirmDelete from "./components/ERM/LicensesFormConfirmDelete.vue";
@@ -27,7 +27,7 @@ export const routes = [
     },
     {
         path: "/cgi-bin/koha/erm/agreements",
-        component: Agreements,
+        component: AgreementsList,
         meta: {
             breadcrumb: [
                 breadcrumbs.home,
@@ -87,7 +87,7 @@ export const routes = [
     },
     {
         path: "/cgi-bin/koha/erm/licenses",
-        component: Licenses,
+        component: LicensesList,
         meta: {
             breadcrumb: [
                 breadcrumbs.home,
index e4c6c46..d52622c 100644 (file)
@@ -1,22 +1,30 @@
-import { defineStore } from 'pinia'
+import { defineStore } from "pinia";
 
-export const useMainStore = defineStore('main', {
-  state: () => ({
+export const useMainStore = defineStore("main", {
+    state: () => ({
         message: null,
         error: null,
+        previousMessage: null,
+        previousError: null,
+        displayed_already: false,
     }),
     actions: {
         setMessage(message) {
             this.error = null;
             this.message = message;
+            this.displayed_already = false;
         },
         setError(error) {
             this.error = "Something went wrong: " + error;
             this.message = null;
+            this.displayed_already = false;
         },
         removeMessages() {
-            this.error = null;
-            this.message = null;
+            if (this.displayed_already) {
+                this.error = null;
+                this.message = null;
+            }
+            this.displayed_already = true;
         },
     },
-});
\ No newline at end of file
+});