1
0
Fork 0
mirror of https://github.com/mealie-recipes/mealie.git synced 2025-07-25 08:09:41 +02:00

feat: Data Management from Shopping List (#3603)

Co-authored-by: boc-the-git <3479092+boc-the-git@users.noreply.github.com>
This commit is contained in:
Michael Genson 2024-05-22 16:58:16 -05:00 committed by GitHub
parent 89982f3e5f
commit ca26639525
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 140 additions and 35 deletions

View file

@ -29,6 +29,7 @@
</v-col>
<v-col v-if="!disableAmount" sm="12" md="3" cols="12">
<v-autocomplete
ref="unitAutocomplete"
v-model="value.unit"
:search-input.sync="unitSearch"
auto-select-first
@ -57,6 +58,7 @@
<!-- Foods Input -->
<v-col v-if="!disableAmount" m="12" md="3" cols="12" class="">
<v-autocomplete
ref="foodAutocomplete"
v-model="value.food"
:search-input.sync="foodSearch"
auto-select-first
@ -200,11 +202,13 @@ export default defineComponent({
const foodStore = useFoodStore();
const foodData = useFoodData();
const foodSearch = ref("");
const foodAutocomplete = ref<HTMLInputElement>();
async function createAssignFood() {
foodData.data.name = foodSearch.value;
props.value.food = await foodStore.actions.createOne(foodData.data) || undefined;
foodData.reset();
foodAutocomplete.value?.blur();
}
// ==================================================
@ -212,11 +216,13 @@ export default defineComponent({
const unitStore = useUnitStore();
const unitsData = useUnitData();
const unitSearch = ref("");
const unitAutocomplete = ref<HTMLInputElement>();
async function createAssignUnit() {
unitsData.data.name = unitSearch.value;
props.value.unit = await unitStore.actions.createOne(unitsData.data) || undefined;
unitsData.reset();
unitAutocomplete.value?.blur();
}
const state = reactive({
@ -269,7 +275,9 @@ export default defineComponent({
contextMenuOptions,
handleUnitEnter,
handleFoodEnter,
foodAutocomplete,
createAssignFood,
unitAutocomplete,
createAssignUnit,
foods: foodStore.foods,
foodSearch,

View file

@ -9,6 +9,7 @@
:item-id.sync="listItem.foodId"
:label="$t('shopping-list.food')"
:icon="$globals.icons.foods"
@create="createAssignFood"
/>
<InputLabelType
v-model="listItem.unit"
@ -16,6 +17,7 @@
:item-id.sync="listItem.unitId"
:label="$t('general.units')"
:icon="$globals.icons.units"
@create="createAssignUnit"
/>
</div>
<div class="d-md-flex align-center" style="gap: 20px">
@ -28,37 +30,49 @@
@keypress="handleNoteKeyPress"
></v-textarea>
</div>
<div class="d-flex align-end" style="gap: 20px">
<div>
<InputQuantity v-model="listItem.quantity" />
</div>
<div style="max-width: 300px" class="mt-3 mr-auto">
<InputLabelType
v-model="listItem.label"
:items="labels"
:item-id.sync="listItem.labelId"
:label="$t('shopping-list.label')"
/>
</div>
<div class="d-flex flex-wrap align-end" style="gap: 20px">
<div class="d-flex align-end">
<div>
<InputQuantity v-model="listItem.quantity" />
</div>
<div style="max-width: 300px" class="mt-3 mr-auto">
<InputLabelType
v-model="listItem.label"
:items="labels"
:item-id.sync="listItem.labelId"
:label="$t('shopping-list.label')"
/>
</div>
<v-menu
v-if="listItem.recipeReferences && listItem.recipeReferences.length > 0"
open-on-hover
offset-y
left
top
>
<template #activator="{ on, attrs }">
<v-icon class="mt-auto" icon v-bind="attrs" color="warning" v-on="on">
{{ $globals.icons.alert }}
</v-icon>
</template>
<v-card max-width="350px" class="left-warning-border">
<v-card-text>
{{ $t("shopping-list.linked-item-warning") }}
</v-card-text>
</v-card>
</v-menu>
<v-menu
v-if="listItem.recipeReferences && listItem.recipeReferences.length > 0"
open-on-hover
offset-y
left
top
>
<template #activator="{ on, attrs }">
<v-icon class="mt-auto" icon v-bind="attrs" color="warning" v-on="on">
{{ $globals.icons.alert }}
</v-icon>
</template>
<v-card max-width="350px" class="left-warning-border">
<v-card-text>
{{ $t("shopping-list.linked-item-warning") }}
</v-card-text>
</v-card>
</v-menu>
</div>
<BaseButton
v-if="listItem.labelId && listItem.food && listItem.labelId !== listItem.food.labelId"
small
color="info"
:icon="$globals.icons.tagArrowRight"
:text="$tc('shopping-list.save-label')"
class="mt-2 align-items-flex-start"
@click="assignLabelToFood"
/>
<v-spacer />
</div>
</v-card-text>
</v-card>
@ -100,6 +114,7 @@ import { defineComponent, computed, watch } from "@nuxtjs/composition-api";
import { ShoppingListItemCreate, ShoppingListItemOut } from "~/lib/api/types/group";
import { MultiPurposeLabelOut } from "~/lib/api/types/labels";
import { IngredientFood, IngredientUnit } from "~/lib/api/types/recipe";
import { useFoodStore, useFoodData, useUnitStore, useUnitData } from "~/composables/store";
export default defineComponent({
props: {
@ -121,6 +136,12 @@ export default defineComponent({
},
},
setup(props, context) {
const foodStore = useFoodStore();
const foodData = useFoodData();
const unitStore = useUnitStore();
const unitData = useUnitData();
const listItem = computed({
get: () => {
return props.value;
@ -139,8 +160,47 @@ export default defineComponent({
}
);
async function createAssignFood(val: string) {
// keep UI reactive
listItem.value.food ? listItem.value.food.name = val : listItem.value.food = { name: val };
foodData.data.name = val;
const newFood = await foodStore.actions.createOne(foodData.data);
if (newFood) {
listItem.value.food = newFood;
listItem.value.foodId = newFood.id;
}
foodData.reset();
}
async function createAssignUnit(val: string) {
// keep UI reactive
listItem.value.unit ? listItem.value.unit.name = val : listItem.value.unit = { name: val };
unitData.data.name = val;
const newUnit = await unitStore.actions.createOne(unitData.data);
if (newUnit) {
listItem.value.unit = newUnit;
listItem.value.unitId = newUnit.id;
}
unitData.reset();
}
async function assignLabelToFood() {
if (!(listItem.value.food && listItem.value.foodId && listItem.value.labelId)) {
return;
}
listItem.value.food.labelId = listItem.value.labelId;
// @ts-ignore the food will have an id, even though TS says it might not
await foodStore.actions.updateOne(listItem.value.food);
}
return {
listItem,
createAssignFood,
createAssignUnit,
assignLabelToFood,
};
},
methods: {