# Feature: Daily chore scheduler refactor phase 1

## Overview

**Parent Feature:** .github/feat-calenar-chore/feat-calendar-chore.md

**Goal:** UI refactor of the 'Specific Days' portion of the chore scheduler so that it is not so complicated.

**User Story:**

- As a parent, I will be able to select an assigned chore and configure it to occur on 'Specific Days' as before, except I will be presented with a much easier to use interface.

**Rules:**

- Follow instructions from .github/copilot-instructions.md

**Design:**

- Keep the UI for 'Every X Days' the same for now, this will change in phase 2
- Remove days of the week, time selectors, and checkboxes
- Follow at 'Default Time' pattern with optional time for expiry

**Architecture:**

1. The Design Logic
   The interface shifts from a list of tasks to a set of rules.

- The "Base" State: You see 7 day chips (Su, Mo, Tu, We, Th, Fr, Sa) and one "Default Deadline" box.
- The "Active" State: Days you click become "Active."
- The "Silent" State: Any day not clicked is ignored by the system.

2. The Architecture
   Think of the system as having two layers of memory:

- The Global Layer: This holds the "Master Time" (e.g., 8:00 AM).
- The Exception Layer: This is an empty list that only fills up if you explicitly say a day is "special."
- The Merge Logic: When the system saves, it looks at each selected day. It asks: "Does this day have a special time in the Exception Layer? No? Okay, then use the Master Time."

3. The "When/Then" Flow
   Here is exactly how the interaction feels for the user:

- Step A: Establishing the Routine
  When you click Monday, Wednesday, and Friday...
  Then those days highlight, and the "Default Deadline" box becomes active.
  When you set that box to 8:00 AM...
  Then the system internally marks all three days as "8:00 AM."

- Step B: Adding a Day ()
  When you suddenly decide to add Sunday...
  Then Sunday highlights and automatically adopts the 8:00 AM deadline.
- Step C: Breaking the Routine
  When you click "Set different time" and choose Sunday...
  Then a new, specific time box appears just for Sunday.
  When you change Sunday to 11:00 AM...
  Then the system "unhooks" Sunday from the Master Time. Sunday is now an Exception.
- Step D: Changing the Master Time
  When you later change the "Default Deadline" from 8:00 AM to 9:00 AM...
  Then Monday, Wednesday, and Friday all update to 9:00 AM automatically.
  But Sunday stays at 11:00 AM because it is locked as an exception.

Instead of treating all 7 days as individual, equal data points, we treat them as a Group that follows a Rule.

- The Group: The days you selected (e.g., Mon, Wed, Fri, Sun).
- The Rule: The "Default Deadline" that applies to the whole group (e.g., 8:00 AM).
- The Exception: A specific day that breaks the rule (e.g., "Actually, make Sunday 11:00 AM").

**Time Selector Design:**
We might need to create a new time selector or just add an additional time selector component

1. The "Columnar" Picker
   This popover is split into three distinct columns: Hours, Minutes, and AM/PM.
   When you click the time box...
   Then a small panel opens with three narrow, scrollable columns.
   The Logic: The "Minutes" column only contains four options: :00, :15, :30, :45.
   The Flow: The user's eye scans horizontally. "8" → "30" → "PM".

**The "High-Level" Combined Flow:**
Selection: User clicks Monday.
Trigger: User clicks the "Deadline" box.
The Picker: The Columnar Picker pops up.
The Snap: The user clicks "8" in the first column and "00" in the second.
The Result: The box now displays "08:00 AM."

The "Auto-Apply" Flow
When the user clicks a value (e.g., "AM" or "PM"), the selection is registered immediately.
When the user clicks anywhere outside the popover, it closes automatically.
Then the main UI updates to show the new time.

---

## Data Model Changes

### Backend Models

`ChoreSchedule` gains two new fields (persisted in TinyDB, returned in API responses):

- `default_hour: int = 8` — the master deadline hour for `mode='days'`
- `default_minute: int = 0` — the master deadline minute for `mode='days'`

`from_dict` defaults both to `8` / `0` for backwards compatibility with existing DB records.

### Frontend Models

`ChoreSchedule` interface gains two optional fields (optional for backwards compat with old API responses):

- `default_hour?: number`
- `default_minute?: number`

---

## Frontend Design

- `TimePickerPopover.vue` — new shared component at `frontend/vue-app/src/components/shared/TimePickerPopover.vue`
- `ScheduleModal.vue` — "Specific Days" section fully replaced; "Every X Days" section unchanged

## Backend Implementation

No backend implementation required for phase 1.

---

## Backend Tests

- [x] No backend changes required in phase 1

---

## Frontend Implementation

- [x] Created `frontend/vue-app/src/components/shared/TimePickerPopover.vue`
  - Props: `modelValue: { hour: number, minute: number }`, emits `update:modelValue`
  - Displays formatted time as a clickable button (e.g. `08:00 AM`)
  - Opens a columnar popover with three columns: Hour (1–12), Minute (:00/:15/:30/:45), AM/PM
  - Clicking any column value updates the model immediately
  - Closes on outside click via `mousedown` document listener
  - Fully scoped styles using CSS variables from `colors.css`
- [x] Refactored `ScheduleModal.vue` — "Specific Days" section
  - Replaced 7 checkbox rows + per-row `TimeSelector` with chip-based design
  - **Day chips row**: 7 short chips (Su Mo Tu We Th Fr Sa) — click to toggle active/inactive
  - **Default Deadline row**: shown when ≥1 day selected; single `TimePickerPopover` sets the master time for all non-exception days
  - **Selected day list**: one row per active day (sorted Sun→Sat); each row shows:
    - Day name
    - If no exception: italic "Default (HH:MM AM/PM)" label + "Set different time" link
    - If exception set: a `TimePickerPopover` for that day's override + "Reset to default" link
  - State: `selectedDays: Set<number>`, `defaultTime: TimeValue`, `exceptions: Map<number, TimeValue>`
  - Load logic: first `day_config` entry sets `defaultTime`; entries differing from it populate `exceptions`
  - Save logic: iterates `selectedDays`, applies exception time or falls back to `defaultTime` → `DayConfig[]`
  - "Every X Days" mode left unchanged
  - Validation: unchanged (`selectedDays.size > 0`)

---

## Frontend Tests

- [ ] `TimePickerPopover.vue`: renders formatted time, opens/closes popover, selecting hour/minute/period emits correct value, closes on outside click
- [ ] `ScheduleModal.vue` (Specific Days): chip toggles add/remove from selected set; removing a day also removes its exception; setting a different time creates an exception; resetting removes exception; changing default time does not override exceptions; save payload shape matches `DayConfig[]` with correct times; loading an existing mixed-time schedule restores chips, defaultTime, and exceptions correctly

---

## Future Considerations

---

## Acceptance Criteria (Definition of Done)

### Backend

- [x] No backend changes required — existing `DayConfig { day, hour, minute }` model fully supports the new UI

### Frontend

- [x] "Specific Days" mode shows 7 day chips instead of checkboxes
- [x] Selecting chips shows a single "Default Deadline" time picker
- [x] Selected day list shows each active day with either its default label or an exception time picker
- [x] "Set different time" link creates a per-day exception that overrides the default
- [x] "Reset to default" link removes the exception and the day reverts to the master time
- [x] Changing the Default Deadline updates all non-exception days (by using `defaultTime` at save time)
- [x] "Every X Days" mode is unchanged
- [x] Existing schedules load correctly (first entry = default, differing times = exceptions)
- [x] Save payload is valid `DayConfig[]` consumed by the existing API unchanged
- [x] New `TimePickerPopover` component: columnar Hour/Minute/AMPM picker, closes on outside click
- [ ] Frontend component tests written and passing for `TimePickerPopover` and the refactored `ScheduleModal`
