From da2cd326b3146bbfdaf6f0555e743f39ed31aec4 Mon Sep 17 00:00:00 2001
From: Henrik Askjer <henrik.askjer@uib.no>
Date: Tue, 4 Jan 2022 17:01:00 +0100
Subject: [PATCH] update error messages and add similar word suggestions

---
 src/components/Autocomplete.vue   |   8 ++-
 src/components/DictionaryView.vue | 116 ++++++++++++++++++------------
 2 files changed, 75 insertions(+), 49 deletions(-)

diff --git a/src/components/Autocomplete.vue b/src/components/Autocomplete.vue
index 9b3e8496..77f043c4 100644
--- a/src/components/Autocomplete.vue
+++ b/src/components/Autocomplete.vue
@@ -89,6 +89,7 @@
         loading: false,
         items: [],
         inflection_suggestions: null,
+        similar: null,
         search: null,
         select: this.$route.query? this.$route.query.q : null,
         suggesting: null,
@@ -109,9 +110,9 @@
           if (typeof item != 'string') {
           this.items = []
           this.suggesting = false
-          if (this.inflection_suggestions && this.inflection_suggestions.length) {
-            item.inflection_suggestions = this.inflection_suggestions
-          }
+          item.inflection_suggestions = this.inflection_suggestions
+          item.similar = this.similar
+          
 
           this.submit(item)
           }
@@ -150,6 +151,7 @@
                             suggestions = response.data.a.exact.map(item => ({q: q, match: item[0], time: time, lang: [item[1]], w: true}))
                           }
                           self.inflection_suggestions = response.data.a.inflect
