// Browser-safe. The allowlist of every scalar worksheet field, and a blank plan factory. export const FIELD_IDS = [ "0.1", "0.2", "0.3", "0.4", "1.1", "1.2", "1.3", "1.4", "1.5", "1.6", "1.7", "2.1", "2.3", "2.4", "2.5", "3.1", "3.2", "4.1", "4.2", "4.3", "5.1", "5.2", "5.3", "5.4", "5.5", "5.6", "6.4", ]; export function blankPlan() { const fields = {}; for (const id of FIELD_IDS) fields[id] = ""; fields["1.6"] = "0"; fields["2.1"] = "single"; return { schemaVersion: 1, fields, blendComponents: [ { cultivar: "", group: "", process: "", sharePct: "", fcAnchor: "" }, { cultivar: "", group: "", process: "", sharePct: "", fcAnchor: "" }, ], temps: { charge: { time: "0:00", tempC: "", tempF: "" }, tp: { time: "", tempC: "", tempF: "" }, yellow: { time: "", tempC: "", tempF: "" }, fc: { time: "", tempC: "", tempF: "" }, drop: { time: "", tempC: "", tempF: "" }, }, ror: { tpToYellow: { value: "", ok: false, note: "" }, yellowToFc: { value: "", ok: false, note: "" }, fcToDrop: { value: "", ok: false, note: "" }, }, actuators: [ { time: "0:00", heatPct: "", fanPct: "", expectedBt: "", why: "" }, { time: "", heatPct: "", fanPct: "", expectedBt: "", why: "" }, { time: "", heatPct: "", fanPct: "", expectedBt: "", why: "" }, ], planActual: { charge: { planTime: "0:00", planBt: "", actualTime: "0:00", actualBt: "", ror: "", note: "" }, tp: { planTime: "", planBt: "", actualTime: "", actualBt: "", ror: "", note: "" }, yellow: { planTime: "", planBt: "", actualTime: "", actualBt: "", ror: "", note: "" }, fc: { planTime: "", planBt: "", actualTime: "", actualBt: "", ror: "", note: "" }, drop: { planTime: "", planBt: "", actualTime: "", actualBt: "", ror: "", note: "" }, }, afterRoast: { greenIn: "", out: "", weightLossPct: "", vsTarget: "", actualDtrPct: "", colour: "", restedDays: "", brewRatio: "", method: "", cupNotes: "", cupNotesLine2: "", oneChange: "", disproof: "", }, sanityOverride: { drying: null, maillard: null, dtr: null, ceiling: null }, reference: null, prefill: null, inventory: { lotId: "", lotLabel: "", consumed: null }, }; } /** Keep only known FIELD_IDS, coerce every value to a string. */ export function sanitizeFieldPatch(patch) { const out = {}; if (!patch || typeof patch !== "object") return out; for (const id of FIELD_IDS) { if (Object.prototype.hasOwnProperty.call(patch, id) && patch[id] !== null && patch[id] !== undefined) { out[id] = String(patch[id]); } } return out; }