Phase 9
This commit is contained in:
parent
a1801af63b
commit
d2a7e652b3
16 changed files with 113 additions and 92 deletions
|
|
@ -8,19 +8,19 @@ describe('MealPlan Schemas', () => {
|
|||
type: MealType.DINNER,
|
||||
recipeName: 'Chicken Salad',
|
||||
servings: 2,
|
||||
perServingNutrition: { calories: 300, protein: 30, carbs: 10, fat: 15 }
|
||||
perServingNutrition: { calories: 300, protein: 30, carbs: 10, fat: 15 },
|
||||
};
|
||||
|
||||
const validDay = {
|
||||
date: '2026-05-18',
|
||||
meals: [validMeal],
|
||||
dailyNutritionTotal: { calories: 600, protein: 60, carbs: 20, fat: 30 }
|
||||
dailyNutritionTotal: { calories: 600, protein: 60, carbs: 20, fat: 30 },
|
||||
};
|
||||
|
||||
const validPlan = {
|
||||
weekStartDate: '2026-05-18',
|
||||
days: Array(7).fill(validDay),
|
||||
status: MealPlanStatus.DRAFT
|
||||
status: MealPlanStatus.DRAFT,
|
||||
};
|
||||
|
||||
it('should validate a valid meal plan', () => {
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ describe('NutritionTarget Schemas', () => {
|
|||
proteinG: 150,
|
||||
carbsG: 200,
|
||||
fatG: 70,
|
||||
isActive: true
|
||||
isActive: true,
|
||||
};
|
||||
|
||||
it('should validate a valid target', () => {
|
||||
|
|
|
|||
|
|
@ -16,15 +16,17 @@ export const CreatePriceRecordSchema = z.object({
|
|||
export const BulkPriceRecordInputSchema = z.object({
|
||||
storeId: z.string().min(1),
|
||||
date: z.iso.datetime().optional(),
|
||||
items: z.array(
|
||||
z.object({
|
||||
productId: z.string().min(1),
|
||||
price: z.number().positive(),
|
||||
quantity: z.number().positive(),
|
||||
unit: z.nativeEnum(ServingUnit),
|
||||
notes: z.string().max(1000).trim().optional(),
|
||||
})
|
||||
).min(1),
|
||||
items: z
|
||||
.array(
|
||||
z.object({
|
||||
productId: z.string().min(1),
|
||||
price: z.number().positive(),
|
||||
quantity: z.number().positive(),
|
||||
unit: z.nativeEnum(ServingUnit),
|
||||
notes: z.string().max(1000).trim().optional(),
|
||||
}),
|
||||
)
|
||||
.min(1),
|
||||
});
|
||||
|
||||
export const PriceHistoryQuerySchema = z.object({
|
||||
|
|
@ -70,7 +72,7 @@ export const PriceAnalyticsResponseSchema = z.object({
|
|||
storeName: z.string(),
|
||||
avgTotal: z.number(),
|
||||
tripCount: z.number(),
|
||||
})
|
||||
}),
|
||||
),
|
||||
priceAlerts: z.array(
|
||||
z.object({
|
||||
|
|
@ -82,20 +84,20 @@ export const PriceAnalyticsResponseSchema = z.object({
|
|||
currentPrice: z.number(),
|
||||
changePercent: z.number(),
|
||||
date: z.string(),
|
||||
})
|
||||
}),
|
||||
),
|
||||
spendingOverTime: z.array(
|
||||
z.object({
|
||||
period: z.string(),
|
||||
total: z.number(),
|
||||
})
|
||||
}),
|
||||
),
|
||||
spendingByCategory: z.array(
|
||||
z.object({
|
||||
category: z.string(),
|
||||
total: z.number(),
|
||||
avgPerItem: z.number(),
|
||||
})
|
||||
}),
|
||||
),
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -22,16 +22,19 @@ export const ShoppingItemSchema = z.object({
|
|||
export const CreateShoppingListSchema = z.object({
|
||||
name: z.string().min(1).max(100).trim(),
|
||||
preferredStoreId: z.string().optional(),
|
||||
items: z.array(
|
||||
z.object({
|
||||
productId: z.string().optional(),
|
||||
customName: z.string().optional(),
|
||||
quantity: z.number().positive(),
|
||||
unit: z.nativeEnum(ServingUnit),
|
||||
notes: z.string().optional(),
|
||||
category: z.nativeEnum(ProductCategory).optional(),
|
||||
})
|
||||
).optional().default([]),
|
||||
items: z
|
||||
.array(
|
||||
z.object({
|
||||
productId: z.string().optional(),
|
||||
customName: z.string().optional(),
|
||||
quantity: z.number().positive(),
|
||||
unit: z.nativeEnum(ServingUnit),
|
||||
notes: z.string().optional(),
|
||||
category: z.nativeEnum(ProductCategory).optional(),
|
||||
}),
|
||||
)
|
||||
.optional()
|
||||
.default([]),
|
||||
});
|
||||
|
||||
export const UpdateShoppingListSchema = z.object({
|
||||
|
|
@ -41,17 +44,18 @@ export const UpdateShoppingListSchema = z.object({
|
|||
items: z.array(ShoppingItemSchema).optional(),
|
||||
});
|
||||
|
||||
export const AddShoppingItemSchema = z.object({
|
||||
productId: z.string().optional(),
|
||||
customName: z.string().optional(),
|
||||
quantity: z.number().positive(),
|
||||
unit: z.nativeEnum(ServingUnit),
|
||||
notes: z.string().max(500).trim().optional(),
|
||||
category: z.nativeEnum(ProductCategory).optional(),
|
||||
}).refine(
|
||||
(data) => data.productId || data.customName,
|
||||
{ message: 'Must provide either a productId or customName' }
|
||||
);
|
||||
export const AddShoppingItemSchema = z
|
||||
.object({
|
||||
productId: z.string().optional(),
|
||||
customName: z.string().optional(),
|
||||
quantity: z.number().positive(),
|
||||
unit: z.nativeEnum(ServingUnit),
|
||||
notes: z.string().max(500).trim().optional(),
|
||||
category: z.nativeEnum(ProductCategory).optional(),
|
||||
})
|
||||
.refine((data) => data.productId || data.customName, {
|
||||
message: 'Must provide either a productId or customName',
|
||||
});
|
||||
|
||||
export const UpdateShoppingItemSchema = z.object({
|
||||
quantity: z.number().positive().optional(),
|
||||
|
|
@ -68,10 +72,12 @@ export const ShoppingListResponseSchema = z.object({
|
|||
name: z.string(),
|
||||
status: z.nativeEnum(ShoppingListStatus),
|
||||
items: z.array(ShoppingItemSchema),
|
||||
createdFrom: z.object({
|
||||
type: z.nativeEnum(ShoppingListSourceType),
|
||||
referenceId: z.string().optional(),
|
||||
}).optional(),
|
||||
createdFrom: z
|
||||
.object({
|
||||
type: z.nativeEnum(ShoppingListSourceType),
|
||||
referenceId: z.string().optional(),
|
||||
})
|
||||
.optional(),
|
||||
mealPlanId: z.string().optional(),
|
||||
totalEstimatedCost: z.number().optional(),
|
||||
preferredStoreId: z.string().optional(),
|
||||
|
|
@ -93,20 +99,22 @@ export const StoreComparisonResultSchema = z.object({
|
|||
estimatedTotal: z.number(),
|
||||
itemsCovered: z.number(),
|
||||
itemsMissing: z.array(z.string()),
|
||||
})
|
||||
}),
|
||||
),
|
||||
splitStoreOption: z.object({
|
||||
stores: z.array(
|
||||
z.object({
|
||||
storeId: z.string(),
|
||||
storeName: z.string(),
|
||||
items: z.array(z.string()),
|
||||
subtotal: z.number(),
|
||||
})
|
||||
),
|
||||
estimatedTotal: z.number(),
|
||||
savingsVsBestSingleStore: z.number(),
|
||||
}).optional(),
|
||||
splitStoreOption: z
|
||||
.object({
|
||||
stores: z.array(
|
||||
z.object({
|
||||
storeId: z.string(),
|
||||
storeName: z.string(),
|
||||
items: z.array(z.string()),
|
||||
subtotal: z.number(),
|
||||
}),
|
||||
),
|
||||
estimatedTotal: z.number(),
|
||||
savingsVsBestSingleStore: z.number(),
|
||||
})
|
||||
.optional(),
|
||||
});
|
||||
|
||||
export const BasketStoreComparisonResponseSchema = StoreComparisonResultSchema;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue