Compare commits

..

5 Commits

Author SHA1 Message Date
b514655b5c progressively updating to use api 2025-08-16 12:22:10 +12:00
b3f92210fa Proxy forwards Query parameters too 2025-08-16 11:01:56 +12:00
2e54690ee4 Starting basic API client 2025-08-15 19:01:47 +12:00
f7e24657f5 Initial schema creation 2025-08-15 18:02:13 +12:00
0b1334d508 [PIE-13] New recipe page (!11)
Add `/recipe/new` path with form to add new recipe
Mostly designed but not fully: steps and ingredients are inputtable with final styling but it cannot be submitted yet, and other crucial components like description, rating, etc are not yet implemented.
Many design changes too cos i couldnt help myself

More additions will certainly be required but this PR is huge so I will split it out into more
Reviewed-on: #11
Co-authored-by: june <self@breadone.net>
Co-committed-by: june <self@breadone.net>
2025-08-15 16:12:02 +12:00
4 changed files with 91 additions and 24 deletions

View File

@@ -1,4 +1,11 @@
import Pocketbase from "pocketbase"
import Pocketbase, { type RecordListOptions } from "pocketbase"
import {
type Recipe,
type Ingredient,
type Step,
type Tag,
Collection
} from './schema'
const client = new Pocketbase("http://localhost:4321")
client.autoCancellation(false)
@@ -10,3 +17,26 @@ client.files.getRelativeURL = (record: { [key: string]: any; }, filename: string
}
export default client;
class APIClient {
client: Pocketbase
constructor() {
this.client = new Pocketbase("http://localhost:4321")
this.client.autoCancellation(false)
}
async getRecipesPaginated(page: number, perPage: number = 30, options: RecordListOptions) {
return await this.client.collection<Recipe>(Collection.RECIPES).getList(page, perPage, options)
}
async getAllRecipes() {
return await this.client.collection<Recipe>(Collection.RECIPES).getFullList({ expand: "steps,ingredients,tags" })
}
async getRecipe(id: string) {
return await this.client.collection<Recipe>(Collection.RECIPES).getOne(id, { expand: 'ingredients,tags,steps' })
}
}
export const client2 = new APIClient()

53
src/data/schema.ts Normal file
View File

@@ -0,0 +1,53 @@
// Base PB type
export interface BaseRecord {
id: string,
created: string,
updated: string
}
export interface Ingredient extends BaseRecord {
quantity: string,
unit: string,
name: string
}
export interface Step extends BaseRecord {
index: number,
instruction: string,
ingredients?: Ingredient[]
}
export interface Tag extends BaseRecord {
name: string
}
// not sure Image is the best type cos it might be quite heavy to get all the fields every time but
// it is here in case it is (a good idea)
export interface Image extends BaseRecord {
id: string
}
export interface Recipe extends BaseRecord {
name: string,
description?: string,
servings?: number,
images?: string[], // image IDs
ingredients: string[]
steps: string[],
tags?: string[]
expand: {
images?: Image[], // image IDs,
ingredients: Ingredient[]
steps: Step[],
tags?: Tag[]
}
}
export const Collection = {
RECIPES: 'recipes',
STEPS: 'steps',
INGREDIENTS: 'ingredients',
TAGS: 'tags',
IMAGES: 'images'
}

View File

@@ -5,8 +5,7 @@ import type { APIRoute } from "astro";
const getProxyUrl = (request: Request) => {
const proxyUrl = new URL(import.meta.env.PUBLIC_PB_URL);
const requestUrl = new URL(request.url);
return new URL(requestUrl.pathname, proxyUrl);
return new URL(requestUrl.pathname + requestUrl.search, proxyUrl);
};
export const ALL: APIRoute = async ({ request }) => {

View File

@@ -1,5 +1,6 @@
---
import client from "@/data/pocketbase";
import client, { client2 } from "@/data/pocketbase";
import SiteLayout from "@/layouts/base";
import ImageCarousel from "@/components/Detail/ImageCarousel";
import IngredientTableView from "@/components/Detail/IngredientTableView";
@@ -8,23 +9,7 @@ import InfoView from "@/components/Detail/InfoView";
const { recipeid } = Astro.params;
const re = await client.collection("recipes").getOne(recipeid ?? "0");
const stepIds = re.steps
let steps = await Promise.all(
stepIds.map(async s =>
await client.collection("steps").getOne(s)
)
)
steps = steps.sort((a, b) => a.index - b.index);
const ingredients = await Promise.all(
re.ingredients.map(async s =>
await client.collection("ingredients").getOne(s)
)
)
const re = await client2.getRecipe(recipeid as string)
---
<SiteLayout>
@@ -37,12 +22,12 @@ const ingredients = await Promise.all(
<InfoView re={re} />
<p class="text-[22pt] font-bold 'md:mt-4'">Ingredients</p>
<IngredientTableView class:list={['md:w-80', 'px-4']} ingredients={ingredients} />
<IngredientTableView class:list={['md:w-80', 'px-4']} ingredients={re.expand.ingredients} />
</div>
<div class="flex mt-4 md:flex-2/3 w-full flex-col">
<!-- Steps -->
<StepView class="md:ml-3" steps={steps} />
<StepView class="md:ml-3" steps={re.expand.steps} />
</div>
</div>