# Serena Chat

Serena is the AI-powered virtual assistant for Monetarie NPC Backoffice. The Serena Chat component provides a floating chat interface that helps users navigate the system and answers common questions about financial operations.

## Overview

Serena is designed to:

- Answer questions about PIX transfers
- Guide users through account operations
- Explain SISBAJUD order processes
- Provide general system navigation help

## Component Structure

```vue
<template>
  <div class="serena-container">
    <!-- Floating Action Button -->
    <v-btn
      v-if="!serenaStore.isOpen"
      class="serena-fab"
      color="serena"
      size="large"
      icon
      @click="serenaStore.open"
    >
      <span class="text-h5 font-weight-bold">S</span>
      <v-tooltip activator="parent" location="left">
        {{ t('serena.tooltip') }}
      </v-tooltip>
    </v-btn>

    <!-- Chat Window -->
    <v-card v-if="serenaStore.isOpen" class="serena-chat" elevation="8">
      <!-- Header -->
      <v-card-title class="bg-serena text-white d-flex align-center py-2">
        <v-icon class="mr-2">mdi-robot-happy-outline</v-icon>
        {{ t('serena.title') }}
        <v-spacer />
        <v-btn icon size="small" variant="text" color="white" @click="serenaStore.close">
          <v-icon>mdi-minus</v-icon>
        </v-btn>
        <v-btn icon size="small" variant="text" color="white" @click="serenaStore.close">
          <v-icon>mdi-close</v-icon>
        </v-btn>
      </v-card-title>

      <!-- Messages -->
      <v-card-text class="chat-messages pa-3" ref="messagesContainer">
        <!-- Greeting -->
        <div v-if="serenaStore.messages.length === 0" class="message assistant">
          <v-avatar color="serena" size="32" class="mr-2">
            <span class="text-white text-body-2">S</span>
          </v-avatar>
          <div class="message-content">
            {{ t('serena.greeting') }}
          </div>
        </div>

        <!-- Chat History -->
        <div
          v-for="msg in serenaStore.messages"
          :key="msg.id"
          :class="['message', msg.role]"
        >
          <!-- Avatar and message content -->
        </div>

        <!-- Typing Indicator -->
        <div v-if="serenaStore.isTyping" class="message assistant">
          <v-avatar color="serena" size="32" class="mr-2">
            <span class="text-white text-body-2">S</span>
          </v-avatar>
          <div class="message-content typing">
            <span class="dot"></span>
            <span class="dot"></span>
            <span class="dot"></span>
          </div>
        </div>
      </v-card-text>

      <!-- Input -->
      <v-card-actions class="pa-2">
        <v-text-field
          v-model="messageInput"
          :placeholder="t('serena.placeholder')"
          variant="outlined"
          density="compact"
          hide-details
          @keyup.enter="sendMessage"
        />
        <v-btn
          icon
          color="serena"
          :disabled="!messageInput.trim() || serenaStore.isTyping"
          @click="sendMessage"
        >
          <v-icon>mdi-send</v-icon>
        </v-btn>
      </v-card-actions>
    </v-card>
  </div>
</template>
```

## Data Interfaces

### Chat Message

```typescript
interface ChatMessage {
  id: number           // Unique message ID
  role: 'user' | 'assistant'  // Message sender
  content: string      // Message text
  timestamp: string    // ISO timestamp
}
```

### Serena Response

```typescript
interface SerenaResponse {
  keywords: string[]   // Trigger keywords
  response: string     // Response text
}
```

## Serena Store

The `useSerenaStore` manages the chat state:

