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