Fix New plan feeling like a no-op; add plan delete and why-panel collapse
Test and deploy / test-and-deploy (push) Successful in 1m34s
Test and deploy / test-and-deploy (push) Successful in 1m34s
New plan reset the form correctly but left the Plans drawer open over
it, so the reset was invisible until the user closed the drawer
themselves. Now closes it immediately, matching selectPlan().
Also adds a delete button per plan in the Plans drawer (server route
already existed) - deleting the currently open plan resets to a fresh
blank one, matching New plan.
Why-panel teaching callouts ("WHY CULTIVAR SETS THE CLOCK" etc.) now
default collapsed instead of wall-to-wall expanded on first load, with
an "Expand all" button in the header on both the planner and cupping
pages. Persistence flips from tracking collapsed-vs-default-open to
expanded-vs-default-closed to match.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
This commit is contained in:
+42
-6
@@ -16,10 +16,11 @@ import { initPrefillPanel } from "./prefill-ui.js?v=__ASSET_VERSION__";
|
||||
import { initAlogPanel } from "./alog-ui.js?v=__ASSET_VERSION__";
|
||||
import { initPrint } from "./print.js?v=__ASSET_VERSION__";
|
||||
import { initLotPicker } from "./lot-picker.js?v=__ASSET_VERSION__";
|
||||
import { protectedFetch, csrfToken } from "./api.js?v=__ASSET_VERSION__";
|
||||
import { api, protectedFetch, csrfToken } from "./api.js?v=__ASSET_VERSION__";
|
||||
import { initSideNav } from "./nav.js?v=__ASSET_VERSION__";
|
||||
import { wireWhyPanels } from "./why-panels.js?v=__ASSET_VERSION__";
|
||||
import { initFieldHelp } from "./field-help.js?v=__ASSET_VERSION__";
|
||||
import { showToast } from "./toast.js?v=__ASSET_VERSION__";
|
||||
|
||||
const FIELD_ID_SET = new Set(FIELD_IDS);
|
||||
const STORAGE_PREFIX = "roastPlannerPlan.v2";
|
||||
@@ -823,6 +824,7 @@ async function loadPlans() {
|
||||
list.replaceChildren(
|
||||
...plans.map((plan) => {
|
||||
const item = document.createElement("li");
|
||||
item.className = "plan-list-row";
|
||||
const button = document.createElement("button");
|
||||
button.type = "button";
|
||||
button.className = "plan-list-item";
|
||||
@@ -833,7 +835,20 @@ async function loadPlans() {
|
||||
updated.textContent = `Updated ${new Date(plan.updated_at).toLocaleDateString()}`;
|
||||
button.append(title, updated);
|
||||
button.addEventListener("click", () => selectPlan(plan));
|
||||
item.append(button);
|
||||
|
||||
const deleteBtn = document.createElement("button");
|
||||
deleteBtn.type = "button";
|
||||
deleteBtn.className = "icon-btn plan-list-delete";
|
||||
deleteBtn.setAttribute("aria-label", `Delete ${title.textContent}`);
|
||||
deleteBtn.textContent = "✕";
|
||||
// A sibling of the select button, not nested inside it — stopPropagation alone
|
||||
// wouldn't be enough to keep a click here from also selecting the plan otherwise.
|
||||
deleteBtn.addEventListener("click", (event) => {
|
||||
event.stopPropagation();
|
||||
deletePlan(plan);
|
||||
});
|
||||
|
||||
item.append(button, deleteBtn);
|
||||
return item;
|
||||
}),
|
||||
);
|
||||
@@ -860,10 +875,9 @@ async function selectPlan(plan) {
|
||||
lotPicker?.refreshRefineSuggestion();
|
||||
document.querySelector("[data-close-drawer]")?.click();
|
||||
}
|
||||
async function newPlan() {
|
||||
if (!confirm("Start a new plan? Your current plan is already saved locally."))
|
||||
return;
|
||||
if (!(await flushCurrentPlan())) return;
|
||||
// Shared by newPlan() and deletePlan() (when the deleted plan was the one on screen) — resets
|
||||
// the whole app to a fresh, unsynced plan.
|
||||
function resetToBlankPlan() {
|
||||
remotePlanId = null;
|
||||
draftSyncedAt = null;
|
||||
state.plan = blankPlan();
|
||||
@@ -875,6 +889,28 @@ async function newPlan() {
|
||||
lotPicker?.renderOptions();
|
||||
lotPicker?.refreshRefineSuggestion();
|
||||
}
|
||||
async function newPlan() {
|
||||
if (!confirm("Start a new plan? Your current plan is already saved locally."))
|
||||
return;
|
||||
if (!(await flushCurrentPlan())) return;
|
||||
resetToBlankPlan();
|
||||
// Without this, the Plans drawer stays open over the now-blank form — the reset happens but
|
||||
// is invisible, so it doesn't read as "starting something new" until the user closes it themselves.
|
||||
document.querySelector("[data-close-drawer]")?.click();
|
||||
}
|
||||
async function deletePlan(plan) {
|
||||
const name = plan.plan?.fields?.["0.1"] || "Untitled plan";
|
||||
if (!confirm(`Delete "${name}"? This cannot be undone.`)) return;
|
||||
try {
|
||||
await api(`/api/plans/${plan.id}`, { method: "DELETE" });
|
||||
} catch (error) {
|
||||
showToast(error.message, "fail");
|
||||
return;
|
||||
}
|
||||
showToast("Plan deleted.");
|
||||
if (plan.id === remotePlanId) resetToBlankPlan();
|
||||
await loadPlans();
|
||||
}
|
||||
|
||||
function wireToolbar() {
|
||||
document.getElementById("btn-toggle-fids").addEventListener("click", (e) => {
|
||||
|
||||
Reference in New Issue
Block a user