13. Detalle de un Chatbot

 

Detalle de un Chatbot

1. Configuración de la Ruta de Detalle

1.1. Actualizar el Botón "Ver" en el Listado

En ChatbotListItem.vue:

vue

<script setup>

import { EyeIcon, PencilIcon, TrashIcon } from '@heroicons/vue/24/solid'

import { PrimaryButton, SecondaryButton, DangerButton } from '@/Components/Buttons'


const emit = defineEmits(['delete'])


defineProps({

    chatbot: {

        type: Object,

        required: true

    }

})

</script>


<template>

    <div class="flex flex-col md:flex-row md:items-center md:justify-between py-4">

        <div class="flex-1">

            <div class="text-gray-800 dark:text-gray-200 font-medium">

                {{ chatbot.name }}

            </div>

            <div class="text-sm text-gray-500 dark:text-gray-400">

                Creado: {{ dayjs(chatbot.created_at).fromNow() }}

            </div>

        </div>


        <div class="flex space-x-2 mt-4 md:mt-0">

            <!-- 👇 Ruta corregida para el detalle -->

            <PrimaryButton 

                :href="route('chatbots.show', chatbot.id)"

                aria-label="Ver detalles del chatbot"

                class="gap-2"

            >

                <EyeIcon class="w-4 h-4" />

                <span>Ver</span>

            </PrimaryButton>

            

            <SecondaryButton 

                :href="route('chatbots.edit', chatbot.id)"

                aria-label="Editar chatbot"

                class="gap-2"

            >

                <PencilIcon class="w-4 h-4" />

                <span>Editar</span>

            </SecondaryButton>

            

            <DangerButton 

                aria-label="Eliminar chatbot"

                class="gap-2"

                @click="$emit('delete', chatbot.id)"

            >

                <TrashIcon class="w-4 h-4" />

                <span>Eliminar</span>

            </DangerButton>

        </div>

    </div>

</template>


2. Controlador - Método Show

2.1. Actualizar ChatbotController

En app/Http/Controllers/ChatbotController.php:

php

<?php


namespace App\Http\Controllers;


use App\Models\Chatbot;

use Illuminate\Http\Request;

use Inertia\Inertia;


class ChatbotController extends Controller

{

    /**

     * Display a listing of the resource.

     */

    public function index(Request $request)

    {

        $chatbots = $request->user()->chatbots;

        

        return Inertia::render('Chatbots/Index', [

            'chatbots' => $chatbots,

        ]);

    }


    /**

     * Display the specified resource.

     */

    public function show(Request $request, Chatbot $chatbot)

    {

        // Verificar que el chatbot pertenece al usuario

        if ($chatbot->user_id !== $request->user()->id) {

            abort(403, 'No tienes permiso para ver este chatbot.');

        }

        

        return Inertia::render('Chatbots/Show', [

            'chatbot' => $chatbot,

        ]);

    }


    // ... otros métodos

}


3. Creación de la Vista Show

3.1. Estructura del Componente

Crear resources/js/Pages/Chatbots/Show.vue:

vue

<script setup>

import { defineProps } from 'vue'

import { Link } from '@inertiajs/vue3'

import AppLayout from '@/Layouts/AppLayout.vue'

import dayjs from '@/utils/dayjs'

import PrimaryButton from '@/Components/PrimaryButton.vue'

import SecondaryButton from '@/Components/SecondaryButton.vue'

import { 

    ArrowLeftIcon, 

    PencilIcon, 

    TrashIcon,

    ChatBubbleLeftRightIcon,

} from '@heroicons/vue/24/solid'


defineProps({

    chatbot: {

        type: Object,

        required: true

    }

})

</script>


