Files
Cibello-app/packages/validation/src/profile.ts
T

95 lines
3.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { z } from "zod";
import {
ACTIVITY_LEVELS,
ALLERGENS,
CONSENT_KINDS,
CUISINES,
DIET_PATTERNS,
EQUIPMENT,
GOAL_TYPES,
PRECISION_MODES,
RELIGIOUS_RULES,
SEXES,
} from "@app/shared-types";
/** Hälsoprofil hanteras separat från hushållsdata (spec §7, §56). */
export const updateHealthProfileInputSchema = z.object({
birthYear: z.number().int().min(1900).max(2030).optional(),
sex: z.enum(SEXES).optional(),
heightCm: z.number().min(80).max(250).optional(),
weightKg: z.number().min(20).max(400).optional(),
targetWeightKg: z.number().min(20).max(400).optional(),
activityLevel: z.enum(ACTIVITY_LEVELS).optional(),
trainingSessionsPerWeek: z.number().int().min(0).max(21).optional(),
trainingTypes: z.array(z.string().max(50)).max(10).optional(),
});
export type UpdateHealthProfileInput = z.infer<typeof updateHealthProfileInputSchema>;
export const updatePreferencesInputSchema = z.object({
primaryGoal: z.enum(GOAL_TYPES).optional(),
goals: z.array(z.enum(GOAL_TYPES)).max(11).optional(),
dietPattern: z.enum(DIET_PATTERNS).optional(),
religiousRule: z.enum(RELIGIOUS_RULES).optional(),
allergens: z.array(z.enum(ALLERGENS)).optional(),
intolerances: z.array(z.string().max(60)).max(30).optional(),
avoidIngredientIds: z.array(z.string().max(80)).max(100).optional(),
favoriteCuisines: z.array(z.enum(CUISINES)).max(19).optional(),
dislikedDishes: z.array(z.string().max(80)).max(50).optional(),
spiceLevelMax: z.number().int().min(0).max(5).optional(),
weeklyBudgetMinor: z.number().int().min(0).max(10_000_000).nullable().optional(),
maxCookingMinutesWeekday: z.number().int().min(5).max(360).nullable().optional(),
equipment: z.array(z.enum(EQUIPMENT)).optional(),
defaultPortions: z.number().int().min(1).max(20).optional(),
});
export type UpdatePreferencesInput = z.infer<typeof updatePreferencesInputSchema>;
export const updateMeInputSchema = z.object({
displayName: z.string().min(1).max(80).trim().optional(),
locale: z.string().min(2).max(10).optional(),
precisionMode: z.enum(PRECISION_MODES).optional(),
});
export type UpdateMeInput = z.infer<typeof updateMeInputSchema>;
export const consentInputSchema = z.object({
kind: z.enum(CONSENT_KINDS),
granted: z.boolean(),
});
export type ConsentInput = z.infer<typeof consentInputSchema>;
/** Onboarding i ett svep (spec §6): allt är valfritt utom visningsnamnet som redan finns. */
export const onboardingInputSchema = z.object({
healthProfile: updateHealthProfileInputSchema.optional(),
preferences: updatePreferencesInputSchema.optional(),
precisionMode: z.enum(PRECISION_MODES).default("simple"),
householdChoice: z
.discriminatedUnion("kind", [
z.object({ kind: z.literal("create"), name: z.string().min(1).max(80) }),
z.object({ kind: z.literal("join"), inviteCode: z.string().min(4).max(20) }),
z.object({ kind: z.literal("skip") }),
])
.default({ kind: "skip" }),
});
export type OnboardingInput = z.infer<typeof onboardingInputSchema>;
/** Progressive onboarding Step A minimal info for immediate value (FAS 1b). */
export const quickStartInputSchema = z.object({
// Backwards-compatible single goal; if `goals` is omitted we fall back to this.
primaryGoal: z.enum(GOAL_TYPES).optional(),
// Multi-select goals (new UI). First goal is considered primary.
goals: z.array(z.enum(GOAL_TYPES)).max(11).optional(),
// Household size for the auto-created household (default 1 if omitted).
persons: z.coerce.number().int().min(1).max(50).optional(),
precisionMode: z.enum(PRECISION_MODES).default("simple"),
});
export type QuickStartInput = z.infer<typeof quickStartInputSchema>;
/** Progressive onboarding status response (FAS 1b). */
export const onboardingStatusSchema = z.object({
step: z.enum(["a", "b", "c"]),
onboardingCompleted: z.boolean(),
hasHousehold: z.boolean(),
hasHealthProfile: z.boolean(),
hasPreferences: z.boolean(),
});
export type OnboardingStatus = z.infer<typeof onboardingStatusSchema>;