fix: meal planner auto-selects current week on load, + New week idempotent

- Add autoSelectPlan() to the store: after loadPlans() resolves, set
  activePlan to the current week's plan (or most recent) without a second
  API round-trip -- list already returns full PlanSummary with slots
- Call autoSelectPlan(mondayOfCurrentWeek()) in onMounted so the grid
  populates immediately without the user touching the dropdown
- Make onNewPlan idempotent: if a 409 comes back, activate the existing
  plan for that week instead of surfacing an error to the user
This commit is contained in:
pyr0ball 2026-04-16 10:50:34 -07:00
parent dbaf2b6ac8
commit de0008f5c7
2 changed files with 29 additions and 7 deletions

View file

@ -101,7 +101,10 @@ const canAddMealType = computed(() =>
(activePlan.value?.meal_types.length ?? 0) < 4 (activePlan.value?.meal_types.length ?? 0) < 4
) )
onMounted(() => store.loadPlans()) onMounted(async () => {
await store.loadPlans()
store.autoSelectPlan(mondayOfCurrentWeek())
})
function mondayOfCurrentWeek(): string { function mondayOfCurrentWeek(): string {
const today = new Date() const today = new Date()
@ -116,15 +119,20 @@ function mondayOfCurrentWeek(): string {
async function onNewPlan() { async function onNewPlan() {
planError.value = null planError.value = null
planCreating.value = true planCreating.value = true
const weekStart = mondayOfCurrentWeek()
try { try {
const weekStart = mondayOfCurrentWeek()
await store.createPlan(weekStart, ['dinner']) await store.createPlan(weekStart, ['dinner'])
} catch (err: unknown) { } catch (err: unknown) {
const msg = err instanceof Error ? err.message : String(err) const msg = err instanceof Error ? err.message : String(err)
// 409 means a plan for this week already exists surface it helpfully if (msg.includes('409') || msg.toLowerCase().includes('already exists')) {
planError.value = msg.includes('409') || msg.toLowerCase().includes('already exists') // Plan for this week exists just activate it instead of erroring
? 'A plan for this week already exists. Select it from the dropdown above.' const existing = plans.value.find(p => p.week_start === weekStart)
: `Couldn't create plan: ${msg}` if (existing) {
await store.setActivePlan(existing.id)
}
} else {
planError.value = `Couldn't create plan: ${msg}`
}
} finally { } finally {
planCreating.value = false planCreating.value = false
} }

View file

@ -40,6 +40,20 @@ export const useMealPlanStore = defineStore('mealPlan', () => {
} }
} }
/**
* Auto-select the best available plan without a round-trip.
* Prefers the plan whose week_start matches preferredWeekStart (current week's Monday).
* Falls back to the first plan in the list (most recent, since list is DESC).
* No-ops if a plan is already active or no plans exist.
*/
function autoSelectPlan(preferredWeekStart?: string) {
if (activePlan.value || plans.value.length === 0) return
const match = preferredWeekStart
? (plans.value.find(p => p.week_start === preferredWeekStart) ?? plans.value[0])
: plans.value[0]
if (match) activePlan.value = match ?? null
}
async function createPlan(weekStart: string, mealTypes: string[]): Promise<MealPlan> { async function createPlan(weekStart: string, mealTypes: string[]): Promise<MealPlan> {
const plan = await mealPlanAPI.create(weekStart, mealTypes) const plan = await mealPlanAPI.create(weekStart, mealTypes)
plans.value = [plan, ...plans.value] plans.value = [plan, ...plans.value]
@ -129,7 +143,7 @@ export const useMealPlanStore = defineStore('mealPlan', () => {
return { return {
plans, activePlan, shoppingList, prepSession, plans, activePlan, shoppingList, prepSession,
loading, shoppingListLoading, prepLoading, slots, loading, shoppingListLoading, prepLoading, slots,
getSlot, loadPlans, createPlan, setActivePlan, getSlot, loadPlans, autoSelectPlan, createPlan, setActivePlan,
upsertSlot, clearSlot, loadShoppingList, loadPrepSession, updatePrepTask, upsertSlot, clearSlot, loadShoppingList, loadPrepSession, updatePrepTask,
} }
}) })