'use client'; import React from 'react'; import { X, Plus, ClipboardList, ChevronDown, Loader2, CheckCircle2, Clock, AlertCircle, Ban, Users, Layers, } from 'lucide-react'; import { motion, AnimatePresence } from 'framer-motion'; import { format } from 'date-fns'; import { ptBR } from 'date-fns/locale'; import type { Protocol, ProtocolStatus } from '../hooks/useProtocolPanel'; import Toast from './ui/Toast'; // ─── Status config ──────────────────────────────────────────────────────────── type StatusConfig = { label: string color: string bg: string icon: React.ReactNode } const STATUS: Record = { OPEN: { label: 'Aberto', color: 'text-blue-400', bg: 'bg-blue-500/10 border-blue-500/20', icon: }, IN_PROGRESS: { label: 'Em Andamento', color: 'text-brand-400', bg: 'bg-brand-500/10 border-brand-500/20', icon: }, WAITING_CLIENT: { label: 'Aguardando Cliente', color: 'text-amber-400', bg: 'bg-amber-500/10 border-amber-500/20', icon: }, WAITING_AGENT: { label: 'Aguardando Agente', color: 'text-orange-400', bg: 'bg-orange-500/10 border-orange-500/20', icon: }, RESOLVED: { label: 'Resolvido', color: 'text-emerald-400', bg: 'bg-emerald-500/10 border-emerald-500/20', icon: }, CANCELLED: { label: 'Cancelado', color: 'text-slate-400', bg: 'bg-slate-500/10 border-slate-500/20', icon: }, } const TRANSITIONS: Record = { OPEN: ['IN_PROGRESS', 'CANCELLED'], IN_PROGRESS: ['WAITING_CLIENT', 'WAITING_AGENT', 'RESOLVED', 'CANCELLED'], WAITING_CLIENT: ['IN_PROGRESS', 'RESOLVED', 'CANCELLED'], WAITING_AGENT: ['IN_PROGRESS', 'RESOLVED', 'CANCELLED'], RESOLVED: [], CANCELLED: [], } function StatusBadge({ status }: { status: ProtocolStatus }) { const cfg = STATUS[status] return ( {cfg.icon} {cfg.label} ) } // ─── Protocol card ──────────────────────────────────────────────────────────── interface ProtocolCardProps { protocol: Protocol isActive: boolean updatingId: string | null onStatusChange: (protocol: Protocol, status: ProtocolStatus) => void } function ProtocolCard({ protocol, isActive, updatingId, onStatusChange }: ProtocolCardProps) { const [showActions, setShowActions] = React.useState(false) const transitions = TRANSITIONS[protocol.status] const isUpdating = updatingId === protocol.id return (
{/* Header */}
{protocol.number} {isActive && ( ATIVO )}

{format(new Date(protocol.createdAt), "dd/MM/yyyy 'às' HH:mm", { locale: ptBR })}

{/* Sector / Team */} {(protocol.sector || protocol.team) && (
{protocol.sector && ( {protocol.sector.name} )} {protocol.team && ( {protocol.team.name} )}
)} {/* Summary */} {protocol.summary && (

{protocol.summary}

)} {/* Status actions */} {transitions.length > 0 && (
{showActions && ( {transitions.map((s) => { const cfg = STATUS[s] return ( ) })} )}
)} {/* Resolved at */} {protocol.resolvedAt && (

Resolvido em {format(new Date(protocol.resolvedAt), "dd/MM/yyyy 'às' HH:mm", { locale: ptBR })}

)}
) } // ─── Panel ──────────────────────────────────────────────────────────────────── interface ProtocolPanelProps { isOpen: boolean chatId: string | null onClose: () => void // injected from useProtocolPanel protocols: Protocol[] loading: boolean activeProtocol: Protocol | null hasActive: boolean showOpenForm: boolean openForm: () => void setShowOpenForm: (v: boolean) => void sectors: any[] teams: any[] selectedSectorId: string setSelectedSectorId: (v: string) => void selectedTeamId: string setSelectedTeamId: (v: string) => void loadingSectors: boolean loadingTeams: boolean isOpening: boolean openProtocol: () => void updatingId: string | null updateStatus: (protocol: Protocol, status: ProtocolStatus) => void toast: { message: string; type: 'success' | 'error' } | null } export default function ProtocolPanel({ isOpen, onClose, protocols, loading, activeProtocol, hasActive, showOpenForm, openForm, setShowOpenForm, sectors, teams, selectedSectorId, setSelectedSectorId, selectedTeamId, setSelectedTeamId, loadingSectors, loadingTeams, isOpening, openProtocol, updatingId, updateStatus, toast, }: ProtocolPanelProps) { const selectClass = "w-full bg-white/5 border border-white/10 rounded-xl px-3 py-2 text-sm text-white focus:outline-none focus:border-brand-500/50 transition-colors appearance-none" return ( {isOpen && ( {/* Header */}
Protocolos de Atendimento
{/* Body */}
{/* Open protocol form */} {showOpenForm ? (

Novo Protocolo

{/* Sector */}
{loadingSectors && ( )}
{/* Team */} {selectedSectorId && (
{loadingTeams && ( )}
)}
) : ( !hasActive && ( ) )}
{/* Active protocol */} {activeProtocol && !showOpenForm && (

Protocolo Ativo

{!hasActive && null}
)} {/* Open new when active exists */} {hasActive && !showOpenForm && ( )} {/* History */} {loading ? (
) : protocols.length === 0 ? (

Nenhum protocolo para este chat.

) : ( (() => { const history = protocols.filter( (p) => p.status === 'RESOLVED' || p.status === 'CANCELLED' ) return history.length > 0 ? (

Histórico

{history.map((p) => ( ))}
) : null })() )}
)}
) }