Skip to content

E-Mail-Snnoze (WIP)#589

Merged
dspangenberg merged 3 commits into
mainfrom
develop
Jul 15, 2026
Merged

E-Mail-Snnoze (WIP)#589
dspangenberg merged 3 commits into
mainfrom
develop

Conversation

@dspangenberg

@dspangenberg dspangenberg commented Jul 15, 2026

Copy link
Copy Markdown
Owner

Summary by CodeRabbit

  • Neue Funktionen

    • E-Mails lassen sich mit „Erneut erinnern“ bis zu einem gewählten Zeitpunkt snoozen.
    • Neuer Snooze-Button mit Dropdown-Zeitoptionen (z. B. heute, morgen, nächste Woche) und Option zum Unsnooze.
    • Bereitstellung/Anzeige der Snooze-Info in der E-Mail-Ansicht.
  • Verbesserungen

    • Umbenennung der Snooze-Ansicht sowie bessere Darstellung von Datum und Anhängen in der E-Mail-Liste.
    • Einheitlichere Menüdarstellung (u. a. Icon-/Shortcut-Handling).
  • Bug Fixes

    • Snoozed-Status wird in der „Gesendet“-Ansicht korrekt ausgefiltert.
  • Chores

    • Regelmäßiger Hintergrundjob zum automatischen Unsnooze (alle 1 Minute).

@coderabbitai

coderabbitai Bot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@dspangenberg, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 47 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: d419c4cb-1dab-4148-a300-c6004ab26463

📥 Commits

Reviewing files that changed from the base of the PR and between afa9d59 and 9e03a94.

📒 Files selected for processing (2)
  • app/Console/Commands/SnoozeCommand.php
  • resources/js/Pages/App/Email/EmailIndex.tsx

Walkthrough

Die Änderung ergänzt Snooze- und Unsnooze-Endpunkte, erweitert Mail-Daten und Ansichtsfilter, verarbeitet abgelaufene Snoozes automatisch und integriert eine zeitbasierte Snooze-Auswahl samt Statusanzeige in die E-Mail-Oberfläche.

Changes

E-Mail-Snooze

Layer / File(s) Summary
Mail-Daten und Ansichtsfilter
app/Data/DropboxMailData.php, app/Models/DropboxMail.php, resources/js/Types/generated.d.ts, resources/typescript-transformer-manifest.json
snoozed_until wird als nullable Datumsfeld ergänzt, speicherbar gemacht und für bestimmte Ansichten auf NULL gefiltert.
Snooze-Endpunkte
app/Http/Requests/DropboxMailSnoozeRequest.php, app/Http/Controllers/App/EmailController.php, routes/tenant.php
Neue PUT-Routen validieren, setzen und löschen Snooze-Zeitpunkte; beim Archivieren wird der Snooze entfernt.
Snooze-Auswahl und Toolbar
resources/js/Pages/App/Email/EmailSnoozeButton.tsx, resources/js/Pages/App/Email/EmailIndex.tsx
Ein Dropdown berechnet zukünftige Zeitpunkte und sendet Snooze- oder Unsnooze-Anfragen; Toolbar und Navigation verwenden die neue Komponente.
Snooze-Status und Menü-Darstellung
resources/js/Pages/App/Email/Email.tsx, resources/js/Components/twc-ui/menu.tsx, resources/js/Pages/App/Email/EmailIndexEntry.tsx
Gesnozte E-Mails zeigen ihren Erinnerungszeitpunkt; Menüoptionen und Listendarstellung erhalten angepasste Eigenschaften und Formatierungen.
Automatische Unsnooze-Verarbeitung
app/Console/Commands/SnoozeCommand.php, routes/console.php
Ein minütlich geplanter Command hebt abgelaufene Snoozes auf, setzt Mailstatus zurück und versendet Benachrichtigungen.

Estimated code review effort: 3 (Moderate) | ~30 minutes

Sequence Diagram(s)

sequenceDiagram
  participant E-Mail-Nutzer
  participant EmailSnoozeButton
  participant EmailController
  participant DropboxMail
  E-Mail-Nutzer->>EmailSnoozeButton: Snooze-Zeitpunkt auswählen
  EmailSnoozeButton->>EmailController: PUT snooze mit formatiertem Zeitpunkt
  EmailController->>DropboxMail: snoozed_until speichern
  DropboxMail-->>EmailController: Mail speichern
  EmailController-->>EmailSnoozeButton: Zurückleitung
Loading

Possibly related PRs

Poem

Hoppel, die Mail ruht sacht,
bis sie wieder „klick“ macht.
Snooze hält sie im Hasenbau,
der Wecker ruft sie pünktlich schlau.
hopp hopp, zurück im Postfach!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive Der Titel ist thematisch passend, aber wegen Tippfehler und dem generischen „WIP“ zu unpräzise. Bitte einen kurzen, konkreten Titel wählen, z. B. „E-Mails snoozen und unsnoozen einführen“.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch develop

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

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🧹 Nitpick comments (2)
resources/js/Pages/App/Email/EmailIndex.tsx (1)

49-62: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Unbenutzten Code und console.log entfernen.

Die Funktionen midday, afternoon, tomorrow sowie der console.log-Aufruf werden nicht verwendet und sind vermutlich Überbleibsel der Auslagerung in die Komponente EmailSnoozeButton. Sie sollten aus Gründen der Übersichtlichkeit entfernt werden.

♻️ Vorgeschlagene Änderung
-  const midday = () => {
-    return setHours(startOfToday(), 12)
-  }
-
-  const afternoon = () => {
-    return setHours(startOfToday(), 17)
-  }
-
-  const tomorrow = () => {
-    return setHours(startOfTomorrow(), 9)
-  }
-
-  console.log(tomorrow())
-
   const handleRestore = async () => {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@resources/js/Pages/App/Email/EmailIndex.tsx` around lines 49 - 62, Remove the
unused midday, afternoon, and tomorrow helper functions and delete the
console.log(tomorrow()) call from the component, leaving the existing
EmailSnoozeButton behavior unchanged.
resources/js/Components/twc-ui/menu.tsx (1)

78-79: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Unbenutzte Property simpleShortcut entfernen.

Die Property simpleShortcut wurde in diesem PR neu eingeführt, wird aber im Rendern der Komponente nicht verwendet.

  • resources/js/Components/twc-ui/menu.tsx#L78-L79: Entferne simpleShortcut?: boolean aus dem Interface.
  • resources/js/Components/twc-ui/menu.tsx#L101-L104: Entferne simpleShortcut = false, aus der Destrukturierung der Props.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@resources/js/Components/twc-ui/menu.tsx` around lines 78 - 79, Remove the
unused simpleShortcut property from the props interface and remove its default
value from the component props destructuring in
resources/js/Components/twc-ui/menu.tsx at lines 78-79 and 101-104; no other
prop behavior needs to change.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@app/Http/Controllers/App/EmailController.php`:
- Around line 195-209: Update snooze() and unsnooze() to enforce the same
Dropbox access and mail-to-Dropbox relationship checks used by archive() and
unarchive() before modifying DropboxMail. Reuse the existing authorization
pattern and ensure mail->dropbox_id matches dropbox->id, while preserving the
current snooze and unsnooze behavior after validation.

In `@app/Http/Requests/DropboxMailSnoozeRequest.php`:
- Line 17: Update the validation rules for snoozed_until in
DropboxMailSnoozeRequest to require a timestamp strictly after the current time,
while preserving the existing required, date, and date_format:d.m.Y H:i
validations.

In `@app/Models/DropboxMail.php`:
- Line 73: Update the archived filter in the query configuration to require both
a non-null archived_at and a null snoozed_until, ensuring snoozed mails appear
only in the snooze view while preserving the existing archive condition for
non-snoozed mails.
- Around line 71-75: Update the status query branches in DropboxMail’s status
filtering logic so only future snoozed_until values remain in the snoozed view,
while expired snoozes are included in the normal inbox/sent views. Use now() for
the time comparison and preserve the existing archived, inbound, and trashed
conditions.

In `@resources/js/Pages/App/Email/EmailSnoozeButton.tsx`:
- Around line 19-22: Erweitere in
resources/js/Pages/App/Email/EmailSnoozeButton.tsx im Interface
EmailSnoozeButtonProps den Typ von mail auf optional sowie null-zulässig. Füge
am Anfang von onSnooze und onUnSnooze jeweils eine Prüfung ein, die bei
fehlendem mail sofort zurückkehrt, bevor auf mail.id zugegriffen wird.

---

Nitpick comments:
In `@resources/js/Components/twc-ui/menu.tsx`:
- Around line 78-79: Remove the unused simpleShortcut property from the props
interface and remove its default value from the component props destructuring in
resources/js/Components/twc-ui/menu.tsx at lines 78-79 and 101-104; no other
prop behavior needs to change.

In `@resources/js/Pages/App/Email/EmailIndex.tsx`:
- Around line 49-62: Remove the unused midday, afternoon, and tomorrow helper
functions and delete the console.log(tomorrow()) call from the component,
leaving the existing EmailSnoozeButton behavior unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 7fb942d0-543a-494a-be8b-4ba7f53f22b2

📥 Commits

Reviewing files that changed from the base of the PR and between 19e17bc and e89a2e1.

📒 Files selected for processing (12)
  • app/Data/DropboxMailData.php
  • app/Http/Controllers/App/EmailController.php
  • app/Http/Requests/DropboxMailSnoozeRequest.php
  • app/Models/DropboxMail.php
  • resources/js/Components/twc-ui/menu.tsx
  • resources/js/Pages/App/Email/Email.tsx
  • resources/js/Pages/App/Email/EmailIndex.tsx
  • resources/js/Pages/App/Email/EmailIndexEntry.tsx
  • resources/js/Pages/App/Email/EmailSnoozeButton.tsx
  • resources/js/Types/generated.d.ts
  • resources/typescript-transformer-manifest.json
  • routes/tenant.php

Comment thread app/Http/Controllers/App/EmailController.php
Comment thread app/Http/Requests/DropboxMailSnoozeRequest.php Outdated
Comment on lines +71 to +75
'sent' => $query->whereNull('archived_at')->where('is_inbound', false)->whereNull('snoozed_until'),
'snoozed' => $query->whereNotNull('snoozed_until'),
'archived' => $query->whereNotNull('archived_at'),
'trash' => $query->onlyTrashed(),
default => $query->whereNull('archived_at')->where('is_inbound', true),
default => $query->whereNull('snoozed_until')->whereNull('archived_at')->where('is_inbound', true),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Abgelaufene Snoozes müssen wieder sichtbar werden.

whereNotNull('snoozed_until') behandelt auch bereits abgelaufene Zeitpunkte als aktiv. Dadurch bleiben solche Mails aus Inbox/Sent ausgeschlossen und erscheinen dauerhaft im Snooze-View. Vergleiche mit now() und berücksichtige abgelaufene Werte wieder in den normalen Ansichten oder räume sie serverseitig auf.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/Models/DropboxMail.php` around lines 71 - 75, Update the status query
branches in DropboxMail’s status filtering logic so only future snoozed_until
values remain in the snoozed view, while expired snoozes are included in the
normal inbox/sent views. Use now() for the time comparison and preserve the
existing archived, inbound, and trashed conditions.

'sent' => $query->whereNull('archived_at')->where('is_inbound', false),
'sent' => $query->whereNull('archived_at')->where('is_inbound', false)->whereNull('snoozed_until'),
'snoozed' => $query->whereNotNull('snoozed_until'),
'archived' => $query->whereNotNull('archived_at'),

@coderabbitai coderabbitai Bot Jul 15, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Die Archiv-Ansicht muss Snoozes ausschließen.

Eine Mail mit gesetztem archived_at und snoozed_until erscheint derzeit sowohl unter „Archiv“ als auch unter „Erneut erinnern“. Ergänze im archived-Zweig whereNull('snoozed_until'), sofern die Snooze-Ansicht exklusiv sein soll.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/Models/DropboxMail.php` at line 73, Update the archived filter in the
query configuration to require both a non-null archived_at and a null
snoozed_until, ensuring snoozed mails appear only in the snooze view while
preserving the existing archive condition for non-snoozed mails.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Snoozed und archived dürfte nicht vorkommen. eher button ausblenden oder?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
rg -n "archive" resources/js/Pages/App/Email/*.tsx -i
rg -n "function archive|->archive|archived_at" app/Http/Controllers/App/EmailController.php

Length of output: 1982


🏁 Script executed:

#!/bin/bash
sed -n '195,240p' app/Http/Controllers/App/EmailController.php

Length of output: 1502


Confirmed: archive() neither clears snoozed_until nor checks it, and snooze() doesn't clear archived_at. So the button/UI approach alone won't prevent the inconsistent state, since both actions are independent backend endpoints reachable regardless of which button is currently shown (e.g., a mail could be archived first, then later a snooze action could still be triggered from another view, or vice versa).

@dspangenberg Das UI-Ausblenden ist sinnvoll und verbessert die UX, löst das Problem aber nicht vollständig: archive() prüft/löscht snoozed_until nicht, und snooze()/unsnooze() prüfen/löschen archived_at nicht. Beide Endpunkte sind unabhängig vom aktuell angezeigten Button erreichbar (z. B. via direktem Request oder wenn der Nutzer die Seite zwischen zwei Ansichten wechselt), sodass der inkonsistente Zustand weiterhin entstehen kann.

Ich würde daher beides kombinieren:

  1. UI: Snooze-/Archiv-Buttons gegenseitig ausblenden, wenn der jeweils andere Zustand aktiv ist (z. B. EmailSnoozeButton deaktivieren, wenn mail.archived_at gesetzt ist, und den Archiv-Button ausblenden, wenn mail.snoozed_until gesetzt ist).
  2. Backend: Bei archive() zusätzlich snoozed_until = null setzen und bei snooze() zusätzlich archived_at = null setzen, damit der Zustand auch bei direkten Requests konsistent bleibt.

Damit wäre der Ausgangsvorschlag (Filter in scopeView) dann auch nur noch eine zusätzliche Absicherung und kein Muss – aber ich würde ihn trotzdem behalten, falls es Altdaten oder Edge Cases gibt.

Soll ich das im Detail als `` ausarbeiten (Backend + UI)?


✏️ Learnings added
Learnt from: dspangenberg
Repo: dspangenberg/opsc PR: 589
File: app/Models/DropboxMail.php:73-73
Timestamp: 2026-07-15T13:54:08.762Z
Learning: In app/Http/Controllers/App/EmailController.php, the `archive()` method sets `archived_at = now()` without clearing `snoozed_until`, and `snooze()`/`unsnooze()` set `snoozed_until` without clearing `archived_at`. If both fields should be mutually exclusive on `DropboxMail`, both backend methods need to clear the opposing field, not just UI buttons in resources/js/Pages/App/Email/EmailIndex.tsx and EmailSnoozeButton.tsx.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


The requested changes have been implemented and a pull request has been created: View PR

Comment thread resources/js/Pages/App/Email/EmailSnoozeButton.tsx

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@app/Console/Commands/SnoozeCommand.php`:
- Around line 29-30: Update the SnoozeCommand::handle method return type from
bool to int so it matches the integer exit codes it returns and Laravel/Symfony
command expectations. Preserve the existing 0 and 1 return behavior.
- Around line 62-64: Guard the GeneralNotificationEvent::dispatch call in
SnoozeCommand so it runs only when $mail->dropbox->user is present. Skip
notification dispatch for dropboxes without an associated user, while preserving
the existing “Unsnoozed E-Mail” notification for valid User instances.

In `@resources/js/Pages/App/Email/EmailIndex.tsx`:
- Line 126: Update the EmailSnoozeButton visibility condition in EmailIndex so
it also renders when view === 'snoozed', while preserving its existing
availability for the inbox and sent views.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: ea4687ba-1499-4378-bbe0-40a6e47cc56b

📥 Commits

Reviewing files that changed from the base of the PR and between e89a2e1 and afa9d59.

📒 Files selected for processing (6)
  • app/Console/Commands/SnoozeCommand.php
  • app/Http/Controllers/App/EmailController.php
  • app/Http/Requests/DropboxMailSnoozeRequest.php
  • resources/js/Pages/App/Email/EmailIndex.tsx
  • resources/js/Pages/App/Email/EmailSnoozeButton.tsx
  • routes/console.php
🚧 Files skipped from review as they are similar to previous changes (3)
  • app/Http/Requests/DropboxMailSnoozeRequest.php
  • app/Http/Controllers/App/EmailController.php
  • resources/js/Pages/App/Email/EmailSnoozeButton.tsx

Comment thread app/Console/Commands/SnoozeCommand.php Outdated
Comment thread app/Console/Commands/SnoozeCommand.php Outdated
Comment thread resources/js/Pages/App/Email/EmailIndex.tsx Outdated
@dspangenberg
dspangenberg merged commit 6cf6ad6 into main Jul 15, 2026
3 checks passed
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