Messaging: add explicit Delete button to the conversation header

The list-row trash is always-visible now, but add an unmissable "Delete"
button in the open-conversation header (ChatView) too. Deletes the whole 1:1
conversation for everyone and clears the selection.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-17 20:04:50 -04:00
parent 53765e1448
commit fe78c25fd1
2 changed files with 50 additions and 4 deletions
+45 -3
View File
@@ -1,6 +1,6 @@
import { useState, useRef, useEffect } from "react";
import { useAuth } from "@/contexts/AuthContext";
import { useChatMessages, usePartnerInfo } from "@/hooks/useDirectMessages";
import { useChatMessages, usePartnerInfo, STAFF_GROUP_ID } from "@/hooks/useDirectMessages";
import { supabase } from "@/integrations/supabase/client";
import { ScrollArea } from "@/components/ui/scroll-area";
import { Button } from "@/components/ui/button";
@@ -19,6 +19,7 @@ import {
interface Props {
partnerId: string | null;
partnerName: string;
onDeleted?: () => void;
}
function getInitials(name: string) {
@@ -32,12 +33,26 @@ function formatMessageDate(dateStr: string) {
return format(d, "MMM d, h:mm a");
}
export default function ChatView({ partnerId, partnerName }: Props) {
export default function ChatView({ partnerId, partnerName, onDeleted }: Props) {
const { user, isAdmin, isStaff } = useAuth();
const { messages, loading, sendMessage, deleteMessage } = useChatMessages(partnerId);
const partnerInfo = usePartnerInfo(partnerId);
const [draft, setDraft] = useState("");
const [sending, setSending] = useState(false);
const [deleteConvOpen, setDeleteConvOpen] = useState(false);
const canDeleteConversation = !!partnerId && partnerId !== STAFF_GROUP_ID;
const deleteConversation = async () => {
if (!user || !partnerId) return;
const { error } = await supabase
.from("direct_messages")
.delete()
.or(`and(sender_id.eq.${user.id},recipient_id.eq.${partnerId}),and(sender_id.eq.${partnerId},recipient_id.eq.${user.id})`);
setDeleteConvOpen(false);
if (error) { toast({ title: "Couldn't delete conversation", description: error.message, variant: "destructive" }); return; }
toast({ title: "Conversation deleted" });
onDeleted?.();
};
const [creatingRequestId, setCreatingRequestId] = useState<string | null>(null);
const [deletingId, setDeletingId] = useState<string | null>(null);
const scrollRef = useRef<HTMLDivElement>(null);
@@ -133,7 +148,7 @@ export default function ChatView({ partnerId, partnerName }: Props) {
{getInitials(partnerName)}
</AvatarFallback>
</Avatar>
<div className="min-w-0">
<div className="min-w-0 flex-1">
<div className="font-semibold text-sm truncate">{partnerName}</div>
{partnerInfo && (partnerInfo.ownerName || partnerInfo.unit || partnerInfo.associationName) && (
<div className="text-[11px] text-muted-foreground truncate">
@@ -141,8 +156,35 @@ export default function ChatView({ partnerId, partnerName }: Props) {
</div>
)}
</div>
{canDeleteConversation && (
<Button
variant="ghost"
size="sm"
className="shrink-0 gap-1 text-muted-foreground hover:text-destructive"
onClick={() => setDeleteConvOpen(true)}
>
<Trash2 className="h-4 w-4" /> Delete
</Button>
)}
</div>
<AlertDialog open={deleteConvOpen} onOpenChange={setDeleteConvOpen}>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>Delete this conversation?</AlertDialogTitle>
<AlertDialogDescription>
This permanently deletes the conversation with {partnerName} for everyone. This can't be undone.
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel>Cancel</AlertDialogCancel>
<AlertDialogAction className="bg-destructive text-destructive-foreground hover:bg-destructive/90" onClick={deleteConversation}>
Delete
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
{/* Messages */}
<div ref={scrollRef} className="flex-1 overflow-y-auto px-4 py-4 space-y-3">
{loading ? (
+5 -1
View File
@@ -62,7 +62,11 @@ export default function MessagesPage() {
onMessageWholeBoard={handleMessageWholeBoard}
/>
</div>
<ChatView partnerId={selectedPartnerId} partnerName={partnerName} />
<ChatView
partnerId={selectedPartnerId}
partnerName={partnerName}
onDeleted={() => { setSelectedPartnerId(null); setPartnerName(""); }}
/>
</div>
</TabsContent>