"use client" import { useState, useEffect } from "react" import { Button } from "@/components/ui/button" import { Input } from "@/components/ui/input" import { Label } from "@/components/ui/label" import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select" import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table" import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" import { Alert, AlertDescription } from "@/components/ui/alert" import { Download, Search, Loader2, DollarSign, TrendingUp, Calculator } from "lucide-react" const API_BASE_URL = process.env.NEXT_PUBLIC_API_URL || "http://localhost:5000/api/v1" function formatDateBr(dateStr:string) { const [year, month, day] = dateStr.split("-"); return `${day}/${month}/${year}`; } export function formatDateTime(raw?: string): string { if (!raw || raw === "-") return "-" const iso = raw.replace(" ", "T") const date = new Date(iso) if (isNaN(date.getTime())) return "-" return ( date.toLocaleDateString("pt-BR", { day: "2-digit", month: "2-digit", year: "numeric", }) + " " + date.toLocaleTimeString("pt-BR", { hour: "2-digit", minute: "2-digit", second: "2-digit", hour12: false, }) ) } interface ClientTranscriptionData { uniqueid: string src: string dst: string start_call: string total_billsec: number total_min: string client_total_cost: string } interface HitTranscriptionData { companyId: string // Empresa uniqueid: string // Identificador da chamada src: string // Origem dst: string // Destino total_billsec: number // Quantidade de segundos qtd_token_input: number // Quantidade de tokens(input) qtd_token_output: number // Quantidade de tokens(output) total_min: number, custo_hit: string // Custo HIT client_total_cost: string // Custo Cliente client_price: string // Preço Cliente por Minuto start_call: string // Inicio end_call: string // Fim } type TranscriptionData = ClientTranscriptionData | HitTranscriptionData // Interface para informações de custo interface CostInfo { company_id: string start_date: string end_date: string total_cost_hit: number total_client_cost: number } // Interface para cotação do dólar interface ExchangeRateResponse { USDBRL: { code: string codein: string name: string high: string low: string varBid: string pctChange: string bid: string ask: string timestamp: string create_date: string } } interface PaginationInfo { total: number page: number page_size: number total_pages: number } interface ApiResponse { success: boolean data: { data: TranscriptionData[] pagination: PaginationInfo cost?: CostInfo } } export default function TranscriptionTable() { const [data, setData] = useState([]) const [costInfo, setCostInfo] = useState(null) const [exchangeRate, setExchangeRate] = useState(null) const [isLoading, setIsLoading] = useState(false) const [isExporting, setIsExporting] = useState(false) const [error, setError] = useState("") // Filtros const [companyId, setCompanyId] = useState("") const [startDate, setStartDate] = useState("") const [endDate, setEndDate] = useState("") const [who, setWho] = useState<"client" | "hit">("client") // Estados para paginação const [pagination, setPagination] = useState({ total: 0, page: 1, page_size: 20, total_pages: 0, }) const [currentPage, setCurrentPage] = useState(1) const [pageSize, setPageSize] = useState(20) const getAuthHeaders = () => { const token = localStorage.getItem("access_token") return { Authorization: `Bearer ${token}`, "Content-Type": "application/json", } } // Função para buscar a cotação do dólar const fetchExchangeRate = async () => { try { const response = await fetch("https://economia.awesomeapi.com.br/json/last/USD-BRL") if (response.ok) { const data: ExchangeRateResponse = await response.json() const rate = Number.parseFloat(data.USDBRL.ask) // Usando o valor de venda (ask) setExchangeRate(rate) return rate } } catch (err) { console.log("Erro ao buscar cotação do dólar:", err) // Usar uma cotação padrão em caso de erro setExchangeRate(5.5) return 5.5 } return null } const fetchData = async (page: number = currentPage) => { if (!companyId || !startDate || !endDate) { setError("Preencha todos os campos obrigatórios") return } setIsLoading(true) setError("") try { // Buscar cotação do dólar em paralelo const ratePromise = fetchExchangeRate() const params = new URLSearchParams({ companyId, startDate, endDate, who, page: page.toString(), page_size: pageSize.toString(), }) const response = await fetch(`${API_BASE_URL}/usage/data/trascription?${params}`, { headers: getAuthHeaders(), }) if (response.ok) { const result: ApiResponse = await response.json() if (result.success && result.data) { setData(result.data.data || []) setPagination(result.data.pagination) setCostInfo(result.data.cost || null) setCurrentPage(result.data.pagination.page) } else { setData([]) setCostInfo(null) setPagination({ total: 0, page: 1, page_size: 20, total_pages: 0 }) } } else { const errorData = await response.json() setError(errorData.message || "Erro ao buscar dados") } // Aguardar a cotação do dólar await ratePromise } catch (err) { console.log("====> Erro de conexão com o servidor: ", err) setError("Erro de conexão com o servidor") } finally { setIsLoading(false) } } const exportToExcel = async () => { if (!companyId || !startDate || !endDate) { setError("Preencha todos os campos obrigatórios") return } setIsExporting(true) setError("") try { const params = new URLSearchParams({ companyId, startDate, endDate, who, }) const response = await fetch(`${API_BASE_URL}/usage/export/trascription?${params}`, { headers: getAuthHeaders(), }) if (response.ok) { const blob = await response.blob() const url = window.URL.createObjectURL(blob) const a = document.createElement("a") a.href = url a.download = `transcription-report-${who}-${startDate}-${endDate}.xlsx` document.body.appendChild(a) a.click() window.URL.revokeObjectURL(url) document.body.removeChild(a) } else { const errorData = await response.json() setError(errorData.message || "Erro ao exportar dados") } } catch (err) { console.log("====> Erro de conexão com o servidor: ", err) setError("Erro de conexão com o servidor") } finally { setIsExporting(false) } } // Funções de navegação de páginas const goToPage = (page: number) => { if (page >= 1 && page <= pagination.total_pages) { setCurrentPage(page) fetchData(page) } } const goToFirstPage = () => goToPage(1) const goToPreviousPage = () => goToPage(currentPage - 1) const goToNextPage = () => goToPage(currentPage + 1) const goToLastPage = () => goToPage(pagination.total_pages) // Função para formatar valores monetários const formatCurrency = (value: number, currency = "USD"): string => { return new Intl.NumberFormat("pt-BR", { style: "currency", currency: currency, minimumFractionDigits: 2, maximumFractionDigits: 2, }).format(value) } // Função para converter USD para BRL const convertUsdToBrl = (usdValue: number): number => { if (!exchangeRate) return usdValue return usdValue * exchangeRate } // Buscar cotação do dólar quando o componente for montado useEffect(() => { fetchExchangeRate() }, []) return (
{/* Card de Informações de Custo */} {costInfo && exchangeRate && (
Custo Total HIT
{formatCurrency(convertUsdToBrl(costInfo.total_cost_hit), "BRL")}

Empresa {costInfo.company_id} • {formatCurrency(costInfo.total_cost_hit, "USD")}

Custo Total Cliente
{formatCurrency(costInfo.total_client_cost, "BRL")}

{formatDateBr(costInfo.start_date)} até {formatDateBr(costInfo.end_date)}

Margem
{formatCurrency(costInfo.total_client_cost - convertUsdToBrl(costInfo.total_cost_hit), "BRL")}

{( ((costInfo.total_client_cost - convertUsdToBrl(costInfo.total_cost_hit)) / costInfo.total_client_cost) * 100 ).toFixed(1)} % de margem

)} {/* Filtros */} Filtros de Consulta
setCompanyId(e.target.value)} placeholder="123" />
setStartDate(e.target.value)} />
setEndDate(e.target.value)} />
{error && ( {error} )} {/* Indicador de cotação do dólar */} {exchangeRate && (
Cotação USD/BRL: R$ {exchangeRate.toFixed(4)}
)} {/* Tabela de Dados */} Resultados da Consulta {pagination.total > 0 && ( (Página {currentPage} de {pagination.total_pages} - {pagination.total} registros total) )} {data.length > 0 ? (
{who === "hit" ? ( <> Empresa Identificador da chamada Origem Destino Segundos Minutos Custo Cliente (R$) Preço Cliente p/ Minuto (R$) Custo HIT ($) Início Fim Tokens (Input) Tokens (Output) ) : ( <> ID Único Origem Destino Início Duração (s) Duração (m) Custo (R$) )} {data.map((item, index) => ( {who === "hit" ? ( <> {(item as HitTranscriptionData).companyId || "-"} {(item as HitTranscriptionData).uniqueid || "-"} {(item as HitTranscriptionData).src || "-"} {(item as HitTranscriptionData).dst || "-"} {(item as HitTranscriptionData).total_billsec || "-"} {(item as HitTranscriptionData).total_min || "-"} {(item as HitTranscriptionData).client_total_cost ? `R$ ${(item as HitTranscriptionData).client_total_cost.slice(0, 4)}` : "-"} {(item as HitTranscriptionData).client_price ? `R$ ${(item as HitTranscriptionData).client_price}` : "-"} {(item as HitTranscriptionData).custo_hit ? `$ ${(item as HitTranscriptionData).custo_hit.slice(0, 4)}` : "-"} {formatDateTime((item as HitTranscriptionData).start_call || "-")} {formatDateTime((item as HitTranscriptionData).end_call || "-")} {(item as HitTranscriptionData).qtd_token_input || "-"} {(item as HitTranscriptionData).qtd_token_output || "-"} ) : ( <> {(item as ClientTranscriptionData).uniqueid || "-"} {(item as ClientTranscriptionData).src || "-"} {(item as ClientTranscriptionData).dst || "-"} {formatDateTime((item as ClientTranscriptionData).start_call || "-")} {(item as ClientTranscriptionData).total_billsec || "-"} {(item as ClientTranscriptionData).total_min || "-"} {(item as ClientTranscriptionData).client_total_cost ? `R$ ${(item as ClientTranscriptionData).client_total_cost.slice(0, 4)}` : "-"} )} ))}
) : (
Nenhum dado encontrado. Use os filtros acima para buscar dados.
)} {/* Componente de Paginação */} {pagination.total > 0 && (

Mostrando {(currentPage - 1) * pagination.page_size + 1} até{" "} {Math.min(currentPage * pagination.page_size, pagination.total)}{" "} de {pagination.total} resultados

{/* Páginas numeradas */} {Array.from({ length: Math.min(5, pagination.total_pages) }, (_, i) => { let pageNum if (pagination.total_pages <= 5) { pageNum = i + 1 } else if (currentPage <= 3) { pageNum = i + 1 } else if (currentPage >= pagination.total_pages - 2) { pageNum = pagination.total_pages - 4 + i } else { pageNum = currentPage - 2 + i } return ( ) })}
)}
) }