sag_components 2.0.0-beta52 → 2.0.0-beta53

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/index.esm.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import React$1, { useState, useRef, useEffect, useCallback, useMemo } from 'react';
2
2
  import styled, { keyframes, css } from 'styled-components';
3
- import { ResponsiveContainer, PieChart as PieChart$1, Pie, Cell, Tooltip as Tooltip$2, BarChart as BarChart$1, CartesianGrid, XAxis, YAxis, Bar, LabelList, ReferenceLine, Brush, LineChart, Line, AreaChart as AreaChart$1, Legend, Area } from 'recharts';
3
+ import { ResponsiveContainer, PieChart as PieChart$1, Pie, Cell, Tooltip as Tooltip$2, BarChart as BarChart$1, CartesianGrid, XAxis, YAxis, Bar, LabelList, ReferenceLine, Brush, LineChart, Line, AreaChart as AreaChart$1, Legend, Area, ScatterChart, ZAxis, Scatter, ComposedChart } from 'recharts';
4
4
  import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
5
5
  import { motion, AnimatePresence } from 'framer-motion';
6
6
 
@@ -1902,7 +1902,7 @@ const ControlsContainer$a = styled.div`
1902
1902
  box-sizing: border-box;
1903
1903
  }
1904
1904
  `;
1905
- const Controls$8 = styled.div`
1905
+ const Controls$9 = styled.div`
1906
1906
  display: flex;
1907
1907
  flex-direction: column;
1908
1908
  width: 100%;
@@ -2026,7 +2026,7 @@ const ControlsContainer$9 = styled.div`
2026
2026
  //border: 1px solid red;
2027
2027
  align-items: center;
2028
2028
  `;
2029
- const Controls$7 = styled.div`
2029
+ const Controls$8 = styled.div`
2030
2030
  position: relative;
2031
2031
  border-radius: 100px;
2032
2032
  width: ${props => props.width.toString().concat('', 'px')};
