@servicetitan/marketing-ui 1.3.0 → 1.6.1

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.
Files changed (60) hide show
  1. package/dist/components/charts/line-chart/components/body.d.ts.map +1 -1
  2. package/dist/components/charts/line-chart/components/body.js +6 -7
  3. package/dist/components/charts/line-chart/components/body.js.map +1 -1
  4. package/dist/components/charts/line-chart/components/body.module.less +0 -1
  5. package/dist/components/charts/line-chart/components/hover-popover.d.ts.map +1 -1
  6. package/dist/components/charts/line-chart/components/hover-popover.js +4 -1
  7. package/dist/components/charts/line-chart/components/hover-popover.js.map +1 -1
  8. package/dist/components/charts/line-chart/components/hover-popover.module.less +0 -1
  9. package/dist/components/charts/line-chart/components/sidebar.d.ts +1 -1
  10. package/dist/components/charts/line-chart/components/sidebar.d.ts.map +1 -1
  11. package/dist/components/charts/line-chart/components/sidebar.js +3 -3
  12. package/dist/components/charts/line-chart/components/sidebar.js.map +1 -1
  13. package/dist/components/charts/line-chart/components/sidebar.module.less +7 -3
  14. package/dist/components/charts/line-chart/components/stuff.d.ts +6 -0
  15. package/dist/components/charts/line-chart/components/stuff.d.ts.map +1 -1
  16. package/dist/components/charts/line-chart/components/stuff.js +62 -5
  17. package/dist/components/charts/line-chart/components/stuff.js.map +1 -1
  18. package/dist/components/charts/line-chart/components/stuff.module.less +12 -3
  19. package/dist/components/charts/line-chart/components/svg-bars.d.ts +1 -0
  20. package/dist/components/charts/line-chart/components/svg-bars.d.ts.map +1 -1
  21. package/dist/components/charts/line-chart/components/svg-bars.js +15 -7
  22. package/dist/components/charts/line-chart/components/svg-bars.js.map +1 -1
  23. package/dist/components/charts/line-chart/components/svg-body.d.ts.map +1 -1
  24. package/dist/components/charts/line-chart/components/svg-body.js +2 -1
  25. package/dist/components/charts/line-chart/components/svg-body.js.map +1 -1
  26. package/dist/components/charts/line-chart/components/svg.module.less +0 -1
  27. package/dist/components/charts/line-chart/line-chart.stories.d.ts +4 -1
  28. package/dist/components/charts/line-chart/line-chart.stories.d.ts.map +1 -1
  29. package/dist/components/charts/line-chart/line-chart.stories.js +113 -2
  30. package/dist/components/charts/line-chart/line-chart.stories.js.map +1 -1
  31. package/dist/components/charts/line-chart/stores/line-chart.store.d.ts.map +1 -1
  32. package/dist/components/charts/line-chart/stores/line-chart.store.js +21 -6
  33. package/dist/components/charts/line-chart/stores/line-chart.store.js.map +1 -1
  34. package/dist/components/charts/line-chart/stores/svg.store.js +1 -1
  35. package/dist/components/charts/line-chart/stores/svg.store.js.map +1 -1
  36. package/dist/components/charts/line-chart/utils/interfaces.d.ts +1 -1
  37. package/dist/components/charts/line-chart/utils/interfaces.d.ts.map +1 -1
  38. package/dist/components/charts/line-chart/utils/internal-interfaces.d.ts +1 -0
  39. package/dist/components/charts/line-chart/utils/internal-interfaces.d.ts.map +1 -1
  40. package/dist/utils/formatters.js +1 -1
  41. package/package.json +2 -2
  42. package/src/components/charts/line-chart/components/body.module.less +0 -1
  43. package/src/components/charts/line-chart/components/body.tsx +23 -28
  44. package/src/components/charts/line-chart/components/hover-popover.module.less +0 -1
  45. package/src/components/charts/line-chart/components/hover-popover.tsx +1 -0
  46. package/src/components/charts/line-chart/components/sidebar.module.less +7 -3
  47. package/src/components/charts/line-chart/components/sidebar.tsx +17 -16
  48. package/src/components/charts/line-chart/components/stuff.module.less +12 -3
  49. package/src/components/charts/line-chart/components/stuff.module.less.d.ts +2 -0
  50. package/src/components/charts/line-chart/components/stuff.tsx +104 -17
  51. package/src/components/charts/line-chart/components/svg-bars.tsx +37 -19
  52. package/src/components/charts/line-chart/components/svg-body.tsx +8 -0
  53. package/src/components/charts/line-chart/components/svg.module.less +0 -1
  54. package/src/components/charts/line-chart/line-chart.stories.tsx +159 -1
  55. package/src/components/charts/line-chart/stores/line-chart.store.ts +26 -6
  56. package/src/components/charts/line-chart/stores/svg.store.ts +1 -1
  57. package/src/components/charts/line-chart/utils/interfaces.ts +1 -1
  58. package/src/components/charts/line-chart/utils/internal-interfaces.ts +1 -0
  59. package/src/utils/__tests__/formatters.test.ts +1 -1
  60. package/src/utils/formatters.ts +1 -1
