added categories for dish and ingredient

This commit is contained in:
taogaetz 2025-12-03 14:01:37 -05:00
parent f241b06336
commit 1c0ce2d741
8 changed files with 150 additions and 0 deletions

View File

@ -0,0 +1,21 @@
-- RedefineTables
PRAGMA defer_foreign_keys=ON;
PRAGMA foreign_keys=OFF;
CREATE TABLE "new_Recipe" (
"id" TEXT NOT NULL PRIMARY KEY,
"name" TEXT NOT NULL,
"description" TEXT,
"instructions" TEXT,
"photoUrl" TEXT,
"time" TEXT NOT NULL DEFAULT 'Medium',
"station" TEXT NOT NULL DEFAULT 'Pans',
"type" TEXT NOT NULL DEFAULT 'Dish',
"hidden" BOOLEAN NOT NULL DEFAULT false,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL
);
INSERT INTO "new_Recipe" ("createdAt", "description", "hidden", "id", "instructions", "name", "photoUrl", "station", "time", "updatedAt") SELECT "createdAt", "description", "hidden", "id", "instructions", "name", "photoUrl", "station", "time", "updatedAt" FROM "Recipe";
DROP TABLE "Recipe";
ALTER TABLE "new_Recipe" RENAME TO "Recipe";
PRAGMA foreign_keys=ON;
PRAGMA defer_foreign_keys=OFF;

View File

@ -25,6 +25,7 @@ model Recipe {
photoUrl String?
time String @default("Medium") // Quick, Medium, Long
station String @default("Pans") // Garde Manger, Pans, Grill
type String @default("Dish") // Ingredient or Dish
hidden Boolean @default(false) // Hidden from non-chefs
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt

View File

@ -0,0 +1,29 @@
import type { PageServerLoad } from './$types';
import prisma from '$lib/server/prisma';
export const load: PageServerLoad = async ({ locals }) => {
// Get dish recipes only
// If not authenticated, filter out hidden recipes
const recipes = await prisma.recipe.findMany({
where: {
type: 'Dish',
...(locals.authenticated ? {} : { hidden: false })
},
include: {
ingredients: {
include: {
ingredient: true
}
}
},
orderBy: {
createdAt: 'desc'
}
});
return {
recipes,
authenticated: locals.authenticated,
hasAccess: locals.hasAccess
};
};

View File

@ -0,0 +1,33 @@
<script lang="ts">
import type { PageProps } from './$types';
import RecipeCard from '$lib/components/RecipeCard.svelte';
let { data }: PageProps = $props();
</script>
<svelte:head>
<title>Dishes - Chef Bible</title>
<meta name="description" content="Dish recipes" />
</svelte:head>
<main class="m-0 min-h-screen bg-gradient-to-br from-base-200 to-base-300 p-0">
<section class="mx-auto max-w-7xl p-10 lg:p-6">
<div class="mb-4">
<h1 class="text-sm text-base-content/60">
<a href="/" class="hover:underline">Home</a> / Dishes
</h1>
</div>
<div class="grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
{#each data.recipes as recipe}
<RecipeCard {recipe} authenticated={data.authenticated} />
{/each}
</div>
{#if data.recipes.length === 0}
<div class="mt-12 text-center">
<p class="text-base-content/60">No dish recipes found.</p>
</div>
{/if}
</section>
</main>

View File

@ -0,0 +1,29 @@
import type { PageServerLoad } from './$types';
import prisma from '$lib/server/prisma';
export const load: PageServerLoad = async ({ locals }) => {
// Get ingredient recipes only
// If not authenticated, filter out hidden recipes
const recipes = await prisma.recipe.findMany({
where: {
type: 'Ingredient',
...(locals.authenticated ? {} : { hidden: false })
},
include: {
ingredients: {
include: {
ingredient: true
}
}
},
orderBy: {
createdAt: 'desc'
}
});
return {
recipes,
authenticated: locals.authenticated,
hasAccess: locals.hasAccess
};
};

View File

@ -0,0 +1,33 @@
<script lang="ts">
import type { PageProps } from './$types';
import RecipeCard from '$lib/components/RecipeCard.svelte';
let { data }: PageProps = $props();
</script>
<svelte:head>
<title>Ingredients - Chef Bible</title>
<meta name="description" content="Ingredient recipes" />
</svelte:head>
<main class="m-0 min-h-screen bg-gradient-to-br from-base-200 to-base-300 p-0">
<section class="mx-auto max-w-7xl p-10 lg:p-6">
<div class="mb-4">
<h1 class="text-sm text-base-content/60">
<a href="/" class="hover:underline">Home</a> / Ingredients
</h1>
</div>
<div class="grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
{#each data.recipes as recipe}
<RecipeCard {recipe} authenticated={data.authenticated} />
{/each}
</div>
{#if data.recipes.length === 0}
<div class="mt-12 text-center">
<p class="text-base-content/60">No ingredient recipes found.</p>
</div>
{/if}
</section>
</main>

View File

@ -24,6 +24,7 @@ export const POST: RequestHandler = async ({ request, params }) => {
const instructions = (formData.get('instructions') as string | null)?.trim() || null;
const time = ((formData.get('time') as string | null)?.trim() || 'Medium') as string;
const station = ((formData.get('station') as string | null)?.trim() || 'Pans') as string;
const type = ((formData.get('type') as string | null)?.trim() || 'Dish') as string;
const hidden = formData.get('hidden') === 'on'; // Checkbox returns 'on' when checked
const photo = formData.get('photo') as File | null;
const parsedIngredientsRaw = formData.get('parsedIngredients') as string | null;
@ -101,6 +102,7 @@ export const POST: RequestHandler = async ({ request, params }) => {
photoUrl: photoUrl || existingRecipe.photoUrl, // Keep existing photo if no new one uploaded
time,
station,
type,
hidden
}
});

View File

@ -24,6 +24,7 @@ export const POST: RequestHandler = async ({ request }) => {
const instructions = (formData.get('instructions') as string | null)?.trim() || null;
const time = ((formData.get('time') as string | null)?.trim() || 'Medium') as string;
const station = ((formData.get('station') as string | null)?.trim() || 'Pans') as string;
const type = ((formData.get('type') as string | null)?.trim() || 'Dish') as string;
const hidden = formData.get('hidden') === 'on'; // Checkbox returns 'on' when checked
const photo = formData.get('photo') as File | null;
const parsedIngredientsRaw = formData.get('parsedIngredients') as string | null;
@ -91,6 +92,7 @@ export const POST: RequestHandler = async ({ request }) => {
photoUrl,
time,
station,
type,
hidden
}
});