309 lines
		
	
	
		
			7.3 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
			
		
		
	
	
			309 lines
		
	
	
		
			7.3 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
<template>
 | 
						|
  <div>
 | 
						|
    <h1>Register vin</h1>
 | 
						|
 | 
						|
    <ScanToVinmonopolet @wine="wineFromVinmonopoletScan" v-if="showCamera" />
 | 
						|
 | 
						|
    <div class="button-container">
 | 
						|
      <button class="vin-button" @click="showCamera = !showCamera">
 | 
						|
        {{ showCamera ? "Skjul camera" : "Legg til vin med camera" }}
 | 
						|
      </button>
 | 
						|
 | 
						|
      <button class="vin-button" @click="manualyFillInnWine">
 | 
						|
        Legg til en vin manuelt
 | 
						|
      </button>
 | 
						|
 | 
						|
      <button class="vin-button" @click="showImportLink = !showImportLink">
 | 
						|
        {{ showImportLink ? "Skjul importer fra link" : "Importer fra link" }}
 | 
						|
      </button>
 | 
						|
    </div>
 | 
						|
 | 
						|
    <div v-if="showImportLink" class="import-from-link">
 | 
						|
      <label>Importer vin fra vinmonopolet link:</label>
 | 
						|
      <input
 | 
						|
        type="text"
 | 
						|
        placeholder="Vinmonopol lenke"
 | 
						|
        ref="vinmonopoletLinkInput"
 | 
						|
        autocapitalize="none"
 | 
						|
        @input="addWineByUrl"
 | 
						|
      />
 | 
						|
 | 
						|
      <div v-if="linkError" class="error">
 | 
						|
        {{ linkError }}
 | 
						|
      </div>
 | 
						|
    </div>
 | 
						|
 | 
						|
    <div v-if="wines.length > 0" class="wine-edit-container">
 | 
						|
      <h2>Dagens registrerte viner</h2>
 | 
						|
 | 
						|
      <div>
 | 
						|
        <button class="vin-button" @click="sendWines">Send inn dagens viner</button>
 | 
						|
      </div>
 | 
						|
 | 
						|
      <div class="wines">
 | 
						|
        <wine v-for="wine in wines" :key="wine.id" :wine="wine">
 | 
						|
          <template v-slot:default>
 | 
						|
            <div v-if="editingWine == wine" class="wine-edit">
 | 
						|
              <div class="label-div" v-for="key in Object.keys(wine)" :key="key">
 | 
						|
                <label>{{ key }}</label>
 | 
						|
                <input type="text" v-model="wine[key]" :placeholder="key" />
 | 
						|
              </div>
 | 
						|
            </div>
 | 
						|
          </template>
 | 
						|
 | 
						|
          <template v-slot:bottom>
 | 
						|
            <div class="button-container row small">
 | 
						|
              <button v-if="editingWine == wine && wine._id" class="vin-button small warning" @click="updateWine(wine)">
 | 
						|
                Oppdater vin
 | 
						|
              </button>
 | 
						|
 | 
						|
              <button class="vin-button small" @click="editingWine = editingWine == wine ? false : wine">
 | 
						|
                {{ editingWine == wine ? "Lukk" : "Rediger" }}
 | 
						|
              </button>
 | 
						|
 | 
						|
              <button class="danger vin-button small" @click="deleteWine(wine)">
 | 
						|
                Slett
 | 
						|
              </button>
 | 
						|
            </div>
 | 
						|
          </template>
 | 
						|
        </wine>
 | 
						|
      </div>
 | 
						|
    </div>
 | 
						|
 | 
						|
    <div class="button-container" v-if="wines.length > 0"></div>
 | 
						|
  </div>
 | 
						|
</template>
 | 
						|
 | 
						|
<script>
 | 
						|
import ScanToVinmonopolet from "@/ui/ScanToVinmonopolet";
 | 
						|
import Wine from "@/ui/Wine";
 | 
						|
 | 
						|
