# Bug List

**Feature Bugs:** .github/specs/feat-calendar-chore/feat-calendar-chore.md

## Bugs

### When rescheduling an extended time chore, the extended time should be reset(removed)

When a chore has had it's time extended, but later edited through the scheduler and saved, the extended time for this chore should be reset. (A previous too late chore would again be too late if the current time is past the newly changed schedule)

**Root cause:** The PUT handler in `chore_schedule_api.py` saved the new schedule but never deleted the `TaskExtension` record for that child+task pair.

**Fix:**

- `backend/db/task_extensions.py` — Added `delete_extension_for_child_task(child_id, task_id)` that removes the `TaskExtension` matching both child and task IDs.
- `backend/api/chore_schedule_api.py` — Imported the new function and called it immediately before `upsert_schedule(schedule)` in the PUT handler.

#### Additional Test Cases With This Fix

- []

### User Test Findings:

This flow produces a bug

1. A chore that is 'too late' (scheduled expiry time is 8:00am, but the current time is 3pm)
2. Extend the time on that chore causes the 'too late' to disappear. The chore is now valid again.
3. Enter the scheduler on that chore and set the expiry time to 9am (when it is 3pm in real time) the chore stays active -- I expect the chore to go back to the 'too late' state since the extended time was reset again. It should revert back to 'too late'

**Analysis:** The backend fix (deleting the extension on PUT) is correct. Step 3 failing is a side effect of Bug 3 (Extend Time not refreshing the UI) — the frontend was in a stale state after step 2, so step 3 was operating on stale item data. Once Bug 3 is fixed (direct refresh in `doExtendTime`), step 2 reliably updates the UI, and step 3's `onScheduleSaved → refresh()` then correctly re-evaluates `isChoreExpired` against the fresh data (no `extension_date`, 9am schedule → TOO LATE). No additional frontend changes needed beyond the backend deletion fix.

---

### Extend time is cut off of chore kebab menu

The dropdown for the kebab menu does not extend far enough to show all the items. It should show all the items.
https://git.ryankegel.com/ryan/chore/attachments/951592da-29a2-4cca-912e-9b160eb2f19c

**Root cause:** The `.kebab-menu` is `position: absolute` inside `.chore-kebab-wrap`, which lives inside a `ScrollingList` card. The scroll wrapper has `overflow-y: hidden`, which clips any absolutely positioned content that extends below the card boundary. CSS cannot set `overflow-x: auto` and `overflow-y: visible` simultaneously — the browser coerces `visible` to `auto`.

**Fix:** (`frontend/vue-app/src/components/child/ParentView.vue`)

- Added `menuPosition = ref({ top: 0, left: 0 })` and `kebabBtnRefs = ref<Map<string, HTMLElement>>(new Map())`.
- Added a `:ref` callback on `.kebab-btn` to register/unregister each button element keyed by `item.id`.
- `openChoreMenu` now captures `getBoundingClientRect()` on the trigger button and stores `{ top: rect.bottom, left: rect.right - 140 }` into `menuPosition`.
- Wrapped `.kebab-menu` in `<Teleport to="body">` and switched it to `position: fixed` with inline `:style` driven by `menuPosition`. `z-index` raised to `9999`.
- `onDocClick` required no changes — it already checks `.kebab-menu` via `composedPath()`, which traverses the real DOM regardless of teleport destination.

#### Additional Test Cases With This Fix

- []

### User Test Findings:

Fix confirmed

---

### When a chore has passed it's time or when an time expired chore is extended, it should be updated right away in all UIs.

An SSE event should happen when a chore has been extended or expired so that the UI updates. Currently, the user has to refresh to see this change.

**Root cause:** In `ParentView.vue`, three call sites called `resetExpiryTimers()` synchronously — before `refresh()` resolved — so new timers were set against stale item data. `ChildView.vue` already delayed the call with `setTimeout(..., 300)` correctly.

**Fix:** (`frontend/vue-app/src/components/child/ParentView.vue`)

- In `handleChoreScheduleModified`, `handleChoreTimeExtended`, and `onScheduleSaved`: replaced `resetExpiryTimers()` with `setTimeout(() => resetExpiryTimers(), 300)` to match the existing correct pattern in `ChildView.vue`.

#### Additional Test Cases With This Fix

- []

### User Test Findings:

I'm still not seeing the chore update back to active state when 'Extend time' is selected from the menu. I have to refresh the page to see the change.

**Root cause of remaining failure:** `doExtendTime` posted to the API and relied entirely on the SSE `chore_time_extended` event to trigger a refresh. If SSE delivery is delayed or the event is missed, the UI never updates. The previous fix (timer delay) only corrected expiry timer scheduling, not the extend-time response path.

**Additional fix:** (`frontend/vue-app/src/components/child/ParentView.vue`)

- In `doExtendTime`: after a successful API response, call `childChoreListRef.value?.refresh()` and `setTimeout(() => resetExpiryTimers(), 300)` directly. Added an early `return` on error to prevent a refresh on failure.

---

### On the Every X Days scheduler, the every [x] input box and day dropbox should be on the same line

Currently they are on seperate lines.

**Root cause:** `.interval-row` and `.interval-time-row` shared a combined CSS rule that included `flex-wrap: wrap`, causing the interval input and day select to wrap onto a new line at the modal's narrow width.

**Fix:** (`frontend/vue-app/src/components/shared/ScheduleModal.vue`)

- Split the combined `.interval-row, .interval-time-row` rule into two separate rules. Removed `flex-wrap: wrap` from `.interval-row` only; kept it on `.interval-time-row`.

#### Additional Test Cases With This Fix

- []

### User Test Findings:

Fix confirmed

---

### In the chore scheduler, the time selector needs to be much smaller

The time selector should have a smaller font size, borders, up/down arrows. A font size of 1rem should be fine.

**Root cause:** `.time-value` had `font-size: 1.4rem` and `.time-separator` had `font-size: 1.6rem`. All button/value boxes were `2.5rem` wide/tall. A `@media (max-width: 480px)` block made them even larger on small screens.

**Fix:** (`frontend/vue-app/src/components/shared/TimeSelector.vue`)

- `.arrow-btn` and `.time-value`: width/height `2.5rem` → `1.8rem`; arrow font `0.85rem` → `0.75rem`.
- `.time-value`: `font-size: 1.4rem` → `1rem`.
- `.time-separator`: `font-size: 1.6rem` → `1rem`.
- `.ampm-btn`: width `3rem` → `2.2rem`; height `2.5rem` → `1.8rem`; font `0.95rem` → `0.8rem`.
- Removed the `@media (max-width: 480px)` block that was enlarging all sizes on mobile.

#### Additional Test Cases With This Fix

- [x]

### User Test Findings:

Fix confirmed
