init
This commit is contained in:
commit
c19b910c36
80 changed files with 16134 additions and 0 deletions
54
app/lib/units.ts
Normal file
54
app/lib/units.ts
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
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" });
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue