Skip to content

Commit

Permalink
Merge pull request #273 from COS301-SE-2024/feature/update-download-pdf
Browse files Browse the repository at this point in the history
Feature/update download pdf
  • Loading branch information
Johane-B authored Jul 30, 2024
2 parents 6793850 + 6a67a79 commit 4a4d52a
Show file tree
Hide file tree
Showing 4 changed files with 678 additions and 322 deletions.
120 changes: 5 additions & 115 deletions wee/frontend/src/app/(pages)/results/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { saveReport } from '../../services/SaveReportService';
import { Metadata, ErrorResponse } from '../../models/ScraperModels';
import { FiSearch, FiImage, FiAnchor, FiLink, FiCode, FiUmbrella, FiBook } from "react-icons/fi";
import { TitleTagsAnalysis, HeadingAnalysis, ImageAnalysis, InternalLinksAnalysis, MetaDescriptionAnalysis, UniqueContentAnalysis, SEOError } from '../../models/ScraperModels';
import { handleDownloadReport } from '../../services/DownloadIndividualReport';

interface Classifications {
label: string;
Expand Down Expand Up @@ -151,119 +152,8 @@ function ResultsComponent() {
router.back();
};

const handleDownloadReport = () => {
const doc = new jsPDF();

// Title
doc.setFontSize(20);
const title = 'Web Exploration Engine Individual Report';
const titleWidth = doc.getStringUnitWidth(title) * 20 / doc.internal.scaleFactor;
const x = (doc.internal.pageSize.width - titleWidth) / 2;
doc.text(title, x, 20);

// Define table positions and dimensions
const startY = 30;
const margin = 14;
const headerHeight = 10;
const rowHeight = 10;
const columnWidth = [60, 190];

// Function to draw a horizontal line
const drawLine = (lineY: number): void => {
doc.setDrawColor(200, 200, 200); // Light grey color
doc.line(0, lineY - 1, margin + columnWidth[0] + columnWidth[1], lineY - 1);
};

// Draw Table Header
const darkTealGreenR = 47;
const darkTealGreenG = 139;
const darkTealGreenB = 87;
doc.setFontSize(14);
doc.setFillColor(darkTealGreenR, darkTealGreenG, darkTealGreenB); // Set header background color
doc.rect(0, startY, columnWidth[0] + columnWidth[1], headerHeight, 'F');
doc.setTextColor(255, 255, 255);
doc.text('Category', margin + 2, startY + 7);
doc.text('Information', margin + columnWidth[0] + 2, startY + 7);

// Function to split text into lines that fit within a max width
const splitText =(text: string, maxWidth: number): string[] => {
const lines = [];
let line = '';
const words = text.split(' ');

for (const word of words) {
const testLine = line + (line.length > 0 ? ' ' : '') + word;
const testWidth = doc.getStringUnitWidth(testLine) * 20 / doc.internal.scaleFactor;

if (testWidth > maxWidth) {
lines.push(line);
line = word;
} else {
line = testLine;
}
}
if (line.length > 0) {
lines.push(line);
}

return lines;
};

// Draw Table Rows
const rows = [
['URL', url || 'N/A'],
['Title', summaryInfo?.title || 'N/A'],
['Description', summaryInfo?.description || 'N/A'],
['Website Status', websiteStatus || 'N/A'],
['Crawlable', isCrawlable ? 'Yes' : 'No'],
['Industry', industryClassification?.label || 'N/A'],
['Confidence Score', isCrawlable ? `${(industryClassification?.score ? (industryClassification.score * 100).toFixed(2) : 0)}%` : 'N/A'],
['Domain Match', domainClassification?.label || 'N/A'],
['Confidence Score', isCrawlable ? `${(domainClassification?.score ? (domainClassification.score * 100).toFixed(2) : 0)}%` : 'N/A'],
];

let y = startY + headerHeight;
doc.setFontSize(12);
doc.setTextColor(0, 0, 0);

rows.forEach(row => {
const [category, info] = row;
const categoryLines = splitText(category, columnWidth[0] - 4);
const infoLines = splitText(info, columnWidth[1] - 4);

categoryLines.forEach((line, i) => {
doc.text(line, margin + 2, y + (i * rowHeight) + 7);
});
infoLines.forEach((line, i) => {
doc.text(line, margin + columnWidth[0] + 2, y + (i * rowHeight) + 7);
});

// Draw line after each row
drawLine(y + Math.max(categoryLines.length, infoLines.length) * rowHeight + 3);

y += Math.max(categoryLines.length, infoLines.length) * rowHeight;

if (y > 270) { // Check if the y position exceeds the page limit
doc.addPage();
y = 20; // Reset y position on the new page
doc.text('Category', margin + 2, y + 7);
doc.text('Information', margin + columnWidth[0] + 2, y + 7);
y += headerHeight;
}
});

// Clean Filename
const cleanFilename = (url: string | null): string => {
if (!url) return 'website-summary-report';
let filename = url.replace('http://', '').replace('https://', '');
filename = filename.split('').map(char => {
return ['/', ':', '*', '?', '"', '<', '>', '|'].includes(char) ? '_' : char;
}).join('');
return filename.length > 50 ? filename.substring(0, 50) : filename;
};

const filename = cleanFilename(url);
doc.save(`${filename}.pdf`);
const downloadSummaryReport = (key: any) => {
handleDownloadReport(url, summaryInfo, websiteStatus, isCrawlable, industryClassification, domainClassification,addresses,emails,phones,socialLinks,titleTagsAnalysis,headingAnalysis,imagesAnalysis,internalLinkingAnalysis,metaDescriptionAnalysis,uniqContentAnalysis);
};

// Pagination Logic
Expand Down Expand Up @@ -380,7 +270,7 @@ function ResultsComponent() {
key="download"
startContent={<FiDownload className={iconClasses}/>}
description="Download the report to your device"
onAction={handleDownloadReport}
onAction={downloadSummaryReport}
data-testid="download-report-button"
>
Download
Expand All @@ -399,7 +289,7 @@ function ResultsComponent() {
key="download"
startContent={<FiDownload className={iconClasses}/>}
description="Download the report to your device"
onAction={handleDownloadReport}
onAction={downloadSummaryReport}
data-testid="download-report-button"
>
Download
Expand Down
214 changes: 7 additions & 207 deletions wee/frontend/src/app/(pages)/summaryreport/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import jsPDF from 'jspdf';
import html2canvas from 'html2canvas';import { FiShare, FiDownload, FiSave } from "react-icons/fi";
import { useUserContext } from '../../context/UserContext';
import { saveReport } from '../../services/SaveReportService';

import { generatePDFReport } from '../../services/DownloadSummaryReport'

interface weakClassification {
url: string;
Expand Down Expand Up @@ -126,212 +126,12 @@ export default function SummaryReport() {


const handleDownloadReport = async () => {
if (!summaryReport) {
console.error("Summary report is undefined");
return;
}

const doc = new jsPDF();
let currentPage = 1;

// Function to add page number to the footer
const addPageNumber = (pageNumber: number) => {
doc.setFontSize(10);
doc.text(`Page ${pageNumber-1}`, doc.internal.pageSize.width - 30, doc.internal.pageSize.height - 10);
};

// Title
doc.setFontSize(20);
const title = 'Web Exploration Engine Summary Report';
const titleWidth = doc.getStringUnitWidth(title) * 20 / doc.internal.scaleFactor;
const x = (doc.internal.pageSize.width - titleWidth) / 2;
doc.text(title, x, 20);

// Define table positions and dimensions
const startY = 30;
const margin = 14;
const headerHeight = 10;
const rowHeight = 10;
const columnWidth = [60, 190];

// Function to draw a horizontal line
const drawLine = (lineY: number): void => {
doc.setDrawColor(200, 200, 200); // Set line color to light grey
doc.line(0, lineY - 1, margin + columnWidth[0] + columnWidth[1], lineY - 1); // Draw horizontal line
};

// Draw Table Header
const darkTealGreenR = 47;
const darkTealGreenG = 139;
const darkTealGreenB = 87;
doc.setFontSize(14);
doc.setFillColor(darkTealGreenR, darkTealGreenG, darkTealGreenB); // Set header background color
doc.rect(0, startY, columnWidth[0] + columnWidth[1], headerHeight, 'F');
doc.setTextColor(255, 255, 255);
doc.text('Category', margin + 2, startY + 7);
doc.text('Information', margin + columnWidth[0] + 2, startY + 7);

// Function to split text into lines that fit within a max width
const splitText = (text: string, maxWidth: number): string[] => {
const lines = [];
let line = '';
const words = text.split(' ');

for (const word of words) {
const testLine = line + (line.length > 0 ? ' ' : '') + word;
const testWidth = doc.getStringUnitWidth(testLine) * 20 / doc.internal.scaleFactor;

if (testWidth > maxWidth) {
lines.push(line);
line = word;
} else {
line = testLine;
}
}
if (line.length > 0) {
lines.push(line);
}

return lines;
};

// Draw Table Rows
const rows = [
['Total URLs', summaryReport.totalUrls?.toString() || 'N/A'],
['Scrapable URLs', summaryReport.scrapableUrls?.toString() || 'N/A'],
['Average Time', `${summaryReport.avgTime?.toString() || 'N/A'} seconds`],
];

let y = startY + headerHeight;
doc.setFontSize(12);
doc.setTextColor(0, 0, 0);

rows.forEach(row => {
const [category, info] = row;
const categoryLines = splitText(category, columnWidth[0] - 4);
const infoLines = splitText(info, columnWidth[1] - 4);

categoryLines.forEach((line, i) => {
doc.text(line, margin + 2, y + (i * rowHeight) + 7);
});
infoLines.forEach((line, i) => {
doc.text(line, margin + columnWidth[0] + 2, y + (i * rowHeight) + 7);
});

// Draw line after each row
drawLine(y + Math.max(categoryLines.length, infoLines.length) * rowHeight + 3);

y += Math.max(categoryLines.length, infoLines.length) * rowHeight;

if (y > 270) { // Check if the y position exceeds the page limit
doc.addPage();
addPageNumber(++currentPage); // Add page number before the new content
y = 20; // Reset y position on the new page
doc.text('Category', margin + 2, y + 7);
doc.text('Information', margin + columnWidth[0] + 2, y + 7);
y += headerHeight;
}
});

// Add page number to the last page
addPageNumber(++currentPage);

// Function to add chart to PDF
const addChartToPDF = async () => {
const captureChart = async (chartId: string, title: string, yPosition: number) => {
const chartElement = document.getElementById(chartId);
if (chartElement) {
const canvas = await html2canvas(chartElement);
const imgData = canvas.toDataURL('image/png');
doc.addPage();
addPageNumber(++currentPage); // Add page number before the new content
doc.setFontSize(18);
doc.text(title, 20, 20);

// Calculate image dimensions based on aspect ratio
const width = doc.internal.pageSize.width - 40; // Adjust as needed
const height = canvas.height * (width / canvas.width);

doc.addImage(imgData, 'PNG', 20, yPosition, width, height);

}
};

// Example usage
await captureChart('pie-chart', 'Industry Classification Distribution', 30);
// Add list of low confidence URLs
if (weakClassification && weakClassification.length > 0) {
const lowConfidenceUrls = weakClassification
.filter(item => item.score < 0.5) // Adjust threshold as needed
.map(item => item.url);

if (lowConfidenceUrls.length > 0) {
doc.addPage();
addPageNumber(++currentPage); // Add page number before the new content
doc.setFontSize(18);
doc.text('Low Confidence URLs (Confidence Score < 50%)', 20, 20);
doc.setFontSize(12);
lowConfidenceUrls.forEach((url, index) => {
const y = 30 + index * 10; // Adjust as needed for spacing
doc.text(`${index + 1}. ${url}`, 20, y);
});
}
}

await captureChart('bar-chart', 'Website Status Distribution', 30);
if (parkedUrls && parkedUrls.length > 0) {
doc.addPage();
addPageNumber(++currentPage); // Add page number before the new content
doc.setFontSize(12);
doc.text('Parked URLs', 20, 20);

parkedUrls.forEach((url, index) => {
const y = 30 + index * 10; // Adjust as needed for spacing
doc.text(`${index + 1}. ${url}`, 20, y);
});
}


await captureChart('radial-chart', 'Domain Match Distribution', 30);
// Add list of mismatched URLs
if (mismatchedUrls && mismatchedUrls.length > 0) {
doc.addPage();
addPageNumber(++currentPage); // Add page number before the new content
doc.setFontSize(12);
doc.text('Mismatched URLs', 20, 20);

mismatchedUrls.forEach((item, index) => {
const startY = 30;
const lineHeight = 10; // Line height for each item
const maxLinesPerPage = Math.floor((doc.internal.pageSize.height - startY) / lineHeight); // Calculate max lines per page
const lines: string[] | undefined = doc.splitTextToSize(`${index + 1}. ${item.url} - Meta: ${item.metadataClass}, Domain: ${item.domainClass}`, doc.internal.pageSize.width - 40);

if (lines) {
if (index > 0 && (startY + lines.length * lineHeight) > doc.internal.pageSize.height - 20) {
doc.addPage();
addPageNumber(++currentPage);
doc.setFontSize(12);
doc.text('Mismatched URLs (Continued)', 20, 20);
}

lines.forEach((line: string, i: number) => {
const y: number = startY + i * lineHeight;
doc.text(line, 20, y);
});
} else {
console.error('splitTextToSize returned undefined for item:', item);
}
});

}

// Save the PDF
doc.save('website-summary-report.pdf');
};

// Add charts and save the PDF
await addChartToPDF();
doc.save('website-summary-report.pdf');
await generatePDFReport(
summaryReport,
weakClassification || [],
parkedUrls || [],
mismatchedUrls || []
);
};

return (
Expand Down
Loading

0 comments on commit 4a4d52a

Please sign in to comment.