@@ -2282,7 +2282,7 @@ const Benchmark = props => {
2282
2282
  id: "Tooltip",
2283
2283
  content: getTooltipText(),
2284
2284
  direction: tooltipDirection
2285
- }, /*#__PURE__*/React$1.createElement(Controls$7, {
2285
+ }, /*#__PURE__*/React$1.createElement(Controls$8, {
2286
2286
  id: "ControlsBenchmark",
2287
2287
  height: height,
2288
2288
  width: width
@@ -2407,7 +2407,7 @@ const PieChart = props => {
2407
2407
  }, legendData.length === 0 || legendData.every(item => item.value === undefined || item.value === null) ? /*#__PURE__*/React$1.createElement(NoDataFoundMessage, {
2408
2408
  className: "NoDataFoundMessage",
2409
2409
  noDataText: noDataText
2410
- }) : /*#__PURE__*/React$1.createElement(Controls$8, {
2410
+ }) : /*#__PURE__*/React$1.createElement(Controls$9, {
2411
2411
  className: "Controls",
2412
2412
  height: height,
2413
2413
  width: width
@@ -25147,8 +25147,8 @@ function styleInject(css, ref) {
25147
25147
  }
25148
25148
  }
25149
25149
 
25150
- var css_248z = "@keyframes react-loading-skeleton {\n 100% {\n transform: translateX(100%);\n }\n}\n\n.react-loading-skeleton {\n --base-color: #ebebeb;\n --highlight-color: #f5f5f5;\n --animation-duration: 1.5s;\n --animation-direction: normal;\n --pseudo-element-display: block; /* Enable animation */\n\n background-color: var(--base-color);\n\n width: 100%;\n border-radius: 0.25rem;\n display: inline-flex;\n line-height: 1;\n\n position: relative;\n user-select: none;\n overflow: hidden;\n}\n\n.react-loading-skeleton::after {\n content: ' ';\n display: var(--pseudo-element-display);\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n height: 100%;\n background-repeat: no-repeat;\n background-image: var(\n --custom-highlight-background,\n linear-gradient(\n 90deg,\n var(--base-color) 0%,\n var(--highlight-color) 50%,\n var(--base-color) 100%\n )\n );\n transform: translateX(-100%);\n\n animation-name: react-loading-skeleton;\n animation-direction: var(--animation-direction);\n animation-duration: var(--animation-duration);\n animation-timing-function: ease-in-out;\n animation-iteration-count: infinite;\n}\n\n@media (prefers-reduced-motion) {\n .react-loading-skeleton {\n --pseudo-element-display: none; /* Disable animation */\n }\n}\n";
25151
- styleInject(css_248z);
25150
+ var css_248z$1 = "@keyframes react-loading-skeleton {\n 100% {\n transform: translateX(100%);\n }\n}\n\n.react-loading-skeleton {\n --base-color: #ebebeb;\n --highlight-color: #f5f5f5;\n --animation-duration: 1.5s;\n --animation-direction: normal;\n --pseudo-element-display: block; /* Enable animation */\n\n background-color: var(--base-color);\n\n width: 100%;\n border-radius: 0.25rem;\n display: inline-flex;\n line-height: 1;\n\n position: relative;\n user-select: none;\n overflow: hidden;\n}\n\n.react-loading-skeleton::after {\n content: ' ';\n display: var(--pseudo-element-display);\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n height: 100%;\n background-repeat: no-repeat;\n background-image: var(\n --custom-highlight-background,\n linear-gradient(\n 90deg,\n var(--base-color) 0%,\n var(--highlight-color) 50%,\n var(--base-color) 100%\n )\n );\n transform: translateX(-100%);\n\n animation-name: react-loading-skeleton;\n animation-direction: var(--animation-direction);\n animation-duration: var(--animation-duration);\n animation-timing-function: ease-in-out;\n animation-iteration-count: infinite;\n}\n\n@media (prefers-reduced-motion) {\n .react-loading-skeleton {\n --pseudo-element-display: none; /* Disable animation */\n }\n}\n";
25151
+ styleInject(css_248z$1);
25152
25152
 
25153
25153
  const OneColumnContainer = props => {
25154
25154
  const {
@@ -25345,7 +25345,7 @@ const ControlsContainer$7 = styled.div`
25345
25345
  box-sizing: border-box;
25346
25346
  }
25347
25347
  `;
25348
- const Controls$6 = styled.div`
25348
+ const Controls$7 = styled.div`
25349
25349
  display: flex;
25350
25350
  flex-direction: column;
25351
25351
  width: 100%;
@@ -25413,7 +25413,7 @@ const FormattedValue$3 = props => {
25413
25413
  height: height,
25414
25414
  width: width,
25415
25415
  textcolor: textcolor
25416
- }, /*#__PURE__*/React$1.createElement(Controls$6, {
25416
+ }, /*#__PURE__*/React$1.createElement(Controls$7, {
25417
25417
  className: "Controls",
25418
25418
  height: height,
25419
25419
  width: width
@@ -25473,7 +25473,7 @@ const ControlsContainer$6 = styled.div`
25473
25473
  height: ${props => props.height};
25474
25474
  min-width: 250px;
25475
25475
  `;
25476
- const Controls$5 = styled.div`
25476
+ const Controls$6 = styled.div`
25477
25477
  height: 100%;
25478
25478
  width: 100%;
25479
25479
  background: white;
@@ -25606,7 +25606,7 @@ const ControlsContainer$5 = styled.div`
25606
25606
  box-sizing: border-box;
25607
25607
  }
25608
25608
  `;
25609
- const Controls$4 = styled.div`
25609
+ const Controls$5 = styled.div`
25610
25610
  display: flex;
25611
25611
  gap: 20px;
25612
25612
  flex-direction: column;
@@ -25669,7 +25669,7 @@ const PerformanceAnalyticsLegend = props => {
25669
25669
  className: className,
25670
25670
  height: height,
25671
25671
  width: width
25672
- }, legendData?.length > 0 ? /*#__PURE__*/React$1.createElement(Controls$4, {
25672
+ }, legendData?.length > 0 ? /*#__PURE__*/React$1.createElement(Controls$5, {
25673
25673
  height: height,
25674
25674
  width: width
25675
25675
  }, /*#__PURE__*/React$1.createElement(LegendDataContainer, {
@@ -25837,7 +25837,7 @@ const BarChartsByWeeks = props => {
25837
25837
  height: height,
25838
25838
  width: width,
25839
25839
  ref: controlsContainerRef
25840
- }, /*#__PURE__*/React$1.createElement(Controls$5, {
25840
+ }, /*#__PURE__*/React$1.createElement(Controls$6, {
25841
25841
  height: getControlsHeight()
25842
25842
  }, showTitle && /*#__PURE__*/React$1.createElement(TitleAndValueContainer$2, null, /*#__PURE__*/React$1.createElement(Title$b, null, title), /*#__PURE__*/React$1.createElement(FormattedValue$3, {
25843
25843
  title: headerValueTopTitle,
@@ -26043,7 +26043,7 @@ const ControlsContainer$4 = styled.div`
26043
26043
  box-sizing: border-box;
26044
26044
  }
26045
26045
  `;
26046
- const Controls$3 = styled.div`
26046
+ const Controls$4 = styled.div`
26047
26047
  display: flex;
26048
26048
  flex-direction: column;
26049
26049
  width: 100%;
@@ -26269,7 +26269,7 @@ const TotalDoughnutChart = props => {
26269
26269
  }, legendData.length === 0 || legendData.every(item => item.value === undefined || item.value === null) ? /*#__PURE__*/React$1.createElement(NoDataFoundMessage, {
26270
26270
  className: "NoDataFoundMessage",
26271
26271
  noDataText: noDataText
26272
- }) : /*#__PURE__*/React$1.createElement(Controls$3, {
26272
+ }) : /*#__PURE__*/React$1.createElement(Controls$4, {
26273
26273
  className: "Controls",
26274
26274
  height: height,
26275
26275
  width: width
@@ -28521,7 +28521,7 @@ const ControlsContainer$1 = styled.div`
28521
28521
  height: ${props => props.height};
28522
28522
  min-width: 250px;
28523
28523
  `;
28524
- const Controls$2 = styled.div`
28524
+ const Controls$3 = styled.div`
28525
28525
  height: 100%;
28526
28526
  width: 100%;
28527
28527
  background: white;
@@ -28706,7 +28706,7 @@ const BarChart = props => {
28706
28706
  height: height,
28707
28707
  width: width,
28708
28708
  ref: controlsContainerRef
28709
- }, /*#__PURE__*/React$1.createElement(Controls$2, null, /*#__PURE__*/React$1.createElement(Title$3, null, title), /*#__PURE__*/React$1.createElement(ResponsiveContainer, {
28709
+ }, /*#__PURE__*/React$1.createElement(Controls$3, null, /*#__PURE__*/React$1.createElement(Title$3, null, title), /*#__PURE__*/React$1.createElement(ResponsiveContainer, {
28710
28710
  width: "100%",
28711
28711
  height: 400
28712
28712
  }, /*#__PURE__*/React$1.createElement(BarChart$1, {
@@ -28870,7 +28870,7 @@ const LegendContainer = styled.div`
28870
28870
  width: ${props => `${props.width}px`};
28871
28871
  bottom: 20px;
28872
28872
  `;
28873
- const Controls$1 = styled.div`
28873
+ const Controls$2 = styled.div`
28874
28874
  /* height: calc(100% - 30px); */
28875
28875
  height: 100%;
28876
28876
  display: flex;
@@ -29134,7 +29134,7 @@ const DoubleBarSingleLine = props => {
29134
29134
  hasScroll: hasScroll
29135
29135
  }, data.length === 0 ? /*#__PURE__*/React$1.createElement(NoDataFoundMessage, {
29136
29136
  noDataText: noDataText
29137
- }) : /*#__PURE__*/React$1.createElement(Controls$1, {
29137
+ }) : /*#__PURE__*/React$1.createElement(Controls$2, {
29138
29138
  className: "Controls"
29139
29139
  }, title && title.trim() !== '' && /*#__PURE__*/React$1.createElement(Title$2, null, title), /*#__PURE__*/React$1.createElement(ChartsWrapper, {
29140
29140
  width: hasScroll ? `${data.length * 178}px` : 'auto'
@@ -29224,7 +29224,7 @@ const AreaChartContaner = styled.div`
29224
29224
  height: ${props => props.height};
29225
29225
  min-width: 1100px;
29226
29226
  `;
29227
- const HeaderContainer$1 = styled.div`
29227
+ const HeaderContainer$2 = styled.div`
29228
29228
  display: flex;
29229
29229
  justify-content: space-between;
29230
29230
  padding: 10px 40px;
@@ -29283,7 +29283,7 @@ const ControlsContainer = styled.div`
29283
29283
  font-family: Poppins;
29284
29284
  margin: 0;
29285
29285
  `;
29286
- const Controls = styled.div`
29286
+ const Controls$1 = styled.div`
29287
29287
  display: flex;
29288
29288
  align-items: center;
29289
29289
  `;
@@ -29329,7 +29329,7 @@ const CheckBox = props => {
29329
29329
  fontSize: fontSize,
29330
29330
  width: width,
29331
29331
  height: height
29332
- }, /*#__PURE__*/React$1.createElement(Controls, {
29332
+ }, /*#__PURE__*/React$1.createElement(Controls$1, {
29333
29333
  className: "Controls",
29334
29334
  "data-testid": "controls"
29335
29335
  }, checkedState ? /*#__PURE__*/React$1.createElement(CheckBoxIconContainer, {
@@ -29561,7 +29561,7 @@ const AreaChart = props => {
29561
29561
  noDataText: "",
29562
29562
  width: width,
29563
29563
  height: height
29564
- }) : /*#__PURE__*/React$1.createElement(React$1.Fragment, null, /*#__PURE__*/React$1.createElement(HeaderContainer$1, {
29564
+ }) : /*#__PURE__*/React$1.createElement(React$1.Fragment, null, /*#__PURE__*/React$1.createElement(HeaderContainer$2, {
29565
29565
  "data-testid": "header-container"
29566
29566
  }, /*#__PURE__*/React$1.createElement(Title$1, {
29567
29567
  "data-testid": "title"
@@ -30055,7 +30055,7 @@ const BreakdownPanelContainer = styled.div`
30055
30055
  height: ${props => props.height};
30056
30056
  min-width: 1100px;
30057
30057
  `;
30058
- const HeaderContainer = styled.div`
30058
+ const HeaderContainer$1 = styled.div`
30059
30059
  display: flex;
30060
30060
  justify-content: space-between;
30061
30061
  align-items: center;
@@ -30128,7 +30128,7 @@ const BreakdownPanel = props => {
30128
30128
  noDataText: "",
30129
30129
  width: width,
30130
30130
  height: height
30131
- }) : /*#__PURE__*/React$1.createElement(React$1.Fragment, null, /*#__PURE__*/React$1.createElement(HeaderContainer, {
30131
+ }) : /*#__PURE__*/React$1.createElement(React$1.Fragment, null, /*#__PURE__*/React$1.createElement(HeaderContainer$1, {
30132
30132
  "data-testid": "header-container"
30133
30133
  }, /*#__PURE__*/React$1.createElement(Title, {
30134
30134
  "data-testid": "title"
@@ -30154,264 +30154,2070 @@ const BreakdownPanel = props => {
30154
30154
  }))))));
30155
30155
  };
30156
30156
 
30157
- const BatteryChartContainer = styled.div`
30158
- position: relative;
30159
- font-family: "Poppins", sans-serif;
30160
- display: grid;
30161
- grid-template-columns: auto auto;
30162
- grid-template-rows: auto 1fr auto;
30163
- color: #212121;
30164
- background-color: ${props => props.backgroundColor || 'transparent'};
30165
- padding: ${props => props.containerPadding || '25px 30px 0'};
30166
- width: ${props => props.width};
30167
- height: ${props => props.height};
30168
- `;
30169
- const PanelSide = styled.div`
30170
- display: flex;
30171
- flex-direction: column;
30172
- justify-content: space-between;
30157
+ const BubbleChartContainer = styled.div`
30158
+ position: relative;
30159
+ width: ${props => props.width};
30160
+ height: ${props => props.height};
30161
+ display: flex;
30162
+ flex-direction: column;
30163
+ background-color: ${props => props.backgroundColor};
30164
+ border-radius: 8px;
30165
+ padding: 10px;
30166
+ box-sizing: border-box;
30167
+ font-family: "Poppins", sans-serif;
30168
+ min-width: 800px;
30169
+
30170
+ /* Enable proper overflow handling */
30171
+ overflow: hidden;
30173
30172
  `;
30174
- const ProgressDetails = styled.div`
30175
- display: flex;
30176
- flex-direction: column;
30177
- flex-grow: 1;
30173
+ styled.div`
30174
+ position: absolute;
30175
+ font-family: "Poppins", sans-serif;
30176
+ font-size: 12px;
30177
+ font-weight: 500;
30178
+ color: #555;
30179
+ text-align: center;
30180
+
30181
+ &.top-left {
30182
+ top: 20px;
30183
+ left: 20px;
30184
+ }
30185
+
30186
+ &.top-right {
30187
+ top: 20px;
30188
+ right: 20px;
30189
+ }
30190
+
30191
+ &.bottom-left {
30192
+ bottom: 20px;
30193
+ left: 20px;
30194
+ }
30195
+
30196
+ &.bottom-right {
30197
+ bottom: 20px;
30198
+ right: 20px;
30199
+ }
30178
30200
  `;
30179
- const HeadingText = styled.p`
30180
- grid-column: 1 / span 2;
30181
- color: #212121;
30182
- font-size: 18px;
30183
- font-weight: 400;
30184
- padding-left: 10px;
30201
+ const CustomTooltipContainer = styled.div`
30202
+ background-color: white;
30203
+ border-radius: 6px;
30204
+ z-index: 1000;
30205
+ padding: 10px 14px;
30206
+ box-shadow: 0 2px 10px rgba(0, 0, 0, 0.15);
30207
+ max-width: 220px;
30208
+ font-family: "Poppins", sans-serif;
30209
+
30210
+ h4 {
30185
30211
  margin: 0 0 8px;
30186
- `;
30187
- const HeadingPercentage = styled.p`
30188
- color: #212121;
30189
- font-size: 32px;
30190
- font-weight: 500;
30191
- padding-left: 10px;
30192
- margin: 0;
30193
- `;
30194
- const ChartSide = styled.div`
30195
- text-align: center;
30196
- `;
30197
- const ChartWrapper = styled.div`
30198
- position: relative;
30199
- width: 110px;
30200
- `;
30201
- const GoalValue = styled.div`
30202
- text-align: center;
30203
- font-size: 18px;
30204
- color: #8B8989;
30205
- line-height: 1;
30206
- &.overload {
30207
- position: absolute;
30208
- top: ${props => props.goalValuePosition}px;
30209
- left: 0;
30210
- right: 0;
30211
- z-index: 2;
30212
- margin: 0 auto;
30213
- width: 40%;
30214
- display: inline;
30215
- padding: 0px 8px;
30216
- border: 2px solid #F2F2F2;
30217
- border-bottom: none;
30218
- border-radius: 6px 6px 0px 0px;
30219
- background-color: white;
30212
+ font-size: 14px;
30213
+ font-weight: 600;
30214
+ }
30215
+
30216
+ p {
30217
+ margin: 3px 0;
30218
+ font-size: 12px;
30219
+ color: #555;
30220
+ }
30221
+
30222
+ @media (max-width: 768px) {
30223
+ padding: 8px 12px;
30224
+ max-width: 180px;
30225
+
30226
+ h4 {
30227
+ font-size: 12px;
30228
+ margin: 0 0 6px;
30220
30229
  }
30230
+
30231
+ p {
30232
+ font-size: 10px;
30233
+ }
30234
+ }
30221
30235
  `;
30222
- const Indicator = styled.div`
30223
- position: absolute;
30224
- top: ${props => props.top}px;
30225
- left: 0;
30226
- transform: translateY(50%);
30227
- width: calc(100% + 60px);
30228
- display: flex;
30229
- gap: 6px;
30230
- justify-content: center;
30231
- padding-left: 4px;
30232
- align-items: center;
30233
- z-index: 1;
30234
- `;
30235
- const IndicatorLine = styled.div`
30236
- width: 100%;
30237
- height: 0;
30238
- border-top: 4px dashed ${props => props.color};
30236
+ const TooltipMetric = styled.div`
30237
+ display: flex;
30238
+ justify-content: space-between;
30239
+ margin: 5px 0;
30240
+ font-size: 12px;
30241
+
30242
+ span:last-child {
30243
+ font-weight: 500;
30244
+ }
30245
+
30246
+ @media (max-width: 768px) {
30247
+ font-size: 10px;
30248
+ margin: 4px 0;
30249
+ }
30239
30250
  `;
30240
- const IndicatorText = styled.span`
30241
- font-size: 18px;
30242
- font-weight: 400;
30243
- color: ${props => props.color};
30251
+ styled.div`
30252
+ position: relative;
30253
+ width: 100%;
30254
+ height: 100%;
30244
30255
  `;
30245
- const ProgressLegend = styled.div`
30246
- margin-top: 12px;
30256
+ const HeaderContainer = styled.div`
30257
+ display: flex;
30258
+ justify-content: space-between;
30259
+ align-items: baseline;
30260
+ padding: 0;
30261
+ margin-bottom: 10px;
30247
30262
  `;
30248
- const LegendItem = styled.div`
30249
- display: flex;
30250
- gap: 4px;
30251
- align-items: center;
30252
- margin-bottom: 12px;
30263
+ const ChartTitle = styled.h2`
30264
+ font-family: "Poppins", sans-serif;
30265
+ font-size: 18px;
30266
+ font-weight: 400;
30267
+ margin: 0;
30268
+ color: #212121;
30253
30269
  `;
30254
- const LegendText = styled.span`
30255
- color: #8B8989;
30256
- font-size: 14px;
30270
+ const ChartSubtitle = styled.p`
30271
+ font-family: "Poppins", sans-serif;
30272
+ font-size: 14px;
30273
+ font-weight: 500;
30274
+ color: #484A4C;
30275
+ margin: 0;
30257
30276
  `;
30258
- const LegendCube = styled.div`
30259
- border-radius: 3px;
30260
- width: 17px;
30261
- height: 17px;
30262
- background-color: ${props => props.color};
30277
+ const ChartContainer = styled.div`
30278
+ position: relative;
30279
+ width: 100%;
30280
+ height: 90%; /* Reduced from 93% to make room for the zoom controls */
30281
+ flex: 1;
30263
30282
  `;
30264
- const ProgressDescription = styled.div`
30265
- color: #8B8989;
30266
- font-size: 12px;
30267
- font-weight: 400;
30268
- margin-top: auto;
30283
+
30284
+ /* Updated Zoom Controls Styles to match the new design */
30285
+ const ZoomControlsContainer = styled.div`
30286
+ display: flex;
30287
+ align-items: center;
30288
+ align-self: flex-start;
30289
+ margin-top: 10px;
30290
+ background: linear-gradient(to right, rgba(255, 255, 255, 0.98), rgba(245, 245, 245, 0.92));
30291
+ border-radius: 8px;
30292
+ padding: 6px 6px 6px 12px;
30293
+ box-shadow: 0px 0px 20px rgba(0, 0, 0, 0.1);
30294
+ z-index: 10;
30295
+ font-family: "Poppins", sans-serif;
30296
+ backdrop-filter: blur(8px);
30297
+ transition: background-color 0.3s ease, box-shadow 0.3s ease;
30269
30298
  `;
30270
- const ProgressItem = styled.p`
30271
- margin: 0 0 6px;
30299
+ const ZoomPercentage = styled.span`
30300
+ font-size: 18px;
30301
+ font-weight: 500;
30302
+ color: #726F6F;
30303
+ margin: 0;
30304
+ min-width: 50px;
30272
30305
  `;
30273
- const StarText = styled.span`
30274
- width: 100%;
30275
- color: #B1B1B1;
30276
- font-size: 9px;
30277
- grid-column: 1 / span 2;
30278
- padding-top: 10px;
30306
+ const ZoomButton = styled.button`
30307
+ width: 26px;
30308
+ height: 20px;
30309
+ border: none;
30310
+ background: none;
30311
+ font-size: 24px;
30312
+ font-weight: 500;
30313
+ color: #726F6F;
30314
+ cursor: pointer;
30315
+ display: flex;
30316
+ align-items: center;
30317
+ justify-content: center;
30318
+ padding: 0;
30319
+ margin: 0 ;
30320
+
30321
+ &:hover {
30322
+ color: #333;
30323
+ }
30324
+
30325
+ &:focus {
30326
+ outline: none;
30327
+ }
30279
30328
  `;
30329
+ const ZoomResetButton = styled.button`
30330
+ font-family: "Poppins", sans-serif;
30331
+ font-size: 14px;
30332
+ font-weight: 400;
30333
+ height: 32px;
30334
+ padding: 0 12px;
30335
+ margin-left: 5px;
30336
+ border-radius: 8px;
30337
+ background-color: white;
30338
+ border: 1px solid #ddd;
30339
+ cursor: pointer;
30340
+ color: #212121;
30341
+ background: linear-gradient(to right, rgba(255, 255, 255, 0.98), rgba(245, 245, 245, 0.92));
30342
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
30343
+ transition: all 0.2s ease-in-out;
30280
30344
 
30281
- const BatteryChart = props => {
30345
+ &:hover {
30346
+ background: linear-gradient(to right, #f0f0f0, #eaeaea);
30347
+ border-color: #ccc;
30348
+ box-shadow: 0 2px 6px rgba(0, 0, 0, 0.08);
30349
+ }
30350
+
30351
+ &:active {
30352
+ background: #e0e0e0;
30353
+ transform: scale(0.98);
30354
+ box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15);
30355
+ }
30356
+
30357
+ &:focus {
30358
+ outline: none;
30359
+ box-shadow: 0 0 0 3px rgba(100, 150, 250, 0.4);
30360
+ }
30361
+ `;
30362
+
30363
+ // Enhanced color palette with bubble-like transparency and gradients
30364
+ const defaultColorPalette = [
30365
+ // Top Left - Yellow Bubbles
30366
+ 'rgba(255, 249, 220, 0.7)',
30367
+ // Inner highlight
30368
+ 'rgba(255, 235, 165, 0.4)',
30369
+ // Outer edge
30370
+
30371
+ // Top Right - Green Bubbles
30372
+ 'rgba(235, 255, 240, 0.7)',
30373
+ // Inner highlight
30374
+ 'rgba(190, 235, 200, 0.4)',
30375
+ // Outer edge
30376
+
30377
+ // Bottom Left - Pink Bubbles
30378
+ 'rgba(255, 235, 240, 0.7)',
30379
+ // Inner highlight
30380
+ 'rgba(255, 190, 200, 0.4)',
30381
+ // Outer edge
30382
+
30383
+ // Bottom Right - Cream/Yellow Bubbles
30384
+ 'rgba(255, 250, 230, 0.7)',
30385
+ // Inner highlight
30386
+ 'rgba(255, 235, 180, 0.4)' // Outer edge
30387
+ ];
30388
+
30389
+ // Main component
30390
+ const BubbleChart = _ref => {
30391
+ let {
30392
+ data = [],
30393
+ title = 'Event Performance Based on Incrementality',
30394
+ subtitle = '* Total cost is reflected by the circle size',
30395
+ leftHeader = 'Low INC Sales ROI',
30396
+ rightHeader = 'High INC Sales ROI',
30397
+ topHeader = 'High INC Sales',
30398
+ bottomHeader = 'Low INC Sales',
30399
+ colorPalette = defaultColorPalette,
30400
+ height = '600px',
30401
+ width = '100%',
30402
+ backgroundColor = 'white',
30403
+ showAxis = false
30404
+ } = _ref;
30405
+ // Calculate the medians and domain for raw X, Y, and Z values
30282
30406
  const {
30283
- className,
30284
- containerPadding,
30285
- width,
30286
- height,
30287
- title,
30288
- color,
30289
- backgroundColor,
30290
- indicatorColor,
30291
- noCommitment,
30292
- goalAmount,
30293
- currentAmount,
30294
- ask,
30295
- target,
30296
- totalSegmentsLines,
30297
- starText
30298
- } = props;
30299
- const [top, setTop] = useState(0);
30300
- const [goalValuePosition, setGoalValuePosition] = useState(0);
30301
- const [containerHeight, setContainerHeight] = useState(0); // State to store container height
30302
- const containerRef = useRef(null); // Ref for BatteryChartContainer
30407
+ xMedian,
30408
+ yMedian,
30409
+ xDomain,
30410
+ yDomain,
30411
+ zRange
30412
+ } = useMemo(() => {
30413
+ if (!data || !Array.isArray(data) || data.length === 0) {
30414
+ return {
30415
+ xMedian: 0,
30416
+ yMedian: 0,
30417
+ xDomain: [0, 100],
30418
+ yDomain: [0, 100],
30419
+ zRange: [0, 3600]
30420
+ };
30421
+ }
30303
30422
 
30304
- // Calculate the percentage and completed segments
30305
- const percentage = Math.round(currentAmount / goalAmount * 100);
30306
- const completedSegments = Math.min(Math.floor(currentAmount / goalAmount * totalSegmentsLines), totalSegmentsLines);
30423
+ // Extract x, y, and size values
30424
+ const xValues = data.map(item => item.x).filter(x => x !== undefined && x !== null);
30425
+ const yValues = data.map(item => item.y).filter(y => y !== undefined && y !== null);
30426
+ const sizeValues = data.map(item => item.size).filter(size => size !== undefined && size !== null);
30427
+
30428
+ // Calculate min and max values
30429
+ const minX = Math.min(...xValues);
30430
+ const maxX = Math.max(...xValues);
30431
+ const minY = Math.min(...yValues);
30432
+ const maxY = Math.max(...yValues);
30433
+ Math.min(...sizeValues);
30434
+ const maxSize = Math.max(...sizeValues);
30435
+
30436
+ // Calculate medians
30437
+ const calculateMedian = arr => {
30438
+ if (!arr || arr.length === 0) return 0;
30439
+ const sorted = [...arr].sort((a, b) => a - b);
30440
+ const middle = Math.floor(sorted.length / 2);
30441
+ if (sorted.length % 2 === 1) {
30442
+ return sorted[middle];
30443
+ }
30444
+ return (sorted[middle - 1] + sorted[middle]) / 2;
30445
+ };
30446
+ const medianX = calculateMedian(xValues);
30447
+ const medianY = calculateMedian(yValues);
30307
30448
 
30308
- // Dynamically create the data for the bar chart
30309
- let barsChips = Array.from({
30310
- length: totalSegmentsLines
30311
- }).map((_, index) => ({
30312
- name: `segment-${index}`,
30313
- value: 100,
30314
- isCompleted: index >= totalSegmentsLines - completedSegments,
30315
- // Fill from bottom up
30316
- color: index >= totalSegmentsLines - completedSegments ? color : "#e5e7eb" // Completed or remaining color
30317
- }));
30449
+ // Calculate domains based on median-centered logic
30450
+ const calculateDomainBasedOnMedian = (min, max, median) => {
30451
+ const distance = Math.max(Math.abs(max - median), Math.abs(min - median));
30452
+ return [median - distance, median + distance];
30453
+ };
30454
+ const xDom = calculateDomainBasedOnMedian(minX, maxX, medianX);
30455
+ const yDom = calculateDomainBasedOnMedian(minY, maxY, medianY);
30318
30456
 
30319
- // Add 4 extra chips if currentAmount > goalAmount
30320
- if (currentAmount > goalAmount && !noCommitment) {
30321
- const extraSegments = 4;
30322
- const extraData = Array.from({
30323
- length: extraSegments
30324
- }).map((_, index) => ({
30325
- name: `extra-segment-${index}`,
30326
- value: 100,
30327
- isCompleted: true,
30328
- color: "#E8F5EB"
30329
- }));
30457
+ // Determine z-axis range scaled appropriately
30458
+ const zRng = [0, maxSize * 7];
30459
+ return {
30460
+ xMedian: medianX,
30461
+ yMedian: medianY,
30462
+ xDomain: xDom,
30463
+ yDomain: yDom,
30464
+ zRange: zRng
30465
+ };
30466
+ }, [data]);
30330
30467
 
30331
- // Prepend the extra segments to the barsChips array
30332
- barsChips = [...extraData, ...barsChips];
30333
- }
30468
+ // Init viewDomain with calculated domain values
30469
+ const fullDomain = useMemo(() => ({
30470
+ x: xDomain,
30471
+ y: yDomain
30472
+ }), [xDomain, yDomain]);
30334
30473
 
30335
- // Calculate the top position for the indicator and goal value
30474
+ // State for current view domain
30475
+ const [viewDomain, setViewDomain] = useState(fullDomain);
30476
+ const [zoomLevel, setZoomLevel] = useState(100);
30477
+
30478
+ // Drag state
30479
+ const [isDragging, setIsDragging] = useState(false);
30480
+ const [dragStart, setDragStart] = useState({
30481
+ x: 0,
30482
+ y: 0
30483
+ });
30484
+ const [domainStart, setDomainStart] = useState(fullDomain);
30485
+
30486
+ // Refs for the chart container
30487
+ const containerRef = useRef(null);
30488
+ const scatterChartRef = useRef(null);
30489
+
30490
+ // Set up initial domain
30336
30491
  useEffect(() => {
30337
- const barHeight = containerHeight / (totalSegmentsLines + (currentAmount > goalAmount ? 4 : 0)); // Adjust for extra chips
30338
- let newTop;
30339
- let newGoalValuePosition;
30340
- if (currentAmount > goalAmount) {
30341
- // Position the indicator slightly below the top chip
30342
- newTop = barHeight * 1.5; // Slightly below the 4th chip
30343
- // Position the goal value just above the active chips
30492
+ // Set initial viewDomain from fullDomain
30493
+ setViewDomain(fullDomain);
30494
+ }, [fullDomain]);
30495
+
30496
+ // Function to get gradient fill based on quadrant
30497
+ const getFill = useCallback((x, y) => {
30498
+ if (x < xMedian && y > yMedian) return 'url(#topLeftGradient)'; // Top Left
30499
+ if (x >= xMedian && y > yMedian) return 'url(#topRightGradient)'; // Top Right
30500
+ if (x < xMedian && y <= yMedian) return 'url(#bottomLeftGradient)'; // Bottom Left
30501
+ if (x >= xMedian && y <= yMedian) return 'url(#bottomRightGradient)'; // Bottom Right
30502
+ return 'gray'; // fallback
30503
+ }, [xMedian, yMedian]);
30504
+
30505
+ // CustomTooltip component inside BubbleChart
30506
+ const CustomTooltip = useCallback(_ref2 => {
30507
+ let {
30508
+ active,
30509
+ payload
30510
+ } = _ref2;
30511
+ if (active && payload && payload.length && payload[0].payload.tooltip) {
30512
+ const data = payload[0].payload;
30513
+ return /*#__PURE__*/React$1.createElement(CustomTooltipContainer, {
30514
+ "data-testid": "tooltip-container"
30515
+ }, /*#__PURE__*/React$1.createElement("h4", {
30516
+ "data-testid": "tooltip-title"
30517
+ }, data.tooltip.title), data.tooltip.description && /*#__PURE__*/React$1.createElement(TooltipMetric, {
30518
+ "data-testid": "tooltip-description"
30519
+ }, /*#__PURE__*/React$1.createElement("span", null, data.tooltip.description)), /*#__PURE__*/React$1.createElement(TooltipMetric, {
30520
+ "data-testid": "tooltip-cost"
30521
+ }, /*#__PURE__*/React$1.createElement("span", null, "Total cost:"), /*#__PURE__*/React$1.createElement("span", null, formatCurrency(data.tooltip.cost))), /*#__PURE__*/React$1.createElement(TooltipMetric, {
30522
+ "data-testid": "tooltip-sales"
30523
+ }, /*#__PURE__*/React$1.createElement("span", null, "INC Sales:"), /*#__PURE__*/React$1.createElement("span", null, formatCurrency(data.tooltip.incSales))), /*#__PURE__*/React$1.createElement(TooltipMetric, {
30524
+ "data-testid": "tooltip-roi"
30525
+ }, /*#__PURE__*/React$1.createElement("span", null, "INC Sales ROI:"), /*#__PURE__*/React$1.createElement("span", null, formatROI(data.tooltip.roi))), /*#__PURE__*/React$1.createElement(TooltipMetric, {
30526
+ "data-testid": "tooltip-units"
30527
+ }, /*#__PURE__*/React$1.createElement("span", null, "INC Units:"), /*#__PURE__*/React$1.createElement("span", null, formatUnits(data.tooltip.units))));
30528
+ }
30529
+ return null;
30530
+ }, []);
30344
30531
 
30345
- newGoalValuePosition = barHeight * 2.3;
30346
- // newGoalValuePosition = (totalSegmentsLines - completedSegments + 4) * barHeight - barHeight / 2;
30532
+ // Process all chart data - use original data values
30533
+ const allChartData = useMemo(() => {
30534
+ return data.map((item, index) => {
30535
+ if (item.x === undefined || item.y === undefined || item.size === undefined) {
30536
+ console.warn('Skipping data item with missing values:', item);
30537
+ return null;
30538
+ }
30539
+ const tooltipInfo = {
30540
+ title: item.name || 'Marketing event',
30541
+ description: item.description || '',
30542
+ cost: item.size || 0,
30543
+ units: item.units || 0,
30544
+ roi: item.x || 0,
30545
+ incSales: item.y || 0,
30546
+ ...(item.tooltip || {})
30547
+ };
30548
+ return {
30549
+ x: item.x,
30550
+ // Use original x value
30551
+ y: item.y,
30552
+ // Use original y value
30553
+ z: item.size,
30554
+ // Use original size value
30555
+ tooltip: tooltipInfo,
30556
+ fill: getFill(item.x, item.y),
30557
+ key: `bubble-${index}` // Use index for stable keys
30558
+ };
30559
+ }).filter(Boolean); // Filter out null items
30560
+ }, [data, getFill]);
30561
+
30562
+ // Function to determine which data points should be visible
30563
+ const getVisibleData = useCallback(() => {
30564
+ return allChartData.filter(item => item.x >= viewDomain.x[0] && item.x <= viewDomain.x[1] && item.y >= viewDomain.y[0] && item.y <= viewDomain.y[1]);
30565
+ }, [allChartData, viewDomain]);
30566
+
30567
+ // Get visible data - memoized
30568
+ const visibleData = useMemo(() => getVisibleData(), [getVisibleData]);
30569
+
30570
+ // Calculate a new domain based on zoom level and center point - memoized
30571
+ const calculateDomain = useCallback((center, zoomFactor) => {
30572
+ // Calculate new domain size
30573
+ const xSize = (fullDomain.x[1] - fullDomain.x[0]) * zoomFactor;
30574
+ const ySize = (fullDomain.y[1] - fullDomain.y[0]) * zoomFactor;
30575
+
30576
+ // Calculate new domain
30577
+ return {
30578
+ x: [center.x - xSize / 2, center.x + xSize / 2],
30579
+ y: [center.y - ySize / 2, center.y + ySize / 2]
30580
+ };
30581
+ }, [fullDomain]);
30582
+
30583
+ // Rendering gradients with enhanced bubble-like appearance
30584
+ const renderGradients = useCallback(() => /*#__PURE__*/React$1.createElement("defs", null, /*#__PURE__*/React$1.createElement("radialGradient", {
30585
+ id: "topLeftGradient",
30586
+ cx: "25%",
30587
+ cy: "25%",
30588
+ r: "70%",
30589
+ fx: "20%",
30590
+ fy: "20%"
30591
+ }, /*#__PURE__*/React$1.createElement("stop", {
30592
+ offset: "0%",
30593
+ stopColor: colorPalette[0]
30594
+ }), /*#__PURE__*/React$1.createElement("stop", {
30595
+ offset: "85%",
30596
+ stopColor: colorPalette[1]
30597
+ })), /*#__PURE__*/React$1.createElement("radialGradient", {
30598
+ id: "topRightGradient",
30599
+ cx: "25%",
30600
+ cy: "25%",
30601
+ r: "70%",
30602
+ fx: "20%",
30603
+ fy: "20%"
30604
+ }, /*#__PURE__*/React$1.createElement("stop", {
30605
+ offset: "0%",
30606
+ stopColor: colorPalette[2]
30607
+ }), /*#__PURE__*/React$1.createElement("stop", {
30608
+ offset: "85%",
30609
+ stopColor: colorPalette[3]
30610
+ })), /*#__PURE__*/React$1.createElement("radialGradient", {
30611
+ id: "bottomLeftGradient",
30612
+ cx: "25%",
30613
+ cy: "25%",
30614
+ r: "70%",
30615
+ fx: "20%",
30616
+ fy: "20%"
30617
+ }, /*#__PURE__*/React$1.createElement("stop", {
30618
+ offset: "0%",
30619
+ stopColor: colorPalette[4]
30620
+ }), /*#__PURE__*/React$1.createElement("stop", {
30621
+ offset: "85%",
30622
+ stopColor: colorPalette[5]
30623
+ })), /*#__PURE__*/React$1.createElement("radialGradient", {
30624
+ id: "bottomRightGradient",
30625
+ cx: "25%",
30626
+ cy: "25%",
30627
+ r: "70%",
30628
+ fx: "20%",
30629
+ fy: "20%"
30630
+ }, /*#__PURE__*/React$1.createElement("stop", {
30631
+ offset: "0%",
30632
+ stopColor: colorPalette[6]
30633
+ }), /*#__PURE__*/React$1.createElement("stop", {
30634
+ offset: "85%",
30635
+ stopColor: colorPalette[7]
30636
+ })), /*#__PURE__*/React$1.createElement("filter", {
30637
+ id: "bubble-blur",
30638
+ x: "-50%",
30639
+ y: "-50%",
30640
+ width: "200%",
30641
+ height: "200%"
30642
+ }, /*#__PURE__*/React$1.createElement("feGaussianBlur", {
30643
+ in: "SourceGraphic",
30644
+ stdDeviation: "0.3"
30645
+ }))), [colorPalette]);
30646
+
30647
+ // Handle mouse down for dragging
30648
+ const handleMouseDown = useCallback(e => {
30649
+ if (containerRef.current?.contains(e.target)) {
30650
+ setIsDragging(true);
30651
+ setDragStart({
30652
+ x: e.clientX,
30653
+ y: e.clientY
30654
+ });
30655
+ setDomainStart({
30656
+ ...viewDomain
30657
+ }); // Store current domain, not fullDomain
30658
+ e.preventDefault();
30659
+ }
30660
+ }, [viewDomain]); // Add viewDomain as dependency to capture current value
30661
+
30662
+ // Handle mouse move for dragging
30663
+ const handleMouseMove = useCallback(e => {
30664
+ if (!isDragging) return;
30665
+ const dx = e.clientX - dragStart.x;
30666
+ const dy = e.clientY - dragStart.y;
30667
+ const containerWidth = containerRef.current?.clientWidth || 800;
30668
+ const containerHeight = containerRef.current?.clientHeight || 600;
30669
+
30670
+ // Calculate the domain range from the domainStart (which preserves zoom level)
30671
+ const xRange = domainStart.x[1] - domainStart.x[0];
30672
+ const yRange = domainStart.y[1] - domainStart.y[0];
30673
+
30674
+ // Calculate the shift amount (negative for dx to make drag direction feel natural)
30675
+ const xShift = -(dx / containerWidth) * xRange * 1.5; // Multiply by 1.5 to make dragging more responsive
30676
+ const yShift = dy / containerHeight * yRange * 1.5; // Y is inverted in charts
30677
+
30678
+ // Create new domain values based on the domainStart (preserves zoom level)
30679
+ const newXDomain = [domainStart.x[0] + xShift, domainStart.x[1] + xShift];
30680
+ const newYDomain = [domainStart.y[0] + yShift, domainStart.y[1] + yShift];
30681
+
30682
+ // Update the domain
30683
+ setViewDomain({
30684
+ x: newXDomain,
30685
+ y: newYDomain
30686
+ });
30687
+ }, [isDragging, dragStart, domainStart]);
30688
+
30689
+ // Handle mouse up for dragging
30690
+ const handleMouseUp = useCallback(() => {
30691
+ setIsDragging(false);
30692
+ }, []);
30693
+
30694
+ // Handle zoom in
30695
+ const handleZoomIn = useCallback(() => {
30696
+ if (zoomLevel >= 400) return;
30697
+ const newZoomLevel = zoomLevel + 20;
30698
+ setZoomLevel(newZoomLevel);
30699
+
30700
+ // Calculate zoom factor (smaller factor = more zoomed in)
30701
+ const zoomFactor = 100 / newZoomLevel;
30702
+
30703
+ // Get current domain center
30704
+ const centerX = (viewDomain.x[0] + viewDomain.x[1]) / 2;
30705
+ const centerY = (viewDomain.y[0] + viewDomain.y[1]) / 2;
30706
+
30707
+ // Calculate new domain
30708
+ const newDomain = calculateDomain({
30709
+ x: centerX,
30710
+ y: centerY
30711
+ }, zoomFactor);
30712
+
30713
+ // Update domain
30714
+ setViewDomain(newDomain);
30715
+ }, [zoomLevel, viewDomain, calculateDomain]);
30716
+
30717
+ // Handle zoom out
30718
+ const handleZoomOut = useCallback(() => {
30719
+ if (zoomLevel <= 50) return;
30720
+ const newZoomLevel = zoomLevel - 20;
30721
+
30722
+ // If returning to 100%, reset to full domain
30723
+ if (newZoomLevel === 100) {
30724
+ setViewDomain({
30725
+ ...fullDomain
30726
+ });
30727
+ setZoomLevel(100);
30728
+ return;
30729
+ }
30730
+ setZoomLevel(newZoomLevel);
30731
+
30732
+ // Calculate zoom factor (larger factor = more zoomed out)
30733
+ const zoomFactor = 100 / newZoomLevel;
30734
+
30735
+ // Get current domain center
30736
+ const centerX = (viewDomain.x[0] + viewDomain.x[1]) / 2;
30737
+ const centerY = (viewDomain.y[0] + viewDomain.y[1]) / 2;
30738
+
30739
+ // Calculate new domain size
30740
+ const xSize = (fullDomain.x[1] - fullDomain.x[0]) * zoomFactor;
30741
+ const ySize = (fullDomain.y[1] - fullDomain.y[0]) * zoomFactor;
30742
+
30743
+ // If new domain would be larger than full domain, reset to full
30744
+ if (xSize >= fullDomain.x[1] - fullDomain.x[0] || ySize >= fullDomain.y[1] - fullDomain.y[0]) {
30745
+ setViewDomain({
30746
+ ...fullDomain
30747
+ });
30748
+ setZoomLevel(100);
30749
+ return;
30750
+ }
30751
+
30752
+ // Calculate new domain
30753
+ const newDomain = calculateDomain({
30754
+ x: centerX,
30755
+ y: centerY
30756
+ }, zoomFactor);
30757
+
30758
+ // Update domain
30759
+ setViewDomain(newDomain);
30760
+ }, [zoomLevel, viewDomain, fullDomain, calculateDomain]);
30761
+
30762
+ // Handle reset
30763
+ const handleReset = useCallback(() => {
30764
+ setZoomLevel(100);
30765
+ setViewDomain({
30766
+ ...fullDomain
30767
+ });
30768
+ }, [fullDomain]);
30769
+
30770
+ // Handle mouse wheel
30771
+ const handleWheel = useCallback(e => {
30772
+ e.preventDefault();
30773
+ if (e.deltaY < 0) {
30774
+ handleZoomIn();
30347
30775
  } else {
30348
- // Normal case: position the indicator above the active chips
30349
- newTop = (totalSegmentsLines - completedSegments) * barHeight / 1.65;
30350
- // Position the goal value just above the active chips
30351
- newGoalValuePosition = newTop;
30776
+ handleZoomOut();
30352
30777
  }
30353
- setTop(newTop);
30354
- setGoalValuePosition(newGoalValuePosition);
30355
- }, [completedSegments, totalSegmentsLines, currentAmount, goalAmount, containerHeight]);
30778
+ }, [handleZoomIn, handleZoomOut]);
30779
+
30780
+ // Memoize the visibility condition for the middle value label
30781
+ const isMiddleValueVisible = useMemo(() => xMedian >= viewDomain.x[0] && xMedian <= viewDomain.x[1] && yMedian >= viewDomain.y[0] && yMedian <= viewDomain.y[1], [viewDomain, xMedian, yMedian]);
30782
+
30783
+ // Set up event listeners
30356
30784
  useEffect(() => {
30357
- if (containerRef.current) {
30358
- const height = containerRef.current.offsetHeight;
30359
- if (height > 0) {
30360
- setContainerHeight(height);
30361
- }
30785
+ const container = containerRef.current;
30786
+ if (!container) return;
30787
+ container.addEventListener('wheel', handleWheel, {
30788
+ passive: false
30789
+ });
30790
+ container.addEventListener('mousedown', handleMouseDown);
30791
+ window.addEventListener('mousemove', handleMouseMove);
30792
+ window.addEventListener('mouseup', handleMouseUp);
30793
+ return () => {
30794
+ container.removeEventListener('wheel', handleWheel);
30795
+ container.removeEventListener('mousedown', handleMouseDown);
30796
+ window.removeEventListener('mousemove', handleMouseMove);
30797
+ window.removeEventListener('mouseup', handleMouseUp);
30798
+ };
30799
+ }, [handleWheel, handleMouseDown, handleMouseMove, handleMouseUp]);
30800
+
30801
+ // Unified arrow component with direction parameter
30802
+ const Arrow = _ref3 => {
30803
+ let {
30804
+ viewBox,
30805
+ direction
30806
+ } = _ref3;
30807
+ // Define points based on direction
30808
+ let points = '';
30809
+ switch (direction) {
30810
+ case 'top':
30811
+ points = `${viewBox.x},${viewBox.y - 10} ${viewBox.x - 5},${viewBox.y} ${viewBox.x + 5},${viewBox.y}`;
30812
+ break;
30813
+ case 'bottom':
30814
+ points = `${viewBox.x},${viewBox.y + viewBox.height + 10} ${viewBox.x - 5},${viewBox.y + viewBox.height} ${viewBox.x + 5},${viewBox.y + viewBox.height}`;
30815
+ break;
30816
+ case 'left':
30817
+ points = `${viewBox.x - 10},${viewBox.y} ${viewBox.x},${viewBox.y - 5} ${viewBox.x},${viewBox.y + 5}`;
30818
+ break;
30819
+ case 'right':
30820
+ points = `${viewBox.x + viewBox.width + 10},${viewBox.y} ${viewBox.x + viewBox.width},${viewBox.y - 5} ${viewBox.x + viewBox.width},${viewBox.y + 5}`;
30821
+ break;
30362
30822
  }
30363
- }, [containerRef, width, height]);
30364
- return /*#__PURE__*/React$1.createElement(BatteryChartContainer, {
30365
- ref: containerRef,
30823
+ return /*#__PURE__*/React$1.createElement("polygon", {
30824
+ points: points,
30825
+ fill: "#D0D0D0"
30826
+ });
30827
+ };
30828
+
30829
+ // Function to format currency values
30830
+ const formatCurrency = value => {
30831
+ if (Math.abs(value) >= 1000000) {
30832
+ return `$${(value / 1000000).toFixed(1)}M`;
30833
+ } else if (Math.abs(value) >= 1000) {
30834
+ return `$${(value / 1000).toFixed(1)}K`;
30835
+ }
30836
+ return `$${value.toFixed(1)}`;
30837
+ };
30838
+
30839
+ // Function to format units values
30840
+ const formatUnits = value => {
30841
+ if (Math.abs(value) >= 1000000) {
30842
+ return `${(value / 1000000).toFixed(1)}M`;
30843
+ } else if (Math.abs(value) >= 1000) {
30844
+ return `${(value / 1000).toFixed(1)}K`;
30845
+ }
30846
+ return `${value.toFixed(1)}`;
30847
+ };
30848
+
30849
+ // Function to format ROI values
30850
+ const formatROI = value => {
30851
+ return value.toFixed(1);
30852
+ };
30853
+
30854
+ // Format the median values for display
30855
+ const formattedMedianValue = useMemo(() => {
30856
+ const formattedX = formatROI(xMedian);
30857
+ const formattedY = formatUnits(yMedian);
30858
+ return `${formattedX}, ${formattedY}`;
30859
+ }, [xMedian, yMedian]);
30860
+
30861
+ // Render the component
30862
+ return /*#__PURE__*/React$1.createElement(BubbleChartContainer, {
30366
30863
  width: width,
30367
30864
  height: height,
30368
- className: className,
30369
- containerPadding: containerPadding,
30370
- backgroundColor: backgroundColor
30371
- }, /*#__PURE__*/React$1.createElement(HeadingText, null, title), /*#__PURE__*/React$1.createElement(PanelSide, null, /*#__PURE__*/React$1.createElement(ProgressDetails, null, !noCommitment && /*#__PURE__*/React$1.createElement(HeadingPercentage, null, percentage, "%"), /*#__PURE__*/React$1.createElement(ProgressDescription, null, ask && /*#__PURE__*/React$1.createElement(ProgressItem, null, "ASK: ", `$${getFormattedValue(ask, false) + getFormattedUnits(ask)}`), target && /*#__PURE__*/React$1.createElement(ProgressItem, null, "Target: ", `$${getFormattedValue(target, false) + getFormattedUnits(target)}`)), /*#__PURE__*/React$1.createElement(ProgressLegend, null, /*#__PURE__*/React$1.createElement(LegendItem, null, /*#__PURE__*/React$1.createElement(LegendCube, {
30372
- color: color
30373
- }), /*#__PURE__*/React$1.createElement(LegendText, null, "Spend")), !noCommitment && /*#__PURE__*/React$1.createElement(LegendItem, null, /*#__PURE__*/React$1.createElement(LegendCube, {
30374
- color: "#E3E4E5"
30375
- }), /*#__PURE__*/React$1.createElement(LegendText, null, "Commitment"))))), /*#__PURE__*/React$1.createElement(ChartSide, null, /*#__PURE__*/React$1.createElement(ChartWrapper, null, /*#__PURE__*/React$1.createElement(GoalValue, {
30376
- className: currentAmount > goalAmount && !noCommitment ? "overload" : "",
30377
- goalValuePosition: goalValuePosition
30378
- }, !noCommitment ? `$${getFormattedValue(goalAmount, false) + getFormattedUnits(goalAmount)}` : `$${getFormattedValue(currentAmount, false) + getFormattedUnits(currentAmount)}`), !noCommitment && /*#__PURE__*/React$1.createElement(Indicator, {
30379
- top: top
30380
- }, /*#__PURE__*/React$1.createElement(IndicatorLine, {
30381
- color: indicatorColor
30382
- }), /*#__PURE__*/React$1.createElement(IndicatorText, {
30383
- color: indicatorColor
30384
- }, `$${getFormattedValue(currentAmount, false) + getFormattedUnits(currentAmount)}`)), /*#__PURE__*/React$1.createElement(ResponsiveContainer, {
30385
- height: Math.max(containerHeight - 105, 210)
30386
- }, /*#__PURE__*/React$1.createElement(BarChart$1, {
30387
- data: barsChips,
30388
- layout: "vertical",
30865
+ ref: containerRef,
30866
+ style: {
30867
+ cursor: isDragging ? 'grabbing' : 'grab'
30868
+ },
30869
+ backgroundColor: backgroundColor,
30870
+ "data-testid": "bubble-chart-container"
30871
+ }, /*#__PURE__*/React$1.createElement(HeaderContainer, {
30872
+ "data-testid": "header-container"
30873
+ }, /*#__PURE__*/React$1.createElement(ChartTitle, {
30874
+ "data-testid": "chart-title"
30875
+ }, title), /*#__PURE__*/React$1.createElement(ChartSubtitle, {
30876
+ "data-testid": "chart-subtitle"
30877
+ }, subtitle)), /*#__PURE__*/React$1.createElement(ChartContainer, {
30878
+ ref: scatterChartRef,
30879
+ "data-testid": "chart-container"
30880
+ }, /*#__PURE__*/React$1.createElement(ResponsiveContainer, {
30881
+ width: "100%",
30882
+ height: "100%",
30883
+ "data-testid": "responsive-container"
30884
+ }, /*#__PURE__*/React$1.createElement(ScatterChart, {
30389
30885
  margin: {
30390
- top: 5,
30391
- right: 5,
30392
- left: 5,
30393
- bottom: 5
30886
+ top: 60,
30887
+ right: 190,
30888
+ bottom: 50,
30889
+ left: 180
30394
30890
  },
30395
- barSize: 4
30396
- }, /*#__PURE__*/React$1.createElement(XAxis, {
30891
+ "data-testid": "scatter-chart"
30892
+ }, renderGradients(), /*#__PURE__*/React$1.createElement(XAxis, {
30397
30893
  type: "number",
30398
- hide: true,
30399
- domain: [0, 100]
30894
+ dataKey: "x",
30895
+ domain: viewDomain.x,
30896
+ axisLine: showAxis,
30897
+ tickLine: showAxis,
30898
+ tick: showAxis ? {
30899
+ fontSize: 10,
30900
+ fontWeight: 400,
30901
+ fontFamily: 'Poppins'
30902
+ } : false,
30903
+ tickFormatter: value => formatUnits(value),
30904
+ hide: !showAxis,
30905
+ "data-testid": "x-axis",
30906
+ style: {
30907
+ fontSize: '10px',
30908
+ fontWeight: 400,
30909
+ fontFamily: 'Poppins'
30910
+ }
30400
30911
  }), /*#__PURE__*/React$1.createElement(YAxis, {
30401
- type: "category",
30402
- hide: true,
30403
- dataKey: "name"
30404
- }), /*#__PURE__*/React$1.createElement(Bar, {
30405
- dataKey: "value",
30406
- background: {
30407
- fill: "#f3f4f6"
30912
+ type: "number",
30913
+ dataKey: "y",
30914
+ domain: viewDomain.y,
30915
+ axisLine: showAxis,
30916
+ tickLine: showAxis,
30917
+ tick: showAxis ? {
30918
+ fontSize: 10,
30919
+ fontWeight: 400,
30920
+ fontFamily: 'Poppins'
30921
+ } : false,
30922
+ tickFormatter: value => formatUnits(value),
30923
+ hide: !showAxis,
30924
+ "data-testid": "y-axis",
30925
+ style: {
30926
+ fontSize: '10px',
30927
+ fontWeight: 400,
30928
+ fontFamily: 'Poppins'
30929
+ }
30930
+ }), /*#__PURE__*/React$1.createElement(ZAxis, {
30931
+ type: "number",
30932
+ dataKey: "z",
30933
+ range: [0, 7000],
30934
+ domain: [0, Math.max(...data.map(item => item.size || 0))],
30935
+ "data-testid": "z-axis"
30936
+ }), /*#__PURE__*/React$1.createElement(ReferenceLine, {
30937
+ x: xMedian,
30938
+ stroke: "#D0D0D0",
30939
+ strokeDasharray: "4 4",
30940
+ isFront: false,
30941
+ "data-testid": "reference-line-x",
30942
+ label: xMedian >= viewDomain.x[0] && xMedian <= viewDomain.x[1] ? {
30943
+ value: topHeader,
30944
+ position: "top",
30945
+ offset: 40,
30946
+ fill: '#484A4C',
30947
+ fontSize: 16,
30948
+ fontWeight: 500
30949
+ } : null
30950
+ }), xMedian >= viewDomain.x[0] && xMedian <= viewDomain.x[1] && /*#__PURE__*/React$1.createElement(ReferenceLine, {
30951
+ x: xMedian,
30952
+ stroke: "transparent",
30953
+ isFront: true,
30954
+ label: _ref4 => {
30955
+ let {
30956
+ viewBox
30957
+ } = _ref4;
30958
+ return /*#__PURE__*/React$1.createElement(Arrow, {
30959
+ viewBox: viewBox,
30960
+ direction: "top"
30961
+ });
30962
+ }
30963
+ }), /*#__PURE__*/React$1.createElement(ReferenceLine, {
30964
+ x: xMedian,
30965
+ stroke: "transparent",
30966
+ isFront: false,
30967
+ "data-testid": "reference-line-x-bottom",
30968
+ label: xMedian >= viewDomain.x[0] && xMedian <= viewDomain.x[1] ? {
30969
+ value: bottomHeader,
30970
+ position: "bottom",
30971
+ offset: 30,
30972
+ fill: '#484A4C',
30973
+ fontSize: 16,
30974
+ fontWeight: 500
30975
+ } : null
30976
+ }), xMedian >= viewDomain.x[0] && xMedian <= viewDomain.x[1] && /*#__PURE__*/React$1.createElement(ReferenceLine, {
30977
+ x: xMedian,
30978
+ stroke: "transparent",
30979
+ isFront: true,
30980
+ label: _ref5 => {
30981
+ let {
30982
+ viewBox
30983
+ } = _ref5;
30984
+ return /*#__PURE__*/React$1.createElement(Arrow, {
30985
+ viewBox: viewBox,
30986
+ direction: "bottom"
30987
+ });
30988
+ }
30989
+ }), /*#__PURE__*/React$1.createElement(ReferenceLine, {
30990
+ y: yMedian,
30991
+ stroke: "#D0D0D0",
30992
+ strokeDasharray: "4 4",
30993
+ isFront: false,
30994
+ "data-testid": "reference-line-y",
30995
+ label: yMedian >= viewDomain.y[0] && yMedian <= viewDomain.y[1] ? {
30996
+ value: leftHeader,
30997
+ position: "left",
30998
+ offset: 30,
30999
+ fill: '#484A4C',
31000
+ fontSize: 16,
31001
+ fontWeight: 500
31002
+ } : null
31003
+ }), yMedian >= viewDomain.y[0] && yMedian <= viewDomain.y[1] && /*#__PURE__*/React$1.createElement(ReferenceLine, {
31004
+ y: yMedian,
31005
+ isFront: true,
31006
+ stroke: "transparent",
31007
+ label: _ref6 => {
31008
+ let {
31009
+ viewBox
31010
+ } = _ref6;
31011
+ return /*#__PURE__*/React$1.createElement(Arrow, {
31012
+ viewBox: viewBox,
31013
+ direction: "left"
31014
+ });
31015
+ }
31016
+ }), /*#__PURE__*/React$1.createElement(ReferenceLine, {
31017
+ y: yMedian,
31018
+ stroke: "transparent",
31019
+ isFront: false,
31020
+ "data-testid": "reference-line-y-transparent",
31021
+ label: yMedian >= viewDomain.y[0] && yMedian <= viewDomain.y[1] ? {
31022
+ value: rightHeader,
31023
+ position: "right",
31024
+ offset: 30,
31025
+ fill: '#484A4C',
31026
+ fontSize: 16,
31027
+ fontWeight: 500
31028
+ } : null
31029
+ }), yMedian >= viewDomain.y[0] && yMedian <= viewDomain.y[1] && /*#__PURE__*/React$1.createElement(ReferenceLine, {
31030
+ y: yMedian,
31031
+ isFront: true,
31032
+ stroke: "transparent",
31033
+ label: _ref7 => {
31034
+ let {
31035
+ viewBox
31036
+ } = _ref7;
31037
+ return /*#__PURE__*/React$1.createElement(Arrow, {
31038
+ viewBox: viewBox,
31039
+ direction: "right"
31040
+ });
31041
+ }
31042
+ }), /*#__PURE__*/React$1.createElement(Tooltip$2, {
31043
+ content: /*#__PURE__*/React$1.createElement(CustomTooltip, null),
31044
+ cursor: false,
31045
+ wrapperStyle: {
31046
+ zIndex: 9999,
31047
+ position: 'absolute',
31048
+ pointerEvents: 'auto'
30408
31049
  },
30409
- radius: [8, 8, 8, 8]
30410
- }, barsChips.map((entry, index) => /*#__PURE__*/React$1.createElement(Cell, {
30411
- key: `cell-${index}`,
30412
- fill: entry.color
30413
- }))))))), starText !== "" && /*#__PURE__*/React$1.createElement(StarText, null, starText));
31050
+ allowEscapeViewBox: {
31051
+ x: false,
31052
+ y: false
31053
+ },
31054
+ "data-testid": "tooltip"
31055
+ }), /*#__PURE__*/React$1.createElement(Scatter, {
31056
+ name: "Bubble Chart",
31057
+ data: visibleData,
31058
+ shape: "circle",
31059
+ fill: "transparent",
31060
+ isAnimationActive: false,
31061
+ animationBegin: 0,
31062
+ animationDuration: 0,
31063
+ "data-testid": "scatter"
31064
+ }, visibleData.map((entry, index) => /*#__PURE__*/React$1.createElement(Cell, {
31065
+ key: entry.key,
31066
+ fill: entry.fill,
31067
+ stroke: "rgba(255,255,255,0.6)",
31068
+ strokeWidth: 1.5,
31069
+ filter: "url(#bubble-blur)",
31070
+ "data-testid": `cell-${index}`
31071
+ }))), isMiddleValueVisible && /*#__PURE__*/React$1.createElement(ReferenceLine, {
31072
+ x: xMedian,
31073
+ y: yMedian,
31074
+ stroke: "transparent",
31075
+ isFront: true,
31076
+ "data-testid": "middle-value-reference",
31077
+ label: _ref8 => {
31078
+ let {
31079
+ viewBox
31080
+ } = _ref8;
31081
+ // Calculate the exact position of the median point in the SVG
31082
+ const xPos = viewBox.x + (xMedian - viewDomain.x[0]) / (viewDomain.x[1] - viewDomain.x[0]) * viewBox.width;
31083
+ const yPos = viewBox.y + (1 - (yMedian - viewDomain.y[0]) / (viewDomain.y[1] - viewDomain.y[0])) * viewBox.height;
31084
+ return /*#__PURE__*/React$1.createElement("text", {
31085
+ x: xPos,
31086
+ y: yPos,
31087
+ textAnchor: "middle",
31088
+ dominantBaseline: "middle",
31089
+ fill: "#484A4C",
31090
+ fontSize: 16,
31091
+ fontWeight: 600,
31092
+ style: {
31093
+ backgroundColor: 'rgba(255, 255, 255, 0.7)',
31094
+ padding: '2px'
31095
+ }
31096
+ }, formattedMedianValue);
31097
+ }
31098
+ })))), /*#__PURE__*/React$1.createElement(ZoomControlsContainer, {
31099
+ "data-testid": "zoom-controls-container"
31100
+ }, /*#__PURE__*/React$1.createElement(ZoomPercentage, {
31101
+ "data-testid": "zoom-percentage"
31102
+ }, zoomLevel, "%"), /*#__PURE__*/React$1.createElement(ZoomButton, {
31103
+ onClick: handleZoomOut,
31104
+ title: "Zoom Out",
31105
+ "data-testid": "zoom-out-button"
31106
+ }, "\u2212"), /*#__PURE__*/React$1.createElement(ZoomButton, {
31107
+ onClick: handleZoomIn,
31108
+ title: "Zoom In",
31109
+ "data-testid": "zoom-in-button"
31110
+ }, "+"), /*#__PURE__*/React$1.createElement(ZoomResetButton, {
31111
+ onClick: handleReset,
31112
+ "data-testid": "zoom-reset-button"
31113
+ }, "Reset")));
31114
+ };
31115
+
31116
+ const BatteryChartContainer = styled.div`
31117
+ position: relative;
31118
+ font-family: "Poppins", sans-serif;
31119
+ display: grid;
31120
+ grid-template-columns: auto auto;
31121
+ grid-template-rows: auto 1fr auto;
31122
+ color: #212121;
31123
+ background-color: ${props => props.backgroundColor || 'transparent'};
31124
+ padding: ${props => props.containerPadding || '25px 30px 0'};
31125
+ width: ${props => props.width};
31126
+ height: ${props => props.height};
31127
+ `;
31128
+ const PanelSide = styled.div`
31129
+ display: flex;
31130
+ flex-direction: column;
31131
+ justify-content: space-between;
31132
+ `;
31133
+ const ProgressDetails = styled.div`
31134
+ display: flex;
31135
+ flex-direction: column;
31136
+ flex-grow: 1;
31137
+ `;
31138
+ const HeadingText = styled.p`
31139
+ grid-column: 1 / span 2;
31140
+ color: #212121;
31141
+ font-size: 18px;
31142
+ font-weight: 400;
31143
+ padding-left: 10px;
31144
+ margin: 0 0 8px;
31145
+ `;
31146
+ const HeadingPercentage = styled.p`
31147
+ color: #212121;
31148
+ font-size: 32px;
31149
+ font-weight: 500;
31150
+ padding-left: 10px;
31151
+ margin: 0;
31152
+ `;
31153
+ const ChartSide = styled.div`
31154
+ text-align: center;
31155
+ `;
31156
+ const ChartWrapper = styled.div`
31157
+ position: relative;
31158
+ width: 110px;
31159
+ `;
31160
+ const GoalValue = styled.div`
31161
+ text-align: center;
31162
+ font-size: 18px;
31163
+ color: #8B8989;
31164
+ line-height: 1;
31165
+ &.overload {
31166
+ position: absolute;
31167
+ top: ${props => props.goalValuePosition}px;
31168
+ left: 0;
31169
+ right: 0;
31170
+ z-index: 2;
31171
+ margin: 0 auto;
31172
+ width: 40%;
31173
+ display: inline;
31174
+ padding: 0px 8px;
31175
+ border: 2px solid #F2F2F2;
31176
+ border-bottom: none;
31177
+ border-radius: 6px 6px 0px 0px;
31178
+ background-color: white;
31179
+ }
31180
+ `;
31181
+ const Indicator = styled.div`
31182
+ position: absolute;
31183
+ top: ${props => props.top}px;
31184
+ left: 0;
31185
+ transform: translateY(50%);
31186
+ width: calc(100% + 60px);
31187
+ display: flex;
31188
+ gap: 6px;
31189
+ justify-content: center;
31190
+ padding-left: 4px;
31191
+ align-items: center;
31192
+ z-index: 1;
31193
+ `;
31194
+ const IndicatorLine = styled.div`
31195
+ width: 100%;
31196
+ height: 0;
31197
+ border-top: 4px dashed ${props => props.color};
31198
+ `;
31199
+ const IndicatorText = styled.span`
31200
+ font-size: 18px;
31201
+ font-weight: 400;
31202
+ color: ${props => props.color};
31203
+ `;
31204
+ const ProgressLegend = styled.div`
31205
+ margin-top: 12px;
31206
+ `;
31207
+ const LegendItem = styled.div`
31208
+ display: flex;
31209
+ gap: 4px;
31210
+ align-items: center;
31211
+ margin-bottom: 12px;
31212
+ `;
31213
+ const LegendText = styled.span`
31214
+ color: #8B8989;
31215
+ font-size: 14px;
31216
+ `;
31217
+ const LegendCube = styled.div`
31218
+ border-radius: 3px;
31219
+ width: 17px;
31220
+ height: 17px;
31221
+ background-color: ${props => props.color};
31222
+ `;
31223
+ const ProgressDescription = styled.div`
31224
+ color: #8B8989;
31225
+ font-size: 12px;
31226
+ font-weight: 400;
31227
+ margin-top: auto;
31228
+ `;
31229
+ const ProgressItem = styled.p`
31230
+ margin: 0 0 6px;
31231
+ `;
31232
+ const StarText = styled.span`
31233
+ width: 100%;
31234
+ color: #B1B1B1;
31235
+ font-size: 9px;
31236
+ grid-column: 1 / span 2;
31237
+ padding-top: 10px;
31238
+ `;
31239
+
31240
+ const BatteryChart = props => {
31241
+ const {
31242
+ className,
31243
+ containerPadding,
31244
+ width,
31245
+ height,
31246
+ title,
31247
+ color,
31248
+ backgroundColor,
31249
+ indicatorColor,
31250
+ noCommitment,
31251
+ goalAmount,
31252
+ currentAmount,
31253
+ ask,
31254
+ target,
31255
+ totalSegmentsLines,
31256
+ starText
31257
+ } = props;
31258
+ const [top, setTop] = useState(0);
31259
+ const [goalValuePosition, setGoalValuePosition] = useState(0);
31260
+ const [containerHeight, setContainerHeight] = useState(0); // State to store container height
31261
+ const containerRef = useRef(null); // Ref for BatteryChartContainer
31262
+
31263
+ // Calculate the percentage and completed segments
31264
+ const percentage = Math.round(currentAmount / goalAmount * 100);
31265
+ const completedSegments = Math.min(Math.floor(currentAmount / goalAmount * totalSegmentsLines), totalSegmentsLines);
31266
+
31267
+ // Dynamically create the data for the bar chart
31268
+ let barsChips = Array.from({
31269
+ length: totalSegmentsLines
31270
+ }).map((_, index) => ({
31271
+ name: `segment-${index}`,
31272
+ value: 100,
31273
+ isCompleted: index >= totalSegmentsLines - completedSegments,
31274
+ // Fill from bottom up
31275
+ color: index >= totalSegmentsLines - completedSegments ? color : "#e5e7eb" // Completed or remaining color
31276
+ }));
31277
+
31278
+ // Add 4 extra chips if currentAmount > goalAmount
31279
+ if (currentAmount > goalAmount && !noCommitment) {
31280
+ const extraSegments = 4;
31281
+ const extraData = Array.from({
31282
+ length: extraSegments
31283
+ }).map((_, index) => ({
31284
+ name: `extra-segment-${index}`,
31285
+ value: 100,
31286
+ isCompleted: true,
31287
+ color: "#E8F5EB"
31288
+ }));
31289
+
31290
+ // Prepend the extra segments to the barsChips array
31291
+ barsChips = [...extraData, ...barsChips];
31292
+ }
31293
+
31294
+ // Calculate the top position for the indicator and goal value
31295
+ useEffect(() => {
31296
+ const barHeight = containerHeight / (totalSegmentsLines + (currentAmount > goalAmount ? 4 : 0)); // Adjust for extra chips
31297
+ let newTop;
31298
+ let newGoalValuePosition;
31299
+ if (currentAmount > goalAmount) {
31300
+ // Position the indicator slightly below the top chip
31301
+ newTop = barHeight * 1.5; // Slightly below the 4th chip
31302
+ // Position the goal value just above the active chips
31303
+
31304
+ newGoalValuePosition = barHeight * 2.3;
31305
+ // newGoalValuePosition = (totalSegmentsLines - completedSegments + 4) * barHeight - barHeight / 2;
31306
+ } else {
31307
+ // Normal case: position the indicator above the active chips
31308
+ newTop = (totalSegmentsLines - completedSegments) * barHeight / 1.65;
31309
+ // Position the goal value just above the active chips
31310
+ newGoalValuePosition = newTop;
31311
+ }
31312
+ setTop(newTop);
31313
+ setGoalValuePosition(newGoalValuePosition);
31314
+ }, [completedSegments, totalSegmentsLines, currentAmount, goalAmount, containerHeight]);
31315
+ useEffect(() => {
31316
+ if (containerRef.current) {
31317
+ const height = containerRef.current.offsetHeight;
31318
+ if (height > 0) {
31319
+ setContainerHeight(height);
31320
+ }
31321
+ }
31322
+ }, [containerRef, width, height]);
31323
+ return /*#__PURE__*/React$1.createElement(BatteryChartContainer, {
31324
+ ref: containerRef,
31325
+ width: width,
31326
+ height: height,
31327
+ className: className,
31328
+ containerPadding: containerPadding,
31329
+ backgroundColor: backgroundColor
31330
+ }, /*#__PURE__*/React$1.createElement(HeadingText, null, title), /*#__PURE__*/React$1.createElement(PanelSide, null, /*#__PURE__*/React$1.createElement(ProgressDetails, null, !noCommitment && /*#__PURE__*/React$1.createElement(HeadingPercentage, null, percentage, "%"), /*#__PURE__*/React$1.createElement(ProgressDescription, null, ask && /*#__PURE__*/React$1.createElement(ProgressItem, null, "ASK: ", `$${getFormattedValue(ask, false) + getFormattedUnits(ask)}`), target && /*#__PURE__*/React$1.createElement(ProgressItem, null, "Target: ", `$${getFormattedValue(target, false) + getFormattedUnits(target)}`)), /*#__PURE__*/React$1.createElement(ProgressLegend, null, /*#__PURE__*/React$1.createElement(LegendItem, null, /*#__PURE__*/React$1.createElement(LegendCube, {
31331
+ color: color
31332
+ }), /*#__PURE__*/React$1.createElement(LegendText, null, "Spend")), !noCommitment && /*#__PURE__*/React$1.createElement(LegendItem, null, /*#__PURE__*/React$1.createElement(LegendCube, {
31333
+ color: "#E3E4E5"
31334
+ }), /*#__PURE__*/React$1.createElement(LegendText, null, "Commitment"))))), /*#__PURE__*/React$1.createElement(ChartSide, null, /*#__PURE__*/React$1.createElement(ChartWrapper, null, /*#__PURE__*/React$1.createElement(GoalValue, {
31335
+ className: currentAmount > goalAmount && !noCommitment ? "overload" : "",
31336
+ goalValuePosition: goalValuePosition
31337
+ }, !noCommitment ? `$${getFormattedValue(goalAmount, false) + getFormattedUnits(goalAmount)}` : `$${getFormattedValue(currentAmount, false) + getFormattedUnits(currentAmount)}`), !noCommitment && /*#__PURE__*/React$1.createElement(Indicator, {
31338
+ top: top
31339
+ }, /*#__PURE__*/React$1.createElement(IndicatorLine, {
31340
+ color: indicatorColor
31341
+ }), /*#__PURE__*/React$1.createElement(IndicatorText, {
31342
+ color: indicatorColor
31343
+ }, `$${getFormattedValue(currentAmount, false) + getFormattedUnits(currentAmount)}`)), /*#__PURE__*/React$1.createElement(ResponsiveContainer, {
31344
+ height: Math.max(containerHeight - 105, 210)
31345
+ }, /*#__PURE__*/React$1.createElement(BarChart$1, {
31346
+ data: barsChips,
31347
+ layout: "vertical",
31348
+ margin: {
31349
+ top: 5,
31350
+ right: 5,
31351
+ left: 5,
31352
+ bottom: 5
31353
+ },
31354
+ barSize: 4
31355
+ }, /*#__PURE__*/React$1.createElement(XAxis, {
31356
+ type: "number",
31357
+ hide: true,
31358
+ domain: [0, 100]
31359
+ }), /*#__PURE__*/React$1.createElement(YAxis, {
31360
+ type: "category",
31361
+ hide: true,
31362
+ dataKey: "name"
31363
+ }), /*#__PURE__*/React$1.createElement(Bar, {
31364
+ dataKey: "value",
31365
+ background: {
31366
+ fill: "#f3f4f6"
31367
+ },
31368
+ radius: [8, 8, 8, 8]
31369
+ }, barsChips.map((entry, index) => /*#__PURE__*/React$1.createElement(Cell, {
31370
+ key: `cell-${index}`,
31371
+ fill: entry.color
31372
+ }))))))), starText !== "" && /*#__PURE__*/React$1.createElement(StarText, null, starText));
31373
+ };
31374
+
31375
+ const originalData$1 = [{
31376
+ label: "Vendor Selling Event: Week 28",
31377
+ inc_unit: 20000,
31378
+ inc_roi: 1.2
31379
+ }, {
31380
+ label: "Vendor Selling Event: Week 29",
31381
+ inc_unit: 10000,
31382
+ inc_roi: 1.2
31383
+ }, {
31384
+ label: "Vendor Selling Event: Week 30",
31385
+ inc_unit: 8000,
31386
+ inc_roi: 0.8
31387
+ }, {
31388
+ label: "Vendor Selling Event: Week 33",
31389
+ inc_unit: 12000,
31390
+ inc_roi: 1.1
31391
+ }, {
31392
+ label: "Vendor Selling Event: Week 36",
31393
+ inc_unit: 8000,
31394
+ inc_roi: 1.2
31395
+ }, {
31396
+ label: "Vendor Selling Event: Week 34",
31397
+ inc_unit: 8000,
31398
+ inc_roi: 0.7
31399
+ }, {
31400
+ label: "Vendor Selling Event: Week 35",
31401
+ inc_unit: 8000,
31402
+ inc_roi: 0.8
31403
+ }, {
31404
+ label: "Vendor Selling Event: Week 38",
31405
+ inc_unit: 9000,
31406
+ inc_roi: 1.1
31407
+ }];
31408
+ const dataWithIndex$1 = originalData$1.map((item, index) => ({
31409
+ ...item,
31410
+ index,
31411
+ shortLabel: item.label.replace("Vendor Selling Event: ", "Wk ")
31412
+ }));
31413
+ const CustomizedTick$1 = ({
31414
+ x,
31415
+ y,
31416
+ payload
31417
+ }) => {
31418
+ const label = dataWithIndex$1[payload.value]?.label ?? "";
31419
+ const parts = label.replace("Vendor Selling Event: ", "").split(" ");
31420
+ return /*#__PURE__*/React$1.createElement("g", {
31421
+ transform: `translate(${x},${y})`
31422
+ }, /*#__PURE__*/React$1.createElement("text", {
31423
+ x: 0,
31424
+ y: 0,
31425
+ dy: 16,
31426
+ textAnchor: "middle",
31427
+ fill: "#212121",
31428
+ fontSize: 11,
31429
+ fontWeight: "400",
31430
+ fontFamily: "Poppins"
31431
+ }, /*#__PURE__*/React$1.createElement("tspan", {
31432
+ x: 0,
31433
+ dy: 8
31434
+ }, "Vendor Selling"), /*#__PURE__*/React$1.createElement("tspan", {
31435
+ x: 0,
31436
+ dy: 18
31437
+ }, "Event: ", parts.join(" "))));
31438
+ };
31439
+
31440
+ // Common chart configuration
31441
+ const chartMargins = {
31442
+ top: 15,
31443
+ right: 40,
31444
+ left: 20,
31445
+ bottom: 40
31446
+ };
31447
+ const SeparatedLineBarChart = () => {
31448
+ const [viewWindow, setViewWindow] = useState({
31449
+ startIndex: 0,
31450
+ endIndex: dataWithIndex$1.length - 1
31451
+ });
31452
+ return /*#__PURE__*/React$1.createElement("div", {
31453
+ style: {
31454
+ width: "100%",
31455
+ height: 700
31456
+ }
31457
+ }, /*#__PURE__*/React$1.createElement("div", {
31458
+ style: {
31459
+ height: "40%"
31460
+ }
31461
+ }, /*#__PURE__*/React$1.createElement(ResponsiveContainer, {
31462
+ width: "100%",
31463
+ height: "100%"
31464
+ }, /*#__PURE__*/React$1.createElement(LineChart, {
31465
+ data: dataWithIndex$1 // Use full dataset for alignment
31466
+ ,
31467
+ margin: chartMargins
31468
+ }, /*#__PURE__*/React$1.createElement(CartesianGrid, {
31469
+ strokeDasharray: "3 3",
31470
+ vertical: false
31471
+ }), /*#__PURE__*/React$1.createElement(XAxis, {
31472
+ dataKey: "index",
31473
+ type: "number",
31474
+ domain: ['dataMin', 'dataMax'],
31475
+ padding: {
31476
+ left: 20,
31477
+ right: 20
31478
+ },
31479
+ hide: true
31480
+ }), /*#__PURE__*/React$1.createElement(YAxis, {
31481
+ domain: [0, 2],
31482
+ hide: true
31483
+ }), /*#__PURE__*/React$1.createElement(Tooltip$2, null), /*#__PURE__*/React$1.createElement(Line, {
31484
+ type: "monotone",
31485
+ dataKey: "inc_roi",
31486
+ stroke: "#F8CD00",
31487
+ strokeWidth: 2,
31488
+ dot: {
31489
+ r: 4,
31490
+ fill: "#F8CD00"
31491
+ },
31492
+ activeDot: false,
31493
+ name: "INC Sales ROI"
31494
+ }, /*#__PURE__*/React$1.createElement(LabelList, {
31495
+ dataKey: "inc_roi",
31496
+ position: "top",
31497
+ formatter: value => value.toFixed(1)
31498
+ }))))), /*#__PURE__*/React$1.createElement("div", {
31499
+ style: {
31500
+ height: "60%"
31501
+ }
31502
+ }, /*#__PURE__*/React$1.createElement(ResponsiveContainer, {
31503
+ width: "100%",
31504
+ height: "100%"
31505
+ }, /*#__PURE__*/React$1.createElement(ComposedChart, {
31506
+ data: dataWithIndex$1,
31507
+ margin: chartMargins
31508
+ }, /*#__PURE__*/React$1.createElement(CartesianGrid, {
31509
+ strokeDasharray: "3 3",
31510
+ vertical: false
31511
+ }), /*#__PURE__*/React$1.createElement(XAxis, {
31512
+ dataKey: "index",
31513
+ type: "number",
31514
+ domain: ['dataMin', 'dataMax'],
31515
+ padding: {
31516
+ left: 20,
31517
+ right: 20
31518
+ },
31519
+ tick: /*#__PURE__*/React$1.createElement(CustomizedTick$1, null),
31520
+ interval: 0 // Force display all ticks
31521
+ ,
31522
+ height: 60,
31523
+ tickLine: false,
31524
+ ticks: dataWithIndex$1.map(item => item.index)
31525
+ }), /*#__PURE__*/React$1.createElement(YAxis, {
31526
+ tickFormatter: v => `$${v / 1000}k`,
31527
+ hide: true
31528
+ }), /*#__PURE__*/React$1.createElement(Tooltip$2, null), /*#__PURE__*/React$1.createElement(Bar, {
31529
+ dataKey: "inc_unit",
31530
+ fill: "#CCDCDD",
31531
+ gap: "4px",
31532
+ borderRadius: [4, 4, 0, 8],
31533
+ barSize: 40,
31534
+ name: "INC Sales"
31535
+ }, /*#__PURE__*/React$1.createElement(LabelList, {
31536
+ dataKey: "inc_unit",
31537
+ position: "top",
31538
+ formatter: value => `$${value / 1000}k`,
31539
+ fill: "#212121",
31540
+ fontSize: 12,
31541
+ fontWeight: "400",
31542
+ fontFamily: "Poppins"
31543
+ })), /*#__PURE__*/React$1.createElement(Brush, {
31544
+ dataKey: "index",
31545
+ height: 30,
31546
+ stroke: "#212121",
31547
+ startIndex: viewWindow.startIndex,
31548
+ endIndex: viewWindow.endIndex,
31549
+ onChange: e => {
31550
+ setViewWindow({
31551
+ startIndex: e.startIndex ?? 0,
31552
+ endIndex: e.endIndex ?? dataWithIndex$1.length - 1
31553
+ });
31554
+ },
31555
+ travellerWidth: 12
31556
+ })), /*#__PURE__*/React$1.createElement("div", {
31557
+ style: {
31558
+ marginTop: "-28px"
31559
+ }
31560
+ }, /*#__PURE__*/React$1.createElement(PerformanceAnalyticsLegend, {
31561
+ legendData: [{
31562
+ iconColor: "#CCDCDD",
31563
+ iconType: "Square",
31564
+ title: "INC Sales"
31565
+ }, {
31566
+ iconColor: "#F8CD00",
31567
+ iconType: "LegendUnionIcon",
31568
+ title: "INC Sales ROI"
31569
+ }]
31570
+ })))));
31571
+ };
31572
+
31573
+ const originalData = [{
31574
+ label: "Vendor Selling Event: Week 28",
31575
+ inc_unit: 20000
31576
+ }, {
31577
+ label: "Vendor Selling Event: Week 29",
31578
+ inc_unit: 10000
31579
+ }, {
31580
+ label: "Vendor Selling Event: Week 30",
31581
+ inc_unit: 8000
31582
+ }, {
31583
+ label: "Vendor Selling Event: Week 33",
31584
+ inc_unit: 12000
31585
+ }, {
31586
+ label: "Vendor Selling Event: Week 36",
31587
+ inc_unit: 8000
31588
+ }, {
31589
+ label: "Vendor Selling Event: Week 34",
31590
+ inc_unit: 8000
31591
+ }, {
31592
+ label: "Vendor Selling Event: Week 35",
31593
+ inc_unit: 8000
31594
+ }, {
31595
+ label: "Vendor Selling Event: Week 38",
31596
+ inc_unit: 9000
31597
+ }];
31598
+
31599
+ // Adding index and shortLabel to original data
31600
+ const dataWithIndex = originalData.map((item, index) => ({
31601
+ ...item,
31602
+ index,
31603
+ shortLabel: item.label.replace("Vendor Selling Event: ", "Wk ")
31604
+ }));
31605
+ const CustomizedTick = ({
31606
+ x,
31607
+ y,
31608
+ payload
31609
+ }) => {
31610
+ const label = dataWithIndex[payload.value]?.label ?? "";
31611
+ const parts = label.replace("Vendor Selling Event: ", "").split(" ");
31612
+ return /*#__PURE__*/React$1.createElement("g", {
31613
+ transform: `translate(${x},${y})`
31614
+ }, /*#__PURE__*/React$1.createElement("text", {
31615
+ x: 0,
31616
+ y: 0,
31617
+ dy: 16,
31618
+ textAnchor: "middle",
31619
+ fill: "#212121",
31620
+ fontSize: 11,
31621
+ fontWeight: "400",
31622
+ fontFamily: "Poppins"
31623
+ }, /*#__PURE__*/React$1.createElement("tspan", {
31624
+ x: 0,
31625
+ dy: 8
31626
+ }, "Vendor Selling"), /*#__PURE__*/React$1.createElement("tspan", {
31627
+ x: 0,
31628
+ dy: 18
31629
+ }, "Event: ", parts.join(" "))));
31630
+ };
31631
+ const SingleChart = () => {
31632
+ const [startIndex, setStartIndex] = useState(0);
31633
+ const [endIndex, setEndIndex] = useState(dataWithIndex.length - 1);
31634
+ dataWithIndex.slice(startIndex, endIndex + 1);
31635
+ return /*#__PURE__*/React$1.createElement("div", {
31636
+ style: {
31637
+ width: "100%",
31638
+ height: 600
31639
+ }
31640
+ }, /*#__PURE__*/React$1.createElement("div", {
31641
+ style: {
31642
+ height: "100%"
31643
+ }
31644
+ }, /*#__PURE__*/React$1.createElement(ResponsiveContainer, {
31645
+ width: "100%",
31646
+ height: "100%"
31647
+ }, /*#__PURE__*/React$1.createElement(ComposedChart, {
31648
+ data: dataWithIndex,
31649
+ margin: {
31650
+ top: 40,
31651
+ right: 40,
31652
+ left: 20,
31653
+ bottom: 40
31654
+ }
31655
+ }, /*#__PURE__*/React$1.createElement(CartesianGrid, {
31656
+ strokeDasharray: "3 3",
31657
+ vertical: false
31658
+ }), /*#__PURE__*/React$1.createElement(XAxis, {
31659
+ dataKey: "index",
31660
+ tick: /*#__PURE__*/React$1.createElement(CustomizedTick, null),
31661
+ interval: 0,
31662
+ height: 60,
31663
+ padding: {
31664
+ left: 20,
31665
+ right: 20
31666
+ },
31667
+ tickLine: false
31668
+ }), /*#__PURE__*/React$1.createElement(YAxis, {
31669
+ tickFormatter: v => `$${v / 1000}k`,
31670
+ hide: true
31671
+ }), /*#__PURE__*/React$1.createElement(Tooltip$2, null), /*#__PURE__*/React$1.createElement(Bar, {
31672
+ dataKey: "inc_unit",
31673
+ fill: "#CCDCDD",
31674
+ gap: "4px",
31675
+ borderRadius: [4, 4, 0, 8],
31676
+ barSize: 40,
31677
+ name: "INC Sales"
31678
+ }, /*#__PURE__*/React$1.createElement(LabelList, {
31679
+ dataKey: "inc_unit",
31680
+ position: "top",
31681
+ formatter: value => `$${value / 1000}k`,
31682
+ fill: "#212121",
31683
+ fontSize: 12,
31684
+ fontWeight: "400",
31685
+ fontFamily: "Poppins"
31686
+ })), /*#__PURE__*/React$1.createElement(Brush, {
31687
+ dataKey: "index",
31688
+ height: 30,
31689
+ stroke: "#212121",
31690
+ startIndex: startIndex,
31691
+ endIndex: endIndex,
31692
+ onChange: e => {
31693
+ setStartIndex(e.startIndex ?? 0);
31694
+ setEndIndex(e.endIndex ?? dataWithIndex.length - 1);
31695
+ },
31696
+ travellerWidth: 12
31697
+ })), /*#__PURE__*/React$1.createElement(PerformanceAnalyticsLegend, {
31698
+ legendData: [{
31699
+ iconColor: "#CCDCDD",
31700
+ iconType: "Square",
31701
+ title: "INC Units"
31702
+ }]
31703
+ }))));
31704
+ };
31705
+
31706
+ styled.div`
31707
+ display: flex;
31708
+ gap: 28px;
31709
+ @media (max-width: 1536px) {
31710
+ gap: 20px;
31711
+ }
31712
+ @media (max-width: 1366px) {
31713
+ gap: 17px;
31714
+ }
31715
+ `;
31716
+ const ButtonsControlsContainer = styled.div`
31717
+ display: flex;
31718
+ font: ${props => props.fontSize?.toString().concat('', 'px Poppins, sans-serif')};
31719
+ margin: 0;
31720
+ --highlight-width: auto;
31721
+ --highlight-x-pos: 0;
31722
+ -webkit-font-smoothing: antialiased;
31723
+ -moz-osx-font-smoothing: grayscale;
31724
+ float: left;
31725
+
31726
+ &:not(:first-of-type) {
31727
+ padding-left: 40px;
31728
+ @media (max-width: 1536px) {
31729
+ padding-left: 35px;
31730
+ }
31731
+ @media (max-width: 1366px) {
31732
+ padding-left: 24px;
31733
+ }
31734
+ }
31735
+ `;
31736
+ const Controls = styled.div`
31737
+ display: inline-flex;
31738
+ justify-content: space-between;
31739
+ background: #f2f2f2;
31740
+ border-radius: ${props => props.controlradius.toString().concat('', 'px')}; //12px
31741
+ // max-width: 500px; //use this to limit max lenght of the control
31742
+ padding: 6px;
31743
+ gap: ${props => props.gap};
31744
+ overflow: hidden;
31745
+ position: relative;
31746
+ &.controls::before {
31747
+ content: "";
31748
+ color: #212121;
31749
+ background: #FFFFFF;
31750
+ box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
31751
+ border-radius: ${props => props.segmentradius.toString().concat('', 'px')};
31752
+ width: var(--highlight-width);
31753
+ transform: translateX(var(--highlight-x-pos));
31754
+ position: absolute;
31755
+ top: 3px;
31756
+ bottom: 3px;
31757
+ left: 0;
31758
+ z-index: 0;
31759
+ }
31760
+ &.controls.ready::before {
31761
+ transition: transform 0.3s ease, width 0.3s ease;
31762
+ }
31763
+ `;
31764
+ const ControlsInput = styled.input`
31765
+ opacity: 0;
31766
+ margin: 0;
31767
+ top: 0;
31768
+ right: 0;
31769
+ bottom: 0;
31770
+ left: 0;
31771
+ position: absolute;
31772
+ width: 100%;
31773
+ cursor: pointer;
31774
+ height: 100%;
31775
+ `;
31776
+ const Segment = styled.div`
31777
+ /* width: 100%; uncomment for each segment to have matching width */
31778
+ width: 50%;
31779
+ min-width: ${props => props.segmentwidth.toString().concat('', 'px')}; //120px;
31780
+ position: relative;
31781
+ text-align: center;
31782
+ z-index: 1;
31783
+ `;
31784
+ const SegmentLabel = styled.label`
31785
+ cursor: pointer;
31786
+ display: block;
31787
+ padding: 0 6px;
31788
+ transition: color 0.5s ease;
31789
+ &.active {
31790
+ color: ${props => props.selectedtextcolor};
31791
+ }
31792
+ &.inactive {
31793
+ color: ${props => props.unselectedtextcolor};
31794
+ }
31795
+ `;
31796
+
31797
+ /* eslint-disable react/require-default-props */
31798
+
31799
+ /* SegmentedButton */
31800
+ const SegmentedButton = props => {
31801
+ const {
31802
+ name,
31803
+ options,
31804
+ width,
31805
+ height,
31806
+ controlradius,
31807
+ segmentradius,
31808
+ fontSize,
31809
+ selectedsegmentcolor,
31810
+ selectedtextcolor,
31811
+ unselectedtextcolor,
31812
+ defaultIndex,
31813
+ onClick,
31814
+ gap
31815
+ } = props;
31816
+ const [activeIndex, setActiveIndex] = useState(defaultIndex);
31817
+ const controlRef = useRef();
31818
+ const componentReady = useRef();
31819
+ const optionsRef = options?.map((item, i) => ({
31820
+ ...item,
31821
+ id: i,
31822
+ ref: useRef()
31823
+ }));
31824
+
31825
+ // Determine when the component is "ready"
31826
+ useEffect(() => {
31827
+ componentReady.current = true;
31828
+ }, []);
31829
+ useEffect(() => {
31830
+ if (defaultIndex >= 0 && defaultIndex < options?.length) {
31831
+ setActiveIndex(defaultIndex);
31832
+ }
31833
+ }, [defaultIndex]);
31834
+ useEffect(() => {
31835
+ const activeSegmentRef = optionsRef[activeIndex].ref;
31836
+ const {
31837
+ offsetWidth,
31838
+ offsetLeft
31839
+ } = activeSegmentRef.current;
31840
+ const {
31841
+ style
31842
+ } = controlRef.current;
31843
+ style.setProperty('--highlight-width', `${offsetWidth}px`);
31844
+ style.setProperty('--highlight-x-pos', `${offsetLeft}px`);
31845
+ }, [activeIndex, controlRef, optionsRef]);
31846
+ const onInputChangeHandler = (value, index) => {
31847
+ setActiveIndex(index);
31848
+ onClick({
31849
+ index,
31850
+ value
31851
+ });
31852
+ };
31853
+ let segmentwidth = 120;
31854
+ if (options && options.length > 0 && width && width > 0) {
31855
+ segmentwidth = width / options.length;
31856
+ }
31857
+ return /*#__PURE__*/React$1.createElement(ButtonsControlsContainer, {
31858
+ fontSize: fontSize,
31859
+ ref: controlRef
31860
+ }, /*#__PURE__*/React$1.createElement(Controls, {
31861
+ id: "Controls",
31862
+ selectedsegmentcolor: selectedsegmentcolor,
31863
+ segmentradius: segmentradius,
31864
+ gap: gap,
31865
+ controlradius: controlradius,
31866
+ segmentwidth: segmentwidth,
31867
+ className: `controls ${componentReady.current ? 'ready' : 'idle'}`
31868
+ }, optionsRef?.map((item, i) => /*#__PURE__*/React$1.createElement(Segment, {
31869
+ id: "Segment",
31870
+ key: item.id,
31871
+ selectedsegmentcolor: selectedsegmentcolor,
31872
+ controlradius: controlradius,
31873
+ segmentwidth: segmentwidth,
31874
+ className: `${activeIndex === i ? 'active' : 'inactive'}`,
31875
+ ref: item.ref
31876
+ }, /*#__PURE__*/React$1.createElement(ControlsInput, {
31877
+ type: "radio",
31878
+ value: item.value,
31879
+ id: item.id,
31880
+ name: name,
31881
+ onChange: () => onInputChangeHandler(item.value, item.id),
31882
+ checked: i === activeIndex
31883
+ }), /*#__PURE__*/React$1.createElement(SegmentLabel, {
31884
+ id: "SegmentLabel",
31885
+ selectedtextcolor: selectedtextcolor,
31886
+ unselectedtextcolor: unselectedtextcolor,
31887
+ segmentheight: height / 5,
31888
+ className: `${activeIndex === i ? 'active' : 'inactive'} `,
31889
+ htmlFor: item.value
31890
+ }, item.value)))));
31891
+ };
31892
+ SegmentedButton.propTypes = {
31893
+ name: PropTypes.string,
31894
+ options: PropTypes.arrayOf(PropTypes.shape({
31895
+ value: PropTypes.string
31896
+ })),
31897
+ width: PropTypes.number,
31898
+ height: PropTypes.number,
31899
+ controlradius: PropTypes.number,
31900
+ segmentradius: PropTypes.number,
31901
+ gap: PropTypes.string,
31902
+ fontSize: PropTypes.number,
31903
+ selectedsegmentcolor: PropTypes.string,
31904
+ selectedtextcolor: PropTypes.string,
31905
+ unselectedtextcolor: PropTypes.string,
31906
+ defaultIndex: PropTypes.number,
31907
+ onClick: PropTypes.func
31908
+ };
31909
+ SegmentedButton.defaultProps = {
31910
+ name: '',
31911
+ options: [{
31912
+ value: '4 w'
31913
+ }, {
31914
+ value: '8 w'
31915
+ }, {
31916
+ value: '13 w'
31917
+ }],
31918
+ width: 120,
31919
+ height: 40,
31920
+ controlradius: 8,
31921
+ segmentradius: 8,
31922
+ gap: '0px',
31923
+ fontSize: 14,
31924
+ selectedsegmentcolor: '#3a9df9',
31925
+ selectedtextcolor: '#212121',
31926
+ unselectedtextcolor: 'black',
31927
+ defaultIndex: 0,
31928
+ onClick: () => {}
31929
+ };
31930
+
31931
+ var css_248z = ".BarLine {\r\n font-family: sans-serif;\r\n text-align: center;\r\n }\r\n \r\n /* Make brush background darker */\r\n /* .recharts-brush .recharts-brush-slide {\r\n fill: #a52a2a !important;\r\n stroke: none;\r\n }\r\n \r\n /* Style draggable handles (travellers) */\r\n /* .recharts-brush-traveller {\r\n fill: limegreen !important; /* bright green like in the image */\r\n /* cursor: ew-resize;\r\n } */\r\n */\r\n \r\n /* Optional: center grip arrows (you can fake it with CSS) */\r\n /* .recharts-brush .recharts-brush-traveller > rect {\r\n rx: 2;\r\n ry: 2;\r\n width: 6;\r\n fill: #a52a2a !important; /* dark gray */\r\n /* } */ */\r\n */\r\n \r\n /* Remove tick labels if needed */\r\n .recharts-brush .recharts-layer text {\r\n display: none;\r\n }\r\n ";
31932
+ styleInject(css_248z);
31933
+
31934
+ function InnerBarChart() {
31935
+ const data = [{
31936
+ week: "Week 28",
31937
+ total: 20000,
31938
+ actual: 4000
31939
+ }, {
31940
+ week: "Week 29",
31941
+ total: 10000,
31942
+ actual: 8000
31943
+ }, {
31944
+ week: "Week 30",
31945
+ total: 8000,
31946
+ actual: 950
31947
+ }, {
31948
+ week: "Week 33",
31949
+ total: 12000,
31950
+ actual: 1000
31951
+ }, {
31952
+ week: "Week 36",
31953
+ total: 16000,
31954
+ actual: 13000
31955
+ }, {
31956
+ week: "Week 34",
31957
+ total: 30000,
31958
+ actual: 3000
31959
+ }, {
31960
+ week: "Week 35",
31961
+ total: 8000,
31962
+ actual: 950
31963
+ }, {
31964
+ week: "Week 37",
31965
+ total: 9000,
31966
+ actual: 3000
31967
+ }];
31968
+ const originalData = [{
31969
+ label: "Vendor Selling Event: Week 28",
31970
+ inc_unit: 20000,
31971
+ inc_roi: 1.2
31972
+ }, {
31973
+ label: "Vendor Selling Event: Week 29",
31974
+ inc_unit: 10000,
31975
+ inc_roi: 1.2
31976
+ }, {
31977
+ label: "Vendor Selling Event: Week 30",
31978
+ inc_unit: 8000,
31979
+ inc_roi: 0.8
31980
+ }, {
31981
+ label: "Vendor Selling Event: Week 33",
31982
+ inc_unit: 12000,
31983
+ inc_roi: 1.1
31984
+ }, {
31985
+ label: "Vendor Selling Event: Week 36",
31986
+ inc_unit: 8000,
31987
+ inc_roi: 1.2
31988
+ }, {
31989
+ label: "Vendor Selling Event: Week 34",
31990
+ inc_unit: 8000,
31991
+ inc_roi: 0.7
31992
+ }, {
31993
+ label: "Vendor Selling Event: Week 35",
31994
+ inc_unit: 8000,
31995
+ inc_roi: 0.8
31996
+ }, {
31997
+ label: "Vendor Selling Event: Week 38",
31998
+ inc_unit: 9000,
31999
+ inc_roi: 1.1
32000
+ }];
32001
+ const format = v => v >= 1000 ? `${v / 1000}K` : v;
32002
+ const CustomBarLabel = ({
32003
+ x,
32004
+ y,
32005
+ width,
32006
+ payload
32007
+ }) => {
32008
+ if (!payload || typeof payload.total === "undefined") {
32009
+ console.error("Invalid payload:", payload);
32010
+ return null;
32011
+ }
32012
+ const centerX = x + width / 2;
32013
+ return /*#__PURE__*/React$1.createElement("text", {
32014
+ x: centerX,
32015
+ y: Math.max(y - 8, 10),
32016
+ textAnchor: "middle",
32017
+ fill: "black"
32018
+ }, format(payload.total));
32019
+ };
32020
+ const BarWithInner = props => {
32021
+ const {
32022
+ x,
32023
+ y,
32024
+ width,
32025
+ height,
32026
+ payload
32027
+ } = props;
32028
+ const totalHeight = height;
32029
+ const actualRatio = payload.actual / payload.total;
32030
+ const innerHeight = totalHeight * actualRatio;
32031
+ const innerY = y + (totalHeight - innerHeight);
32032
+ return /*#__PURE__*/React$1.createElement("g", null, /*#__PURE__*/React$1.createElement("rect", {
32033
+ x: x,
32034
+ y: y,
32035
+ width: width,
32036
+ height: height,
32037
+ fill: "#d0e6ea",
32038
+ rx: 4,
32039
+ ry: 4
32040
+ }), /*#__PURE__*/React$1.createElement("text", {
32041
+ x: x + width / 2,
32042
+ y: y - 8,
32043
+ textAnchor: "middle",
32044
+ fontSize: 11,
32045
+ fontWeight: 400,
32046
+ fontFamily: "Poppins",
32047
+ fill: "#212121"
32048
+ }, format(payload.total)), /*#__PURE__*/React$1.createElement("rect", {
32049
+ x: x + width * 0.2,
32050
+ y: innerY,
32051
+ width: width * 0.6,
32052
+ height: innerHeight,
32053
+ fill: "#07575b",
32054
+ rx: 2,
32055
+ ry: 2
32056
+ }), innerHeight > 16 && /*#__PURE__*/React$1.createElement("text", {
32057
+ x: x + width / 2,
32058
+ y: innerY - 6,
32059
+ textAnchor: "middle",
32060
+ fontSize: 11,
32061
+ fontWeight: 400,
32062
+ fontFamily: "Poppins",
32063
+ fill: "#212121"
32064
+ }, format(payload.actual)));
32065
+ };
32066
+ const CustomTooltip = ({
32067
+ active,
32068
+ payload,
32069
+ label
32070
+ }) => {
32071
+ if (!active || !payload || !payload.length) return null;
32072
+ const data = payload[0].payload;
32073
+ return /*#__PURE__*/React$1.createElement("div", {
32074
+ style: {
32075
+ background: "white",
32076
+ border: "1px solid #ccc",
32077
+ padding: "10px",
32078
+ borderRadius: "8px",
32079
+ fontSize: "14px"
32080
+ }
32081
+ }, /*#__PURE__*/React$1.createElement("strong", null, label), /*#__PURE__*/React$1.createElement("div", null, "Actual: ", format(data.actual)), /*#__PURE__*/React$1.createElement("div", null, "Total: ", format(data.total)));
32082
+ };
32083
+ const dataWithIndex = originalData.map((item, index) => ({
32084
+ ...item,
32085
+ index,
32086
+ shortLabel: item.label.replace("Vendor Selling Event: ", "Wk ")
32087
+ }));
32088
+ const CustomizedTick = ({
32089
+ x,
32090
+ y,
32091
+ payload
32092
+ }) => {
32093
+ const label = dataWithIndex[payload.value]?.label ?? "";
32094
+ const parts = label.replace("Vendor Selling Event: ", "").split(" ");
32095
+ return /*#__PURE__*/React$1.createElement("g", {
32096
+ transform: `translate(${x},${y})`
32097
+ }, /*#__PURE__*/React$1.createElement("text", {
32098
+ x: 0,
32099
+ y: 0,
32100
+ dy: 16,
32101
+ textAnchor: "middle",
32102
+ fill: "#212121",
32103
+ fontSize: 11,
32104
+ fontWeight: "400",
32105
+ fontFamily: "Poppins"
32106
+ }, /*#__PURE__*/React$1.createElement("tspan", {
32107
+ x: 0,
32108
+ dy: 8
32109
+ }, "Vendor Selling"), /*#__PURE__*/React$1.createElement("tspan", {
32110
+ x: 0,
32111
+ dy: 18
32112
+ }, "Event: ", parts.join(" "))));
32113
+ };
32114
+ return /*#__PURE__*/React$1.createElement(ResponsiveContainer, {
32115
+ width: "100%",
32116
+ height: 400
32117
+ }, /*#__PURE__*/React$1.createElement(BarChart$1, {
32118
+ data: data,
32119
+ margin: {
32120
+ top: 20,
32121
+ right: 30,
32122
+ left: 20,
32123
+ bottom: 10
32124
+ }
32125
+ }, /*#__PURE__*/React$1.createElement(CartesianGrid, {
32126
+ strokeDasharray: "3 3",
32127
+ vertical: false
32128
+ }), /*#__PURE__*/React$1.createElement(XAxis, {
32129
+ dataKey: "week",
32130
+ tick: /*#__PURE__*/React$1.createElement(CustomizedTick, null)
32131
+ }), /*#__PURE__*/React$1.createElement(YAxis, {
32132
+ type: "number",
32133
+ domain: [0, "dataMax + 2000"],
32134
+ hide: true
32135
+ }), /*#__PURE__*/React$1.createElement(Tooltip$2, {
32136
+ content: /*#__PURE__*/React$1.createElement(CustomTooltip, null)
32137
+ }), /*#__PURE__*/React$1.createElement(Brush, {
32138
+ height: 30,
32139
+ travellerWidth: 10,
32140
+ startIndex: 1,
32141
+ endIndex: 5,
32142
+ y: 369
32143
+ }), /*#__PURE__*/React$1.createElement(Bar, {
32144
+ dataKey: "total",
32145
+ shape: /*#__PURE__*/React$1.createElement(BarWithInner, null),
32146
+ label: /*#__PURE__*/React$1.createElement(CustomBarLabel, null),
32147
+ barSize: 30
32148
+ })));
32149
+ }
32150
+
32151
+ styled.div`
32152
+ font-family: sans-serif;
32153
+ text-align: center;
32154
+ `;
32155
+ styled.div`
32156
+ height: 25%;
32157
+ `;
32158
+ styled.div`
32159
+ height: 75%;
32160
+ `;
32161
+ styled.div`
32162
+ height: 100%;
32163
+ display: flex;
32164
+ flex-direction: column;
32165
+ background-color: white;
32166
+ `;
32167
+ const Container = styled.div`
32168
+ width: 100%;
32169
+ height: 100%;
32170
+ display: flex;
32171
+ flex-direction: column;
32172
+ #Segment {
32173
+ width: auto;
32174
+ white-space: nowrap;
32175
+ font-size: 14px;
32176
+ font-weight: 500;
32177
+ font-family: "Poppins"
32178
+ }
32179
+ `;
32180
+ /* Make brush background darker */
32181
+ /* .recharts-brush .recharts-brush-slide {
32182
+ fill: #a52a2a !important;
32183
+ stroke: none;
32184
+ }
32185
+
32186
+ /* Style draggable handles (travellers) */
32187
+ /* .recharts-brush-traveller {
32188
+ fill: limegreen !important; /* bright green like in the image */
32189
+ /* cursor: ew-resize;
32190
+ } */
32191
+
32192
+ /* Optional: center grip arrows (you can fake it with CSS) */
32193
+ /* .recharts-brush .recharts-brush-traveller > rect {
32194
+ rx: 2;
32195
+ ry: 2;
32196
+ width: 6;
32197
+ fill: #a52a2a !important; /* dark gray */
32198
+ /* } */
32199
+
32200
+ /* Remove tick labels if needed */
32201
+ // .recharts-brush .recharts-layer text {
32202
+ // display: none;
32203
+ // }
32204
+
32205
+ const BrushChart = () => {
32206
+ const segmentedbuttonOptions = ["New Shoppers & Repeaters", "INC Sales & ROI", "INC Units", "Basket Lift"];
32207
+ const [selectedOption, setSelectedOption] = useState(segmentedbuttonOptions[0]);
32208
+ return /*#__PURE__*/React$1.createElement(Container, null, /*#__PURE__*/React$1.createElement(SegmentedButton, {
32209
+ gap: '8px',
32210
+ options: segmentedbuttonOptions.map(value => ({
32211
+ value
32212
+ })),
32213
+ onClick: _ref => {
32214
+ let {
32215
+ value
32216
+ } = _ref;
32217
+ return setSelectedOption(value);
32218
+ }
32219
+ }), selectedOption === "New Shoppers & Repeaters" && /*#__PURE__*/React$1.createElement(InnerBarChart, null), selectedOption === "INC Sales & ROI" && /*#__PURE__*/React$1.createElement(SeparatedLineBarChart, null), selectedOption === "INC Units" && /*#__PURE__*/React$1.createElement(SingleChart, null), selectedOption === "Basket Lift" && /*#__PURE__*/React$1.createElement(SingleChart, null));
30414
32220
  };
30415
32221
 
30416
- export { AreaChart, BannerEventBoxList, BarChart, BarChartsByWeeks, BatteryChart, BreakdownPanel, Button, CollapseHeader, DialogOverlay, DoubleBarSingleLine, DoublePanelDataRow, EventDetailsCard, EventList, FilterPanel, Heatmap, IconButton, LinkButton, LinnerDataBox, MarketShareDescription, OneColumnContainer, PerformanceAnalyticsLegend, PieChart, PopupCharts, QuickFilter, ReportTable, TabMenu, TopToggleList, TotalDoughnutChart, TotalHorizontalCharts };
32222
+ export { AreaChart, BannerEventBoxList, BarChart, BarChartsByWeeks, BatteryChart, BreakdownPanel, BrushChart, BubbleChart, Button, CollapseHeader, DialogOverlay, DoubleBarSingleLine, DoublePanelDataRow, EventDetailsCard, EventList, FilterPanel, Heatmap, IconButton, LinkButton, LinnerDataBox, MarketShareDescription, OneColumnContainer, PerformanceAnalyticsLegend, PieChart, PopupCharts, QuickFilter, ReportTable, TabMenu, TopToggleList, TotalDoughnutChart, TotalHorizontalCharts };
30417
32223
  //# sourceMappingURL=index.esm.js.map