```typescript
// src/stores/serena.ts
export const useSerenaStore = defineStore('serena', () => {
  const isOpen = ref(false)
  const isTyping = ref(false)
  const messages = ref<ChatMessage[]>([])

  function init() {
    const savedMessages = localStorage.getItem('serenaMessages')
    if (savedMessages) {
      messages.value = JSON.parse(savedMessages)
    }
  }

  function open() {
    isOpen.value = true
  }

  function close() {
    isOpen.value = false
  }

  function toggle() {
    isOpen.value = !isOpen.value
  }

  async function sendMessage(content: string, fallbackMessage: string) {
    // Add user message
    const userMessage: ChatMessage = {
      id: Date.now(),
      role: 'user',
      content,
      timestamp: new Date().toISOString()
    }
    messages.value.push(userMessage)
    saveMessages()

    // Show typing indicator
    isTyping.value = true

    // Simulate processing delay
    await new Promise(resolve => setTimeout(resolve, 1000 + Math.random() * 1000))

    // Get response
    const response = getSerenaResponse(content) || fallbackMessage

    // Add assistant message
    const assistantMessage: ChatMessage = {
      id: Date.now() + 1,
      role: 'assistant',
      content: response,
      timestamp: new Date().toISOString()
    }
    messages.value.push(assistantMessage)
    saveMessages()

    isTyping.value = false
  }

  function saveMessages() {
    localStorage.setItem('serenaMessages', JSON.stringify(messages.value))
  }

  function clearHistory() {
    messages.value = []
    localStorage.removeItem('serenaMessages')
  }

  init()

  return {
    isOpen,
    isTyping,
    messages,
    open,
    close,
    toggle,
    sendMessage,
    clearHistory
  }
})
```

## Response Matching

Serena uses keyword-based response matching:

```typescript
// src/mocks/serena.ts
export const serenaResponses: SerenaResponse[] = [
  {
    keywords: ['pix', 'transferencia', 'transferir'],
    response: 'Para realizar uma transferencia PIX, acesse o menu Contas e selecione a opcao de transferencia. Precisa de mais detalhes?'
  },
  {
    keywords: ['conta', 'abrir', 'criar', 'nova'],
    response: 'Para criar uma nova conta, va em Contas > Criar. Voce precisara dos documentos do titular. Posso ajudar com algo mais?'
  },
  {
    keywords: ['bloqueio', 'bloquear', 'sisbajud'],
    response: 'As ordens de bloqueio SISBAJUD sao processadas automaticamente. Voce pode verificar o status no painel SISBAJUD - Ordens.'
  },
  {
    keywords: ['saldo', 'extrato', 'consulta'],
    response: 'Para consultar saldo ou extrato, acesse Contas > Editar e selecione a conta desejada.'
  },
  {
    keywords: ['erro', 'problema', 'falha'],
    response: 'Sinto muito pelo inconveniente. Pode me descrever o erro com mais detalhes para que eu possa ajudar melhor?'
  },
  {
    keywords: ['ajuda', 'help', 'suporte'],
    response: 'Estou aqui para ajudar! Voce pode me perguntar sobre: PIX, contas, transferencias, bloqueios SISBAJUD, ou configuracoes do sistema.'
  }
]

export function getSerenaResponse(message: string): string {
  const lowerMessage = message.toLowerCase()

  for (const item of serenaResponses) {
    if (item.keywords.some(keyword => lowerMessage.includes(keyword))) {
      return item.response
    }
  }

  return '' // Will use fallback from i18n
}
```

## Styling

### Container Positioning

```css
.serena-container {
  position: fixed;
  bottom: 24px;
  right: 24px;
  z-index: 2100;
}
```

### Floating Button Animation

```css
.serena-fab {
  animation: pulse-serena 2s infinite;
}

@keyframes pulse-serena {
  0%, 100% {
    box-shadow: 0 0 0 0 rgba(124, 77, 255, 0.4);
  }
  50% {
    box-shadow: 0 0 0 15px rgba(124, 77, 255, 0);
  }
}
```

### Chat Window

```css
.serena-chat {
  width: 360px;
  height: 480px;
  display: flex;
  flex-direction: column;
}

.chat-messages {
  flex: 1;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 12px;
}
```

### Message Bubbles

```css
.message {
  display: flex;
  align-items: flex-start;
}

.message.user {
  flex-direction: row-reverse;
}

.message-content {
  background: #f5f5f5;
  padding: 8px 12px;
  border-radius: 12px;
  max-width: 80%;
  word-wrap: break-word;
}

.message.user .message-content {
  background: #e3f2fd;
}
```