+                          self.similar = response.data.a.similar
                           if (suggestions.length) {
                             if (suggestions[0].q != suggestions[0].match) {
                               suggestions.unshift({q, match: q, time})
diff --git a/src/components/DictionaryView.vue b/src/components/DictionaryView.vue
index abce6377..e911e953 100644
--- a/src/components/DictionaryView.vue
+++ b/src/components/DictionaryView.vue
@@ -55,10 +55,28 @@
         </div>
       </div>
     </div>
+    
     <div class="error" v-if="error">
-      <h1 tabindex="0" id="result0">Ingen treff</h1>
-      <p>{{error}}</p>
-    </div>
+       <div>
+        <h1 tabindex="0" id="result0">{{error.title}}</h1>
+        <p>{{error.description}}</p>
+       </div>
+     </div>
+     <div class="no_results" v-if="no_results">
+       <div>
+         <p><v-icon left color=primary>error</v-icon> Ingen treff</p>
+       <article v-if="similar && similar.length" class="v-sheet v-card rounded-xl did_you_mean">
+       <span class="dict-label">Mente du:</span>
+       <v-list>
+         <v-list-item v-for="(item, index) in similar" :key="index">
+           <router-link :to="generate_path(item[0])" @click.native="select_suggestion(item[0])">{{item[0]}}</router-link><span v-if="lang=='bm,nn'" >&nbsp;<em>({{["bm","nn","bm, nn"][item[1]-1]}})</em></span>
+         </v-list-item>
+       </v-list>
+
+       </article>
+       </div>
+     </div>
+      
     
   </main>
 </template>
@@ -88,11 +106,6 @@ const api = setup({
 })
 
 
-function QueryException(params) {
-  this.name = "QueryException"
-  this.params = params
-}
-
 function navigate_to_article(self, origin) {
   self.article = null
   self.waiting_for_articles = true
@@ -106,11 +119,7 @@ function navigate_to_article(self, origin) {
   })
   .catch(function(error){
     console.log(error)
-    if (error.response && error.response.status == 404) {
-      self.error = self.$t('error.no_article', {id: self.$route.params.id})
-    } else {
-      self.error = self.$t('error.generic')
-    }
+    self.handle_error(error, true)
   })
   .then(function(response){
     self.waiting_for_articles = false
@@ -152,7 +161,7 @@ function load_articles(self, query, offset, n, dict) {
     })
     .catch(error => {
       self.waiting_for_articles = false
-      self.error_message(error)
+      self.handle_error(error)
     })
   }
     else {
@@ -184,25 +193,23 @@ function navigate_to_query(self, word) {
             total += response.data.articles.nn ? response.data.articles.nn.length : 0
 
           if (total == 0) {
-            if (self.event && query.inflection_suggestions) {
-              self.inflection_suggestions = query.inflection_suggestions
-            }
-            else {
-              self.inflection_suggestions = []
-            }
-              throw new QueryException(query)
-            }
-          else {
-            self.error = null
-          }
 
+            self.inflection_suggestions = (self.event && query.inflection_suggestions) || []
+            self.similar = (self.event && query.similar) || []
+            self.waiting_for_articles = false
+            self.no_results = true
+            self.replace_history() // fixes routing bug when going back from suggested search
 
+          }
+          else {
 
+            self.no_results = null
             Promise.all([
               load_articles(self, query, offset, self.perPage, "bm"),
               load_articles(self, query, offset, self.perPage, "nn")
             ])
             .then(() => {
+              // Show inflection suggestions if they are not among the first results
               if (self.event && self.event.inflection_suggestions) {
                 self.inflection_suggestions = self.event.inflection_suggestions.filter((item) => {
                 if ((item[1] == 1 || item[1] == 3) && self.search_results.bm) {
@@ -221,16 +228,18 @@ function navigate_to_query(self, word) {
               } else {
                 self.inflection_suggestions = []
               }
+
               self.waiting_for_articles = false
               self.$store.commit('setSearchRoute', self.$route.fullPath)
               
               self.replace_history()
             })
-          
+          }
         }).catch(error =>{
           self.waiting_for_articles = false
           console.log(error)
-            self.error_message(error)         
+            self.handle_error(error)
+            self.replace_history()         
         })
 }
 
@@ -245,6 +254,7 @@ export default {
       waiting_for_metadata: true,
       article: null,
       error: null,
+      no_results: null,
       monthly_bm: null,
       monthly_nn: null,
       event: null,
@@ -254,6 +264,7 @@ export default {
       page: 1,
       perPage: 10,
       inflection_suggestions: null,
+      similar: null,
       selected: null
     }
   },
@@ -277,7 +288,8 @@ export default {
                               search_results: this.search_results, 
                               article_info: this.article_info,
                               lang: this.lang, 
-                              error: this.error, 
+                              error: this.error,
+                              no_results: this.no_results,
                               pos_selected: this.pos_selected,
                               scope: this.scope,
                               article_info: this.article_info,
@@ -313,27 +325,32 @@ export default {
         self.monthly_nn = Object.assign(response.data, {dictionary: 'nn'})
       })
     },
-    error_message: function(error) {    
+    handle_error: function(error, article) {    
       this.search_results = {}
       console.log(error)
-      if (error instanceof QueryException) {
-        if (error.params.match) {
-          // If a suggestion from the dropdown isn't found. The message should be revised
-          this.error = this.$t('error.no_word', {q: error.params.match, dict: this.$t('dicts_inline.'+this.lang)})
-
-        } else {
-          this.error = this.$t('error.search_error', {q: error.params.q, dict: this.$t('dicts_inline.'+this.lang)})
-          if (this.lang != "bm,nn") this.error += "\r\n"+this.$t('error.other_dict', {otherDict: this.$t('inline_dict.'+this.lang == "bm"? "nn" : "bm")})
-          if (error.params.search != 2) this.error += "\r\n"+this.$t('error.search_advice')
-        }
-      }
-      else if (error.message == "Network Error") {
-        this.error = this.$t('error.network')
+      if (error.message == "Network Error") {
+        this.error = {title: this.$t('error.network.title'), description: this.$t('error.network.description'), article}
       }
       else if (error.response) {
-        this.error = this.$t('error.server', {code: error.response.status})
+        if (error.response.status == 404) {
+          if (article) {
+            this.error = {title: this.$t('error.404.title'), description: this.$t('error.no_article', {id: this.$route.params.id}), article: true}
+          }
+          else {
+            this.error = {title: this.$t('error.404.title'), description: this.$t('error.404.description'), article}
+          }
+        }
+        else if (error.response.status == 503) {
+          this.error = {title: this.$t('error.503.title'), description: this.$t('error.503.description'), article}
+        }
+        else if (String(error.response.status)[0] == "5") {
+          this.error = {title: this.$t('error.server.title'), description: this.$t('error.server.description', {code: error.response.status}), article}
+        }
+        else {
+          this.error = {title: this.$t('error.generic_code.title'), description: this.$t('error.generic_code.description', {code: error.response.status}), article}
+        }
       } else {
-        this.error = this.$t('error.generic')
+        this.error = {title: this.$t('error.generic.title'), description: this.$t('error.generic.description'), article}
       }
     },
     select_suggestion: function (word) {
@@ -524,6 +541,7 @@ export default {
         self.pos_selected = event.state.pos_selected
         self.scope = event.state.scope
         self.error = event.state.error
+        self.no_results = event.state.no_results
         self.page = event.state.page,
         self.perPage = event.state.perPage
         self.selected = event.state.selected
@@ -565,7 +583,7 @@ div.welcome article {
   margin: auto;
 }
 
-#search_results, #spinner, #above_results, #single_article_container, div.welcome, div.search_container, .error {
+#search_results, #spinner, #above_results, #single_article_container, div.welcome, div.search_container, .error, .no_results {
   padding-left: calc((100vw - 1200px) / 2);
   padding-right: calc((100vw - 1200px) / 2);
 }
@@ -581,10 +599,15 @@ div.welcome article {
 }
 
 
-.error > p {
+.error p, .no_results p {
   margin-left: 15px;
 }
 
+.error div{
+  padding: 10px;
+  padding-top: 24px;
+}
+
 #spinner {
   padding-top: 40px;
 }
@@ -663,4 +686,5 @@ li.suggestion {
   padding: 10px;
 }
 
+
 </style>
-- 
GitLab