Skip to content

feat(memo): create memos on the selected calendar date#5925

Merged
boojack merged 2 commits intomainfrom
feat/calendar-date-prefill
May 2, 2026
Merged

feat(memo): create memos on the selected calendar date#5925
boojack merged 2 commits intomainfrom
feat/calendar-date-prefill

Conversation

@boojack
Copy link
Copy Markdown
Member

@boojack boojack commented May 2, 2026

When a date is active in the activity calendar, the home memo editor now seeds the new memo's createTime/updateTime to that date and reveals the existing TimestampPopover so the user can adjust before saving. Empty in-month calendar cells also become clickable so users can start the first memo for an empty day.

  • Add deriveDefaultCreateTimeFromFilters helper that turns the active displayTime filter into a Date (selected local date + current local hh:mm:ss), with defensive parsing.
  • Drop the count > 0 gate in CalendarCell so empty in-month cells render as buttons; out-of-month cells stay non-interactive.
  • Add defaultCreateTime?: Date prop on MemoEditor; in create mode, useMemoInit seeds timestamps from the prop and a useEffect re-syncs whenever the prop changes (live-derived from the calendar filter). Edit mode and the comment editor are unaffected by construction.
  • PagedMemoList reads MemoFilterContext at the home-editor render site and passes the derived prop.

Frontend-only: the API and store layer already accept custom createTime/updateTime on CreateMemo.

When a date is active in the activity calendar, the home memo editor now
seeds the new memo's createTime/updateTime to that date and reveals the
existing TimestampPopover so the user can adjust before saving. Empty
in-month calendar cells also become clickable so users can start the
first memo for an empty day.

- Add `deriveDefaultCreateTimeFromFilters` helper that turns the active
  `displayTime` filter into a Date (selected local date + current local
  hh:mm:ss), with defensive parsing.
- Drop the `count > 0` gate in CalendarCell so empty in-month cells
  render as buttons; out-of-month cells stay non-interactive.
- Add `defaultCreateTime?: Date` prop on MemoEditor; in create mode,
  useMemoInit seeds timestamps from the prop and a useEffect re-syncs
  whenever the prop changes (live-derived from the calendar filter).
  Edit mode and the comment editor are unaffected by construction.
- PagedMemoList reads MemoFilterContext at the home-editor render site
  and passes the derived prop.

Frontend-only: the API and store layer already accept custom
createTime/updateTime on CreateMemo.
@boojack boojack requested a review from a team as a code owner May 2, 2026 03:40
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 2, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c1c85b36-5302-44d1-afbe-8d7da78421e1

📥 Commits

Reviewing files that changed from the base of the PR and between 7eed864 and f403be2.

📒 Files selected for processing (2)
  • web/src/components/MemoEditor/index.tsx
  • web/tests/derive-default-create-time.test.ts

📝 Walkthrough

Walkthrough

A frontend-only implementation enabling memo timestamp prefilling when users click activity calendar dates. The feature derives a local-time date from an active calendar filter, makes empty calendar cells clickable, adds an optional defaultCreateTime prop to the memo editor, and wires the derived date through the editor lifecycle via context and helper functions.

Changes

Calendar Date Prefill Feature

