refactor: Simplify ConversationTimeline component structure and improve readability

This commit is contained in:
2025-06-08 02:08:51 -03:00
parent 8e39623bd9
commit b2f227b54a

View File

@@ -262,330 +262,327 @@ export function ConversationTimeline({
} }
return ( return (
<Card> <>
<CardHeader> {/* <CardHeader> */}
<CardTitle className="flex items-center justify-between"> {/* <CardTitle className="flex items-center justify-between"> */}
<div className="flex items-center gap-2"> <div className="flex justify-between">
<MessageSquare className="h-5 w-5" /> <div className="flex items-center gap-2">
Conversation Timeline <MessageSquare className="h-5 w-5" />
</div> <h2 className="text-lg font-semibold">Conversation Timeline</h2>
<div className="flex items-center gap-2"> </div>
<Badge variant="outline" className={statusColors[debt.status]}> <div className="flex items-center gap-2">
{statusLabels[debt.status]} {/* <Badge variant="outline" className={statusColors[debt.status]}>
</Badge> {statusLabels[debt.status]}
<span className="text-sm text-gray-500"> </Badge> */}
Round {debt.negotiation_round || 1} <span className="text-sm text-gray-500">
</span> Round {debt.negotiation_round || 1}
</div> </span>
</CardTitle> </div>
</CardHeader> </div>
<CardContent className="space-y-4"> {/* </CardTitle> */}
{messages.length === 0 ? ( {/* </CardHeader> */}
<div className="text-center py-8 text-gray-500 dark:text-gray-400"> {/* <CardContent className="space-y-4"> */}
<MessageSquare className="h-12 w-12 mx-auto mb-4 opacity-50" /> {messages.length === 0 ? (
<p>No conversation messages yet</p> <div className="text-center py-8 text-gray-500 dark:text-gray-400">
<p className="text-sm"> <MessageSquare className="h-12 w-12 mx-auto mb-4 opacity-50" />
Messages will appear here as the negotiation progresses <p>No conversation messages yet</p>
</p> <p className="text-sm">
</div> Messages will appear here as the negotiation progresses
) : ( </p>
<div className="space-y-4"> </div>
{messages.map((message, index) => ( ) : (
<div key={message.id} className="relative"> <div className="space-y-4">
{/* Timeline line */} {messages.map((message, index) => (
{index < messages.length - 1 && ( <div key={message.id} className="relative">
<div className="absolute left-4 top-8 bottom-0 w-0.5 bg-gray-200 dark:bg-gray-700" /> {/* Timeline line */}
)} {index < messages.length - 1 && (
<div className="absolute left-4 top-8 bottom-0 w-0.5 bg-gray-200 dark:bg-gray-700" />
)}
<div className="flex gap-4"> <div className="flex gap-4">
{/* Icon */} {/* Icon */}
<div <div
className={` className={`
flex items-center justify-center w-8 h-8 rounded-full border-2 bg-white dark:bg-gray-800 flex items-center justify-center w-8 h-8 rounded-full border-2 bg-white dark:bg-gray-800
${getMessageColor(message)} border-current ${getMessageColor(message)} border-current
`} `}
> >
{getMessageIcon(message)} {getMessageIcon(message)}
</div>
{/* Content */}
<div className="flex-1 min-w-0">
<div className="flex items-center justify-between mb-2">
<div className="flex items-center gap-2">
<h4 className="font-medium text-gray-900 dark:text-foreground">
{messageTypeLabels[message.message_type] ||
message.message_type}
</h4>
{message.ai_analysis?.sentiment &&
getSentimentIcon(message.ai_analysis.sentiment)}
</div>
<div className="flex items-center gap-2 text-sm text-gray-500 dark:text-gray-400">
<Calendar className="h-3 w-3" />
{formatDate(message.created_at)}
</div>
</div> </div>
{/* Content */} <div className="flex items-center gap-2 text-sm text-gray-600 dark:text-gray-300 mb-2">
<div className="flex-1 min-w-0"> {message.direction === "outbound" ? (
<div className="flex items-center justify-between mb-2"> <>
<div className="flex items-center gap-2"> <User className="h-3 w-3" />
<h4 className="font-medium text-gray-900 dark:text-foreground"> <span>You {message.to_email}</span>
{messageTypeLabels[message.message_type] || </>
message.message_type} ) : (
</h4> <>
{message.ai_analysis?.sentiment && <Building2 className="h-3 w-3" />
getSentimentIcon(message.ai_analysis.sentiment)} <span>{message.from_email} You</span>
</div> </>
<div className="flex items-center gap-2 text-sm text-gray-500 dark:text-gray-400">
<Calendar className="h-3 w-3" />
{formatDate(message.created_at)}
</div>
</div>
<div className="flex items-center gap-2 text-sm text-gray-600 dark:text-gray-300 mb-2">
{message.direction === "outbound" ? (
<>
<User className="h-3 w-3" />
<span>You {message.to_email}</span>
</>
) : (
<>
<Building2 className="h-3 w-3" />
<span>{message.from_email} You</span>
</>
)}
</div>
{message.subject && (
<p className="text-sm font-medium text-gray-800 dark:text-gray-200 mb-2">
Subject: {message.subject}
</p>
)} )}
</div>
<div className="bg-gray-50 dark:bg-gray-800 rounded-lg p-3 text-sm"> {message.subject && (
<p className="whitespace-pre-wrap text-gray-700 dark:text-gray-300"> <p className="text-sm font-medium text-gray-800 dark:text-gray-200 mb-2">
{message.body.length > 200 Subject: {message.subject}
? `${message.body.substring(0, 200)}...` </p>
: message.body} )}
</p>
</div>
{/* AI Analysis */} <div className="bg-gray-50 dark:bg-gray-800 rounded-lg p-3 text-sm">
{message.ai_analysis && ( <p className="whitespace-pre-wrap text-gray-700 dark:text-gray-300">
<div className="mt-2 space-y-2"> {message.body.length > 200
{message.ai_analysis.intent && ( ? `${message.body.substring(0, 200)}...`
<div className="flex items-center gap-2 my-2"> : message.body}
<Badge </p>
variant={ </div>
message.ai_analysis.intent === "acceptance"
? "default"
: "secondary"
}
className={`text-xs ${
message.ai_analysis.intent === "acceptance"
? "bg-green-600 text-white"
: ""
}`}
>
Intent: {message.ai_analysis.intent}
</Badge>
{message.ai_analysis.confidence && (
<span className="text-xs text-gray-500">
{Math.round(
message.ai_analysis.confidence * 100
)}
% confidence
</span>
)}
</div>
)}
{!!message.ai_analysis.extractedTerms {/* AI Analysis */}
?.proposedAmount && ( {message.ai_analysis && (
<div className="text-xs text-gray-600 dark:text-gray-400"> <div className="mt-2 space-y-2">
Proposed Amount: $ {message.ai_analysis.intent && (
{formatCurrency( <div className="flex items-center gap-2 my-2">
message.ai_analysis.extractedTerms.proposedAmount <Badge
)} variant={
</div> message.ai_analysis.intent === "acceptance"
)} ? "default"
: "secondary"
}
className={`text-xs ${
message.ai_analysis.intent === "acceptance"
? "bg-green-600 text-white"
: ""
}`}
>
Intent: {message.ai_analysis.intent}
</Badge>
{message.ai_analysis.confidence && (
<span className="text-xs text-gray-500">
{Math.round(message.ai_analysis.confidence * 100)}
% confidence
</span>
)}
</div>
)}
{/* Show financial outcome for accepted offers */} {!!message.ai_analysis.extractedTerms?.proposedAmount && (
{message.ai_analysis.intent === "acceptance" && <div className="text-xs text-gray-600 dark:text-gray-400">
debt.metadata?.financialOutcome && ( Proposed Amount: $
<div className="bg-green-50 dark:bg-green-900/20 border border-green-200 dark:border-green-800 rounded-lg p-3 mt-2"> {formatCurrency(
{debt.metadata.financialOutcome.financialBenefit message.ai_analysis.extractedTerms.proposedAmount
?.type === "principal_reduction" ? ( )}
<> </div>
<div className="flex items-center gap-2 mb-2"> )}
<TrendingUp className="h-4 w-4 text-green-600" />
<span className="font-medium text-green-800 dark:text-green-200"> {/* Show financial outcome for accepted offers */}
Principal Reduction Achieved {message.ai_analysis.intent === "acceptance" &&
debt.metadata?.financialOutcome && (
<div className="bg-green-50 dark:bg-green-900/20 border border-green-200 dark:border-green-800 rounded-lg p-3 mt-2">
{debt.metadata.financialOutcome.financialBenefit
?.type === "principal_reduction" ? (
<>
<div className="flex items-center gap-2 mb-2">
<TrendingUp className="h-4 w-4 text-green-600" />
<span className="font-medium text-green-800 dark:text-green-200">
Principal Reduction Achieved
</span>
</div>
<div className="grid grid-cols-2 gap-2 text-xs">
<div>
<span className="text-gray-600 dark:text-gray-400">
Original Debt:
</span> </span>
</div> <div className="font-medium">
<div className="grid grid-cols-2 gap-2 text-xs"> $
<div> {
<span className="text-gray-600 dark:text-gray-400"> debt.metadata.financialOutcome
Original Debt: .originalAmount
</span> }
<div className="font-medium">
$
{
debt.metadata.financialOutcome
.originalAmount
}
</div>
</div>
<div>
<span className="text-gray-600 dark:text-gray-400">
Settlement Amount:
</span>
<div className="font-medium">
$
{
debt.metadata.financialOutcome
.acceptedAmount
}
</div>
</div>
<div>
<span className="text-gray-600 dark:text-gray-400">
Total Savings:
</span>
<div className="font-medium text-green-600">
$
{
debt.metadata.financialOutcome
.actualSavings
}
</div>
</div>
<div>
<span className="text-gray-600 dark:text-gray-400">
Reduction:
</span>
<div className="font-medium text-green-600">
{
debt.metadata.financialOutcome
.financialBenefit.percentage
}
%
</div>
</div> </div>
</div> </div>
</> <div>
) : debt.metadata.financialOutcome <span className="text-gray-600 dark:text-gray-400">
.financialBenefit?.type === Settlement Amount:
"payment_restructuring" ? (
<>
<div className="flex items-center gap-2 mb-2">
<Calendar className="h-4 w-4 text-blue-600" />
<span className="font-medium text-blue-800 dark:text-blue-200">
Payment Plan Restructured
</span> </span>
<div className="font-medium">
$
{
debt.metadata.financialOutcome
.acceptedAmount
}
</div>
</div> </div>
<div className="space-y-2 text-xs"> <div>
<div className="bg-blue-50 dark:bg-blue-900/30 rounded p-2"> <span className="text-gray-600 dark:text-gray-400">
<div className="font-medium text-blue-800 dark:text-blue-200 mb-1"> Total Savings:
{ </span>
debt.metadata.financialOutcome <div className="font-medium text-green-600">
.financialBenefit.description $
} {
</div> debt.metadata.financialOutcome
{debt.metadata.financialOutcome .actualSavings
.financialBenefit.cashFlowBenefit && ( }
<div className="text-blue-600 dark:text-blue-300"> </div>
💰{" "} </div>
{ <div>
debt.metadata.financialOutcome <span className="text-gray-600 dark:text-gray-400">
.financialBenefit.cashFlowBenefit Reduction:
} </span>
</div> <div className="font-medium text-green-600">
)} {
debt.metadata.financialOutcome
.financialBenefit.percentage
}
%
</div>
</div>
</div>
</>
) : debt.metadata.financialOutcome.financialBenefit
?.type === "payment_restructuring" ? (
<>
<div className="flex items-center gap-2 mb-2">
<Calendar className="h-4 w-4 text-blue-600" />
<span className="font-medium text-blue-800 dark:text-blue-200">
Payment Plan Restructured
</span>
</div>
<div className="space-y-2 text-xs">
<div className="bg-blue-50 dark:bg-blue-900/30 rounded p-2">
<div className="font-medium text-blue-800 dark:text-blue-200 mb-1">
{
debt.metadata.financialOutcome
.financialBenefit.description
}
</div> </div>
{debt.metadata.financialOutcome {debt.metadata.financialOutcome
.paymentStructure && ( .financialBenefit.cashFlowBenefit && (
<div className="grid grid-cols-2 gap-2"> <div className="text-blue-600 dark:text-blue-300">
<div> 💰{" "}
<span className="text-gray-600 dark:text-gray-400"> {
Monthly Payment: debt.metadata.financialOutcome
</span> .financialBenefit.cashFlowBenefit
<div className="font-medium"> }
$
{
debt.metadata.financialOutcome
.paymentStructure.monthlyAmount
}
</div>
</div>
<div>
<span className="text-gray-600 dark:text-gray-400">
Term Length:
</span>
<div className="font-medium">
{
debt.metadata.financialOutcome
.paymentStructure
.numberOfPayments
}{" "}
months
</div>
</div>
<div>
<span className="text-gray-600 dark:text-gray-400">
Total Amount:
</span>
<div className="font-medium">
$
{formatCurrency(
debt.metadata.financialOutcome
.paymentStructure.totalAmount
)}
</div>
</div>
<div>
<span className="text-gray-600 dark:text-gray-400">
Frequency:
</span>
<div className="font-medium capitalize">
{
debt.metadata.financialOutcome
.paymentStructure.frequency
}
</div>
</div>
</div> </div>
)} )}
</div> </div>
</> {debt.metadata.financialOutcome
) : ( .paymentStructure && (
<> <div className="grid grid-cols-2 gap-2">
<div className="flex items-center gap-2 mb-2"> <div>
<CheckCircle className="h-4 w-4 text-green-600" /> <span className="text-gray-600 dark:text-gray-400">
<span className="font-medium text-green-800 dark:text-green-200"> Monthly Payment:
Offer Accepted </span>
</span> <div className="font-medium">
</div> $
<div className="text-xs text-gray-600 dark:text-gray-400"> {
Settlement terms have been agreed upon. debt.metadata.financialOutcome
</div> .paymentStructure.monthlyAmount
</> }
)} </div>
</div> </div>
)} <div>
</div> <span className="text-gray-600 dark:text-gray-400">
)} Term Length:
</div> </span>
<div className="font-medium">
{
debt.metadata.financialOutcome
.paymentStructure.numberOfPayments
}{" "}
months
</div>
</div>
<div>
<span className="text-gray-600 dark:text-gray-400">
Total Amount:
</span>
<div className="font-medium">
$
{formatCurrency(
debt.metadata.financialOutcome
.paymentStructure.totalAmount
)}
</div>
</div>
<div>
<span className="text-gray-600 dark:text-gray-400">
Frequency:
</span>
<div className="font-medium capitalize">
{
debt.metadata.financialOutcome
.paymentStructure.frequency
}
</div>
</div>
</div>
)}
</div>
</>
) : (
<>
<div className="flex items-center gap-2 mb-2">
<CheckCircle className="h-4 w-4 text-green-600" />
<span className="font-medium text-green-800 dark:text-green-200">
Offer Accepted
</span>
</div>
<div className="text-xs text-gray-600 dark:text-gray-400">
Settlement terms have been agreed upon.
</div>
</>
)}
</div>
)}
</div>
)}
</div> </div>
</div> </div>
))}
</div>
)}
<Separator className="my-4" />
{/* Summary */}
<div className="bg-blue-50 dark:bg-blue-900/20 rounded-lg p-4">
<div className="flex items-center justify-between text-sm">
<div className="flex items-center gap-4">
<span className="text-gray-600 dark:text-gray-300">
Total Messages: {messages.length}
</span>
<span className="text-gray-600 dark:text-gray-300">
Negotiation Round: {debt.negotiation_round || 1}
</span>
</div> </div>
{debt.last_message_at && ( ))}
<span className="text-gray-500 dark:text-gray-400">
Last Activity: {formatDate(debt.last_message_at)}
</span>
)}
</div>
</div> </div>
</CardContent> )}
</Card>
<Separator className="my-4" />
{/* Summary */}
<div className="bg-blue-50 dark:bg-blue-900/20 rounded-lg p-4">
<div className="flex items-center justify-between text-sm">
<div className="flex items-center gap-4">
<span className="text-gray-600 dark:text-gray-300">
Total Messages: {messages.length}
</span>
<span className="text-gray-600 dark:text-gray-300">
Negotiation Round: {debt.negotiation_round || 1}
</span>
</div>
{debt.last_message_at && (
<span className="text-gray-500 dark:text-gray-400">
Last Activity: {formatDate(debt.last_message_at)}
</span>
)}
</div>
</div>
{/* </CardContent> */}
</>
); );
} }