<template>

    <AppLayout :title="`Chatbot: ${chatbot.name}`">

        <!-- Header -->

        <template #header>

            <div class="flex items-center gap-4">

                <!-- Botón de volver -->

                <Link 

                    :href="route('chatbots.index')" 

                    class="text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200 transition-colors"

                    aria-label="Volver al listado de chatbots"

                >

                    <ArrowLeftIcon class="w-6 h-6" />

                </Link>

                

                <h1 class="font-semibold text-xl text-gray-800 dark:text-gray-200 leading-tight">

                    {{ chatbot.name }}

                </h1>

            </div>

        </template>


        <!-- Contenido principal -->

        <div class="py-12">

            <div class="max-w-7xl mx-auto sm:px-6 lg:px-8">

                <div class="bg-white dark:bg-gray-800 overflow-hidden shadow-xl sm:rounded-lg">

                    <div class="p-6 lg:p-8">

                        <!-- Grid de información -->

                        <div class="grid grid-cols-1 md:grid-cols-2 gap-6">

                            <!-- Columna izquierda -->

                            <div class="space-y-6">

                                <!-- System Prompt -->

                                <div>

                                    <h3 class="text-sm font-medium text-gray-500 dark:text-gray-400">

                                        System Prompt

                                    </h3>

                                    <div class="mt-2 p-4 bg-gray-50 dark:bg-gray-900 rounded-lg">

                                        <p class="text-gray-800 dark:text-gray-200 whitespace-pre-wrap">

                                            {{ chatbot.system_prompt }}

                                        </p>

                                    </div>

                                </div>


                                <!-- Temperatura -->

                                <div>

                                    <h3 class="text-sm font-medium text-gray-500 dark:text-gray-400">

                                        Temperatura

                                    </h3>

                                    <div class="mt-2 flex items-center gap-2">

                                        <div class="flex-1 h-2 bg-gray-200 dark:bg-gray-700 rounded-full">

                                            <div 

                                                class="h-2 bg-blue-600 rounded-full transition-all"

                                                :style="{ width: `${chatbot.temperature * 100}%` }"

                                            />

                                        </div>

                                        <span class="text-sm font-medium text-gray-700 dark:text-gray-300">

                                            {{ chatbot.temperature }}

                                        </span>

                                    </div>

                                </div>


                                <!-- Modelo -->

                                <div>

                                    <h3 class="text-sm font-medium text-gray-500 dark:text-gray-400">

                                        Modelo de IA

                                    </h3>

                                    <div class="mt-2">

                                        <span class="inline-flex items-center px-3 py-1 rounded-full text-sm font-medium bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-200">

                                            {{ chatbot.model }}

                                        </span>

                                    </div>

                                </div>


                                <!-- Fecha de creación -->

                                <div>

                                    <h3 class="text-sm font-medium text-gray-500 dark:text-gray-400">

                                        Creado

                                    </h3>

                                    <div class="mt-2 text-gray-800 dark:text-gray-200">

                                        {{ dayjs(chatbot.created_at).format('DD/MM/YYYY HH:mm') }}

                                        <span class="text-sm text-gray-500 dark:text-gray-400">

                                            ({{ dayjs(chatbot.created_at).fromNow() }})

                                        </span>

                                    </div>

                                </div>

                            </div>


                            <!-- Columna derecha - Acciones y estadísticas -->

                            <div class="space-y-6">

                                <!-- Acciones rápidas -->

                                <div>

                                    <h3 class="text-sm font-medium text-gray-500 dark:text-gray-400">

                                        Acciones

                                    </h3>

                                    <div class="mt-4 space-y-3">

                                        <!-- Chatear -->

                                        <SecondaryButton 

                                            :href="route('chats.create', chatbot.id)"

                                            class="w-full justify-center gap-2"

                                            aria-label="Iniciar chat con este chatbot"

                                        >

                                            <ChatBubbleLeftRightIcon class="w-5 h-5" />

                                            <span>Chatear</span>

                                        </SecondaryButton>


                                        <!-- Editar -->

                                        <SecondaryButton 

                                            :href="route('chatbots.edit', chatbot.id)"

                                            class="w-full justify-center gap-2"

                                            aria-label="Editar chatbot"

                                        >

                                            <PencilIcon class="w-5 h-5" />

                                            <span>Editar</span>

                                        </SecondaryButton>


                                        <!-- Eliminar -->

                                        <DangerButton 

                                            class="w-full justify-center gap-2"

                                            aria-label="Eliminar chatbot"

                                        >

                                            <TrashIcon class="w-5 h-5" />

                                            <span>Eliminar</span>

                                        </DangerButton>

                                    </div>

                                </div>


                                <!-- Estadísticas -->

                                <div>

                                    <h3 class="text-sm font-medium text-gray-500 dark:text-gray-400">

                                        Estadísticas

                                    </h3>

                                    <div class="mt-4 grid grid-cols-2 gap-4">

                                        <div class="bg-gray-50 dark:bg-gray-900 rounded-lg p-4 text-center">

                                            <div class="text-2xl font-bold text-gray-800 dark:text-gray-200">

                                                0

                                            </div>

                                            <div class="text-xs text-gray-500 dark:text-gray-400">

                                                Conversaciones

                                            </div>

                                        </div>

                                        <div class="bg-gray-50 dark:bg-gray-900 rounded-lg p-4 text-center">

                                            <div class="text-2xl font-bold text-gray-800 dark:text-gray-200">

                                                0

                                            </div>

                                            <div class="text-xs text-gray-500 dark:text-gray-400">

                                                Mensajes

                                            </div>

                                        </div>

                                    </div>

                                </div>

                            </div>

                        </div>

                    </div>

                </div>

            </div>

        </div>

    </AppLayout>

