54 lines
2.1 KiB
TypeScript
54 lines
2.1 KiB
TypeScript
import type { BaseUnit, RecipeUnit, StoreItem } from "@/app/types";
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Unit conversion: recipe units → the catalog item's base unit.
|
|
//
|
|
// Weight ↔ volume crossings (e.g. "1 cup rice" for a rice bag sold by weight)
|
|
// use the item's `gramsPerMl`. Anything else that doesn't line up is a data
|
|
// bug, so we throw loudly instead of guessing.
|
|
// ---------------------------------------------------------------------------
|
|
|
|
const GRAMS_PER: Partial<Record<RecipeUnit, number>> = { g: 1, oz: 28.35, lb: 453.6 };
|
|
const ML_PER: Partial<Record<RecipeUnit, number>> = { ml: 1, tsp: 4.93, tbsp: 14.79, cup: 236.6 };
|
|
|
|
export function toBaseUnit(amount: number, unit: RecipeUnit, item: StoreItem): number {
|
|
const base = item.baseUnit;
|
|
|
|
if (base === "each") {
|
|
if (unit === "each") return amount;
|
|
throw new Error(`"${item.id}" is sold by count; recipe used "${unit}"`);
|
|
}
|
|
|
|
if (base === "g") {
|
|
if (GRAMS_PER[unit] !== undefined) return amount * GRAMS_PER[unit]!;
|
|
if (ML_PER[unit] !== undefined && item.gramsPerMl) return amount * ML_PER[unit]! * item.gramsPerMl;
|
|
}
|
|
|
|
if (base === "ml") {
|
|
if (ML_PER[unit] !== undefined) return amount * ML_PER[unit]!;
|
|
}
|
|
|
|
throw new Error(`Can't convert ${unit} → ${base} for "${item.id}" (missing gramsPerMl?)`);
|
|
}
|
|
|
|
/** Pretty-print a base-unit amount using US kitchen units. */
|
|
export function formatAmount(amount: number, base: BaseUnit): string {
|
|
if (base === "each") {
|
|
const rounded = Math.round(amount * 10) / 10;
|
|
return `${rounded}`;
|
|
}
|
|
if (base === "g") {
|
|
const lb = amount / 453.6;
|
|
return lb >= 1 ? `${lb.toFixed(1)} lb` : `${(amount / 28.35).toFixed(1)} oz`;
|
|
}
|
|
// ml
|
|
const cups = amount / 236.6;
|
|
// Number(...) drops trailing zeros: 2.50 → 2.5, 2.00 → 2
|
|
if (cups >= 0.25) return `${Number(cups.toFixed(cups >= 4 ? 0 : 2))} cup`;
|
|
const tbsp = amount / 14.79;
|
|
return tbsp >= 1 ? `${tbsp.toFixed(1)} tbsp` : `${(amount / 4.93).toFixed(1)} tsp`;
|
|
}
|
|
|
|
export function formatUsd(value: number): string {
|
|
return value.toLocaleString("en-US", { style: "currency", currency: "USD" });
|
|
}
|