datastake-daf 0.6.423 → 0.6.424
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/index.js +138 -209
- package/package.json +1 -1
- package/src/@daf/core/components/Dashboard/PdfView/index.jsx +119 -232
package/dist/components/index.js
CHANGED
|
@@ -13305,12 +13305,41 @@ DAFFooter.propTypes = {
|
|
|
13305
13305
|
const PAGE_HEIGHT = 1587;
|
|
13306
13306
|
const FOOTER_HEIGHT = 70;
|
|
13307
13307
|
const HEADER_HEIGHT = 100;
|
|
13308
|
-
const
|
|
13309
|
-
const
|
|
13310
|
-
|
|
13311
|
-
const
|
|
13312
|
-
|
|
13313
|
-
|
|
13308
|
+
const CONTENT_HEIGHT_PER_PAGE = 1200; // Maximum content height per page
|
|
13309
|
+
const PAGE_TOP_MARGIN = 30; // Margin at the top of content on new pages
|
|
13310
|
+
|
|
13311
|
+
const Row = _ref => {
|
|
13312
|
+
let {
|
|
13313
|
+
widgets,
|
|
13314
|
+
i,
|
|
13315
|
+
onChangeHeight = () => {}
|
|
13316
|
+
} = _ref;
|
|
13317
|
+
const ref = React.useRef();
|
|
13318
|
+
const [height, setHeight] = React.useState(0);
|
|
13319
|
+
React.useEffect(() => {
|
|
13320
|
+
const observer = new ResizeObserver(entries => {
|
|
13321
|
+
for (const entry of entries) {
|
|
13322
|
+
setHeight(entry.contentRect.height);
|
|
13323
|
+
}
|
|
13324
|
+
});
|
|
13325
|
+
observer.observe(ref.current);
|
|
13326
|
+
return () => observer.disconnect();
|
|
13327
|
+
}, []);
|
|
13328
|
+
React.useEffect(() => {
|
|
13329
|
+
if (height) {
|
|
13330
|
+
onChangeHeight(i, {
|
|
13331
|
+
height,
|
|
13332
|
+
ref
|
|
13333
|
+
});
|
|
13334
|
+
}
|
|
13335
|
+
}, [height]);
|
|
13336
|
+
return /*#__PURE__*/jsxRuntime.jsx("section", {
|
|
13337
|
+
ref: ref,
|
|
13338
|
+
style: widgets.style,
|
|
13339
|
+
children: typeof widgets.render === 'function' ? widgets.render() : null
|
|
13340
|
+
});
|
|
13341
|
+
};
|
|
13342
|
+
function PdfView(_ref2) {
|
|
13314
13343
|
let {
|
|
13315
13344
|
config = [],
|
|
13316
13345
|
customClassName,
|
|
@@ -13320,224 +13349,125 @@ function PdfView(_ref) {
|
|
|
13320
13349
|
accountId = 'IDD-0000000',
|
|
13321
13350
|
documentId = 'IDD-0000000',
|
|
13322
13351
|
downloadId = 'DWL-00000123'
|
|
13323
|
-
} =
|
|
13352
|
+
} = _ref2;
|
|
13353
|
+
const [sectionsConfig, setSectionsConfig] = React.useState({});
|
|
13324
13354
|
const [pages, setPages] = React.useState([1]);
|
|
13325
|
-
const
|
|
13326
|
-
|
|
13327
|
-
|
|
13328
|
-
|
|
13329
|
-
|
|
13330
|
-
|
|
13331
|
-
|
|
13332
|
-
|
|
13333
|
-
|
|
13334
|
-
|
|
13335
|
-
|
|
13336
|
-
|
|
13337
|
-
|
|
13338
|
-
// Reset all children
|
|
13339
|
-
const allElements = section.querySelectorAll('*');
|
|
13340
|
-
allElements.forEach(el => {
|
|
13341
|
-
if (!isHTMLElement(el)) return;
|
|
13342
|
-
el.style.marginTop = '';
|
|
13343
|
-
el.style.marginBottom = '';
|
|
13344
|
-
el.style.pageBreakBefore = '';
|
|
13345
|
-
el.style.breakBefore = '';
|
|
13346
|
-
el.removeAttribute('data-pdf-page');
|
|
13347
|
-
});
|
|
13348
|
-
});
|
|
13349
|
-
}, []);
|
|
13350
|
-
const getAllBreakableElements = React.useCallback(section => {
|
|
13351
|
-
const elements = [];
|
|
13352
|
-
const shouldInclude = el => {
|
|
13353
|
-
if (!isHTMLElement(el)) return false;
|
|
13354
|
-
const style = window.getComputedStyle(el);
|
|
13355
|
-
if (style.display === 'inline' || style.display === 'contents') return false;
|
|
13356
|
-
if (style.position === 'absolute' || style.position === 'fixed') return false;
|
|
13357
|
-
if (el.offsetHeight === 0) return false;
|
|
13358
|
-
return true;
|
|
13359
|
-
};
|
|
13360
|
-
const traverse = parent => {
|
|
13361
|
-
Array.from(parent.children).forEach(child => {
|
|
13362
|
-
if (shouldInclude(child)) {
|
|
13363
|
-
elements.push(child);
|
|
13364
|
-
traverse(child);
|
|
13365
|
-
}
|
|
13355
|
+
const doSizing = React.useCallback(() => {
|
|
13356
|
+
const keys = Object.keys(sectionsConfig);
|
|
13357
|
+
let _pages = [1];
|
|
13358
|
+
let _page = 1;
|
|
13359
|
+
if (keys.length === config.length) {
|
|
13360
|
+
// Reset all margins and padding first
|
|
13361
|
+
keys.forEach(k => {
|
|
13362
|
+
const {
|
|
13363
|
+
ref
|
|
13364
|
+
} = sectionsConfig[k];
|
|
13365
|
+
ref.current.style.marginTop = '0px';
|
|
13366
|
+
ref.current.style.marginBottom = '0px';
|
|
13367
|
+
ref.current.style.paddingBottom = '0px';
|
|
13366
13368
|
});
|
|
13367
|
-
|
|
13368
|
-
|
|
13369
|
-
|
|
13370
|
-
|
|
13371
|
-
|
|
13372
|
-
|
|
13373
|
-
|
|
13374
|
-
|
|
13375
|
-
|
|
13376
|
-
|
|
13377
|
-
|
|
13378
|
-
|
|
13379
|
-
|
|
13380
|
-
|
|
13381
|
-
|
|
13382
|
-
|
|
13383
|
-
|
|
13384
|
-
|
|
13385
|
-
|
|
13386
|
-
|
|
13387
|
-
|
|
13388
|
-
|
|
13389
|
-
|
|
13390
|
-
|
|
13391
|
-
|
|
13392
|
-
|
|
13393
|
-
|
|
13394
|
-
|
|
13395
|
-
|
|
13396
|
-
|
|
13397
|
-
|
|
13398
|
-
|
|
13369
|
+
let currentPageHeight = 0; // Track height accumulated on current page
|
|
13370
|
+
const sectionGap = 24; // Gap between sections
|
|
13371
|
+
|
|
13372
|
+
keys.forEach((k, i) => {
|
|
13373
|
+
const {
|
|
13374
|
+
height,
|
|
13375
|
+
ref
|
|
13376
|
+
} = sectionsConfig[k];
|
|
13377
|
+
const isFirstSection = i === 0;
|
|
13378
|
+
const isLastSection = i === keys.length - 1;
|
|
13379
|
+
|
|
13380
|
+
// First section on first page needs header space
|
|
13381
|
+
if (isFirstSection) {
|
|
13382
|
+
ref.current.style.marginTop = "".concat(HEADER_HEIGHT, "px");
|
|
13383
|
+
currentPageHeight = 0; // Content height tracking starts fresh
|
|
13384
|
+
}
|
|
13385
|
+
|
|
13386
|
+
// Check if this section would exceed the page content limit
|
|
13387
|
+
const willExceedPageLimit = currentPageHeight + height > CONTENT_HEIGHT_PER_PAGE;
|
|
13388
|
+
if (willExceedPageLimit && !isFirstSection) {
|
|
13389
|
+
// Need to break to a new page
|
|
13390
|
+
_page += 1;
|
|
13391
|
+
_pages.push(_page);
|
|
13392
|
+
|
|
13393
|
+
// Calculate remaining space on current page
|
|
13394
|
+
const remainingSpace = PAGE_HEIGHT - currentPageHeight - HEADER_HEIGHT - FOOTER_HEIGHT;
|
|
13395
|
+
|
|
13396
|
+
// Add margin to previous section to push current section to next page
|
|
13397
|
+
if (sectionsConfig[keys[i - 1]]) {
|
|
13398
|
+
const {
|
|
13399
|
+
ref: prevRef
|
|
13400
|
+
} = sectionsConfig[keys[i - 1]];
|
|
13401
|
+
prevRef.current.style.marginBottom = "".concat(remainingSpace, "px");
|
|
13399
13402
|
}
|
|
13403
|
+
|
|
13404
|
+
// Position this section at the top of the new page
|
|
13405
|
+
ref.current.style.marginTop = "".concat(HEADER_HEIGHT + PAGE_TOP_MARGIN, "px");
|
|
13406
|
+
|
|
13407
|
+
// Reset page height counter for new page
|
|
13408
|
+
currentPageHeight = height + sectionGap;
|
|
13400
13409
|
} else {
|
|
13401
|
-
//
|
|
13402
|
-
|
|
13410
|
+
// Section fits on current page
|
|
13411
|
+
currentPageHeight += height + sectionGap;
|
|
13403
13412
|
}
|
|
13404
|
-
currentPageHeight += gapBefore + sectionHeight;
|
|
13405
|
-
} else {
|
|
13406
|
-
// Doesn't fit - need to move to next page
|
|
13407
|
-
const remainingSpace = CONTENT_HEIGHT - currentPageHeight;
|
|
13408
|
-
|
|
13409
|
-
// Calculate margin needed to push this section to the next page
|
|
13410
|
-
// remainingSpace = space left on current page
|
|
13411
|
-
// Then we need to skip: footer margin + footer + header margin + header
|
|
13412
|
-
const pushMargin = remainingSpace + PAGE_MARGIN_BOTTOM + FOOTER_HEIGHT + PAGE_MARGIN_TOP + HEADER_HEIGHT;
|
|
13413
|
-
|
|
13414
|
-
// Move entire section to next page
|
|
13415
|
-
currentPage += 1;
|
|
13416
|
-
section.setAttribute('data-pdf-page', currentPage.toString());
|
|
13417
|
-
section.style.pageBreakBefore = 'always';
|
|
13418
|
-
section.style.breakBefore = 'page';
|
|
13419
|
-
section.style.marginTop = "".concat(pushMargin, "px");
|
|
13420
|
-
|
|
13421
|
-
// Start fresh height counter for new page
|
|
13422
|
-
currentPageHeight = sectionHeight;
|
|
13423
|
-
|
|
13424
|
-
// Check if section is too tall and needs internal breaks
|
|
13425
|
-
if (sectionHeight > CONTENT_HEIGHT) {
|
|
13426
|
-
// Try to break within section
|
|
13427
|
-
const innerElements = getAllBreakableElements(section);
|
|
13428
|
-
let pageHeightInSection = 0;
|
|
13429
|
-
let sectionPage = currentPage;
|
|
13430
|
-
for (const el of innerElements) {
|
|
13431
|
-
const rect = el.getBoundingClientRect();
|
|
13432
|
-
const sectionRect = section.getBoundingClientRect();
|
|
13433
|
-
const relativeTop = rect.top - sectionRect.top;
|
|
13434
|
-
const elHeight = rect.height;
|
|
13435
|
-
|
|
13436
|
-
// Check if this element would exceed the page
|
|
13437
|
-
if (pageHeightInSection + elHeight > CONTENT_HEIGHT && relativeTop > 50) {
|
|
13438
|
-
// Calculate remaining space on this page within the section
|
|
13439
|
-
const remainingInSection = CONTENT_HEIGHT - pageHeightInSection;
|
|
13440
|
-
const pushMarginInner = remainingInSection + PAGE_MARGIN_BOTTOM + FOOTER_HEIGHT + PAGE_MARGIN_TOP + HEADER_HEIGHT;
|
|
13441
|
-
sectionPage += 1;
|
|
13442
|
-
el.setAttribute('data-pdf-page', sectionPage.toString());
|
|
13443
|
-
el.style.pageBreakBefore = 'always';
|
|
13444
|
-
el.style.breakBefore = 'page';
|
|
13445
|
-
el.style.marginTop = "".concat(pushMarginInner, "px");
|
|
13446
|
-
|
|
13447
|
-
// Reset page height for new page within section
|
|
13448
|
-
pageHeightInSection = elHeight;
|
|
13449
|
-
} else {
|
|
13450
|
-
pageHeightInSection += elHeight;
|
|
13451
|
-
}
|
|
13452
|
-
}
|
|
13453
13413
|
|
|
13454
|
-
|
|
13455
|
-
|
|
13456
|
-
|
|
13457
|
-
currentPageHeight = pageHeightInSection;
|
|
13458
|
-
}
|
|
13414
|
+
// Add padding to last section
|
|
13415
|
+
if (isLastSection) {
|
|
13416
|
+
ref.current.style.paddingBottom = "".concat(PAGE_TOP_MARGIN, "px");
|
|
13459
13417
|
}
|
|
13460
|
-
}
|
|
13461
|
-
|
|
13462
|
-
|
|
13463
|
-
|
|
13464
|
-
}, (_, idx) => idx + 1));
|
|
13465
|
-
|
|
13466
|
-
// Reset flag after a brief delay to allow next calculation
|
|
13467
|
-
setTimeout(() => {
|
|
13468
|
-
isCalculatingRef.current = false;
|
|
13469
|
-
}, 100);
|
|
13470
|
-
}, [getAllBreakableElements, resetPaginationStyles]);
|
|
13471
|
-
React.useLayoutEffect(() => {
|
|
13472
|
-
// Use requestAnimationFrame to ensure DOM is painted
|
|
13473
|
-
const rafId = requestAnimationFrame(() => {
|
|
13474
|
-
paginateContent();
|
|
13475
|
-
});
|
|
13476
|
-
return () => cancelAnimationFrame(rafId);
|
|
13477
|
-
}, [paginateContent, config]);
|
|
13418
|
+
});
|
|
13419
|
+
setPages(_pages);
|
|
13420
|
+
}
|
|
13421
|
+
}, [sectionsConfig, config.length]);
|
|
13478
13422
|
React.useEffect(() => {
|
|
13479
|
-
|
|
13480
|
-
|
|
13481
|
-
|
|
13482
|
-
|
|
13483
|
-
|
|
13484
|
-
|
|
13485
|
-
|
|
13486
|
-
resizeTimeoutRef.current = setTimeout(() => {
|
|
13487
|
-
// Use requestAnimationFrame to avoid ResizeObserver loop warning
|
|
13488
|
-
requestAnimationFrame(() => {
|
|
13489
|
-
paginateContent();
|
|
13490
|
-
});
|
|
13491
|
-
}, 150);
|
|
13492
|
-
});
|
|
13493
|
-
sections.forEach(section => observer.observe(section));
|
|
13494
|
-
return () => {
|
|
13495
|
-
observer.disconnect();
|
|
13496
|
-
if (resizeTimeoutRef.current) {
|
|
13497
|
-
clearTimeout(resizeTimeoutRef.current);
|
|
13498
|
-
}
|
|
13499
|
-
};
|
|
13500
|
-
}, [paginateContent, config.length]);
|
|
13423
|
+
doSizing();
|
|
13424
|
+
}, [doSizing]);
|
|
13425
|
+
const onChangeHeight = React.useCallback((index, conf) => {
|
|
13426
|
+
setSectionsConfig(prev => _objectSpread2(_objectSpread2({}, prev), {}, {
|
|
13427
|
+
[index]: conf
|
|
13428
|
+
}));
|
|
13429
|
+
}, []);
|
|
13501
13430
|
const contClassName = formatClassname(['daf-analysis daf-pdf-view', customClassName]);
|
|
13502
|
-
|
|
13503
|
-
|
|
13504
|
-
style: {
|
|
13505
|
-
position: 'relative',
|
|
13506
|
-
minHeight: "".concat(PAGE_HEIGHT, "px")
|
|
13507
|
-
},
|
|
13508
|
-
children: [/*#__PURE__*/jsxRuntime.jsx("div", {
|
|
13431
|
+
const renderDashboard = React.useCallback(() => {
|
|
13432
|
+
return /*#__PURE__*/jsxRuntime.jsx("div", {
|
|
13509
13433
|
className: "view-content",
|
|
13510
13434
|
children: /*#__PURE__*/jsxRuntime.jsx("div", {
|
|
13511
13435
|
className: "daf-analysis-layout",
|
|
13512
13436
|
children: /*#__PURE__*/jsxRuntime.jsx("div", {
|
|
13513
13437
|
className: "sections-cont",
|
|
13514
|
-
|
|
13515
|
-
|
|
13516
|
-
|
|
13517
|
-
|
|
13518
|
-
|
|
13519
|
-
position: 'relative'
|
|
13520
|
-
},
|
|
13521
|
-
children: config.map((widgets, index) => /*#__PURE__*/jsxRuntime.jsx("section", {
|
|
13522
|
-
ref: el => {
|
|
13523
|
-
sectionsRef.current[index] = el;
|
|
13524
|
-
},
|
|
13525
|
-
style: widgets.style,
|
|
13526
|
-
"data-pdf-section": "true",
|
|
13527
|
-
children: typeof widgets.render === 'function' ? widgets.render() : null
|
|
13528
|
-
}, "dashboard-section-".concat(index + 1)))
|
|
13438
|
+
children: config.map((widgets, i) => /*#__PURE__*/jsxRuntime.jsx(Row, {
|
|
13439
|
+
widgets: widgets,
|
|
13440
|
+
i: i,
|
|
13441
|
+
onChangeHeight: onChangeHeight
|
|
13442
|
+
}, "dashboard-sections=".concat(i + 1)))
|
|
13529
13443
|
})
|
|
13530
13444
|
})
|
|
13531
|
-
})
|
|
13445
|
+
});
|
|
13446
|
+
}, [config, onChangeHeight]);
|
|
13447
|
+
|
|
13448
|
+
// <div className="daf-analysis">
|
|
13449
|
+
// <Header title={t('Dashboard Title')} />
|
|
13450
|
+
|
|
13451
|
+
// <div className="content">
|
|
13452
|
+
// <div className="view-content">
|
|
13453
|
+
// <div className="daf-analysis-layout">
|
|
13454
|
+
// <div className='sections-cont w-pt'>
|
|
13455
|
+
// <section>
|
|
13456
|
+
|
|
13457
|
+
return /*#__PURE__*/jsxRuntime.jsxs("div", {
|
|
13458
|
+
className: contClassName,
|
|
13459
|
+
style: {
|
|
13460
|
+
position: 'relative'
|
|
13461
|
+
},
|
|
13462
|
+
children: [renderDashboard(), pages.map(page => /*#__PURE__*/jsxRuntime.jsxs(jsxRuntime.Fragment, {
|
|
13532
13463
|
children: [/*#__PURE__*/jsxRuntime.jsxs("div", {
|
|
13533
13464
|
style: {
|
|
13534
|
-
top: (page - 1) * PAGE_HEIGHT
|
|
13465
|
+
top: (page - 1) * PAGE_HEIGHT,
|
|
13535
13466
|
width: '100%',
|
|
13536
|
-
height: HEADER_HEIGHT,
|
|
13467
|
+
height: HEADER_HEIGHT - 24,
|
|
13537
13468
|
position: 'absolute',
|
|
13538
13469
|
left: 0,
|
|
13539
|
-
zIndex: 1000000
|
|
13540
|
-
pointerEvents: 'none'
|
|
13470
|
+
zIndex: 1000000
|
|
13541
13471
|
},
|
|
13542
13472
|
className: "flex-row dashboard-header",
|
|
13543
13473
|
children: [/*#__PURE__*/jsxRuntime.jsx("div", {
|
|
@@ -13552,15 +13482,14 @@ function PdfView(_ref) {
|
|
|
13552
13482
|
alt: "logo"
|
|
13553
13483
|
})
|
|
13554
13484
|
})]
|
|
13555
|
-
}), /*#__PURE__*/jsxRuntime.jsxs("div", {
|
|
13485
|
+
}, "headers-".concat(page)), /*#__PURE__*/jsxRuntime.jsxs("div", {
|
|
13556
13486
|
style: {
|
|
13557
|
-
top: page * PAGE_HEIGHT - FOOTER_HEIGHT
|
|
13487
|
+
top: page * PAGE_HEIGHT - FOOTER_HEIGHT,
|
|
13558
13488
|
width: '100%',
|
|
13559
13489
|
height: FOOTER_HEIGHT,
|
|
13560
13490
|
position: 'absolute',
|
|
13561
13491
|
left: 0,
|
|
13562
|
-
zIndex: 1000000
|
|
13563
|
-
pointerEvents: 'none'
|
|
13492
|
+
zIndex: 1000000
|
|
13564
13493
|
},
|
|
13565
13494
|
className: "dashboard-footer flex-row",
|
|
13566
13495
|
children: [/*#__PURE__*/jsxRuntime.jsx("div", {
|
|
@@ -13596,8 +13525,8 @@ function PdfView(_ref) {
|
|
|
13596
13525
|
children: page
|
|
13597
13526
|
})
|
|
13598
13527
|
})]
|
|
13599
|
-
})]
|
|
13600
|
-
}
|
|
13528
|
+
}, "footers-".concat(page))]
|
|
13529
|
+
}))]
|
|
13601
13530
|
});
|
|
13602
13531
|
}
|
|
13603
13532
|
PdfView.propTypes = {
|
package/package.json
CHANGED
|
@@ -1,17 +1,42 @@
|
|
|
1
1
|
import moment from "moment";
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
|
-
import {
|
|
3
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
4
4
|
import { formatClassname } from "../../../../../helpers/ClassesHelper";
|
|
5
5
|
|
|
6
6
|
const PAGE_HEIGHT = 1587;
|
|
7
7
|
const FOOTER_HEIGHT = 70;
|
|
8
8
|
const HEADER_HEIGHT = 100;
|
|
9
|
-
const
|
|
10
|
-
const
|
|
11
|
-
const CONTENT_HEIGHT = 1200; // 1397px
|
|
12
|
-
const SECTION_GAP = 24;
|
|
9
|
+
const CONTENT_HEIGHT_PER_PAGE = 1200; // Maximum content height per page
|
|
10
|
+
const PAGE_TOP_MARGIN = 30; // Margin at the top of content on new pages
|
|
13
11
|
|
|
14
|
-
const
|
|
12
|
+
const Row = ({ widgets, i, onChangeHeight = () => { } }) => {
|
|
13
|
+
const ref = useRef();
|
|
14
|
+
const [height, setHeight] = useState(0);
|
|
15
|
+
|
|
16
|
+
useEffect(() => {
|
|
17
|
+
const observer = new ResizeObserver((entries) => {
|
|
18
|
+
for (const entry of entries) {
|
|
19
|
+
setHeight(entry.contentRect.height);
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
observer.observe(ref.current);
|
|
24
|
+
|
|
25
|
+
return () => observer.disconnect();
|
|
26
|
+
}, []);
|
|
27
|
+
|
|
28
|
+
useEffect(() => {
|
|
29
|
+
if (height) {
|
|
30
|
+
onChangeHeight(i, { height, ref });
|
|
31
|
+
}
|
|
32
|
+
}, [height])
|
|
33
|
+
|
|
34
|
+
return (
|
|
35
|
+
<section ref={ref} style={widgets.style}>
|
|
36
|
+
{typeof widgets.render === 'function' ? widgets.render() : null}
|
|
37
|
+
</section>
|
|
38
|
+
)
|
|
39
|
+
};
|
|
15
40
|
|
|
16
41
|
export default function PdfView({
|
|
17
42
|
config = [],
|
|
@@ -23,251 +48,120 @@ export default function PdfView({
|
|
|
23
48
|
documentId = 'IDD-0000000',
|
|
24
49
|
downloadId = 'DWL-00000123',
|
|
25
50
|
}) {
|
|
51
|
+
const [sectionsConfig, setSectionsConfig] = useState({});
|
|
26
52
|
const [pages, setPages] = useState([1]);
|
|
27
|
-
const contentRef = useRef(null);
|
|
28
|
-
const sectionsRef = useRef([]);
|
|
29
|
-
const resizeTimeoutRef = useRef(null);
|
|
30
|
-
const isCalculatingRef = useRef(false);
|
|
31
53
|
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
if (!isHTMLElement(el)) return;
|
|
45
|
-
el.style.marginTop = '';
|
|
46
|
-
el.style.marginBottom = '';
|
|
47
|
-
el.style.pageBreakBefore = '';
|
|
48
|
-
el.style.breakBefore = '';
|
|
49
|
-
el.removeAttribute('data-pdf-page');
|
|
54
|
+
const doSizing = useCallback(() => {
|
|
55
|
+
const keys = Object.keys(sectionsConfig);
|
|
56
|
+
let _pages = [1];
|
|
57
|
+
let _page = 1;
|
|
58
|
+
|
|
59
|
+
if (keys.length === config.length) {
|
|
60
|
+
// Reset all margins and padding first
|
|
61
|
+
keys.forEach(k => {
|
|
62
|
+
const { ref } = sectionsConfig[k];
|
|
63
|
+
ref.current.style.marginTop = '0px';
|
|
64
|
+
ref.current.style.marginBottom = '0px';
|
|
65
|
+
ref.current.style.paddingBottom = '0px';
|
|
50
66
|
});
|
|
51
|
-
});
|
|
52
|
-
}, []);
|
|
53
|
-
|
|
54
|
-
const getAllBreakableElements = useCallback((section) => {
|
|
55
|
-
const elements = [];
|
|
56
|
-
|
|
57
|
-
const shouldInclude = (el) => {
|
|
58
|
-
if (!isHTMLElement(el)) return false;
|
|
59
|
-
const style = window.getComputedStyle(el);
|
|
60
|
-
if (style.display === 'inline' || style.display === 'contents') return false;
|
|
61
|
-
if (style.position === 'absolute' || style.position === 'fixed') return false;
|
|
62
|
-
if (el.offsetHeight === 0) return false;
|
|
63
|
-
return true;
|
|
64
|
-
};
|
|
65
67
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
if (shouldInclude(child)) {
|
|
69
|
-
elements.push(child);
|
|
70
|
-
traverse(child);
|
|
71
|
-
}
|
|
72
|
-
});
|
|
73
|
-
};
|
|
68
|
+
let currentPageHeight = 0; // Track height accumulated on current page
|
|
69
|
+
const sectionGap = 24; // Gap between sections
|
|
74
70
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
71
|
+
keys.forEach((k, i) => {
|
|
72
|
+
const { height, ref } = sectionsConfig[k];
|
|
73
|
+
const isFirstSection = i === 0;
|
|
74
|
+
const isLastSection = i === keys.length - 1;
|
|
78
75
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
if (sections.length === 0) return;
|
|
85
|
-
|
|
86
|
-
isCalculatingRef.current = true;
|
|
87
|
-
|
|
88
|
-
resetPaginationStyles(sections);
|
|
76
|
+
// First section on first page needs header space
|
|
77
|
+
if (isFirstSection) {
|
|
78
|
+
ref.current.style.marginTop = `${HEADER_HEIGHT}px`;
|
|
79
|
+
currentPageHeight = 0; // Content height tracking starts fresh
|
|
80
|
+
}
|
|
89
81
|
|
|
90
|
-
|
|
91
|
-
|
|
82
|
+
// Check if this section would exceed the page content limit
|
|
83
|
+
const willExceedPageLimit = currentPageHeight + height > CONTENT_HEIGHT_PER_PAGE;
|
|
92
84
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
85
|
+
if (willExceedPageLimit && !isFirstSection) {
|
|
86
|
+
// Need to break to a new page
|
|
87
|
+
_page += 1;
|
|
88
|
+
_pages.push(_page);
|
|
96
89
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
const sectionHeight = section.offsetHeight;
|
|
100
|
-
const isFirstOnPage = currentPageHeight === 0;
|
|
101
|
-
const gapBefore = isFirstOnPage ? 0 : SECTION_GAP;
|
|
102
|
-
|
|
103
|
-
if (currentPageHeight + gapBefore + sectionHeight <= CONTENT_HEIGHT) {
|
|
104
|
-
// Fits in current page
|
|
105
|
-
section.setAttribute('data-pdf-page', currentPage.toString());
|
|
106
|
-
|
|
107
|
-
if (isFirstOnPage) {
|
|
108
|
-
// First item on page
|
|
109
|
-
if (currentPage === 1) {
|
|
110
|
-
// Very first section on first page - needs to be below header
|
|
111
|
-
section.style.marginTop = '0px'; // Container padding handles this
|
|
112
|
-
} else {
|
|
113
|
-
// First section on subsequent pages - no margin (container padding handles it)
|
|
114
|
-
section.style.marginTop = '0px';
|
|
115
|
-
}
|
|
116
|
-
} else {
|
|
117
|
-
// Not first item on page - add gap
|
|
118
|
-
section.style.marginTop = `${SECTION_GAP}px`;
|
|
119
|
-
}
|
|
120
|
-
currentPageHeight += gapBefore + sectionHeight;
|
|
121
|
-
} else {
|
|
122
|
-
// Doesn't fit - need to move to next page
|
|
123
|
-
const remainingSpace = CONTENT_HEIGHT - currentPageHeight;
|
|
124
|
-
|
|
125
|
-
// Calculate margin needed to push this section to the next page
|
|
126
|
-
// remainingSpace = space left on current page
|
|
127
|
-
// Then we need to skip: footer margin + footer + header margin + header
|
|
128
|
-
const pushMargin = remainingSpace + PAGE_MARGIN_BOTTOM + FOOTER_HEIGHT + PAGE_MARGIN_TOP + HEADER_HEIGHT;
|
|
129
|
-
|
|
130
|
-
// Move entire section to next page
|
|
131
|
-
currentPage += 1;
|
|
132
|
-
breaks.push({ section, type: 'section', page: currentPage });
|
|
133
|
-
section.setAttribute('data-pdf-page', currentPage.toString());
|
|
134
|
-
section.style.pageBreakBefore = 'always';
|
|
135
|
-
section.style.breakBefore = 'page';
|
|
136
|
-
section.style.marginTop = `${pushMargin}px`;
|
|
137
|
-
|
|
138
|
-
// Start fresh height counter for new page
|
|
139
|
-
currentPageHeight = sectionHeight;
|
|
140
|
-
|
|
141
|
-
// Check if section is too tall and needs internal breaks
|
|
142
|
-
if (sectionHeight > CONTENT_HEIGHT) {
|
|
143
|
-
// Try to break within section
|
|
144
|
-
const innerElements = getAllBreakableElements(section);
|
|
145
|
-
let pageHeightInSection = 0;
|
|
146
|
-
let sectionPage = currentPage;
|
|
90
|
+
// Calculate remaining space on current page
|
|
91
|
+
const remainingSpace = PAGE_HEIGHT - currentPageHeight - HEADER_HEIGHT - FOOTER_HEIGHT;
|
|
147
92
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
const
|
|
151
|
-
|
|
152
|
-
const elHeight = rect.height;
|
|
153
|
-
|
|
154
|
-
// Check if this element would exceed the page
|
|
155
|
-
if (pageHeightInSection + elHeight > CONTENT_HEIGHT && relativeTop > 50) {
|
|
156
|
-
// Calculate remaining space on this page within the section
|
|
157
|
-
const remainingInSection = CONTENT_HEIGHT - pageHeightInSection;
|
|
158
|
-
const pushMarginInner = remainingInSection + PAGE_MARGIN_BOTTOM + FOOTER_HEIGHT + PAGE_MARGIN_TOP + HEADER_HEIGHT;
|
|
159
|
-
|
|
160
|
-
sectionPage += 1;
|
|
161
|
-
breaks.push({ element: el, type: 'inner', page: sectionPage });
|
|
162
|
-
el.setAttribute('data-pdf-page', sectionPage.toString());
|
|
163
|
-
el.style.pageBreakBefore = 'always';
|
|
164
|
-
el.style.breakBefore = 'page';
|
|
165
|
-
el.style.marginTop = `${pushMarginInner}px`;
|
|
166
|
-
|
|
167
|
-
// Reset page height for new page within section
|
|
168
|
-
pageHeightInSection = elHeight;
|
|
169
|
-
} else {
|
|
170
|
-
pageHeightInSection += elHeight;
|
|
171
|
-
}
|
|
93
|
+
// Add margin to previous section to push current section to next page
|
|
94
|
+
if (sectionsConfig[keys[i - 1]]) {
|
|
95
|
+
const { ref: prevRef } = sectionsConfig[keys[i - 1]];
|
|
96
|
+
prevRef.current.style.marginBottom = `${remainingSpace}px`;
|
|
172
97
|
}
|
|
98
|
+
|
|
99
|
+
// Position this section at the top of the new page
|
|
100
|
+
ref.current.style.marginTop = `${HEADER_HEIGHT + PAGE_TOP_MARGIN}px`;
|
|
173
101
|
|
|
174
|
-
//
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
102
|
+
// Reset page height counter for new page
|
|
103
|
+
currentPageHeight = height + sectionGap;
|
|
104
|
+
} else {
|
|
105
|
+
// Section fits on current page
|
|
106
|
+
currentPageHeight += height + sectionGap;
|
|
179
107
|
}
|
|
180
|
-
}
|
|
181
|
-
});
|
|
182
108
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
}, 100);
|
|
189
|
-
}, [getAllBreakableElements, resetPaginationStyles]);
|
|
109
|
+
// Add padding to last section
|
|
110
|
+
if (isLastSection) {
|
|
111
|
+
ref.current.style.paddingBottom = `${PAGE_TOP_MARGIN}px`;
|
|
112
|
+
}
|
|
113
|
+
});
|
|
190
114
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
paginateContent();
|
|
195
|
-
});
|
|
196
|
-
|
|
197
|
-
return () => cancelAnimationFrame(rafId);
|
|
198
|
-
}, [paginateContent, config]);
|
|
115
|
+
setPages(_pages);
|
|
116
|
+
}
|
|
117
|
+
}, [sectionsConfig, config.length]);
|
|
199
118
|
|
|
200
119
|
useEffect(() => {
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
const observer = new ResizeObserver(() => {
|
|
205
|
-
// Debounce the pagination calculation
|
|
206
|
-
if (resizeTimeoutRef.current) {
|
|
207
|
-
clearTimeout(resizeTimeoutRef.current);
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
resizeTimeoutRef.current = setTimeout(() => {
|
|
211
|
-
// Use requestAnimationFrame to avoid ResizeObserver loop warning
|
|
212
|
-
requestAnimationFrame(() => {
|
|
213
|
-
paginateContent();
|
|
214
|
-
});
|
|
215
|
-
}, 150);
|
|
216
|
-
});
|
|
217
|
-
|
|
218
|
-
sections.forEach(section => observer.observe(section));
|
|
120
|
+
doSizing();
|
|
121
|
+
}, [doSizing]);
|
|
219
122
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
clearTimeout(resizeTimeoutRef.current);
|
|
224
|
-
}
|
|
225
|
-
};
|
|
226
|
-
}, [paginateContent, config.length]);
|
|
123
|
+
const onChangeHeight = useCallback((index, conf) => {
|
|
124
|
+
setSectionsConfig((prev) => ({ ...prev, [index]: conf }))
|
|
125
|
+
}, []);
|
|
227
126
|
|
|
228
127
|
const contClassName = formatClassname(['daf-analysis daf-pdf-view', customClassName]);
|
|
229
128
|
|
|
230
|
-
|
|
231
|
-
|
|
129
|
+
const renderDashboard = useCallback(() => {
|
|
130
|
+
return (
|
|
232
131
|
<div className="view-content">
|
|
233
132
|
<div className="daf-analysis-layout">
|
|
234
|
-
<div
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
}}
|
|
243
|
-
>
|
|
244
|
-
{config.map((widgets, index) => (
|
|
245
|
-
<section
|
|
246
|
-
key={`dashboard-section-${index + 1}`}
|
|
247
|
-
ref={(el) => {
|
|
248
|
-
sectionsRef.current[index] = el;
|
|
249
|
-
}}
|
|
250
|
-
style={widgets.style}
|
|
251
|
-
data-pdf-section="true"
|
|
252
|
-
>
|
|
253
|
-
{typeof widgets.render === 'function' ? widgets.render() : null}
|
|
254
|
-
</section>
|
|
133
|
+
<div className='sections-cont'>
|
|
134
|
+
{config.map((widgets, i) => (
|
|
135
|
+
<Row
|
|
136
|
+
widgets={widgets}
|
|
137
|
+
key={`dashboard-sections=${i + 1}`}
|
|
138
|
+
i={i}
|
|
139
|
+
onChangeHeight={onChangeHeight}
|
|
140
|
+
/>
|
|
255
141
|
))}
|
|
256
142
|
</div>
|
|
257
143
|
</div>
|
|
258
144
|
</div>
|
|
145
|
+
);
|
|
146
|
+
}, [config, onChangeHeight]);
|
|
147
|
+
|
|
148
|
+
// <div className="daf-analysis">
|
|
149
|
+
// <Header title={t('Dashboard Title')} />
|
|
150
|
+
|
|
151
|
+
// <div className="content">
|
|
152
|
+
// <div className="view-content">
|
|
153
|
+
// <div className="daf-analysis-layout">
|
|
154
|
+
// <div className='sections-cont w-pt'>
|
|
155
|
+
// <section>
|
|
156
|
+
|
|
157
|
+
return (
|
|
158
|
+
<div className={contClassName} style={{ position: 'relative' }}>
|
|
159
|
+
{renderDashboard()}
|
|
259
160
|
{pages.map((page) => (
|
|
260
|
-
|
|
161
|
+
<>
|
|
261
162
|
<div
|
|
262
|
-
style={{
|
|
263
|
-
|
|
264
|
-
width: '100%',
|
|
265
|
-
height: HEADER_HEIGHT,
|
|
266
|
-
position: 'absolute',
|
|
267
|
-
left: 0,
|
|
268
|
-
zIndex: 1000000,
|
|
269
|
-
pointerEvents: 'none'
|
|
270
|
-
}}
|
|
163
|
+
style={{ top: ((page - 1) * PAGE_HEIGHT), width: '100%', height: HEADER_HEIGHT - 24, position: 'absolute', left: 0, zIndex: 1000000 }}
|
|
164
|
+
key={`headers-${page}`}
|
|
271
165
|
className="flex-row dashboard-header"
|
|
272
166
|
>
|
|
273
167
|
<div className="flex flex-column justify-center flex-1">
|
|
@@ -278,15 +172,8 @@ export default function PdfView({
|
|
|
278
172
|
</div>
|
|
279
173
|
</div>
|
|
280
174
|
<div
|
|
281
|
-
style={{
|
|
282
|
-
|
|
283
|
-
width: '100%',
|
|
284
|
-
height: FOOTER_HEIGHT,
|
|
285
|
-
position: 'absolute',
|
|
286
|
-
left: 0,
|
|
287
|
-
zIndex: 1000000,
|
|
288
|
-
pointerEvents: 'none'
|
|
289
|
-
}}
|
|
175
|
+
style={{ top: (page * PAGE_HEIGHT) - FOOTER_HEIGHT, width: '100%', height: FOOTER_HEIGHT, position: 'absolute', left: 0, zIndex: 1000000 }}
|
|
176
|
+
key={`footers-${page}`}
|
|
290
177
|
className="dashboard-footer flex-row"
|
|
291
178
|
>
|
|
292
179
|
<div className="flex flex-column justify-center">
|
|
@@ -320,7 +207,7 @@ export default function PdfView({
|
|
|
320
207
|
<h5>{page}</h5>
|
|
321
208
|
</div>
|
|
322
209
|
</div>
|
|
323
|
-
|
|
210
|
+
</>
|
|
324
211
|
))}
|
|
325
212
|
</div>
|
|
326
213
|
);
|