Skip to content

feat(desktop): add NIP-ER reminder UI — create, view, and manage encrypted reminders#963

Draft
wpfleger96 wants to merge 6 commits into
paul/nip-er-relay-schedulerfrom
paul/nip-er-desktop-reminders-ui
Draft

feat(desktop): add NIP-ER reminder UI — create, view, and manage encrypted reminders#963
wpfleger96 wants to merge 6 commits into
paul/nip-er-relay-schedulerfrom
paul/nip-er-desktop-reminders-ui

Conversation

@wpfleger96

Copy link
Copy Markdown
Collaborator

Summary

Adds the desktop client UI for NIP-ER (kind:30300 event reminders), completing the third PR in the reminder stack.

Users can set reminders on any message via a "Remind me later" action in the message context menu, view and manage all reminders from a dedicated sidebar panel, and receive toast notifications when reminders come due.

Stack: #934#957this PR

What's included

Service layer (reminderService.ts)

  • createReminder — builds a kind:30300 parameterized-replaceable event with random d-tag, not_before timestamp, and NIP-44 encrypted content
  • fetchReminders — queries own kind:30300 events and decrypts each individually
  • completeReminder / snoozeReminder / cancelReminder — publish replacement events with updated status and expiration tags

"Remind me later" dialog (RemindMeLaterDialog.tsx)

  • Time presets: 30 min, 1 hour, 3 hours, tomorrow 9am, next Monday 9am
  • Optional note field
  • Triggered from the message action bar's "more" menu (Clock icon)

Reminders panel (RemindersPanel.tsx)

  • Accessible from sidebar (Bell icon → /reminders route)
  • Groups pending reminders by due status: overdue, today, upcoming
  • Each row shows target message preview, note, relative due time, and action buttons (complete, snooze 1hr, cancel)

Due-detection (client-side)

  • 60-second setInterval compares not_before against Date.now()
  • Fires toast notification when a reminder transitions from upcoming to due
  • No relay scheduler dependency — purely local timer for v1

Wiring

  • RemindMeLaterProvider context avoids prop-threading through 4 intermediate components
  • MessageRow uses useRemindLater() hook to open the dialog with target context
  • DialogFooter component added to the shared dialog UI (was missing)
  • Route tree updated for /reminders path

Design decisions

  • Individual events, not a blob — each reminder is its own parameterized-replaceable event (unlike channel stars which use a single encrypted blob). This preserves relay-side scheduler integration from PR feat(relay): add NIP-ER push scheduler with cross-pod delivery #957.
  • No feed pipeline integration — kind:30300 events are author-only with no p-tags, so they cannot flow through the server-side HomeFeedResponse/event_mentions pipeline. Due-detection is purely client-side.
  • Presets only for v1 — no custom datetime picker. Keeps scope tight.
  • Jittered expiration — completed/cancelled reminders get 30-90 day expiration tags for eventual relay-side cleanup.

Files changed

File Change
desktop/src/shared/constants/kinds.ts Add KIND_EVENT_REMINDER = 30300
desktop/src/shared/ui/dialog.tsx Add DialogFooter component
desktop/src/features/reminders/lib/reminderTypes.ts New — TypeScript types
desktop/src/features/reminders/lib/reminderService.ts New — service layer
desktop/src/features/reminders/ui/RemindMeLaterDialog.tsx New — time picker dialog
desktop/src/features/reminders/ui/RemindMeLaterProvider.tsx New — context provider
desktop/src/features/reminders/ui/RemindersPanel.tsx New — panel with due-detection
desktop/src/features/reminders/ui/RemindersScreen.tsx New — route wrapper
desktop/src/app/routes/reminders.tsx New — route definition
desktop/src/app/routeTree.gen.ts Add /reminders route
desktop/src/app/routes.ts Register route
desktop/src/app/AppShell.tsx Add provider + nav handler
desktop/src/app/navigation/useAppNavigation.ts Add goReminders
desktop/src/features/messages/ui/MessageActionBar.tsx Add onRemindLater prop + menu item
desktop/src/features/messages/ui/MessageRow.tsx Wire useRemindLater hook
desktop/src/features/sidebar/ui/AppSidebar.tsx Add Reminders nav item

@wpfleger96 wpfleger96 requested a review from a team as a code owner June 11, 2026 00:13
@wpfleger96 wpfleger96 marked this pull request as draft June 11, 2026 00:21
wpfleger96 pushed a commit that referenced this pull request Jun 11, 2026
wpfleger96 added a commit that referenced this pull request Jun 11, 2026
@wpfleger96 wpfleger96 force-pushed the paul/nip-er-relay-scheduler branch from 8b4db46 to d920ae7 Compare June 11, 2026 19:21
@wpfleger96 wpfleger96 force-pushed the paul/nip-er-desktop-reminders-ui branch from acfbe1b to 5b2e79c Compare June 11, 2026 19:22
wpfleger96 pushed a commit that referenced this pull request Jun 11, 2026
@wpfleger96 wpfleger96 force-pushed the paul/nip-er-relay-scheduler branch from d920ae7 to 275ad4b Compare June 11, 2026 19:32
npub1mn7jgtj4w2pd0g0zeuhxsa6jy6p0rewxz4kujt98my82ahfmp72sxjexk7 and others added 4 commits June 11, 2026 15:32
…ypted reminders

Implements the desktop client UI for kind:30300 event reminders (NIP-ER):

- Service layer (reminderService.ts): create, complete, snooze, and cancel
  reminders as individual parameterized-replaceable events with NIP-44
  encrypt-to-self. Each reminder has a random d-tag, not_before timestamp,
  and encrypted content containing the target message reference and optional
  note.

- "Remind me later" action: new menu item in MessageActionBar opens a dialog
  with time presets (30min, 1hr, 3hr, tomorrow 9am, next Monday 9am) and an
  optional note field.

- Reminders panel: accessible from sidebar (Bell icon), shows pending
  reminders grouped by due status (overdue/today/upcoming) with
  complete/snooze/cancel action buttons per row.

- Due-detection: local 60-second interval checks not_before against
  Date.now() and fires toast notifications when reminders become due.
  No relay scheduler dependency for v1 — purely client-side.

- RemindMeLaterProvider context avoids prop-threading through 4 intermediate
  components; MessageRow uses the hook directly.

All reminder content is NIP-44 encrypted — never stored or transmitted in
plaintext. Completed/cancelled reminders get jittered 30-90 day expiration
tags for eventual relay-side cleanup.

Co-authored-by: Will Pfleger <pfleger.will@gmail.com>
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
Captures 4 screenshots verifying the NIP-ER reminder feature renders
correctly: sidebar nav item, message action menu, time-picker dialog,
and empty reminders panel. Registered in the smoke project.

Co-authored-by: Will Pfleger <wpfleger@squareup.com>
Signed-off-by: Will Pfleger <wpfleger@squareup.com>
…enshots

Radix UI components animate in via CSS transitions. Playwright's toBeVisible()
resolves mid-animation, producing greyed-out or partially-rendered screenshots.

- Create shared waitForAnimations(page) utility in tests/helpers/animations.ts
- Wire it into screenshot.mjs so the just desktop-screenshot path settles
  animations automatically before capture
- Update reminders-screenshots.spec.ts to call waitForAnimations before every
  page.screenshot(), add clip regions for focused captures
- Update AGENTS.md to reference the shared helper as mandatory

Co-authored-by: Will Pfleger <wpfleger@block.xyz>
Signed-off-by: Will Pfleger <wpfleger@block.xyz>
@wpfleger96 wpfleger96 force-pushed the paul/nip-er-desktop-reminders-ui branch from dc0ded6 to 7388a58 Compare June 11, 2026 19:33
Add a "Custom date & time" section below the time presets in the
RemindMeLaterDialog, using native date and time inputs styled with the
existing Input component. The date picker defaults to today and prevents
selecting past dates. A "Set reminder" button creates the reminder at
the user-selected timestamp.

Also extends the screenshot spec to 6 tests: widens the action menu
screenshot clip, adds tests for the reminders panel with active and
fired/overdue reminders, and adds KIND_EVENT_REMINDER mock support to
the e2e bridge for seeding reminder data in tests.

Co-authored-by: Will Pfleger <wpfleger@block.xyz>
Signed-off-by: Will Pfleger <wpfleger@block.xyz>
wpfleger96 pushed a commit that referenced this pull request Jun 11, 2026
@wpfleger96

Copy link
Copy Markdown
Collaborator Author

1. Sidebar — Reminders nav item

The bell icon in the sidebar navigation opens the Reminders panel.

01-sidebar-reminders-nav

2. Action menu — "Remind me later"

Hovering a message and opening "More actions" reveals the "Remind me later" option in the context menu.

02-message-action-remind-later

3. Time presets + custom date/time dialog

Clicking "Remind me later" opens a dialog with preset durations and a custom date/time picker (date defaults to today).

03-remind-me-later-dialog

4. Reminders panel — empty state

The Reminders panel before any reminders are set.

04-reminders-panel-empty

5. Reminders panel — active pending reminder

A reminder scheduled for the future, showing in the "Upcoming" or "Today" group.

05-reminders-panel-active

6. Reminders panel — fired/overdue reminder

A reminder past its due time, shown in the "Overdue" group with urgency styling.

06-reminders-panel-fired

wpfleger96 pushed a commit that referenced this pull request Jun 11, 2026
Co-authored-by: Will Pfleger <wpfleger@squareup.com>
Signed-off-by: Will Pfleger <wpfleger@squareup.com>
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