70 lines
2.0 KiB
TypeScript
70 lines
2.0 KiB
TypeScript
import type { Substitution, Unit } from "@app/shared-types";
|
||
|
||
export interface SubstitutableIngredient {
|
||
canonicalIngredientId: string;
|
||
displayNameSv: string;
|
||
quantity: number;
|
||
unit: Unit;
|
||
optional: boolean;
|
||
}
|
||
|
||
export interface SubstitutionResult {
|
||
ingredients: SubstitutableIngredient[];
|
||
applied: {
|
||
fromId: string;
|
||
toId: string;
|
||
ratio: number;
|
||
instructionsSv?: string | undefined;
|
||
warningSv?: string | undefined;
|
||
};
|
||
}
|
||
|
||
/**
|
||
* Substitutionsmotor (spec §20): byt ingrediens med mängdfaktor och
|
||
* instruktionspåverkan. Näringen räknas ALLTID om av nutrition-engine efteråt –
|
||
* denna modul ändrar bara ingredienslistan.
|
||
*/
|
||
export function applySubstitution(
|
||
ingredients: SubstitutableIngredient[],
|
||
substitution: Pick<
|
||
Substitution,
|
||
"fromIngredientId" | "toIngredientId" | "ratio" | "instructionsSv" | "notRecommendedFor"
|
||
>,
|
||
toDisplayNameSv: string,
|
||
context?: string,
|
||
): SubstitutionResult {
|
||
const target = ingredients.find((i) => i.canonicalIngredientId === substitution.fromIngredientId);
|
||
if (!target) {
|
||
throw new Error(
|
||
`Ingrediensen ${substitution.fromIngredientId} finns inte i receptet och kan inte bytas.`,
|
||
);
|
||
}
|
||
|
||
let warningSv: string | undefined;
|
||
if (context && substitution.notRecommendedFor.includes(context)) {
|
||
warningSv = `Observera: detta byte rekommenderas inte för ${context}.`;
|
||
}
|
||
|
||
const next = ingredients.map((ing) =>
|
||
ing.canonicalIngredientId === substitution.fromIngredientId
|
||
? {
|
||
...ing,
|
||
canonicalIngredientId: substitution.toIngredientId,
|
||
displayNameSv: toDisplayNameSv,
|
||
quantity: Math.round(ing.quantity * substitution.ratio * 100) / 100,
|
||
}
|
||
: ing,
|
||
);
|
||
|
||
return {
|
||
ingredients: next,
|
||
applied: {
|
||
fromId: substitution.fromIngredientId,
|
||
toId: substitution.toIngredientId,
|
||
ratio: substitution.ratio,
|
||
instructionsSv: substitution.instructionsSv ?? undefined,
|
||
warningSv,
|
||
},
|
||
};
|
||
}
|