@@ -42,6 +42,7 @@ interface SvgBodyProps {
42
42
  export const SvgBody: React.FC<SvgBodyProps> = observer(({ horizontalGrid, metrics }) => {
43
43
  const [{ key }] = useDependencies(SvgStore);
44
44
  const barMetrics = metrics.filter(m => m.type === 'bar');
45
+ const stackedBarMetrics = metrics.filter(m => m.type === 'stacked-bar');
45
46
  const lineMetrics = metrics.filter(m => m.type === 'line');
46
47
 
47
48
  return (
@@ -53,6 +54,13 @@ export const SvgBody: React.FC<SvgBodyProps> = observer(({ horizontalGrid, metri
53
54
  >
54
55
  {horizontalGrid && <SvgGrid />}
55
56
  {!!barMetrics.length && <SvgBars key={keyVal('bars', key)} metrics={barMetrics} />}
57
+ {!!stackedBarMetrics.length && (
58
+ <SvgBars
59
+ key={keyVal('stacked-bars', key)}
60
+ metrics={stackedBarMetrics}
61
+ isStackedBarChart
62
+ />
63
+ )}
56
64
  {!!lineMetrics.length && <SvgLines key={keyVal('lines', key)} metrics={lineMetrics} />}
57
65
  </svg>
58
66
  );
@@ -2,7 +2,6 @@
2
2
 
3
3
  .svg-hover {
4
4
  position: absolute;
5
- z-index: @z-index-global-nav;
6
5
  inset: 0;
7
6
  height: 100%;
8
7
  width: 100%;
@@ -1,4 +1,5 @@
1
- import React from 'react';
1
+ import React, { FC, useState } from 'react';
2
+ import { Form } from '@servicetitan/design-system';
2
3
  import { LineChart, LineChartPeriod } from './index';
3
4
 
4
5
  export default {
@@ -33,6 +34,36 @@ const dailyValues = (() => {
33
34
  };
34
35
  })();
35
36
 
37
+ const stackedBarChartValues = (() => {
38
+ const periods: LineChartPeriod[] = [];
39
+ const days = new Date(2021, 7, 0).getDate();
40
+
41
+ for (let i = 1; i <= days; i++) {
42
+ periods.push({
43
+ from: new Date(2021, 7, i),
44
+ to: new Date(2021, 7, i + 1),
45
+ });
46
+ }
47
+
48
+ return {
49
+ periods,
50
+ values: [
51
+ {
52
+ metricId: 2,
53
+ values: periods.map((_, index) => 15 + (index % 5) * 15),
54
+ },
55
+ {
56
+ metricId: 3,
57
+ values: periods.map((_, index) => 10 + (index % 5) * 10),
58
+ },
59
+ {
60
+ metricId: 4,
61
+ values: periods.map((_, index) => 5 + (index % 5) * 5),
62
+ },
63
+ ],
64
+ };
65
+ })();
66
+
36
67
  const weeklyValues = (() => {
37
68
  const periods: LineChartPeriod[] = [];
38
69
 
@@ -73,10 +104,12 @@ export const lineChartDailyBottomTitles = () => (
73
104
  title: 'Budget',
74
105
  type: 'line',
75
106
  opts: { dashed: true },
107
+ isRight: true,
76
108
  },
77
109
  ]}
78
110
  metricValues={dailyValues.values}
79
111
  periods={dailyValues.periods}
112
+ titleY="Left title"
80
113
  display={{
81
114
  yLeft: false,
82
115
  yLeftFormat: 'money',
@@ -85,6 +118,42 @@ export const lineChartDailyBottomTitles = () => (
85
118
  />
86
119
  );
87
120
 
121
+ export const stackedBarChartDailyBottomTitles = () => {
122
+ return (
123
+ <LineChart
124
+ resolution="day"
125
+ metrics={[
126
+ {
127
+ id: 2,
128
+ title: 'Lead Calls',
129
+ type: 'stacked-bar',
130
+ color: '#D0D8DD',
131
+ },
132
+ {
133
+ id: 3,
134
+ title: 'Online Bookings',
135
+ type: 'stacked-bar',
136
+ color: '#08BFDF',
137
+ },
138
+ {
139
+ id: 4,
140
+ title: 'Manual Calls',
141
+ type: 'stacked-bar',
142
+ color: '#1FBC70',
143
+ },
144
+ ]}
145
+ metricValues={stackedBarChartValues.values}
146
+ periods={dailyValues.periods}
147
+ titleY="Left title"
148
+ display={{
149
+ yLeft: false,
150
+ yLeftFormat: 'number',
151
+ metricsTitlePosition: 'bottom',
152
+ }}
153
+ />
154
+ );
155
+ };
156
+
88
157
  export const lineChartWeekly = () => (
89
158
  <LineChart
90
159
  resolution="week"
@@ -113,3 +182,92 @@ export const lineChartWeekly = () => (
113
182
  }}
114
183
  />
115
184
  );
185
+
186
+ const CountrySelect = () => {
187
+ const [value, setValue] = useState<any>();
188
+ const options = [
189
+ { key: 1, group: 'Arcona', value: 1, text: 'Australia' },
190
+ { key: 2, group: 'Arcona', value: 2, text: 'America' },
191
+ { key: 3, group: 'Arcona', value: 3, text: 'New Zealand' },
192
+ { key: 4, group: 'Ewok', value: 4, text: 'Spain' },
193
+ { key: 5, group: 'Gungan', value: 5, text: 'Turkey' },
194
+ { key: 6, group: 'Gungan', value: 6, text: 'India' },
195
+ ];
196
+
197
+ return (
198
+ <Form.Select
199
+ width="4"
200
+ open
201
+ grouped
202
+ label="Clearable select with groups"
203
+ placeholder="Choose Country"
204
+ options={options}
205
+ onChange={(event, value) => setValue(value.value)}
206
+ value={value}
207
+ />
208
+ );
209
+ };
210
+
211
+ export const lineChartMergedDays: FC = () => (
212
+ <div style={{ width: '800px' }}>
213
+ <LineChart
214
+ resolution="week"
215
+ metrics={[
216
+ {
217
+ id: 1,
218
+ color: '#60dfa6',
219
+ title: 'Revenue',
220
+ type: 'bar',
221
+ },
222
+ {
223
+ id: 2,
224
+ color: '#737475',
225
+ title: 'Numbers',
226
+ type: 'line',
227
+ isRight: true,
228
+ },
229
+ ]}
230
+ metricValues={weeklyValues.values}
231
+ periods={weeklyValues.periods}
232
+ titleY="Left title"
233
+ display={{
234
+ yLeft: true,
235
+ yRight: true,
236
+ yLeftFormat: 'moneyShort',
237
+ metricsTitlePosition: 'top',
238
+ }}
239
+ />
240
+ </div>
241
+ );
242
+
243
+ export const lineChartIndexes: FC = () => (
244
+ <div>
245
+ <CountrySelect />
246
+ <LineChart
247
+ resolution="week"
248
+ metrics={[
249
+ {
250
+ id: 1,
251
+ color: '#60dfa6',
252
+ title: 'Revenue',
253
+ type: 'bar',
254
+ },
255
+ {
256
+ id: 2,
257
+ color: '#737475',
258
+ title: 'Numbers',
259
+ type: 'line',
260
+ isRight: true,
261
+ },
262
+ ]}
263
+ metricValues={weeklyValues.values}
264
+ periods={weeklyValues.periods}
265
+ display={{
266
+ yLeft: true,
267
+ yRight: true,
268
+ yLeftFormat: 'moneyShort',
269
+ metricsTitlePosition: 'top',
270
+ }}
271
+ />
272
+ </div>
273
+ );
@@ -13,18 +13,22 @@ import { ChartMetric, SideMetricsSettings } from '../utils/internal-interfaces';
13
13
  import { getFormatter } from '../utils/formatters';
14
14
 
15
15
  const getSideMetricsSettings = (
16
- ids: number[],
16
+ metrics: ChartMetric[],
17
17
  values: LineChartMetricValues[],
18
18
  range?: number,
19
19
  title?: string,
20
20
  format?: LineChartDisplayValueFormat
21
21
  ): SideMetricsSettings | undefined => {
22
22
  let maxRange = range ?? 0;
23
+ const lineBarMetricIDs = metrics
24
+ .filter(m => m.type === 'line' || m.type === 'bar')
25
+ .map(m => m.id);
26
+ const stackedBarMetricIDs = metrics.filter(m => m.type === 'stacked-bar').map(m => m.id);
23
27
 
24
28
  if (!maxRange) {
25
29
  maxRange = values.reduce(
26
30
  (sum, metricValues) =>
27
- ids.includes(metricValues.metricId)
31
+ lineBarMetricIDs.includes(metricValues.metricId)
28
32
  ? Math.max(
29
33
  sum,
30
34
  metricValues.values.reduce((acc, v) => Math.max(acc, v), 0)
@@ -34,8 +38,22 @@ const getSideMetricsSettings = (
34
38
  );
35
39
  }
36
40
 
41
+ if (stackedBarMetricIDs.length) {
42
+ const stackChartMetricValues = values
43
+ .filter(metricValues => stackedBarMetricIDs.includes(metricValues.metricId))
44
+ .map(metric => metric.values);
45
+
46
+ const summedStackedMetrics = stackChartMetricValues[0]?.map((value, i) =>
47
+ stackChartMetricValues.reduce((sum, metricValues) => sum + metricValues[i], 0)
48
+ );
49
+
50
+ if (summedStackedMetrics?.length) {
51
+ maxRange = Math.max(...summedStackedMetrics, maxRange);
52
+ }
53
+ }
54
+
37
55
  if (!maxRange) {
38
- if (!ids.length) {
56
+ if (!lineBarMetricIDs.length && !stackedBarMetricIDs.length) {
39
57
  return undefined;
40
58
  }
41
59
 
@@ -56,7 +74,9 @@ const getSideMetricsSettings = (
56
74
  sums.push(formatter(maxRange - i * step));
57
75
  }
58
76
 
59
- return { maxRange, maxValue: 1.1 * maxRange, title: title ?? '', values: sums };
77
+ const width = title ? 64 : 48;
78
+
79
+ return { maxRange, maxValue: 1.1 * maxRange, title: title ?? '', values: sums, width };
60
80
  };
61
81
 
62
82
  @injectable()
@@ -96,14 +116,14 @@ export class LineChartStore {
96
116
  });
97
117
 
98
118
  this.left = getSideMetricsSettings(
99
- this.metrics.filter(m => !m.isRight).map(m => m.id),
119
+ this.metrics.filter(m => !m.isRight),
100
120
  props.metricValues,
101
121
  props.maxRange,
102
122
  props.titleY,
103
123
  this.display.yLeftFormat
104
124
  );
105
125
  this.right = getSideMetricsSettings(
106
- this.metrics.filter(m => m.isRight).map(m => m.id),
126
+ this.metrics.filter(m => m.isRight),
107
127
  props.metricValues,
108
128
  props.maxRangeRight,
109
129
  props.titleYRight,
@@ -29,7 +29,7 @@ export class SvgStore {
29
29
  this.length = length || 1;
30
30
  this.key = Date.now();
31
31
 
32
- const hasBars = !!metrics.filter(m => m.type === 'bar').length;
32
+ const hasBars = !!metrics.filter(m => m.type === 'bar' || m.type === 'stacked-bar').length;
33
33
 
34
34
  if (hasBars) {
35
35
  this.fullBarWidth = 100 / this.length;
@@ -1,7 +1,7 @@
1
1
  import React from 'react';
2
2
 
3
3
  export type LineChartResolution = 'hour' | 'day' | 'week' | 'month';
4
- export type LineChartMetricType = 'line' | 'bar';
4
+ export type LineChartMetricType = 'line' | 'bar' | 'stacked-bar';
5
5
  export type LineChartMetricsTitlePosition = 'top' | 'top-right' | 'bottom';
6
6
 
7
7
  export interface LineChartMetricOpts {
@@ -5,6 +5,7 @@ export interface SideMetricsSettings {
5
5
  maxValue: number;
6
6
  title: string;
7
7
  values: string[];
8
+ width: number;
8
9
  }
9
10
 
10
11
  export interface ChartMetric {
@@ -35,7 +35,7 @@ describe('formatPercent', () => {
35
35
  [0, '0%'],
36
36
  [0.1, '10%'],
37
37
  [0.0011, '0.1%'],
38
- [0.9999, '99%'],
38
+ [0.9999, '100%'],
39
39
  ];
40
40
 
41
41
  tc.map(([value, result]) =>
@@ -7,7 +7,7 @@ const formatPercentValue = (value: number): string => {
7
7
  return '0';
8
8
  }
9
9
 
10
- const valueMain = value ? Math.abs(Math.floor(value)) : 0;
10
+ const valueMain = value ? Math.abs(Math.round(value)) : 0;
11
11
 
12
12
  if (valueMain > 0) {
13
13
  return accounting.formatNumber(valueMain, 0);