</template>


4. Mejoras y Funcionalidades Adicionales

4.1. Verificar Propiedad del Chatbot

En el controlador, agregar política de autorización:

php

// En app/Policies/ChatbotPolicy.php (crear si no existe)

public function view(User $user, Chatbot $chatbot)

{

    return $user->id === $chatbot->user_id;

}

En el controlador usando policies:

php

public function show(Request $request, Chatbot $chatbot)

{

    $this->authorize('view', $chatbot);

    

    return Inertia::render('Chatbots/Show', [

        'chatbot' => $chatbot,

    ]);

}

4.2. Componente de Estadísticas

Crear resources/js/Components/Chatbots/ChatbotStats.vue:

vue

<script setup>

import { computed } from 'vue'


const props = defineProps({

    chatbot: {

        type: Object,

        required: true

    }

})


// Esto se actualizará cuando tengamos el sistema de chats

const stats = computed(() => ({

    conversations: 0,

    messages: 0,

    lastActivity: null,

}))

</script>


<template>

    <div class="grid grid-cols-2 md:grid-cols-4 gap-4">

        <div class="bg-gray-50 dark:bg-gray-900 rounded-lg p-4 text-center">

            <div class="text-2xl font-bold text-gray-800 dark:text-gray-200">

                {{ stats.conversations }}

            </div>

            <div class="text-xs text-gray-500 dark:text-gray-400">

                Conversaciones

            </div>

        </div>

        

        <div class="bg-gray-50 dark:bg-gray-900 rounded-lg p-4 text-center">

            <div class="text-2xl font-bold text-gray-800 dark:text-gray-200">

                {{ stats.messages }}

            </div>

            <div class="text-xs text-gray-500 dark:text-gray-400">

                Mensajes

            </div>

        </div>

        

        <div class="bg-gray-50 dark:bg-gray-900 rounded-lg p-4 text-center col-span-2">

            <div class="text-sm text-gray-800 dark:text-gray-200">

                {{ stats.lastActivity || 'Sin actividad' }}

            </div>

            <div class="text-xs text-gray-500 dark:text-gray-400">

                Última actividad

            </div>

        </div>

    </div>

</template>

4.3. Mejorar el Formateo de Fechas

En utils/dayjs.js, agregar más formatos:

javascript

// ... configuraciones existentes


// Funciones de formato adicionales

export const formatDateLong = (date) => {

    return dayjs(date).format('dddd, D [de] MMMM [de] YYYY')

}


