Implement food view, Upgrade food views

This commit is contained in:
Michael Götz 2018-04-01 17:39:53 +02:00
parent 3c45c0bb2d
commit c9ec5ead7e
13 changed files with 774 additions and 0 deletions

View File

@ -0,0 +1,34 @@
<template>
<div class="menu">
<div class="p-3 border border-dark rounded bg-light text-dark">
<div v-if="menu">
<p>{{ menu.date | formatDateWithWeekday}}</p>
<ul class="border">
<li v-for="food in menu.menu" :data-food="food.id" :data-rating="food.rating" class="food-item media mb-2">
<single-menu :food="food" :defaultImageUrl="defaultImageUrl"></single-menu>
</li>
</ul>
</div>
<div v-else>
<p> Keine Daten vorhanden.</p>
</div>
</div>
</div>
</template>
<script>
import SingleMenu from '@/components/food/SingleFood'
export default {
name: "DayMenu",
props: ['menu', 'failMessage', 'defaultImageUrl'],
components: {SingleMenu},
}
</script>
<style scoped>
ul {
padding: 0;
}
</style>

View File

@ -0,0 +1,130 @@
<template>
<b-row>
<b-col cols="12" class="text-center border pt-2">
<b-row align-v="center">
<b-col cols="1"></b-col>
<b-col cols="10">
<h4>Detailansicht</h4>
<h5>{{food.name}}</h5>
</b-col>
<b-col cols="1">
<router-link :to="{name: 'food'}">Back</router-link>
</b-col>
</b-row>
</b-col>
<b-col cols="7" class="border">
<b-row>
<b-col class="border pt-2">
<allergens-overview :allergens="food.allergens"></allergens-overview>
</b-col>
</b-row>
<b-row>
<b-col class="border pt-2">
<price-overview :student="food.price_student" :employee="food.price_employee"
:guest="food.price_guest"></price-overview>
</b-col>
</b-row>
<b-row>
<b-col class="border pt-2">
<rating-combined v-on:updateFood="loadFood" :globalRating="food.rating" :foodId="food_id"></rating-combined>
</b-col>
</b-row>
<b-row>
<b-col class="border pt-2">
<comments-overview :comments="comments"></comments-overview>
</b-col>
</b-row>
</b-col>
<b-col cols="5" class="border">
<food-picture :image="food.image" :userFoodImage="userFoodImage"></food-picture>
<food-picture-upload v-on:updateImage="loadUserImage"></food-picture-upload>
<comment-box v-on:updateFood="loadFood" :foodId="food_id"></comment-box>
</b-col>
</b-row>
</template>
<script>
import * as CONFIG from '../../config';
import authentication from "../../authentication";
import AllergensOverview from "@/components/food/utils/AllergensOverview";
import PriceOverview from "@/components/food/utils/PriceOverview";
import RatingCombined from "@/components/food/utils/RatingCombined";
import FoodPicture from "@/components/food/utils/FoodPicture";
import FoodPictureUpload from "@/components/food/utils/PictureUpload";
import CommentBox from "@/components/food/utils/CommentBox";
import CommentsOverview from "@/components/food/utils/CommentsOverview";
export default {
name: "FoodDetail",
components: {
AllergensOverview,
PriceOverview,
RatingCombined,
FoodPicture,
FoodPictureUpload,
CommentBox,
CommentsOverview
},
data() {
return {
food_id: '',
food: {},
comments: '',
show: true,
images: '',
form: {
file: '',
},
userFoodImage: '',
};
}, created() {
this.loadFood();
this.loadUserImage();
},
methods: {
loadFood() {
window.axios.get(CONFIG.API_ROOT_FOOD
.concat('/meals/').concat(this.$route.params.id))
.then(response => {
// JSON responses are automatically parsed.
console.log(JSON.parse(JSON.stringify(response.data)));
this.food = response.data;
this.food_id = this.food.id;
})
.catch(e => {
});
window.axios.get(CONFIG.API_ROOT_FOOD
.concat('/meals/').concat(this.$route.params.id).concat('/comments'))
.then(response => {
console.log(JSON.parse(JSON.stringify(response.data)));
this.comments = response.data;
})
.catch(e => {
});
},
loadUserImage() {
if (authentication.authenticated()) {
let url = CONFIG.API_ROOT_ACCOUNT + '/food/images/?food_id=' + this.$route.params.id;
window.axios
.get(url)
.then(response => {
console.log('LOG IMAGE');
if (response.data.length > 0) {
this.userFoodImage = response.data[0].image.image;
}
})
.catch()
}
},
isAuthenticated: function () {
return authentication.authenticated();
},
}
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,52 @@
<template>
<b-col>
<b-row>
<div class="col col-6" v-for="location in locations">
<tab-menu :title="location.short" :location="location.id" :defaultImageUrl="defaultImageUrl"></tab-menu>
</div>
</b-row>
</b-col>
</template>
<script>
import TabMenu from '@/components/food/TabMenu'
import axios from 'axios'
import * as CONFIG from '@/config.js'
export default {
name: "FoodOverview",
components: {TabMenu},
data() {
return {
defaultImageUrl: '',
locations: [],
}
},
created() {
axios.get(CONFIG.API_ROOT_FOOD.concat('/menus/locations'))
.then(response => {
// JSON responses are automatically parsed.
console.log(JSON.parse(JSON.stringify(response.data)));
this.locations = response.data;
})
.catch(e => {
console.error(e)
});
axios.get(CONFIG.API_ROOT_FOOD.concat('/meals/images/default'))
.then(response => {
// JSON responses are automatically parsed.
console.log(JSON.parse(JSON.stringify(response.data)));
this.defaultImageUrl = response.data.image;
})
.catch(e => {
console.error(e)
});
}
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,81 @@
<template>
<b-col>
<b-row>
<b-col cols="3">
<a v-if="food.image" :href="food.image.thumb" :data-lightbox="title"
:data-title="food.name">
<img :src="food.image.thumb" class="media-object" alt="Bild" width="80px">
</a>
<a v-else :href="defaultImageUrl">
<!--:data-lightbox="title"-->
<!--:data-title="food.name ">-->
<img :src="defaultImageUrl" class="media-object"
alt="Bild" width="80px">
</a>
</b-col>
<b-col cols="7" class="media-body">
<div class="food-name">
<router-link :to="{name: 'food-detail', params:{id: food.id}}">{{ food.name }}</router-link>
</div>
<fa-rating :glyph="star"
:spacing="-1"
:inactive-color="'#cfcfcf'"
:active-color="'#0074D9'"
:increment="0.5"
:fixed-points="2"
:show-rating="false"
:item-size="15"
:inline="true"
v-model="userRating">
</fa-rating>
</b-col>
<div v-if="food.price_student" class="col-2"><span class="float-right">{{ food.price_student }}</span></div>
</b-row>
</b-col>
</template>
<script>
import {FaRating} from 'vue-rate-it';
import Star from 'vue-rate-it/glyphs/star';
import authentication from "../../authentication";
import * as CONFIG from '../../config'
import router from '../../router'
export default {
name: "SingleMenu",
props: ['food', 'title', 'defaultImageUrl'],
components: {FaRating},
data() {
return {
userRating: this.food.rating,
star: '',
};
}, created() {
// register the icon
this.star = Star;
// console.log(this.food.rating);
// this.userRating = this.food.rating;
},
watch: {
userRating: function (newRating) {
if (authentication.authenticated()) {
let url = CONFIG.API_ROOT_FOOD.concat('/meals/').concat(this.food.id).concat('/rating');
window.axios
.post(url, {rating: newRating})
.then(response => {
// TODO: Reload Data
//router.go()
}
)
.catch();
} else {
router.push({name: 'login'})
}
}
}
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,83 @@
<template>
<div>
<h3>{{ title }} </h3>
<b-tabs>
<b-tab title="Daily" active>
<day-menu :menu="dayMenu" :defaultImageUrl="defaultImageUrl"></day-menu>
</b-tab>
<b-tab title="Weekly">
<week-menu :menus="weekMenus" :defaultImageUrl="defaultImageUrl"></week-menu>
</b-tab>
</b-tabs>
</div>
</template>
<script>
import DayMenu from '@/components/food/DayMenu'
import WeekMenu from '@/components/food/WeekMenu'
import axios from 'axios';
import * as CONFIG from '../../config';
export default {
name: "TabMenu",
props: ['title', 'location', 'defaultImageUrl'],
components: {DayMenu, WeekMenu},
data() {
return {
dayMenu: {},
weekMenus: [],
};
},
created() {
let now = new Date('2018/03/19');
let today_yyyymmdd = this.formatDate(now);
now.setDate(now.getDate() + 7);
let last_weekday_yyyymmdd = this.formatDate(now);
axios.get(CONFIG.API_ROOT_FOOD
.concat('/menus/?location=').concat(this.location)
.concat('&startdate=').concat(today_yyyymmdd)
.concat('&enddate=').concat(today_yyyymmdd))
.then(response => {
// JSON responses are automatically parsed.
console.log(JSON.parse(JSON.stringify(response.data)));
if (response.data.length == 1) {
this.dayMenu = response.data[0];
}
})
.catch(e => {
console.error(e)
});
axios.get(CONFIG.API_ROOT_FOOD
.concat('/menus/?location=').concat(this.location)
.concat('&startdate=').concat(today_yyyymmdd)
.concat('&enddate=').concat(last_weekday_yyyymmdd))
.then(response => {
// JSON responses are automatically parsed.
console.log(JSON.parse(JSON.stringify(response.data)));
this.weekMenus = response.data;
})
.catch(e => {
console.error(e)
});
}, methods: {
formatDate: function (date) {
var d = new Date(date),
month = '' + (d.getMonth() + 1),
day = '' + d.getDate(),
year = d.getFullYear();
if (month.length < 2) month = '0' + month;
if (day.length < 2) day = '0' + day;
return [year, month, day].join('-');
}
}
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,24 @@
<template>
<div class="p-3 border border-dark rounded bg-light text-dark">
<div v-if="menus">
<div v-for="menu in menus" class="menu">
<day-menu :menu="menu" :defaultImageUrl="defaultImageUrl"></day-menu>
</div>
</div>
<p v-else>Keine Daten gefunden.</p>
</div>
</template>
<script>
import DayMenu from '@/components/food/DayMenu'
export default {
name: "WeekMenu",
props: ['menus', 'failMessage', 'defaultImageUrl'],
components: {DayMenu: DayMenu},
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,26 @@
<template>
<div>
<h5>Allergene</h5>
<div v-if="allergens">
<ul>
<li v-for="allergen in allergens">{{ allergen.name }}</li>
</ul>
</div>
<div v-else>
Keine Angaben gefunden.
</div>
</div>
</template>
<script>
export default {
name: "AllergensOverview",
props: ['allergens'],
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,94 @@
<template>
<div v-if="isAuthenticated()">
<h5>Kommentare</h5>
<b-form @submit="onSubmit">
<b-form-group id="commentShort"
label="Überschrift, Zusammenfassung"
label-for="commentShort">
<b-form-input id="commentShort"
type="text"
v-model="form.commentShort"
required
placeholder="Enter Title">
</b-form-input>
</b-form-group>
<b-form-group id="commentText"
label="Kommentar"
label-for="commentText">
<b-form-textarea id="commentText"
v-model="form.commentText"
placeholder="Enter something"
:rows="3"
:max-rows="6">
</b-form-textarea>
</b-form-group>
<b-button type="submit" variant="primary">Submit</b-button>
</b-form>
</div>
</template>
<script>
import authentication from "../../../authentication";
import * as CONFIG from "../../../config"
export default {
name: "CommentBox",
props: ['foodId'],
data() {
return {
form: {
commentShort: '',
commentText: '',
}
};
},
created() {
this.getUserComment();
},
watch: {
foodId: function () {
this.getUserComment();
},
},
methods: {
onSubmit(evt) {
evt.preventDefault();
if (authentication.authenticated() && this.foodId) {
let url = CONFIG.API_ROOT_FOOD + '/meals/' + this.foodId + '/comment';
let jsonData = {
"title": this.form.commentShort,
"description": this.form.commentText
};
window.axios
.post(url, jsonData)
.then(response => {
this.$emit('updateFood');
})
.catch()
}
},
isAuthenticated: function () {
return authentication.authenticated();
},
getUserComment: function () {
if (authentication.authenticated() && this.foodId) {
let url = CONFIG.API_ROOT_ACCOUNT + '/food/comments/?food_id=' + this.foodId;
window.axios
.get(url)
.then(response => {
console.log(response.data);
if (response.data.length > 0) {
this.form.commentText = response.data[0].description;
this.form.commentShort = response.data[0].title;
}
})
.catch()
}
},
},
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,22 @@
<template>
<b-row>
<b-col>
<h5>Kommentare</h5>
</b-col>
<div v-for="comment in comments" class="col col-12 border">
<h5>{{comment.title}}</h5>
<p>{{comment.description}}</p>
</div>
</b-row>
</template>
<script>
export default {
name: "CommentsOverview",
props: ['comments'],
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,39 @@
<template>
<div v-if="userFoodImage">
<b-img :src="userFoodImage" fluid-grow alt="Fluid-Grow image"/>
</div>
<div v-else-if="image">
<b-img :src="image" fluid-grow alt="Fluid-Grow image"/>
</div>
<div v-else>
<b-img img :src="defaultImage" fluid-grow alt="Fluid-Grow image"/>
</div>
</template>
<script>
import * as CONFIG from '../../../config'
export default {
name: "FoodPicture",
props: ['image', 'userFoodImage'],
data() {
return {
defaultImage: '',
};
},
created() {
window.axios
.get(CONFIG.API_ROOT_FOOD.concat('/meals/images/default'))
.then(response => {
console.log(JSON.parse(JSON.stringify(response.data)));
this.defaultImage = response.data.image;
})
.catch(e => {
});
},
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,53 @@
<template>
<div v-if="isAuthenticated()">
<h4>Bilder</h4>
<p>Bild senden</p>
<b-form @submit="onSubmit">
<b-form-file v-model="form.file" :state="Boolean(form.file)" placeholder="Choose a file..."></b-form-file>
<b-button type="submit" variant="primary">Submit</b-button>
</b-form>
</div>
</template>
<script>
import * as CONFIG from '../../../config'
import authentication from '../../../authentication'
export default {
name: "PictureUpload",
props: ['image'],
data() {
return {
form: {
file: '',
}
};
},
methods: {
isAuthenticated: function () {
return authentication.authenticated();
},
onSubmit(evt) {
evt.preventDefault();
var formData = new FormData();
console.log(this.form.file);
// append Blob/File object
formData.append('image', this.form.file, this.form.file.name);
window.axios.post(CONFIG.API_ROOT_FOOD
.concat('/meals/').concat(this.$route.params.id).concat('/image'), formData)
.then(response => {
// JSON responses are automatically parsed.
this.$emit('updateImage');
})
.catch(e => {
console.log(JSON.parse(JSON.stringify(e.response)));
});
},
}
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,31 @@
<template>
<div id="prices" class="">
<h5>Preise</h5>
<div class="student">
Student:
<span v-if="student">{{ student }}</span>
<span v-else>Keine Angaben gefunden</span>
</div>
<div class="price-employee">
Employee:
<span v-if="employee">{{ employee }}</span>
<span v-else>Keine Angaben gefunden</span>
</div>
<div class="price-guest">
Guest:
<span v-if="guest">{{ guest }}</span>
<span v-else>Keine Angaben gefunden</span>
</div>
</div>
</template>
<script>
export default {
name: "PriceOverview",
props: ['student', 'employee', 'guest'],
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,105 @@
<template>
<div>
<div id="rating" class="mt-3"><strong>Rating:</strong>
<fa-rating :glyph="star"
:spacing="-1"
:inactive-color="'#cfcfcf'"
:active-color="'#878787'"
:increment="0.5"
:fixed-points="2"
:show-rating="false"
:item-size="15"
:inline="true"
:read-only="true"
v-model="globalRating">
</fa-rating>
</div>
<div v-if="isAuthenticated()" id="user-rating" class="mt-3"><strong>Dein Rating:</strong>
<fa-rating :glyph="star"
:spacing="-1"
:inactive-color="'#cfcfcf'"
:active-color="'#0074D9'"
:increment="0.5"
:fixed-points="2"
:show-rating="false"
:item-size="15"
:inline="true"
v-model="userRating">
</fa-rating>
</div>
</div>
</template>
<script>
import router from '../../../router'
import {FaRating} from 'vue-rate-it';
import Star from 'vue-rate-it/glyphs/star';
import authentication from '../../../authentication'
import * as CONFIG from '../../../config'
export default {
name: "RatingCombined",
components: {FaRating},
props: ['globalRating', 'foodId'],
data() {
return {
star: Star,
userRating: 0.0,
loaded: false,
};
},
created() {
if (window.authentication.authenticated() && this.foodId) {
this.loadUserRating();
this.loaded = true;
}
},
watch: {
foodId: function () {
this.loadUserRating();
this.loaded = true;
},
userRating: function (newRating) {
if (authentication.authenticated() && this.loaded) {
let url = CONFIG.API_ROOT_FOOD.concat('/meals/').concat(this.foodId).concat('/rating');
window.axios
.post(url, {rating: newRating})
.then(response => {
this.$emit('updateFood');
}
)
.catch();
} else {
router.push({name: 'login'})
}
}
},
methods: {
isAuthenticated: function () {
return authentication.authenticated();
},
loadUserRating: function () {
console.log('LOAD USER RATING');
if (authentication.authenticated()) {
console.log(this.foodId);
let url = CONFIG.API_ROOT_ACCOUNT.concat('/food/ratings/?food_id=').concat(this.foodId);
window.axios
.get(url)
.then(response => {
if (response.data.length > 0) {
console.log('RATING');
console.log(response.data);
this.userRating = response.data[0].rating;
}
}
)
.catch();
}
},
},
}
</script>
<style scoped>
</style>