Files
famapp/src/modules/garden/server/share-queries.ts
T
ginnoir f3e38c576c feat: garden plants crud (task 72)
- perenual species lookup with 24h db cache (api key optional)
- /api/garden/species-search route handler
- createPlant / updatePlant / deletePlant server actions
- addPlantImage / removePlantImage / setPrimaryImage actions (max 10)
- listPlants query grouped by container with last-watered subquery
- getPlant query with care log summary and active schedules
- plant-form client component with species autofill and image upload
- plant-list server component grouped by container with unassigned bucket
- plant-detail client component with info/gallery/care tabs
- species-search debounced combobox component
- /garden/plants/new, /[id], /[id]/edit pages
- garden.plant entity registered with search and share support
- /garden page updated to containers/plants tabs (default: containers)
2026-06-01 20:13:20 -05:00

80 lines
2.1 KiB
TypeScript

import { and, eq } from "drizzle-orm";
import { db } from "@/lib/db";
import { gardenContainers, gardenPlants } from "../schema";
export type ContainerShareData = {
id: string;
name: string;
type: string;
locationNotes: string | null;
coverImageUrl: string | null;
plants: { id: string; name: string; scientificName: string | null }[];
};
export type PlantShareData = {
id: string;
name: string;
scientificName: string | null;
primaryImageUrl: string | null;
images: string[];
healthStatus: string;
growthStage: string | null;
category: string;
wateringNotes: string | null;
fertilizingNotes: string | null;
notes: string | null;
sunlight: string | null;
};
export async function loadPlantForShare(id: string): Promise<PlantShareData | null> {
const [plant] = await db
.select({
id: gardenPlants.id,
name: gardenPlants.name,
scientificName: gardenPlants.scientificName,
primaryImageUrl: gardenPlants.primaryImageUrl,
images: gardenPlants.images,
healthStatus: gardenPlants.healthStatus,
growthStage: gardenPlants.growthStage,
category: gardenPlants.category,
wateringNotes: gardenPlants.wateringNotes,
fertilizingNotes: gardenPlants.fertilizingNotes,
notes: gardenPlants.notes,
sunlight: gardenPlants.sunlight,
})
.from(gardenPlants)
.where(eq(gardenPlants.id, id))
.limit(1);
if (!plant) return null;
return plant;
}
export async function loadContainerForShare(id: string): Promise<ContainerShareData | null> {
const [container] = await db
.select()
.from(gardenContainers)
.where(eq(gardenContainers.id, id))
.limit(1);
if (!container) return null;
const plants = await db
.select({
id: gardenPlants.id,
name: gardenPlants.name,
scientificName: gardenPlants.scientificName,
})
.from(gardenPlants)
.where(and(eq(gardenPlants.containerId, id)));
return {
id: container.id,
name: container.name,
type: container.type,
locationNotes: container.locationNotes,
coverImageUrl: container.coverImageUrl,
plants,
};
}