mirror of
https://github.com/idrainformatica/PecFlow.git
synced 2026-06-16 12:45:42 +02:00
146 lines
4.4 KiB
TypeScript
146 lines
4.4 KiB
TypeScript
import { ChevronDown, ChevronRight, Mail, ExternalLink } from 'lucide-react'
|
|
import { useState } from 'react'
|
|
import { useNavigate } from 'react-router-dom'
|
|
import { PecTypeBadge, PecStateBadge } from '@/components/PecBadge/PecBadge'
|
|
import { formatDate } from '@/lib/utils'
|
|
import type { MessageResponse } from '@/types/api.types'
|
|
|
|
interface ReceiptTreeProps {
|
|
message: MessageResponse
|
|
receipts: MessageResponse[]
|
|
}
|
|
|
|
/**
|
|
* Visualizza la gerarchia delle ricevute PEC collegate a un messaggio.
|
|
* Mostra in ordine cronologico: accettazione → consegna (o anomalia).
|
|
* Le ricevute sono cliccabili e navigano al dettaglio del messaggio ricevuta.
|
|
*/
|
|
export function ReceiptTree({ message, receipts }: ReceiptTreeProps) {
|
|
const [expanded, setExpanded] = useState(true)
|
|
const navigate = useNavigate()
|
|
|
|
if (receipts.length === 0) {
|
|
if (message.direction === 'outbound') {
|
|
return (
|
|
<div className="rounded-lg border border-dashed border-muted-foreground/30 p-4 text-sm text-muted-foreground">
|
|
<Mail className="mb-1 inline h-4 w-4 mr-1" />
|
|
Nessuna ricevuta ancora ricevuta per questo messaggio.
|
|
</div>
|
|
)
|
|
}
|
|
return null
|
|
}
|
|
|
|
return (
|
|
<div className="space-y-2">
|
|
<button
|
|
className="flex items-center gap-2 text-sm font-medium text-foreground hover:text-primary"
|
|
onClick={() => setExpanded(!expanded)}
|
|
>
|
|
{expanded ? (
|
|
<ChevronDown className="h-4 w-4" />
|
|
) : (
|
|
<ChevronRight className="h-4 w-4" />
|
|
)}
|
|
Ricevute ({receipts.length})
|
|
</button>
|
|
|
|
{expanded && (
|
|
<div className="ml-4 space-y-2 border-l-2 border-muted pl-4">
|
|
{/* Messaggio originale */}
|
|
<ReceiptNode
|
|
label="Messaggio inviato"
|
|
date={message.sent_at || message.created_at}
|
|
state={message.state}
|
|
isRoot
|
|
/>
|
|
|
|
{/* Ricevute in ordine cronologico */}
|
|
{[...receipts]
|
|
.sort(
|
|
(a, b) =>
|
|
new Date(a.received_at || a.created_at).getTime() -
|
|
new Date(b.received_at || b.created_at).getTime(),
|
|
)
|
|
.map((receipt) => (
|
|
<ReceiptNode
|
|
key={receipt.id}
|
|
label={receipt.subject || 'Ricevuta'}
|
|
date={receipt.received_at || receipt.created_at}
|
|
type={receipt.pec_type}
|
|
messageId={receipt.id}
|
|
onClick={() => navigate(`/messages/${receipt.id}`)}
|
|
/>
|
|
))}
|
|
</div>
|
|
)}
|
|
</div>
|
|
)
|
|
}
|
|
|
|
interface ReceiptNodeProps {
|
|
label: string
|
|
date: string | null
|
|
state?: MessageResponse['state']
|
|
type?: MessageResponse['pec_type']
|
|
messageId?: string
|
|
isRoot?: boolean
|
|
onClick?: () => void
|
|
}
|
|
|
|
function ReceiptNode({ label, date, state, type, isRoot, onClick }: ReceiptNodeProps) {
|
|
const isClickable = !!onClick
|
|
|
|
const content = (
|
|
<div className="flex items-start gap-3">
|
|
{/* Indicatore timeline */}
|
|
<div className="mt-1 flex flex-col items-center">
|
|
<div
|
|
className={`h-3 w-3 rounded-full border-2 ${
|
|
isRoot
|
|
? 'border-primary bg-primary/20'
|
|
: isClickable
|
|
? 'border-blue-500 bg-blue-100'
|
|
: 'border-muted-foreground bg-muted'
|
|
}`}
|
|
/>
|
|
</div>
|
|
|
|
<div className="flex-1 min-w-0">
|
|
<div className="flex items-center gap-2 flex-wrap">
|
|
<span
|
|
className={`text-sm font-medium truncate ${
|
|
isClickable ? 'text-blue-600 group-hover:underline' : ''
|
|
}`}
|
|
>
|
|
{label}
|
|
</span>
|
|
{state && !isRoot && <PecStateBadge state={state} />}
|
|
{type && type !== 'posta_certificata' && <PecTypeBadge type={type} />}
|
|
{isClickable && (
|
|
<ExternalLink className="h-3.5 w-3.5 text-blue-400 group-hover:text-blue-600 flex-shrink-0" />
|
|
)}
|
|
</div>
|
|
{date && (
|
|
<p className="text-xs text-muted-foreground mt-0.5">{formatDate(date)}</p>
|
|
)}
|
|
</div>
|
|
</div>
|
|
)
|
|
|
|
if (isClickable) {
|
|
return (
|
|
<button
|
|
type="button"
|
|
onClick={onClick}
|
|
className="w-full text-left group rounded-md px-2 py-1 -mx-2 hover:bg-muted/50 transition-colors cursor-pointer"
|
|
title="Apri dettaglio ricevuta"
|
|
>
|
|
{content}
|
|
</button>
|
|
)
|
|
}
|
|
|
|
return <div>{content}</div>
|
|
}
|