2024-05-11 06:03:29 +00:00
|
|
|
<template>
|
|
|
|
|
<div>
|
|
|
|
|
<h1>Shopping List</h1>
|
2024-05-12 06:32:28 +00:00
|
|
|
<h4>My Requests</h4>
|
|
|
|
|
<editable-ingredients-panel @on-add="addIngredient" @on-delete="deleteIngredient" @on-update-ingredient="updateIngredient" :ingredients="mySources" />
|
2024-05-13 03:45:46 +00:00
|
|
|
|
2024-05-12 07:33:13 +00:00
|
|
|
<h3>Full shopping list</h3>
|
2024-05-13 03:45:46 +00:00
|
|
|
<h4>Included Meals</h4>
|
|
|
|
|
<meal-selection-list @meal-selected="mealSelected" @meal-unselected="mealUnselected" :checked="includedMeals" :meals="meals" />
|
2024-05-12 06:32:28 +00:00
|
|
|
<ul class="full-shopping-list">
|
2024-05-11 06:03:29 +00:00
|
|
|
<li v-for="item in shoppingList" :key="item.id">
|
|
|
|
|
<shopping-list-item :product="item.product" :sources="item.sources" />
|
|
|
|
|
</li>
|
|
|
|
|
</ul>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!--
|
|
|
|
|
# Functions
|
|
|
|
|
* Add a random item to next shop
|
|
|
|
|
* Add meals to next shop
|
|
|
|
|
* Show cards for the next 7 meals
|
|
|
|
|
* Slider / drawer for more meals
|
|
|
|
|
* Check meal to add
|
|
|
|
|
* Update shopping list automatically as meals change
|
|
|
|
|
* Visual indicator for meals that are already in the list
|
|
|
|
|
* Visual indicator for purchased meals
|
|
|
|
|
* Aggregate items from meals and random items into a single list of products
|
|
|
|
|
* For each product, need to have visibility of
|
|
|
|
|
* Name
|
|
|
|
|
* Link
|
|
|
|
|
* Image
|
|
|
|
|
* Quantity
|
|
|
|
|
* Source meal / person
|
|
|
|
|
* Date added / for
|
|
|
|
|
* Need to be able to mark list as done
|
|
|
|
|
* Keeps history - track purchased meals
|
|
|
|
|
* Clears list
|
|
|
|
|
|
|
|
|
|
* History view of purchased lists (seperate page ofc)
|
|
|
|
|
-->
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<style scoped>
|
|
|
|
|
|
2024-05-12 06:32:28 +00:00
|
|
|
.full-shopping-list li {
|
2024-05-11 06:03:29 +00:00
|
|
|
list-style-type: none;
|
|
|
|
|
|
|
|
|
|
border: 1px solid #ccc;
|
|
|
|
|
border-radius: 0.5em;
|
|
|
|
|
margin-bottom: 1em;
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-12 06:32:28 +00:00
|
|
|
.full-shopping-list {
|
2024-05-11 06:03:29 +00:00
|
|
|
padding: 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
</style>
|
|
|
|
|
|
|
|
|
|
<script>
|
2024-05-12 06:32:28 +00:00
|
|
|
import data from '@/data.js'
|
|
|
|
|
|
|
|
|
|
import EditableIngredientsPanel from '@/components/ingredients/EditableIngredientsPanel.vue'
|
2024-05-11 06:03:29 +00:00
|
|
|
import ShoppingListItem from './ShoppingListItem.vue'
|
|
|
|
|
import MealSelectionList from './MealSelectionList.vue'
|
2024-05-12 06:32:28 +00:00
|
|
|
|
2024-05-13 03:45:46 +00:00
|
|
|
import { mealToShoppingListSources, groupByProduct } from './shopping.js'
|
2024-05-11 06:03:29 +00:00
|
|
|
|
|
|
|
|
export default {
|
|
|
|
|
name: 'ShoppingPage',
|
2024-05-12 06:32:28 +00:00
|
|
|
components: { ShoppingListItem, MealSelectionList, EditableIngredientsPanel },
|
2024-05-11 06:03:29 +00:00
|
|
|
data() {
|
2024-05-13 03:45:46 +00:00
|
|
|
const from = new Date();
|
|
|
|
|
from.setTime(0);
|
|
|
|
|
|
|
|
|
|
const to = new Date();
|
|
|
|
|
to.setDate(to.getDate() + 7);
|
|
|
|
|
|
|
|
|
|
return { from, to, shoppingList: [], sources: [], mySources: [], includedMeals: [], meals: [], person: null }
|
2024-05-12 03:32:18 +00:00
|
|
|
},
|
|
|
|
|
watch: {
|
2024-05-13 03:45:46 +00:00
|
|
|
sources() {
|
2024-05-12 03:32:18 +00:00
|
|
|
this.shoppingList = groupByProduct(this.sources);
|
2024-05-13 03:45:46 +00:00
|
|
|
},
|
|
|
|
|
includedMeals() {
|
|
|
|
|
this.updateSources();
|
|
|
|
|
},
|
|
|
|
|
mySources() {
|
|
|
|
|
this.updateSources();
|
2024-05-12 03:32:18 +00:00
|
|
|
}
|
|
|
|
|
},
|
2024-05-13 03:45:46 +00:00
|
|
|
async beforeMount() {
|
|
|
|
|
const person = await data.currentUser();
|
|
|
|
|
if (!person)
|
|
|
|
|
return this.$router.push({ name: 'login' });
|
|
|
|
|
|
|
|
|
|
this.person = person;
|
|
|
|
|
|
|
|
|
|
this.meals = await data.getMeals(this.from, this.to);
|
|
|
|
|
// this.includedMeals = this.meals;
|
|
|
|
|
},
|
2024-05-12 03:32:18 +00:00
|
|
|
methods: {
|
2024-05-13 03:45:46 +00:00
|
|
|
updateSources() {
|
|
|
|
|
const person = this.person;
|
|
|
|
|
if (!person) return;
|
|
|
|
|
|
|
|
|
|
const mealSources = this.includedMeals.flatMap(mealToShoppingListSources);
|
|
|
|
|
const personSources = this.mySources.map(ingredient => ({ ingredient, person }));
|
|
|
|
|
|
|
|
|
|
this.sources = [...mealSources, ...personSources];
|
|
|
|
|
},
|
2024-05-12 03:32:18 +00:00
|
|
|
mealSelected(meal) {
|
2024-05-13 03:45:46 +00:00
|
|
|
this.includedMeals = [...this.includedMeals, meal];
|
2024-05-12 03:32:18 +00:00
|
|
|
},
|
|
|
|
|
mealUnselected(meal) {
|
2024-05-13 03:45:46 +00:00
|
|
|
this.includedMeals = this.includedMeals.filter(m => m !== meal);
|
2024-05-12 06:32:28 +00:00
|
|
|
},
|
2024-05-13 03:45:46 +00:00
|
|
|
addIngredient() {
|
|
|
|
|
const person = this.person;
|
2024-05-12 06:32:28 +00:00
|
|
|
if (!person) return;
|
|
|
|
|
|
2024-05-13 03:45:46 +00:00
|
|
|
this.myRequestedItems = [{ id: 0 }, ...this.mySources];
|
2024-05-12 06:32:28 +00:00
|
|
|
},
|
2024-05-13 03:45:46 +00:00
|
|
|
deleteIngredient(ingredient) {
|
|
|
|
|
const person = this.person;
|
2024-05-12 06:32:28 +00:00
|
|
|
if (!person) return;
|
|
|
|
|
|
2024-05-13 03:45:46 +00:00
|
|
|
this.myRequestedItems = this.mySources.filter(source => source !== ingredient);
|
2024-05-12 06:32:28 +00:00
|
|
|
},
|
2024-05-13 03:45:46 +00:00
|
|
|
updateIngredient(oldIngredient, newIngredient) {
|
|
|
|
|
const person = this.person;
|
2024-05-12 06:32:28 +00:00
|
|
|
if (!person) return;
|
|
|
|
|
|
2024-05-13 03:45:46 +00:00
|
|
|
this.myRequestedItems = this.mySources.map(source => source === oldIngredient ? newIngredient : source);
|
2024-05-11 06:03:29 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
</script>
|