Layer / File(s) Summary
Type Contract
web/src/components/MemoEditor/types/components.ts
MemoEditorProps gains optional defaultCreateTime?: Date prop for seeding timestamps and popover visibility in create mode.
Helper Derivation
web/src/components/MemoEditor/utils/deriveDefaultCreateTime.ts
New deriveDefaultCreateTimeFromFilters() scans memo filters for displayTime, parses YYYY-MM-DD format, and merges with the provided now time-of-day; returns undefined on parse failure.
Hook Logic
web/src/components/MemoEditor/hooks/useMemoInit.ts
useMemoInit accepts defaultCreateTime and conditionally dispatches setTimestamps during initialization when the option is provided; dependency list updated.
Calendar Interactivity
web/src/components/ActivityCalendar/CalendarCell.tsx
Removes day.count > 0 gate from handleClick, isInteractive, and shouldShowTooltip conditions, making empty in-month cells clickable and tooltips visible when enabled.
Editor Component
web/src/components/MemoEditor/index.tsx
MemoEditorImpl accepts defaultCreateTime, passes it to useMemoInit, adds a live-sync useEffect to re-dispatch timestamps on prop changes, re-seeds timestamps after save/reset in create mode, and widens TimestampPopover render to show in create mode when timestamps are seeded.
List Integration
web/src/components/PagedMemoList/PagedMemoList.tsx
Reads filters from useMemoFilterContext, derives defaultCreateTime via deriveDefaultCreateTimeFromFilters() with useMemo, and passes it to the inline MemoEditor.
Tests
web/tests/calendar-cell-empty-clickable.test.tsx, web/tests/derive-default-create-time.test.ts
New Vitest suites covering CalendarCell empty-day clickability/accessibility and deriveDefaultCreateTimeFromFilters parsing, time merging, and malformed-filter cases.
Documentation
docs/superpowers/specs/2026-05-02-calendar-date-prefill-design.md, docs/superpowers/plans/2026-05-02-calendar-date-prefill.md
Design spec and implementation plan documenting user-visible behavior, touchpoints, helper contract, test strategy, edge cases, and a manual smoke-test checklist.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat(memo): create memos on the selected calendar date' directly and accurately describes the main change: enabling memo creation with timestamps seeded from the selected calendar date.
Description check ✅ Passed The description comprehensively details the feature implementation, covering the helper function, CalendarCell changes, MemoEditor prop additions, and PagedMemoList integration, all directly related to the changeset.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
Review rate limit: 7/8 reviews remaining, refill in 7 minutes and 30 seconds.

Comment @coderabbitai help to get the list of available commands and usage tips.

@boojack
Copy link
Copy Markdown
Member Author

boojack commented May 2, 2026

@codex review

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
web/src/components/MemoEditor/index.tsx (1)

280-284: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Date prefill is lost after the first save in the same filter session.

dispatch(actions.reset()) clears state.timestamps, which hides the TimestampPopover (condition on line 319 becomes false). The live-sync useEffect (lines 94–103) won't re-fire because none of its deps (defaultCreateTime, memo, isInitialized, actions, dispatch) change across the reset. Every memo after the first one typed under the same displayTime filter will be saved with a server-generated "now" timestamp, silently defeating the feature for multi-memo sessions.

The existing defaultVisibility block immediately below already models the correct fix — re-dispatch the default after reset:

🐛 Proposed fix
  dispatch(actions.reset());
  if (!memoName && defaultVisibility) {
    dispatch(actions.setMetadata({ visibility: defaultVisibility }));
  }
