diff --git a/frontend/components/FeedbackReport.tsx b/frontend/components/FeedbackReport.tsx index 1de2908..955a3a2 100755 --- a/frontend/components/FeedbackReport.tsx +++ b/frontend/components/FeedbackReport.tsx @@ -7,6 +7,72 @@ import { BugIcon } from './icons/BugIcon'; import { ExportIcon } from './icons/ExportIcon'; import { LegalIcon } from './icons/LegalIcon'; +/** + * Formats feedback text from Gemini API into properly structured React elements. + * Handles HTML tags, bullet characters, and newline-separated text. + */ +const formatFeedbackText = (text: string): React.ReactNode => { + if (!text) return null; + + // First, handle HTML tags by converting them to a normalized format + let normalizedText = text + // Replace and with newlines + .replace(/<\/li>/gi, '\n') + .replace(/<\/ul>/gi, '\n') + // Remove opening tags + .replace(/]*>/gi, '') + .replace(/]*>/gi, '• ') + // Remove any other HTML tags + .replace(/<[^>]+>/g, '') + // Normalize whitespace around bullets + .replace(/\s*•\s*/g, '\n• ') + // Clean up multiple newlines + .replace(/\n{2,}/g, '\n') + .trim(); + + // Split into lines + const lines = normalizedText.split('\n').filter(line => line.trim()); + + // Separate intro text from bullet points + const bulletLines: string[] = []; + const introLines: string[] = []; + + lines.forEach(line => { + const trimmed = line.trim(); + if (trimmed.startsWith('•')) { + // Remove the bullet character, we'll add it via CSS + bulletLines.push(trimmed.replace(/^•\s*/, '').trim()); + } else if (trimmed) { + // If we haven't started collecting bullets yet, it's intro text + if (bulletLines.length === 0) { + introLines.push(trimmed); + } else { + // Text after bullets - treat as continuation of last bullet + const lastBullet = bulletLines.pop(); + if (lastBullet) { + bulletLines.push(`${lastBullet} ${trimmed}`); + } else { + bulletLines.push(trimmed); + } + } + } + }); + + return ( + <> + {introLines.length > 0 && ( +

{introLines.join(' ')}

+ )} + {bulletLines.length > 0 && ( + + )} + + ); +}; const RagStatusBadge: React.FC<{ status: RagStatus; isLarge?: boolean }> = ({ status, isLarge = false }) => { let colorClasses = ''; @@ -301,7 +367,9 @@ const SubReviewCard: React.FC<{ -

{review.feedback}

+
+ {formatFeedbackText(review.feedback)} +
{currentStatus !== 'Error' && issues.length > 0 && (
@@ -406,9 +474,9 @@ const LeadAgentSummary: React.FC<{ status: OverallStatus, summary: string, onFla
-

- {summary} -

+
+ {formatFeedbackText(summary)} +