datastake-daf 0.6.147 → 0.6.148

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.
@@ -312,11 +312,6 @@ export const useGlobe = ({
312
312
  }
313
313
  });
314
314
  setMapMarkers(newMarkers);
315
-
316
- // Resize the Mapbox GL JS map to ensure proper rendering after data changes
317
- if (mapRef && mapRef.resize) {
318
- mapRef.resize();
319
- }
320
315
  }
321
316
  }, []);
322
317
 
@@ -465,50 +460,6 @@ export const useGlobe = ({
465
460
  const instance = createInstance();
466
461
  if (instance) {
467
462
  setMapRef(instance);
468
-
469
- // Add comprehensive resize detection for Mapbox GL JS responsiveness
470
- const handleResize = () => {
471
- if (instance && instance.resize) {
472
- // Add a small delay to ensure DOM has updated
473
- setTimeout(() => {
474
- instance.resize();
475
- }, 100);
476
- }
477
- };
478
-
479
- // Listen to window resize
480
- window.addEventListener('resize', handleResize);
481
-
482
- // Listen to container size changes using ResizeObserver
483
- const resizeObserver = new ResizeObserver(() => {
484
- handleResize();
485
- });
486
-
487
- if (container.current) {
488
- resizeObserver.observe(container.current);
489
- }
490
-
491
- // Store handlers for cleanup
492
- instance._resizeHandler = handleResize;
493
- instance._resizeObserver = resizeObserver;
494
-
495
- // Add IntersectionObserver to detect when globe becomes visible (handles sidenav scenarios)
496
- const intersectionObserver = new IntersectionObserver((entries) => {
497
- entries.forEach((entry) => {
498
- if (entry.isIntersecting && instance && instance.resize) {
499
- // Globe container is visible, force resize after a delay
500
- setTimeout(() => {
501
- instance.resize();
502
- }, 200);
503
- }
504
- });
505
- });
506
-
507
- if (container.current) {
508
- intersectionObserver.observe(container.current);
509
- }
510
-
511
- instance._intersectionObserver = intersectionObserver;
512
463
  } else {
513
464
  console.log('❌ [GLOBE HOOK] Failed to create map instance');
514
465
  }
@@ -597,34 +548,6 @@ export const useGlobe = ({
597
548
  }
598
549
  }, [data, mapRef, initialMarkerSetIsDone]);
599
550
 
600
- // Add effect to handle layout changes (like sidenav opening/closing)
601
- useEffect(() => {
602
- if (mapRef) {
603
- // Force resize when component becomes visible or layout changes
604
- const handleLayoutChange = () => {
605
- if (mapRef && mapRef.resize) {
606
- setTimeout(() => {
607
- mapRef.resize();
608
- }, 150);
609
- }
610
- };
611
-
612
- // Listen for visibility changes
613
- document.addEventListener('visibilitychange', handleLayoutChange);
614
-
615
- // Listen for focus events (when user returns to tab)
616
- window.addEventListener('focus', handleLayoutChange);
617
-
618
- // Store handlers for cleanup
619
- mapRef._layoutChangeHandler = handleLayoutChange;
620
-
621
- return () => {
622
- document.removeEventListener('visibilitychange', handleLayoutChange);
623
- window.removeEventListener('focus', handleLayoutChange);
624
- };
625
- }
626
- }, [mapRef]);
627
-
628
551
  useEffect(() => {
629
552
  if (activeMarker && mapRef) {
630
553
  const marker = mapMarkers.find((m) => m.data === activeMarker);
@@ -640,24 +563,6 @@ export const useGlobe = ({
640
563
  return () => {
641
564
  isMounted.current = false;
642
565
 
643
- // Cleanup window resize listener and ResizeObserver for Mapbox GL JS
644
- if (mapRef && mapRef._resizeHandler) {
645
- window.removeEventListener('resize', mapRef._resizeHandler);
646
- }
647
-
648
- if (mapRef && mapRef._resizeObserver) {
649
- mapRef._resizeObserver.disconnect();
650
- }
651
-
652
- if (mapRef && mapRef._layoutChangeHandler) {
653
- document.removeEventListener('visibilitychange', mapRef._layoutChangeHandler);
654
- window.removeEventListener('focus', mapRef._layoutChangeHandler);
655
- }
656
-
657
- if (mapRef && mapRef._intersectionObserver) {
658
- mapRef._intersectionObserver.disconnect();
659
- }
660
-
661
566
  // Defer unmounting to avoid race conditions
662
567
  const rootsToUnmount = [...roots.current];
663
568
  roots.current = [];
@@ -673,7 +578,7 @@ export const useGlobe = ({
673
578
  });
674
579
  });
675
580
  };
676
- }, [mapRef]);
581
+ }, []);
677
582
 