+ if (!memoName && defaultCreateTime) {
+   dispatch(actions.setTimestamps({ createTime: defaultCreateTime, updateTime: defaultCreateTime }));
+ }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/src/components/MemoEditor/index.tsx` around lines 280 - 284, Resetting
the editor with dispatch(actions.reset()) clears state.timestamps and hides the
TimestampPopover so the live-sync useEffect (deps: defaultCreateTime, memo,
isInitialized, actions, dispatch) doesn't re-run and subsequent memos lose the
prefetched date; mirror the existing defaultVisibility fix by re-dispatching the
default create-time after the reset (i.e., after dispatch(actions.reset()) call,
call the corresponding action to restore timestamps/createTime using
defaultCreateTime so state.timestamps is repopulated and TimestampPopover
remains visible for the next memo).
🧹 Nitpick comments (1)
web/tests/derive-default-create-time.test.ts (1)

54-69: ⚡ Quick win

Add unconditional date-component assertions to close a coverage gap.

The only non-conditional assertion in this test is expect(result).toBeDefined(). An implementation that ignores the filter entirely and just returns new Date() (today's date with today's time) would pass all assertions here: toBeDefined() passes, and the time-of-day range check would also pass because the time would trivially fall between before and after. The date components (2025, 4, 1) from the filter value "2025-05-01" are never verified on this code path.

🛠️ Proposed fix
  expect(result).toBeDefined();
+ // Verify the date portion always comes from the filter, not from `now`.
+ expect(result!.getFullYear()).toBe(2025);
+ expect(result!.getMonth()).toBe(4); // May (0-indexed)
+ expect(result!.getDate()).toBe(1);
  // Time-of-day should fall between before and after (within 1s tolerance).
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/tests/derive-default-create-time.test.ts` around lines 54 - 69, The test
fails to assert that the date components from the filter are applied; update the
test for deriveDefaultCreateTimeFromFilters to add unconditional assertions that
result's year, month (0-based month adjustment if necessary), and day equal
2025, May (05), and 1 respectively (e.g., check result.getFullYear(),
result.getMonth(), result.getDate()), while keeping the existing time-of-day
range checks intact; reference the function deriveDefaultCreateTimeFromFilters
and the test case in derive-default-create-time.test.ts when making the change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@web/src/components/MemoEditor/index.tsx`:
- Around line 280-284: Resetting the editor with dispatch(actions.reset())
clears state.timestamps and hides the TimestampPopover so the live-sync
useEffect (deps: defaultCreateTime, memo, isInitialized, actions, dispatch)
doesn't re-run and subsequent memos lose the prefetched date; mirror the
existing defaultVisibility fix by re-dispatching the default create-time after
the reset (i.e., after dispatch(actions.reset()) call, call the corresponding
action to restore timestamps/createTime using defaultCreateTime so
state.timestamps is repopulated and TimestampPopover remains visible for the
next memo).

---

Nitpick comments:
In `@web/tests/derive-default-create-time.test.ts`:
- Around line 54-69: The test fails to assert that the date components from the
filter are applied; update the test for deriveDefaultCreateTimeFromFilters to
add unconditional assertions that result's year, month (0-based month adjustment
if necessary), and day equal 2025, May (05), and 1 respectively (e.g., check
result.getFullYear(), result.getMonth(), result.getDate()), while keeping the
existing time-of-day range checks intact; reference the function
deriveDefaultCreateTimeFromFilters and the test case in
derive-default-create-time.test.ts when making the change.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 97d55c2c-62a0-4bba-98de-e1c1fdc02553

📥 Commits

Reviewing files that changed from the base of the PR and between d349fe4 and 7eed864.

📒 Files selected for processing (10)
  • docs/superpowers/plans/2026-05-02-calendar-date-prefill.md
  • docs/superpowers/specs/2026-05-02-calendar-date-prefill-design.md
  • web/src/components/ActivityCalendar/CalendarCell.tsx
  • web/src/components/MemoEditor/hooks/useMemoInit.ts
  • web/src/components/MemoEditor/index.tsx
  • web/src/components/MemoEditor/types/components.ts
  • web/src/components/MemoEditor/utils/deriveDefaultCreateTime.ts
  • web/src/components/PagedMemoList/PagedMemoList.tsx
  • web/tests/calendar-cell-empty-clickable.test.tsx
  • web/tests/derive-default-create-time.test.ts

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7eed86409c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread web/src/components/PagedMemoList/PagedMemoList.tsx
…s keep date

After dispatch(actions.reset()), state.timestamps was wiped and the
live-sync useEffect didn't re-fire (its deps don't change across reset),
so memo #2+ in the same calendar-filter session silently fell back to
server-generated "now". Mirror the existing defaultVisibility re-seed
pattern.

Also tighten the "uses real new Date()" test to assert the date
components come from the filter — previously it would have passed an
impl that returned new Date() and ignored filters entirely.
@boojack boojack merged commit ef55013 into main May 2, 2026
2 of 3 checks passed
@boojack boojack deleted the feat/calendar-date-prefill branch May 2, 2026 03:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant