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>
|