71 lines
2.6 KiB
TypeScript
71 lines
2.6 KiB
TypeScript
import { z } from "zod";
|
|
import { MEAL_LOG_SOURCES, MEAL_TYPES } from "@app/shared-types";
|
|
import { dateStringSchema, quantitySchema, unitSchema, uuidSchema } from "./common.js";
|
|
|
|
const nutritionValuesInputSchema = z.object({
|
|
kcal: z.number().min(0).max(20000),
|
|
proteinG: z.number().min(0).max(1000).default(0),
|
|
carbsG: z.number().min(0).max(2000).default(0),
|
|
fatG: z.number().min(0).max(1000).default(0),
|
|
saturatedFatG: z.number().min(0).max(500).default(0),
|
|
fiberG: z.number().min(0).max(300).default(0),
|
|
sugarG: z.number().min(0).max(1000).default(0),
|
|
saltG: z.number().min(0).max(100).default(0),
|
|
});
|
|
|
|
/**
|
|
* Måltidsloggning (spec §23). Näringsvärden får ALDRIG hittas på av AI:
|
|
* de kommer från recept (deterministiskt), produkt/streckkod, eller
|
|
* användarens egen inmatning. Tallriksfoto ger intervall som användaren bekräftar.
|
|
*/
|
|
export const logMealInputSchema = z.object({
|
|
date: dateStringSchema,
|
|
mealType: z.enum(MEAL_TYPES),
|
|
source: z.enum(MEAL_LOG_SOURCES),
|
|
titleSv: z.string().min(1).max(150),
|
|
recipeId: uuidSchema.optional(),
|
|
mealBoxId: uuidSchema.optional(),
|
|
scanJobId: uuidSchema.optional(),
|
|
portionFraction: z.number().min(0.1).max(5).default(1),
|
|
/** Vid produkt/fritext: ange mängd + per-100-värden eller direkta värden. */
|
|
items: z
|
|
.array(
|
|
z.object({
|
|
displayName: z.string().min(1).max(120),
|
|
canonicalIngredientId: z.string().max(80).optional(),
|
|
productId: uuidSchema.optional(),
|
|
quantity: quantitySchema.optional(),
|
|
unit: unitSchema.optional(),
|
|
nutrition: nutritionValuesInputSchema.optional(),
|
|
}),
|
|
)
|
|
.max(30)
|
|
.default([]),
|
|
/** Direkta värden när användaren själv anger, eller bekräftat foto-intervall. */
|
|
nutritionOverride: nutritionValuesInputSchema.optional(),
|
|
});
|
|
export type LogMealInput = z.infer<typeof logMealInputSchema>;
|
|
|
|
export const dayQuerySchema = z.object({
|
|
date: dateStringSchema,
|
|
});
|
|
|
|
export const createMealBoxInputSchema = z.object({
|
|
recipeId: uuidSchema.optional(),
|
|
titleSv: z.string().min(1).max(150),
|
|
portions: z.number().int().min(1).max(24),
|
|
storageLocationId: uuidSchema,
|
|
frozen: z.boolean().default(false),
|
|
cookedAt: dateStringSchema.optional(),
|
|
reservedForUserId: uuidSchema.optional(),
|
|
});
|
|
export type CreateMealBoxInput = z.infer<typeof createMealBoxInputSchema>;
|
|
|
|
export const consumeMealBoxInputSchema = z.object({
|
|
portions: z.number().int().min(1).max(24).default(1),
|
|
logAsMeal: z.boolean().default(true),
|
|
mealType: z.enum(MEAL_TYPES).default("lunch"),
|
|
date: dateStringSchema.optional(),
|
|
});
|
|
export type ConsumeMealBoxInput = z.infer<typeof consumeMealBoxInputSchema>;
|