mirror of
https://github.com/rjNemo/meal_planner
synced 2026-06-06 02:26:49 +00:00
add error handling
This commit is contained in:
parent
7c3bfb0ea8
commit
f19874e4c7
8 changed files with 147 additions and 42 deletions
76
README.md
76
README.md
|
|
@ -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
|
||||
|
|
|
|||
7
TODO.md
7
TODO.md
|
|
@ -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
13
app.vue
|
|
@ -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
BIN
bun.lockb
Binary file not shown.
58
error.vue
Normal file
58
error.vue
Normal 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>
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
8
types/id.ts
Normal 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");
|
||||
Loading…
Reference in a new issue