datastake-daf 0.6.251 → 0.6.252
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 +63 -281
- package/dist/utils/index.js +1 -1
- package/package.json +1 -1
- package/src/@daf/core/components/Dashboard/Globe/Globe.stories.js +8 -0
- package/src/@daf/core/components/Dashboard/Globe/hook.js +42 -0
- package/src/@daf/core/components/Dashboard/Map/hook.js +1 -1
- package/src/@daf/core/components/Dashboard/Map/storyConfig.js +2 -1
- package/src/@daf/core/components/Dashboard/Map/storyConfig6.js +366 -0
- package/src/@daf/core/components/Dashboard/Steps/Steps.stories.js +0 -5
- package/src/@daf/core/components/Dashboard/Steps/index.jsx +8 -29
- package/src/@daf/core/components/PdfForm/index.js +21 -247
- package/src/@daf/core/components/ViewForm/helper.js +1 -1
package/dist/components/index.js
CHANGED
|
@@ -15422,226 +15422,6 @@ const PdfForm = _ref3 => {
|
|
|
15422
15422
|
return organizedSections;
|
|
15423
15423
|
};
|
|
15424
15424
|
const organizedForm = React.useMemo(() => organizeFormByHeaders(form), [form]);
|
|
15425
|
-
|
|
15426
|
-
// Constants for height calculations (same as PdfView)
|
|
15427
|
-
const PAGE_HEIGHT = 1587;
|
|
15428
|
-
const FOOTER_HEIGHT = 70;
|
|
15429
|
-
const HEADER_HEIGHT = 100;
|
|
15430
|
-
|
|
15431
|
-
// Helper function to estimate tree node height based on content and type
|
|
15432
|
-
const estimateTreeNodeHeight = function (key, config, value) {
|
|
15433
|
-
let level = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0;
|
|
15434
|
-
const baseHeight = 28; // Base height per tree node
|
|
15435
|
-
const indentHeight = level * 2; // Additional height per level
|
|
15436
|
-
let totalHeight = baseHeight + indentHeight;
|
|
15437
|
-
|
|
15438
|
-
// Adjust height based on node type
|
|
15439
|
-
if ((config === null || config === void 0 ? void 0 : config.type) === 'header') {
|
|
15440
|
-
totalHeight += 15; // Headers need more space
|
|
15441
|
-
} else if ((config === null || config === void 0 ? void 0 : config.type) === 'textarea') {
|
|
15442
|
-
totalHeight += 40; // Textareas are taller
|
|
15443
|
-
} else if ((config === null || config === void 0 ? void 0 : config.type) === 'dataLink' || (config === null || config === void 0 ? void 0 : config.type) === 'dataLinkGroup') {
|
|
15444
|
-
totalHeight += 20; // Data links often have more content
|
|
15445
|
-
}
|
|
15446
|
-
|
|
15447
|
-
// Add height for value content if it exists
|
|
15448
|
-
if (value && typeof value === 'string' && value.length > 50) {
|
|
15449
|
-
totalHeight += Math.ceil(value.length / 50) * 15; // Multi-line content
|
|
15450
|
-
}
|
|
15451
|
-
|
|
15452
|
-
// Add height for children recursively
|
|
15453
|
-
if (config !== null && config !== void 0 && config.inputs) {
|
|
15454
|
-
const childKeys = Object.keys(config.inputs).filter(childKey => {
|
|
15455
|
-
const childConfig = config.inputs[childKey];
|
|
15456
|
-
// Check showIf condition
|
|
15457
|
-
if (childConfig !== null && childConfig !== void 0 && childConfig.showIf && !evaluateShowIfCondition(childConfig.showIf, data)) {
|
|
15458
|
-
return false;
|
|
15459
|
-
}
|
|
15460
|
-
return true;
|
|
15461
|
-
}).sort((a, b) => {
|
|
15462
|
-
var _config$inputs$a3, _config$inputs$b3;
|
|
15463
|
-
const positionA = ((_config$inputs$a3 = config.inputs[a]) === null || _config$inputs$a3 === void 0 ? void 0 : _config$inputs$a3.position) || 0;
|
|
15464
|
-
const positionB = ((_config$inputs$b3 = config.inputs[b]) === null || _config$inputs$b3 === void 0 ? void 0 : _config$inputs$b3.position) || 0;
|
|
15465
|
-
return positionA - positionB;
|
|
15466
|
-
});
|
|
15467
|
-
childKeys.forEach(childKey => {
|
|
15468
|
-
const childConfig = config.inputs[childKey];
|
|
15469
|
-
const childValue = (value === null || value === void 0 ? void 0 : value[childKey]) || (data === null || data === void 0 ? void 0 : data[childKey]);
|
|
15470
|
-
totalHeight += estimateTreeNodeHeight(childKey, childConfig, childValue, level + 1);
|
|
15471
|
-
});
|
|
15472
|
-
}
|
|
15473
|
-
|
|
15474
|
-
// Handle array/repeated content
|
|
15475
|
-
if (Array.isArray(value)) {
|
|
15476
|
-
value.forEach(itemValue => {
|
|
15477
|
-
totalHeight += estimateTreeNodeHeight(key, config, itemValue, level);
|
|
15478
|
-
});
|
|
15479
|
-
}
|
|
15480
|
-
return totalHeight;
|
|
15481
|
-
};
|
|
15482
|
-
|
|
15483
|
-
// Helper function to split section based on height constraints (goes deep if needed)
|
|
15484
|
-
const createHeightConstrainedSections = (sectionKey, section) => {
|
|
15485
|
-
const MAX_SECTION_HEIGHT = PAGE_HEIGHT - HEADER_HEIGHT - FOOTER_HEIGHT - 150; // Conservative buffer
|
|
15486
|
-
const subSections = [];
|
|
15487
|
-
|
|
15488
|
-
// Get all top-level items in the section with detailed analysis
|
|
15489
|
-
const topLevelItems = Object.keys(section).filter(key => !(key === 'id' || key === 'label' || key === 'position' || key === 'subTitle')).map(key => {
|
|
15490
|
-
var _section$key;
|
|
15491
|
-
return {
|
|
15492
|
-
key,
|
|
15493
|
-
config: section[key],
|
|
15494
|
-
estimatedHeight: estimateTreeNodeHeight(key, section[key], data === null || data === void 0 ? void 0 : data[key]),
|
|
15495
|
-
canSplit: ((_section$key = section[key]) === null || _section$key === void 0 ? void 0 : _section$key.inputs) && Object.keys(section[key].inputs).length > 1 // Can this item be further split?
|
|
15496
|
-
};
|
|
15497
|
-
}).sort((a, b) => {
|
|
15498
|
-
var _a$config, _b$config;
|
|
15499
|
-
return (((_a$config = a.config) === null || _a$config === void 0 ? void 0 : _a$config.position) || 0) - (((_b$config = b.config) === null || _b$config === void 0 ? void 0 : _b$config.position) || 0);
|
|
15500
|
-
});
|
|
15501
|
-
let currentSubSection = _objectSpread2({}, section);
|
|
15502
|
-
|
|
15503
|
-
// Remove all items from the base section structure
|
|
15504
|
-
Object.keys(section).forEach(key => {
|
|
15505
|
-
if (!(key === 'id' || key === 'label' || key === 'position' || key === 'subTitle')) {
|
|
15506
|
-
delete currentSubSection[key];
|
|
15507
|
-
}
|
|
15508
|
-
});
|
|
15509
|
-
let currentHeight = 80; // Base height for section header
|
|
15510
|
-
let subSectionIndex = 0;
|
|
15511
|
-
topLevelItems.forEach((item, index) => {
|
|
15512
|
-
const {
|
|
15513
|
-
key,
|
|
15514
|
-
config,
|
|
15515
|
-
estimatedHeight,
|
|
15516
|
-
canSplit
|
|
15517
|
-
} = item;
|
|
15518
|
-
|
|
15519
|
-
// If a single item is too large and can be split, split it at the child level
|
|
15520
|
-
if (estimatedHeight > MAX_SECTION_HEIGHT * 0.8 && canSplit) {
|
|
15521
|
-
// Split this large item into smaller parts
|
|
15522
|
-
const childSplits = splitLargeItem(key, config, data === null || data === void 0 ? void 0 : data[key], MAX_SECTION_HEIGHT * 0.6);
|
|
15523
|
-
childSplits.forEach((splitItem, splitIndex) => {
|
|
15524
|
-
// Check if current subsection has room
|
|
15525
|
-
if (currentHeight + splitItem.estimatedHeight > MAX_SECTION_HEIGHT && Object.keys(currentSubSection).length > 4) {
|
|
15526
|
-
// Save current sub-section
|
|
15527
|
-
subSections.push({
|
|
15528
|
-
key: "".concat(sectionKey, "_part_").concat(subSectionIndex),
|
|
15529
|
-
section: _objectSpread2({}, currentSubSection),
|
|
15530
|
-
title: section.label
|
|
15531
|
-
});
|
|
15532
|
-
|
|
15533
|
-
// Start new sub-section
|
|
15534
|
-
currentSubSection = {
|
|
15535
|
-
id: section.id,
|
|
15536
|
-
label: section.label,
|
|
15537
|
-
position: section.position + subSectionIndex + 1,
|
|
15538
|
-
subTitle: section.subTitle
|
|
15539
|
-
};
|
|
15540
|
-
currentHeight = 80;
|
|
15541
|
-
subSectionIndex++;
|
|
15542
|
-
}
|
|
15543
|
-
|
|
15544
|
-
// Add split item to current sub-section
|
|
15545
|
-
currentSubSection[splitItem.key] = splitItem.config;
|
|
15546
|
-
currentHeight += splitItem.estimatedHeight;
|
|
15547
|
-
});
|
|
15548
|
-
} else {
|
|
15549
|
-
// Regular processing for items that fit or can't be split
|
|
15550
|
-
// Check if adding this item would exceed height limit
|
|
15551
|
-
if (currentHeight + estimatedHeight > MAX_SECTION_HEIGHT && Object.keys(currentSubSection).length > 4) {
|
|
15552
|
-
// Save current sub-section
|
|
15553
|
-
subSections.push({
|
|
15554
|
-
key: "".concat(sectionKey, "_part_").concat(subSectionIndex),
|
|
15555
|
-
section: _objectSpread2({}, currentSubSection),
|
|
15556
|
-
title: section.label
|
|
15557
|
-
});
|
|
15558
|
-
|
|
15559
|
-
// Start new sub-section
|
|
15560
|
-
currentSubSection = {
|
|
15561
|
-
id: section.id,
|
|
15562
|
-
label: section.label,
|
|
15563
|
-
position: section.position + subSectionIndex + 1,
|
|
15564
|
-
subTitle: section.subTitle
|
|
15565
|
-
};
|
|
15566
|
-
currentHeight = 80;
|
|
15567
|
-
subSectionIndex++;
|
|
15568
|
-
}
|
|
15569
|
-
|
|
15570
|
-
// Add item to current sub-section
|
|
15571
|
-
currentSubSection[key] = config;
|
|
15572
|
-
currentHeight += estimatedHeight;
|
|
15573
|
-
}
|
|
15574
|
-
});
|
|
15575
|
-
|
|
15576
|
-
// Add the final sub-section if it has content
|
|
15577
|
-
if (Object.keys(currentSubSection).length > 4) {
|
|
15578
|
-
subSections.push({
|
|
15579
|
-
key: subSectionIndex === 0 ? sectionKey : "".concat(sectionKey, "_part_").concat(subSectionIndex),
|
|
15580
|
-
section: currentSubSection,
|
|
15581
|
-
title: section.label
|
|
15582
|
-
});
|
|
15583
|
-
}
|
|
15584
|
-
return subSections.length > 0 ? subSections : [{
|
|
15585
|
-
key: sectionKey,
|
|
15586
|
-
section: section,
|
|
15587
|
-
title: section.label
|
|
15588
|
-
}];
|
|
15589
|
-
};
|
|
15590
|
-
|
|
15591
|
-
// Helper function to split large items at the child level
|
|
15592
|
-
const splitLargeItem = (parentKey, parentConfig, parentValue, maxHeight) => {
|
|
15593
|
-
if (!(parentConfig !== null && parentConfig !== void 0 && parentConfig.inputs)) {
|
|
15594
|
-
return [{
|
|
15595
|
-
key: parentKey,
|
|
15596
|
-
config: parentConfig,
|
|
15597
|
-
estimatedHeight: estimateTreeNodeHeight(parentKey, parentConfig, parentValue)
|
|
15598
|
-
}];
|
|
15599
|
-
}
|
|
15600
|
-
const childItems = Object.keys(parentConfig.inputs).filter(childKey => {
|
|
15601
|
-
const childConfig = parentConfig.inputs[childKey];
|
|
15602
|
-
return !(childConfig !== null && childConfig !== void 0 && childConfig.showIf) || evaluateShowIfCondition(childConfig.showIf, data);
|
|
15603
|
-
}).map(childKey => ({
|
|
15604
|
-
key: childKey,
|
|
15605
|
-
config: parentConfig.inputs[childKey],
|
|
15606
|
-
estimatedHeight: estimateTreeNodeHeight(childKey, parentConfig.inputs[childKey], parentValue === null || parentValue === void 0 ? void 0 : parentValue[childKey])
|
|
15607
|
-
})).sort((a, b) => {
|
|
15608
|
-
var _a$config2, _b$config2;
|
|
15609
|
-
return (((_a$config2 = a.config) === null || _a$config2 === void 0 ? void 0 : _a$config2.position) || 0) - (((_b$config2 = b.config) === null || _b$config2 === void 0 ? void 0 : _b$config2.position) || 0);
|
|
15610
|
-
});
|
|
15611
|
-
const splits = [];
|
|
15612
|
-
let currentSplit = {
|
|
15613
|
-
key: "".concat(parentKey, "_part_0"),
|
|
15614
|
-
config: _objectSpread2(_objectSpread2({}, parentConfig), {}, {
|
|
15615
|
-
inputs: {}
|
|
15616
|
-
}),
|
|
15617
|
-
estimatedHeight: 40 // Base height for parent structure
|
|
15618
|
-
};
|
|
15619
|
-
let splitIndex = 0;
|
|
15620
|
-
childItems.forEach(child => {
|
|
15621
|
-
if (currentSplit.estimatedHeight + child.estimatedHeight > maxHeight && Object.keys(currentSplit.config.inputs).length > 0) {
|
|
15622
|
-
splits.push(currentSplit);
|
|
15623
|
-
splitIndex++;
|
|
15624
|
-
currentSplit = {
|
|
15625
|
-
key: "".concat(parentKey, "_part_").concat(splitIndex),
|
|
15626
|
-
config: _objectSpread2(_objectSpread2({}, parentConfig), {}, {
|
|
15627
|
-
label: parentConfig.label,
|
|
15628
|
-
inputs: {}
|
|
15629
|
-
}),
|
|
15630
|
-
estimatedHeight: 40
|
|
15631
|
-
};
|
|
15632
|
-
}
|
|
15633
|
-
currentSplit.config.inputs[child.key] = child.config;
|
|
15634
|
-
currentSplit.estimatedHeight += child.estimatedHeight;
|
|
15635
|
-
});
|
|
15636
|
-
if (Object.keys(currentSplit.config.inputs).length > 0) {
|
|
15637
|
-
splits.push(currentSplit);
|
|
15638
|
-
}
|
|
15639
|
-
return splits.length > 0 ? splits : [{
|
|
15640
|
-
key: parentKey,
|
|
15641
|
-
config: parentConfig,
|
|
15642
|
-
estimatedHeight: estimateTreeNodeHeight(parentKey, parentConfig, parentValue)
|
|
15643
|
-
}];
|
|
15644
|
-
};
|
|
15645
15425
|
const pdfConfig = React.useMemo(() => {
|
|
15646
15426
|
const sections = [];
|
|
15647
15427
|
Object.keys(organizedForm).forEach(sectionKey => {
|
|
@@ -15649,40 +15429,28 @@ const PdfForm = _ref3 => {
|
|
|
15649
15429
|
if (typeof section !== 'object' || !section.label) {
|
|
15650
15430
|
return;
|
|
15651
15431
|
}
|
|
15652
|
-
|
|
15653
|
-
|
|
15654
|
-
|
|
15655
|
-
|
|
15656
|
-
|
|
15657
|
-
|
|
15658
|
-
|
|
15659
|
-
|
|
15660
|
-
|
|
15661
|
-
|
|
15662
|
-
|
|
15663
|
-
|
|
15664
|
-
|
|
15665
|
-
|
|
15666
|
-
|
|
15667
|
-
|
|
15668
|
-
|
|
15669
|
-
|
|
15670
|
-
|
|
15671
|
-
|
|
15672
|
-
|
|
15673
|
-
|
|
15674
|
-
source: source,
|
|
15675
|
-
version: version,
|
|
15676
|
-
getApiBaseUrl: getApiBaseUrl,
|
|
15677
|
-
getAppHeader: getAppHeader,
|
|
15678
|
-
app: app
|
|
15679
|
-
})
|
|
15680
|
-
}, key),
|
|
15681
|
-
style: {
|
|
15682
|
-
marginBottom: '20px',
|
|
15683
|
-
padding: '0 20px'
|
|
15684
|
-
}
|
|
15685
|
-
});
|
|
15432
|
+
sections.push({
|
|
15433
|
+
render: () => /*#__PURE__*/jsxRuntime.jsx("div", {
|
|
15434
|
+
className: "pdf-form-section",
|
|
15435
|
+
children: /*#__PURE__*/jsxRuntime.jsx(PdfFormContent, {
|
|
15436
|
+
form: {
|
|
15437
|
+
[sectionKey]: section
|
|
15438
|
+
},
|
|
15439
|
+
data: data,
|
|
15440
|
+
t: t,
|
|
15441
|
+
user: user,
|
|
15442
|
+
title: formName,
|
|
15443
|
+
source: source,
|
|
15444
|
+
version: version,
|
|
15445
|
+
getApiBaseUrl: getApiBaseUrl,
|
|
15446
|
+
getAppHeader: getAppHeader,
|
|
15447
|
+
app: app
|
|
15448
|
+
})
|
|
15449
|
+
}, sectionKey),
|
|
15450
|
+
style: {
|
|
15451
|
+
marginBottom: '20px',
|
|
15452
|
+
padding: '0 20px'
|
|
15453
|
+
}
|
|
15686
15454
|
});
|
|
15687
15455
|
});
|
|
15688
15456
|
return sections;
|
|
@@ -18640,7 +18408,7 @@ const useMap$1 = ({
|
|
|
18640
18408
|
const pos = allData.map(m => Array.isArray(m.area) ? m.area : [Number(m.marker?.lat ?? 0), Number(m.marker?.lng ?? 0)]);
|
|
18641
18409
|
const bounds = new L__namespace.LatLngBounds(pos);
|
|
18642
18410
|
mapRef.fitBounds(bounds, {
|
|
18643
|
-
padding: [
|
|
18411
|
+
padding: [10, 10]
|
|
18644
18412
|
});
|
|
18645
18413
|
}
|
|
18646
18414
|
}
|
|
@@ -19931,6 +19699,39 @@ const useGlobe = ({
|
|
|
19931
19699
|
}));
|
|
19932
19700
|
roots.current.push(root);
|
|
19933
19701
|
}
|
|
19702
|
+
} else if (type === "project") {
|
|
19703
|
+
// Handle project markers
|
|
19704
|
+
const el = document.createElement('div');
|
|
19705
|
+
el.className = 'mapboxgl-marker project-marker';
|
|
19706
|
+
el.style.width = '30px';
|
|
19707
|
+
el.style.height = '30px';
|
|
19708
|
+
el.style.backgroundColor = '#52c41a'; // Green color for projects
|
|
19709
|
+
el.style.borderRadius = '50%';
|
|
19710
|
+
el.style.border = '3px solid white';
|
|
19711
|
+
el.style.cursor = 'pointer';
|
|
19712
|
+
el.style.boxShadow = '0px 3.45px 3.45px 0px #00000029';
|
|
19713
|
+
el.style.display = 'flex';
|
|
19714
|
+
el.style.alignItems = 'center';
|
|
19715
|
+
el.style.justifyContent = 'center';
|
|
19716
|
+
el.style.color = 'white';
|
|
19717
|
+
el.style.fontWeight = 'bold';
|
|
19718
|
+
el.style.fontSize = '12px';
|
|
19719
|
+
|
|
19720
|
+
// Add project icon (you can customize this)
|
|
19721
|
+
el.innerHTML = '📋';
|
|
19722
|
+
const div = document.createElement("div");
|
|
19723
|
+
const root = client.createRoot(div);
|
|
19724
|
+
root.render( /*#__PURE__*/jsxRuntime.jsx(jsxRuntime.Fragment, {
|
|
19725
|
+
children: renderTooltipJsx({
|
|
19726
|
+
title: d.name,
|
|
19727
|
+
items: renderTooltip(d),
|
|
19728
|
+
link,
|
|
19729
|
+
total: d.sources,
|
|
19730
|
+
onClickLink: () => onClickLink(d)
|
|
19731
|
+
})
|
|
19732
|
+
}));
|
|
19733
|
+
roots.current.push(root);
|
|
19734
|
+
marker = new mapboxgl.Marker(el).setLngLat([d.marker.lng, d.marker.lat]).setPopup(new mapboxgl.Popup().setDOMContent(div)).addTo(mapRef);
|
|
19934
19735
|
} else {
|
|
19935
19736
|
// Default marker for other types
|
|
19936
19737
|
const el = document.createElement('div');
|
|
@@ -20737,29 +20538,12 @@ const DAFSteps = _ref => {
|
|
|
20737
20538
|
let {
|
|
20738
20539
|
direction = "vertical",
|
|
20739
20540
|
current = 0,
|
|
20740
|
-
items = []
|
|
20741
|
-
scrollThreshold = 4
|
|
20541
|
+
items = []
|
|
20742
20542
|
} = _ref;
|
|
20743
|
-
|
|
20744
|
-
|
|
20745
|
-
|
|
20746
|
-
|
|
20747
|
-
overflowX: "hidden"
|
|
20748
|
-
} : {
|
|
20749
|
-
maxWidth: "100%",
|
|
20750
|
-
overflowX: "auto",
|
|
20751
|
-
overflowY: "hidden",
|
|
20752
|
-
whiteSpace: "nowrap"
|
|
20753
|
-
}), {}, {
|
|
20754
|
-
padding: "8px",
|
|
20755
|
-
marginRight: direction === "vertical" ? "-8px" : "0",
|
|
20756
|
-
paddingRight: direction === "vertical" ? "16px" : "8px"
|
|
20757
|
-
}) : {};
|
|
20758
|
-
return /*#__PURE__*/jsxRuntime.jsx(Widget, {
|
|
20759
|
-
title: "Life Cycle",
|
|
20760
|
-
className: "with-border-header",
|
|
20761
|
-
children: /*#__PURE__*/jsxRuntime.jsx("div", {
|
|
20762
|
-
style: scrollableStyles,
|
|
20543
|
+
return /*#__PURE__*/jsxRuntime.jsx(jsxRuntime.Fragment, {
|
|
20544
|
+
children: /*#__PURE__*/jsxRuntime.jsx(Widget, {
|
|
20545
|
+
title: "Life Cycle",
|
|
20546
|
+
className: "with-border-header",
|
|
20763
20547
|
children: /*#__PURE__*/jsxRuntime.jsx(antd.Steps, {
|
|
20764
20548
|
direction: direction,
|
|
20765
20549
|
current: current,
|
|
@@ -20774,14 +20558,12 @@ DAFSteps.propTypes = {
|
|
|
20774
20558
|
items: PropTypes__default["default"].arrayOf(PropTypes__default["default"].shape({
|
|
20775
20559
|
title: PropTypes__default["default"].string.isRequired,
|
|
20776
20560
|
description: PropTypes__default["default"].string
|
|
20777
|
-
}))
|
|
20778
|
-
scrollThreshold: PropTypes__default["default"].number
|
|
20561
|
+
}))
|
|
20779
20562
|
};
|
|
20780
20563
|
DAFSteps.defaultProps = {
|
|
20781
20564
|
direction: "vertical",
|
|
20782
20565
|
current: 0,
|
|
20783
|
-
items: []
|
|
20784
|
-
scrollThreshold: 4
|
|
20566
|
+
items: []
|
|
20785
20567
|
};
|
|
20786
20568
|
|
|
20787
20569
|
/**
|
package/dist/utils/index.js
CHANGED
|
@@ -3835,7 +3835,7 @@ function showHideForm(form, formsValue) {
|
|
|
3835
3835
|
|
|
3836
3836
|
/* eslint-disable no-constant-condition */
|
|
3837
3837
|
const getNkey = namespace => {
|
|
3838
|
-
if (['location', 'scl', 'village', 'event', 'incidents', 'corrective-actions', 'testimonials', 'initiatives', 'victims', 'pictures', 'documents', 'lir', 'sp', 'im', 'sci', 'bpe', 'gm'].includes(namespace)) {
|
|
3838
|
+
if (['location', 'scl', 'village', 'event', 'incidents', 'corrective-actions', 'testimonials', 'initiatives', 'victims', 'pictures', 'documents', 'lir', 'sp', 'im', 'sci', 'bpe', 'gm', 'project-readiness'].includes(namespace)) {
|
|
3839
3839
|
return 'scoping';
|
|
3840
3840
|
}
|
|
3841
3841
|
return namespace;
|
package/package.json
CHANGED
|
@@ -264,6 +264,48 @@ export const useGlobe = ({
|
|
|
264
264
|
|
|
265
265
|
roots.current.push(root);
|
|
266
266
|
}
|
|
267
|
+
} else if (type === "project") {
|
|
268
|
+
// Handle project markers
|
|
269
|
+
const el = document.createElement('div');
|
|
270
|
+
el.className = 'mapboxgl-marker project-marker';
|
|
271
|
+
el.style.width = '30px';
|
|
272
|
+
el.style.height = '30px';
|
|
273
|
+
el.style.backgroundColor = '#52c41a'; // Green color for projects
|
|
274
|
+
el.style.borderRadius = '50%';
|
|
275
|
+
el.style.border = '3px solid white';
|
|
276
|
+
el.style.cursor = 'pointer';
|
|
277
|
+
el.style.boxShadow = '0px 3.45px 3.45px 0px #00000029';
|
|
278
|
+
el.style.display = 'flex';
|
|
279
|
+
el.style.alignItems = 'center';
|
|
280
|
+
el.style.justifyContent = 'center';
|
|
281
|
+
el.style.color = 'white';
|
|
282
|
+
el.style.fontWeight = 'bold';
|
|
283
|
+
el.style.fontSize = '12px';
|
|
284
|
+
|
|
285
|
+
// Add project icon (you can customize this)
|
|
286
|
+
el.innerHTML = '📋';
|
|
287
|
+
|
|
288
|
+
const div = document.createElement("div");
|
|
289
|
+
const root = createRoot(div);
|
|
290
|
+
|
|
291
|
+
root.render(
|
|
292
|
+
<>
|
|
293
|
+
{renderTooltipJsx({
|
|
294
|
+
title: d.name,
|
|
295
|
+
items: renderTooltip(d),
|
|
296
|
+
link,
|
|
297
|
+
total: d.sources,
|
|
298
|
+
onClickLink: () => onClickLink(d),
|
|
299
|
+
})}
|
|
300
|
+
</>,
|
|
301
|
+
);
|
|
302
|
+
|
|
303
|
+
roots.current.push(root);
|
|
304
|
+
|
|
305
|
+
marker = new mapboxgl.Marker(el)
|
|
306
|
+
.setLngLat([d.marker.lng, d.marker.lat])
|
|
307
|
+
.setPopup(new mapboxgl.Popup().setDOMContent(div))
|
|
308
|
+
.addTo(mapRef);
|
|
267
309
|
} else {
|
|
268
310
|
// Default marker for other types
|
|
269
311
|
const el = document.createElement('div');
|
|
@@ -306,7 +306,7 @@ export const useMap = ({
|
|
|
306
306
|
: [Number(m.marker?.lat ?? 0), Number(m.marker?.lng ?? 0)],
|
|
307
307
|
);
|
|
308
308
|
const bounds = new L.LatLngBounds(pos);
|
|
309
|
-
mapRef.fitBounds(bounds, { padding: [
|
|
309
|
+
mapRef.fitBounds(bounds, { padding: [10, 10] });
|
|
310
310
|
}
|
|
311
311
|
}
|
|
312
312
|
}, [allData, mapRef]);
|
|
@@ -3,5 +3,6 @@ import { storyConfig as DefaultMapConfig } from "./storyConfig2.js";
|
|
|
3
3
|
import { storyConfig as TerritoryMapConfig } from "./storyConfig3.js";
|
|
4
4
|
import { storyConfig as StakeholderMapConfig } from "./storyConfig4.js";
|
|
5
5
|
import { storyConfig as ChainMapConfig } from "./storyConfig5.js";
|
|
6
|
+
import { storyConfig as ProjectConfig } from "./storyConfig6.js";
|
|
6
7
|
|
|
7
|
-
export { DefaultMapConfig, TerritoryMapConfig, StakeholderMapConfig, EventConfig, ChainMapConfig };
|
|
8
|
+
export { DefaultMapConfig, TerritoryMapConfig, StakeholderMapConfig, EventConfig, ChainMapConfig, ProjectConfig };
|
|
@@ -0,0 +1,366 @@
|
|
|
1
|
+
import { findCoordinatesByCountry } from "../Globe/globeHelpers";
|
|
2
|
+
|
|
3
|
+
// Transform project data to match Globe component expectations
|
|
4
|
+
const transformProjectsToGlobeData = (projects) => {
|
|
5
|
+
return projects.map(project => {
|
|
6
|
+
// Get coordinates from country code
|
|
7
|
+
const coordinates = findCoordinatesByCountry(project.country);
|
|
8
|
+
|
|
9
|
+
return {
|
|
10
|
+
...project,
|
|
11
|
+
marker: {
|
|
12
|
+
lat: coordinates[0],
|
|
13
|
+
lng: coordinates[1]
|
|
14
|
+
},
|
|
15
|
+
name: project.name || project.title,
|
|
16
|
+
description: project.projectDescription || "No description available",
|
|
17
|
+
total: 1, // Each project is a single marker
|
|
18
|
+
sources: 1,
|
|
19
|
+
type: "project",
|
|
20
|
+
// Add project-specific data for tooltip
|
|
21
|
+
projectData: {
|
|
22
|
+
datastakeId: project.datastakeId,
|
|
23
|
+
sectoralScope: project.sectoralScope,
|
|
24
|
+
percentageCompletion: project.percentageCompletion,
|
|
25
|
+
country: project.country,
|
|
26
|
+
author: project.author?.name,
|
|
27
|
+
createdAt: project.createdAt,
|
|
28
|
+
mainImage: project.mainImage?.[0]?.url
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
});
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
// Sample project data from the user
|
|
35
|
+
const sampleProjects = [
|
|
36
|
+
{
|
|
37
|
+
"_id": "687a4d9a4cfa60f30db94c52",
|
|
38
|
+
"createdAt": "2025-07-18T00:00:00.000Z",
|
|
39
|
+
"updatedAt": "2025-07-18T00:00:00.000Z",
|
|
40
|
+
"form": "straatosProject",
|
|
41
|
+
"id": "3129457d-b787-4955-ba25-04d67fecfaaa",
|
|
42
|
+
"name": "ABC Mangrove Senegal",
|
|
43
|
+
"country": "SN",
|
|
44
|
+
"datastakeId": "PRJ-00000000103",
|
|
45
|
+
"title": "ABC Mangrove Senegal",
|
|
46
|
+
"sectoralScope": "agricultureForestryAndOtherLandUse",
|
|
47
|
+
"sdgs": [],
|
|
48
|
+
"authorId": "df5378ae-704a-4a46-93b2-336cc5341456",
|
|
49
|
+
"percentageCompletion": 11.76470588235294,
|
|
50
|
+
"projectDescription": "ABC Mangrove Senegal is an environmental and community-focused initiative dedicated to the restoration, preservation, and sustainable management of mangrove ecosystems in Senegal.",
|
|
51
|
+
"mainImage": [
|
|
52
|
+
{
|
|
53
|
+
"url": "https://cdn.straatos.io/dev/company-df5378ae-704a-4a46-93b2-336cc5341456/user-e8d71443-339f-4b45-bbf5-22f0e5f09601/auth-bg_cropped-1754901830065.png",
|
|
54
|
+
"path": "dev/company-df5378ae-704a-4a46-93b2-336cc5341456/user-e8d71443-339f-4b45-bbf5-22f0e5f09601/auth-bg_cropped-1754901830065.png",
|
|
55
|
+
"name": "auth-bg_cropped-1754901830065.png",
|
|
56
|
+
"size": 1693409,
|
|
57
|
+
"type": "image/png"
|
|
58
|
+
}
|
|
59
|
+
],
|
|
60
|
+
"author": {
|
|
61
|
+
"name": "Geri SHPK",
|
|
62
|
+
"country": "AL",
|
|
63
|
+
"category": "civilSociety",
|
|
64
|
+
"subCategory": "internationalNGO"
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"_id": "687a57e24cfa60f30db954ca",
|
|
69
|
+
"createdAt": "2025-07-18T00:00:00.000Z",
|
|
70
|
+
"updatedAt": "2025-07-18T00:00:00.000Z",
|
|
71
|
+
"form": "project",
|
|
72
|
+
"id": "10e09c02-1986-4eb5-9069-355bffdfb93d",
|
|
73
|
+
"name": "Testing",
|
|
74
|
+
"country": "SN",
|
|
75
|
+
"datastakeId": "PRJ-00000000104",
|
|
76
|
+
"title": "Testing",
|
|
77
|
+
"sectoralScope": "agricultureForestryAndOtherLandUse",
|
|
78
|
+
"sdgs": [],
|
|
79
|
+
"authorId": "df5378ae-704a-4a46-93b2-336cc5341456",
|
|
80
|
+
"percentageCompletion": 28.57142857142857,
|
|
81
|
+
"author": {
|
|
82
|
+
"name": "Geri SHPK",
|
|
83
|
+
"country": "AL",
|
|
84
|
+
"category": "civilSociety",
|
|
85
|
+
"subCategory": "internationalNGO"
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
"_id": "687e619d4cfa60f30db967ea",
|
|
90
|
+
"createdAt": "2025-07-21T15:49:49.431Z",
|
|
91
|
+
"updatedAt": "2025-07-21T15:49:49.431Z",
|
|
92
|
+
"form": "straatosProject",
|
|
93
|
+
"id": "51440c46-2d42-452d-8ea1-614002589d4c",
|
|
94
|
+
"name": "Pietra's Project",
|
|
95
|
+
"country": "BR",
|
|
96
|
+
"datastakeId": "PRJ-00000000105",
|
|
97
|
+
"title": "Pietra's Project",
|
|
98
|
+
"sectoralScope": "agricultureForestryAndOtherLandUse",
|
|
99
|
+
"sdgs": [],
|
|
100
|
+
"authorId": "df5378ae-704a-4a46-93b2-336cc5341456",
|
|
101
|
+
"author": {
|
|
102
|
+
"name": "Geri SHPK",
|
|
103
|
+
"country": "AL",
|
|
104
|
+
"category": "civilSociety",
|
|
105
|
+
"subCategory": "internationalNGO"
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
"_id": "6883918729bcd5751e8dd579",
|
|
110
|
+
"createdAt": "2025-07-25T14:15:35.305Z",
|
|
111
|
+
"updatedAt": "2025-07-25T14:15:35.305Z",
|
|
112
|
+
"form": "straatosProject",
|
|
113
|
+
"id": "275acff8-c478-40a5-a23d-94968dca01d1",
|
|
114
|
+
"name": "efwefwe",
|
|
115
|
+
"country": "AX",
|
|
116
|
+
"datastakeId": "PRJ-00000000106",
|
|
117
|
+
"title": "efwefwe",
|
|
118
|
+
"sectoralScope": "agricultureForestryAndOtherLandUse",
|
|
119
|
+
"sdgs": [],
|
|
120
|
+
"authorId": "df5378ae-704a-4a46-93b2-336cc5341456",
|
|
121
|
+
"percentageCompletion": 100,
|
|
122
|
+
"author": {
|
|
123
|
+
"name": "Geri SHPK",
|
|
124
|
+
"country": "AL",
|
|
125
|
+
"category": "civilSociety",
|
|
126
|
+
"subCategory": "internationalNGO"
|
|
127
|
+
}
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
"_id": "6883b50e29bcd5751e8dda3e",
|
|
131
|
+
"createdAt": "2025-07-25T00:00:00.000Z",
|
|
132
|
+
"updatedAt": "2025-07-25T00:00:00.000Z",
|
|
133
|
+
"form": "project",
|
|
134
|
+
"id": "3bac13f1-4ebc-4428-9230-af1dc6ab1ab9",
|
|
135
|
+
"name": "Geri Test",
|
|
136
|
+
"country": "AS",
|
|
137
|
+
"datastakeId": "PRJ-00000000107",
|
|
138
|
+
"title": "Geri Test",
|
|
139
|
+
"sectoralScope": "agricultureForestryAndOtherLandUse",
|
|
140
|
+
"sdgs": [],
|
|
141
|
+
"authorId": "df5378ae-704a-4a46-93b2-336cc5341456",
|
|
142
|
+
"percentageCompletion": 33.33333333333333,
|
|
143
|
+
"projectDescription": "ABC Mangrove Senegal is an environmental and community-focused initiative dedicated to the restoration, preservation, and sustainable management of mangrove ecosystems in Senegal.",
|
|
144
|
+
"mainImage": [
|
|
145
|
+
{
|
|
146
|
+
"url": "https://cdn.straatos.io/dev/company-df5378ae-704a-4a46-93b2-336cc5341456/user-e8d71443-339f-4b45-bbf5-22f0e5f09600/screenshot-from-2024-11-11-09-29-22-1758200879648.png",
|
|
147
|
+
"path": "dev/company-df5378ae-704a-4a46-93b2-336cc5341456/user-e8d71443-339f-4b45-bbf5-22f0e5f09600/screenshot-from-2024-11-11-09-29-22-1758200879648.png",
|
|
148
|
+
"name": "screenshot-from-2024-11-11-09-29-22-1758200879648.png",
|
|
149
|
+
"size": 414991,
|
|
150
|
+
"type": "image/png"
|
|
151
|
+
}
|
|
152
|
+
],
|
|
153
|
+
"author": {
|
|
154
|
+
"name": "Geri SHPK",
|
|
155
|
+
"country": "AL",
|
|
156
|
+
"category": "civilSociety",
|
|
157
|
+
"subCategory": "internationalNGO"
|
|
158
|
+
}
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
"_id": "688c66c62fb165d7a389fbf7",
|
|
162
|
+
"createdAt": "2025-08-01T07:03:34.501Z",
|
|
163
|
+
"updatedAt": "2025-08-01T07:03:34.501Z",
|
|
164
|
+
"form": "straatosProject",
|
|
165
|
+
"id": "39fd860e-412c-456f-9b70-a67d4dc82433",
|
|
166
|
+
"name": "test 777",
|
|
167
|
+
"country": "AL",
|
|
168
|
+
"datastakeId": "PRJ-00000000109",
|
|
169
|
+
"title": "test 777",
|
|
170
|
+
"sectoralScope": "agricultureForestryAndOtherLandUse",
|
|
171
|
+
"sdgs": [],
|
|
172
|
+
"authorId": "df5378ae-704a-4a46-93b2-336cc5341456",
|
|
173
|
+
"author": {
|
|
174
|
+
"name": "Geri SHPK",
|
|
175
|
+
"country": "AL",
|
|
176
|
+
"category": "civilSociety",
|
|
177
|
+
"subCategory": "internationalNGO"
|
|
178
|
+
}
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
"_id": "68927b8d3c4650496ed9003f",
|
|
182
|
+
"createdAt": "2025-08-05T00:00:00.000Z",
|
|
183
|
+
"updatedAt": "2025-08-05T00:00:00.000Z",
|
|
184
|
+
"form": "straatosProject",
|
|
185
|
+
"id": "468204d2-28d6-4097-a362-ad12d642bf4f",
|
|
186
|
+
"name": "Current",
|
|
187
|
+
"country": "AL",
|
|
188
|
+
"datastakeId": "PRJ-00000000111",
|
|
189
|
+
"title": "Current",
|
|
190
|
+
"mainImage": [
|
|
191
|
+
{
|
|
192
|
+
"url": "https://cdn.straatos.io/dev/company-df5378ae-704a-4a46-93b2-336cc5341456/user-e8d71443-339f-4b45-bbf5-22f0e5f09600/screenshot-from-2024-11-28-12-41-52-1754465225229.png",
|
|
193
|
+
"path": "dev/company-df5378ae-704a-4a46-93b2-336cc5341456/user-e8d71443-339f-4b45-bbf5-22f0e5f09600/screenshot-from-2024-11-28-12-41-52-1754465225229.png",
|
|
194
|
+
"name": "screenshot-from-2024-11-28-12-41-52-1754465225229.png",
|
|
195
|
+
"size": 92090,
|
|
196
|
+
"type": "image/png"
|
|
197
|
+
}
|
|
198
|
+
],
|
|
199
|
+
"sectoralScope": "energy",
|
|
200
|
+
"sdgs": [],
|
|
201
|
+
"authorId": "df5378ae-704a-4a46-93b2-336cc5341456",
|
|
202
|
+
"percentageCompletion": 17.647058823529413,
|
|
203
|
+
"projectDescription": "testing testing testing",
|
|
204
|
+
"author": {
|
|
205
|
+
"name": "Geri SHPK",
|
|
206
|
+
"country": "AL",
|
|
207
|
+
"category": "civilSociety",
|
|
208
|
+
"subCategory": "internationalNGO"
|
|
209
|
+
}
|
|
210
|
+
},
|
|
211
|
+
{
|
|
212
|
+
"_id": "68985abea7d389ab99d611e4",
|
|
213
|
+
"createdAt": "2025-08-10T00:00:00.000Z",
|
|
214
|
+
"updatedAt": "2025-08-10T00:00:00.000Z",
|
|
215
|
+
"form": "project",
|
|
216
|
+
"id": "c949c1a4-f83d-45fa-820f-0ee56bc023ba",
|
|
217
|
+
"name": "project 1",
|
|
218
|
+
"country": "AL",
|
|
219
|
+
"datastakeId": "PRJ-00000000112",
|
|
220
|
+
"title": "project 1",
|
|
221
|
+
"mainImage": [
|
|
222
|
+
{
|
|
223
|
+
"url": "https://cdn.straatos.io/dev/company-df5378ae-704a-4a46-93b2-336cc5341456/user-e8d71443-339f-4b45-bbf5-22f0e5f09601/abcmangrove_allcot-10-1756470770827.jpg",
|
|
224
|
+
"path": "dev/company-df5378ae-704a-4a46-93b2-336cc5341456/user-e8d71443-339f-4b45-bbf5-22f0e5f09601/abcmangrove_allcot-10-1756470770827.jpg",
|
|
225
|
+
"name": "abcmangrove_allcot-10-1756470770827.jpg",
|
|
226
|
+
"size": 146120,
|
|
227
|
+
"type": "image/jpeg"
|
|
228
|
+
}
|
|
229
|
+
],
|
|
230
|
+
"sectoralScope": "agricultureForestryAndOtherLandUse",
|
|
231
|
+
"sdgs": [],
|
|
232
|
+
"authorId": "df5378ae-704a-4a46-93b2-336cc5341456",
|
|
233
|
+
"percentageCompletion": 25,
|
|
234
|
+
"author": {
|
|
235
|
+
"name": "Geri SHPK",
|
|
236
|
+
"country": "AL",
|
|
237
|
+
"category": "civilSociety",
|
|
238
|
+
"subCategory": "internationalNGO"
|
|
239
|
+
}
|
|
240
|
+
},
|
|
241
|
+
{
|
|
242
|
+
"_id": "68c3e1817ce6a6d7d8c16250",
|
|
243
|
+
"createdAt": "2025-09-12T00:00:00.000Z",
|
|
244
|
+
"updatedAt": "2025-09-12T00:00:00.000Z",
|
|
245
|
+
"form": "project",
|
|
246
|
+
"id": "b7a6ce62-dda3-4ffd-8f5a-e9721e15fe9f",
|
|
247
|
+
"name": "test fran",
|
|
248
|
+
"country": "CL",
|
|
249
|
+
"datastakeId": "PRJ-00000000113",
|
|
250
|
+
"title": "test fran",
|
|
251
|
+
"sectoralScope": "agricultureForestryAndOtherLandUse",
|
|
252
|
+
"sdgs": [],
|
|
253
|
+
"authorId": "df5378ae-704a-4a46-93b2-336cc5341456",
|
|
254
|
+
"percentageCompletion": 25,
|
|
255
|
+
"author": {
|
|
256
|
+
"name": "Geri SHPK",
|
|
257
|
+
"country": "AL",
|
|
258
|
+
"category": "civilSociety",
|
|
259
|
+
"subCategory": "internationalNGO"
|
|
260
|
+
}
|
|
261
|
+
},
|
|
262
|
+
{
|
|
263
|
+
"_id": "68cab88001892530c66c3079",
|
|
264
|
+
"createdAt": "2025-09-17T13:32:48.646Z",
|
|
265
|
+
"updatedAt": "2025-09-17T13:32:48.646Z",
|
|
266
|
+
"form": "project",
|
|
267
|
+
"id": "a64070b0-74bc-4694-8e29-8006f9de70f7",
|
|
268
|
+
"name": "Pietra's Project",
|
|
269
|
+
"country": "AL",
|
|
270
|
+
"datastakeId": "PRJ-00000000114",
|
|
271
|
+
"title": "Pietra's Project",
|
|
272
|
+
"sectoralScope": "fugitiveEmissionsFromIndustrialGases",
|
|
273
|
+
"sdgs": [],
|
|
274
|
+
"authorId": "df5378ae-704a-4a46-93b2-336cc5341456",
|
|
275
|
+
"percentageCompletion": 25,
|
|
276
|
+
"author": {
|
|
277
|
+
"name": "Geri SHPK",
|
|
278
|
+
"country": "AL",
|
|
279
|
+
"category": "civilSociety",
|
|
280
|
+
"subCategory": "internationalNGO"
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
];
|
|
284
|
+
|
|
285
|
+
export const storyConfig = {
|
|
286
|
+
data: transformProjectsToGlobeData(sampleProjects),
|
|
287
|
+
type: "project",
|
|
288
|
+
primaryLink: true,
|
|
289
|
+
showSider: true,
|
|
290
|
+
siderTitle: "Project Details",
|
|
291
|
+
renderTooltip: (project) => {
|
|
292
|
+
return [
|
|
293
|
+
{ label: "Project ID", value: project.projectData?.datastakeId || "N/A" },
|
|
294
|
+
{ label: "Sector", value: project.projectData?.sectoralScope || "N/A" },
|
|
295
|
+
{ label: "Completion", value: `${Math.round(project.projectData?.percentageCompletion || 0)}%` },
|
|
296
|
+
{ label: "Country", value: project.projectData?.country || "N/A" },
|
|
297
|
+
{ label: "Author", value: project.projectData?.author || "N/A" },
|
|
298
|
+
{ label: "Created", value: project.projectData?.createdAt ? new Date(project.projectData.createdAt).toLocaleDateString() : "N/A" }
|
|
299
|
+
];
|
|
300
|
+
},
|
|
301
|
+
renderSider: (activeMarker) => {
|
|
302
|
+
const project = activeMarker.data;
|
|
303
|
+
const projectData = project.projectData;
|
|
304
|
+
|
|
305
|
+
return (
|
|
306
|
+
<div className="project-sider">
|
|
307
|
+
{projectData?.mainImage && (
|
|
308
|
+
<div className="project-image mb-3">
|
|
309
|
+
<img
|
|
310
|
+
src={projectData.mainImage}
|
|
311
|
+
alt={project.name}
|
|
312
|
+
style={{ width: '100%', height: '200px', objectFit: 'cover', borderRadius: '8px' }}
|
|
313
|
+
/>
|
|
314
|
+
</div>
|
|
315
|
+
)}
|
|
316
|
+
|
|
317
|
+
<div className="project-details">
|
|
318
|
+
<div className="detail-row mb-2">
|
|
319
|
+
<span className="label">Project ID:</span>
|
|
320
|
+
<span className="value">{projectData?.datastakeId || "N/A"}</span>
|
|
321
|
+
</div>
|
|
322
|
+
|
|
323
|
+
<div className="detail-row mb-2">
|
|
324
|
+
<span className="label">Sectoral Scope:</span>
|
|
325
|
+
<span className="value">{projectData?.sectoralScope || "N/A"}</span>
|
|
326
|
+
</div>
|
|
327
|
+
|
|
328
|
+
<div className="detail-row mb-2">
|
|
329
|
+
<span className="label">Completion:</span>
|
|
330
|
+
<span className="value">{Math.round(projectData?.percentageCompletion || 0)}%</span>
|
|
331
|
+
</div>
|
|
332
|
+
|
|
333
|
+
<div className="detail-row mb-2">
|
|
334
|
+
<span className="label">Country:</span>
|
|
335
|
+
<span className="value">{projectData?.country || "N/A"}</span>
|
|
336
|
+
</div>
|
|
337
|
+
|
|
338
|
+
<div className="detail-row mb-2">
|
|
339
|
+
<span className="label">Author:</span>
|
|
340
|
+
<span className="value">{projectData?.author || "N/A"}</span>
|
|
341
|
+
</div>
|
|
342
|
+
|
|
343
|
+
<div className="detail-row mb-2">
|
|
344
|
+
<span className="label">Created:</span>
|
|
345
|
+
<span className="value">
|
|
346
|
+
{projectData?.createdAt ? new Date(projectData.createdAt).toLocaleDateString() : "N/A"}
|
|
347
|
+
</span>
|
|
348
|
+
</div>
|
|
349
|
+
|
|
350
|
+
{project.description && (
|
|
351
|
+
<div className="detail-row mt-3">
|
|
352
|
+
<span className="label">Description:</span>
|
|
353
|
+
<p className="value mt-1" style={{ fontSize: '14px', lineHeight: '1.4' }}>
|
|
354
|
+
{project.description}
|
|
355
|
+
</p>
|
|
356
|
+
</div>
|
|
357
|
+
)}
|
|
358
|
+
</div>
|
|
359
|
+
</div>
|
|
360
|
+
);
|
|
361
|
+
},
|
|
362
|
+
onClickLink: (project) => {
|
|
363
|
+
console.log('Project clicked:', project);
|
|
364
|
+
// You can add navigation logic here
|
|
365
|
+
}
|
|
366
|
+
};
|
|
@@ -17,11 +17,6 @@ VerticalSteps.args = {
|
|
|
17
17
|
{ title: "Step 1", description: "This is the first step" },
|
|
18
18
|
{ title: "Step 2", description: "This is the second step" },
|
|
19
19
|
{ title: "Step 3", description: "This is the third step" },
|
|
20
|
-
{ title: "Step 3", description: "This is the third step" },
|
|
21
|
-
{ title: "Step 3", description: "This is the third step" },
|
|
22
|
-
{ title: "Step 3", description: "This is the third step" },
|
|
23
|
-
{ title: "Step 3", description: "This is the third step" },
|
|
24
|
-
{ title: "Step 3", description: "This is the third step" },
|
|
25
20
|
],
|
|
26
21
|
};
|
|
27
22
|
|
|
@@ -3,35 +3,16 @@ import { Steps } from "antd";
|
|
|
3
3
|
import Widget from "../../Dashboard/Widget/index.jsx";
|
|
4
4
|
import PropTypes from "prop-types";
|
|
5
5
|
|
|
6
|
-
const DAFSteps = ({ direction = "vertical", current = 0, items = []
|
|
7
|
-
const shouldScroll = items.length > scrollThreshold;
|
|
8
|
-
|
|
9
|
-
const scrollableStyles = shouldScroll ? {
|
|
10
|
-
...(direction === "vertical" ? {
|
|
11
|
-
maxHeight: "300px",
|
|
12
|
-
overflowY: "auto",
|
|
13
|
-
overflowX: "hidden"
|
|
14
|
-
} : {
|
|
15
|
-
maxWidth: "100%",
|
|
16
|
-
overflowX: "auto",
|
|
17
|
-
overflowY: "hidden",
|
|
18
|
-
whiteSpace: "nowrap"
|
|
19
|
-
}),
|
|
20
|
-
padding: "8px",
|
|
21
|
-
marginRight: direction === "vertical" ? "-8px" : "0",
|
|
22
|
-
paddingRight: direction === "vertical" ? "16px" : "8px"
|
|
23
|
-
} : {};
|
|
24
|
-
|
|
6
|
+
const DAFSteps = ({ direction = "vertical", current = 0, items = [] }) => {
|
|
25
7
|
return (
|
|
26
|
-
|
|
27
|
-
<
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
/>
|
|
33
|
-
</div>
|
|
8
|
+
<><Widget title="Life Cycle" className="with-border-header">
|
|
9
|
+
<Steps
|
|
10
|
+
direction={direction}
|
|
11
|
+
current={current}
|
|
12
|
+
items={items}
|
|
13
|
+
/>
|
|
34
14
|
</Widget>
|
|
15
|
+
</>
|
|
35
16
|
);
|
|
36
17
|
};
|
|
37
18
|
|
|
@@ -44,14 +25,12 @@ DAFSteps.propTypes = {
|
|
|
44
25
|
description: PropTypes.string,
|
|
45
26
|
})
|
|
46
27
|
),
|
|
47
|
-
scrollThreshold: PropTypes.number,
|
|
48
28
|
};
|
|
49
29
|
|
|
50
30
|
DAFSteps.defaultProps = {
|
|
51
31
|
direction: "vertical",
|
|
52
32
|
current: 0,
|
|
53
33
|
items: [],
|
|
54
|
-
scrollThreshold: 4,
|
|
55
34
|
};
|
|
56
35
|
|
|
57
36
|
export default DAFSteps;
|
|
@@ -525,227 +525,6 @@ const PdfForm = ({
|
|
|
525
525
|
|
|
526
526
|
const organizedForm = useMemo(() => organizeFormByHeaders(form), [form]);
|
|
527
527
|
|
|
528
|
-
// Constants for height calculations (same as PdfView)
|
|
529
|
-
const PAGE_HEIGHT = 1587;
|
|
530
|
-
const FOOTER_HEIGHT = 70;
|
|
531
|
-
const HEADER_HEIGHT = 100;
|
|
532
|
-
|
|
533
|
-
// Helper function to estimate tree node height based on content and type
|
|
534
|
-
const estimateTreeNodeHeight = (key, config, value, level = 0) => {
|
|
535
|
-
const baseHeight = 28; // Base height per tree node
|
|
536
|
-
const indentHeight = level * 2; // Additional height per level
|
|
537
|
-
let totalHeight = baseHeight + indentHeight;
|
|
538
|
-
|
|
539
|
-
// Adjust height based on node type
|
|
540
|
-
if (config?.type === 'header') {
|
|
541
|
-
totalHeight += 15; // Headers need more space
|
|
542
|
-
} else if (config?.type === 'textarea') {
|
|
543
|
-
totalHeight += 40; // Textareas are taller
|
|
544
|
-
} else if (config?.type === 'dataLink' || config?.type === 'dataLinkGroup') {
|
|
545
|
-
totalHeight += 20; // Data links often have more content
|
|
546
|
-
}
|
|
547
|
-
|
|
548
|
-
// Add height for value content if it exists
|
|
549
|
-
if (value && typeof value === 'string' && value.length > 50) {
|
|
550
|
-
totalHeight += Math.ceil(value.length / 50) * 15; // Multi-line content
|
|
551
|
-
}
|
|
552
|
-
|
|
553
|
-
// Add height for children recursively
|
|
554
|
-
if (config?.inputs) {
|
|
555
|
-
const childKeys = Object.keys(config.inputs)
|
|
556
|
-
.filter(childKey => {
|
|
557
|
-
const childConfig = config.inputs[childKey];
|
|
558
|
-
// Check showIf condition
|
|
559
|
-
if (childConfig?.showIf && !evaluateShowIfCondition(childConfig.showIf, data)) {
|
|
560
|
-
return false;
|
|
561
|
-
}
|
|
562
|
-
return true;
|
|
563
|
-
})
|
|
564
|
-
.sort((a, b) => {
|
|
565
|
-
const positionA = config.inputs[a]?.position || 0;
|
|
566
|
-
const positionB = config.inputs[b]?.position || 0;
|
|
567
|
-
return positionA - positionB;
|
|
568
|
-
});
|
|
569
|
-
|
|
570
|
-
childKeys.forEach(childKey => {
|
|
571
|
-
const childConfig = config.inputs[childKey];
|
|
572
|
-
const childValue = value?.[childKey] || data?.[childKey];
|
|
573
|
-
totalHeight += estimateTreeNodeHeight(childKey, childConfig, childValue, level + 1);
|
|
574
|
-
});
|
|
575
|
-
}
|
|
576
|
-
|
|
577
|
-
// Handle array/repeated content
|
|
578
|
-
if (Array.isArray(value)) {
|
|
579
|
-
value.forEach(itemValue => {
|
|
580
|
-
totalHeight += estimateTreeNodeHeight(key, config, itemValue, level);
|
|
581
|
-
});
|
|
582
|
-
}
|
|
583
|
-
|
|
584
|
-
return totalHeight;
|
|
585
|
-
};
|
|
586
|
-
|
|
587
|
-
// Helper function to split section based on height constraints (goes deep if needed)
|
|
588
|
-
const createHeightConstrainedSections = (sectionKey, section) => {
|
|
589
|
-
const MAX_SECTION_HEIGHT = PAGE_HEIGHT - HEADER_HEIGHT - FOOTER_HEIGHT - 150; // Conservative buffer
|
|
590
|
-
const subSections = [];
|
|
591
|
-
|
|
592
|
-
// Get all top-level items in the section with detailed analysis
|
|
593
|
-
const topLevelItems = Object.keys(section)
|
|
594
|
-
.filter(key => !(key === 'id' || key === 'label' || key === 'position' || key === 'subTitle'))
|
|
595
|
-
.map(key => ({
|
|
596
|
-
key,
|
|
597
|
-
config: section[key],
|
|
598
|
-
estimatedHeight: estimateTreeNodeHeight(key, section[key], data?.[key]),
|
|
599
|
-
canSplit: section[key]?.inputs && Object.keys(section[key].inputs).length > 1 // Can this item be further split?
|
|
600
|
-
}))
|
|
601
|
-
.sort((a, b) => (a.config?.position || 0) - (b.config?.position || 0));
|
|
602
|
-
|
|
603
|
-
let currentSubSection = {
|
|
604
|
-
...section,
|
|
605
|
-
};
|
|
606
|
-
|
|
607
|
-
// Remove all items from the base section structure
|
|
608
|
-
Object.keys(section).forEach(key => {
|
|
609
|
-
if (!(key === 'id' || key === 'label' || key === 'position' || key === 'subTitle')) {
|
|
610
|
-
delete currentSubSection[key];
|
|
611
|
-
}
|
|
612
|
-
});
|
|
613
|
-
|
|
614
|
-
let currentHeight = 80; // Base height for section header
|
|
615
|
-
let subSectionIndex = 0;
|
|
616
|
-
|
|
617
|
-
topLevelItems.forEach((item, index) => {
|
|
618
|
-
const { key, config, estimatedHeight, canSplit } = item;
|
|
619
|
-
|
|
620
|
-
// If a single item is too large and can be split, split it at the child level
|
|
621
|
-
if (estimatedHeight > MAX_SECTION_HEIGHT * 0.8 && canSplit) {
|
|
622
|
-
// Split this large item into smaller parts
|
|
623
|
-
const childSplits = splitLargeItem(key, config, data?.[key], MAX_SECTION_HEIGHT * 0.6);
|
|
624
|
-
|
|
625
|
-
childSplits.forEach((splitItem, splitIndex) => {
|
|
626
|
-
// Check if current subsection has room
|
|
627
|
-
if (currentHeight + splitItem.estimatedHeight > MAX_SECTION_HEIGHT && Object.keys(currentSubSection).length > 4) {
|
|
628
|
-
// Save current sub-section
|
|
629
|
-
subSections.push({
|
|
630
|
-
key: `${sectionKey}_part_${subSectionIndex}`,
|
|
631
|
-
section: { ...currentSubSection },
|
|
632
|
-
title: section.label
|
|
633
|
-
});
|
|
634
|
-
|
|
635
|
-
// Start new sub-section
|
|
636
|
-
currentSubSection = {
|
|
637
|
-
id: section.id,
|
|
638
|
-
label: section.label,
|
|
639
|
-
position: section.position + subSectionIndex + 1,
|
|
640
|
-
subTitle: section.subTitle
|
|
641
|
-
};
|
|
642
|
-
currentHeight = 80;
|
|
643
|
-
subSectionIndex++;
|
|
644
|
-
}
|
|
645
|
-
|
|
646
|
-
// Add split item to current sub-section
|
|
647
|
-
currentSubSection[splitItem.key] = splitItem.config;
|
|
648
|
-
currentHeight += splitItem.estimatedHeight;
|
|
649
|
-
});
|
|
650
|
-
} else {
|
|
651
|
-
// Regular processing for items that fit or can't be split
|
|
652
|
-
// Check if adding this item would exceed height limit
|
|
653
|
-
if (currentHeight + estimatedHeight > MAX_SECTION_HEIGHT && Object.keys(currentSubSection).length > 4) {
|
|
654
|
-
// Save current sub-section
|
|
655
|
-
subSections.push({
|
|
656
|
-
key: `${sectionKey}_part_${subSectionIndex}`,
|
|
657
|
-
section: { ...currentSubSection },
|
|
658
|
-
title: section.label
|
|
659
|
-
});
|
|
660
|
-
|
|
661
|
-
// Start new sub-section
|
|
662
|
-
currentSubSection = {
|
|
663
|
-
id: section.id,
|
|
664
|
-
label: section.label,
|
|
665
|
-
position: section.position + subSectionIndex + 1,
|
|
666
|
-
subTitle: section.subTitle
|
|
667
|
-
};
|
|
668
|
-
currentHeight = 80;
|
|
669
|
-
subSectionIndex++;
|
|
670
|
-
}
|
|
671
|
-
|
|
672
|
-
// Add item to current sub-section
|
|
673
|
-
currentSubSection[key] = config;
|
|
674
|
-
currentHeight += estimatedHeight;
|
|
675
|
-
}
|
|
676
|
-
});
|
|
677
|
-
|
|
678
|
-
// Add the final sub-section if it has content
|
|
679
|
-
if (Object.keys(currentSubSection).length > 4) {
|
|
680
|
-
subSections.push({
|
|
681
|
-
key: subSectionIndex === 0 ? sectionKey : `${sectionKey}_part_${subSectionIndex}`,
|
|
682
|
-
section: currentSubSection,
|
|
683
|
-
title: section.label
|
|
684
|
-
});
|
|
685
|
-
}
|
|
686
|
-
|
|
687
|
-
return subSections.length > 0 ? subSections : [{
|
|
688
|
-
key: sectionKey,
|
|
689
|
-
section: section,
|
|
690
|
-
title: section.label
|
|
691
|
-
}];
|
|
692
|
-
};
|
|
693
|
-
|
|
694
|
-
// Helper function to split large items at the child level
|
|
695
|
-
const splitLargeItem = (parentKey, parentConfig, parentValue, maxHeight) => {
|
|
696
|
-
if (!parentConfig?.inputs) {
|
|
697
|
-
return [{ key: parentKey, config: parentConfig, estimatedHeight: estimateTreeNodeHeight(parentKey, parentConfig, parentValue) }];
|
|
698
|
-
}
|
|
699
|
-
|
|
700
|
-
const childItems = Object.keys(parentConfig.inputs)
|
|
701
|
-
.filter(childKey => {
|
|
702
|
-
const childConfig = parentConfig.inputs[childKey];
|
|
703
|
-
return !childConfig?.showIf || evaluateShowIfCondition(childConfig.showIf, data);
|
|
704
|
-
})
|
|
705
|
-
.map(childKey => ({
|
|
706
|
-
key: childKey,
|
|
707
|
-
config: parentConfig.inputs[childKey],
|
|
708
|
-
estimatedHeight: estimateTreeNodeHeight(childKey, parentConfig.inputs[childKey], parentValue?.[childKey])
|
|
709
|
-
}))
|
|
710
|
-
.sort((a, b) => (a.config?.position || 0) - (b.config?.position || 0));
|
|
711
|
-
|
|
712
|
-
const splits = [];
|
|
713
|
-
let currentSplit = {
|
|
714
|
-
key: `${parentKey}_part_0`,
|
|
715
|
-
config: {
|
|
716
|
-
...parentConfig,
|
|
717
|
-
inputs: {}
|
|
718
|
-
},
|
|
719
|
-
estimatedHeight: 40 // Base height for parent structure
|
|
720
|
-
};
|
|
721
|
-
let splitIndex = 0;
|
|
722
|
-
|
|
723
|
-
childItems.forEach(child => {
|
|
724
|
-
if (currentSplit.estimatedHeight + child.estimatedHeight > maxHeight && Object.keys(currentSplit.config.inputs).length > 0) {
|
|
725
|
-
splits.push(currentSplit);
|
|
726
|
-
splitIndex++;
|
|
727
|
-
currentSplit = {
|
|
728
|
-
key: `${parentKey}_part_${splitIndex}`,
|
|
729
|
-
config: {
|
|
730
|
-
...parentConfig,
|
|
731
|
-
label: parentConfig.label,
|
|
732
|
-
inputs: {}
|
|
733
|
-
},
|
|
734
|
-
estimatedHeight: 40
|
|
735
|
-
};
|
|
736
|
-
}
|
|
737
|
-
|
|
738
|
-
currentSplit.config.inputs[child.key] = child.config;
|
|
739
|
-
currentSplit.estimatedHeight += child.estimatedHeight;
|
|
740
|
-
});
|
|
741
|
-
|
|
742
|
-
if (Object.keys(currentSplit.config.inputs).length > 0) {
|
|
743
|
-
splits.push(currentSplit);
|
|
744
|
-
}
|
|
745
|
-
|
|
746
|
-
return splits.length > 0 ? splits : [{ key: parentKey, config: parentConfig, estimatedHeight: estimateTreeNodeHeight(parentKey, parentConfig, parentValue) }];
|
|
747
|
-
};
|
|
748
|
-
|
|
749
528
|
const pdfConfig = useMemo(() => {
|
|
750
529
|
const sections = [];
|
|
751
530
|
|
|
@@ -756,32 +535,27 @@ const PdfForm = ({
|
|
|
756
535
|
return;
|
|
757
536
|
}
|
|
758
537
|
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
style: {
|
|
781
|
-
marginBottom: '20px',
|
|
782
|
-
padding: '0 20px'
|
|
783
|
-
}
|
|
784
|
-
});
|
|
538
|
+
sections.push({
|
|
539
|
+
render: () => (
|
|
540
|
+
<div key={sectionKey} className="pdf-form-section">
|
|
541
|
+
<PdfFormContent
|
|
542
|
+
form={{ [sectionKey]: section }}
|
|
543
|
+
data={data}
|
|
544
|
+
t={t}
|
|
545
|
+
user={user}
|
|
546
|
+
title={formName}
|
|
547
|
+
source={source}
|
|
548
|
+
version={version}
|
|
549
|
+
getApiBaseUrl={getApiBaseUrl}
|
|
550
|
+
getAppHeader={getAppHeader}
|
|
551
|
+
app={app}
|
|
552
|
+
/>
|
|
553
|
+
</div>
|
|
554
|
+
),
|
|
555
|
+
style: {
|
|
556
|
+
marginBottom: '20px',
|
|
557
|
+
padding: '0 20px'
|
|
558
|
+
}
|
|
785
559
|
});
|
|
786
560
|
});
|
|
787
561
|
|
|
@@ -144,7 +144,7 @@ export const filterInputs = (form, data, repeatValues) => {
|
|
|
144
144
|
}
|
|
145
145
|
|
|
146
146
|
export const getNkey = (namespace) => {
|
|
147
|
-
if (['location', 'scl', 'village', 'event', 'incidents', 'corrective-actions', 'testimonials', 'initiatives', 'victims', 'pictures', 'documents', 'lir', 'sp', 'im', 'sci', 'bpe', 'gm'].includes(namespace)) {
|
|
147
|
+
if (['location', 'scl', 'village', 'event', 'incidents', 'corrective-actions', 'testimonials', 'initiatives', 'victims', 'pictures', 'documents', 'lir', 'sp', 'im', 'sci', 'bpe', 'gm', 'project-readiness'].includes(namespace)) {
|
|
148
148
|
return 'scoping';
|
|
149
149
|
}
|
|
150
150
|
|