add error handling

This commit is contained in:
Ruidy 2024-12-11 18:34:41 +01:00
parent 7c3bfb0ea8
commit f19874e4c7
No known key found for this signature in database
GPG key ID: E00F51288CB857CC
8 changed files with 147 additions and 42 deletions

View file

@ -29,45 +29,45 @@ Free meal planner for cooks short on ideas! (like me …)
- Search by name: you look for a recipe? Ours are easy to make and Yummy! ✓
- What's in the fridge ? Choose your main ingredient and get a meal suggestion
- Choose by a category: ✓
- Beef
- Breakfast
- Chicken
- Dessert
- Goat
- Lamb
- Miscellaneous
- Pasta
- Pork
- Seafood
- Side
- Starter
- Vegan
- Vegetarian
- Beef
- Breakfast
- Chicken
- Dessert
- Goat
- Lamb
- Miscellaneous
- Pasta
- Pork
- Seafood
- Side
- Starter
- Vegan
- Vegetarian
- Choose by area:
- American
- British
- Canadian
- Chinese
- Dutch
- Egyptian
- French
- Greek
- Indian
- Irish
- Italian
- Jamaican
- Japanese
- Kenyan
- Malaysian
- Mexican
- Moroccan
- Russian
- Spanish
- Thai
- Tunisian
- Turkish
- Unknown
- Vietnamese
- American
- British
- Canadian
- Chinese
- Dutch
- Egyptian
- French
- Greek
- Indian
- Irish
- Italian
- Jamaican
- Japanese
- Kenyan
- Malaysian
- Mexican
- Moroccan
- Russian
- Spanish
- Thai
- Tunisian
- Turkish
- Unknown
- Vietnamese
- Cocktail selection
- Create a profile and save your favourite meals ✓
- Notation system: know what are the most loved meals

View file

@ -7,7 +7,12 @@
- [x] deploy
- [x] nuxt image
- [x] prettier and eslint
- [ ] transition
- [ ] transition and loading times
- [ ] pwa
- [ ] seo, robots.txt
- [x] update the README
- [ ] create image provider
- [ ] fetch recipe per id
- [ ] add mood section
- [ ] store recipes into my db (SQLite)
- [ ] process them using AI

13
app.vue
View file

@ -7,3 +7,16 @@
<AppFooter />
</div>
</template>
<style>
.page-enter-active,
.page-leave-active {
transition: all 0.4s;
}
.page-enter-from,
.page-leave-to {
opacity: 0;
filter: blur(1rem);
}
</style>

BIN
bun.lockb

Binary file not shown.

58
error.vue Normal file
View file

@ -0,0 +1,58 @@
<template>
<div class="min-h-screen flex items-center justify-center bg-base-200">
<div class="text-center max-w-md p-8">
<div class="card bg-base-100 shadow-xl">
<div class="card-body">
<!-- Error Icon -->
<div class="text-error text-6xl mb-4">
<svg
xmlns="http://www.w3.org/2000/svg"
class="mx-auto h-24 w-24"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"
/>
</svg>
</div>
<!-- Error Details -->
<h1 class="text-4xl font-bold mb-4">
{{ error?.statusCode || "Error" }}
</h1>
<p class="text-xl mb-6">
{{ error?.message || "Something went wrong" }}
</p>
<!-- Action Buttons -->
<div class="flex justify-center gap-4">
<button class="btn btn-primary" @click="handleError">
Try Again
</button>
<button class="btn btn-ghost" @click="navigateToHome">
Go Home
</button>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
const error = useError();
const route = useRoute();
const handleError = () => {
clearError({ redirect: route.redirectedFrom?.fullPath ?? "/" });
};
const navigateToHome = () => {
clearError({ redirect: "/" });
};
</script>

View file

@ -1,6 +1,17 @@
<script setup lang="ts">
import { idSchema } from "~/types/id";
const { params } = useRoute();
const id = params.id;
const routeParam = params.id;
const parsed = idSchema.safeParse(routeParam);
if (!parsed.success) {
throw createError({
statusCode: 400,
statusMessage: "Invalid recipe id",
});
}
const {
data: recipe,

View file

@ -1,12 +1,22 @@
import { parseRecipeData } from "~/utils/recipes";
import type { Meal } from "~/types/recipe";
import { idSchema } from "~/types/id";
export default defineEventHandler(async (event) => {
const { apiUrl } = useRuntimeConfig();
const id = getRouterParam(event, "id");
const routeParam = getRouterParam(event, "id");
const parsed = idSchema.safeParse(routeParam);
if (!parsed.success) {
throw createError({
statusCode: 400,
statusMessage: "Invalid recipe id",
message: parsed.error.message,
});
}
const data = await $fetch<{ meals: Meal[] }>(
new URL(`lookup.php?i=${id}`, apiUrl).toString(),
new URL(`lookup.php?i=${parsed.data}`, apiUrl).toString(),
);
if (!data?.meals) {
throw createError({

8
types/id.ts Normal file
View file

@ -0,0 +1,8 @@
import { z } from "zod";
export const idSchema = z
.number({
required_error: "recipe id is required",
invalid_type_error: "recipe id must be a number",
})
.positive("recipe id must be positive");