678
583
  // Map control handlers
679
584
  const zoomHandler = useCallback(() => mapRef?.zoomIn(), [mapRef]);
@@ -742,21 +647,11 @@ export const useGlobe = ({
742
647
  [zoomHandler, zoomOutHandler, recenterMap, moveUpHandler, moveDownHandler],
743
648
  );
744
649
 
745
- // Expose a manual resize method for external triggers
746
- const forceResize = useCallback(() => {
747
- if (mapRef && mapRef.resize) {
748
- setTimeout(() => {
749
- mapRef.resize();
750
- }, 100);
751
- }
752
- }, [mapRef]);
753
-
754
650
  return {
755
651
  container,
756
652
  activeMarker,
757
653
  mapOptionsButtonsConfig,
758
654
  emptyStateIsVisible,
759
655
  setEmptyStateIsVisible,
760
- forceResize,
761
656
  };
762
657
  };
@@ -130,7 +130,7 @@ function Globe({
130
130
  );
131
131
 
132
132
  // Use custom hook to configure globe functionality
133
- const { container, activeMarker, mapOptionsButtonsConfig, forceResize } = useGlobe({
133
+ const { container, activeMarker, mapOptionsButtonsConfig } = useGlobe({
134
134
  data: mappedData,
135
135
  user,
136
136
  polygon,
@@ -159,18 +159,6 @@ function Globe({
159
159
  onRender?.();
160
160
  }, [onRender]);
161
161
 
162
- // Force resize when component becomes visible (handles sidenav open/close scenarios)
163
- useEffect(() => {
164
- if (forceResize) {
165
- // Trigger resize after component mounts
166
- const timer = setTimeout(() => {
167
- forceResize();
168
- }, 300);
169
-
170
- return () => clearTimeout(timer);
171
- }
172
- }, [forceResize]);
173
-
174
162
  return (
175
163
  <ComponentWithFocus>
176
164
  <Style className={formatClassname([showSider && activeMarker && "with-sider"])}>
@@ -6,17 +6,6 @@ const Style = styled.div`
6
6
  position: relative;
7
7
  width: 100%;
8
8
  height: 472px;
9
- min-height: 300px;
10
-
11
- @media (max-width: 768px) {
12
- height: 350px;
13
- min-height: 250px;
14
- }
15
-
16
- @media (max-width: 480px) {
17
- height: 300px;
18
- min-height: 200px;
19
- }
20
9
 
21
10
  .filter-cont {
22
11
  position: absolute;
@@ -11,15 +11,16 @@ export default function KeyIndicatorsWidget({
11
11
  widgetClassName,
12
12
  withTooltip = false,
13
13
  title = "Key Indicators",
14
- noMinWidth = false,
14
+ noMinWidth = false,
15
15
  children,
16
+ noTitle = false,
16
17
  }) {
17
-
18
18
  const component = (
19
19
  <Widget
20
20
  loading={loading}
21
21
  className={formatClassname(["flex-1 with-border-header", widgetClassName])}
22
- title={t(title)}
22
+ title={noTitle ? undefined : t(title)}
23
+ noTitle={noTitle}
23
24
  >
24
25
  {children}
25
26
  <Style className={formatClassname(["flex", className])}>
@@ -0,0 +1,72 @@
1
+ import ProjectWidget from "./index.jsx";
2
+ import ThemeLayout from "../../../ThemeLayout/index.jsx";
3
+ import Widget from "../index.jsx";
4
+
5
+ import DashboardLayout from "../../DashboardLayout/index.jsx";
6
+ export default {
7
+ title: "Dashboard/Widgets/ProjectWidget",
8
+ component: ProjectWidget,
9
+ tags: ["autodocs"],
10
+ decorators: [
11
+ (Story) => (
12
+ <div style={{ margin: "3em" }}>
13
+ <ThemeLayout>
14
+ <Story />
15
+ </ThemeLayout>
16
+ </div>
17
+ ),
18
+ ],
19
+ };
20
+
21
+ export const Primary = {
22
+ name: "ProjectWidget",
23
+ args: {
24
+ image:
25
+ "https://images.squarespace-cdn.com/content/v1/606d4deb4db8c15ea53b3624/1618824875786-3V9HT8BLB1L5PEEJC6ZQ/124.jpg",
26
+ title: "ProjectWidgetTitle",
27
+ onLinkClick: () => {},
28
+ linkIcon: "Link",
29
+ sdgList: [
30
+ "noPoverty",
31
+ "zeroHunger",
32
+ "goodHealthWellbeing",
33
+ "qualityEducation",
34
+ "genderEquality",
35
+ "cleanWaterSanitation",
36
+ "affordableCleanEnergy",
37
+ "decentWorkEconomicGrowth",
38
+ "industryInnovationInfrastructure",
39
+ "reducedInequalities",
40
+ "sustainableCitiesCommunities",
41
+ "responsibleConsumptionProduction",
42
+ "climateAction",
43
+ "lifeBelowWater",
44
+ "lifeOnLand",
45
+ "peaceJusticeStrongInstitutions",
46
+ "partnershipsForGoals",
47
+ ],
48
+ items: [
49
+ { label: "Item 1", render: () => <span>Value 1</span> },
50
+ { label: "Item 2", render: () => <span>Value 2</span> },
51
+ { label: "Item 3", render: () => <span>Value 3</span> },
52
+ ],
53
+ },
54
+ render: (args) => {
55
+ return (
56
+ <DashboardLayout>
57
+ <Widget title="Project Catalogue" className="with-border-header">
58
+ <section>
59
+ <ProjectWidget {...args} />
60
+
61
+ <ProjectWidget
62
+ {...args}
63
+ sdgList={["noPoverty", "lifeBelowWater"]}
64
+ />
65
+
66
+ <ProjectWidget {...args} sdgList={[]} />
67
+ </section>
68
+ </Widget>
69
+ </DashboardLayout>
70
+ );
71
+ },
72
+ };
@@ -0,0 +1,84 @@
1
+ import { Card, Tooltip } from "antd";
2
+ import { ImageContainer, ProjectWidgetItems, SDGList, Label } from "./style.js";
3
+ import CustomIcon from "../../../Icon/CustomIcon.jsx";
4
+ import { SDG_IMAGES } from "../../../../../../constants/SDGs.js";
5
+
6
+ const { Meta } = Card;
7
+
8
+ export default function ProjectWidget({
9
+ title,
10
+ description,
11
+ onLinkClick,
12
+ image,
13
+ linkIcon = "Link",
14
+ sdgList,
15
+ items,
16
+ hideSDGList = false,
17
+ t = (x) => x,
18
+ }) {
19
+ return (
20
+ <Card
21
+ style={{
22
+ flex: 1,
23
+ }}
24
+ cover={
25
+ <ImageContainer>
26
+ {/* <img src={image} alt="ProjectWidget" /> */}
27
+ <div
28
+ className="image"
29
+ style={{
30
+ backgroundImage: `url(${image})`,
31
+ }}
32
+ />
33
+ {onLinkClick && (
34
+ <div className="icon-container" onClick={onLinkClick}>
35
+ <CustomIcon
36
+ name={linkIcon}
37
+ width={16}
38
+ height={16}
39
+ color="black"
40
+ />
41
+ </div>
42
+ )}
43
+ </ImageContainer>
44
+ }
45
+ >
46
+ <Meta title={title || undefined} description={description || undefined} />
47
+ <ProjectWidgetItems>
48
+ {items.map((item, index) => (
49
+ <li key={index} className="project-widget-item">
50
+ <Label>{item.label}</Label>
51
+ {item.render()}
52
+ </li>
53
+ ))}
54
+ </ProjectWidgetItems>
55
+
56
+ {!hideSDGList && (
57
+ <div
58
+ style={{
59
+ borderTop: "1px solid var(--base-gray-30)",
60
+ paddingTop: "10px",
61
+ }}
62
+ >
63
+ <Label>SDGs:</Label>
64
+ <SDGList>
65
+ {sdgList.map((sdg, index) => {
66
+ return (
67
+ <li key={index} className="project-widget-item">
68
+ <Tooltip title={t(`SDGS::${sdg}`)}>
69
+ <div
70
+ style={{
71
+ backgroundImage: `url(${SDG_IMAGES[sdg].img})`,
72
+ }}
73
+ className="sdg-item-image"
74
+ />
75
+ </Tooltip>
76
+ </li>
77
+ );
78
+ })}
79
+ </SDGList>
80
+ </div>
81
+ )}
82
+ </Card>
83
+ );
84
+ }
@@ -0,0 +1,74 @@
1
+ import styled from "styled-components";
2
+
3
+ export const ImageContainer = styled.div`
4
+ overflow: hidden;
5
+ position: relative;
6
+
7
+ .image {
8
+ width: 100%;
9
+ height: 151px;
10
+ background-size: cover;
11
+ background-position: center;
12
+ background-repeat: no-repeat;
13
+
14
+ border-bottom-left-radius: 3px;
15
+ border-bottom-right-radius: 3px;
16
+ }
17
+
18
+ .icon-container {
19
+ position: absolute;
20
+ top: 10px;
21
+ right: 10px;
22
+ background: white;
23
+ padding: 10px;
24
+ border-radius: 6px;
25
+ cursor: pointer;
26
+ }
27
+ `;
28
+
29
+ export const ProjectWidgetItems = styled.ul`
30
+ list-style: none;
31
+ padding: 0;
32
+ padding-top: 10px;
33
+ margin: 0;
34
+
35
+ .project-widget-item {
36
+ display: flex;
37
+ justify-content: space-between;
38
+ align-items: center;
39
+ border-bottom: 1px solid var(--base-gray-30);
40
+ padding: 10px 0;
41
+
42
+ &:last-of-type {
43
+ border-bottom: 0;
44
+ }
45
+ }
46
+ `;
47
+
48
+ export const SDGList = styled.ul`
49
+ list-style: none;
50
+ padding: 0;
51
+ display: flex;
52
+ flex-wrap: wrap;
53
+ gap: 4px;
54
+ margin: 0;
55
+
56
+ .sdg-item-image {
57
+ width: 24px;
58
+ height: 24px;
59
+ background-size: cover;
60
+ background-position: center;
61
+ background-repeat: no-repeat;
62
+ }
63
+ `;
64
+
65
+ export const Label = styled.span`
66
+ font-family: SF UI Display;
67
+ font-weight: 500;
68
+ font-style: Medium;
69
+ font-size: 14px;
70
+ leading-trim: NONE;
71
+ line-height: 26px;
72
+ letter-spacing: 0%;
73
+ color: #6c737f;
74
+ `;
@@ -5,6 +5,32 @@ export default {
5
5
  title: "Dashboard/Widgets/SDGWidget",
6
6
  component: SDGWidget,
7
7
  tags: ["autodocs"],
8
+ argsTypes: {
9
+ activeSdgGoals: {
10
+ control: {
11
+ type: "checkbox",
12
+ },
13
+ options: [
14
+ "noPoverty",
15
+ "zeroHunger",
16
+ "goodHealthWellbeing",
17
+ "qualityEducation",
18
+ "genderEquality",
19
+ "cleanWaterSanitation",
20
+ "affordableCleanEnergy",
21
+ "decentWorkEconomicGrowth",
22
+ "industryInnovationInfrastructure",
23
+ "reducedInequalities",
24
+ "sustainableCitiesCommunities",
25
+ "responsibleConsumptionProduction",
26
+ "climateAction",
27
+ "lifeBelowWater",
28
+ "lifeOnLand",
29
+ "peaceJusticeStrongInstitutions",
30
+ "partnershipsForGoals",
31
+ ],
32
+ },
33
+ },
8
34
  decorators: [
9
35
  (Story) => (
10
36
  <div style={{ margin: "3em" }}>
@@ -42,20 +68,10 @@ export const Primary = {
42
68
  },
43
69
  };
44
70
 
45
- // NO_POVERTY: "noPoverty",
46
- // ZERO_HUNGER: "zeroHunger",
47
- // GOOD_HEALTH_WELL_BEING: "goodHealthWellbeing",
48
- // QUALITY_EDUCATION: "qualityEducation",
49
- // GENDER_EQUALITY: "genderEquality",
50
- // CLEAN_WATER_SANITATION: "cleanWaterSanitation",
51
- // AFFORDABLE_CLEAN_ENERGY: "affordableCleanEnergy",
52
- // DECENT_WORK_ECONOMIC_GROWTH: "decentWorkEconomicGrowth",
53
- // INDUSTRY_INNOVATION_INFRASTRUCTURE: "industryInnovationInfrastructure",
54
- // REDUCED_INEQUALITIES: "reducedInequalities",
55
- // SUSTAINABLE_CITIES_COMMUNITIES: "sustainableCitiesCommunities",
56
- // RESPONSIBLE_CONSUMPTION_PRODUCTION: "responsibleConsumptionProduction",
57
- // CLIMATE_ACTION: "climateAction",
58
- // LIFE_BELOW_WATER: "lifeBelowWater",
59
- // LIFE_ON_LAND: "lifeOnLand",
60
- // PEACE_JUSTICE_STRONG_INSTITUTIONS: "peaceJusticeStrongInstitutions",
61
- // PARTNERSHIPS_FOR_GOALS: "partnershipsForGoals",
71
+ export const Empty = {
72
+ name: "Empty",
73
+ args: {
74
+ title: "Sustainable Development Goals",
75
+ activeSdgGoals: [],
76
+ },
77
+ };
@@ -1,29 +1,11 @@
1
- const KEYS = {
2
- NO_POVERTY: "noPoverty",
3
- ZERO_HUNGER: "zeroHunger",
4
- GOOD_HEALTH_WELL_BEING: "goodHealthWellbeing",
5
- QUALITY_EDUCATION: "qualityEducation",
6
- GENDER_EQUALITY: "genderEquality",
7
- CLEAN_WATER_SANITATION: "cleanWaterSanitation",
8
- AFFORDABLE_CLEAN_ENERGY: "affordableCleanEnergy",
9
- DECENT_WORK_ECONOMIC_GROWTH: "decentWorkEconomicGrowth",
10
- INDUSTRY_INNOVATION_INFRASTRUCTURE: "industryInnovationInfrastructure",
11
- REDUCED_INEQUALITIES: "reducedInequalities",
12
- SUSTAINABLE_CITIES_COMMUNITIES: "sustainableCitiesCommunities",
13
- RESPONSIBLE_CONSUMPTION_PRODUCTION: "responsibleConsumptionProduction",
14
- CLIMATE_ACTION: "climateAction",
15
- LIFE_BELOW_WATER: "lifeBelowWater",
16
- LIFE_ON_LAND: "lifeOnLand",
17
- PEACE_JUSTICE_STRONG_INSTITUTIONS: "peaceJusticeStrongInstitutions",
18
- PARTNERSHIPS_FOR_GOALS: "partnershipsForGoals",
19
- };
1
+ import { SDG_KEYS as KEYS } from "../../../../../../constants/SDGs";
20
2
 
21
3
  export const getGoalConfig = () => {
22
4
  return [
23
- { img: "/SDGs/SDGs.svg", key: KEYS.NO_POVERTY, disabled: "/SDGs/SDGs-17.svg" },
24
- { img: "/SDGs/SDGs-1.svg", key: KEYS.ZERO_HUNGER, disabled: "/SDGs/SDGs-18.svg" },
5
+ { img: "/SDGs/SDGs.svg", key: KEYS.NO_POVERTY, disabled: "./SDGs/SDGs-17.svg" },
6
+ { img: "/SDGs/SDGs-1.svg", key: KEYS.ZERO_HUNGER, disabled: "./SDGs/SDGs-18.svg" },
25
7
  {
26
- img:"/SDGs/SDGs-2.svg",
8
+ img: "/SDGs/SDGs-2.svg",
27
9
  key: KEYS.GOOD_HEALTH_WELL_BEING,
28
10
  disabled: "/SDGs/SDGs-19.svg",
29
11
  },
@@ -32,12 +32,12 @@ export default function SDGWidget({
32
32
 
33
33
  const SDGContainer = styled.div`
34
34
  display: grid;
35
- grid-template-columns: repeat(auto-fit, minmax(90px, 1fr));
35
+ grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
36
36
  gap: 8px;
37
37
 
38
38
  .sdg-item {
39
- height: 90px;
40
- width: 90px;
39
+ height: 100px;
40
+ width: 100px;
41
41
  border-radius: 8px;
42
42
  background-size: cover;
43
43
  background-position: center;