Skip to content

Commit

Permalink
shopping from meal plan edit
Browse files Browse the repository at this point in the history
  • Loading branch information
vabene1111 committed Dec 28, 2024
1 parent bf4fc9a commit c1bfa56
Show file tree
Hide file tree
Showing 45 changed files with 291 additions and 152 deletions.
26 changes: 17 additions & 9 deletions cookbook/serializer.py
Original file line number Diff line number Diff line change
Expand Up @@ -1155,10 +1155,8 @@ class AutoMealPlanSerializer(serializers.Serializer):


class ShoppingListRecipeSerializer(serializers.ModelSerializer):
recipe_name = serializers.ReadOnlyField(source='recipe.name')
mealplan_note = serializers.ReadOnlyField(source='mealplan.note')
mealplan_from_date = serializers.ReadOnlyField(source='mealplan.from_date')
mealplan_type = serializers.ReadOnlyField(source='mealplan.meal_type.name')
recipe_data = RecipeOverviewSerializer(source='recipe', read_only=True, required=False)
meal_plan_data = MealPlanSerializer(source='mealplan', read_only=True, required=False)
servings = CustomDecimalField()

def update(self, instance, validated_data):
Expand All @@ -1170,18 +1168,19 @@ def update(self, instance, validated_data):

class Meta:
model = ShoppingListRecipe
fields = ('id', 'recipe_name', 'name', 'recipe', 'mealplan', 'servings', 'mealplan_note', 'mealplan_from_date',
'mealplan_type')
fields = ('id', 'name', 'recipe', 'recipe_data', 'mealplan', 'meal_plan_data', 'servings',)
read_only_fields = ('id',)


class ShoppingListEntrySerializer(WritableNestedModelSerializer):
food = FoodSerializer(allow_null=True)
unit = UnitSerializer(allow_null=True, required=False)
recipe_mealplan = ShoppingListRecipeSerializer(source='list_recipe', read_only=True)
list_recipe_data = ShoppingListRecipeSerializer(source='list_recipe', read_only=True)
amount = CustomDecimalField()
created_by = UserSerializer(read_only=True)
completed_at = serializers.DateTimeField(allow_null=True, required=False)
mealplan_id = serializers.IntegerField(required=False, write_only=True,
help_text='If a mealplan id is given try to find existing or create new ShoppingListRecipe with that meal plan and link entry to it')

def get_fields(self, *args, **kwargs):
fields = super().get_fields(*args, **kwargs)
Expand Down Expand Up @@ -1215,10 +1214,20 @@ def run_validation(self, data):
def create(self, validated_data):
validated_data['space'] = self.context['request'].space
validated_data['created_by'] = self.context['request'].user

if validated_data['mealplan_id']:
slr, created = ShoppingListRecipe.objects.get_or_create(mealplan_id=validated_data['mealplan_id'], mealplan__space=self.context['request'].space)
validated_data['list_recipe'] = slr
del validated_data['mealplan_id']

return super().create(validated_data)

def update(self, instance, validated_data):
user = self.context['request'].user

if validated_data['mealplan_id']:
del validated_data['mealplan_id']

# update the onhand for food if shopping_add_onhand is True
if user.userpreference.shopping_add_onhand:
if checked := validated_data.get('checked', None):
Expand All @@ -1232,8 +1241,7 @@ class Meta:
model = ShoppingListEntry
fields = (
'id', 'list_recipe', 'food', 'unit', 'amount', 'order', 'checked',
'recipe_mealplan',
'created_by', 'created_at', 'updated_at', 'completed_at', 'delay_until'
'list_recipe_data', 'created_by', 'created_at', 'updated_at', 'completed_at', 'delay_until', 'mealplan_id'
)
read_only_fields = ('id', 'created_by', 'created_at')

Expand Down
2 changes: 1 addition & 1 deletion vue3/src/components/display/ClosableHelpAlert.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
</template>
<p>
{{ props.text}}
<v-btn color="success" class="float-right" v-if="props.actionText != ''" @click="emit('click')">{{ actionText}}</v-btn>
<v-btn color="success" class="float-right" v-if="props.actionText" @click="emit('click')">{{ actionText}}</v-btn>
</p>
</v-alert>
</template>
Expand Down
2 changes: 1 addition & 1 deletion vue3/src/components/display/MealPlanView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
</v-card>


