mirror of
https://github.com/mealie-recipes/mealie.git
synced 2025-08-05 21:45:25 +02:00
feat: Remove Explore URLs and make the normal URLs public (#2632)
* add groupSlug to most routes * fixed more routing issues * fixed jank and incorrect routes * remove public explore links * remove unused groupSlug and explore routes * nuked explore pages * fixed public toolstore bug * fixed various routes missing group slug * restored public app header menu * fix janky login redirect * 404 recipe API call returns to login * removed unused explore layout * force redirect when using the wrong group slug * fixed dead admin links * removed unused middleware from earlier attempt * 🧹 * improve cookbooks sidebar fixed sidebar link not working fixed sidebar link target hide cookbooks header when there are none * added group slug to user * fix $auth typehints * vastly simplified groupSlug logic * allow logged-in users to view other groups * fixed some edgecases that bypassed isOwnGroup * fixed static home ref * 🧹 * fixed redirect logic * lint warning * removed group slug from group and user pages refactored all components to use route groupSlug or user group slug moved some group pages to recipe pages * fixed some bad types * 🧹 * moved groupSlug routes under /g/groupSlug * move /recipe/ to /r/ * fix backend url generation and metadata injection * moved shopping lists to root/other route fixes * changed shared from /recipes/ to /r/ * fixed 404 redirect not awaiting * removed unused import * fix doc links * fix public recipe setting not affecting public API * fixed backend tests * fix nuxt-generate command --------- Co-authored-by: Hayden <64056131+hay-kot@users.noreply.github.com>
This commit is contained in:
parent
94cf690e8f
commit
80968b02bb
87 changed files with 555 additions and 501 deletions
|
@ -105,13 +105,13 @@
|
|||
</section>
|
||||
</section>
|
||||
<v-container class="mt-4 d-flex justify-center text-center">
|
||||
<nuxt-link to="/group/migrations"> {{ $t('recipe.looking-for-migrations') }} </nuxt-link>
|
||||
<nuxt-link :to="`/group/migrations`"> {{ $t('recipe.looking-for-migrations') }} </nuxt-link>
|
||||
</v-container>
|
||||
</v-container>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, reactive, ref, toRefs, useContext, onMounted } from "@nuxtjs/composition-api";
|
||||
import { computed, defineComponent, reactive, ref, toRefs, useContext, onMounted, useRoute } from "@nuxtjs/composition-api";
|
||||
import { useAdminApi } from "~/composables/api";
|
||||
import { AllBackups } from "~/lib/api/types/admin";
|
||||
|
||||
|
@ -119,6 +119,8 @@ export default defineComponent({
|
|||
layout: "admin",
|
||||
setup() {
|
||||
const { i18n, $auth } = useContext();
|
||||
const route = useRoute();
|
||||
const groupSlug = computed(() => route.value.params.groupSlug || $auth.user?.groupSlug || "");
|
||||
|
||||
const adminApi = useAdminApi();
|
||||
const selected = ref("");
|
||||
|
@ -192,6 +194,7 @@ export default defineComponent({
|
|||
onMounted(refreshBackups);
|
||||
|
||||
return {
|
||||
groupSlug,
|
||||
restoreBackup,
|
||||
selected,
|
||||
...toRefs(state),
|
||||
|
|
|
@ -77,7 +77,7 @@ export default defineComponent({
|
|||
const refUserDialog = ref();
|
||||
const { $auth } = useContext();
|
||||
|
||||
const user = computed(() => $auth.user as UserOut | null);
|
||||
const user = computed(() => $auth.user);
|
||||
|
||||
const { $globals, i18n } = useContext();
|
||||
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
<template>
|
||||
<client-only>
|
||||
<CookbookPage :group-slug="groupSlug" />
|
||||
</client-only>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, useRoute } from "@nuxtjs/composition-api";
|
||||
import CookbookPage from "@/components/Domain/Cookbook/CookbookPage.vue";
|
||||
|
||||
export default defineComponent({
|
||||
components: { CookbookPage },
|
||||
layout: "explore",
|
||||
setup() {
|
||||
const route = useRoute();
|
||||
const groupSlug = route.value.params.groupSlug;
|
||||
|
||||
return {
|
||||
groupSlug,
|
||||
}
|
||||
},
|
||||
})
|
||||
</script>
|
|
@ -1,47 +0,0 @@
|
|||
<template>
|
||||
<div v-if="recipe">
|
||||
<client-only>
|
||||
<RecipePage :recipe="recipe" />
|
||||
</client-only>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, useAsync, useMeta, useRoute, useRouter } from "@nuxtjs/composition-api";
|
||||
import RecipePage from "~/components/Domain/Recipe/RecipePage/RecipePage.vue";
|
||||
import { usePublicExploreApi } from "~/composables/api/api-client";
|
||||
|
||||
export default defineComponent({
|
||||
components: { RecipePage },
|
||||
layout: "explore",
|
||||
setup() {
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const groupSlug = route.value.params.groupSlug;
|
||||
const recipeSlug = route.value.params.recipeSlug;
|
||||
const api = usePublicExploreApi(groupSlug);
|
||||
|
||||
const { title } = useMeta();
|
||||
|
||||
const recipe = useAsync(async () => {
|
||||
const { data, error } = await api.explore.recipes.getOne(recipeSlug);
|
||||
|
||||
if (error) {
|
||||
console.error("error loading recipe -> ", error);
|
||||
router.push("/");
|
||||
}
|
||||
|
||||
if (data) {
|
||||
title.value = data?.name || "";
|
||||
}
|
||||
|
||||
return data;
|
||||
});
|
||||
|
||||
return {
|
||||
recipe,
|
||||
};
|
||||
},
|
||||
head: {},
|
||||
});
|
||||
</script>
|
|
@ -1,42 +0,0 @@
|
|||
<template>
|
||||
<div v-if="groupSlug">
|
||||
<client-only>
|
||||
<RecipeExplorerPage :group-slug="groupSlug" />
|
||||
</client-only>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, useRoute, useRouter } from "@nuxtjs/composition-api";
|
||||
import { invoke } from "@vueuse/core";
|
||||
import RecipeExplorerPage from "~/components/Domain/Recipe/RecipeExplorerPage.vue";
|
||||
import { usePublicExploreApi } from "~/composables/api/api-client";
|
||||
|
||||
export default defineComponent({
|
||||
components: { RecipeExplorerPage },
|
||||
layout: "explore",
|
||||
setup() {
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const groupSlug = route.value.params.groupSlug;
|
||||
const api = usePublicExploreApi(groupSlug);
|
||||
|
||||
invoke(async () => {
|
||||
if (!groupSlug) {
|
||||
return;
|
||||
}
|
||||
|
||||
// try to fetch one tag to make sure the group slug is valid
|
||||
const { data } = await api.explore.tags.getAll(1, 1);
|
||||
if (!data) {
|
||||
// the group slug is invalid, so leave the page (this results in a 404)
|
||||
router.push("/explore/recipes");
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
groupSlug,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
|
@ -90,14 +90,22 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from "@nuxtjs/composition-api";
|
||||
import { defineComponent, useRouter } from "@nuxtjs/composition-api";
|
||||
import draggable from "vuedraggable";
|
||||
import { useCookbooks } from "@/composables/use-group-cookbooks";
|
||||
import { useLoggedInState } from "~/composables/use-logged-in-state";
|
||||
import RecipeOrganizerSelector from "~/components/Domain/Recipe/RecipeOrganizerSelector.vue";
|
||||
|
||||
export default defineComponent({
|
||||
components: { draggable, RecipeOrganizerSelector },
|
||||
setup() {
|
||||
const { isOwnGroup, loggedIn } = useLoggedInState();
|
||||
const router = useRouter();
|
||||
|
||||
if (!(loggedIn.value && isOwnGroup.value)) {
|
||||
router.back();
|
||||
}
|
||||
|
||||
const { cookbooks, actions } = useCookbooks();
|
||||
|
||||
return {
|
14
frontend/pages/g/_groupSlug/index.vue
Normal file
14
frontend/pages/g/_groupSlug/index.vue
Normal file
|
@ -0,0 +1,14 @@
|
|||
<template>
|
||||
<div>
|
||||
<RecipeExplorerPage />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from "@nuxtjs/composition-api";
|
||||
import RecipeExplorerPage from "~/components/Domain/Recipe/RecipeExplorerPage.vue";
|
||||
|
||||
export default defineComponent({
|
||||
components: { RecipeExplorerPage },
|
||||
});
|
||||
</script>
|
59
frontend/pages/g/_groupSlug/r/_slug/index.vue
Normal file
59
frontend/pages/g/_groupSlug/r/_slug/index.vue
Normal file
|
@ -0,0 +1,59 @@
|
|||
<template>
|
||||
<div>
|
||||
<RecipePage v-if="recipe" :recipe="recipe" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, ref, useAsync, useContext, useMeta, useRoute, useRouter } from "@nuxtjs/composition-api";
|
||||
import { useLoggedInState } from "~/composables/use-logged-in-state";
|
||||
import RecipePage from "~/components/Domain/Recipe/RecipePage/RecipePage.vue";
|
||||
import { usePublicExploreApi } from "~/composables/api/api-client";
|
||||
import { useRecipe } from "~/composables/recipes";
|
||||
import { Recipe } from "~/lib/api/types/recipe";
|
||||
|
||||
export default defineComponent({
|
||||
components: { RecipePage },
|
||||
setup() {
|
||||
const { $auth } = useContext();
|
||||
const { isOwnGroup } = useLoggedInState();
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const slug = route.value.params.slug;
|
||||
|
||||
const { title } = useMeta();
|
||||
|
||||
let recipe = ref<Recipe | null>(null);
|
||||
if (isOwnGroup.value) {
|
||||
const { recipe: data } = useRecipe(slug);
|
||||
recipe = data;
|
||||
} else {
|
||||
const groupSlug = computed(() => route.value.params.groupSlug || $auth.user?.groupSlug || "")
|
||||
const api = usePublicExploreApi(groupSlug.value);
|
||||
recipe = useAsync(async () => {
|
||||
const { data, error } = await api.explore.recipes.getOne(slug);
|
||||
|
||||
if (error) {
|
||||
console.error("error loading recipe -> ", error);
|
||||
router.push(`/g/${groupSlug.value}`);
|
||||
}
|
||||
|
||||
return data;
|
||||
})
|
||||
}
|
||||
|
||||
title.value = recipe.value?.name || "";
|
||||
|
||||
return {
|
||||
recipe,
|
||||
};
|
||||
},
|
||||
head() {
|
||||
if (this.recipe) {
|
||||
return {
|
||||
title: this.recipe.name
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
|
@ -94,7 +94,7 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref, useRoute, useRouter } from "@nuxtjs/composition-api";
|
||||
import { computed, defineComponent, ref, useContext, useRoute, useRouter } from "@nuxtjs/composition-api";
|
||||
import { invoke, until } from "@vueuse/core";
|
||||
import {
|
||||
CreateIngredientFood,
|
||||
|
@ -124,9 +124,12 @@ export default defineComponent({
|
|||
RecipeIngredientEditor,
|
||||
},
|
||||
setup() {
|
||||
const { $auth } = useContext();
|
||||
const panels = ref<number[]>([]);
|
||||
|
||||
const route = useRoute();
|
||||
const groupSlug = computed(() => route.value.params.groupSlug || $auth.user?.groupSlug || "");
|
||||
|
||||
const router = useRouter();
|
||||
const slug = route.value.params.slug;
|
||||
const api = useUserApi();
|
||||
|
@ -324,7 +327,7 @@ export default defineComponent({
|
|||
const { response } = await api.recipes.updateOne(recipe.value.slug, recipe.value);
|
||||
|
||||
if (response?.status === 200) {
|
||||
router.push("/recipe/" + recipe.value.slug);
|
||||
router.push(`/g/${groupSlug.value}/r/${recipe.value.slug}`);
|
||||
}
|
||||
}
|
||||
|
|
@ -20,7 +20,7 @@
|
|||
|
||||
<AdvancedOnly>
|
||||
<v-container class="d-flex justify-center align-center my-4">
|
||||
<a to="/group/migrations"> {{ $t('recipe.looking-for-migrations') }}</a>
|
||||
<a :to="`/group/migrations`"> {{ $t('recipe.looking-for-migrations') }}</a>
|
||||
</v-container>
|
||||
</AdvancedOnly>
|
||||
</div>
|
||||
|
@ -34,7 +34,7 @@ import AdvancedOnly from "~/components/global/AdvancedOnly.vue";
|
|||
export default defineComponent({
|
||||
components: { AdvancedOnly },
|
||||
setup() {
|
||||
const { $globals, i18n } = useContext();
|
||||
const { $auth, $globals, i18n } = useContext();
|
||||
|
||||
const subpages: MenuItem[] = [
|
||||
{
|
||||
|
@ -71,10 +71,11 @@ export default defineComponent({
|
|||
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const groupSlug = computed(() => route.value.params.groupSlug || $auth.user?.groupSlug || "");
|
||||
|
||||
const subpage = computed({
|
||||
set(subpage: string) {
|
||||
router.push({ path: `/recipe/create/${subpage}`, query: route.value.query });
|
||||
router.push({ path: `/g/${groupSlug.value}/r/create/${subpage}`, query: route.value.query });
|
||||
},
|
||||
get() {
|
||||
return route.value.path.split("/").pop() ?? "url";
|
||||
|
@ -82,6 +83,7 @@ export default defineComponent({
|
|||
});
|
||||
|
||||
return {
|
||||
groupSlug,
|
||||
subpages,
|
||||
subpage,
|
||||
};
|
|
@ -10,7 +10,7 @@ export default defineComponent({
|
|||
const router = useRouter();
|
||||
onMounted(() => {
|
||||
// Force redirect to first valid page
|
||||
router.replace("/recipe/create/url");
|
||||
router.replace("/r/create/url");
|
||||
});
|
||||
return {};
|
||||
},
|
|
@ -35,7 +35,7 @@
|
|||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, reactive, toRefs, ref, useRouter } from "@nuxtjs/composition-api";
|
||||
import { defineComponent, reactive, toRefs, ref, useContext, useRouter, computed, useRoute } from "@nuxtjs/composition-api";
|
||||
import { AxiosResponse } from "axios";
|
||||
import { useUserApi } from "~/composables/api";
|
||||
import { validators } from "~/composables/use-validators";
|
||||
|
@ -47,6 +47,10 @@ export default defineComponent({
|
|||
error: false,
|
||||
loading: false,
|
||||
});
|
||||
const { $auth } = useContext();
|
||||
const route = useRoute();
|
||||
const groupSlug = computed(() => route.value.params.groupSlug || $auth.user?.groupSlug || "");
|
||||
|
||||
const api = useUserApi();
|
||||
const router = useRouter();
|
||||
|
||||
|
@ -56,7 +60,7 @@ export default defineComponent({
|
|||
state.loading = false;
|
||||
return;
|
||||
}
|
||||
router.push(`/recipe/${response.data}?edit=${edit.toString()}`);
|
||||
router.push(`/g/${groupSlug.value}/r/${response.data}?edit=${edit.toString()}`);
|
||||
}
|
||||
|
||||
const newRecipeName = ref("");
|
|
@ -32,7 +32,7 @@
|
|||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, reactive, toRefs, ref, useRouter } from "@nuxtjs/composition-api";
|
||||
import { defineComponent, reactive, toRefs, ref, useRouter, computed, useContext, useRoute } from "@nuxtjs/composition-api";
|
||||
import { AxiosResponse } from "axios";
|
||||
import { useUserApi } from "~/composables/api";
|
||||
import { validators } from "~/composables/use-validators";
|
||||
|
@ -45,6 +45,10 @@ export default defineComponent({
|
|||
loading: false,
|
||||
makeFileRecipeImage: false,
|
||||
});
|
||||
const { $auth } = useContext();
|
||||
const route = useRoute();
|
||||
const groupSlug = computed(() => route.value.params.groupSlug || $auth.user?.groupSlug || "");
|
||||
|
||||
const api = useUserApi();
|
||||
const router = useRouter();
|
||||
|
||||
|
@ -56,7 +60,7 @@ export default defineComponent({
|
|||
state.loading = false;
|
||||
return;
|
||||
}
|
||||
router.push(`/recipe/${response.data}/ocr-editor`);
|
||||
router.push(`/g/${groupSlug.value}/r/${response.data}/ocr-editor`);
|
||||
}
|
||||
|
||||
const domCreateByOcr = ref<VForm | null>(null);
|
|
@ -69,6 +69,7 @@ import {
|
|||
ref,
|
||||
useRouter,
|
||||
computed,
|
||||
useContext,
|
||||
useRoute,
|
||||
onMounted,
|
||||
} from "@nuxtjs/composition-api";
|
||||
|
@ -85,8 +86,11 @@ export default defineComponent({
|
|||
loading: false,
|
||||
});
|
||||
|
||||
const { $auth } = useContext();
|
||||
const api = useUserApi();
|
||||
const route = useRoute();
|
||||
const groupSlug = computed(() => route.value.params.groupSlug || $auth.user?.groupSlug || "");
|
||||
|
||||
const router = useRouter();
|
||||
const tags = useTagStore();
|
||||
|
||||
|
@ -99,7 +103,7 @@ export default defineComponent({
|
|||
if (refreshTags) {
|
||||
tags.actions.refresh();
|
||||
}
|
||||
router.push(`/recipe/${response.data}?edit=${edit.toString()}`);
|
||||
router.push(`/g/${groupSlug.value}/r/${response.data}?edit=${edit.toString()}`);
|
||||
}
|
||||
|
||||
const recipeUrl = computed({
|
|
@ -30,7 +30,7 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, reactive, toRefs, ref, useRouter } from "@nuxtjs/composition-api";
|
||||
import { computed, defineComponent, reactive, toRefs, ref, useContext, useRoute, useRouter } from "@nuxtjs/composition-api";
|
||||
import { AxiosResponse } from "axios";
|
||||
import { useUserApi } from "~/composables/api";
|
||||
import { validators } from "~/composables/use-validators";
|
||||
|
@ -41,6 +41,10 @@ export default defineComponent({
|
|||
error: false,
|
||||
loading: false,
|
||||
});
|
||||
const { $auth } = useContext();
|
||||
const route = useRoute();
|
||||
const groupSlug = computed(() => route.value.params.groupSlug || $auth.user?.groupSlug || "");
|
||||
|
||||
const api = useUserApi();
|
||||
const router = useRouter();
|
||||
|
||||
|
@ -50,7 +54,7 @@ export default defineComponent({
|
|||
state.loading = false;
|
||||
return;
|
||||
}
|
||||
router.push(`/recipe/${response.data}?edit=${edit.toString()}`);
|
||||
router.push(`/g/${groupSlug.value}/r/${response.data}?edit=${edit.toString()}`);
|
||||
}
|
||||
|
||||
const newRecipeZip = ref<File | null>(null);
|
|
@ -7,7 +7,7 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, useAsync, useMeta, useRoute, useRouter } from "@nuxtjs/composition-api";
|
||||
import { computed, defineComponent, useAsync, useContext, useMeta, useRoute, useRouter } from "@nuxtjs/composition-api";
|
||||
import RecipePage from "~/components/Domain/Recipe/RecipePage/RecipePage.vue";
|
||||
import { usePublicApi } from "~/composables/api/api-client";
|
||||
|
||||
|
@ -15,7 +15,10 @@ export default defineComponent({
|
|||
components: { RecipePage },
|
||||
layout: "basic",
|
||||
setup() {
|
||||
const { $auth } = useContext();
|
||||
const route = useRoute();
|
||||
const groupSlug = computed(() => route.value.params.groupSlug || $auth.user?.groupSlug || "");
|
||||
|
||||
const router = useRouter();
|
||||
const recipeId = route.value.params.id;
|
||||
const api = usePublicApi();
|
||||
|
@ -27,7 +30,7 @@ export default defineComponent({
|
|||
|
||||
if (error) {
|
||||
console.error("error loading recipe -> ", error);
|
||||
router.push("/");
|
||||
router.push(`/g/${groupSlug.value}`);
|
||||
}
|
||||
|
||||
if (data) {
|
|
@ -46,7 +46,9 @@ export default defineComponent({
|
|||
labels: i18n.tc("data-pages.labels.labels"),
|
||||
};
|
||||
|
||||
const DATA_TYPE_OPTIONS = [
|
||||
const route = useRoute();
|
||||
|
||||
const DATA_TYPE_OPTIONS = computed(() => [
|
||||
{
|
||||
text: i18n.t("general.recipes"),
|
||||
value: "new",
|
||||
|
@ -67,9 +69,7 @@ export default defineComponent({
|
|||
value: "new",
|
||||
to: "/group/data/labels",
|
||||
},
|
||||
];
|
||||
|
||||
const route = useRoute();
|
||||
]);
|
||||
|
||||
const buttonText = computed(() => {
|
||||
const last = route.value.path.split("/").pop();
|
||||
|
|
|
@ -26,10 +26,10 @@
|
|||
|
||||
<div class="d-flex align-center justify-space-between mb-2">
|
||||
<v-tabs>
|
||||
<v-tab to="/group/mealplan/planner/view">{{ $t('meal-plan.meal-planner') }}</v-tab>
|
||||
<v-tab to="/group/mealplan/planner/edit">{{ $t('general.edit') }}</v-tab>
|
||||
<v-tab :to="`/group/mealplan/planner/view`">{{ $t('meal-plan.meal-planner') }}</v-tab>
|
||||
<v-tab :to="`/group/mealplan/planner/edit`">{{ $t('general.edit') }}</v-tab>
|
||||
</v-tabs>
|
||||
<ButtonLink :icon="$globals.icons.calendar" to="/group/mealplan/settings" :text="$tc('general.settings')" />
|
||||
<ButtonLink :icon="$globals.icons.calendar" :to="`/group/mealplan/settings`" :text="$tc('general.settings')" />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
</template>
|
||||
</i18n>
|
||||
<v-container class="mt-1 px-0">
|
||||
<nuxt-link class="text-center" to="/user/profile/edit"> {{ $t('group.looking-to-update-your-profile') }} </nuxt-link>
|
||||
<nuxt-link class="text-center" :to="`/user/profile/edit`"> {{ $t('group.looking-to-update-your-profile') }} </nuxt-link>
|
||||
</v-container>
|
||||
</BasePageTitle>
|
||||
<v-data-table
|
||||
|
|
|
@ -1,29 +1,21 @@
|
|||
<template>
|
||||
<div v-if="groupSlug">
|
||||
<RecipeExplorerPage :group-slug="groupSlug" />
|
||||
</div>
|
||||
<div></div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref } from "@nuxtjs/composition-api";
|
||||
import { invoke } from "@vueuse/core";
|
||||
import { useUserApi } from "~/composables/api/api-client";
|
||||
import RecipeExplorerPage from "~/components/Domain/Recipe/RecipeExplorerPage.vue";
|
||||
|
||||
import { computed, defineComponent, useContext, useRouter } from "@nuxtjs/composition-api";
|
||||
export default defineComponent({
|
||||
components: { RecipeExplorerPage },
|
||||
layout: "blank",
|
||||
setup() {
|
||||
const api = useUserApi();
|
||||
const groupSlug = ref<string>();
|
||||
const { $auth } = useContext();
|
||||
const router = useRouter();
|
||||
const groupSlug = computed(() => $auth.user?.groupSlug);
|
||||
|
||||
invoke(async () => {
|
||||
const { data } = await api.users.getSelfGroup();
|
||||
groupSlug.value = data?.slug;
|
||||
});
|
||||
|
||||
return {
|
||||
groupSlug,
|
||||
};
|
||||
},
|
||||
if (groupSlug.value) {
|
||||
router.push(`/g/${groupSlug.value}`);
|
||||
} else {
|
||||
router.push("/login");
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -103,6 +103,7 @@
|
|||
<script lang="ts">
|
||||
import { defineComponent, ref, useContext, computed, reactive, useRouter } from "@nuxtjs/composition-api";
|
||||
import { useDark, whenever } from "@vueuse/core";
|
||||
import { useLoggedInState } from "~/composables/use-logged-in-state";
|
||||
import { useAppInfo } from "~/composables/api";
|
||||
import { usePasswordField } from "~/composables/use-passwords";
|
||||
import { alert } from "~/composables/use-toast";
|
||||
|
@ -115,11 +116,13 @@ export default defineComponent({
|
|||
|
||||
const router = useRouter();
|
||||
const { $auth, i18n } = useContext();
|
||||
const { loggedIn } = useLoggedInState();
|
||||
const groupSlug = computed(() => $auth.user?.groupSlug);
|
||||
|
||||
whenever(
|
||||
() => $auth.loggedIn,
|
||||
() => loggedIn.value && groupSlug.value,
|
||||
() => {
|
||||
router.push("/");
|
||||
router.push(`/g/${groupSlug.value || ""}`);
|
||||
},
|
||||
{ immediate: true },
|
||||
);
|
||||
|
|
|
@ -1,33 +0,0 @@
|
|||
<template>
|
||||
<div>
|
||||
<RecipePage v-if="recipe" :recipe="recipe" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, useRoute } from "@nuxtjs/composition-api";
|
||||
import RecipePage from "~/components/Domain/Recipe/RecipePage/RecipePage.vue";
|
||||
import { useRecipe } from "~/composables/recipes";
|
||||
|
||||
export default defineComponent({
|
||||
components: { RecipePage },
|
||||
setup() {
|
||||
const route = useRoute();
|
||||
const slug = route.value.params.slug;
|
||||
|
||||
const { recipe, loading } = useRecipe(slug);
|
||||
|
||||
return {
|
||||
recipe,
|
||||
loading,
|
||||
};
|
||||
},
|
||||
head() {
|
||||
if (this.recipe) {
|
||||
return {
|
||||
title: this.recipe.name
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
|
@ -199,7 +199,7 @@
|
|||
|
||||
<v-lazy>
|
||||
<div class="d-flex justify-end mt-10">
|
||||
<ButtonLink to="/group/data/labels" :text="$tc('shopping-list.manage-labels')" :icon="$globals.icons.tags" />
|
||||
<ButtonLink :to="`/group/data/labels`" :text="$tc('shopping-list.manage-labels')" :icon="$globals.icons.tags" />
|
||||
</div>
|
||||
</v-lazy>
|
||||
</v-container>
|
||||
|
@ -236,6 +236,7 @@ export default defineComponent({
|
|||
ShoppingListItemEditor,
|
||||
},
|
||||
setup() {
|
||||
const { $auth, i18n } = useContext();
|
||||
const preferences = useShoppingListPreferences();
|
||||
|
||||
const { idle } = useIdle(5 * 60 * 1000) // 5 minutes
|
||||
|
@ -247,10 +248,9 @@ export default defineComponent({
|
|||
const reorderLabelsDialog = ref(false);
|
||||
|
||||
const route = useRoute();
|
||||
const groupSlug = computed(() => route.value.params.groupSlug || $auth.user?.groupSlug || "");
|
||||
const id = route.value.params.id;
|
||||
|
||||
const { i18n } = useContext();
|
||||
|
||||
// ===============================================================
|
||||
// Shopping List Actions
|
||||
|
||||
|
@ -755,6 +755,7 @@ export default defineComponent({
|
|||
deleteListItem,
|
||||
edit,
|
||||
getLabelColor,
|
||||
groupSlug,
|
||||
itemsByLabel,
|
||||
listItems,
|
||||
loadingCounter,
|
||||
|
|
|
@ -33,19 +33,22 @@
|
|||
</v-card>
|
||||
</section>
|
||||
<div class="d-flex justify-end mt-10">
|
||||
<ButtonLink to="/group/data/labels" :text="$tc('shopping-list.manage-labels')" :icon="$globals.icons.tags" />
|
||||
<ButtonLink :to="`/group/data/labels`" :text="$tc('shopping-list.manage-labels')" :icon="$globals.icons.tags" />
|
||||
</div>
|
||||
</v-container>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, useAsync, reactive, toRefs } from "@nuxtjs/composition-api";
|
||||
import { computed, defineComponent, useAsync, useContext, reactive, toRefs, useRoute } from "@nuxtjs/composition-api";
|
||||
import { useUserApi } from "~/composables/api";
|
||||
import { useAsyncKey } from "~/composables/use-utils";
|
||||
|
||||
export default defineComponent({
|
||||
setup() {
|
||||
const { $auth } = useContext();
|
||||
const userApi = useUserApi();
|
||||
const route = useRoute();
|
||||
const groupSlug = computed(() => route.value.params.groupSlug || $auth.user?.groupSlug || "");
|
||||
|
||||
const state = reactive({
|
||||
createName: "",
|
||||
|
@ -95,6 +98,7 @@ export default defineComponent({
|
|||
|
||||
return {
|
||||
...toRefs(state),
|
||||
groupSlug,
|
||||
shoppingLists,
|
||||
createOne,
|
||||
deleteOne,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<v-container>
|
||||
<RecipeCardSection v-if="user" :icon="$globals.icons.heart" :title="$tc('user.user-favorites')" :recipes="user.favoriteRecipes">
|
||||
<RecipeCardSection v-if="user && isOwnGroup" :icon="$globals.icons.heart" :title="$tc('user.user-favorites')" :recipes="user.favoriteRecipes">
|
||||
</RecipeCardSection>
|
||||
</v-container>
|
||||
</template>
|
||||
|
@ -8,6 +8,7 @@
|
|||
<script lang="ts">
|
||||
import { defineComponent, useAsync, useRoute } from "@nuxtjs/composition-api";
|
||||
import RecipeCardSection from "~/components/Domain/Recipe/RecipeCardSection.vue";
|
||||
import { useLoggedInState } from "~/composables/use-logged-in-state";
|
||||
import { useUserApi } from "~/composables/api";
|
||||
import { useAsyncKey } from "~/composables/use-utils";
|
||||
|
||||
|
@ -16,6 +17,7 @@ export default defineComponent({
|
|||
setup() {
|
||||
const api = useUserApi();
|
||||
const route = useRoute();
|
||||
const { isOwnGroup } = useLoggedInState();
|
||||
|
||||
const userId = route.value.params.id;
|
||||
|
||||
|
@ -26,6 +28,7 @@ export default defineComponent({
|
|||
|
||||
return {
|
||||
user,
|
||||
isOwnGroup,
|
||||
};
|
||||
},
|
||||
head() {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<div></div>
|
||||
</template>
|
||||
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from "@nuxtjs/composition-api";
|
||||
|
||||
|
@ -16,6 +16,6 @@ export default defineComponent({
|
|||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
<style scoped>
|
||||
</style>
|
||||
</style>
|
||||
|
|
|
@ -108,9 +108,9 @@
|
|||
:label="$t('profile.show-advanced-description')"
|
||||
@change="updateUser"
|
||||
></v-checkbox>
|
||||
<nuxt-link class="mt-5 d-flex flex-column justify-center text-center" to="/group"> {{ $t('profile.looking-for-privacy-settings') }} </nuxt-link>
|
||||
<nuxt-link class="mt-5 d-flex flex-column justify-center text-center" :to="`/group`"> {{ $t('profile.looking-for-privacy-settings') }} </nuxt-link>
|
||||
<div class="d-flex flex-wrap justify-center mt-5">
|
||||
<v-btn outlined class="rounded-xl my-1 mx-1" to="/user/profile" nuxt exact>
|
||||
<v-btn outlined class="rounded-xl my-1 mx-1" :to="`/user/profile`" nuxt exact>
|
||||
<v-icon left>
|
||||
{{ $globals.icons.backArrow }}
|
||||
</v-icon>
|
||||
|
|
|
@ -16,17 +16,6 @@
|
|||
</v-icon>
|
||||
{{ $t('profile.get-invite-link') }}
|
||||
</v-btn>
|
||||
<v-btn
|
||||
v-if="group && group.preferences && !group.preferences.privateGroup"
|
||||
outlined
|
||||
rounded
|
||||
@click="getPublicLink()"
|
||||
>
|
||||
<v-icon left>
|
||||
{{ $globals.icons.shareVariant }}
|
||||
</v-icon>
|
||||
{{ $t('profile.get-public-link') }}
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
<div v-show="generatedSignupLink !== ''">
|
||||
<v-card-text>
|
||||
|
@ -114,7 +103,7 @@
|
|||
<v-row tag="section">
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<UserProfileLinkCard
|
||||
:link="{ text: $tc('profile.manage-user-profile'), to: '/user/profile/edit' }"
|
||||
:link="{ text: $tc('profile.manage-user-profile'), to: `/user/profile/edit` }"
|
||||
:image="require('~/static/svgs/manage-profile.svg')"
|
||||
>
|
||||
<template #title> {{ $t('profile.user-settings') }} </template>
|
||||
|
@ -124,7 +113,7 @@
|
|||
<AdvancedOnly>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<UserProfileLinkCard
|
||||
:link="{ text: $tc('profile.manage-your-api-tokens'), to: '/user/profile/api-tokens' }"
|
||||
:link="{ text: $tc('profile.manage-your-api-tokens'), to: `/user/profile/api-tokens` }"
|
||||
:image="require('~/static/svgs/manage-api-tokens.svg')"
|
||||
>
|
||||
<template #title> {{ $t('settings.token.api-tokens') }} </template>
|
||||
|
@ -143,7 +132,7 @@
|
|||
<v-row tag="section">
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<UserProfileLinkCard
|
||||
:link="{ text: $tc('profile.group-settings'), to: '/group' }"
|
||||
:link="{ text: $tc('profile.group-settings'), to: `/group` }"
|
||||
:image="require('~/static/svgs/manage-group-settings.svg')"
|
||||
>
|
||||
<template #title> {{ $t('profile.group-settings') }} </template>
|
||||
|
@ -152,7 +141,7 @@
|
|||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<UserProfileLinkCard
|
||||
:link="{ text: $tc('profile.manage-cookbooks'), to: '/group/cookbooks' }"
|
||||
:link="{ text: $tc('profile.manage-cookbooks'), to: `/g/${groupSlug}/cookbooks` }"
|
||||
:image="require('~/static/svgs/manage-cookbooks.svg')"
|
||||
>
|
||||
<template #title> {{ $t('sidebar.cookbooks') }} </template>
|
||||
|
@ -161,7 +150,7 @@
|
|||
</v-col>
|
||||
<v-col v-if="user.canManage" cols="12" sm="12" md="6">
|
||||
<UserProfileLinkCard
|
||||
:link="{ text: $tc('profile.manage-members'), to: '/group/members' }"
|
||||
:link="{ text: $tc('profile.manage-members'), to: `/group/members` }"
|
||||
:image="require('~/static/svgs/manage-members.svg')"
|
||||
>
|
||||
<template #title> {{ $t('profile.members') }} </template>
|
||||
|
@ -171,7 +160,7 @@
|
|||
<AdvancedOnly>
|
||||
<v-col v-if="user.advanced" cols="12" sm="12" md="6">
|
||||
<UserProfileLinkCard
|
||||
:link="{ text: $tc('profile.manage-webhooks'), to: '/group/webhooks' }"
|
||||
:link="{ text: $tc('profile.manage-webhooks'), to: `/group/webhooks` }"
|
||||
:image="require('~/static/svgs/manage-webhooks.svg')"
|
||||
>
|
||||
<template #title> {{ $t('settings.webhooks.webhooks') }} </template>
|
||||
|
@ -182,7 +171,7 @@
|
|||
<AdvancedOnly>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<UserProfileLinkCard
|
||||
:link="{ text: $tc('profile.manage-notifiers'), to: '/group/notifiers' }"
|
||||
:link="{ text: $tc('profile.manage-notifiers'), to: `/group/notifiers` }"
|
||||
:image="require('~/static/svgs/manage-notifiers.svg')"
|
||||
>
|
||||
<template #title> {{ $t('profile.notifiers') }} </template>
|
||||
|
@ -193,7 +182,7 @@
|
|||
<AdvancedOnly>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<UserProfileLinkCard
|
||||
:link="{ text: $tc('profile.manage-data'), to: '/group/data/foods' }"
|
||||
:link="{ text: $tc('profile.manage-data'), to: `/group/data/foods` }"
|
||||
:image="require('~/static/svgs/manage-recipes.svg')"
|
||||
>
|
||||
<template #title> {{ $t('profile.manage-data') }} </template>
|
||||
|
@ -204,7 +193,7 @@
|
|||
<AdvancedOnly>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<UserProfileLinkCard
|
||||
:link="{ text: $tc('profile.manage-data-migrations'), to: '/group/migrations' }"
|
||||
:link="{ text: $tc('profile.manage-data-migrations'), to: `/group/migrations` }"
|
||||
:image="require('~/static/svgs/manage-data-migrations.svg')"
|
||||
>
|
||||
<template #title>{{ $t('profile.data-migrations') }} </template>
|
||||
|
@ -218,7 +207,7 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, useContext, ref, toRefs, reactive, useAsync } from "@nuxtjs/composition-api";
|
||||
import { computed, defineComponent, useContext, ref, toRefs, reactive, useAsync, useRoute } from "@nuxtjs/composition-api";
|
||||
import { invoke, until } from "@vueuse/core";
|
||||
import UserProfileLinkCard from "@/components/Domain/User/UserProfileLinkCard.vue";
|
||||
import { useUserApi } from "~/composables/api";
|
||||
|
@ -239,6 +228,8 @@ export default defineComponent({
|
|||
scrollToTop: true,
|
||||
setup() {
|
||||
const { $auth, i18n } = useContext();
|
||||
const route = useRoute();
|
||||
const groupSlug = computed(() => route.value.params.groupSlug || $auth.user?.groupSlug || "");
|
||||
|
||||
// @ts-ignore $auth.user is typed as unknown, but it's a user
|
||||
const user = computed<UserOut | null>(() => $auth.user);
|
||||
|
@ -261,14 +252,6 @@ export default defineComponent({
|
|||
group.value = data;
|
||||
});
|
||||
|
||||
function getPublicLink() {
|
||||
if (group.value) {
|
||||
publicLink.value = `${window.location.origin}/explore/recipes/${group.value.slug}`
|
||||
showPublicLink.value = true;
|
||||
generatedSignupLink.value = "";
|
||||
}
|
||||
}
|
||||
|
||||
async function getSignupLink() {
|
||||
const { data } = await api.groups.createInvitation({ uses: 1 });
|
||||
if (data) {
|
||||
|
@ -350,16 +333,16 @@ export default defineComponent({
|
|||
return iconText[key] ?? $globals.icons.primary;
|
||||
}
|
||||
|
||||
const statsTo: { [key: string]: string } = {
|
||||
totalRecipes: "/",
|
||||
const statsTo = computed<{ [key: string]: string }>(() => { return {
|
||||
totalRecipes: `/g/${groupSlug.value}/`,
|
||||
totalUsers: "/group/members",
|
||||
totalCategories: "/recipes/categories",
|
||||
totalTags: "/recipes/tags",
|
||||
totalTools: "/recipes/tools",
|
||||
};
|
||||
totalCategories: `/g/${groupSlug.value}/recipes/categories`,
|
||||
totalTags: `/g/${groupSlug.value}/recipes/tags`,
|
||||
totalTools: `/g/${groupSlug.value}/recipes/tools`,
|
||||
}});
|
||||
|
||||
function getStatsTo(key: string) {
|
||||
return statsTo[key] ?? "unknown";
|
||||
return statsTo.value[key] ?? "unknown";
|
||||
}
|
||||
|
||||
const storage = useAsync(async () => {
|
||||
|
@ -386,6 +369,7 @@ export default defineComponent({
|
|||
});
|
||||
|
||||
return {
|
||||
groupSlug,
|
||||
storageText,
|
||||
storageUsedPercentage,
|
||||
getStatsTitle,
|
||||
|
@ -399,7 +383,6 @@ export default defineComponent({
|
|||
showPublicLink,
|
||||
publicLink,
|
||||
getSignupLink,
|
||||
getPublicLink,
|
||||
sendInvite,
|
||||
validators,
|
||||
validEmail,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue