diff --git a/src/app/(inbox)/email/[id]/page.tsx b/src/app/(inbox)/email/[id]/page.tsx
index 3bbb338..bf85706 100644
--- a/src/app/(inbox)/email/[id]/page.tsx
+++ b/src/app/(inbox)/email/[id]/page.tsx
@@ -3,7 +3,6 @@ import { getSession, getAccountId, getEmail } from "@/lib/jmap";
import { formatAddressList, formatFullDate } from "@/lib/format";
import { notFound } from "next/navigation";
import EmailBody from "@/components/EmailBody";
-import MarkAsRead from "@/components/MarkAsRead";
export const dynamic = "force-dynamic";
@@ -43,7 +42,6 @@ export default async function EmailPage({ params }: Props) {
return (
-
{/* Subject */}
diff --git a/src/components/EmailListPanel.tsx b/src/components/EmailListPanel.tsx
index fbe9348..6a3112c 100644
--- a/src/components/EmailListPanel.tsx
+++ b/src/components/EmailListPanel.tsx
@@ -1,9 +1,11 @@
"use client";
import Link from "next/link";
+import { useEffect, useState } from "react";
import { usePathname } from "next/navigation";
import { Email } from "@/lib/types";
import { formatAddressList, formatDate } from "@/lib/format";
+import { markEmailAsRead } from "@/app/(inbox)/email/[id]/actions";
interface Props {
emails: Email[];
@@ -16,6 +18,21 @@ export default function EmailListPanel({ emails, unreadCount = 0 }: Props) {
? pathname.slice("/email/".length)
: undefined;
+ // Track emails marked read this session so the list stays accurate
+ // even though the layout's server data is only fetched once.
+ const [clientReadIds, setClientReadIds] = useState(new Set());
+
+ useEffect(() => {
+ if (!selectedId) return;
+ const email = emails.find((e) => e.id === selectedId);
+ if (!email) return;
+ const alreadyRead = !!email.keywords?.["$seen"] || clientReadIds.has(selectedId);
+ if (!alreadyRead) {
+ setClientReadIds((prev) => new Set([...prev, selectedId]));
+ markEmailAsRead(selectedId);
+ }
+ }, [selectedId]); // eslint-disable-line react-hooks/exhaustive-deps
+
return (
{/* Header */}
@@ -43,7 +60,10 @@ export default function EmailListPanel({ emails, unreadCount = 0 }: Props) {
)}
{emails.map((email) => {
const isSelected = email.id === selectedId;
- const isUnread = email.id !== selectedId && !email.keywords?.["$seen"];
+ const isUnread =
+ !email.keywords?.["$seen"] &&
+ !clientReadIds.has(email.id) &&
+ email.id !== selectedId;
return (
{
- if (!alreadyRead) {
- markEmailAsRead(emailId);
- }
- }, [emailId, alreadyRead]);
-
- return null;
-}