Basic editing of users ingredients
This commit is contained in:
parent
a4a4497dc4
commit
6a7dfbe460
3 changed files with 105 additions and 13 deletions
56
src/components/ingredients/EditableIngredientsPanel.vue
Normal file
56
src/components/ingredients/EditableIngredientsPanel.vue
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
<template>
|
||||
|
||||
<div>
|
||||
<ul>
|
||||
<li v-for="ingredient in ingredients" :key="ingredient.id">
|
||||
<div v-if="editing">
|
||||
<ingredient-line :ingredient="ingredient" @update="updateIngredient" @update-ingredient="updateIngredient" @update-product-link="updateProduct" />
|
||||
<button @click="$emit('on-delete', ingredient)">
|
||||
<img class="icon" :src="require('@/assets/trash.svg')" />
|
||||
</button>
|
||||
</div>
|
||||
<div v-else>
|
||||
<compact-parsed-ingredient :ingredient="ingredient" />
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
<button v-if="editing" @click="$emit('on-add')">Add Ingredient</button>
|
||||
<button @click="editing = !editing">{{ editing ? 'Done' : 'Edit' }}</button>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
<style>
|
||||
.icon {
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import data from '@/data.js'
|
||||
import IngredientLine from './IngredientLine.vue'
|
||||
import CompactParsedIngredient from './CompactParsedIngredient.vue'
|
||||
|
||||
export default {
|
||||
name: 'EditableIngredientsPanel',
|
||||
components: { IngredientLine, CompactParsedIngredient },
|
||||
props: ['ingredients', 'editOnly'],
|
||||
data() {
|
||||
return {
|
||||
editing: this.editOnly ?? false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async updateProduct(ingredient, product_link) {
|
||||
const product = await data.parseProduct(ingredient, product_link);
|
||||
this.$emit('on-update-ingredient', ingredient, { ...ingredient, product });
|
||||
},
|
||||
async updateIngredient(ingredient, line) {
|
||||
const newIngredients = await data.parseIngredients([line]);
|
||||
this.$emit('on-update-ingredient', ingredient, newIngredients[0]);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
|
@ -3,7 +3,11 @@
|
|||
<h1>Shopping List</h1>
|
||||
<h4>Included Meals</h4>
|
||||
<meal-selection-list @meal-selected="mealSelected" @meal-unselected="mealUnselected" />
|
||||
<ul>
|
||||
<h4>My Requests</h4>
|
||||
<editable-ingredients-panel @on-add="addIngredient" @on-delete="deleteIngredient" @on-update-ingredient="updateIngredient" :ingredients="mySources" />
|
||||
|
||||
<h4>Full shopping list</h4>
|
||||
<ul class="full-shopping-list">
|
||||
<li v-for="item in shoppingList" :key="item.id">
|
||||
<shopping-list-item :product="item.product" :sources="item.sources" />
|
||||
</li>
|
||||
|
|
@ -38,7 +42,7 @@
|
|||
|
||||
<style scoped>
|
||||
|
||||
li {
|
||||
.full-shopping-list li {
|
||||
list-style-type: none;
|
||||
|
||||
border: 1px solid #ccc;
|
||||
|
|
@ -46,28 +50,33 @@ li {
|
|||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
ul {
|
||||
.full-shopping-list {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import data from '@/data.js'
|
||||
|
||||
import EditableIngredientsPanel from '@/components/ingredients/EditableIngredientsPanel.vue'
|
||||
import ShoppingListItem from './ShoppingListItem.vue'
|
||||
import MealSelectionList from './MealSelectionList.vue'
|
||||
|
||||
import { mealToShoppingListSources, removeMealFromShoppingListSources, groupByProduct } from './shopping.js'
|
||||
|
||||
export default {
|
||||
name: 'ShoppingPage',
|
||||
components: {
|
||||
ShoppingListItem, MealSelectionList
|
||||
},
|
||||
components: { ShoppingListItem, MealSelectionList, EditableIngredientsPanel },
|
||||
data() {
|
||||
return { shoppingList: [], sources: [] }
|
||||
return { shoppingList: [], sources: [], mySources: [] }
|
||||
},
|
||||
watch: {
|
||||
sources() {
|
||||
async sources() {
|
||||
this.shoppingList = groupByProduct(this.sources);
|
||||
|
||||
const person = await data.currentUser();
|
||||
this.mySources = this.sources.filter(source => source.person?.id === person?.id).map(source => source.ingredient);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
|
@ -76,6 +85,25 @@ export default {
|
|||
},
|
||||
mealUnselected(meal) {
|
||||
this.sources = removeMealFromShoppingListSources(this.sources, meal);
|
||||
},
|
||||
async addIngredient() {
|
||||
const person = await data.currentUser();
|
||||
if (!person) return;
|
||||
|
||||
this.sources = this.sources.concat([{ ingredient: { id: 0 }, person }]);
|
||||
},
|
||||
async deleteIngredient(ingredient) {
|
||||
const person = await data.currentUser();
|
||||
if (!person) return;
|
||||
|
||||
const isMatch = source => source.ingredient === ingredient && source.person?.id === person.id;
|
||||
this.sources = this.sources.filter(source => !isMatch(source));
|
||||
},
|
||||
async updateIngredient(oldIngredient, newIngredient) {
|
||||
const person = await data.currentUser();
|
||||
if (!person) return;
|
||||
|
||||
this.sources = this.sources.map(source => source.ingredient === oldIngredient ? { ingredient: newIngredient, person } : source);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,20 +14,28 @@ export function mealToShoppingListSources(meal) {
|
|||
}
|
||||
|
||||
export function removeMealFromShoppingListSources(sources, meal) {
|
||||
return sources.filter(source => source.meal.id !== meal.id);
|
||||
return sources.filter(source => source.meal?.id !== meal.id);
|
||||
}
|
||||
|
||||
export function groupByProduct(sources) {
|
||||
const noProductKey = "no-product";
|
||||
const noProduct = { name: "No product", };
|
||||
|
||||
const grouped = {};
|
||||
for (const source of sources) {
|
||||
if (!grouped[source.ingredient.product.id]) {
|
||||
grouped[source.ingredient.product.id] = {
|
||||
product: source.ingredient.product,
|
||||
const key = source.ingredient?.product?.id ?? noProductKey;
|
||||
if (!key) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!grouped[key]) {
|
||||
grouped[key] = {
|
||||
product: source.ingredient.product ?? noProduct,
|
||||
sources: [],
|
||||
};
|
||||
}
|
||||
|
||||
grouped[source.ingredient.product.id].sources.push(source);
|
||||
grouped[key].sources.push(source);
|
||||
}
|
||||
|
||||
return Object.values(grouped);
|
||||
|
|
|
|||
Loading…
Reference in a new issue