1
0
Fork 0
mirror of https://github.com/mealie-recipes/mealie.git synced 2025-08-02 20:15:24 +02:00

feat: Move "on hand" and "last made" to household (#4616)

Co-authored-by: Kuchenpirat <24235032+Kuchenpirat@users.noreply.github.com>
This commit is contained in:
Michael Genson 2025-01-13 10:19:49 -06:00 committed by GitHub
parent e565b919df
commit e9892aba89
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
53 changed files with 1618 additions and 400 deletions

View file

@ -204,6 +204,10 @@ export default defineComponent({
shoppingListShowAllToggled: false,
});
const userHousehold = computed(() => {
return $auth.user?.householdSlug || "";
});
const shoppingListChoices = computed(() => {
return props.shoppingLists.filter((list) => preferences.value.viewAllLists || list.userId === $auth.user?.id);
});
@ -248,8 +252,9 @@ export default defineComponent({
}
const shoppingListIngredients: ShoppingListIngredient[] = recipe.recipeIngredient.map((ing) => {
const householdsWithFood = (ing.food?.householdsWithIngredientFood || []);
return {
checked: !ing.food?.onHand,
checked: !householdsWithFood.includes(userHousehold.value),
ingredient: ing,
disableAmount: recipe.settings?.disableAmount || false,
}
@ -276,7 +281,8 @@ export default defineComponent({
}
// Store the on-hand ingredients for later
if (ing.ingredient.food?.onHand) {
const householdsWithFood = (ing.ingredient.food?.householdsWithIngredientFood || []);
if (householdsWithFood.includes(userHousehold.value)) {
onHandIngs.push(ing);
return sections;
}

View file

@ -96,7 +96,12 @@
<v-icon left>
{{ $globals.icons.calendar }}
</v-icon>
{{ $t('recipe.last-made-date', { date: value ? new Date(value).toLocaleDateString($i18n.locale) : $t("general.never") } ) }}
<div v-if="lastMadeReady">
{{ $t('recipe.last-made-date', { date: lastMade ? new Date(lastMade).toLocaleDateString($i18n.locale) : $t("general.never") } ) }}
</div>
<div v-else>
<AppLoader tiny />
</div>
</v-chip>
</div>
<div class="d-flex justify-center flex-wrap mt-1">
@ -110,7 +115,7 @@
</template>
<script lang="ts">
import { computed, defineComponent, reactive, ref, toRefs, useContext } from "@nuxtjs/composition-api";
import { computed, defineComponent, onMounted, reactive, ref, toRefs, useContext } from "@nuxtjs/composition-api";
import { whenever } from "@vueuse/core";
import { VForm } from "~/types/vuetify";
import { useUserApi } from "~/composables/api";
@ -119,10 +124,6 @@ import { Recipe, RecipeTimelineEventIn } from "~/lib/api/types/recipe";
export default defineComponent({
props: {
value: {
type: String,
default: null,
},
recipe: {
type: Object as () => Recipe,
required: true,
@ -146,6 +147,20 @@ export default defineComponent({
const newTimelineEventImagePreviewUrl = ref<string>();
const newTimelineEventTimestamp = ref<string>();
const lastMade = ref(props.recipe.lastMade);
const lastMadeReady = ref(false);
onMounted(async () => {
if (!$auth.user?.householdSlug) {
lastMade.value = props.recipe.lastMade;
} else {
const { data } = await userApi.households.getCurrentUserHouseholdRecipe(props.recipe.slug || "");
lastMade.value = data?.lastMade;
}
lastMadeReady.value = true;
});
whenever(
() => madeThisDialog.value,
() => {
@ -195,11 +210,9 @@ export default defineComponent({
const newEvent = eventResponse.data;
// we also update the recipe's last made value
if (!props.value || newTimelineEvent.value.timestamp > props.value) {
if (!lastMade.value || newTimelineEvent.value.timestamp > lastMade.value) {
lastMade.value = newTimelineEvent.value.timestamp;
await userApi.recipes.updateLastMade(props.recipe.slug, newTimelineEvent.value.timestamp);
// update recipe in parent so the user can see it
context.emit("input", newTimelineEvent.value.timestamp);
}
// update the image, if provided
@ -234,6 +247,8 @@ export default defineComponent({
newTimelineEventImage,
newTimelineEventImagePreviewUrl,
newTimelineEventTimestamp,
lastMade,
lastMadeReady,
createTimelineEvent,
clearImage,
uploadImage,

View file

@ -30,7 +30,6 @@
<v-col cols="12" class="d-flex flex-wrap justify-center">
<RecipeLastMade
v-if="isOwnGroup"
:value="recipe.lastMade"
:recipe="recipe"
:class="true ? undefined : 'force-bottom'"
/>

View file

@ -10,7 +10,7 @@
<h2 class="mb-2 mt-4">{{ $t('tool.required-tools') }}</h2>
<v-list-item v-for="(tool, index) in recipe.tools" :key="index" dense>
<v-checkbox
v-model="recipe.tools[index].onHand"
v-model="recipeTools[index].onHand"
hide-details
class="pt-0 my-auto py-auto"
color="secondary"
@ -26,14 +26,18 @@
</template>
<script lang="ts">
import { defineComponent } from "@nuxtjs/composition-api";
import { computed, defineComponent } from "@nuxtjs/composition-api";
import { useLoggedInState } from "~/composables/use-logged-in-state";
import { usePageState, usePageUser } from "~/composables/recipe-page/shared-state";
import { useToolStore } from "~/composables/store";
import { NoUndefinedField } from "~/lib/api/types/non-generated";
import { Recipe } from "~/lib/api/types/recipe";
import { Recipe, RecipeTool } from "~/lib/api/types/recipe";
import RecipeIngredients from "~/components/Domain/Recipe/RecipeIngredients.vue";
interface RecipeToolWithOnHand extends RecipeTool {
onHand: boolean;
}
export default defineComponent({
components: {
RecipeIngredients,
@ -59,9 +63,31 @@ export default defineComponent({
const { user } = usePageUser();
const { isEditMode } = usePageState(props.recipe.slug);
const recipeTools = computed(() => {
if (!(user.householdSlug && toolStore)) {
return props.recipe.tools.map((tool) => ({ ...tool, onHand: false }) as RecipeToolWithOnHand);
} else {
return props.recipe.tools.map((tool) => {
const onHand = tool.householdsWithTool?.includes(user.householdSlug) || false;
return { ...tool, onHand } as RecipeToolWithOnHand;
});
}
})
function updateTool(index: number) {
if (user.id && toolStore) {
toolStore.actions.updateOne(props.recipe.tools[index]);
if (user.id && user.householdSlug && toolStore) {
const tool = recipeTools.value[index];
if (tool.onHand && !tool.householdsWithTool?.includes(user.householdSlug)) {
if (!tool.householdsWithTool) {
tool.householdsWithTool = [user.householdSlug];
} else {
tool.householdsWithTool.push(user.householdSlug);
}
} else if (!tool.onHand && tool.householdsWithTool?.includes(user.householdSlug)) {
tool.householdsWithTool = tool.householdsWithTool.filter((household) => household !== user.householdSlug);
}
toolStore.actions.updateOne(tool);
} else {
console.log("no user, skipping server update");
}
@ -69,6 +95,7 @@ export default defineComponent({
return {
toolStore,
recipeTools,
isEditMode,
updateTool,
};

View file

@ -8,14 +8,14 @@
</v-icon>
<div v-if="large" class="text-small">
<slot>
{{ small ? "" : waitingText }}
{{ (small || tiny) ? "" : waitingText }}
</slot>
</div>
</div>
</v-progress-circular>
<div v-if="!large" class="text-small">
<slot>
{{ small ? "" : waitingTextCalculated }}
{{ (small || tiny) ? "" : waitingTextCalculated }}
</slot>
</div>
</div>
@ -31,6 +31,10 @@ export default defineComponent({
type: Boolean,
default: true,
},
tiny: {
type: Boolean,
default: false,
},
small: {
type: Boolean,
default: false,
@ -50,6 +54,13 @@ export default defineComponent({
},
setup(props) {
const size = computed(() => {
if (props.tiny) {
return {
width: 2,
icon: 0,
size: 25,
};
}
if (props.small) {
return {
width: 2,