mirror of
https://github.com/TandoorRecipes/recipes.git
synced 2026-01-01 04:10:06 -05:00
lots of shopping list improvements
This commit is contained in:
@@ -1184,7 +1184,6 @@ class ShoppingListRecipeSerializer(serializers.ModelSerializer):
|
|||||||
servings = CustomDecimalField()
|
servings = CustomDecimalField()
|
||||||
|
|
||||||
def update(self, instance, validated_data):
|
def update(self, instance, validated_data):
|
||||||
# TODO remove once old shopping list
|
|
||||||
if 'servings' in validated_data and self.context.get('view', None).__class__.__name__ != 'ShoppingListViewSet':
|
if 'servings' in validated_data and self.context.get('view', None).__class__.__name__ != 'ShoppingListViewSet':
|
||||||
SLR = RecipeShoppingEditor(user=self.context['request'].user, space=self.context['request'].space)
|
SLR = RecipeShoppingEditor(user=self.context['request'].user, space=self.context['request'].space)
|
||||||
SLR.edit_servings(servings=validated_data['servings'], id=instance.id)
|
SLR.edit_servings(servings=validated_data['servings'], id=instance.id)
|
||||||
@@ -1274,6 +1273,7 @@ class ShoppingListEntrySimpleCreateSerializer(serializers.Serializer):
|
|||||||
amount = CustomDecimalField()
|
amount = CustomDecimalField()
|
||||||
unit_id = serializers.IntegerField(allow_null=True)
|
unit_id = serializers.IntegerField(allow_null=True)
|
||||||
food_id = serializers.IntegerField(allow_null=True)
|
food_id = serializers.IntegerField(allow_null=True)
|
||||||
|
ingredient_id = serializers.IntegerField(allow_null=True)
|
||||||
|
|
||||||
|
|
||||||
class ShoppingListEntryBulkCreateSerializer(serializers.Serializer):
|
class ShoppingListEntryBulkCreateSerializer(serializers.Serializer):
|
||||||
|
|||||||
@@ -1375,7 +1375,7 @@ class ShoppingListRecipeViewSet(LoggingMixin, viewsets.ModelViewSet):
|
|||||||
pagination_class = DefaultPagination
|
pagination_class = DefaultPagination
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
self.queryset = self.queryset.filter(Q(entries__space=self.request.space) | Q(recipe__space=self.request.space))
|
self.queryset = self.queryset.filter(Q(entries__space=self.request.space) | Q(recipe__space=self.request.space) | Q(mealplan__space=self.request.space))
|
||||||
|
|
||||||
# TODO implement test for this
|
# TODO implement test for this
|
||||||
if not self.detail:
|
if not self.detail:
|
||||||
@@ -1405,6 +1405,7 @@ class ShoppingListRecipeViewSet(LoggingMixin, viewsets.ModelViewSet):
|
|||||||
amount=e['amount'],
|
amount=e['amount'],
|
||||||
unit_id=e['unit_id'],
|
unit_id=e['unit_id'],
|
||||||
food_id=e['food_id'],
|
food_id=e['food_id'],
|
||||||
|
ingredient_id=e['ingredient_id'],
|
||||||
created_by_id=request.user.id,
|
created_by_id=request.user.id,
|
||||||
space_id=request.space.id,
|
space_id=request.space.id,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -99,6 +99,7 @@ function loadRecipeData() {
|
|||||||
amount: ingredient.amount,
|
amount: ingredient.amount,
|
||||||
food: ingredient.food,
|
food: ingredient.food,
|
||||||
unit: ingredient.unit,
|
unit: ingredient.unit,
|
||||||
|
ingredient: ingredient,
|
||||||
checked: (ingredient.food ? !(ingredient.food.ignoreShopping || ingredient.food.foodOnhand) : true),
|
checked: (ingredient.food ? !(ingredient.food.ignoreShopping || ingredient.food.foodOnhand) : true),
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@@ -132,7 +133,8 @@ function createShoppingListRecipe() {
|
|||||||
shoppingListEntries.entries.push({
|
shoppingListEntries.entries.push({
|
||||||
amount: entry.amount * (servings.value / (recipe.value.servings ? recipe.value.servings : 1)),
|
amount: entry.amount * (servings.value / (recipe.value.servings ? recipe.value.servings : 1)),
|
||||||
foodId: entry.food ? entry.food.id! : null,
|
foodId: entry.food ? entry.food.id! : null,
|
||||||
unitId: entry.unit ? entry.unit.id! : null
|
unitId: entry.unit ? entry.unit.id! : null,
|
||||||
|
ingredientId: entry.ingredient ? entry.ingredient.id! : null,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<v-dialog max-width="1400" :activator="dialogActivator" v-model="model">
|
<v-dialog max-width="1400" :activator="dialogActivator" v-model="model">
|
||||||
<component :is="editorComponent" :item="item" @create="createEvent" @save="saveEvent" @delete="deleteEvent" dialog @close="model = false" :itemDefaults="itemDefaults"></component>
|
<component :is="editorComponent" :item="props.item" :item-id="props.itemId" @create="createEvent" @save="saveEvent" @delete="deleteEvent" dialog @close="model = false" :itemDefaults="props.itemDefaults"></component>
|
||||||
</v-dialog>
|
</v-dialog>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -20,6 +20,7 @@ const props = defineProps({
|
|||||||
model: { type: String as PropType<EditorSupportedModels>, required: true, },
|
model: { type: String as PropType<EditorSupportedModels>, required: true, },
|
||||||
activator: {default: 'parent'},
|
activator: {default: 'parent'},
|
||||||
item: {default: null},
|
item: {default: null},
|
||||||
|
itemId: {type: [Number, String], required: false, default: undefined},
|
||||||
itemDefaults: {required: false},
|
itemDefaults: {required: false},
|
||||||
disabledFields: {default: []},
|
disabledFields: {default: []},
|
||||||
closeAfterCreate: {default: true},
|
closeAfterCreate: {default: true},
|
||||||
|
|||||||
@@ -50,42 +50,33 @@
|
|||||||
</div>
|
</div>
|
||||||
<v-list density="compact">
|
<v-list density="compact">
|
||||||
<template v-for="[i, e] in shoppingListFood.entries" :key="e.id">
|
<template v-for="[i, e] in shoppingListFood.entries" :key="e.id">
|
||||||
<v-list-item border class="mt-1" :class="{'cursor-pointer': !e.recipeMealplan}">
|
<v-list-item border class="mt-1">
|
||||||
<v-list-item-title>
|
<v-list-item-title>
|
||||||
<b>
|
<b>
|
||||||
{{ $n(e.amount) }}
|
<span v-if="e.amount != 0">{{ $n(e.amount) }} </span>
|
||||||
<span v-if="e.unit">{{ e.unit.name }}</span>
|
<span v-if="e.unit">{{ e.unit.name }} </span>
|
||||||
</b>
|
</b>
|
||||||
{{ e.food.name }}
|
<span v-if="e.food">
|
||||||
|
{{ e.food.name }}
|
||||||
|
</span>
|
||||||
</v-list-item-title>
|
</v-list-item-title>
|
||||||
<v-list-item-subtitle v-if="e.completedAt">
|
<v-list-item-subtitle v-if="e.completedAt">
|
||||||
<v-icon icon="fa-solid fa-check" size="small" color="success"></v-icon>
|
<v-icon icon="fa-solid fa-check" size="small" color="success"></v-icon>
|
||||||
{{ $t('Completed') }} {{ DateTime.fromJSDate(e.completedAt).toLocaleString(DateTime.DATETIME_SHORT) }}
|
{{ $t('Completed') }} {{ DateTime.fromJSDate(e.completedAt).toLocaleString(DateTime.DATETIME_SHORT) }}
|
||||||
</v-list-item-subtitle>
|
</v-list-item-subtitle>
|
||||||
<v-list-item-subtitle v-if="e.recipeMealplan && e.recipeMealplan.recipeName !== ''">
|
<v-list-item-subtitle v-if="e.listRecipe && e.listRecipeData.recipe">
|
||||||
{{ e.recipeMealplan.servings }} x
|
{{ e.listRecipeData.servings }} x {{ e.listRecipeData.recipeData.name }}
|
||||||
<router-link :to="{name: 'view_recipe', params: {id: e.recipeMealplan.id}}" target="_blank" class="text-decoration-none"><b>
|
|
||||||
{{ e.recipeMealplan.recipeName }} </b>
|
|
||||||
</router-link>
|
|
||||||
</v-list-item-subtitle>
|
</v-list-item-subtitle>
|
||||||
<v-list-item-subtitle v-if="e.recipeMealplan && e.recipeMealplan.mealplanType !== undefined">
|
<v-list-item-subtitle v-if="e.listRecipe && e.listRecipeData.mealplan">
|
||||||
{{ e.recipeMealplan.mealplanType }} {{ DateTime.fromJSDate(e.recipeMealplan.mealplanFromDate).toLocaleString(DateTime.DATE_SHORT) }}
|
{{ e.listRecipeData.mealPlanData.mealType.name }} {{ DateTime.fromJSDate(e.listRecipeData.mealPlanData.fromDate).toLocaleString(DateTime.DATE_SHORT) }}
|
||||||
</v-list-item-subtitle>
|
</v-list-item-subtitle>
|
||||||
<v-list-item-subtitle>
|
<v-list-item-subtitle>
|
||||||
{{ e.createdBy.displayName }} - {{ DateTime.fromJSDate(e.createdAt).toLocaleString(DateTime.DATETIME_SHORT) }}
|
{{ e.createdBy.displayName }} - {{ DateTime.fromJSDate(e.createdAt).toLocaleString(DateTime.DATETIME_SHORT) }}
|
||||||
</v-list-item-subtitle>
|
</v-list-item-subtitle>
|
||||||
<v-list-item-subtitle v-if="isDelayed(e)" class="text-info font-weight-bold">
|
<v-list-item-subtitle v-if="isDelayed(e)" class="text-info font-weight-bold">
|
||||||
{{ $t('PostponedUntil') }} {{ DateTime.fromJSDate(e.delayUntil).toLocaleString(DateTime.DATETIME_SHORT) }}
|
{{ $t('PostponedUntil') }} {{ DateTime.fromJSDate(e.delayUntil!).toLocaleString(DateTime.DATETIME_SHORT) }}
|
||||||
</v-list-item-subtitle>
|
</v-list-item-subtitle>
|
||||||
|
|
||||||
<!-- <template #append>-->
|
|
||||||
<!-- <v-btn size="small" color="edit" icon="$edit" v-if="!e.recipeMealplan">-->
|
|
||||||
<!-- <v-icon icon="$edit"></v-icon>-->
|
|
||||||
<!-- <model-edit-dialog model="ShoppingListEntry" :item="e" @delete="useShoppingStore().entries.delete(e.id); shoppingListFood.entries.delete(e.id)"-->
|
|
||||||
<!-- @save="(args: ShoppingListEntry) => (shoppingListFood.entries.set(e.id, args))"></model-edit-dialog>-->
|
|
||||||
<!-- </v-btn>-->
|
|
||||||
<!-- </template>-->
|
|
||||||
|
|
||||||
<v-btn-group divided border>
|
<v-btn-group divided border>
|
||||||
<v-btn icon="" @click="e.amount = e.amount / 2; updateEntryAmount(e)" v-if="!e.listRecipeData">
|
<v-btn icon="" @click="e.amount = e.amount / 2; updateEntryAmount(e)" v-if="!e.listRecipeData">
|
||||||
<v-icon icon="fa-solid fa-divide"></v-icon>
|
<v-icon icon="fa-solid fa-divide"></v-icon>
|
||||||
@@ -102,13 +93,15 @@
|
|||||||
</v-btn>
|
</v-btn>
|
||||||
<v-btn color="edit" icon="$edit" v-if="!e.listRecipeData">
|
<v-btn color="edit" icon="$edit" v-if="!e.listRecipeData">
|
||||||
<v-icon icon="$edit"></v-icon>
|
<v-icon icon="$edit"></v-icon>
|
||||||
<model-edit-dialog model="ShoppingListEntry" :item="e" @delete="useShoppingStore().entries.delete(e.id); shoppingListFood.entries.delete(e.id)"
|
<model-edit-dialog model="ShoppingListEntry" :item="e"
|
||||||
@save="(args: ShoppingListEntry) => (shoppingListFood.entries.set(e.id, args))"></model-edit-dialog>
|
@delete="useShoppingStore().entries.delete(e.id!); shoppingListFood.entries.delete(e.id!)"
|
||||||
|
@save="(args: ShoppingListEntry) => { useShoppingStore().entries.set(e.id!, args); shoppingListFood.entries.set(e.id!, args) }"></model-edit-dialog>
|
||||||
</v-btn>
|
</v-btn>
|
||||||
<v-btn color="edit" icon="$recipes" v-if="e.listRecipe && e.listRecipeData.recipe" :to="{name: 'view_recipe', params: {id: e.listRecipeData.recipe}}">
|
<v-btn color="edit" icon="$recipes" v-if="e.listRecipe && e.listRecipeData.recipe"
|
||||||
|
:to="{name: 'view_recipe', params: {id: e.listRecipeData.recipe}}">
|
||||||
<v-icon icon="$recipes"></v-icon>
|
<v-icon icon="$recipes"></v-icon>
|
||||||
</v-btn>
|
</v-btn>
|
||||||
<v-btn icon="" @click="useShoppingStore().deleteObject(e, true); shoppingListFood.entries.delete(e.id)" color="delete">
|
<v-btn icon="" @click="useShoppingStore().deleteObject(e, true); shoppingListFood.entries.delete(e.id!)" color="delete">
|
||||||
<v-icon icon="$delete"></v-icon>
|
<v-icon icon="$delete"></v-icon>
|
||||||
</v-btn>
|
</v-btn>
|
||||||
</v-btn-group>
|
</v-btn-group>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<v-list-item class="swipe-container" :id="itemContainerId" @touchend="handleSwipe()" @click="emit('clicked', entries)"
|
<v-list-item class="swipe-container" :id="itemContainerId" @touchend="handleSwipe()" @click="dialog = true;"
|
||||||
v-if="(useUserPreferenceStore().deviceSettings.shopping_show_checked_entries || !isChecked) && (useUserPreferenceStore().deviceSettings.shopping_show_delayed_entries || !isShoppingLineDelayed)"
|
v-if="isShoppingListFoodVisible(props.shoppingListFood, useUserPreferenceStore().deviceSettings)"
|
||||||
>
|
>
|
||||||
<!-- <div class="swipe-action" :class="{'bg-success': !isChecked , 'bg-warning': isChecked }">-->
|
<!-- <div class="swipe-action" :class="{'bg-success': !isChecked , 'bg-warning': isChecked }">-->
|
||||||
<!-- <i class="swipe-icon fa-fw fas" :class="{'fa-check': !isChecked , 'fa-cart-plus': isChecked }"></i>-->
|
<!-- <i class="swipe-icon fa-fw fas" :class="{'fa-check': !isChecked , 'fa-cart-plus': isChecked }"></i>-->
|
||||||
@@ -44,6 +44,7 @@
|
|||||||
|
|
||||||
</v-list-item>
|
</v-list-item>
|
||||||
|
|
||||||
|
<shopping-line-item-dialog v-model="dialog" v-model:shopping-list-food="props.shoppingListFood"></shopping-line-item-dialog>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
@@ -56,7 +57,8 @@ import {useUserPreferenceStore} from "@/stores/UserPreferenceStore.js";
|
|||||||
import {ApiApi, Food, ShoppingListEntry} from '@/openapi'
|
import {ApiApi, Food, ShoppingListEntry} from '@/openapi'
|
||||||
import {ErrorMessageType, useMessageStore} from "@/stores/MessageStore";
|
import {ErrorMessageType, useMessageStore} from "@/stores/MessageStore";
|
||||||
import {IShoppingListFood, ShoppingLineAmount} from "@/types/Shopping";
|
import {IShoppingListFood, ShoppingLineAmount} from "@/types/Shopping";
|
||||||
import {isDelayed, isShoppingListFoodDelayed} from "@/utils/logic_utils";
|
import {isDelayed, isShoppingListFoodDelayed, isShoppingListFoodVisible} from "@/utils/logic_utils";
|
||||||
|
import ShoppingLineItemDialog from "@/components/dialogs/ShoppingLineItemDialog.vue";
|
||||||
|
|
||||||
const emit = defineEmits(['clicked'])
|
const emit = defineEmits(['clicked'])
|
||||||
|
|
||||||
@@ -65,6 +67,8 @@ const props = defineProps({
|
|||||||
hideInfoRow: {type: Boolean, default: false}
|
hideInfoRow: {type: Boolean, default: false}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const dialog = ref(false)
|
||||||
|
|
||||||
const entries = computed(() => {
|
const entries = computed(() => {
|
||||||
return Array.from(props.shoppingListFood.entries.values())
|
return Array.from(props.shoppingListFood.entries.values())
|
||||||
})
|
})
|
||||||
@@ -93,13 +97,6 @@ const isChecked = computed(() => {
|
|||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
|
|
||||||
/**
|
|
||||||
* determine if any entry in a given IShoppingListFood is delayed, if so return true
|
|
||||||
*/
|
|
||||||
const isShoppingLineDelayed = computed(() => {
|
|
||||||
return isShoppingListFoodDelayed(props.shoppingListFood)
|
|
||||||
})
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* style action button depending on if all items are checked or not
|
* style action button depending on if all items are checked or not
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -100,8 +100,7 @@
|
|||||||
<v-divider></v-divider>
|
<v-divider></v-divider>
|
||||||
|
|
||||||
<template v-for="[i, value] in category.foods" :key="value.food.id">
|
<template v-for="[i, value] in category.foods" :key="value.food.id">
|
||||||
<shopping-line-item :shopping-list-food="value"
|
<shopping-line-item :shopping-list-food="value" ></shopping-line-item>
|
||||||
@clicked="() => {shoppingLineItemDialog = true; shoppingLineItemDialogFood = value;}"></shopping-line-item>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
@@ -164,15 +163,20 @@
|
|||||||
<v-list>
|
<v-list>
|
||||||
<v-list-item v-for="r in useShoppingStore().getAssociatedRecipes()">
|
<v-list-item v-for="r in useShoppingStore().getAssociatedRecipes()">
|
||||||
<template #prepend>
|
<template #prepend>
|
||||||
<v-btn color="edit" icon :disabled="r.mealplan">
|
<v-btn color="edit" icon >
|
||||||
{{ r.servings }}
|
{{ r.servings }}
|
||||||
<number-scaler-dialog :number="r.servings"
|
<number-scaler-dialog
|
||||||
@confirm="(servings: number) => {updateRecipeServings(r, servings)}"></number-scaler-dialog>
|
v-if="r.mealplan == undefined"
|
||||||
|
:number="r.servings"
|
||||||
|
@confirm="(servings: number) => {updateRecipeServings(r, servings)}"
|
||||||
|
></number-scaler-dialog>
|
||||||
|
<model-edit-dialog model="MealPlan" :item-id="r.mealplan" v-if="r.mealplan != undefined" activator="parent"> </model-edit-dialog>
|
||||||
</v-btn>
|
</v-btn>
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<div class="ms-2">
|
<div class="ms-2">
|
||||||
<p v-if="r.recipe">{{ r.recipeData.name }} <br/></p>
|
<p v-if="r.recipe">{{ r.recipeData.name }}<br/></p>
|
||||||
<p v-if="r.mealplan">
|
<p v-if="r.mealplan">
|
||||||
{{ r.mealPlanData.mealType.name }} - {{ DateTime.fromJSDate(r.mealPlanData.fromDate).toLocaleString(DateTime.DATE_FULL) }}
|
{{ r.mealPlanData.mealType.name }} - {{ DateTime.fromJSDate(r.mealPlanData.fromDate).toLocaleString(DateTime.DATE_FULL) }}
|
||||||
</p>
|
</p>
|
||||||
@@ -181,7 +185,7 @@
|
|||||||
<template #append>
|
<template #append>
|
||||||
<v-btn icon color="delete">
|
<v-btn icon color="delete">
|
||||||
<v-icon icon="$delete"></v-icon>
|
<v-icon icon="$delete"></v-icon>
|
||||||
<delete-confirm-dialog :object-name="r.recipeName" :model-name="$t('ShoppingListRecipe')"
|
<delete-confirm-dialog :object-name="r.name" :model-name="$t('ShoppingListRecipe')"
|
||||||
@delete="deleteListRecipe(r)"></delete-confirm-dialog>
|
@delete="deleteListRecipe(r)"></delete-confirm-dialog>
|
||||||
</v-btn>
|
</v-btn>
|
||||||
</template>
|
</template>
|
||||||
@@ -198,8 +202,8 @@
|
|||||||
<v-container>
|
<v-container>
|
||||||
<v-row>
|
<v-row>
|
||||||
<v-col>
|
<v-col>
|
||||||
<SupermarketEditor :item="useUserPreferenceStore().deviceSettings.shopping_selected_supermarket"
|
<supermarket-editor :item="useUserPreferenceStore().deviceSettings.shopping_selected_supermarket"
|
||||||
@save="(args: Supermarket) => (useUserPreferenceStore().deviceSettings.shopping_selected_supermarket = args)"></SupermarketEditor>
|
@save="(args: Supermarket) => (useUserPreferenceStore().deviceSettings.shopping_selected_supermarket = args)"></supermarket-editor>
|
||||||
</v-col>
|
</v-col>
|
||||||
</v-row>
|
</v-row>
|
||||||
</v-container>
|
</v-container>
|
||||||
@@ -207,8 +211,6 @@
|
|||||||
</v-window-item>
|
</v-window-item>
|
||||||
</v-window>
|
</v-window>
|
||||||
|
|
||||||
<shopping-line-item-dialog v-model="shoppingLineItemDialog" v-model:shopping-list-food="shoppingLineItemDialogFood"></shopping-line-item-dialog>
|
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
@@ -228,14 +230,13 @@ import SupermarketEditor from "@/components/model_editors/SupermarketEditor.vue"
|
|||||||
import DeleteConfirmDialog from "@/components/dialogs/DeleteConfirmDialog.vue";
|
import DeleteConfirmDialog from "@/components/dialogs/DeleteConfirmDialog.vue";
|
||||||
import ShoppingListEntryInput from "@/components/inputs/ShoppingListEntryInput.vue";
|
import ShoppingListEntryInput from "@/components/inputs/ShoppingListEntryInput.vue";
|
||||||
import {DateTime} from "luxon";
|
import {DateTime} from "luxon";
|
||||||
|
import MealPlanEditor from "@/components/model_editors/MealPlanEditor.vue";
|
||||||
|
import ModelEditDialog from "@/components/dialogs/ModelEditDialog.vue";
|
||||||
|
|
||||||
const {t} = useI18n()
|
const {t} = useI18n()
|
||||||
|
|
||||||
const currentTab = ref("shopping")
|
const currentTab = ref("shopping")
|
||||||
|
|
||||||
const shoppingLineItemDialog = ref(false)
|
|
||||||
const shoppingLineItemDialogFood = ref({} as IShoppingListFood)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* VSelect items for shopping list grouping options with localized names
|
* VSelect items for shopping list grouping options with localized names
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ models/AccessToken.ts
|
|||||||
models/AuthToken.ts
|
models/AuthToken.ts
|
||||||
models/AutoMealPlan.ts
|
models/AutoMealPlan.ts
|
||||||
models/Automation.ts
|
models/Automation.ts
|
||||||
|
models/AutomationTypeEnum.ts
|
||||||
|
models/BaseUnitEnum.ts
|
||||||
models/BookmarkletImport.ts
|
models/BookmarkletImport.ts
|
||||||
models/BookmarkletImportList.ts
|
models/BookmarkletImportList.ts
|
||||||
models/ConnectorConfigConfig.ts
|
models/ConnectorConfigConfig.ts
|
||||||
@@ -31,6 +33,16 @@ models/MealPlan.ts
|
|||||||
models/MealType.ts
|
models/MealType.ts
|
||||||
models/MethodEnum.ts
|
models/MethodEnum.ts
|
||||||
models/NutritionInformation.ts
|
models/NutritionInformation.ts
|
||||||
|
models/OpenDataCategory.ts
|
||||||
|
models/OpenDataConversion.ts
|
||||||
|
models/OpenDataFood.ts
|
||||||
|
models/OpenDataFoodProperty.ts
|
||||||
|
models/OpenDataProperty.ts
|
||||||
|
models/OpenDataStore.ts
|
||||||
|
models/OpenDataStoreCategory.ts
|
||||||
|
models/OpenDataUnit.ts
|
||||||
|
models/OpenDataUnitTypeEnum.ts
|
||||||
|
models/OpenDataVersion.ts
|
||||||
models/PaginatedAutomationList.ts
|
models/PaginatedAutomationList.ts
|
||||||
models/PaginatedBookmarkletImportListList.ts
|
models/PaginatedBookmarkletImportListList.ts
|
||||||
models/PaginatedCookLogList.ts
|
models/PaginatedCookLogList.ts
|
||||||
@@ -77,6 +89,13 @@ models/PatchedInviteLink.ts
|
|||||||
models/PatchedKeyword.ts
|
models/PatchedKeyword.ts
|
||||||
models/PatchedMealPlan.ts
|
models/PatchedMealPlan.ts
|
||||||
models/PatchedMealType.ts
|
models/PatchedMealType.ts
|
||||||
|
models/PatchedOpenDataCategory.ts
|
||||||
|
models/PatchedOpenDataConversion.ts
|
||||||
|
models/PatchedOpenDataFood.ts
|
||||||
|
models/PatchedOpenDataProperty.ts
|
||||||
|
models/PatchedOpenDataStore.ts
|
||||||
|
models/PatchedOpenDataUnit.ts
|
||||||
|
models/PatchedOpenDataVersion.ts
|
||||||
models/PatchedProperty.ts
|
models/PatchedProperty.ts
|
||||||
models/PatchedPropertyType.ts
|
models/PatchedPropertyType.ts
|
||||||
models/PatchedRecipe.ts
|
models/PatchedRecipe.ts
|
||||||
@@ -136,7 +155,6 @@ models/SupermarketCategoryRelation.ts
|
|||||||
models/Sync.ts
|
models/Sync.ts
|
||||||
models/SyncLog.ts
|
models/SyncLog.ts
|
||||||
models/ThemeEnum.ts
|
models/ThemeEnum.ts
|
||||||
models/TypeEnum.ts
|
|
||||||
models/Unit.ts
|
models/Unit.ts
|
||||||
models/UnitConversion.ts
|
models/UnitConversion.ts
|
||||||
models/User.ts
|
models/User.ts
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -13,13 +13,13 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { mapValues } from '../runtime';
|
import { mapValues } from '../runtime';
|
||||||
import type { TypeEnum } from './TypeEnum';
|
import type { AutomationTypeEnum } from './AutomationTypeEnum';
|
||||||
import {
|
import {
|
||||||
TypeEnumFromJSON,
|
AutomationTypeEnumFromJSON,
|
||||||
TypeEnumFromJSONTyped,
|
AutomationTypeEnumFromJSONTyped,
|
||||||
TypeEnumToJSON,
|
AutomationTypeEnumToJSON,
|
||||||
TypeEnumToJSONTyped,
|
AutomationTypeEnumToJSONTyped,
|
||||||
} from './TypeEnum';
|
} from './AutomationTypeEnum';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@@ -35,10 +35,10 @@ export interface Automation {
|
|||||||
id?: number;
|
id?: number;
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @type {TypeEnum}
|
* @type {AutomationTypeEnum}
|
||||||
* @memberof Automation
|
* @memberof Automation
|
||||||
*/
|
*/
|
||||||
type: TypeEnum;
|
type: AutomationTypeEnum;
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @type {string}
|
* @type {string}
|
||||||
@@ -111,7 +111,7 @@ export function AutomationFromJSONTyped(json: any, ignoreDiscriminator: boolean)
|
|||||||
return {
|
return {
|
||||||
|
|
||||||
'id': json['id'] == null ? undefined : json['id'],
|
'id': json['id'] == null ? undefined : json['id'],
|
||||||
'type': TypeEnumFromJSON(json['type']),
|
'type': AutomationTypeEnumFromJSON(json['type']),
|
||||||
'name': json['name'] == null ? undefined : json['name'],
|
'name': json['name'] == null ? undefined : json['name'],
|
||||||
'description': json['description'] == null ? undefined : json['description'],
|
'description': json['description'] == null ? undefined : json['description'],
|
||||||
'param1': json['param_1'] == null ? undefined : json['param_1'],
|
'param1': json['param_1'] == null ? undefined : json['param_1'],
|
||||||
@@ -135,7 +135,7 @@ export function AutomationToJSONTyped(value?: Omit<Automation, 'created_by'> | n
|
|||||||
return {
|
return {
|
||||||
|
|
||||||
'id': value['id'],
|
'id': value['id'],
|
||||||
'type': TypeEnumToJSON(value['type']),
|
'type': AutomationTypeEnumToJSON(value['type']),
|
||||||
'name': value['name'],
|
'name': value['name'],
|
||||||
'description': value['description'],
|
'description': value['description'],
|
||||||
'param_1': value['param1'],
|
'param_1': value['param1'],
|
||||||
|
|||||||
@@ -13,13 +13,13 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { mapValues } from '../runtime';
|
import { mapValues } from '../runtime';
|
||||||
import type { TypeEnum } from './TypeEnum';
|
import type { AutomationTypeEnum } from './AutomationTypeEnum';
|
||||||
import {
|
import {
|
||||||
TypeEnumFromJSON,
|
AutomationTypeEnumFromJSON,
|
||||||
TypeEnumFromJSONTyped,
|
AutomationTypeEnumFromJSONTyped,
|
||||||
TypeEnumToJSON,
|
AutomationTypeEnumToJSON,
|
||||||
TypeEnumToJSONTyped,
|
AutomationTypeEnumToJSONTyped,
|
||||||
} from './TypeEnum';
|
} from './AutomationTypeEnum';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@@ -35,10 +35,10 @@ export interface PatchedAutomation {
|
|||||||
id?: number;
|
id?: number;
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @type {TypeEnum}
|
* @type {AutomationTypeEnum}
|
||||||
* @memberof PatchedAutomation
|
* @memberof PatchedAutomation
|
||||||
*/
|
*/
|
||||||
type?: TypeEnum;
|
type?: AutomationTypeEnum;
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @type {string}
|
* @type {string}
|
||||||
@@ -109,7 +109,7 @@ export function PatchedAutomationFromJSONTyped(json: any, ignoreDiscriminator: b
|
|||||||
return {
|
return {
|
||||||
|
|
||||||
'id': json['id'] == null ? undefined : json['id'],
|
'id': json['id'] == null ? undefined : json['id'],
|
||||||
'type': json['type'] == null ? undefined : TypeEnumFromJSON(json['type']),
|
'type': json['type'] == null ? undefined : AutomationTypeEnumFromJSON(json['type']),
|
||||||
'name': json['name'] == null ? undefined : json['name'],
|
'name': json['name'] == null ? undefined : json['name'],
|
||||||
'description': json['description'] == null ? undefined : json['description'],
|
'description': json['description'] == null ? undefined : json['description'],
|
||||||
'param1': json['param_1'] == null ? undefined : json['param_1'],
|
'param1': json['param_1'] == null ? undefined : json['param_1'],
|
||||||
@@ -133,7 +133,7 @@ export function PatchedAutomationToJSONTyped(value?: Omit<PatchedAutomation, 'cr
|
|||||||
return {
|
return {
|
||||||
|
|
||||||
'id': value['id'],
|
'id': value['id'],
|
||||||
'type': TypeEnumToJSON(value['type']),
|
'type': AutomationTypeEnumToJSON(value['type']),
|
||||||
'name': value['name'],
|
'name': value['name'],
|
||||||
'description': value['description'],
|
'description': value['description'],
|
||||||
'param_1': value['param1'],
|
'param_1': value['param1'],
|
||||||
|
|||||||
@@ -37,6 +37,12 @@ export interface ShoppingListEntrySimpleCreate {
|
|||||||
* @memberof ShoppingListEntrySimpleCreate
|
* @memberof ShoppingListEntrySimpleCreate
|
||||||
*/
|
*/
|
||||||
foodId: number | null;
|
foodId: number | null;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {number}
|
||||||
|
* @memberof ShoppingListEntrySimpleCreate
|
||||||
|
*/
|
||||||
|
ingredientId: number | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -46,6 +52,7 @@ export function instanceOfShoppingListEntrySimpleCreate(value: object): value is
|
|||||||
if (!('amount' in value) || value['amount'] === undefined) return false;
|
if (!('amount' in value) || value['amount'] === undefined) return false;
|
||||||
if (!('unitId' in value) || value['unitId'] === undefined) return false;
|
if (!('unitId' in value) || value['unitId'] === undefined) return false;
|
||||||
if (!('foodId' in value) || value['foodId'] === undefined) return false;
|
if (!('foodId' in value) || value['foodId'] === undefined) return false;
|
||||||
|
if (!('ingredientId' in value) || value['ingredientId'] === undefined) return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,6 +69,7 @@ export function ShoppingListEntrySimpleCreateFromJSONTyped(json: any, ignoreDisc
|
|||||||
'amount': json['amount'],
|
'amount': json['amount'],
|
||||||
'unitId': json['unit_id'],
|
'unitId': json['unit_id'],
|
||||||
'foodId': json['food_id'],
|
'foodId': json['food_id'],
|
||||||
|
'ingredientId': json['ingredient_id'],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,6 +87,7 @@ export function ShoppingListEntrySimpleCreateToJSONTyped(value?: ShoppingListEnt
|
|||||||
'amount': value['amount'],
|
'amount': value['amount'],
|
||||||
'unit_id': value['unitId'],
|
'unit_id': value['unitId'],
|
||||||
'food_id': value['foodId'],
|
'food_id': value['foodId'],
|
||||||
|
'ingredient_id': value['ingredientId'],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ export * from './AccessToken';
|
|||||||
export * from './AuthToken';
|
export * from './AuthToken';
|
||||||
export * from './AutoMealPlan';
|
export * from './AutoMealPlan';
|
||||||
export * from './Automation';
|
export * from './Automation';
|
||||||
|
export * from './AutomationTypeEnum';
|
||||||
|
export * from './BaseUnitEnum';
|
||||||
export * from './BookmarkletImport';
|
export * from './BookmarkletImport';
|
||||||
export * from './BookmarkletImportList';
|
export * from './BookmarkletImportList';
|
||||||
export * from './ConnectorConfigConfig';
|
export * from './ConnectorConfigConfig';
|
||||||
@@ -28,6 +30,16 @@ export * from './MealPlan';
|
|||||||
export * from './MealType';
|
export * from './MealType';
|
||||||
export * from './MethodEnum';
|
export * from './MethodEnum';
|
||||||
export * from './NutritionInformation';
|
export * from './NutritionInformation';
|
||||||
|
export * from './OpenDataCategory';
|
||||||
|
export * from './OpenDataConversion';
|
||||||
|
export * from './OpenDataFood';
|
||||||
|
export * from './OpenDataFoodProperty';
|
||||||
|
export * from './OpenDataProperty';
|
||||||
|
export * from './OpenDataStore';
|
||||||
|
export * from './OpenDataStoreCategory';
|
||||||
|
export * from './OpenDataUnit';
|
||||||
|
export * from './OpenDataUnitTypeEnum';
|
||||||
|
export * from './OpenDataVersion';
|
||||||
export * from './PaginatedAutomationList';
|
export * from './PaginatedAutomationList';
|
||||||
export * from './PaginatedBookmarkletImportListList';
|
export * from './PaginatedBookmarkletImportListList';
|
||||||
export * from './PaginatedCookLogList';
|
export * from './PaginatedCookLogList';
|
||||||
@@ -74,6 +86,13 @@ export * from './PatchedInviteLink';
|
|||||||
export * from './PatchedKeyword';
|
export * from './PatchedKeyword';
|
||||||
export * from './PatchedMealPlan';
|
export * from './PatchedMealPlan';
|
||||||
export * from './PatchedMealType';
|
export * from './PatchedMealType';
|
||||||
|
export * from './PatchedOpenDataCategory';
|
||||||
|
export * from './PatchedOpenDataConversion';
|
||||||
|
export * from './PatchedOpenDataFood';
|
||||||
|
export * from './PatchedOpenDataProperty';
|
||||||
|
export * from './PatchedOpenDataStore';
|
||||||
|
export * from './PatchedOpenDataUnit';
|
||||||
|
export * from './PatchedOpenDataVersion';
|
||||||
export * from './PatchedProperty';
|
export * from './PatchedProperty';
|
||||||
export * from './PatchedPropertyType';
|
export * from './PatchedPropertyType';
|
||||||
export * from './PatchedRecipe';
|
export * from './PatchedRecipe';
|
||||||
@@ -133,7 +152,6 @@ export * from './SupermarketCategoryRelation';
|
|||||||
export * from './Sync';
|
export * from './Sync';
|
||||||
export * from './SyncLog';
|
export * from './SyncLog';
|
||||||
export * from './ThemeEnum';
|
export * from './ThemeEnum';
|
||||||
export * from './TypeEnum';
|
|
||||||
export * from './Unit';
|
export * from './Unit';
|
||||||
export * from './UnitConversion';
|
export * from './UnitConversion';
|
||||||
export * from './User';
|
export * from './User';
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import {
|
|||||||
} from "@/types/Shopping";
|
} from "@/types/Shopping";
|
||||||
import {ErrorMessageType, useMessageStore} from "@/stores/MessageStore";
|
import {ErrorMessageType, useMessageStore} from "@/stores/MessageStore";
|
||||||
import {useUserPreferenceStore} from "@/stores/UserPreferenceStore";
|
import {useUserPreferenceStore} from "@/stores/UserPreferenceStore";
|
||||||
import {isDelayed} from "@/utils/logic_utils";
|
import {isDelayed, isEntryVisible} from "@/utils/logic_utils";
|
||||||
import {DateTime} from "luxon";
|
import {DateTime} from "luxon";
|
||||||
|
|
||||||
const _STORE_ID = "shopping_store"
|
const _STORE_ID = "shopping_store"
|
||||||
@@ -194,9 +194,11 @@ export const useShoppingStore = defineStore(_STORE_ID, () => {
|
|||||||
let requestParameters = {pageSize: 50, page: 1} as ApiShoppingListEntryListRequest
|
let requestParameters = {pageSize: 50, page: 1} as ApiShoppingListEntryListRequest
|
||||||
if (mealPlanId) {
|
if (mealPlanId) {
|
||||||
requestParameters.mealplan = mealPlanId
|
requestParameters.mealplan = mealPlanId
|
||||||
|
} else {
|
||||||
|
// only clear local entries when not given a meal plan to not accidentally filter the shopping list
|
||||||
|
entries.value = new Map<number, ShoppingListEntry>
|
||||||
}
|
}
|
||||||
|
|
||||||
entries.value = new Map<number, ShoppingListEntry>
|
|
||||||
recLoadShoppingListEntries(requestParameters)
|
recLoadShoppingListEntries(requestParameters)
|
||||||
|
|
||||||
api.apiSupermarketCategoryList().then(r => {
|
api.apiSupermarketCategoryList().then(r => {
|
||||||
@@ -217,23 +219,23 @@ export const useShoppingStore = defineStore(_STORE_ID, () => {
|
|||||||
* recursively load shopping list entries from paginated api
|
* recursively load shopping list entries from paginated api
|
||||||
* @param requestParameters
|
* @param requestParameters
|
||||||
*/
|
*/
|
||||||
function recLoadShoppingListEntries(requestParameters: ApiShoppingListEntryListRequest){
|
function recLoadShoppingListEntries(requestParameters: ApiShoppingListEntryListRequest) {
|
||||||
let api = new ApiApi()
|
let api = new ApiApi()
|
||||||
api.apiShoppingListEntryList(requestParameters).then((r) => {
|
api.apiShoppingListEntryList(requestParameters).then((r) => {
|
||||||
r.results.forEach((e) => {
|
r.results.forEach((e) => {
|
||||||
entries.value.set(e.id!, e)
|
entries.value.set(e.id!, e)
|
||||||
})
|
|
||||||
if(r.next){
|
|
||||||
requestParameters.page = requestParameters.page + 1
|
|
||||||
recLoadShoppingListEntries(requestParameters)
|
|
||||||
} else {
|
|
||||||
currentlyUpdating.value = false
|
|
||||||
initialized.value = true
|
|
||||||
}
|
|
||||||
}).catch((err) => {
|
|
||||||
currentlyUpdating.value = false
|
|
||||||
useMessageStore().addError(ErrorMessageType.FETCH_ERROR, err)
|
|
||||||
})
|
})
|
||||||
|
if (r.next) {
|
||||||
|
requestParameters.page = requestParameters.page + 1
|
||||||
|
recLoadShoppingListEntries(requestParameters)
|
||||||
|
} else {
|
||||||
|
currentlyUpdating.value = false
|
||||||
|
initialized.value = true
|
||||||
|
}
|
||||||
|
}).catch((err) => {
|
||||||
|
currentlyUpdating.value = false
|
||||||
|
useMessageStore().addError(ErrorMessageType.FETCH_ERROR, err)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -321,7 +323,7 @@ export const useShoppingStore = defineStore(_STORE_ID, () => {
|
|||||||
let recipes = [] as ShoppingListRecipe[]
|
let recipes = [] as ShoppingListRecipe[]
|
||||||
|
|
||||||
entries.value.forEach(e => {
|
entries.value.forEach(e => {
|
||||||
if (e.listRecipe != null && recipes.findIndex(x => x.id == e.listRecipe) == -1) {
|
if (e.listRecipe != null && recipes.findIndex(x => x.id == e.listRecipe) == -1 && isEntryVisible(e, useUserPreferenceStore().deviceSettings)) {
|
||||||
recipes.push(e.listRecipeData)
|
recipes.push(e.listRecipeData)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import {ErrorMessageType, PreparedMessage, useMessageStore} from "@/stores/Messa
|
|||||||
import {ApiApi, ServerSettings, Space, Supermarket, UserPreference, UserSpace} from "@/openapi";
|
import {ApiApi, ServerSettings, Space, Supermarket, UserPreference, UserSpace} from "@/openapi";
|
||||||
import {ShoppingGroupingOptions} from "@/types/Shopping";
|
import {ShoppingGroupingOptions} from "@/types/Shopping";
|
||||||
import {computed, ComputedRef} from "vue";
|
import {computed, ComputedRef} from "vue";
|
||||||
|
import {DeviceSettings} from "@/types/settings";
|
||||||
|
|
||||||
const DEVICE_SETTINGS_KEY = 'TANDOOR_DEVICE_SETTINGS'
|
const DEVICE_SETTINGS_KEY = 'TANDOOR_DEVICE_SETTINGS'
|
||||||
const USER_PREFERENCE_KEY = 'TANDOOR_USER_PREFERENCE'
|
const USER_PREFERENCE_KEY = 'TANDOOR_USER_PREFERENCE'
|
||||||
@@ -11,31 +12,11 @@ const SERVER_SETTINGS_KEY = 'TANDOOR_SERVER_SETTINGS'
|
|||||||
const ACTIVE_SPACE_KEY = 'TANDOOR_ACTIVE_SPACE'
|
const ACTIVE_SPACE_KEY = 'TANDOOR_ACTIVE_SPACE'
|
||||||
const USER_SPACES_KEY = 'TANDOOR_USER_SPACES'
|
const USER_SPACES_KEY = 'TANDOOR_USER_SPACES'
|
||||||
|
|
||||||
class DeviceSettings {
|
|
||||||
shopping_show_checked_entries = false
|
|
||||||
shopping_show_delayed_entries = false
|
|
||||||
shopping_show_selected_supermarket_only = false
|
|
||||||
shopping_selected_grouping = ShoppingGroupingOptions.CATEGORY
|
|
||||||
shopping_selected_supermarket: Supermarket | null = null
|
|
||||||
shopping_item_info_created_by = false
|
|
||||||
shopping_item_info_mealplan = true
|
|
||||||
shopping_item_info_recipe = true
|
|
||||||
shopping_show_debug = false
|
|
||||||
|
|
||||||
mealplan_displayPeriod = 'week'
|
|
||||||
mealplan_displayPeriodCount = 3
|
|
||||||
mealplan_startingDayOfWeek = 1
|
|
||||||
mealplan_displayWeekNumbers = true
|
|
||||||
|
|
||||||
general_tableItemsPerPage = 10
|
|
||||||
general_closedHelpAlerts: String[] = []
|
|
||||||
}
|
|
||||||
|
|
||||||
export const useUserPreferenceStore = defineStore('user_preference_store', () => {
|
export const useUserPreferenceStore = defineStore('user_preference_store', () => {
|
||||||
/**
|
/**
|
||||||
* settings only saved on device to allow per device customization
|
* settings only saved on device to allow per device customization
|
||||||
*/
|
*/
|
||||||
let deviceSettings = useStorage(DEVICE_SETTINGS_KEY, new DeviceSettings(), localStorage, {mergeDefaults: true})
|
let deviceSettings = useStorage(DEVICE_SETTINGS_KEY, getDefaultDeviceSettings(), localStorage, {mergeDefaults: true})
|
||||||
/**
|
/**
|
||||||
* database user settings, cache in local storage in case application is started offline
|
* database user settings, cache in local storage in case application is started offline
|
||||||
*/
|
*/
|
||||||
@@ -140,7 +121,7 @@ export const useUserPreferenceStore = defineStore('user_preference_store', () =>
|
|||||||
function switchSpace(space: Space) {
|
function switchSpace(space: Space) {
|
||||||
let api = new ApiApi()
|
let api = new ApiApi()
|
||||||
|
|
||||||
api.apiSwitchActiveSpaceRetrieve({spaceId: space.id}).then(r => {
|
api.apiSwitchActiveSpaceRetrieve({spaceId: space.id!}).then(r => {
|
||||||
loadActiveSpace()
|
loadActiveSpace()
|
||||||
location.reload()
|
location.reload()
|
||||||
}).catch(err => {
|
}).catch(err => {
|
||||||
@@ -152,7 +133,32 @@ export const useUserPreferenceStore = defineStore('user_preference_store', () =>
|
|||||||
* resets all device settings to their default value
|
* resets all device settings to their default value
|
||||||
*/
|
*/
|
||||||
function resetDeviceSettings() {
|
function resetDeviceSettings() {
|
||||||
deviceSettings.value = new DeviceSettings()
|
deviceSettings.value = getDefaultDeviceSettings()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns a default device settings object
|
||||||
|
*/
|
||||||
|
function getDefaultDeviceSettings(): DeviceSettings {
|
||||||
|
return {
|
||||||
|
shopping_show_checked_entries: false,
|
||||||
|
shopping_show_delayed_entries: false,
|
||||||
|
shopping_show_selected_supermarket_only: false,
|
||||||
|
shopping_selected_grouping: ShoppingGroupingOptions.CATEGORY,
|
||||||
|
shopping_selected_supermarket: null,
|
||||||
|
shopping_item_info_created_by: false,
|
||||||
|
shopping_item_info_mealplan: true,
|
||||||
|
shopping_item_info_recipe: true,
|
||||||
|
shopping_show_debug: false,
|
||||||
|
|
||||||
|
mealplan_displayPeriod: 'week',
|
||||||
|
mealplan_displayPeriodCount: 3,
|
||||||
|
mealplan_startingDayOfWeek: 1,
|
||||||
|
mealplan_displayWeekNumbers: true,
|
||||||
|
|
||||||
|
general_tableItemsPerPage: 10,
|
||||||
|
general_closedHelpAlerts: [],
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// always load settings on first initialization of store
|
// always load settings on first initialization of store
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import {Food, Recipe, ShoppingListEntry, Unit} from "@/openapi";
|
import {Food, Ingredient, Recipe, ShoppingListEntry, Unit} from "@/openapi";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* enum of different options a shopping list can be grouped by
|
* enum of different options a shopping list can be grouped by
|
||||||
@@ -98,5 +98,6 @@ export type ShoppingDialogRecipeEntry = {
|
|||||||
amount: number,
|
amount: number,
|
||||||
unit: Unit|null,
|
unit: Unit|null,
|
||||||
food: Food|null,
|
food: Food|null,
|
||||||
|
ingredient: Ingredient|null,
|
||||||
checked: boolean,
|
checked: boolean,
|
||||||
}
|
}
|
||||||
21
vue3/src/types/settings.ts
Normal file
21
vue3/src/types/settings.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import {Supermarket} from "@/openapi";
|
||||||
|
|
||||||
|
export type DeviceSettings = {
|
||||||
|
shopping_show_checked_entries: boolean
|
||||||
|
shopping_show_delayed_entries: boolean
|
||||||
|
shopping_show_selected_supermarket_only: boolean
|
||||||
|
shopping_selected_grouping: string
|
||||||
|
shopping_selected_supermarket: Supermarket | null
|
||||||
|
shopping_item_info_created_by: boolean
|
||||||
|
shopping_item_info_mealplan: boolean
|
||||||
|
shopping_item_info_recipe: boolean
|
||||||
|
shopping_show_debug: boolean
|
||||||
|
|
||||||
|
mealplan_displayPeriod: string
|
||||||
|
mealplan_displayPeriodCount: number
|
||||||
|
mealplan_startingDayOfWeek: number
|
||||||
|
mealplan_displayWeekNumbers: boolean
|
||||||
|
|
||||||
|
general_tableItemsPerPage: number
|
||||||
|
general_closedHelpAlerts: String[]
|
||||||
|
}
|
||||||
@@ -1,5 +1,37 @@
|
|||||||
import {ShoppingListEntry, Space} from "@/openapi";
|
import {ShoppingListEntry, Space} from "@/openapi";
|
||||||
import {IShoppingListFood} from "@/types/Shopping";
|
import {IShoppingListFood} from "@/types/Shopping";
|
||||||
|
import {DeviceSettings} from "@/types/settings";
|
||||||
|
|
||||||
|
// -------------- SHOPPING RELATED ----------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* determines if an entry should be visible to the user based on its delayed/checked state and the current device settings
|
||||||
|
* @param entry entry for which visibility should be determined
|
||||||
|
* @param deviceSettings user device settings based on which entry visibility is controlled
|
||||||
|
*/
|
||||||
|
export function isEntryVisible(entry: ShoppingListEntry, deviceSettings: DeviceSettings) {
|
||||||
|
let entryVisible = true
|
||||||
|
if (isDelayed(entry) && !deviceSettings.shopping_show_delayed_entries) {
|
||||||
|
entryVisible = false
|
||||||
|
}
|
||||||
|
if (entry.checked && !deviceSettings.shopping_show_checked_entries) {
|
||||||
|
entryVisible = false
|
||||||
|
}
|
||||||
|
return entryVisible
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* loops through all entries of a shopping list food and determines if it should be visible based on the isEntryVisible function
|
||||||
|
* @param slf shopping list food holder
|
||||||
|
* @param deviceSettings user device settings based on which entry visibility is controlled
|
||||||
|
*/
|
||||||
|
export function isShoppingListFoodVisible(slf: IShoppingListFood, deviceSettings: DeviceSettings){
|
||||||
|
let foodVisible = false
|
||||||
|
slf.entries.forEach(entry => {
|
||||||
|
foodVisible = foodVisible || isEntryVisible(entry, deviceSettings)
|
||||||
|
})
|
||||||
|
return foodVisible
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* determine if a shopping list entry is delayed
|
* determine if a shopping list entry is delayed
|
||||||
@@ -22,6 +54,8 @@ export function isShoppingListFoodDelayed(slf: IShoppingListFood) {
|
|||||||
return hasDelayedEntry
|
return hasDelayedEntry
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -------------- SPACE RELATED ----------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* checks if the given space is above any of the configured limits
|
* checks if the given space is above any of the configured limits
|
||||||
* @param space space to check limit for
|
* @param space space to check limit for
|
||||||
|
|||||||
Reference in New Issue
Block a user