mirror of
https://github.com/mealie-recipes/mealie.git
synced 2026-02-03 06:23:10 -05:00
feat: Add range of dates to shopping list from meal planner (#6981)
This commit is contained in:
@@ -91,7 +91,7 @@ const state = reactive({
|
|||||||
shoppingListDialog: false,
|
shoppingListDialog: false,
|
||||||
menuItems: [
|
menuItems: [
|
||||||
{
|
{
|
||||||
title: i18n.t("recipe.add-to-list"),
|
title: i18n.t("meal-plan.add-day-to-list"),
|
||||||
icon: $globals.icons.cartCheck,
|
icon: $globals.icons.cartCheck,
|
||||||
color: undefined,
|
color: undefined,
|
||||||
event: "shoppingList",
|
event: "shoppingList",
|
||||||
@@ -123,8 +123,8 @@ async function getShoppingLists() {
|
|||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-invalid-void-type
|
// eslint-disable-next-line @typescript-eslint/no-invalid-void-type
|
||||||
const eventHandlers: { [key: string]: () => void | Promise<any> } = {
|
const eventHandlers: { [key: string]: () => void | Promise<any> } = {
|
||||||
shoppingList: () => {
|
shoppingList: async () => {
|
||||||
getShoppingLists();
|
await getShoppingLists();
|
||||||
state.shoppingListDialog = true;
|
state.shoppingListDialog = true;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -227,7 +227,7 @@ const currentHouseholdSlug = ref("");
|
|||||||
const filteredShoppingLists = ref<ShoppingListSummary[]>([]);
|
const filteredShoppingLists = ref<ShoppingListSummary[]>([]);
|
||||||
|
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
shoppingListDialog: true,
|
shoppingListDialog: false,
|
||||||
shoppingListIngredientDialog: false,
|
shoppingListIngredientDialog: false,
|
||||||
shoppingListShowAllToggled: false,
|
shoppingListShowAllToggled: false,
|
||||||
});
|
});
|
||||||
@@ -249,6 +249,7 @@ watch([dialog, () => preferences.value.viewAllLists], () => {
|
|||||||
openShoppingListIngredientDialog(selectedShoppingList.value);
|
openShoppingListIngredientDialog(selectedShoppingList.value);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
state.shoppingListDialog = true;
|
||||||
ready.value = true;
|
ready.value = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -371,7 +372,7 @@ async function consolidateRecipesIntoSections(recipes: RecipeWithScale[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function initState() {
|
function initState() {
|
||||||
state.shoppingListDialog = true;
|
state.shoppingListDialog = false;
|
||||||
state.shoppingListIngredientDialog = false;
|
state.shoppingListIngredientDialog = false;
|
||||||
state.shoppingListShowAllToggled = false;
|
state.shoppingListShowAllToggled = false;
|
||||||
recipeIngredientSections.value = [];
|
recipeIngredientSections.value = [];
|
||||||
|
|||||||
@@ -369,7 +369,9 @@
|
|||||||
"recipe-rules": "Recipe Rules",
|
"recipe-rules": "Recipe Rules",
|
||||||
"applies-to-all-days": "Applies to all days",
|
"applies-to-all-days": "Applies to all days",
|
||||||
"applies-on-days": "Applies on {0}s",
|
"applies-on-days": "Applies on {0}s",
|
||||||
"meal-plan-settings": "Meal Plan Settings"
|
"meal-plan-settings": "Meal Plan Settings",
|
||||||
|
"add-all-to-list": "Add All to List",
|
||||||
|
"add-day-to-list": "Add Day to List"
|
||||||
},
|
},
|
||||||
"migration": {
|
"migration": {
|
||||||
"migration-data-removed": "Migration data removed",
|
"migration-data-removed": "Migration data removed",
|
||||||
|
|||||||
@@ -1,5 +1,11 @@
|
|||||||
<template>
|
<template>
|
||||||
<v-container>
|
<v-container>
|
||||||
|
<RecipeDialogAddToShoppingList
|
||||||
|
v-if="shoppingLists"
|
||||||
|
v-model="state.shoppingListDialog"
|
||||||
|
:recipes="weekRecipesWithScales"
|
||||||
|
:shopping-lists="shoppingLists"
|
||||||
|
/>
|
||||||
<v-menu
|
<v-menu
|
||||||
v-model="state.picker"
|
v-model="state.picker"
|
||||||
:close-on-content-click="false"
|
:close-on-content-click="false"
|
||||||
@@ -45,13 +51,23 @@
|
|||||||
|
|
||||||
<div class="d-flex flex-wrap align-center justify-space-between mb-2">
|
<div class="d-flex flex-wrap align-center justify-space-between mb-2">
|
||||||
<v-tabs style="width: fit-content;">
|
<v-tabs style="width: fit-content;">
|
||||||
<v-tab :to="{ name: 'household-mealplan-planner-view', query: route.query }">
|
<v-tab :to="{ name: TABS.view, query: route.query }">
|
||||||
{{ $t('meal-plan.meal-planner') }}
|
{{ $t('meal-plan.meal-planner') }}
|
||||||
</v-tab>
|
</v-tab>
|
||||||
<v-tab :to="{ name: 'household-mealplan-planner-edit', query: route.query }">
|
<v-tab :to="{ name: TABS.edit, query: route.query }">
|
||||||
{{ $t('general.edit') }}
|
{{ $t('general.edit') }}
|
||||||
</v-tab>
|
</v-tab>
|
||||||
</v-tabs>
|
</v-tabs>
|
||||||
|
<BaseButton
|
||||||
|
v-if="route.name === TABS.view"
|
||||||
|
color="info"
|
||||||
|
:icon="$globals.icons.cartCheck"
|
||||||
|
:text="$t('meal-plan.add-all-to-list')"
|
||||||
|
:disabled="!hasRecipes"
|
||||||
|
:loading="state.addAllLoading"
|
||||||
|
class="ml-auto mr-4"
|
||||||
|
@click="addAllToList"
|
||||||
|
/>
|
||||||
<ButtonLink
|
<ButtonLink
|
||||||
:icon="$globals.icons.calendar"
|
:icon="$globals.icons.calendar"
|
||||||
:to="`/household/mealplan/settings`"
|
:to="`/household/mealplan/settings`"
|
||||||
@@ -72,15 +88,27 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { isSameDay, addDays, parseISO, format, isValid } from "date-fns";
|
import { isSameDay, addDays, parseISO, format, isValid } from "date-fns";
|
||||||
|
import RecipeDialogAddToShoppingList from "~/components/Domain/Recipe/RecipeDialogAddToShoppingList.vue";
|
||||||
import { useHouseholdSelf } from "~/composables/use-households";
|
import { useHouseholdSelf } from "~/composables/use-households";
|
||||||
import { useMealplans } from "~/composables/use-group-mealplan";
|
import { useMealplans } from "~/composables/use-group-mealplan";
|
||||||
import { useUserMealPlanPreferences } from "~/composables/use-users/preferences";
|
import { useUserMealPlanPreferences } from "~/composables/use-users/preferences";
|
||||||
|
import type { ShoppingListSummary } from "~/lib/api/types/household";
|
||||||
|
import { useUserApi } from "~/composables/api";
|
||||||
|
|
||||||
export default defineNuxtComponent({
|
export default defineNuxtComponent({
|
||||||
|
components: {
|
||||||
|
RecipeDialogAddToShoppingList,
|
||||||
|
},
|
||||||
setup() {
|
setup() {
|
||||||
|
const TABS = {
|
||||||
|
view: "household-mealplan-planner-view",
|
||||||
|
edit: "household-mealplan-planner-edit",
|
||||||
|
};
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const i18n = useI18n();
|
const i18n = useI18n();
|
||||||
|
const api = useUserApi();
|
||||||
const { household } = useHouseholdSelf();
|
const { household } = useHouseholdSelf();
|
||||||
|
|
||||||
useSeoMeta({
|
useSeoMeta({
|
||||||
@@ -96,7 +124,7 @@ export default defineNuxtComponent({
|
|||||||
// Force to /view if current route is /planner
|
// Force to /view if current route is /planner
|
||||||
if (route.path === "/household/mealplan/planner") {
|
if (route.path === "/household/mealplan/planner") {
|
||||||
router.push({
|
router.push({
|
||||||
name: "household-mealplan-planner-view",
|
name: TABS.view,
|
||||||
query: route.query,
|
query: route.query,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -120,8 +148,12 @@ export default defineNuxtComponent({
|
|||||||
start: initialStartDate,
|
start: initialStartDate,
|
||||||
picker: false,
|
picker: false,
|
||||||
end: initialEndDate,
|
end: initialEndDate,
|
||||||
|
shoppingListDialog: false,
|
||||||
|
addAllLoading: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const shoppingLists = ref<ShoppingListSummary[]>();
|
||||||
|
|
||||||
const firstDayOfWeek = computed(() => {
|
const firstDayOfWeek = computed(() => {
|
||||||
return household.value?.preferences?.firstDayOfWeek || 0;
|
return household.value?.preferences?.firstDayOfWeek || 0;
|
||||||
});
|
});
|
||||||
@@ -145,7 +177,7 @@ export default defineNuxtComponent({
|
|||||||
watch(weekRange, (newRange) => {
|
watch(weekRange, (newRange) => {
|
||||||
// Keep current route name and params, just update the query
|
// Keep current route name and params, just update the query
|
||||||
router.replace({
|
router.replace({
|
||||||
name: route.name || "household-mealplan-planner-view",
|
name: route.name || TABS.view,
|
||||||
params: route.params,
|
params: route.params,
|
||||||
query: {
|
query: {
|
||||||
...route.query,
|
...route.query,
|
||||||
@@ -193,7 +225,41 @@ export default defineNuxtComponent({
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const hasRecipes = computed(() => {
|
||||||
|
return mealsByDate.value.some(day => day.meals.some(meal => meal.recipe));
|
||||||
|
});
|
||||||
|
|
||||||
|
const weekRecipesWithScales = computed(() => {
|
||||||
|
const allRecipes: any[] = [];
|
||||||
|
for (const day of mealsByDate.value) {
|
||||||
|
for (const meal of day.meals) {
|
||||||
|
if (meal.recipe) {
|
||||||
|
allRecipes.push(meal.recipe);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return allRecipes.map(recipe => ({
|
||||||
|
scale: 1,
|
||||||
|
...recipe,
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
|
async function getShoppingLists() {
|
||||||
|
const { data } = await api.shopping.lists.getAll(1, -1, { orderBy: "name", orderDirection: "asc" });
|
||||||
|
if (data) {
|
||||||
|
shoppingLists.value = data.items as ShoppingListSummary[] ?? [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function addAllToList() {
|
||||||
|
state.value.addAllLoading = true;
|
||||||
|
await getShoppingLists();
|
||||||
|
state.value.shoppingListDialog = true;
|
||||||
|
state.value.addAllLoading = false;
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
TABS,
|
||||||
route,
|
route,
|
||||||
state,
|
state,
|
||||||
actions,
|
actions,
|
||||||
@@ -201,6 +267,10 @@ export default defineNuxtComponent({
|
|||||||
weekRange,
|
weekRange,
|
||||||
firstDayOfWeek,
|
firstDayOfWeek,
|
||||||
numberOfDays,
|
numberOfDays,
|
||||||
|
hasRecipes,
|
||||||
|
shoppingLists,
|
||||||
|
weekRecipesWithScales,
|
||||||
|
addAllToList,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user