Merge pull request #38 from jieyitang/master

feat: Add delete function for single message
This commit is contained in:
BeilunYang
2025-03-16 15:17:36 +08:00
committed by GitHub
3 changed files with 140 additions and 4 deletions

View File

@@ -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

View File

@@ -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<Timer>()
const messagesRef = useRef<Message[]>([]) // 添加 ref 来追踪最新的消息列表
const [total, setTotal] = useState(0)
const [messageToDelete, setMessageToDelete] = useState<Message | null>(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 (
<>
<div className="h-full flex flex-col">
<div className="p-2 flex justify-between items-center border-b border-primary/20">
<Button
@@ -160,7 +212,7 @@ export function MessageList({ email, onMessageSelect, selectedMessageId }: Messa
key={message.id}
onClick={() => onMessageSelect(message.id)}
className={cn(
"p-3 hover:bg-primary/5 cursor-pointer",
"p-3 hover:bg-primary/5 cursor-pointer group",
selectedMessageId === message.id && "bg-primary/10"
)}
>
@@ -176,6 +228,17 @@ export function MessageList({ email, onMessageSelect, selectedMessageId }: Messa
</span>
</div>
</div>
<Button
variant="ghost"
size="icon"
className="opacity-0 group-hover:opacity-100 h-8 w-8"
onClick={(e) => {
e.stopPropagation()
setMessageToDelete(message)
}}
>
<Trash2 className="h-4 w-4 text-destructive" />
</Button>
</div>
</div>
))}
@@ -192,5 +255,25 @@ export function MessageList({ email, onMessageSelect, selectedMessageId }: Messa
)}
</div>
</div>
<AlertDialog open={!!messageToDelete} onOpenChange={() => setMessageToDelete(null)}>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle></AlertDialogTitle>
<AlertDialogDescription>
{messageToDelete?.subject}
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel></AlertDialogCancel>
<AlertDialogAction
className="bg-destructive hover:bg-destructive/90"
onClick={() => messageToDelete && handleDelete(messageToDelete)}
>
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
</>
)
}

View File

@@ -45,7 +45,10 @@ export function ThreeColumnLayout() {
</div>
<div className="flex-1 overflow-auto">
<EmailList
onEmailSelect={setSelectedEmail}
onEmailSelect={(email) => {
setSelectedEmail(email)
setSelectedMessageId(null)
}}
selectedEmailId={selectedEmail?.id}
/>
</div>