mirror of
https://github.com/mealie-recipes/mealie.git
synced 2025-05-24 01:12:54 -04:00
feat: implement user favorites page (#1376)
* fix geFavorites return * add support for toggling to dense cards on desktop * add favorites page link * implement basic favorites page
This commit is contained in:
parent
f6c18ec73d
commit
3030e3e7f4
@ -1,5 +1,15 @@
|
||||
import { BaseCRUDAPI } from "../_base";
|
||||
import { ChangePassword, DeleteTokenResponse, LongLiveTokenIn, LongLiveTokenOut, ResetPassword, UserBase, UserIn, UserOut } from "~/types/api-types/user";
|
||||
import {
|
||||
ChangePassword,
|
||||
DeleteTokenResponse,
|
||||
LongLiveTokenIn,
|
||||
LongLiveTokenOut,
|
||||
ResetPassword,
|
||||
UserBase,
|
||||
UserFavorites,
|
||||
UserIn,
|
||||
UserOut,
|
||||
} from "~/types/api-types/user";
|
||||
|
||||
const prefix = "/api";
|
||||
|
||||
@ -32,7 +42,7 @@ export class UserApi extends BaseCRUDAPI<UserIn, UserOut, UserBase> {
|
||||
}
|
||||
|
||||
async getFavorites(id: string) {
|
||||
await this.requests.get(routes.usersIdFavorites(id));
|
||||
return await this.requests.get<UserFavorites>(routes.usersIdFavorites(id));
|
||||
}
|
||||
|
||||
async changePassword(id: string, changePassword: ChangePassword) {
|
||||
|
@ -14,6 +14,17 @@
|
||||
</v-icon>
|
||||
{{ $vuetify.breakpoint.xsOnly ? null : $t("general.random") }}
|
||||
</v-btn>
|
||||
<ContextMenu
|
||||
v-if="!$vuetify.breakpoint.xsOnly"
|
||||
:items="[
|
||||
{
|
||||
title: 'Toggle View',
|
||||
icon: $globals.icons.eye,
|
||||
event: 'toggle-dense-view',
|
||||
},
|
||||
]"
|
||||
@toggle-dense-view="mobileCards = !mobileCards"
|
||||
/>
|
||||
<v-menu v-if="$listeners.sort" offset-y left>
|
||||
<template #activator="{ on, attrs }">
|
||||
<v-btn text :icon="$vuetify.breakpoint.xsOnly" v-bind="attrs" :loading="sortLoading" v-on="on">
|
||||
@ -103,11 +114,11 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, reactive, toRefs, useContext, useRouter } from "@nuxtjs/composition-api";
|
||||
import { computed, defineComponent, reactive, toRefs, useContext, useRouter, ref } from "@nuxtjs/composition-api";
|
||||
import RecipeCard from "./RecipeCard.vue";
|
||||
import RecipeCardMobile from "./RecipeCardMobile.vue";
|
||||
import { useSorter } from "~/composables/recipes";
|
||||
import {Recipe} from "~/types/api-types/recipe";
|
||||
import { Recipe } from "~/types/api-types/recipe";
|
||||
|
||||
const SORT_EVENT = "sort";
|
||||
|
||||
@ -129,10 +140,6 @@ export default defineComponent({
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
mobileCards: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
singleColumn: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
@ -143,6 +150,7 @@ export default defineComponent({
|
||||
},
|
||||
},
|
||||
setup(props, context) {
|
||||
const mobileCards = ref(false);
|
||||
const utils = useSorter();
|
||||
|
||||
const EVENTS = {
|
||||
@ -155,7 +163,7 @@ export default defineComponent({
|
||||
|
||||
const { $globals, $vuetify } = useContext();
|
||||
const viewScale = computed(() => {
|
||||
return props.mobileCards || $vuetify.breakpoint.smAndDown;
|
||||
return mobileCards.value || $vuetify.breakpoint.smAndDown;
|
||||
});
|
||||
|
||||
const displayTitleIcon = computed(() => {
|
||||
@ -164,7 +172,7 @@ export default defineComponent({
|
||||
|
||||
const state = reactive({
|
||||
sortLoading: false,
|
||||
})
|
||||
});
|
||||
|
||||
const router = useRouter();
|
||||
function navigateRandom() {
|
||||
@ -204,6 +212,7 @@ export default defineComponent({
|
||||
}
|
||||
|
||||
return {
|
||||
mobileCards,
|
||||
...toRefs(state),
|
||||
EVENTS,
|
||||
viewScale,
|
||||
|
@ -7,7 +7,9 @@
|
||||
|
||||
<v-list-item-content>
|
||||
<v-list-item-title> {{ $auth.user.fullName }}</v-list-item-title>
|
||||
<v-list-item-subtitle> {{ $auth.user.admin ? $t("user.admin") : $t("user.user") }}</v-list-item-subtitle>
|
||||
<v-list-item-subtitle>
|
||||
<NuxtLink class="favorites-link" :to="`/user/${$auth.user.id}/favorites`"> Favorite Recipes </NuxtLink>
|
||||
</v-list-item-subtitle>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
<v-divider></v-divider>
|
||||
@ -200,4 +202,12 @@ export default defineComponent({
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.favorites-link {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.favorites-link:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
</style>
|
||||
|
@ -1,13 +1,32 @@
|
||||
<template>
|
||||
<div></div>
|
||||
<v-container>
|
||||
<RecipeCardSection v-if="user" :icon="$globals.icons.heart" title="User Favorites" :recipes="user.favoriteRecipes">
|
||||
</RecipeCardSection>
|
||||
</v-container>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from "@nuxtjs/composition-api";
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, useAsync, useRoute } from "@nuxtjs/composition-api";
|
||||
import RecipeCardSection from "~/components/Domain/Recipe/RecipeCardSection.vue";
|
||||
import { useUserApi } from "~/composables/api";
|
||||
import { useAsyncKey } from "~/composables/use-utils";
|
||||
|
||||
export default defineComponent({
|
||||
components: { RecipeCardSection },
|
||||
setup() {
|
||||
return {};
|
||||
const api = useUserApi();
|
||||
const route = useRoute();
|
||||
|
||||
const userId = route.value.params.id;
|
||||
|
||||
const user = useAsync(async () => {
|
||||
const { data } = await api.users.getFavorites(userId);
|
||||
return data;
|
||||
}, useAsyncKey());
|
||||
|
||||
return {
|
||||
user,
|
||||
};
|
||||
},
|
||||
head() {
|
||||
return {
|
||||
@ -16,6 +35,5 @@ export default defineComponent({
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
</style>
|
||||
|
||||
<style scoped></style>
|
||||
|
Loading…
x
Reference in New Issue
Block a user