- Implemented a bash script to test n8n API and retrieve credential schemas. - Added types for API responses, Google Calendar, and WhatsApp instances. - Configured Vitest for testing with React and added setup for testing-library.
8.8 KiB
8.8 KiB
Story 2.2: Exibir Cards de Instâncias WhatsApp com Status
Story Metadata
- Epic: Epic 2 - WhatsApp Management via EvolutionAPI
- Story ID: 2.2
- Priority: P0 (Critical)
- Effort Estimate: 2-3 hours
- Status: Ready for Review
- Assignee: James (Dev Agent)
User Story
Como usuário, Eu quero ver minhas instâncias WhatsApp como cards com status, Para que eu saiba quais estão conectadas ou desconectadas.
Acceptance Criteria
- ✅ Componente
WhatsAppInstanceCard.tsxcriado - ✅ Dashboard exibe grid/lista de cards (um para cada instância em
EVOLUTION_INSTANCE_NAMES) - ✅ Cada card mostra: Nome da instância, Status badge (verde "Connected" ou vermelho "Disconnected")
- ✅ Layout dos cards segue design similar à imagem de referência da EvolutionAPI
- ✅ Cards são responsivos (stack em mobile, grid em desktop)
- ✅ Status é carregado via
getAllInstancesStatusao montar o componente - ✅ Loading state exibido enquanto status carrega
- ✅ Erro de API exibe mensagem amigável no card
Technical Implementation Notes
WhatsApp Instance Card Component
Criar arquivo /components/WhatsAppInstanceCard.tsx:
'use client'
interface WhatsAppInstanceCardProps {
instance: string
status: 'connected' | 'disconnected' | 'error'
error?: string
onGenerateQR?: () => void
onDisconnect?: () => void
}
export default function WhatsAppInstanceCard({
instance,
status,
error,
onGenerateQR,
onDisconnect,
}: WhatsAppInstanceCardProps) {
const statusConfig = {
connected: {
badge: 'Connected',
color: 'bg-green-500',
textColor: 'text-green-400',
},
disconnected: {
badge: 'Disconnected',
color: 'bg-red-500',
textColor: 'text-red-400',
},
error: {
badge: 'Error',
color: 'bg-yellow-500',
textColor: 'text-yellow-400',
},
}
const config = statusConfig[status]
return (
<div className="bg-gray-800 border border-gray-700 rounded-lg p-4 hover:border-primary-500 transition-colors">
{/* Header */}
<div className="flex items-center justify-between mb-4">
<h3 className="text-lg font-semibold text-white">{instance}</h3>
<span
className={`inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium ${config.color} text-white`}
>
{config.badge}
</span>
</div>
{/* Error Message (if any) */}
{error && (
<div className="mb-4 p-2 bg-red-900/20 border border-red-800 rounded text-sm text-red-400">
{error}
</div>
)}
{/* Actions - Will be implemented in next stories */}
<div className="flex gap-2">
{status === 'disconnected' && (
<button
onClick={onGenerateQR}
className="flex-1 px-4 py-2 bg-primary-600 hover:bg-primary-700 text-white text-sm font-medium rounded-md transition-colors"
>
Gerar QR Code
</button>
)}
{status === 'connected' && (
<button
onClick={onDisconnect}
className="flex-1 px-4 py-2 bg-red-600 hover:bg-red-700 text-white text-sm font-medium rounded-md transition-colors"
>
Desconectar
</button>
)}
{status === 'error' && (
<button
disabled
className="flex-1 px-4 py-2 bg-gray-700 text-gray-400 text-sm font-medium rounded-md cursor-not-allowed"
>
Indisponível
</button>
)}
</div>
</div>
)
}
Update Dashboard Page
Atualizar /app/dashboard/page.tsx:
'use client'
import { useEffect, useState } from 'react'
import { supabase } from '@/lib/supabase'
import { getAllInstancesStatus, type InstanceStatus } from '@/lib/evolutionapi'
import WhatsAppInstanceCard from '@/components/WhatsAppInstanceCard'
export default function DashboardPage() {
const [userName, setUserName] = useState<string>('Usuário')
const [instances, setInstances] = useState<InstanceStatus[]>([])
const [loading, setLoading] = useState(true)
useEffect(() => {
const getUser = async () => {
const { data: { user } } = await supabase.auth.getUser()
if (user?.email) {
const name = user.email.split('@')[0]
setUserName(name)
}
}
const loadInstances = async () => {
setLoading(true)
try {
const data = await getAllInstancesStatus()
setInstances(data)
} catch (error) {
console.error('Error loading instances:', error)
} finally {
setLoading(false)
}
}
getUser()
loadInstances()
}, [])
return (
<div className="space-y-6">
{/* Welcome Section */}
<div className="bg-gray-800 rounded-lg p-6 border border-gray-700">
<h2 className="text-2xl font-bold text-white mb-2">
Bem-vindo ao Portal AutomatizaSE, {userName}!
</h2>
<p className="text-gray-400">
Gerencie suas integrações de WhatsApp e Google Calendar.
</p>
</div>
{/* WhatsApp Instances Section */}
<div>
<h3 className="text-xl font-semibold text-white mb-4">Instâncias WhatsApp</h3>
{loading ? (
<div className="text-center py-8 text-gray-400">
Carregando instâncias...
</div>
) : instances.length === 0 ? (
<div className="text-center py-8 text-gray-400">
Nenhuma instância configurada
</div>
) : (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
{instances.map((instance) => (
<WhatsAppInstanceCard
key={instance.instance}
instance={instance.instance}
status={instance.status}
error={instance.error}
onGenerateQR={() => {
// Will be implemented in Story 2.3
console.log('Generate QR for:', instance.instance)
}}
onDisconnect={() => {
// Will be implemented in Story 2.4
console.log('Disconnect:', instance.instance)
}}
/>
))}
</div>
)}
</div>
{/* Google Calendar Section - Placeholder */}
<div className="bg-gray-800 rounded-lg p-6 border border-gray-700">
<h3 className="text-lg font-semibold text-white mb-2">
Google Calendar
</h3>
<p className="text-gray-400 text-sm">
Em breve: Autorize integração com Google Calendar
</p>
</div>
</div>
)
}
Testing Checklist
- Componente
WhatsAppInstanceCardcriado - Cards renderizam corretamente no dashboard
- Status badge exibe cores corretas (verde/vermelho/amarelo)
- Layout responsivo funciona (grid em desktop, stack em mobile)
- Loading state exibido durante carregamento
- Erro de API exibe mensagem no card
- Botões "Gerar QR Code" e "Desconectar" aparecem conforme status
- Cards seguem design similar à EvolutionAPI
Dependencies
- Blocks: Story 2.3, 2.4 (botões serão implementados nestas stories)
- Blocked By: Story 2.1 (precisa de integração com EvolutionAPI)
Notes
- Botões são placeholders nesta story - funcionalidade completa nas próximas stories
- Design inspirado na interface da EvolutionAPI fornecida pelo usuário
Dev Agent Record
Agent Model Used
- claude-sonnet-4-5-20250929
Completion Notes
- Componente
WhatsAppInstanceCard.tsxcriado em/componentscom suporte a 3 estados (connected, disconnected, error) - Dashboard page atualizado para carregar e exibir cards de instâncias WhatsApp
- Implementado loading state e tratamento de erros
- Layout responsivo com grid (1 col mobile, 2 cols tablet, 3 cols desktop)
- Botões com type="button" para acessibilidade
- Re-export de
InstanceStatustype adicionado emlib/evolutionapi.tspara facilitar imports - Código passa em validações TypeScript e Biome linter (sem erros no componente criado)
- Nota: QRCodeModal e funcionalidade de geração de QR já foram implementados (possivelmente por Story 2.3), mas mantidos para compatibilidade
File List
Created:
/components/WhatsAppInstanceCard.tsx- Componente de card de instância WhatsApp
Modified:
/app/dashboard/page.tsx- Adicionado carregamento e exibição de cards de instâncias/lib/evolutionapi.ts- Adicionado re-export de InstanceStatus type
Change Log
- 2025-10-05: Implementação completa da Story 2.2
- Criado componente WhatsAppInstanceCard com badges de status coloridos
- Atualizado dashboard para exibir grid responsivo de cards
- Adicionado loading state e mensagens de erro
- Corrigido export de tipos TypeScript
- Aplicadas correções de acessibilidade (button type)