Skip to content

Commit 3115104

Browse files
Merge pull request #3407 from OneCommunityGlobal/Samman-sharepdf
Samman_SharePDF button for phase II
2 parents 7085b33 + 8a0c759 commit 3115104

6 files changed

Lines changed: 219 additions & 6 deletions

File tree

package-lock.json

Lines changed: 120 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,9 @@
2929
"history": "^4.10.1",
3030
"html-react-parser": "^1.4.14",
3131
"html-to-pdfmake": "^2.0.6",
32+
"html2canvas": "^1.4.1",
3233
"joi": "^14.0.6",
34+
"jspdf": "^3.0.1",
3335
"jwt-decode": "^2.2.0",
3436
"leaflet": "1.7.1",
3537
"leaflet.heat": "^0.2.0",

src/components/BMDashboard/WeeklyProjectSummary/WeeklyProjectSummary.jsx

Lines changed: 91 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import { useEffect, useMemo, useState } from 'react';
22
import './WeeklyProjectSummary.css';
33
import { useDispatch, useSelector } from 'react-redux';
44
import { v4 as uuidv4 } from 'uuid';
5+
import html2canvas from 'html2canvas';
6+
import { jsPDF } from 'jspdf';
57
import WeeklyProjectSummaryHeader from './WeeklyProjectSummaryHeader';
68
import { fetchAllMaterials } from '../../../actions/bmdashboard/materialsActions';
79
import QuantityOfMaterialsUsed from './QuantityOfMaterialsUsed/QuantityOfMaterialsUsed';
@@ -268,9 +270,97 @@ export default function WeeklyProjectSummary() {
268270
[quantityOfMaterialsUsedData],
269271
);
270272

273+
const handleSaveAsPDF = async () => {
274+
const currentOpenSections = { ...openSections };
275+
276+
try {
277+
const allSectionsOpen = {};
278+
sections.forEach(section => {
279+
allSectionsOpen[section.key] = true;
280+
});
281+
setOpenSections(allSectionsOpen);
282+
283+
// eslint-disable-next-line no-promise-executor-return
284+
await new Promise(resolve => setTimeout(resolve, 500));
285+
286+
const contentElement = document.querySelector('.weekly-project-summary-container');
287+
if (!contentElement) throw new Error('Weekly project summary container not found.');
288+
289+
const pdfContainer = document.createElement('div');
290+
pdfContainer.id = 'pdf-export-container';
291+
Object.assign(pdfContainer.style, {
292+
width: '420mm',
293+
padding: '10mm',
294+
backgroundColor: '#fff',
295+
position: 'absolute',
296+
left: '-9999px',
297+
boxSizing: 'border-box',
298+
});
299+
300+
const clonedContent = contentElement.cloneNode(true);
301+
302+
// Remove buttons and controls not needed in PDF
303+
clonedContent
304+
.querySelectorAll(
305+
'button, .weekly-project-summary-dropdown-icon, .no-print, .weekly-summary-header-controls',
306+
)
307+
.forEach(el => el.parentNode?.removeChild(el));
308+
309+
const styleElem = document.createElement('style');
310+
styleElem.textContent = `
311+
img, svg {
312+
height: auto !important;
313+
page-break-inside: avoid !important;
314+
}
315+
`;
316+
317+
clonedContent.prepend(styleElem);
318+
pdfContainer.appendChild(clonedContent);
319+
document.body.appendChild(pdfContainer);
320+
321+
const canvas = await html2canvas(pdfContainer, {
322+
scale: 2,
323+
useCORS: true,
324+
backgroundColor: '#fff',
325+
windowWidth: pdfContainer.scrollWidth,
326+
windowHeight: pdfContainer.scrollHeight,
327+
logging: false,
328+
});
329+
330+
if (!canvas) throw new Error('Failed to capture content as image.');
331+
332+
const imgData = canvas.toDataURL('image/jpeg', 0.95);
333+
334+
const pdfWidth = 210;
335+
const imgHeight = (canvas.height * pdfWidth) / canvas.width;
336+
337+
// eslint-disable-next-line new-cap
338+
const pdf = new jsPDF({
339+
orientation: 'portrait',
340+
unit: 'mm',
341+
format: [pdfWidth, imgHeight],
342+
});
343+
344+
pdf.addImage(imgData, 'JPEG', 0, 0, pdfWidth, imgHeight);
345+
346+
const now = new Date();
347+
const fileName = `weekly-project-summary-${now.toISOString().slice(0, 10)}.pdf`;
348+
349+
// Save the PDF
350+
pdf.save(fileName);
351+
352+
document.body.removeChild(pdfContainer);
353+
} catch (err) {
354+
// eslint-disable-next-line no-console
355+
console.error('PDF generation failed:', err);
356+
} finally {
357+
setOpenSections(currentOpenSections);
358+
}
359+
};
360+
271361
return (
272362
<div className={`weekly-project-summary-container ${darkMode ? 'dark-mode' : ''}`}>
273-
<WeeklyProjectSummaryHeader />
363+
<WeeklyProjectSummaryHeader handleSaveAsPDF={handleSaveAsPDF} />
274364
<div className="weekly-project-summary-dashboard-container">
275365
<div className="weekly-project-summary-dashboard-grid">
276366
{sections.map(({ title, key, className, content }) => (

src/components/BMDashboard/WeeklyProjectSummary/WeeklyProjectSummaryHeader.jsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import {
99
} from '../../../actions/bmdashboard/weeklyProjectSummaryActions';
1010
import './WeeklyProjectSummary.css';
1111

12-
export default function WeeklyProjectSummaryHeader() {
12+
export default function WeeklyProjectSummaryHeader({ handleSaveAsPDF }) {
1313
const dispatch = useDispatch();
1414
const projectFilter = useSelector(state => state.weeklyProjectSummary.projectFilter);
1515
const dateRangeFilter = useSelector(state => state.weeklyProjectSummary.dateRangeFilter);
@@ -100,7 +100,9 @@ export default function WeeklyProjectSummaryHeader() {
100100
))}
101101
</Input>
102102

103-
<Button className="weekly-summary-share-btn">Share PDF</Button>
103+
<Button className="weekly-summary-share-btn" onClick={handleSaveAsPDF}>
104+
Share PDF
105+
</Button>
104106
</div>
105107
</header>
106108
</div>

src/components/TotalOrgSummary/AccordianWrapper/AccordianWrapper.jsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ export default function AccordianWrapper({ children, title }) {
77

88
return (
99
<Collapsible
10+
open
1011
className={darkMode ? 'bg-space-cadet text-light' : ''}
1112
openedClassName={darkMode ? 'bg-space-cadet text-light' : ''}
1213
trigger={title}

src/components/TotalOrgSummary/TotalOrgSummary.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,4 +52,4 @@
5252

5353
.chart-title.dark-mode p{
5454
color: white;
55-
}
55+
}

0 commit comments

Comments
 (0)