export const formatDateTime = (date) => {

    return dayjs(date).format('DD/MM/YYYY HH:mm:ss')

}


export const formatTimeAgo = (date) => {

    return dayjs(date).fromNow()

}

Uso en el componente:

vue

<script setup>

import { formatDateLong, formatTimeAgo } from '@/utils/dayjs'

</script>


<template>

    <div>

        <div class="text-gray-800 dark:text-gray-200">

            {{ formatDateLong(chatbot.created_at) }}

        </div>

        <div class="text-sm text-gray-500 dark:text-gray-400">

            {{ formatTimeAgo(chatbot.created_at) }}

        </div>

    </div>

</template>


5. Navegación y Breadcrumbs

5.1. Componente de Breadcrumbs

Crear resources/js/Components/Breadcrumbs.vue:

vue

<script setup>

import { Link } from '@inertiajs/vue3'

import { ChevronRightIcon } from '@heroicons/vue/24/solid'


defineProps({

    items: {

        type: Array,

        required: true

    }

})

</script>


<template>

    <nav class="flex" aria-label="Breadcrumb">

        <ol class="flex items-center space-x-2">

            <li v-for="(item, index) in items" :key="index">

                <div class="flex items-center">

                    <ChevronRightIcon 

                        v-if="index > 0"

                        class="w-4 h-4 text-gray-400 dark:text-gray-600 mr-2"

                        aria-hidden="true"

                    />

                    <Link

                        v-if="item.href"

                        :href="item.href"

                        class="text-sm text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200"

                    >

                        {{ item.label }}

                    </Link>

                    <span v-else class="text-sm font-medium text-gray-800 dark:text-gray-200">

                        {{ item.label }}

                    </span>

                </div>

            </li>

        </ol>

    </nav>

</template>

Uso en Show.vue:

vue

<template>

    <AppLayout :title="`Chatbot: ${chatbot.name}`">

        <template #header>

            <div class="flex flex-col gap-2">

                <Breadcrumbs :items="[

                    { label: 'Chatbots', href: route('chatbots.index') },

                    { label: chatbot.name }

                ]" />

                

                <h1 class="font-semibold text-xl text-gray-800 dark:text-gray-200">

                    {{ chatbot.name }}

                </h1>

            </div>

        </template>

        <!-- ... -->

    </AppLayout>

</template>


6. Resumen

6.1. Archivos Creados/Modificados

Archivo

Acción

app/Http/Controllers/ChatbotController.php

✅ Método show agregado

resources/js/Pages/Chatbots/Show.vue

✅ Creado

resources/js/Components/Chatbots/ChatbotListItem.vue

✅ Ruta actualizada

resources/js/Components/Breadcrumbs.vue

✅ Creado (opcional)

6.2. Estructura de la Vista Show

text

Show.vue

├── AppLayout

│   ├── Header

│   │   ├── Botón Volver

│   │   └── Título del Chatbot

│   └── Contenido

│       ├── Columna Izquierda

│       │   ├── System Prompt

│       │   ├── Temperatura (barra)

│       │   ├── Modelo de IA

│       │   └── Fecha de Creación

│       └── Columna Derecha

│           ├── Acciones

│           │   ├── Chatear

│           │   ├── Editar

│           │   └── Eliminar

│           └── Estadísticas

│               ├── Conversaciones

│               └── Mensajes

6.3. Funcionalidades Implementadas

  • ✅ Visualización de todos los datos del chatbot

  • ✅ Barra de temperatura con representación visual

  • ✅ Botón de volver al listado

  • ✅ Acciones rápidas desde el detalle

  • ✅ Autorización para verificar propiedad

  • ✅ Formato de fechas legible

  • ✅ Soporte Dark Mode

¡La vista de detalle está completa y lista para usar! 🚀


Comentarios

Entradas más populares de este blog

1. Introducción al curso de Chatbots personalizados con Laravel & OpenAI

2. Prerequisitos para el Curso de Chatbots con Laravel y OpenAI

4. Herramientas de Calidad