<model-edit-dialog model="MealPlan" v-model="newPlanDialog" :itemDefaults="newPlanDialogDefaultItem"
<model-edit-dialog model="MealPlan" v-model="newPlanDialog" :itemDefaults="newPlanDialogDefaultItem" :close-after-create="false"
@create="(arg: any) => useMealPlanStore().plans.set(arg.id, arg)"></model-edit-dialog>
</v-col>
</v-row>
Expand Down
16 changes: 9 additions & 7 deletions vue3/src/components/display/ShoppingLineItem.vue
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ const amounts = computed((): Map<number, ShoppingLineAmount> => {
* compute the second (info) row of the line item based on the entries and the device settings
*/
const infoRow = computed(() => {
if(props.hideInfoRow){
if (props.hideInfoRow) {
return ''
}
Expand All @@ -171,14 +171,16 @@ const infoRow = computed(() => {
authors.push(e.createdBy.displayName)
}
if (e.recipeMealplan !== null) {
let recipe_name = e.recipeMealplan.recipeName
if (recipes.indexOf(recipe_name) === -1) {
recipes.push(recipe_name.substring(0, 14) + (recipe_name.length > 14 ? '..' : ''))
if (e.listRecipe != null) {
if (e.listRecipeData.recipe != null) {
let recipe_name = e.listRecipeData.recipeData.name
if (recipes.indexOf(recipe_name) === -1) {
recipes.push(recipe_name.substring(0, 14) + (recipe_name.length > 14 ? '..' : ''))
}
}
if ('mealplan_from_date' in e.recipeMealplan) {
let meal_plan_entry = (e?.recipeMealplan?.mealplanType || '') + ' (' + DateTime.fromJSDate(e.recipeMealplan.mealplanFromDate).toLocaleString(DateTime.DATETIME_SHORT) + ')'
if (e.listRecipeData.mealplan != null) {
let meal_plan_entry = (e.listRecipeData.mealPlanData.mealType.name.substring(0, 8) || '') + ' (' + DateTime.fromJSDate(e.listRecipeData.mealPlanData.fromDate).toLocaleString(DateTime.DATE_SHORT) + ')'
if (meal_pans.indexOf(meal_plan_entry) === -1) {
meal_pans.push(meal_plan_entry)
}
Expand Down
52 changes: 12 additions & 40 deletions vue3/src/components/display/ShoppingListView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -83,16 +83,7 @@
</template>
</v-alert>

<v-text-field :label="$t('Shopping_input_placeholder')" density="compact" @keyup.enter="addIngredient()" v-model="ingredientInput" hide-details>
<template #append>
<v-btn
density="comfortable"
@click="addIngredient()"
:icon="ingredientInputIcon"
color="create"
></v-btn>
</template>
</v-text-field>
<shopping-list-entry-input></shopping-list-entry-input>

<v-list class="mt-3" density="compact" v-if="!useShoppingStore().initialized">
<v-skeleton-loader type="list-item"></v-skeleton-loader>
Expand Down Expand Up @@ -168,7 +159,7 @@
<v-row>
<v-col>
<v-card>
<v-card-title>{{ $t('Recipes') }}</v-card-title>
<v-card-title>{{ $t('Recipes') }} / {{ $t('Meal_Plan') }}</v-card-title>
<v-card-text>
<v-list>
<v-list-item v-for="r in useShoppingStore().getAssociatedRecipes()">
Expand All @@ -179,9 +170,14 @@
@confirm="(servings: number) => {updateRecipeServings(r, servings)}"></number-scaler-dialog>
</v-btn>
</template>
<span class="ms-2">
{{ r.recipeName }}
</span>

<div class="ms-2">
<p v-if="r.recipe">{{ r.recipeData.name }} <br/></p>
<p v-if="r.mealplan">
{{ r.mealPlanData.mealType.name }} - {{ DateTime.fromJSDate(r.mealPlanData.fromDate).toLocaleString(DateTime.DATE_FULL) }}
</p>
</div>

<template #append>
<v-btn icon color="delete">
<v-icon icon="$delete"></v-icon>
Expand Down Expand Up @@ -230,14 +226,13 @@ import {useI18n} from "vue-i18n";
import NumberScalerDialog from "@/components/inputs/NumberScalerDialog.vue";
import SupermarketEditor from "@/components/model_editors/SupermarketEditor.vue";
import DeleteConfirmDialog from "@/components/dialogs/DeleteConfirmDialog.vue";
import ShoppingListEntryInput from "@/components/inputs/ShoppingListEntryInput.vue";
import {DateTime} from "luxon";
const {t} = useI18n()
const currentTab = ref("shopping")
const ingredientInput = ref('')
const ingredientInputIcon = ref('fa-solid fa-plus')
const shoppingLineItemDialog = ref(false)
const shoppingLineItemDialogFood = ref({} as IShoppingListFood)
Expand Down Expand Up @@ -273,29 +268,6 @@ onMounted(() => {
}
})
/**
* add new ingredient from ingredient text input
*/
function addIngredient() {
const api = new ApiApi()
api.apiIngredientFromStringCreate({ingredientString: {text: ingredientInput.value} as IngredientString}).then(r => {
useShoppingStore().createObject({
amount: Math.max(r.amount, 1),
unit: r.unit,
food: r.food,
} as ShoppingListEntry, true)
ingredientInput.value = ''
ingredientInputIcon.value = 'fa-solid fa-check'
setTimeout(() => {
ingredientInputIcon.value = 'fa-solid fa-plus'
}, 1000)
}).catch(err => {
useMessageStore().addError(ErrorMessageType.CREATE_ERROR, err)
})
}
/**
* determines if a category as entries that should be visible
* @param category
Expand Down
73 changes: 73 additions & 0 deletions vue3/src/components/inputs/ShoppingListEntryInput.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<template>
<v-text-field :label="$t('Shopping_input_placeholder')" density="compact" @keyup.enter="addIngredient()" v-model="ingredientInput" :loading="props.loading" hide-details>
<template #append>
<v-btn
density="comfortable"
@click="addIngredient()"
:icon="ingredientInputIcon"
color="create"
></v-btn>
</template>
</v-text-field>
</template>

<script setup lang="ts">
import {PropType, ref} from "vue";
import {ApiApi, IngredientString, MealPlan, ShoppingListEntry, ShoppingListRecipe} from "@/openapi";
import {useShoppingStore} from "@/stores/ShoppingStore";
import {ErrorMessageType, useMessageStore} from "@/stores/MessageStore";
const props = defineProps({
shoppingListRecipe: {type: {} as PropType<ShoppingListRecipe>, required: false},
mealPlan: {type: {} as PropType<MealPlan>, required: false},
loading: {type: Boolean, required: false},
})
const ingredientInput = ref('')
const ingredientInputIcon = ref('fa-solid fa-plus')
const loading = ref(false)
/**
* add new ingredient from ingredient text input
*/
function addIngredient() {
const api = new ApiApi()
loading.value = true
api.apiIngredientFromStringCreate({ingredientString: {text: ingredientInput.value} as IngredientString}).then(r => {
let sle = {
amount: Math.max(r.amount, 1),
unit: r.unit,
food: r.food,
} as ShoppingListEntry
console.log('adding SLR ? ', props.mealPlan)
if (props.mealPlan) {
console.log('yes')
sle.mealplanId = props.mealPlan.id
}
useShoppingStore().createObject(sle, true).finally(() => {
loading.value = false
})
ingredientInput.value = ''
ingredientInputIcon.value = 'fa-solid fa-check'
setTimeout(() => {
ingredientInputIcon.value = 'fa-solid fa-plus'
}, 1000)
}).catch(err => {
useMessageStore().addError(ErrorMessageType.CREATE_ERROR, err)
loading.value = false
})
}
</script>


<style scoped>
</style>
Loading

0 comments on commit c1bfa56

Please sign in to comment.