@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.
- package/dist/components/charts/line-chart/components/body.d.ts.map +1 -1
- package/dist/components/charts/line-chart/components/body.js +6 -7
- package/dist/components/charts/line-chart/components/body.js.map +1 -1
- package/dist/components/charts/line-chart/components/body.module.less +0 -1
- package/dist/components/charts/line-chart/components/hover-popover.d.ts.map +1 -1
- package/dist/components/charts/line-chart/components/hover-popover.js +4 -1
- package/dist/components/charts/line-chart/components/hover-popover.js.map +1 -1
- package/dist/components/charts/line-chart/components/hover-popover.module.less +0 -1
- package/dist/components/charts/line-chart/components/sidebar.d.ts +1 -1
- package/dist/components/charts/line-chart/components/sidebar.d.ts.map +1 -1
- package/dist/components/charts/line-chart/components/sidebar.js +3 -3
- package/dist/components/charts/line-chart/components/sidebar.js.map +1 -1
- package/dist/components/charts/line-chart/components/sidebar.module.less +7 -3
- package/dist/components/charts/line-chart/components/stuff.d.ts +6 -0
- package/dist/components/charts/line-chart/components/stuff.d.ts.map +1 -1
- package/dist/components/charts/line-chart/components/stuff.js +62 -5
- package/dist/components/charts/line-chart/components/stuff.js.map +1 -1
- package/dist/components/charts/line-chart/components/stuff.module.less +12 -3
- package/dist/components/charts/line-chart/components/svg-bars.d.ts +1 -0
- package/dist/components/charts/line-chart/components/svg-bars.d.ts.map +1 -1
- package/dist/components/charts/line-chart/components/svg-bars.js +15 -7
- package/dist/components/charts/line-chart/components/svg-bars.js.map +1 -1
- package/dist/components/charts/line-chart/components/svg-body.d.ts.map +1 -1
- package/dist/components/charts/line-chart/components/svg-body.js +2 -1
- package/dist/components/charts/line-chart/components/svg-body.js.map +1 -1
- package/dist/components/charts/line-chart/components/svg.module.less +0 -1
- package/dist/components/charts/line-chart/line-chart.stories.d.ts +4 -1
- package/dist/components/charts/line-chart/line-chart.stories.d.ts.map +1 -1
- package/dist/components/charts/line-chart/line-chart.stories.js +113 -2
- package/dist/components/charts/line-chart/line-chart.stories.js.map +1 -1
- package/dist/components/charts/line-chart/stores/line-chart.store.d.ts.map +1 -1
- package/dist/components/charts/line-chart/stores/line-chart.store.js +21 -6
- package/dist/components/charts/line-chart/stores/line-chart.store.js.map +1 -1
- package/dist/components/charts/line-chart/stores/svg.store.js +1 -1
- package/dist/components/charts/line-chart/stores/svg.store.js.map +1 -1
- package/dist/components/charts/line-chart/utils/interfaces.d.ts +1 -1
- package/dist/components/charts/line-chart/utils/interfaces.d.ts.map +1 -1
- package/dist/components/charts/line-chart/utils/internal-interfaces.d.ts +1 -0
- package/dist/components/charts/line-chart/utils/internal-interfaces.d.ts.map +1 -1
- package/dist/utils/formatters.js +1 -1
- package/package.json +2 -2
- package/src/components/charts/line-chart/components/body.module.less +0 -1
- package/src/components/charts/line-chart/components/body.tsx +23 -28
- package/src/components/charts/line-chart/components/hover-popover.module.less +0 -1
- package/src/components/charts/line-chart/components/hover-popover.tsx +1 -0
- package/src/components/charts/line-chart/components/sidebar.module.less +7 -3
- package/src/components/charts/line-chart/components/sidebar.tsx +17 -16
- package/src/components/charts/line-chart/components/stuff.module.less +12 -3
- package/src/components/charts/line-chart/components/stuff.module.less.d.ts +2 -0
- package/src/components/charts/line-chart/components/stuff.tsx +104 -17
- package/src/components/charts/line-chart/components/svg-bars.tsx +37 -19
- package/src/components/charts/line-chart/components/svg-body.tsx +8 -0
- package/src/components/charts/line-chart/components/svg.module.less +0 -1
- package/src/components/charts/line-chart/line-chart.stories.tsx +159 -1
- package/src/components/charts/line-chart/stores/line-chart.store.ts +26 -6
- package/src/components/charts/line-chart/stores/svg.store.ts +1 -1
- package/src/components/charts/line-chart/utils/interfaces.ts +1 -1
- package/src/components/charts/line-chart/utils/internal-interfaces.ts +1 -0
- package/src/utils/__tests__/formatters.test.ts +1 -1
- 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
|
);
|
|
@@ -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
|
-
|
|
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
|
-
|
|
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 (!
|
|
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
|
-
|
|
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)
|
|
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)
|
|
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 {
|
package/src/utils/formatters.ts
CHANGED
|
@@ -7,7 +7,7 @@ const formatPercentValue = (value: number): string => {
|
|
|
7
7
|
return '0';
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
const valueMain = value ? Math.abs(Math.
|
|
10
|
+
const valueMain = value ? Math.abs(Math.round(value)) : 0;
|
|
11
11
|
|
|
12
12
|
if (valueMain > 0) {
|
|
13
13
|
return accounting.formatNumber(valueMain, 0);
|