diff --git a/src/components/Card/OverviewCard.astro b/src/components/Card/OverviewCard.astro index 8a73c9e..bd226c2 100644 --- a/src/components/Card/OverviewCard.astro +++ b/src/components/Card/OverviewCard.astro @@ -4,8 +4,7 @@ import TagRow from "./TagRow.astro" const { recipe } = Astro.props; -const headerImage = await client.collection("images").getOne(recipe.images[0]) -const image = await client.files.getRelativeURL(headerImage, headerImage.image) +const image = (await client.getRecipeImages(recipe.id))[0] ---
@@ -19,7 +18,7 @@ const image = await client.files.getRelativeURL(headerImage, headerImage.image)
- +
diff --git a/src/components/Card/TagRow.astro b/src/components/Card/TagRow.astro index af56aec..e1a644e 100644 --- a/src/components/Card/TagRow.astro +++ b/src/components/Card/TagRow.astro @@ -1,27 +1,10 @@ --- -import client from "../../data/pocketbase" - -interface Props { - tagIds: string[] -} - -const { tagIds } = Astro.props - -const tags = tagIds && tagIds.length > 0 - ? await Promise.all(tagIds.map(async (tagId: string) => { - try { - const tagData = await client.collection("tags").getOne(tagId) - return { name: tagData.name, id: tagId } - } catch (error) { - return null - } - })) - : [] +const { tags } = Astro.props ---
{ - tags.map(tag => ( + (tags ?? []).map(tag => ( getLink(img)) -) +const links = await client.getRecipeImages(recipe as string) --- diff --git a/src/components/Detail/InfoView.astro b/src/components/Detail/InfoView.astro index 2516136..4bde49e 100644 --- a/src/components/Detail/InfoView.astro +++ b/src/components/Detail/InfoView.astro @@ -26,4 +26,4 @@ const waitTime = formatTime(re.waittime) {waitTime && (

{waitTime} Wait

)} {re.rating !== 0 && (

{re.rating}

/10

)}
- \ No newline at end of file + \ No newline at end of file diff --git a/src/components/Detail/StepIngredientSideView.astro b/src/components/Detail/StepIngredientSideView.astro index b4cdc49..325890d 100644 --- a/src/components/Detail/StepIngredientSideView.astro +++ b/src/components/Detail/StepIngredientSideView.astro @@ -3,13 +3,10 @@ import client from "@/data/pocketbase"; const { ingredients, class: className } = Astro.props; -const ings = await Promise.all( - ingredients.map(async i => await client.collection("ingredients").getOne(i)) -) ---
- {ings.map(i => ( + {ingredients.map(i => (

• {i.quantity} {i.unit || " "} {i.name}

diff --git a/src/components/Detail/StepView.astro b/src/components/Detail/StepView.astro index 1860721..ef41ea5 100644 --- a/src/components/Detail/StepView.astro +++ b/src/components/Detail/StepView.astro @@ -16,7 +16,7 @@ const { steps, class: className } = Astro.props

{s.instruction}

{s.ingredients && s.ingredients.length > 0 && (
- +
)}
diff --git a/src/data/pocketbase.ts b/src/data/pocketbase.ts index bc56688..ef6d8de 100644 --- a/src/data/pocketbase.ts +++ b/src/data/pocketbase.ts @@ -1,12 +1,49 @@ -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) +class APIClient { + client: Pocketbase + + constructor() { + this.client = new Pocketbase("http://localhost:4321") + this.client.autoCancellation(false) + } + + async getRecipesPage(page: number, perPage: number = 30, options: RecordListOptions) { + return await this.client.collection(Collection.RECIPES).getList(page, perPage, options) + } + + async getAllRecipes() { + return await this.client.collection(Collection.RECIPES).getFullList({ expand: 'ingredients,tags,steps,images,steps.ingredients' }) + } + + async getRecipe(id: string) { + return await this.client.collection(Collection.RECIPES).getOne(id, { expand: 'ingredients,tags,steps,images,steps.ingredients' }) + } + + // IMAGE + async getImageURL(imgID: string, relative: boolean = true) { + const record = await this.client.collection("images").getOne(imgID) + const res = this.client.files.getURL(record, record.image) + return relative ? res.substring(21) : res + } + + async getRecipeImages(recipeID: string) { + const re = await this.getRecipe(recipeID) + const imgIDs = re.images ?? [] + + const urls = Promise.all( + imgIDs.map(img => this.getImageURL(img)) + ) + return urls + } -// Return a relative url for file instead of full path including localhost, which breaks external access -client.files.getRelativeURL = (record: { [key: string]: any; }, filename: string, queryParams?: FileOptions | undefined) => { - const res = client.files.getURL(record, filename) - return res.substring(21) } - +const client = new APIClient() export default client; \ No newline at end of file diff --git a/src/data/schema.ts b/src/data/schema.ts new file mode 100644 index 0000000..e2b49f3 --- /dev/null +++ b/src/data/schema.ts @@ -0,0 +1,55 @@ +// 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 + filename: string + url?: 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' +} diff --git a/src/pages/api/[...proxy].ts b/src/pages/api/[...proxy].ts index c831988..9574877 100644 --- a/src/pages/api/[...proxy].ts +++ b/src/pages/api/[...proxy].ts @@ -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 }) => { diff --git a/src/pages/index.astro b/src/pages/index.astro index bf1ef86..592c409 100644 --- a/src/pages/index.astro +++ b/src/pages/index.astro @@ -3,7 +3,7 @@ import PageLayout from "@/layouts/base" import client from "@/data/pocketbase" import OverviewCard from "@/components/Card/OverviewCard" -const recipies = await client.collection("recipes").getFullList() +const recipes = await client.getAllRecipes() --- @@ -11,7 +11,7 @@ const recipies = await client.collection("recipes").getFullList()
{ - recipies.map(r => ( + recipes.map(r => ( )) } diff --git a/src/pages/recipe/[recipeid].astro b/src/pages/recipe/[recipeid].astro index d123a91..d5ce764 100644 --- a/src/pages/recipe/[recipeid].astro +++ b/src/pages/recipe/[recipeid].astro @@ -1,5 +1,6 @@ --- import client from "@/data/pocketbase"; + import SiteLayout from "@/layouts/base"; import ImageCarousel from "@/components/Detail/ImageCarousel"; import IngredientTableView from "@/components/Detail/IngredientTableView"; @@ -8,41 +9,25 @@ 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 client.getRecipe(recipeid as string) ---
- +

{re.name}

Ingredients

- +
- +