diff --git a/frontend/components/Campaigns.tsx b/frontend/components/Campaigns.tsx
index 85be4be..8451a70 100755
--- a/frontend/components/Campaigns.tsx
+++ b/frontend/components/Campaigns.tsx
@@ -1205,50 +1205,50 @@ const CampaignDetail: React.FC<{
reportRootEl.style.top = '0px';
reportRootEl.style.zIndex = '-1';
document.body.appendChild(reportRootEl);
-
+
const reactRoot = ReactDOM.createRoot(reportRootEl);
-
+
try {
const proofsWithLatestVersion = proofsToExport.map(p => ({
...p,
versions: [p.versions[0]], // Only render the latest version
}));
-
+
reactRoot.render();
- await new Promise(resolve => setTimeout(resolve, 1000)); // Wait for render and images
-
- const { default: jspdf } = await import('jspdf');
- const { default: html2canvas } = await import('html2canvas');
+ await new Promise(resolve => setTimeout(resolve, 1500)); // Wait for render and images
const reportContent = reportRootEl.children[0] as HTMLElement;
if (!reportContent) throw new Error("PDF report element not found");
-
- const canvas = await html2canvas(reportContent, { scale: 2, useCORS: true });
-
- const imgData = canvas.toDataURL('image/png');
- const pdf = new jspdf('p', 'mm', 'a4', true);
- const pdfWidth = pdf.internal.pageSize.getWidth();
- const pdfHeight = pdf.internal.pageSize.getHeight();
- const canvasWidth = canvas.width;
- const canvasHeight = canvas.height;
- const ratio = canvasWidth / pdfWidth;
- const pagedCanvasHeight = canvasHeight / ratio;
-
- let heightLeft = pagedCanvasHeight;
- let position = 0;
-
- pdf.addImage(imgData, 'PNG', 0, position, pdfWidth, pagedCanvasHeight, undefined, 'FAST');
- heightLeft -= pdfHeight;
-
- while (heightLeft > 0) {
- position -= pdfHeight;
- pdf.addPage();
- pdf.addImage(imgData, 'PNG', 0, position, pdfWidth, pagedCanvasHeight, undefined, 'FAST');
- heightLeft -= pdfHeight;
- }
-
- pdf.save(`${fileName.replace(/[^a-zA-Z0-9]/g, '_')}.pdf`);
+
+ const safeTitle = fileName.replace(/[^a-zA-Z0-9 _-]/g, '_');
+ const printWindow = window.open('', '_blank');
+ if (!printWindow) throw new Error("Popup blocked. Please allow popups for this site and try again.");
+
+ printWindow.document.write(`
+
+
+ ${safeTitle}
+
+
+
+${reportContent.outerHTML}
+`);
+ printWindow.document.close();
+
+ await new Promise(resolve => {
+ const timeout = setTimeout(resolve, 3000);
+ printWindow.onload = () => { clearTimeout(timeout); resolve(); };
+ });
+
+ printWindow.print();
+ setTimeout(() => { try { printWindow.close(); } catch (_) {} }, 1000);
} catch (error) {
console.error("Failed to generate PDF:", error);
@@ -1618,38 +1618,40 @@ const ProofDetailView: React.FC<{
reactRoot.render();
- await new Promise(resolve => setTimeout(resolve, 1000));
-
- const { default: jspdf } = await import('jspdf');
- const { default: html2canvas } = await import('html2canvas');
+ await new Promise(resolve => setTimeout(resolve, 1500));
const reportContent = reportRootEl.children[0] as HTMLElement;
if (!reportContent) throw new Error("PDF report element not found");
- const canvas = await html2canvas(reportContent, { scale: 2, useCORS: true });
-
- const imgData = canvas.toDataURL('image/png');
- const pdf = new jspdf('p', 'mm', 'a4', true);
- const pdfWidth = pdf.internal.pageSize.getWidth();
- const pdfHeight = pdf.internal.pageSize.getHeight();
- const ratio = canvas.width / pdfWidth;
- const pagedCanvasHeight = canvas.height / ratio;
-
- let heightLeft = pagedCanvasHeight;
- let position = 0;
-
- pdf.addImage(imgData, 'PNG', 0, position, pdfWidth, pagedCanvasHeight, undefined, 'FAST');
- heightLeft -= pdfHeight;
-
- while (heightLeft > 0) {
- position -= pdfHeight;
- pdf.addPage();
- pdf.addImage(imgData, 'PNG', 0, position, pdfWidth, pagedCanvasHeight, undefined, 'FAST');
- heightLeft -= pdfHeight;
- }
-
const fileName = `${campaignName} - ${proof.proofName} V${selectedVersion.version} Report`;
- pdf.save(`${fileName.replace(/[^a-zA-Z0-9]/g, '_')}.pdf`);
+ const safeTitle = fileName.replace(/[^a-zA-Z0-9 _-]/g, '_');
+ const printWindow = window.open('', '_blank');
+ if (!printWindow) throw new Error("Popup blocked. Please allow popups for this site and try again.");
+
+ printWindow.document.write(`
+
+
+ ${safeTitle}
+
+
+
+${reportContent.outerHTML}
+`);
+ printWindow.document.close();
+
+ await new Promise(resolve => {
+ const timeout = setTimeout(resolve, 3000);
+ printWindow.onload = () => { clearTimeout(timeout); resolve(); };
+ });
+
+ printWindow.print();
+ setTimeout(() => { try { printWindow.close(); } catch (_) {} }, 1000);
} catch (error) {
console.error("Failed to generate PDF:", error);
diff --git a/frontend/components/PDFReport.tsx b/frontend/components/PDFReport.tsx
index 8859e5f..715c040 100755
--- a/frontend/components/PDFReport.tsx
+++ b/frontend/components/PDFReport.tsx
@@ -1,7 +1,5 @@
import React from 'react';
-import type { AgentReview, SubReview, RagStatus, OverallStatus } from '../types';
-import { BarclaysLogo } from './icons/BarclaysLogo';
-import { OliverLogo } from './icons/OliverLogo';
+import type { AgentReview, RagStatus } from '../types';
import { LegalIcon } from './icons/LegalIcon';
import { BrandIcon } from './icons/BrandIcon';
import { ChannelIcon } from './icons/ChannelIcon';
@@ -9,6 +7,7 @@ import { ChannelIcon } from './icons/ChannelIcon';
interface PDFReportProps {
campaignName: string;
proofs: any[];
+ baseUrl?: string;
}
/**
@@ -75,9 +74,9 @@ const formatFeedbackTextForPDF = (text: string): React.ReactNode => {
{renderBoldMarkdownForPDF(introLines.join(' '))}
)}
{bulletGroups.length > 0 && (
-
+
{bulletGroups.map((group, index) => (
- -
+
-
{group.map((line, lineIdx) => (
{lineIdx > 0 &&
}
@@ -110,7 +109,7 @@ const RagStatusBadge: React.FC<{ status: RagStatus }> = ({ status }) => {
};
-export const PDFReport: React.FC = ({ campaignName, proofs }) => {
+export const PDFReport: React.FC = ({ campaignName, proofs, baseUrl = window.location.origin }) => {
const today = new Date().toLocaleDateString('en-GB', {
day: '2-digit',
month: 'long',
@@ -125,8 +124,8 @@ export const PDFReport: React.FC = ({ campaignName, proofs }) =>
{/* --- Cover Page --- */}
-
-
+

+
Oliver
AI Compliance & Brand Report
@@ -203,7 +202,7 @@ export const PDFReport: React.FC
= ({ campaignName, proofs }) =>
{/* Detailed Agent Feedback */}
{agentReviews.map(({ title, review, icon }) => (
-
+
{icon} {title}
@@ -214,8 +213,8 @@ export const PDFReport: React.FC = ({ campaignName, proofs }) =>
{review.issues && review.issues.length > 0 && (
Key Actions:
-
- {review.issues.map((issue, i) => - {issue}
)}
+
+ {review.issues.map((issue, i) => - {issue}
)}
)}
diff --git a/frontend/components/icons/BarclaysLogo.tsx b/frontend/components/icons/BarclaysLogo.tsx
index 4c3cc0e..9630db2 100755
--- a/frontend/components/icons/BarclaysLogo.tsx
+++ b/frontend/components/icons/BarclaysLogo.tsx
@@ -1,6 +1,6 @@
import React from 'react';
-// Shield with checkmark - Heroicons "shield-check" (outline)
+// Shield with checkmark - used as Barclays brand icon in UI (Login, LoadingVisual)
export const BarclaysLogo: React.FC> = (props) => (