mirror of
https://github.com/mealie-recipes/mealie.git
synced 2025-08-02 20:15:24 +02:00
feat: Add Households to Mealie (#3970)
This commit is contained in:
parent
0c29cef17d
commit
eb170cc7e5
315 changed files with 6975 additions and 3577 deletions
|
@ -2,30 +2,11 @@
|
|||
<div v-if="preferences">
|
||||
<BaseCardSectionTitle :title="$tc('group.general-preferences')"></BaseCardSectionTitle>
|
||||
<v-checkbox v-model="preferences.privateGroup" class="mt-n4" :label="$t('group.private-group')"></v-checkbox>
|
||||
<v-select
|
||||
v-model="preferences.firstDayOfWeek"
|
||||
:prepend-icon="$globals.icons.calendarWeekBegin"
|
||||
:items="allDays"
|
||||
item-text="name"
|
||||
item-value="value"
|
||||
:label="$t('settings.first-day-of-week')"
|
||||
/>
|
||||
|
||||
<BaseCardSectionTitle class="mt-5" :title="$tc('group.group-recipe-preferences')"></BaseCardSectionTitle>
|
||||
<template v-for="(_, key) in preferences">
|
||||
<v-checkbox
|
||||
v-if="labels[key]"
|
||||
:key="key"
|
||||
v-model="preferences[key]"
|
||||
class="mt-n4"
|
||||
:label="labels[key]"
|
||||
></v-checkbox>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, computed, useContext } from "@nuxtjs/composition-api";
|
||||
import { defineComponent, computed } from "@nuxtjs/composition-api";
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
|
@ -35,48 +16,6 @@ export default defineComponent({
|
|||
},
|
||||
},
|
||||
setup(props, context) {
|
||||
const { i18n } = useContext();
|
||||
|
||||
const labels = {
|
||||
recipePublic: i18n.tc("group.allow-users-outside-of-your-group-to-see-your-recipes"),
|
||||
recipeShowNutrition: i18n.tc("group.show-nutrition-information"),
|
||||
recipeShowAssets: i18n.tc("group.show-recipe-assets"),
|
||||
recipeLandscapeView: i18n.tc("group.default-to-landscape-view"),
|
||||
recipeDisableComments: i18n.tc("group.disable-users-from-commenting-on-recipes"),
|
||||
recipeDisableAmount: i18n.tc("group.disable-organizing-recipe-ingredients-by-units-and-food"),
|
||||
};
|
||||
|
||||
const allDays = [
|
||||
{
|
||||
name: i18n.t("general.sunday"),
|
||||
value: 0,
|
||||
},
|
||||
{
|
||||
name: i18n.t("general.monday"),
|
||||
value: 1,
|
||||
},
|
||||
{
|
||||
name: i18n.t("general.tuesday"),
|
||||
value: 2,
|
||||
},
|
||||
{
|
||||
name: i18n.t("general.wednesday"),
|
||||
value: 3,
|
||||
},
|
||||
{
|
||||
name: i18n.t("general.thursday"),
|
||||
value: 4,
|
||||
},
|
||||
{
|
||||
name: i18n.t("general.friday"),
|
||||
value: 5,
|
||||
},
|
||||
{
|
||||
name: i18n.t("general.saturday"),
|
||||
value: 6,
|
||||
},
|
||||
];
|
||||
|
||||
const preferences = computed({
|
||||
get() {
|
||||
return props.value;
|
||||
|
@ -87,8 +26,6 @@ export default defineComponent({
|
|||
});
|
||||
|
||||
return {
|
||||
allDays,
|
||||
labels,
|
||||
preferences,
|
||||
};
|
||||
},
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
import { computed, defineComponent, reactive, ref, toRefs, useContext } from "@nuxtjs/composition-api";
|
||||
import { Recipe } from "~/lib/api/types/recipe";
|
||||
import RecipeDialogAddToShoppingList from "~/components/Domain/Recipe/RecipeDialogAddToShoppingList.vue";
|
||||
import { ShoppingListSummary } from "~/lib/api/types/group";
|
||||
import { ShoppingListSummary } from "~/lib/api/types/household";
|
||||
import { useUserApi } from "~/composables/api";
|
||||
|
||||
export interface ContextMenuItem {
|
|
@ -35,7 +35,7 @@
|
|||
|
||||
<script lang="ts">
|
||||
import { defineComponent, computed, ref } from "@nuxtjs/composition-api";
|
||||
import { ReadWebhook } from "~/lib/api/types/group";
|
||||
import { ReadWebhook } from "~/lib/api/types/household";
|
||||
import { timeLocalToUTC, timeUTCToLocal } from "~/composables/use-group-webhooks";
|
||||
|
||||
export default defineComponent({
|
|
@ -0,0 +1,99 @@
|
|||
<template>
|
||||
<div v-if="preferences">
|
||||
<BaseCardSectionTitle :title="$tc('group.general-preferences')"></BaseCardSectionTitle>
|
||||
<v-checkbox v-model="preferences.privateHousehold" class="mt-n4" :label="$t('household.private-household')"></v-checkbox>
|
||||
<v-select
|
||||
v-model="preferences.firstDayOfWeek"
|
||||
:prepend-icon="$globals.icons.calendarWeekBegin"
|
||||
:items="allDays"
|
||||
item-text="name"
|
||||
item-value="value"
|
||||
:label="$t('settings.first-day-of-week')"
|
||||
/>
|
||||
|
||||
<BaseCardSectionTitle class="mt-5" :title="$tc('household.household-recipe-preferences')"></BaseCardSectionTitle>
|
||||
<template v-for="(_, key) in preferences">
|
||||
<v-checkbox
|
||||
v-if="labels[key]"
|
||||
:key="key"
|
||||
v-model="preferences[key]"
|
||||
class="mt-n4"
|
||||
:label="labels[key]"
|
||||
></v-checkbox>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, computed, useContext } from "@nuxtjs/composition-api";
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
value: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
setup(props, context) {
|
||||
const { i18n } = useContext();
|
||||
|
||||
const labels = {
|
||||
recipePublic: i18n.tc("household.allow-users-outside-of-your-household-to-see-your-recipes"),
|
||||
recipeShowNutrition: i18n.tc("group.show-nutrition-information"),
|
||||
recipeShowAssets: i18n.tc("group.show-recipe-assets"),
|
||||
recipeLandscapeView: i18n.tc("group.default-to-landscape-view"),
|
||||
recipeDisableComments: i18n.tc("group.disable-users-from-commenting-on-recipes"),
|
||||
recipeDisableAmount: i18n.tc("group.disable-organizing-recipe-ingredients-by-units-and-food"),
|
||||
};
|
||||
|
||||
const allDays = [
|
||||
{
|
||||
name: i18n.t("general.sunday"),
|
||||
value: 0,
|
||||
},
|
||||
{
|
||||
name: i18n.t("general.monday"),
|
||||
value: 1,
|
||||
},
|
||||
{
|
||||
name: i18n.t("general.tuesday"),
|
||||
value: 2,
|
||||
},
|
||||
{
|
||||
name: i18n.t("general.wednesday"),
|
||||
value: 3,
|
||||
},
|
||||
{
|
||||
name: i18n.t("general.thursday"),
|
||||
value: 4,
|
||||
},
|
||||
{
|
||||
name: i18n.t("general.friday"),
|
||||
value: 5,
|
||||
},
|
||||
{
|
||||
name: i18n.t("general.saturday"),
|
||||
value: 6,
|
||||
},
|
||||
];
|
||||
|
||||
const preferences = computed({
|
||||
get() {
|
||||
return props.value;
|
||||
},
|
||||
set(val) {
|
||||
context.emit("input", val);
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
allDays,
|
||||
labels,
|
||||
preferences,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
</style>
|
|
@ -337,7 +337,7 @@ export default defineComponent({
|
|||
);
|
||||
break;
|
||||
case EVENTS.updated:
|
||||
setter("update_at", $globals.icons.sortClockAscending, $globals.icons.sortClockDescending, "desc", false);
|
||||
setter("updated_at", $globals.icons.sortClockAscending, $globals.icons.sortClockDescending, "desc", false);
|
||||
break;
|
||||
case EVENTS.lastMade:
|
||||
setter(
|
||||
|
|
|
@ -138,11 +138,11 @@ import RecipeDialogShare from "./RecipeDialogShare.vue";
|
|||
import { useLoggedInState } from "~/composables/use-logged-in-state";
|
||||
import { useUserApi } from "~/composables/api";
|
||||
import { useGroupRecipeActions } from "~/composables/use-group-recipe-actions";
|
||||
import { useGroupSelf } from "~/composables/use-groups";
|
||||
import { useHouseholdSelf } from "~/composables/use-households";
|
||||
import { alert } from "~/composables/use-toast";
|
||||
import { usePlanTypeOptions } from "~/composables/use-group-mealplan";
|
||||
import { Recipe } from "~/lib/api/types/recipe";
|
||||
import { GroupRecipeActionOut, ShoppingListSummary } from "~/lib/api/types/group";
|
||||
import { GroupRecipeActionOut, ShoppingListSummary } from "~/lib/api/types/household";
|
||||
import { PlanEntryType } from "~/lib/api/types/meal-plan";
|
||||
import { useAxiosDownloader } from "~/composables/api/use-axios-download";
|
||||
|
||||
|
@ -254,14 +254,14 @@ export default defineComponent({
|
|||
});
|
||||
|
||||
const { i18n, $auth, $globals } = useContext();
|
||||
const { group } = useGroupSelf();
|
||||
const { household } = useHouseholdSelf();
|
||||
const { isOwnGroup } = useLoggedInState();
|
||||
|
||||
const route = useRoute();
|
||||
const groupSlug = computed(() => route.value.params.groupSlug || $auth.user?.groupSlug || "");
|
||||
|
||||
const firstDayOfWeek = computed(() => {
|
||||
return group.value?.preferences?.firstDayOfWeek || 0;
|
||||
return household.value?.preferences?.firstDayOfWeek || 0;
|
||||
});
|
||||
|
||||
// ===========================================================================
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
</tr>
|
||||
</template>
|
||||
<template #item.name="{ item }">
|
||||
<a :href="`/r/${item.slug}`" style="color: inherit; text-decoration: inherit; " @click="$emit('click')">{{ item.name }}</a>
|
||||
<a :href="`/g/${groupSlug}/r/${item.slug}`" style="color: inherit; text-decoration: inherit; " @click="$emit('click')">{{ item.name }}</a>
|
||||
</template>
|
||||
<template #item.tags="{ item }">
|
||||
<RecipeChip small :items="item.tags" :is-category="false" url-prefix="tags" />
|
||||
|
@ -48,7 +48,7 @@ import UserAvatar from "../User/UserAvatar.vue";
|
|||
import RecipeChip from "./RecipeChips.vue";
|
||||
import { Recipe } from "~/lib/api/types/recipe";
|
||||
import { useUserApi } from "~/composables/api";
|
||||
import { UserOut } from "~/lib/api/types/user";
|
||||
import { UserSummary } from "~/lib/api/types/user";
|
||||
|
||||
const INPUT_EVENT = "input";
|
||||
|
||||
|
@ -95,7 +95,8 @@ export default defineComponent({
|
|||
},
|
||||
},
|
||||
setup(props, context) {
|
||||
const { i18n } = useContext();
|
||||
const { $auth, i18n } = useContext();
|
||||
const groupSlug = $auth.user?.groupSlug;
|
||||
|
||||
function setValue(value: Recipe[]) {
|
||||
context.emit(INPUT_EVENT, value);
|
||||
|
@ -134,7 +135,7 @@ export default defineComponent({
|
|||
// ============
|
||||
// Group Members
|
||||
const api = useUserApi();
|
||||
const members = ref<UserOut[]>([]);
|
||||
const members = ref<UserSummary[]>([]);
|
||||
|
||||
async function refreshMembers() {
|
||||
const { data } = await api.groups.fetchMembers();
|
||||
|
@ -149,13 +150,19 @@ export default defineComponent({
|
|||
|
||||
function getMember(id: string) {
|
||||
if (members.value[0]) {
|
||||
return members.value.find((m) => m.id === id)?.username;
|
||||
return members.value.find((m) => m.id === id)?.fullName;
|
||||
}
|
||||
|
||||
return i18n.t("general.none");
|
||||
}
|
||||
|
||||
return { setValue, headers, members, getMember };
|
||||
return {
|
||||
groupSlug,
|
||||
setValue,
|
||||
headers,
|
||||
members,
|
||||
getMember,
|
||||
};
|
||||
},
|
||||
|
||||
data() {
|
||||
|
|
|
@ -127,14 +127,14 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, reactive, ref, useContext, watchEffect } from "@nuxtjs/composition-api"
|
||||
import { toRefs } from "@vueuse/core"
|
||||
import RecipeIngredientListItem from "./RecipeIngredientListItem.vue"
|
||||
import { useUserApi } from "~/composables/api"
|
||||
import { alert } from "~/composables/use-toast"
|
||||
import { useShoppingListPreferences } from "~/composables/use-users/preferences"
|
||||
import { ShoppingListSummary } from "~/lib/api/types/group"
|
||||
import { Recipe, RecipeIngredient } from "~/lib/api/types/recipe"
|
||||
import { computed, defineComponent, reactive, ref, useContext, watchEffect } from "@nuxtjs/composition-api";
|
||||
import { toRefs } from "@vueuse/core";
|
||||
import RecipeIngredientListItem from "./RecipeIngredientListItem.vue";
|
||||
import { useUserApi } from "~/composables/api";
|
||||
import { alert } from "~/composables/use-toast";
|
||||
import { useShoppingListPreferences } from "~/composables/use-users/preferences";
|
||||
import { ShoppingListSummary } from "~/lib/api/types/household";
|
||||
import { Recipe, RecipeIngredient } from "~/lib/api/types/recipe";
|
||||
|
||||
export interface RecipeWithScale extends Recipe {
|
||||
scale: number;
|
||||
|
@ -209,7 +209,8 @@ export default defineComponent({
|
|||
watchEffect(
|
||||
() => {
|
||||
if (shoppingListChoices.value.length === 1 && !state.shoppingListShowAllToggled) {
|
||||
openShoppingListIngredientDialog(shoppingListChoices.value[0]);
|
||||
selectedShoppingList.value = shoppingListChoices.value[0];
|
||||
openShoppingListIngredientDialog(selectedShoppingList.value);
|
||||
} else {
|
||||
ready.value = true;
|
||||
}
|
||||
|
@ -365,12 +366,8 @@ export default defineComponent({
|
|||
}
|
||||
})
|
||||
|
||||
const successMessage = promises.length === 1
|
||||
? i18n.t("recipe.successfully-added-to-list") as string
|
||||
: i18n.t("recipe.failed-to-add-to-list") as string;
|
||||
|
||||
success ? alert.success(successMessage)
|
||||
: alert.error(i18n.t("failed-to-add-recipes-to-list") as string)
|
||||
success ? alert.success(i18n.tc("recipe.successfully-added-to-list"))
|
||||
: alert.error(i18n.tc("failed-to-add-recipes-to-list"))
|
||||
|
||||
state.shoppingListDialog = false;
|
||||
state.shoppingListIngredientDialog = false;
|
||||
|
|
|
@ -66,7 +66,7 @@ import { defineComponent, computed, toRefs, reactive, useContext, useRoute } fro
|
|||
import { useClipboard, useShare, whenever } from "@vueuse/core";
|
||||
import { RecipeShareToken } from "~/lib/api/types/recipe";
|
||||
import { useUserApi } from "~/composables/api";
|
||||
import { useGroupSelf } from "~/composables/use-groups";
|
||||
import { useHouseholdSelf } from "~/composables/use-households";
|
||||
import { alert } from "~/composables/use-toast";
|
||||
|
||||
export default defineComponent({
|
||||
|
@ -113,12 +113,12 @@ export default defineComponent({
|
|||
);
|
||||
|
||||
const { $auth, i18n } = useContext();
|
||||
const { group } = useGroupSelf();
|
||||
const { household } = useHouseholdSelf();
|
||||
const route = useRoute();
|
||||
const groupSlug = computed(() => route.value.params.groupSlug || $auth.user?.groupSlug || "");
|
||||
|
||||
const firstDayOfWeek = computed(() => {
|
||||
return group.value?.preferences?.firstDayOfWeek || 0;
|
||||
return household.value?.preferences?.firstDayOfWeek || 0;
|
||||
});
|
||||
|
||||
// ============================================================
|
||||
|
|
|
@ -349,7 +349,7 @@ export default defineComponent({
|
|||
{
|
||||
icon: $globals.icons.update,
|
||||
name: i18n.tc("general.updated"),
|
||||
value: "update_at",
|
||||
value: "updated_at",
|
||||
},
|
||||
{
|
||||
icon: $globals.icons.diceMultiple,
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
</template>
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent } from "@nuxtjs/composition-api";
|
||||
import { RecipeIngredient } from "~/lib/api/types/group";
|
||||
import { RecipeIngredient } from "~/lib/api/types/household";
|
||||
import { useParsedIngredientText } from "~/composables/recipes";
|
||||
|
||||
export default defineComponent({
|
||||
|
|
|
@ -114,7 +114,7 @@ import { computed, defineComponent, reactive, ref, toRefs, useContext } from "@n
|
|||
import { whenever } from "@vueuse/core";
|
||||
import { VForm } from "~/types/vuetify";
|
||||
import { useUserApi } from "~/composables/api";
|
||||
import { useGroupSelf } from "~/composables/use-groups";
|
||||
import { useHouseholdSelf } from "~/composables/use-households";
|
||||
import { Recipe, RecipeTimelineEventIn } from "~/lib/api/types/recipe";
|
||||
|
||||
export default defineComponent({
|
||||
|
@ -131,7 +131,7 @@ export default defineComponent({
|
|||
setup(props, context) {
|
||||
const madeThisDialog = ref(false);
|
||||
const userApi = useUserApi();
|
||||
const { group } = useGroupSelf();
|
||||
const { household } = useHouseholdSelf();
|
||||
const { $auth, i18n } = useContext();
|
||||
const domMadeThisForm = ref<VForm>();
|
||||
const newTimelineEvent = ref<RecipeTimelineEventIn>({
|
||||
|
@ -157,7 +157,7 @@ export default defineComponent({
|
|||
);
|
||||
|
||||
const firstDayOfWeek = computed(() => {
|
||||
return group.value?.preferences?.firstDayOfWeek || 0;
|
||||
return household.value?.preferences?.firstDayOfWeek || 0;
|
||||
});
|
||||
|
||||
function clearImage() {
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
import { computed, defineComponent, useContext, useRoute } from "@nuxtjs/composition-api";
|
||||
import DOMPurify from "dompurify";
|
||||
import { useFraction } from "~/composables/recipes/use-fraction";
|
||||
import { ShoppingListItemOut } from "~/lib/api/types/group";
|
||||
import { ShoppingListItemOut } from "~/lib/api/types/household";
|
||||
import { RecipeSummary } from "~/lib/api/types/recipe";
|
||||
|
||||
export default defineComponent({
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref, useContext } from "@nuxtjs/composition-api";
|
||||
import { ShoppingListMultiPurposeLabelOut } from "~/lib/api/types/group";
|
||||
import { ShoppingListMultiPurposeLabelOut } from "~/lib/api/types/household";
|
||||
|
||||
interface actions {
|
||||
text: string;
|
||||
|
|
|
@ -75,7 +75,7 @@
|
|||
<v-row v-if="listItem.checked" no-gutters class="mb-2">
|
||||
<v-col cols="auto">
|
||||
<div class="text-caption font-weight-light font-italic">
|
||||
{{ $t("shopping-list.completed-on", {date: new Date(listItem.updateAt || "").toLocaleDateString($i18n.locale)}) }}
|
||||
{{ $t("shopping-list.completed-on", {date: new Date(listItem.updatedAt || "").toLocaleDateString($i18n.locale)}) }}
|
||||
</div>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
@ -99,7 +99,7 @@ import { defineComponent, computed, ref, useContext } from "@nuxtjs/composition-
|
|||
import RecipeIngredientListItem from "../Recipe/RecipeIngredientListItem.vue";
|
||||
import ShoppingListItemEditor from "./ShoppingListItemEditor.vue";
|
||||
import MultiPurposeLabel from "./MultiPurposeLabel.vue";
|
||||
import { ShoppingListItemOut } from "~/lib/api/types/group";
|
||||
import { ShoppingListItemOut } from "~/lib/api/types/household";
|
||||
import { MultiPurposeLabelOut, MultiPurposeLabelSummary } from "~/lib/api/types/labels";
|
||||
import { IngredientFood, IngredientUnit, RecipeSummary } from "~/lib/api/types/recipe";
|
||||
import RecipeList from "~/components/Domain/Recipe/RecipeList.vue";
|
||||
|
|
|
@ -111,7 +111,7 @@
|
|||
|
||||
<script lang="ts">
|
||||
import { defineComponent, computed, watch } from "@nuxtjs/composition-api";
|
||||
import { ShoppingListItemCreate, ShoppingListItemOut } from "~/lib/api/types/group";
|
||||
import { ShoppingListItemCreate, ShoppingListItemOut } from "~/lib/api/types/household";
|
||||
import { MultiPurposeLabelOut } from "~/lib/api/types/labels";
|
||||
import { IngredientFood, IngredientUnit } from "~/lib/api/types/recipe";
|
||||
import { useFoodStore, useFoodData, useUnitStore, useUnitData } from "~/composables/store";
|
||||
|
|
|
@ -183,7 +183,7 @@ export default defineComponent({
|
|||
{
|
||||
icon: $globals.icons.calendarMultiselect,
|
||||
title: i18n.tc("meal-plan.meal-planner"),
|
||||
to: "/group/mealplan/planner/view",
|
||||
to: "/household/mealplan/planner/view",
|
||||
restricted: true,
|
||||
},
|
||||
{
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<v-toolbar flat>
|
||||
<v-toolbar color="transparent" flat>
|
||||
<BaseButton color="null" rounded secondary @click="$router.go(-1)">
|
||||
<template #icon> {{ $globals.icons.arrowLeftBold }}</template>
|
||||
{{ $t('general.back') }}
|
||||
|
|
|
@ -85,6 +85,8 @@
|
|||
:label="inputField.label"
|
||||
:name="inputField.varName"
|
||||
:items="inputField.options"
|
||||
:item-text="inputField.itemText"
|
||||
:item-value="inputField.itemValue"
|
||||
:return-object="false"
|
||||
:hint="inputField.hint"
|
||||
persistent-hint
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue