diff client/src/components/map/Bottlenecks.vue @ 1272:bc55ffaeb639

cleaned up client/src directory better organization of files and directories, better naming, separation of admin and map context
author Markus Kottlaender <markus@intevation.de>
date Thu, 22 Nov 2018 07:07:12 +0100
parents
children dc3fb8ad8f86
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/src/components/map/Bottlenecks.vue	Thu Nov 22 07:07:12 2018 +0100
@@ -0,0 +1,233 @@
+<template>
+    <div>
+        <h6 class="mb-0 py-2 px-3 border-bottom d-flex align-items-center bg-info text-white">
+          <i class="fa fa-ship mr-2"></i>
+          Bottlenecks
+        </h6>
+        <div class="row p-2 text-left small">
+            <div class="col-5">
+                <a href="#" @click="sortBy('name')" class="sort-link">Name</a>
+                <i :class="sortClass" v-if="sortColumn === 'name'"></i>
+            </div>
+            <div class="col-2">
+                <a
+                    href="#"
+                    @click="sortBy('latestMeasurement')"
+                    class="sort-link"
+                >Latest Measurement</a>
+                <i :class="sortClass" v-if="sortColumn === 'latestMeasurement'"></i>
+            </div>
+            <div class="col-3">
+                <a href="#" @click="sortBy('chainage')" class="sort-link">Chainage</a>
+                <i :class="sortClass" v-if="sortColumn === 'chainage'"></i>
+            </div>
+            <div class="col-2"></div>
+        </div>
+        <div class="bottleneck-list small text-left" v-if="filteredAndSortedBottlenecks().length">
+            <div
+                v-for="bottleneck in filteredAndSortedBottlenecks()"
+                :key="bottleneck.properties.name"
+                class="border-top row mx-0 py-2"
+            >
+                <div class="col-5 text-left">
+                    <a
+                        href="#"
+                        class="d-block"
+                        @click="moveToBottleneck(bottleneck)"
+                    >{{ bottleneck.properties.name }}</a>
+                </div>
+                <div class="col-2">{{ displayCurrentSurvey(bottleneck.properties.current) }}</div>
+                <div
+                    class="col-3"
+                >{{ displayCurrentChainage(bottleneck.properties.from, bottleneck.properties.from) }}</div>
+                <div class="col-2 text-right">
+                    <button
+                        type="button"
+                        class="btn btn-sm btn-outline-secondary"
+                        @click="toggleBottleneck(bottleneck.properties.name)"
+                    >
+                        <i class="fa fa-angle-down"></i>
+                    </button>
+                </div>
+                <div
+                    :class="['col-12', 'surveys', {open: openBottleneck === bottleneck.properties.name}]"
+                >
+                    <a
+                        href="#"
+                        class="d-block p-2"
+                        v-for="(survey, index) in openBottleneckSurveys"
+                        :key="index"
+                        @click="selectSurvey(survey, bottleneck)"
+                    >{{ survey.date_info }}</a>
+                </div>
+            </div>
+        </div>
+        <div v-else class="small text-center py-3 border-top">
+            No results.
+        </div>
+    </div>
+</template>
+
+<script>
+/*
+ * This is Free Software under GNU Affero General Public License v >= 3.0
+ * without warranty, see README.md and license for details.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ * License-Filename: LICENSES/AGPL-3.0.txt
+ *
+ * Copyright (C) 2018 by via donau
+ *   – Österreichische Wasserstraßen-Gesellschaft mbH
+ * Software engineering by Intevation GmbH
+ *
+ * Author(s):
+ * Markus Kottländer <markus.kottlaender@intevation.de>
+ */
+import { mapState } from "vuex";
+import { HTTP } from "../../lib/http";
+import { displayError } from "../../lib/errors.js";
+
+export default {
+  name: "bottlenecks",
+  data() {
+    return {
+      sortColumn: "name",
+      sortDirection: "ASC",
+      openBottleneck: null,
+      openBottleneckSurveys: null
+    };
+  },
+  computed: {
+    ...mapState("application", ["searchQuery", "showSearchbarLastState"]),
+    ...mapState("bottlenecks", ["bottlenecks"]),
+    sortClass() {
+      return [
+        "fa ml-1",
+        {
+          "fa-sort-amount-asc": this.sortDirection === "ASC",
+          "fa-sort-amount-desc": this.sortDirection === "DESC"
+        }
+      ];
+    }
+  },
+  methods: {
+    filteredAndSortedBottlenecks() {
+      return this.bottlenecks
+        .filter(bn => {
+          return bn.properties.name
+            .toLowerCase()
+            .includes(this.searchQuery.toLowerCase());
+        })
+        .sort((bnA, bnB) => {
+          switch (this.sortColumn) {
+            case "name":
+              if (
+                bnA.properties.name.toLowerCase() <
+                bnB.properties.name.toLowerCase()
+              )
+                return this.sortDirection === "ASC" ? -1 : 1;
+              if (
+                bnA.properties.name.toLowerCase() >
+                bnB.properties.name.toLowerCase()
+              )
+                return this.sortDirection === "ASC" ? 1 : -1;
+              return 0;
+
+            case "latestMeasurement": {
+              if (
+                (bnA.properties.current || "") < (bnB.properties.current || "")
+              )
+                return this.sortDirection === "ASC" ? -1 : 1;
+              if (
+                (bnA.properties.current || "") > (bnB.properties.current || "")
+              )
+                return this.sortDirection === "ASC" ? 1 : -1;
+              return 0;
+            }
+
+            case "chainage":
+              if (bnA.properties.from < bnB.properties.from)
+                return this.sortDirection === "ASC" ? -1 : 1;
+              if (bnA.properties.from > bnB.properties.from)
+                return this.sortDirection === "ASC" ? 1 : -1;
+              return 0;
+
+            default:
+              return 0;
+          }
+        });
+    },
+    selectSurvey(survey, bottleneck) {
+      this.$store.dispatch(
+        "bottlenecks/setSelectedBottleneck",
+        bottleneck.properties.name
+      );
+      this.$store.commit("bottlenecks/setSelectedSurvey", survey);
+      this.moveToBottleneck(bottleneck);
+    },
+    moveToBottleneck(bottleneck) {
+      this.$store.commit("map/moveMap", {
+        coordinates: bottleneck.geometry.coordinates,
+        zoom: 17,
+        preventZoomOut: true
+      });
+    },
+    sortBy(column) {
+      this.sortColumn = column;
+      this.sortDirection = this.sortDirection === "ASC" ? "DESC" : "ASC";
+    },
+    toggleBottleneck(name) {
+      this.openBottleneckSurveys = null;
+      if (name === this.openBottleneck) {
+        this.openBottleneck = null;
+      } else {
+        this.openBottleneck = name;
+
+        HTTP.get("/surveys/" + name, {
+          headers: {
+            "X-Gemma-Auth": localStorage.getItem("token"),
+            "Content-type": "text/xml; charset=UTF-8"
+          }
+        })
+          .then(response => {
+            this.openBottleneckSurveys = response.data.surveys;
+          })
+          .catch(error => {
+            const { status, data } = error.response;
+            displayError({
+              title: "Backend Error",
+              message: `${status}: ${data.message || data}`
+            });
+          });
+      }
+    },
+    displayCurrentSurvey(current) {
+      return current ? current.substr(0, current.length - 1) : "";
+    },
+    displayCurrentChainage(from, to) {
+      return from / 10 + " - " + to / 10;
+    }
+  },
+  mounted() {
+    this.$store.dispatch("bottlenecks/loadBottlenecks");
+  }
+};
+</script>
+
+<style lang="sass" scoped>
+.bottleneck-list
+  overflow-y: auto
+  max-height: 500px
+
+.surveys
+  max-height: 0
+  overflow: hidden
+  transition: max-height 0.3s ease
+
+.surveys.open
+  max-height: 999px
+
+.sort-link
+  color: #444
+  font-weight: bold
+</style>