Implement delete chat with confirmation dialog

This commit is contained in:
Pablo de la Torre Jamardo 2025-07-20 19:54:10 +02:00
parent 3d7ba68511
commit c5e72d5708
4 changed files with 226 additions and 4 deletions

View File

@ -6,6 +6,7 @@
:current-chat-id="chatUuid"
@select-chat="selectChat"
@create-chat="createNewChat"
@delete-chat="deleteChat"
/>
<!-- Área principal del chat -->
@ -48,6 +49,9 @@ const loadHistory = async () => {
// Cargar mensajes de un chat específico
const loadMessages = async (selectedChatId) => {
if (!chatUuid.value) {
return;
}
try {
const data = await chatService.getChatMessages(selectedChatId)
messages.value = data
@ -76,6 +80,18 @@ const createNewChat = async () => {
}
}
// Eliminar un chat
const deleteChat = async () => {
try {
await chatService.deleteChat(chatUuid.value)
chatUuid.value = null;
await loadHistory()
await loadMessages(chatUuid.value)
} catch (error) {
console.error("Error al crear nuevo chat:", error)
}
}
// Enviar mensaje
const sendMessage = async (prompt) => {
// Crear nuevo chat si no existe

View File

@ -9,15 +9,31 @@
v-for="chat in chats"
:key="chat.conversationId"
:class="{ active: chat.conversationId === currentChatId }"
@click="$emit('select-chat', chat.conversationId)"
>
{{ chat.title }}
@click="$emit('select-chat', chat.conversationId)">
<span class="chat-title">{{ chat.title }}</span>
<button
aria-label="Eliminar chat"
class="delete-btn"
title="Eliminar chat"
@click.stop="onDeleteClick(chat.conversationId)">
</button>
</li>
</ul>
<ConfirmDialog
:visible="showConfirm"
message="¿Seguro que quieres eliminar este chat?"
title="Confirmar borrado"
@cancel="onCancel"
@confirm="onConfirm"
/>
</aside>
</template>
<script setup>
import {ref} from "vue"
import ConfirmDialog from "./ConfirmDialog.vue"
defineProps({
chats: {
type: Array,
@ -29,7 +45,29 @@ defineProps({
}
})
defineEmits(['select-chat', 'create-chat'])
const emit = defineEmits(['select-chat', 'create-chat', 'delete-chat'])
const showConfirm = ref(false)
const chatToDelete = ref(null)
function onDeleteClick(chatId) {
chatToDelete.value = chatId
showConfirm.value = true
}
function onConfirm() {
showConfirm.value = false
if (chatToDelete.value) {
emit('delete-chat', chatToDelete.value)
chatToDelete.value = null
}
}
function onCancel() {
showConfirm.value = false
chatToDelete.value = null
}
</script>
<style scoped>
@ -92,4 +130,51 @@ defineEmits(['select-chat', 'create-chat'])
color: white;
font-weight: bold;
}
li {
display: flex;
align-items: center;
justify-content: space-between;
padding: 0.5rem 0.75rem;
cursor: pointer;
border-radius: 8px;
transition: background-color 0.2s ease;
font-size: 0.95rem;
}
li:hover {
background-color: #2c2f3a;
}
li.active {
background-color: #3451d1;
color: white;
font-weight: bold;
}
.chat-title {
flex-grow: 1;
user-select: none;
}
.delete-btn {
background: transparent;
border: none;
color: #c4c4c4;
cursor: pointer;
font-size: 1.1rem;
padding: 0 0.3rem;
opacity: 0;
transition: opacity 0.3s ease, color 0.3s ease;
user-select: none;
}
li:hover .delete-btn {
opacity: 1;
}
.delete-btn:hover {
color: #ff4d4f;
}
</style>

View File

@ -0,0 +1,105 @@
<template>
<transition name="fade">
<div v-if="visible" class="overlay" @click.self="cancel">
<div class="dialog">
<h3>{{ title }}</h3>
<p>{{ message }}</p>
<div class="buttons">
<button class="btn cancel" @click="cancel">Cancelar</button>
<button class="btn confirm" @click="confirm">Confirmar</button>
</div>
</div>
</div>
</transition>
</template>
<script setup>
const props = defineProps({
visible: Boolean,
title: {type: String, default: "Confirmación"},
message: {type: String, default: "¿Estás seguro?"},
})
const emit = defineEmits(["confirm", "cancel"])
const confirm = () => emit("confirm")
const cancel = () => emit("cancel")
</script>
<style scoped>
.overlay {
position: fixed;
inset: 0;
background-color: rgba(0, 0, 0, 0.5);
display: flex;
justify-content: center;
align-items: center;
z-index: 1000;
}
.dialog {
background: white;
padding: 1.5rem;
border-radius: 12px;
width: 320px;
max-width: 90vw;
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.2);
text-align: center;
animation: popin 0.2s ease-out;
color: #333;
}
.buttons {
margin-top: 1.5rem;
display: flex;
gap: 1rem;
justify-content: center;
}
.btn {
padding: 0.6rem 1.2rem;
border-radius: 6px;
border: none;
cursor: pointer;
font-weight: 500;
font-size: 0.95rem;
transition: background 0.2s ease;
}
.btn.cancel {
background: #e0e0e0;
color: #333;
}
.btn.cancel:hover {
background: #d5d5d5;
}
.btn.confirm {
background: #e53935;
color: white;
}
.btn.confirm:hover {
background: #c62828;
}
.fade-enter-active, .fade-leave-active {
transition: opacity 0.25s ease;
}
.fade-enter-from, .fade-leave-to {
opacity: 0;
}
@keyframes popin {
from {
transform: scale(0.9);
opacity: 0;
}
to {
transform: scale(1);
opacity: 1;
}
}
</style>

View File

@ -39,6 +39,22 @@ class ChatService {
}
}
async deleteChat(chatId) {
try {
const response = await fetch(`/api/v1/conversations/${chatId}`, {
method: "DELETE",
})
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`)
}
return true
} catch (error) {
console.error("Error removing chat:", error)
toast.error("Could not removing chat")
throw error
}
}
async getChatMessages(chatId) {
try {
const response = await fetch(`/api/v1/conversations/${chatId}/messages`)