export default {
 | 
						|
  components: { ScanToVinmonopolet, Wine },
 | 
						|
  data() {
 | 
						|
    return {
 | 
						|
      wines: [],
 | 
						|
      editingWine: undefined,
 | 
						|
      showCamera: false,
 | 
						|
      showImportLink: false,
 | 
						|
      linkError: undefined
 | 
						|
    };
 | 
						|
  },
 | 
						|
  watch: {
 | 
						|
    wines() {
 | 
						|
      this.$emit("counter", this.wines.length);
 | 
						|
    }
 | 
						|
  },
 | 
						|
  created() {
 | 
						|
    this.fetchLotterWines();
 | 
						|
  },
 | 
						|
  methods: {
 | 
						|
    fetchLotterWines() {
 | 
						|
      fetch("/api/lottery/wines")
 | 
						|
        .then(resp => resp.json())
 | 
						|
        .then(response => (this.wines = response.wines));
 | 
						|
    },
 | 
						|
    wineFromVinmonopoletScan(wineResponse) {
 | 
						|
      if (this.wines.map(wine => wine.name).includes(wineResponse.name)) {
 | 
						|
        this.toastText = "Vinen er allerede lagt til.";
 | 
						|
        this.showToast = true;
 | 
						|
        return;
 | 
						|
      }
 | 
						|
 | 
						|
      this.toastText = "Fant og la til vin:<br>" + wineResponse.name;
 | 
						|
      this.showToast = true;
 | 
						|
 | 
						|
      this.wines.unshift(wineResponse);
 | 
						|
    },
 | 
						|
    manualyFillInnWine() {
 | 
						|
      fetch("/api/lottery/wine/schema")
 | 
						|
        .then(resp => resp.json())
 | 
						|
        .then(response => response.schema)
 | 
						|
        .then(wineSchema => {
 | 
						|
          this.editingWine = wineSchema;
 | 
						|
          this.wines.unshift(wineSchema);
 | 
						|
        });
 | 
						|
    },
 | 
						|
    addWineByUrl(event) {
 | 
						|
      const url = event.target.value;
 | 
						|
      this.linkError = null;
 | 
						|
 | 
						|
      if (!url.includes("vinmonopolet.no")) {
 | 
						|
        this.linkError = "Dette er ikke en gydlig vinmonopolet lenke.";
 | 
						|
        return;
 | 
						|
      }
 | 
						|
      const id = url.split("/").pop();
 | 
						|
 | 
						|
      fetch(`/api/vinmonopolet/wine/by-id/${id}`)
 | 
						|
        .then(resp => resp.json())
 | 
						|
        .then(response => {
 | 
						|
          const { wine } = response;
 | 
						|
          this.wines.unshift(wine);
 | 
						|
          this.$refs.vinmonopoletLinkInput.value = "";
 | 
						|
        });
 | 
						|
    },
 | 
						|
    sendWines() {
 | 
						|
      const filterOutExistingWines = wine => wine["_id"] == null;
 | 
						|
 | 
						|
      const options = {
 | 
						|
        method: "POST",
 | 
						|
        headers: {
 | 
						|
          "Content-Type": "application/json"
 | 
						|
        },
 | 
						|
        body: JSON.stringify({
 | 
						|
          wines: this.wines.filter(filterOutExistingWines)
 | 
						|
        })
 | 
						|
      };
 | 
						|
 | 
						|
      fetch("/api/lottery/wines", options).then(resp => {
 | 
						|
        try {
 | 
						|
          if (resp.ok == false) {
 | 
						|
            throw resp;
 | 
						|
          }
 | 
						|
 | 
						|
          resp.json().then(response => {
 | 
						|
            if (response.success == false) {
 | 
						|
              throw response;
 | 
						|
            } else {
 | 
						|
              this.$toast.info({
 | 
						|
                title: "Viner sendt inn!",
 | 
						|
                timeout: 4000
 | 
						|
              });
 | 
						|
            }
 | 
						|
          });
 | 
						|
        } catch (error) {
 | 
						|
          this.$toast.error({
 | 
						|
            title: "Feil oppsto ved innsending!",
 | 
						|
            description: error.message,
 | 
						|
            timeout: 4000
 | 
						|
          });
 | 
						|
        }
 | 
						|
      });
 | 
						|
    },
 | 
						|
    updateWine(updatedWine) {
 | 
						|
      const options = {
 | 
						|
        method: "PUT",
 | 
						|
        headers: { "Content-Type": "application/json" },
 | 
						|
        body: JSON.stringify({ wine: updatedWine })
 | 
						|
      };
 | 
						|
 | 
						|
      fetch(`/api/lottery/wine/${updatedWine._id}`, options)
 | 
						|
        .then(resp => resp.json())
 | 
						|
        .then(response => {
 | 
						|
          this.editingWine = null;
 | 
						|
 | 
						|
          if (response.success) {
 | 
						|
            this.$toast.info({
 | 
						|
              title: response.message
 | 
						|
            });
 | 
						|
          } else {
 | 
						|
            this.$toast.error({
 | 
						|
              title: response.message
 | 
						|
            });
 | 
						|
          }
 | 
						|
        });
 | 
						|
    },
 | 
						|
    deleteWine(deletedWine) {
 | 
						|
      this.wines = this.wines.filter(wine => wine.name != deletedWine.name);
 | 
						|
 | 
						|
      if (deletedWine._id == null) return;
 | 
						|
 | 
						|
      const options = { method: "DELETE" };
 | 
						|
      fetch(`/api/lottery/wine/${deletedWine._id}`, options)
 | 
						|
        .then(resp => resp.json())
 | 
						|
        .then(response => {
 | 
						|
          this.editingWine = null;
 | 
						|
 | 
						|
          this.$toast.info({
 | 
						|
            title: response.message
 | 
						|
          });
 | 
						|
        });
 | 
						|
    }
 | 
						|
  }
 | 
						|
};
 | 
						|
