95 lines
3.9 KiB
TypeScript
95 lines
3.9 KiB
TypeScript
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>;
|