mirror of
https://github.com/rjNemo/meal_planner
synced 2026-06-06 02:26:49 +00:00
feat: Add categories page with category card and data fetching
This commit is contained in:
parent
2872907a98
commit
e042e06b19
6 changed files with 83 additions and 32 deletions
30
components/CategoryCard.vue
Normal file
30
components/CategoryCard.vue
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
<template>
|
||||||
|
<NuxtLink
|
||||||
|
:to="`/category/${category.strCategory}`"
|
||||||
|
class="block max-w-sm rounded-lg border border-gray-200 bg-white p-6 shadow hover:bg-gray-100 dark:border-gray-700 dark:bg-gray-800 dark:hover:bg-gray-700"
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
:src="category.strCategoryThumb"
|
||||||
|
:alt="category.strCategory"
|
||||||
|
class="mb-4 h-48 w-full object-cover rounded"
|
||||||
|
/>
|
||||||
|
<h5 class="mb-2 text-2xl font-bold tracking-tight text-gray-900 dark:text-white">
|
||||||
|
{{ category.strCategory }}
|
||||||
|
</h5>
|
||||||
|
<p class="font-normal text-gray-700 dark:text-gray-400">
|
||||||
|
{{ category.strCategoryDescription }}
|
||||||
|
</p>
|
||||||
|
</NuxtLink>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
interface Category {
|
||||||
|
strCategory: string
|
||||||
|
strCategoryThumb: string
|
||||||
|
strCategoryDescription: string
|
||||||
|
}
|
||||||
|
|
||||||
|
defineProps<{
|
||||||
|
category: Category
|
||||||
|
}>()
|
||||||
|
</script>
|
||||||
4
composables/useCategories.ts
Normal file
4
composables/useCategories.ts
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
export function useCategories() {
|
||||||
|
const { $client } = useNuxtApp();
|
||||||
|
return $client.listCategories.useQuery();
|
||||||
|
}
|
||||||
19
pages/categories.vue
Normal file
19
pages/categories.vue
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
const { data: categories, status } = useCategories();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="container mx-auto px-4">
|
||||||
|
<h1 class="text-4xl font-bold mb-8 text-center">Recipe Categories</h1>
|
||||||
|
|
||||||
|
<div v-if="status === 'pending'" class="text-center">Loading...</div>
|
||||||
|
|
||||||
|
<div v-else class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||||
|
<category-card
|
||||||
|
v-for="category in categories"
|
||||||
|
:key="category.strCategory"
|
||||||
|
:category="category"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
27
server/trpc/routers/categories.ts
Normal file
27
server/trpc/routers/categories.ts
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
import { publicProcedure, router } from "../trpc";
|
||||||
|
|
||||||
|
const { apiUrl } = useRuntimeConfig();
|
||||||
|
|
||||||
|
type Category = {
|
||||||
|
idCategory: string;
|
||||||
|
strCategory: string;
|
||||||
|
strCategoryThumb: string;
|
||||||
|
strCategoryDescription: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const categoryRouter = router({
|
||||||
|
listCategories: publicProcedure.query(async () => {
|
||||||
|
const data = await $fetch<{ categories: Category[] }>(
|
||||||
|
new URL("categories.php", apiUrl).toString(),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!data?.categories) {
|
||||||
|
throw createError({
|
||||||
|
statusCode: 500,
|
||||||
|
statusMessage: "Failed to fetch categories",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return data.categories;
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
@ -1,24 +1,9 @@
|
||||||
import type { inferRouterOutputs } from "@trpc/server";
|
import type { inferRouterOutputs } from "@trpc/server";
|
||||||
import { z } from "zod";
|
import { mergeRouters } from "../trpc";
|
||||||
import { privateProcedure, router, mergeRouters } from "../trpc";
|
|
||||||
import { recipeRouter } from "./recipes";
|
import { recipeRouter } from "./recipes";
|
||||||
|
import { categoryRouter } from "./categories";
|
||||||
|
|
||||||
export const helloRouter = router({
|
export const appRouter = mergeRouters(categoryRouter, recipeRouter);
|
||||||
// hello: publicProcedure
|
|
||||||
hello: privateProcedure
|
|
||||||
.input(
|
|
||||||
z.object({
|
|
||||||
text: z.string().nullish(),
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
.query(({ input }) => {
|
|
||||||
return {
|
|
||||||
greeting: `hello ${input?.text ?? "world"}`,
|
|
||||||
};
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
export const appRouter = mergeRouters(helloRouter, recipeRouter);
|
|
||||||
// export type definition of API
|
// export type definition of API
|
||||||
export type AppRouter = typeof appRouter;
|
export type AppRouter = typeof appRouter;
|
||||||
export type RouterOutput = inferRouterOutputs<AppRouter>;
|
export type RouterOutput = inferRouterOutputs<AppRouter>;
|
||||||
|
|
|
||||||
|
|
@ -65,18 +65,4 @@ export const recipeRouter = router({
|
||||||
const recipes = parseRecipeData(data);
|
const recipes = parseRecipeData(data);
|
||||||
return recipes;
|
return recipes;
|
||||||
}),
|
}),
|
||||||
categories: publicProcedure.query(async () => {
|
|
||||||
const data = await $fetch<{ categories: Category[] }>(
|
|
||||||
new URL("categories.php", apiUrl).toString(),
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!data?.categories) {
|
|
||||||
throw createError({
|
|
||||||
statusCode: 500,
|
|
||||||
statusMessage: "Failed to fetch categories",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return data.categories;
|
|
||||||
}),
|
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue