diff --git a/src/admin/lib/queries/plan.ts b/src/admin/lib/queries/plan.ts index 1958f61..068f419 100644 --- a/src/admin/lib/queries/plan.ts +++ b/src/admin/lib/queries/plan.ts @@ -29,6 +29,30 @@ export interface ResolvedCell { rangeTo: string | null; } +export interface PlanCategory { + id: number; + key: string; + label: string; + color: string; + sort_order: number; + is_active: boolean; +} + +export const planCategoriesOptions = () => + queryOptions({ + queryKey: ["plan", "categories"], + queryFn: () => jsonQuery("/api/admin/plan/categories"), + }); + +/** Build a key → category lookup from the categories list. */ +export function categoryMap( + categories: PlanCategory[] | undefined, +): Record { + const map: Record = {}; + for (const c of categories ?? []) map[c.key] = c; + return map; +} + /** Czech labels for the plan_category enum — single source of truth shared * by the grid chips, the detail view, and aria-labels. */ export const PLAN_CATEGORIES: ReadonlyArray<{ value: string; label: string }> = @@ -42,13 +66,14 @@ export const PLAN_CATEGORIES: ReadonlyArray<{ value: string; label: string }> = { value: "other", label: "Jiné" }, ]; -const PLAN_CATEGORY_LABELS: Record = Object.fromEntries( - PLAN_CATEGORIES.map((c) => [c.value, c.label]), -); - -/** Czech label for a plan category, falling back to the raw value. */ -export function planCategoryLabel(value: string): string { - return PLAN_CATEGORY_LABELS[value] ?? value; +/** Czech label for a plan category key, resolved from the loaded categories + * map, falling back to the raw key. The `map` arg is optional so callers not + * yet threading categories still compile (they show the raw key until wired). */ +export function planCategoryLabel( + key: string, + map?: Record, +): string { + return map?.[key]?.label ?? key; } /** Build the display label for a cell's project, preferring the server-