### Typing Indicator

```css
.typing {
  display: flex;
  gap: 4px;
  padding: 12px;
}

.typing .dot {
  width: 8px;
  height: 8px;
  background: #9e9e9e;
  border-radius: 50%;
  animation: typing-dot 1.4s infinite ease-in-out both;
}

.typing .dot:nth-child(1) { animation-delay: -0.32s; }
.typing .dot:nth-child(2) { animation-delay: -0.16s; }

@keyframes typing-dot {
  0%, 80%, 100% { transform: scale(0); }
  40% { transform: scale(1); }
}
```

## Usage

Include in your layout:

```vue
<!-- src/layouts/AppLayout.vue -->
<template>
  <v-app>
    <TopBar />
    <LeftSidebar />
    <v-main>
      <router-view />
    </v-main>
    <RightPanel />
    <SerenaChat />  <!-- Add Serena here -->
  </v-app>
</template>

<script setup lang="ts">
import SerenaChat from '@/features/serena/components/SerenaChat.vue'
</script>
```

## Vuetify Theme Configuration

Add the Serena color to your theme:

```typescript
// src/plugins/vuetify.ts
import { createVuetify } from 'vuetify'

export default createVuetify({
  theme: {
    themes: {
      light: {
        colors: {
          serena: '#7c4dff',
          // ... other colors
        }
      }
    }
  }
})
```

## Customization

### Adding New Responses

```typescript
// src/mocks/serena.ts
export const serenaResponses: SerenaResponse[] = [
  // ... existing responses
  {
    keywords: ['relatorio', 'report', 'exportar'],
    response: 'Para gerar relatorios, acesse Configuracoes > Relatorios. Voce pode exportar em PDF ou Excel.'
  }
]
```

### Integrating with AI API

Replace the mock response function with a real API call:

```typescript
// src/stores/serena.ts
async function sendMessage(content: string, fallbackMessage: string) {
  const userMessage: ChatMessage = {
    id: Date.now(),
    role: 'user',
    content,
    timestamp: new Date().toISOString()
  }
  messages.value.push(userMessage)

  isTyping.value = true

  try {
    const response = await fetch('/api/serena/chat', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        message: content,
        history: messages.value.slice(-10) // Last 10 messages for context
      })
    })

    const data = await response.json()

    const assistantMessage: ChatMessage = {
      id: Date.now() + 1,
      role: 'assistant',
      content: data.response,
      timestamp: new Date().toISOString()
    }
    messages.value.push(assistantMessage)
  } catch (error) {
    // Use fallback on error
    const assistantMessage: ChatMessage = {
      id: Date.now() + 1,
      role: 'assistant',
      content: fallbackMessage,
      timestamp: new Date().toISOString()
    }
    messages.value.push(assistantMessage)
  }

  isTyping.value = false
  saveMessages()
}
```

### Adding Quick Actions

```vue
<template>
  <div class="quick-actions" v-if="serenaStore.messages.length === 0">
    <v-chip
      v-for="action in quickActions"
      :key="action"
      size="small"
      variant="outlined"
      @click="sendQuickAction(action)"
    >
      {{ action }}
    </v-chip>
  </div>
</template>

<script setup>
const quickActions = [
  'Como fazer PIX?',
  'Ver ordens SISBAJUD',
  'Criar conta',
  'Ajuda'
]

function sendQuickAction(action: string) {
  messageInput.value = action
  sendMessage()
}
</script>
```

## Internationalization

```typescript
// pt-BR.ts
serena: {
  title: 'Serena IA',
  placeholder: 'Digite sua mensagem...',
  greeting: 'Ola! Sou a Serena, sua assistente virtual. Como posso ajudar?',
  fallback: 'Desculpe, nao entendi. Pode reformular a pergunta?',
  tooltip: 'Assistente Virtual Serena'
}
```

## Related Documentation

- [Pinia Stores](/api/stores) - Serena store details
- [i18n Setup](/api/i18n) - Internationalization configuration
- [Dashboard](/guide/dashboard) - Main application layout
