From eb8023280be0e43f645daf93dd224633047525f2 Mon Sep 17 00:00:00 2001
From: jieyitang <14948774+jieyitang@users.noreply.github.com>
Date: Fri, 14 Mar 2025 16:48:54 +0800
Subject: [PATCH 1/2] fix: prevent unnecessary requests when switching emails
---
app/components/emails/three-column-layout.tsx | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/app/components/emails/three-column-layout.tsx b/app/components/emails/three-column-layout.tsx
index eb2a54e..0ca9558 100644
--- a/app/components/emails/three-column-layout.tsx
+++ b/app/components/emails/three-column-layout.tsx
@@ -45,7 +45,10 @@ export function ThreeColumnLayout() {
{
+ setSelectedEmail(email)
+ setSelectedMessageId(null)
+ }}
selectedEmailId={selectedEmail?.id}
/>
From 21d09a2cb0d5a018bc9a16ba3e789dd7636395fe Mon Sep 17 00:00:00 2001
From: jieyitang <14948774+jieyitang@users.noreply.github.com>
Date: Fri, 14 Mar 2025 16:52:38 +0800
Subject: [PATCH 2/2] feat: add delete function for single email message
---
app/api/emails/[id]/[messageId]/route.ts | 50 +++++++++++++
app/components/emails/message-list.tsx | 89 +++++++++++++++++++++++-
2 files changed, 136 insertions(+), 3 deletions(-)
diff --git a/app/api/emails/[id]/[messageId]/route.ts b/app/api/emails/[id]/[messageId]/route.ts
index 891be33..71e59cb 100644
--- a/app/api/emails/[id]/[messageId]/route.ts
+++ b/app/api/emails/[id]/[messageId]/route.ts
@@ -5,6 +5,56 @@ import { and, eq } from "drizzle-orm"
import { getUserId } from "@/lib/apiKey"
export const runtime = "edge"
+export async function DELETE(
+ request: Request,
+ { params }: { params: Promise<{ id: string; messageId: string }> }
+) {
+ const userId = await getUserId()
+
+ try {
+ const db = createDb()
+ const { id, messageId } = await params
+ const email = await db.query.emails.findFirst({
+ where: and(
+ eq(emails.id, id),
+ eq(emails.userId, userId!)
+ )
+ })
+
+ if (!email) {
+ return NextResponse.json(
+ { error: "Email not found or no permission to view" },
+ { status: 403 }
+ )
+ }
+
+ const message = await db.query.messages.findFirst({
+ where: and(
+ eq(messages.emailId, id),
+ eq(messages.id, messageId)
+ )
+ })
+
+ if(!message) {
+ return NextResponse.json(
+ { error: "Message not found or already deleted" },
+ { status: 404 }
+ )
+ }
+
+ await db.delete(messages)
+ .where(eq(messages.id, messageId))
+
+ return NextResponse.json({ success: true })
+ } catch (error) {
+ console.error('Failed to delete email:', error)
+ return NextResponse.json(
+ { error: "Failed to delete message" },
+ { status: 500 }
+ )
+ }
+}
+
export async function GET(_request: Request, { params }: { params: Promise<{ id: string; messageId: string }> }) {
try {
const { id, messageId } = await params
diff --git a/app/components/emails/message-list.tsx b/app/components/emails/message-list.tsx
index 61b6335..1a4e346 100644
--- a/app/components/emails/message-list.tsx
+++ b/app/components/emails/message-list.tsx
@@ -1,11 +1,22 @@
"use client"
import { useState, useEffect, useRef } from "react"
-import { Mail, Calendar, RefreshCw } from "lucide-react"
+import {Mail, Calendar, RefreshCw, Trash2} from "lucide-react"
import { cn } from "@/lib/utils"
import { Button } from "@/components/ui/button"
import { useThrottle } from "@/hooks/use-throttle"
import { EMAIL_CONFIG } from "@/config"
+import { useToast } from "@/components/ui/use-toast"
+import {
+ AlertDialog,
+ AlertDialogAction,
+ AlertDialogCancel,
+ AlertDialogContent,
+ AlertDialogDescription,
+ AlertDialogFooter,
+ AlertDialogHeader,
+ AlertDialogTitle
+} from "@/components/ui/alert-dialog";
interface Message {
id: string
@@ -19,7 +30,7 @@ interface MessageListProps {
id: string
address: string
}
- onMessageSelect: (messageId: string) => void
+ onMessageSelect: (messageId: string | null) => void
selectedMessageId?: string | null
}
@@ -38,6 +49,8 @@ export function MessageList({ email, onMessageSelect, selectedMessageId }: Messa
const pollTimeoutRef = useRef()
const messagesRef = useRef([]) // 添加 ref 来追踪最新的消息列表
const [total, setTotal] = useState(0)
+ const [messageToDelete, setMessageToDelete] = useState(null)
+ const { toast } = useToast()
// 当 messages 改变时更新 ref
useEffect(() => {
@@ -118,6 +131,44 @@ export function MessageList({ email, onMessageSelect, selectedMessageId }: Messa
}
}, 200)
+ const handleDelete = async (message: Message) => {
+ try {
+ const response = await fetch(`/api/emails/${email.id}/${message.id}`, {
+ method: "DELETE"
+ })
+
+ if (!response.ok) {
+ const data = await response.json()
+ toast({
+ title: "错误",
+ description: (data as { error: string }).error,
+ variant: "destructive"
+ })
+ return
+ }
+
+ setMessages(prev => prev.filter(e => e.id !== message.id))
+ setTotal(prev => prev - 1)
+
+ toast({
+ title: "成功",
+ description: "邮件已删除"
+ })
+
+ if (selectedMessageId === message.id) {
+ onMessageSelect(null)
+ }
+ } catch {
+ toast({
+ title: "错误",
+ description: "删除邮件失败",
+ variant: "destructive"
+ })
+ } finally {
+ setMessageToDelete(null)
+ }
+ }
+
useEffect(() => {
if (!email.id) {
return
@@ -134,6 +185,7 @@ export function MessageList({ email, onMessageSelect, selectedMessageId }: Messa
}, [email.id])
return (
+ <>
+
))}
@@ -192,5 +255,25 @@ export function MessageList({ email, onMessageSelect, selectedMessageId }: Messa
)}
+ setMessageToDelete(null)}>
+
+
+ 确认删除
+
+ 确定要删除邮件 {messageToDelete?.subject} 吗?
+
+
+
+ 取消
+ messageToDelete && handleDelete(messageToDelete)}
+ >
+ 删除
+
+
+
+
+ >
)
}
\ No newline at end of file