"use client" import { useEffect, useState, useCallback } from "react" import { useParams } from "next/navigation" import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" import { Badge } from "@/components/ui/badge" import { Button } from "@/components/ui/button" import { Loader2, ExternalLink, CheckCircle, AlertCircle, Clock, MessageSquare } from "lucide-react" import { getTicketStatusMeta } from "@/lib/ticket-status-style" import { getTicketPriorityMeta } from "@/lib/ticket-priority-style" interface TicketData { id: string reference: number subject: string summary: string | null status: string priority: string channel: string createdAt: string resolvedAt: string | null requester: { id: string name: string } assignee: { id: string name: string } | null company: { id: string name: string } | null comments: Array<{ id: string body: string createdAt: string author: { id: string name: string } }> rating: { rating: number comment: string | null createdAt: string } | null } interface TokenData { id: string scope: string expiresAt: string used: boolean } export default function TicketViewPage() { const params = useParams() const token = params.token as string const [loading, setLoading] = useState(true) const [error, setError] = useState(null) const [ticket, setTicket] = useState(null) const [tokenData, setTokenData] = useState(null) const [tryingRaven, setTryingRaven] = useState(true) const [ravenAvailable, setRavenAvailable] = useState(false) const loadTicket = useCallback(async () => { try { setLoading(true) const response = await fetch(`/api/ticket-access/${token}`) if (!response.ok) { const data = await response.json() throw new Error(data.error || "Erro ao carregar chamado") } const data = await response.json() setTicket(data.ticket) setTokenData(data.token) } catch (err) { setError(err instanceof Error ? err.message : "Erro desconhecido") } finally { setLoading(false) } }, [token]) // Tenta abrir o protocolo raven:// useEffect(() => { if (!token) return const tryRavenProtocol = async () => { setTryingRaven(true) // Tenta abrir o protocolo raven:// const ravenUrl = `raven://ticket/${token}` // Cria um iframe oculto para detectar se o protocolo foi aceito const iframe = document.createElement("iframe") iframe.style.display = "none" document.body.appendChild(iframe) let protocolHandled = false // Listener para detectar se o navegador aceitou o protocolo const handleBlur = () => { protocolHandled = true setRavenAvailable(true) } window.addEventListener("blur", handleBlur) // Tenta navegar para o protocolo try { window.location.href = ravenUrl } catch { // Protocolo não suportado } // Aguarda 2 segundos para ver se o protocolo foi aceito setTimeout(() => { window.removeEventListener("blur", handleBlur) document.body.removeChild(iframe) if (!protocolHandled) { // Protocolo não foi aceito, carrega o ticket no navegador setTryingRaven(false) loadTicket() } }, 2000) } tryRavenProtocol() }, [token, loadTicket]) const formatDate = (dateStr: string) => { return new Date(dateStr).toLocaleString("pt-BR", { timeZone: "America/Sao_Paulo", day: "2-digit", month: "2-digit", year: "numeric", hour: "2-digit", minute: "2-digit", }) } // Mostra tela de "Abrindo no Raven..." if (tryingRaven) { return (

Abrindo no Raven...

Se o aplicativo Raven estiver instalado, ele abrirá automaticamente.

Caso contrário, o chamado será exibido aqui em instantes.

) } // Mostra loading if (loading) { return (

Carregando chamado...

) } // Mostra erro if (error) { return (

Erro ao carregar

{error}

) } if (!ticket) return null const statusMeta = getTicketStatusMeta(ticket.status) const priorityMeta = getTicketPriorityMeta(ticket.priority) return (
{/* Header */}
R
Raven
{ravenAvailable && ( )}
{/* Ticket Card */}
#{ticket.reference} {statusMeta.label} {priorityMeta.label}
{ticket.subject}
{/* Informações */}
Solicitante

{ticket.requester.name}

Responsável

{ticket.assignee?.name ?? "Não atribuído"}

Criado em

{formatDate(ticket.createdAt)}

{ticket.resolvedAt && (
Resolvido em

{formatDate(ticket.resolvedAt)}

)} {ticket.company && (
Empresa

{ticket.company.name}

)}
{/* Resumo */} {ticket.summary && (

Descrição

{ticket.summary}

)} {/* Avaliação */} {ticket.rating && (
Avaliação
{[1, 2, 3, 4, 5].map((star) => ( ))}
{ticket.rating.comment && (

{ticket.rating.comment}

)}
)} {/* Comentários */} {ticket.comments.length > 0 && (

Últimas atualizações

{ticket.comments.map((comment) => (
{comment.author.name} {formatDate(comment.createdAt)}

{comment.body}

))}
)}
{/* Footer */}

Este link expira em {tokenData ? formatDate(tokenData.expiresAt) : "breve"}.
Para acesso completo, utilize o aplicativo Raven ou acesse o portal.

) }