</script>
 | 
						|
 | 
						|
<style lang="scss" scoped>
 | 
						|
@import "@/styles/media-queries.scss";
 | 
						|
@import "@/styles/variables.scss";
 | 
						|
 | 
						|
h1 {
 | 
						|
  text-align: center;
 | 
						|
}
 | 
						|
 | 
						|
.button-container {
 | 
						|
  margin: 1.5rem 0 0;
 | 
						|
  flex-wrap: wrap;
 | 
						|
}
 | 
						|
 | 
						|
.row {
 | 
						|
  margin: 0.25rem 0;
 | 
						|
}
 | 
						|
 | 
						|
.import-from-link {
 | 
						|
  width: 70%;
 | 
						|
  max-width: 800px;
 | 
						|
  margin: 1.5rem auto 0;
 | 
						|
  display: flex;
 | 
						|
  flex-direction: column;
 | 
						|
 | 
						|
  label {
 | 
						|
    display: inline-block;
 | 
						|
    font-size: 1rem;
 | 
						|
    text-transform: uppercase;
 | 
						|
    letter-spacing: 0px;
 | 
						|
    font-weight: 600;
 | 
						|
  }
 | 
						|
 | 
						|
  input {
 | 
						|
    font-size: 1.5rem;
 | 
						|
    min-height: 2rem;
 | 
						|
    line-height: 2rem;
 | 
						|
    border: none;
 | 
						|
    border-bottom: 1px solid black;
 | 
						|
    width: 100%;
 | 
						|
  }
 | 
						|
 | 
						|
  .error {
 | 
						|
    margin-top: 0.5rem;
 | 
						|
    padding: 1.25rem;
 | 
						|
    background-color: $light-red;
 | 
						|
    color: $red;
 | 
						|
    font-size: 1.3rem;
 | 
						|
 | 
						|
    @include mobile {
 | 
						|
      font-size: 1.1rem;
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
.wine-edit-container {
 | 
						|
  max-width: 1500px;
 | 
						|
  padding: 2rem;
 | 
						|
  margin: 0 auto;
 | 
						|
 | 
						|
  .wines {
 | 
						|
    display: flex;
 | 
						|
    flex-wrap: wrap;
 | 
						|
    justify-content: center;
 | 
						|
 | 
						|
    > div {
 | 
						|
      margin: 1rem;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  label {
 | 
						|
    margin-top: 0.7rem;
 | 
						|
    width: 100%;
 | 
						|
  }
 | 
						|
 | 
						|
  .button-container {
 | 
						|
    margin-top: 1rem;
 | 
						|
 | 
						|
    button:not(:last-child) {
 | 
						|
      margin-right: 0.5rem;
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
</style>
 |