Skip to content

feat(chores): a schedule wizard, and "any day" beyond a week - #364

Merged
jherforth merged 1 commit into
mainfrom
feat/schedule-wizard
Oct 31, 2026
Merged

jherforth merged 1 commit into
mainfrom
feat/schedule-wizard

Conversation

@jherforth

Copy link
Copy Markdown
Owner

Why

Scheduling a chore on the By person board meant reading a menu of chips (Every day, Weekdays, Mon · Wed · Fri…) and knowing which one fit. Jason asked for a wizard that steps through it, beside the picker rather than replacing it. He also asked that the "any day" option from #362 go beyond a week.

What changes

Picker | Wizard in the Add dialog, as in the concept. The picker is unchanged. Each display remembers which mode was used last (picker at first). The wizard has five steps (four where step 3 doesn't apply):

  1. How often?

    • On certain days of the week
    • Once in a while, any day
    • Every few days
    • On a date each month
    • Again a while after it's done
    • Just once
  2. The details:

    • days (with Every day / Weekdays / Weekends shortcuts);
    • a period (a week, two weeks, a month, three months, six months, a year);
    • every N days;
    • dates of the month (several allowed);
    • N days, weeks, months or years after done (the picker only offers months and years);
    • an optional date.

    It shows the timing so far ("So far: Once a month, any day").

  3. If it isn't done that day… (only for timings that fall on days): it goes away at the end of the day, or it stays until it's done. The picker never asked this; it always made day-of schedules.

  4. The chores: the existing tick list, with New chore.

  5. Check and add: "Emma: 🌀 Change furnace filter. Once a month, any day.", plus a note if it stays until done, or if some chores move from another schedule.

Back keeps the answers given. A step counter shows where you are.

Any day, beyond a week. #362's weekly becomes any-day, with its period in interval:

Period Window
1w Sunday–Saturday
2w two weeks from the week it was set up
1m calendar month
3m calendar quarter
6m half year
1y calendar year

The rules are the same for every period:

  • the card is due on the period's last day;
  • it counts toward the daily bonus only on that day;
  • an undone period is one miss;
  • the next period starts fresh.

weekly is still accepted (as any-day every 1w), and migration 38 converts existing weekly rows. The schedule dialog's Duration offers Once in a while (any day) with a period field.

Board calendar. An any-day chore is drawn by its period. The calendar now knows which schedules have a card up, so a monthly chore done on the 3rd doesn't show as "waiting" when you look at the 20th; that week's history alone couldn't tell.

Code

  • New client/src/components/ScheduleWizard.jsx: the steps and the timing they build (wizardTiming). The board keeps the dialog, the chores step, the review and saving (keep becomes the schedule's duration).
  • Server rules in server/services/anyDayChores.js (renamed from weeklyChores.js): periodOf(date, period, anchor) plus validation. client/src/utils/choreScheduleGroups.js has the same period logic (anyDayPeriodOf) for the calendar.
  • Migration schema38-anyDayChores.

Testing

  • Server npm test 700/700.
    • anyDayChoresRules.test.js: week, fortnight, month (including leap February), quarter, half and year boundaries; the weekly alias.
    • anyDayChores.test.js, on a real server:
      • a weekly chore appears at once, due Saturday;
      • monthly, quarterly, half-yearly, yearly and fortnightly cards are due at their period ends;
      • weekly is accepted and bad periods are refused;
      • the bonus is held back only on the last day (today is a Saturday, so the Saturday branch ran);
      • done today: cleared overnight, no new card that month, and its history keeps its chore;
      • an undone period gives one miss and a fresh card;
      • switching to any-day, or changing the period, re-dates the open card;
      • migration 38 converts a planted weekly row.
  • Client vitest 883/883. Period logic matches the server's; any-day timings group and order correctly, write the right fields, and can be moved off. Calendar cases: done, waiting, due today, no open card, missed, not done, planned, before creation. check:i18n and build are clean.
  • Edge (demo data), at 1280px and phone width, 24 checks:
    • opens on the picker, then switches to the wizard;
    • "Once in a while → A month → furnace filter → review → Add" saves any-day/1m with its card due at month end, in a "Once a month, any day" group;
    • the wizard is remembered on the next open;
    • "Certain days → Mon, Thu → stays until done → Recycling" saves 0 0 * * 1,4/until-completed;
    • Back from the review returns to the wizard with its answer kept;
    • the schedule dialog lists all six periods;
    • no sideways scroll; no page errors.

🤖 Generated with Claude Code

The board's Add dialog keeps its picker of chips and gains a wizard beside
it (Picker | Wizard; each display remembers which it last used). The
wizard steps through it: how often (certain days, once in a while any day,
every few days, a date each month, again a while after it's done, just
once), the details, and for timings on days whether a chore not done that
day goes at day's end or stays until done; then the chores, and a
one-line summary before Add. Back keeps the answers.

"Once a week, any day" (#362) becomes once in a period, any day: duration
`any-day` with its period in `interval`: a week, two weeks, a month,
three or six months (calendar quarters and halves), or a year. Each
period's card is due on its last day, counts toward the daily bonus only
then, and an undone period is one miss; the next period starts fresh.
`weekly` is still accepted as any-day every week, and migration 38 turns
existing weekly rows into any-day 1w. The schedule dialog offers the
periods too.

The board's week calendar draws an any-day chore by its period, and uses
which schedules have a card up so a monthly chore done earlier in the
month isn't shown as waiting.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@jherforth
jherforth merged commit 13f1602 into main Oct 31, 2026
7 checks passed
@github-project-automation github-project-automation Bot moved this from Backlog to Done in HomeGlow Kanban Oct 31, 2026
adamecker pushed a commit to adamecker/HomeGlow that referenced this pull request Oct 31, 2026
…) into test/all-combined

Upstream's any-day chores migration renumbered 38 -> 44: this branch
already uses 38 for choreExpiry (renumbered upstream 32), and 43 is
the highest registered id. Its test updated to match (43 -> 44).
Google Tasks sync (schema 28/34) and custom ChoreIconPicker preserved.
@mrramam

mrramam commented Oct 31, 2026

Copy link
Copy Markdown
Collaborator

Read through any-day after merge and reproduced these on a fresh server, with the nightly run triggered through /api/system/backgroundTasks.

Most serious:

  1. Nightly reset unassigns cards with clams. A yearly any-day chore with 2 clams lost its person at the nightly run. With 0 clams it kept its person. The open card blocks a respawn, so it stays unassigned for the rest of the period.
  2. Changing timing strands the card. Move an open any-day chore to Mon/Wed and the card keeps its old due date, stays when overdue, logs a miss, and blocks the daily bonus: finishing everything else paid 1 bonus in the control and 0 here. Deleting the parent also leaves a card that stays when overdue.
  3. Prune can delete an undone chore. With history moved to the parent by keepHistory, the prune query sees a completion on the parent. An until-completed chore done once, then made one-time, with its open card deleted, was removed at the nightly run undone, and the chore went with it. This isn't limited to any-day.

Also:

  1. Copy loses the period. The copy step in ChoreScheduleBoard sets interval to null unless the duration is once-completed. Copying a "once every 3 months" chore stored 1w on the copy.
  2. Two-week periods can be off by a week. periodOf anchors on created_at, a UTC date. On the same Saturday in Pacific time, a morning chore's period ends Nov 7, but one created at 8 pm ends that night.
  3. Week view near a period boundary. anyDayOnCalendar returns on any completion in the week. Done Nov 30 with December's card open, today Dec 2: December's waiting state is hidden. A later week holding the period's end also shows "planned" when the chore is already done for that period.
  4. wizardTiming accepts 2.5 days and 1.5 weeks, and the server then rejects them with a 400.

Not run end to end:

  • A card due next year passes shouldShowChoreToday, and useChoreSoundScheduler has no other due check, so a chore with a due sound looks like it chimes daily.
  • A chore added on the period's last day gets a card due that day, so it looks like it can log a miss that night.

@jherforth jherforth self-assigned this Oct 31, 2026
@jherforth jherforth added the enhancement New feature or request label Oct 31, 2026
@jherforth jherforth added this to the 2.0 milestone Oct 31, 2026
@jherforth

Copy link
Copy Markdown
Owner Author

Addressed in #369

jherforth added a commit that referenced this pull request Nov 1, 2026
- A card from someone's own schedule keeps its person overnight, clams or not.
- Moved off any-day, or deleted, its open card goes instead of lingering as a
  one-time chore due every day (holding back the bonus, logging misses).
- A repeating schedule made one-time counts only completions logged after the
  change (one_time_after_history_id, migration 40), so it isn't cleared undone.
- Copy keeps an any-day group's period.
- Two-week periods count from the household's date the schedule was made.
- The week calendar handles a week that holds two periods, and plans nothing
  for a period already done.
- The wizard takes whole numbers only.
- Due-time sounds skip a one-time chore due on a later day.
- A card made on its period's last day doesn't count that day.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

2 participants