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

feat: Add Households to Mealie (#3970)

This commit is contained in:
Michael Genson 2024-08-22 10:14:32 -05:00 committed by GitHub
parent 0c29cef17d
commit eb170cc7e5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
315 changed files with 6975 additions and 3577 deletions

View file

@ -4,7 +4,7 @@ import { BaseCRUDAPI, BaseCRUDAPIReadOnly } from "~/lib/api/base/base-clients";
import { QueryValue } from "~/lib/api/base/route";
type BoundT = {
id?: string | number;
id?: string | number | null;
};
interface PublicStoreActions<T extends BoundT> {

View file

@ -160,6 +160,9 @@ export function usePageUser(): { user: UserOut } {
group: "",
groupId: "",
groupSlug: "",
household: "",
householdId: "",
householdSlug: "",
cacheKey: "",
email: "",
},

View file

@ -46,7 +46,7 @@ export function useParsedIngredientText(ingredient: RecipeIngredient, disableAmo
}
const { quantity, food, unit, note } = ingredient;
const usePluralUnit = quantity !== undefined && (quantity * scale > 1 || quantity * scale === 0);
const usePluralUnit = quantity !== undefined && ((quantity || 0) * scale > 1 || (quantity || 0) * scale === 0);
const usePluralFood = (!quantity) || quantity * scale > 1
let returnQty = "";
@ -69,8 +69,8 @@ export function useParsedIngredientText(ingredient: RecipeIngredient, disableAmo
}
}
const unitName = useUnitName(unit, usePluralUnit);
const foodName = useFoodName(food, usePluralFood);
const unitName = useUnitName(unit || undefined, usePluralUnit);
const foodName = useFoodName(food || undefined, usePluralFood);
return {
quantity: returnQty ? sanitizeIngredientHTML(returnQty) : undefined,

View file

@ -2,7 +2,7 @@ import { reactive, ref, Ref } from "@nuxtjs/composition-api";
import { usePublicStoreActions, useStoreActions } from "../partials/use-actions-factory";
import { usePublicExploreApi } from "../api/api-client";
import { useUserApi } from "~/composables/api";
import { RecipeTag } from "~/lib/api/types/admin";
import { RecipeTag } from "~/lib/api/types/recipe";
const items: Ref<RecipeTag[]> = ref([]);
const publicStoreLoading = ref(false);

View file

@ -1,6 +1,7 @@
import { useAsync, ref, Ref, useContext } from "@nuxtjs/composition-api";
import { useAsyncKey } from "./use-utils";
import { usePublicExploreApi } from "./api/api-client";
import { useHouseholdSelf } from "./use-households";
import { useUserApi } from "~/composables/api";
import { ReadCookBook, UpdateCookBook } from "~/lib/api/types/cookbook";
@ -67,6 +68,7 @@ export const usePublicCookbooks = function (groupSlug: string) {
export const useCookbooks = function () {
const api = useUserApi();
const { household } = useHouseholdSelf();
const loading = ref(false);
const { i18n } = useContext();
@ -100,7 +102,7 @@ export const useCookbooks = function () {
async createOne() {
loading.value = true;
const { data } = await api.cookbooks.createOne({
name: i18n.t("cookbook.cookbook-with-name", [String((cookbookStore?.value?.length ?? 0) + 1)]) as string,
name: i18n.t("cookbook.household-cookbook-name", [household.value?.name || "", String((cookbookStore?.value?.length ?? 0) + 1)]) as string,
});
if (data && cookbookStore?.value) {
cookbookStore.value.push(data);

View file

@ -1,7 +1,7 @@
import { computed, reactive, ref } from "@nuxtjs/composition-api";
import { useStoreActions } from "./partials/use-actions-factory";
import { useUserApi } from "~/composables/api";
import { GroupRecipeActionOut, RecipeActionType } from "~/lib/api/types/group";
import { GroupRecipeActionOut, GroupRecipeActionType } from "~/lib/api/types/household";
import { Recipe } from "~/lib/api/types/recipe";
const groupRecipeActions = ref<GroupRecipeActionOut[] | null>(null);
@ -10,7 +10,7 @@ const loading = ref(false);
export function useGroupRecipeActionData() {
const data = reactive({
id: "",
actionType: "link" as RecipeActionType,
actionType: "link" as GroupRecipeActionType,
title: "",
url: "",
});

View file

@ -1,7 +1,7 @@
import { useAsync, ref } from "@nuxtjs/composition-api";
import { useAsyncKey } from "./use-utils";
import { useUserApi } from "~/composables/api";
import { ReadWebhook } from "~/lib/api/types/group";
import { ReadWebhook } from "~/lib/api/types/household";
export const useGroupWebhooks = function () {
const api = useUserApi();

View file

@ -51,7 +51,7 @@ export const useGroups = function () {
loading.value = true;
const asyncKey = String(Date.now());
const groups = useAsync(async () => {
const { data } = await api.groups.getAll();
const { data } = await api.groups.getAll(1, -1, {orderBy: "name", orderDirection: "asc"});;
if (data) {
return data.items;
@ -66,7 +66,7 @@ export const useGroups = function () {
async function refreshAllGroups() {
loading.value = true;
const { data } = await api.groups.getAll();
const { data } = await api.groups.getAll(1, -1, {orderBy: "name", orderDirection: "asc"});;
if (data) {
groups.value = data.items;

View file

@ -0,0 +1,117 @@
import { computed, ref, Ref, useAsync } from "@nuxtjs/composition-api";
import { useUserApi } from "~/composables/api";
import { HouseholdCreate, HouseholdInDB } from "~/lib/api/types/household";
const householdSelfRef = ref<HouseholdInDB | null>(null);
const loading = ref(false);
export const useHouseholdSelf = function () {
const api = useUserApi();
async function refreshHouseholdSelf() {
loading.value = true;
const { data } = await api.households.getCurrentUserHousehold();
householdSelfRef.value = data;
loading.value = false;
}
const actions = {
get() {
if (!(householdSelfRef.value || loading.value)) {
refreshHouseholdSelf();
}
return householdSelfRef;
},
async updatePreferences() {
if (!householdSelfRef.value) {
await refreshHouseholdSelf();
}
if (!householdSelfRef.value?.preferences) {
return;
}
const { data } = await api.households.setPreferences(householdSelfRef.value.preferences);
if (data) {
householdSelfRef.value.preferences = data;
}
},
};
const household = actions.get();
return { actions, household };
};
export const useHouseholds = function () {
const api = useUserApi();
const loading = ref(false);
function getAllHouseholds() {
loading.value = true;
const asyncKey = String(Date.now());
const households = useAsync(async () => {
const { data } = await api.households.getAll(1, -1, {orderBy: "name, group.name", orderDirection: "asc"});
if (data) {
return data.items;
} else {
return null;
}
}, asyncKey);
loading.value = false;
return households;
}
async function refreshAllHouseholds() {
loading.value = true;
const { data } = await api.households.getAll(1, -1, {orderBy: "name, group.name", orderDirection: "asc"});;
if (data) {
households.value = data.items;
} else {
households.value = null;
}
loading.value = false;
}
async function deleteHousehold(id: string | number) {
loading.value = true;
const { data } = await api.households.deleteOne(id);
loading.value = false;
refreshAllHouseholds();
return data;
}
async function createHousehold(payload: HouseholdCreate) {
loading.value = true;
const { data } = await api.households.createOne(payload);
if (data && households.value) {
households.value.push(data);
}
}
const households = getAllHouseholds();
function useHouseholdsInGroup(groupIdRef: Ref<string>) {
return computed(
() => {
return (households.value && groupIdRef.value)
? households.value.filter((h) => h.groupId === groupIdRef.value)
: [];
},
);
}
return {
households,
useHouseholdsInGroup,
getAllHouseholds,
refreshAllHouseholds,
deleteHousehold,
createHousehold,
};
};

View file

@ -1,7 +1,7 @@
import { computed, reactive, watch } from "@nuxtjs/composition-api";
import { useLocalStorage } from "@vueuse/core";
import { useUserApi } from "~/composables/api";
import { ShoppingListItemOut, ShoppingListOut } from "~/lib/api/types/group";
import { ShoppingListItemOut, ShoppingListOut } from "~/lib/api/types/household";
import { RequestResponse } from "~/lib/api/types/non-generated";
const localStorageKey = "shopping-list-queue";
@ -144,7 +144,7 @@ export function useShoppingListItemActions(shoppingListId: string) {
function checkUpdateState(list: ShoppingListOut) {
const cutoffDate = new Date(queue.lastUpdate + queueTimeout).toISOString();
if (list.updateAt && list.updateAt > cutoffDate) {
if (list.updatedAt && list.updatedAt > cutoffDate) {
// If the queue is too far behind the shopping list to reliably do updates, we clear the queue
console.log("Out of sync with server; clearing queue");
clearQueueItems("all");