mirror of
https://github.com/hay-kot/mealie.git
synced 2025-08-22 14:33:33 -07:00
Add to Shopping List Dialog
This commit is contained in:
parent
ee68f95d4b
commit
0dbb837dff
1 changed files with 201 additions and 226 deletions
|
@ -51,7 +51,7 @@
|
||||||
<BaseDialog
|
<BaseDialog
|
||||||
v-if="shoppingListIngredientDialog"
|
v-if="shoppingListIngredientDialog"
|
||||||
v-model="dialog"
|
v-model="dialog"
|
||||||
:title="selectedShoppingList ? selectedShoppingList.name : $t('recipe.add-to-list')"
|
:title="selectedShoppingList?.name || $t('recipe.add-to-list')"
|
||||||
:icon="$globals.icons.cartCheck"
|
:icon="$globals.icons.cartCheck"
|
||||||
width="70%"
|
width="70%"
|
||||||
:submit-text="$t('recipe.add-to-list')"
|
:submit-text="$t('recipe.add-to-list')"
|
||||||
|
@ -137,7 +137,7 @@
|
||||||
color="secondary"
|
color="secondary"
|
||||||
density="compact"
|
density="compact"
|
||||||
/>
|
/>
|
||||||
<div :key="ingredientData.ingredient.quantity">
|
<div :key="`${ingredientData.ingredient.quantity || 'no-qty'}-${i}`">
|
||||||
<RecipeIngredientListItem
|
<RecipeIngredientListItem
|
||||||
:ingredient="ingredientData.ingredient"
|
:ingredient="ingredientData.ingredient"
|
||||||
:disable-amount="ingredientData.disableAmount"
|
:disable-amount="ingredientData.disableAmount"
|
||||||
|
@ -172,7 +172,7 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script setup lang="ts">
|
||||||
import { toRefs } from "@vueuse/core";
|
import { toRefs } from "@vueuse/core";
|
||||||
import RecipeIngredientListItem from "./RecipeIngredientListItem.vue";
|
import RecipeIngredientListItem from "./RecipeIngredientListItem.vue";
|
||||||
import { useUserApi } from "~/composables/api";
|
import { useUserApi } from "~/composables/api";
|
||||||
|
@ -203,61 +203,43 @@ export interface ShoppingListRecipeIngredientSection {
|
||||||
ingredientSections: ShoppingListIngredientSection[];
|
ingredientSections: ShoppingListIngredientSection[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export default defineNuxtComponent({
|
interface Props {
|
||||||
components: {
|
recipes?: RecipeWithScale[];
|
||||||
RecipeIngredientListItem,
|
shoppingLists?: ShoppingListSummary[];
|
||||||
},
|
}
|
||||||
props: {
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
modelValue: {
|
recipes: undefined,
|
||||||
type: Boolean,
|
shoppingLists: () => [],
|
||||||
default: false,
|
});
|
||||||
},
|
|
||||||
recipes: {
|
|
||||||
type: Array as () => RecipeWithScale[],
|
|
||||||
default: undefined,
|
|
||||||
},
|
|
||||||
shoppingLists: {
|
|
||||||
type: Array as () => ShoppingListSummary[],
|
|
||||||
default: () => [],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
emits: ["update:modelValue"],
|
|
||||||
setup(props, context) {
|
|
||||||
const i18n = useI18n();
|
|
||||||
const $auth = useMealieAuth();
|
|
||||||
const api = useUserApi();
|
|
||||||
const preferences = useShoppingListPreferences();
|
|
||||||
const ready = ref(false);
|
|
||||||
|
|
||||||
// v-model support
|
const dialog = defineModel<boolean>({ default: false });
|
||||||
const dialog = computed({
|
|
||||||
get: () => {
|
|
||||||
return props.modelValue;
|
|
||||||
},
|
|
||||||
set: (val) => {
|
|
||||||
context.emit("update:modelValue", val);
|
|
||||||
initState();
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const state = reactive({
|
const i18n = useI18n();
|
||||||
|
const $auth = useMealieAuth();
|
||||||
|
const api = useUserApi();
|
||||||
|
const preferences = useShoppingListPreferences();
|
||||||
|
const ready = ref(false);
|
||||||
|
|
||||||
|
const state = reactive({
|
||||||
shoppingListDialog: true,
|
shoppingListDialog: true,
|
||||||
shoppingListIngredientDialog: false,
|
shoppingListIngredientDialog: false,
|
||||||
shoppingListShowAllToggled: false,
|
shoppingListShowAllToggled: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
const userHousehold = computed(() => {
|
const { shoppingListDialog, shoppingListIngredientDialog, shoppingListShowAllToggled: _shoppingListShowAllToggled } = toRefs(state);
|
||||||
|
|
||||||
|
const userHousehold = computed(() => {
|
||||||
return $auth.user.value?.householdSlug || "";
|
return $auth.user.value?.householdSlug || "";
|
||||||
});
|
});
|
||||||
|
|
||||||
const shoppingListChoices = computed(() => {
|
const shoppingListChoices = computed(() => {
|
||||||
return props.shoppingLists.filter(list => preferences.value.viewAllLists || list.userId === $auth.user.value?.id);
|
return props.shoppingLists.filter(list => preferences.value.viewAllLists || list.userId === $auth.user.value?.id);
|
||||||
});
|
});
|
||||||
|
|
||||||
const recipeIngredientSections = ref<ShoppingListRecipeIngredientSection[]>([]);
|
const recipeIngredientSections = ref<ShoppingListRecipeIngredientSection[]>([]);
|
||||||
const selectedShoppingList = ref<ShoppingListSummary | null>(null);
|
const selectedShoppingList = ref<ShoppingListSummary | null>(null);
|
||||||
|
|
||||||
watchEffect(
|
watchEffect(
|
||||||
() => {
|
() => {
|
||||||
if (shoppingListChoices.value.length === 1 && !state.shoppingListShowAllToggled) {
|
if (shoppingListChoices.value.length === 1 && !state.shoppingListShowAllToggled) {
|
||||||
selectedShoppingList.value = shoppingListChoices.value[0];
|
selectedShoppingList.value = shoppingListChoices.value[0];
|
||||||
|
@ -267,9 +249,15 @@ export default defineNuxtComponent({
|
||||||
ready.value = true;
|
ready.value = true;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
async function consolidateRecipesIntoSections(recipes: RecipeWithScale[]) {
|
watch(dialog, (val) => {
|
||||||
|
if (!val) {
|
||||||
|
initState();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
async function consolidateRecipesIntoSections(recipes: RecipeWithScale[]) {
|
||||||
const recipeSectionMap = new Map<string, ShoppingListRecipeIngredientSection>();
|
const recipeSectionMap = new Map<string, ShoppingListRecipeIngredientSection>();
|
||||||
for (const recipe of recipes) {
|
for (const recipe of recipes) {
|
||||||
if (!recipe.slug) {
|
if (!recipe.slug) {
|
||||||
|
@ -277,7 +265,10 @@ export default defineNuxtComponent({
|
||||||
}
|
}
|
||||||
|
|
||||||
if (recipeSectionMap.has(recipe.slug)) {
|
if (recipeSectionMap.has(recipe.slug)) {
|
||||||
recipeSectionMap.get(recipe.slug).recipeScale += recipe.scale;
|
const existingSection = recipeSectionMap.get(recipe.slug);
|
||||||
|
if (existingSection) {
|
||||||
|
existingSection.recipeScale += recipe.scale;
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -347,19 +338,19 @@ export default defineNuxtComponent({
|
||||||
}
|
}
|
||||||
|
|
||||||
recipeIngredientSections.value = Array.from(recipeSectionMap.values());
|
recipeIngredientSections.value = Array.from(recipeSectionMap.values());
|
||||||
}
|
}
|
||||||
|
|
||||||
function initState() {
|
function initState() {
|
||||||
state.shoppingListDialog = true;
|
state.shoppingListDialog = true;
|
||||||
state.shoppingListIngredientDialog = false;
|
state.shoppingListIngredientDialog = false;
|
||||||
state.shoppingListShowAllToggled = false;
|
state.shoppingListShowAllToggled = false;
|
||||||
recipeIngredientSections.value = [];
|
recipeIngredientSections.value = [];
|
||||||
selectedShoppingList.value = null;
|
selectedShoppingList.value = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
initState();
|
initState();
|
||||||
|
|
||||||
async function openShoppingListIngredientDialog(list: ShoppingListSummary) {
|
async function openShoppingListIngredientDialog(list: ShoppingListSummary) {
|
||||||
if (!props.recipes?.length) {
|
if (!props.recipes?.length) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -368,13 +359,13 @@ export default defineNuxtComponent({
|
||||||
await consolidateRecipesIntoSections(props.recipes);
|
await consolidateRecipesIntoSections(props.recipes);
|
||||||
state.shoppingListDialog = false;
|
state.shoppingListDialog = false;
|
||||||
state.shoppingListIngredientDialog = true;
|
state.shoppingListIngredientDialog = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function setShowAllToggled() {
|
function setShowAllToggled() {
|
||||||
state.shoppingListShowAllToggled = true;
|
state.shoppingListShowAllToggled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function bulkCheckIngredients(value = true) {
|
function bulkCheckIngredients(value = true) {
|
||||||
recipeIngredientSections.value.forEach((recipeSection) => {
|
recipeIngredientSections.value.forEach((recipeSection) => {
|
||||||
recipeSection.ingredientSections.forEach((ingSection) => {
|
recipeSection.ingredientSections.forEach((ingSection) => {
|
||||||
ingSection.ingredients.forEach((ing) => {
|
ingSection.ingredients.forEach((ing) => {
|
||||||
|
@ -382,9 +373,9 @@ export default defineNuxtComponent({
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function addRecipesToList() {
|
async function addRecipesToList() {
|
||||||
if (!selectedShoppingList.value) {
|
if (!selectedShoppingList.value) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -420,23 +411,7 @@ export default defineNuxtComponent({
|
||||||
state.shoppingListDialog = false;
|
state.shoppingListDialog = false;
|
||||||
state.shoppingListIngredientDialog = false;
|
state.shoppingListIngredientDialog = false;
|
||||||
dialog.value = false;
|
dialog.value = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
|
||||||
dialog,
|
|
||||||
preferences,
|
|
||||||
ready,
|
|
||||||
shoppingListChoices,
|
|
||||||
...toRefs(state),
|
|
||||||
addRecipesToList,
|
|
||||||
bulkCheckIngredients,
|
|
||||||
openShoppingListIngredientDialog,
|
|
||||||
setShowAllToggled,
|
|
||||||
recipeIngredientSections,
|
|
||||||
selectedShoppingList,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="css">
|
<style scoped lang="css">
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue