@mptw/skylens-ui 1.0.0

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 (143) hide show
  1. package/.editorconfig +12 -0
  2. package/.eslintrc.cjs +4 -0
  3. package/.nuxtrc +1 -0
  4. package/.playground/app.config.ts +5 -0
  5. package/.playground/nuxt.config.ts +3 -0
  6. package/README.md +73 -0
  7. package/app.config.ts +5 -0
  8. package/app.vue +3 -0
  9. package/assets/css/fonts/MEShPlus-font-icon.eot +0 -0
  10. package/assets/css/fonts/MEShPlus-font-icon.svg +186 -0
  11. package/assets/css/fonts/MEShPlus-font-icon.ttf +0 -0
  12. package/assets/css/fonts/MEShPlus-font-icon.woff +0 -0
  13. package/assets/css/icons.css +555 -0
  14. package/assets/css/layout.styl +98 -0
  15. package/assets/css/tailwind.css +3 -0
  16. package/assets/images/commons/app-logo-white.png +0 -0
  17. package/assets/images/commons/app-logo.png +0 -0
  18. package/assets/images/commons/empty-box.png +0 -0
  19. package/assets/images/commons/watermark.svg +15 -0
  20. package/components/SLAlertModal.vue +99 -0
  21. package/components/SLBreadcrumbs.vue +42 -0
  22. package/components/SLButton.vue +301 -0
  23. package/components/SLCalendarButton.vue +259 -0
  24. package/components/SLCalendarPopup.vue +832 -0
  25. package/components/SLCard.vue +118 -0
  26. package/components/SLChart.vue +181 -0
  27. package/components/SLCheckbox.vue +179 -0
  28. package/components/SLCircleButton.vue +95 -0
  29. package/components/SLCollapsableBlock.vue +116 -0
  30. package/components/SLCollapsableMulitPillSelect.vue +92 -0
  31. package/components/SLConfirmModal.vue +122 -0
  32. package/components/SLDateInput.vue +460 -0
  33. package/components/SLDatePicker.vue +143 -0
  34. package/components/SLDistributor.vue +30 -0
  35. package/components/SLDownloadButton.vue +410 -0
  36. package/components/SLDraggable.vue +151 -0
  37. package/components/SLDropdown.vue +277 -0
  38. package/components/SLDropdownItem.vue +31 -0
  39. package/components/SLElementWithTitle.vue +181 -0
  40. package/components/SLEyeCheckbox.vue +162 -0
  41. package/components/SLFileInput.vue +101 -0
  42. package/components/SLGenderAgeSelect.vue +279 -0
  43. package/components/SLHeatMap.vue +151 -0
  44. package/components/SLHourRangeInput.vue +211 -0
  45. package/components/SLIOSSwitch.vue +235 -0
  46. package/components/SLIcon.vue +35 -0
  47. package/components/SLIconButton.vue +130 -0
  48. package/components/SLInfoTip.vue +221 -0
  49. package/components/SLInsightSitePage.vue +27 -0
  50. package/components/SLLegend.vue +76 -0
  51. package/components/SLLinearProgressBar.vue +35 -0
  52. package/components/SLLink.vue +162 -0
  53. package/components/SLLoading.vue +127 -0
  54. package/components/SLMapChart.vue +151 -0
  55. package/components/SLModal.vue +377 -0
  56. package/components/SLMonthCalendarButton.vue +378 -0
  57. package/components/SLMonthPicker.vue +151 -0
  58. package/components/SLMultiSelect.vue +121 -0
  59. package/components/SLNoData.vue +43 -0
  60. package/components/SLPageModal.vue +64 -0
  61. package/components/SLPagination.vue +192 -0
  62. package/components/SLPillCheckbox.vue +207 -0
  63. package/components/SLPillLabel.vue +101 -0
  64. package/components/SLPopupMenuButton.vue +158 -0
  65. package/components/SLProfileButton.vue +186 -0
  66. package/components/SLRadioButton.vue +97 -0
  67. package/components/SLRadioButtonGroup.vue +113 -0
  68. package/components/SLRadioGroup.vue +201 -0
  69. package/components/SLRangeInput.vue +209 -0
  70. package/components/SLRegionsMapChart.vue +151 -0
  71. package/components/SLRightSider.vue +242 -0
  72. package/components/SLSearchInput.vue +87 -0
  73. package/components/SLSelect.vue +545 -0
  74. package/components/SLSelectAllToggle.vue +118 -0
  75. package/components/SLSiderbarNav.vue +394 -0
  76. package/components/SLSiderbarNavItem.vue +204 -0
  77. package/components/SLSitePage.vue +96 -0
  78. package/components/SLSkyInsightSitePage.vue +27 -0
  79. package/components/SLSortByDropdown.vue +189 -0
  80. package/components/SLSpinIcon.vue +24 -0
  81. package/components/SLStayRangeInput.vue +306 -0
  82. package/components/SLTab.vue +159 -0
  83. package/components/SLTable.vue +409 -0
  84. package/components/SLTableTooltip.vue +111 -0
  85. package/components/SLTabs.vue +388 -0
  86. package/components/SLTextInput.vue +362 -0
  87. package/components/SLTextarea.vue +134 -0
  88. package/components/SLToast.vue +71 -0
  89. package/components/SLToggleButton.vue +78 -0
  90. package/components/SLTwoLayerMultiSelect.vue +428 -0
  91. package/components/SLTwoLayerSelect.vue +265 -0
  92. package/components/SLWarnModal.vue +75 -0
  93. package/interface/IDateRange.ts +5 -0
  94. package/interface/IHourRange.ts +4 -0
  95. package/interface/IInputOption.ts +6 -0
  96. package/interface/ILegendItem.ts +7 -0
  97. package/interface/IPopupMenuButton.ts +5 -0
  98. package/interface/IStayRange.ts +15 -0
  99. package/interface/ITableField.ts +19 -0
  100. package/interface/IWeb.ts +5 -0
  101. package/interface/NavConfigType.ts +14 -0
  102. package/interface/commons.ts +7 -0
  103. package/models/DateRange.ts +21 -0
  104. package/nuxt.config.ts +22 -0
  105. package/package.json +52 -0
  106. package/plugins/googlemaps.ts +17 -0
  107. package/plugins/v-calendar.ts +5 -0
  108. package/public/assets/files/taiwan-regions.json +7 -0
  109. package/public/assets/files/taiwan.json +24 -0
  110. package/public/assets/images/commons/default-favico.png +0 -0
  111. package/public/assets/images/dashboard/closure-button-icon.png +0 -0
  112. package/public/assets/images/dashboard/dashboard-widget-bar-chart-icon-disabled.png +0 -0
  113. package/public/assets/images/dashboard/dashboard-widget-bar-chart-icon-poi.png +0 -0
  114. package/public/assets/images/dashboard/dashboard-widget-bar-chart-icon-web.png +0 -0
  115. package/public/assets/images/dashboard/dashboard-widget-country-heatmap-chart-icon-disabled.png +0 -0
  116. package/public/assets/images/dashboard/dashboard-widget-country-heatmap-chart-icon.png +0 -0
  117. package/public/assets/images/dashboard/dashboard-widget-geo-list-icon-disabled.png +0 -0
  118. package/public/assets/images/dashboard/dashboard-widget-geo-list-icon-poi.png +0 -0
  119. package/public/assets/images/dashboard/dashboard-widget-geo-list-icon-web.png +0 -0
  120. package/public/assets/images/dashboard/dashboard-widget-heatmap-chart-icon-disabled.png +0 -0
  121. package/public/assets/images/dashboard/dashboard-widget-heatmap-chart-icon-web.png +0 -0
  122. package/public/assets/images/dashboard/dashboard-widget-line-chart-icon-disabled.png +0 -0
  123. package/public/assets/images/dashboard/dashboard-widget-line-chart-icon-poi.png +0 -0
  124. package/public/assets/images/dashboard/dashboard-widget-list-icon-disabled.png +0 -0
  125. package/public/assets/images/dashboard/dashboard-widget-list-icon-poi.png +0 -0
  126. package/public/assets/images/dashboard/dashboard-widget-list-icon-web.png +0 -0
  127. package/public/assets/images/dashboard/dashboard-widget-pie-chart-icon-disabled.png +0 -0
  128. package/public/assets/images/dashboard/dashboard-widget-pie-chart-icon-poi.png +0 -0
  129. package/public/assets/images/dashboard/dashboard-widget-pie-chart-icon-web.png +0 -0
  130. package/public/assets/images/dashboard/drag-hint-icon.svg +3 -0
  131. package/public/assets/images/dashboard/extend-button-icon.png +0 -0
  132. package/public/assets/images/dashboard/map-list-chart-icon.svg +17 -0
  133. package/public/assets/images/dashboard/map-marker-chart-icon.svg +32 -0
  134. package/public/assets/images/dashboard/pie-chart-icon.svg +4 -0
  135. package/public/assets/images/dashboard/poi-gender-age-chart-icon.svg +20 -0
  136. package/public/assets/images/dashboard/poi-nav-icon.png +0 -0
  137. package/public/assets/images/dashboard/web-gender-age-chart-icon.svg +20 -0
  138. package/public/assets/images/dashboard/web-nav-icon.png +0 -0
  139. package/tailwind.config.js +300 -0
  140. package/tsconfig.json +8 -0
  141. package/utils/constants.ts +160 -0
  142. package/utils/generateSheet.ts +36 -0
  143. package/utils/index.ts +539 -0
package/utils/index.ts ADDED
@@ -0,0 +1,539 @@
1
+ import {
2
+ differenceInCalendarDays,
3
+ differenceInCalendarMonths,
4
+ isFirstDayOfMonth,
5
+ isLastDayOfMonth,
6
+ addDays,
7
+ subDays,
8
+ subMonths,
9
+ endOfMonth,
10
+ startOfMonth,
11
+ getDay,
12
+ getDate,
13
+ getMonth,
14
+ getYear,
15
+ format as formatDate,
16
+ getDaysInMonth,
17
+ } from 'date-fns';
18
+ import { sortBy, isEqual } from "lodash-es";
19
+ import { HanRegex } from '#imports';
20
+ import type IDateRange from '~ui/interface/IDateRange';
21
+ import { ScreenSize } from '~ui/interface/commons';
22
+ import ExcelJS from 'exceljs';
23
+ import { useGtm } from '@gtm-support/vue-gtm';
24
+
25
+ export const getUID = () => {
26
+ return `uid-${Math.random().toString(36).substring(2)}`;
27
+ };
28
+
29
+ export const dateRangeToStatus = (dateRange: IDateRange | null, baseDate = new Date()) => {
30
+ if (!dateRange || !dateRange.start || !dateRange.end) return 'custom';
31
+
32
+ const { start, end } = dateRange;
33
+ const diff = differenceInCalendarDays(end, start);
34
+ const isYesterday = differenceInCalendarDays(baseDate, end) === 1;
35
+
36
+ // if (diff === 0 && isYesterday) {
37
+ // return 'yesterday';
38
+ // }
39
+ if (diff === 6 && isYesterday) {
40
+ return 'last7Days';
41
+ } else if (diff === 29 && isYesterday) {
42
+ return 'last30Days';
43
+ } else if (diff === 89 && isYesterday) {
44
+ return 'last90Days';
45
+ } else if (
46
+ getYear(start) === getYear(end) &&
47
+ getMonth(start) === getMonth(end) &&
48
+ isFirstDayOfMonth(start) &&
49
+ isLastDayOfMonth(end) &&
50
+ differenceInCalendarMonths(end, baseDate) === -1
51
+ ) {
52
+ return 'lastMonth';
53
+ }
54
+
55
+ return 'custom';
56
+ };
57
+
58
+ export const statusToDateRange = (status: string | null, baseDate = new Date()) => {
59
+ const yesterday = subDays(baseDate, 1);
60
+ const lastMonth = subMonths(baseDate, 1);
61
+
62
+ switch (status) {
63
+ // case 'yesterday':
64
+ // return { start: yesterday, end: yesterday };
65
+ case 'last30Days':
66
+ return { start: subDays(baseDate, 30), end: yesterday };
67
+ case 'last90Days':
68
+ return { start: subDays(baseDate, 90), end: yesterday };
69
+ case 'lastMonth':
70
+ return { start: startOfMonth(lastMonth), end: endOfMonth(lastMonth) };
71
+ case 'last7Days':
72
+ return { start: subDays(baseDate, 7), end: yesterday };
73
+ default:
74
+ return null;
75
+ }
76
+ };
77
+
78
+ export const isPreviousDateRange = (leftDateRange: IDateRange | null, rightDateRange: IDateRange | null) => {
79
+ if (!leftDateRange || !rightDateRange) {
80
+ return 'custom';
81
+ }
82
+
83
+ const { start: leftStart, end: leftEnd } = leftDateRange;
84
+ const { start: rightStart, end: rightEnd } = rightDateRange;
85
+
86
+ if (!leftStart || !leftEnd || !rightStart || !rightEnd) {
87
+ return 'custom';
88
+ }
89
+
90
+ const leftDiff = differenceInCalendarDays(leftEnd, leftStart);
91
+ const rightDiff = differenceInCalendarDays(rightEnd, rightStart);
92
+ const startDiff = differenceInCalendarDays(leftStart, rightStart);
93
+ const endDiff = differenceInCalendarDays(leftEnd, rightEnd);
94
+ const leftStartRightEndDiff = differenceInCalendarDays(leftStart, rightEnd);
95
+
96
+ return leftStartRightEndDiff === 1 &&
97
+ ((leftDiff === rightDiff && startDiff === endDiff) ||
98
+ (isFirstDayOfMonth(leftStart) &&
99
+ isLastDayOfMonth(leftEnd) &&
100
+ isFirstDayOfMonth(rightStart) &&
101
+ isLastDayOfMonth(rightEnd) &&
102
+ differenceInCalendarMonths(leftStart, rightStart) === 1))
103
+ ? 'previous'
104
+ : 'custom';
105
+ };
106
+
107
+ export const previousDateRange = (dateRange: IDateRange | null) => {
108
+ if (!dateRange) return null;
109
+
110
+ const status = dateRangeToStatus(dateRange);
111
+ const { start, end } = dateRange;
112
+ const diff = differenceInCalendarDays(end, start);
113
+ const lastMonth = subMonths(start, 1);
114
+
115
+ switch (status) {
116
+ // case 'yesterday':
117
+ case 'last7Days':
118
+ case 'last30Days':
119
+ case 'last90Days':
120
+ case 'custom':
121
+ return {
122
+ start: subDays(start, diff + 1),
123
+ end: subDays(end, diff + 1),
124
+ };
125
+ case 'lastMonth':
126
+ return {
127
+ start: startOfMonth(lastMonth),
128
+ end: endOfMonth(lastMonth),
129
+ };
130
+ default:
131
+ return null;
132
+ }
133
+ };
134
+
135
+ export const emailValidator = (value: string) => /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/.test(value);
136
+
137
+ export const hexToRgba = (hex: string, opacity: number) => {
138
+ const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
139
+ return result
140
+ ? `rgba(${parseInt(result[1], 16)}, ${parseInt(result[2], 16)}, ${parseInt(
141
+ result[3],
142
+ 16
143
+ )}, ${opacity})`
144
+ : `rgba(255, 255, 255, 0)`;
145
+ };
146
+
147
+ export const formatDateRange = (dateRange: IDateRange | null) => {
148
+ if (!dateRange) return '';
149
+
150
+ return `${formatDate(dateRange.start, 'yyyy/MM/dd')} - ${formatDate(
151
+ dateRange.end,
152
+ 'yyyy/MM/dd'
153
+ )}`;
154
+ };
155
+
156
+ export const passwordValidator = (value: string) =>
157
+ !(
158
+ !!value &&
159
+ value.length >= 5 &&
160
+ value.length <= 202 &&
161
+ /^[w.@]+$/.test(value)
162
+ );
163
+
164
+ export const windowSize = () => {
165
+ const windowWidth = window.innerWidth;
166
+ let windowSize: ScreenSize = ScreenSize['2xl'];
167
+
168
+ if (windowWidth < 1024) {
169
+ windowSize = ScreenSize.md;
170
+ } else if (windowWidth < 1280) {
171
+ windowSize = ScreenSize.lg;
172
+ } else if (windowWidth < 1366) {
173
+ windowSize = ScreenSize.xl;
174
+ } else if (windowWidth < 1536) {
175
+ windowSize = ScreenSize['1.5xl'];
176
+ }
177
+
178
+ return windowSize;
179
+ };
180
+
181
+ const getCharLength = (char = '') => {
182
+ const matched = HanRegex.test(char);
183
+ return matched ? 2 : 1;
184
+ };
185
+
186
+ export const stringLength = (str: string) => {
187
+ if (!str) return 0;
188
+ let length = 0;
189
+ for (const symbol of str) {
190
+ length += getCharLength(symbol);
191
+ }
192
+
193
+ return length;
194
+ };
195
+
196
+ export function rankListBy<T>(list: T[], rankBy: keyof T, desc = true) {
197
+ let currentRank = 0;
198
+ let nextRank = 1;
199
+
200
+ let sortedList = sortBy(list, rankBy);
201
+
202
+ if (desc) {
203
+ sortedList = [...sortedList].reverse();
204
+ }
205
+
206
+ return sortedList.map((item, i) => {
207
+ if (i === 0) {
208
+ currentRank += 1;
209
+ nextRank += 1;
210
+ return {
211
+ ...item,
212
+ rank: currentRank,
213
+ };
214
+ } else {
215
+ const lastItem = sortedList[i - 1];
216
+ if (isEqual(item[rankBy], lastItem[rankBy])) {
217
+ nextRank += 1;
218
+ } else {
219
+ currentRank = nextRank;
220
+ nextRank += 1;
221
+ }
222
+ }
223
+
224
+ return {
225
+ ...item,
226
+ rank: currentRank,
227
+ };
228
+ });
229
+ }
230
+
231
+ export const getBarChartGridTop = (maxValue: number, showLabel = true) => {
232
+ return (
233
+ 30 +
234
+ (showLabel
235
+ ? Number(maxValue).toLocaleString().length *
236
+ 8 *
237
+ Math.sin((30 / 180) * Math.PI)
238
+ : 0)
239
+ );
240
+ };
241
+
242
+ export const getBarChartGridLeft = (value: number, min: number) => {
243
+ const left = Number(value).toLocaleString().length * 12;
244
+ if (min) return Math.max(left, min);
245
+ return left;
246
+ };
247
+
248
+ export const getBarChartBarLabelHeight = (maxValue: string | number, showLabel = true) => {
249
+ return (
250
+ 16 +
251
+ (showLabel
252
+ ? Number(maxValue).toLocaleString().length *
253
+ 8 *
254
+ Math.sin((30 / 180) * Math.PI)
255
+ : 0)
256
+ );
257
+ };
258
+
259
+ export const getChartLabelWidth = (maxValue: string | number) => {
260
+ return Number(maxValue).toLocaleString().length * 8;
261
+ };
262
+
263
+ export const getDayDatesMatchWeekDay = (dateRange1: IDateRange, dateRange2: IDateRange | null) => {
264
+ const dayDates: {
265
+ date: string,
266
+ day: number,
267
+ weekDay: string,
268
+ }[] = [];
269
+
270
+ if (!dateRange2) {
271
+ const daysInMonth = getDaysInMonth(dateRange1.start);
272
+ for (let i = 0; i < daysInMonth; i += 1) {
273
+ const day = addDays(dateRange1.start, i);
274
+
275
+ dayDates.push({
276
+ date: formatDate(day, 'yyyy/MM/dd'),
277
+ day: getDay(day),
278
+ weekDay: translateDayToLocale(getDay(day)),
279
+ });
280
+ }
281
+ return dayDates;
282
+ }
283
+
284
+ const weekDayOfRange1Start = getDay(dateRange1.start);
285
+ const weekDayOfRange2Start = getDay(dateRange2.start);
286
+ const weekDayDiff = weekDayOfRange1Start - weekDayOfRange2Start;
287
+
288
+ if (
289
+ (weekDayDiff > 0 && weekDayDiff <= 3)
290
+ || (weekDayDiff < -3)
291
+ ) {
292
+ const iteratorTimes = weekDayDiff > 0 ? weekDayDiff : (weekDayDiff + 7);
293
+ for(let i = 0; i < iteratorTimes; i += 1) {
294
+ const day = addDays(dateRange2.start, i);
295
+ dayDates.push({
296
+ date: formatDate(day, 'yyyy/MM/dd'),
297
+ day: getDay(day),
298
+ weekDay: translateDayToLocale(getDay(day)),
299
+ });
300
+ }
301
+ }
302
+
303
+ const daysOfLastMonth = differenceInCalendarDays(dateRange1.end, dateRange1.start) + 1;
304
+ for(let i = 0; i < daysOfLastMonth; i += 1) {
305
+ const day = addDays(dateRange1.start, i);
306
+ dayDates.push({
307
+ date: formatDate(day, 'yyyy/MM/dd'),
308
+ day: getDay(day),
309
+ weekDay: translateDayToLocale(getDay(day)),
310
+ });
311
+ }
312
+
313
+ const overMonth1Days = getDate(dateRange2.end) - getDate(dateRange1.end) - (7 - Math.abs(weekDayDiff));
314
+ if (overMonth1Days > 0) {
315
+ for(let j = overMonth1Days; j > 0; j -= 1) {
316
+ const day = subDays(dateRange2.end, j);
317
+ dayDates.push({
318
+ date: formatDate(day, 'yyyy/MM/dd'),
319
+ day: getDay(day),
320
+ weekDay: translateDayToLocale(getDay(day)),
321
+ });
322
+ }
323
+ }
324
+
325
+
326
+ return dayDates;
327
+ }
328
+
329
+ export const translateDayToLocale = (day: number) => {
330
+ switch(day) {
331
+ case 0:
332
+ return '日';
333
+ case 1:
334
+ return '一';
335
+ case 2:
336
+ return '二';
337
+ case 3:
338
+ return '三';
339
+ case 4:
340
+ return '四';
341
+ case 5:
342
+ return '五';
343
+ default:
344
+ return '六';
345
+ }
346
+ }
347
+
348
+ export const numberToLocaleString = (value: number | null, { NaNString = '' } = {}, toNumber = false) => {
349
+ if (value === null || isNaN(value)) {
350
+ return NaNString || '';
351
+ } else if (!toNumber) {
352
+ return Number(value).toLocaleString();
353
+ }
354
+
355
+ return value;
356
+ }
357
+
358
+ export const toFixed = (value: number | null, fixedTo: number = 0, { NaNString = '', unsign = false, unit = '' } = {}, toNumber = false) => {
359
+ if (value === null || isNaN(value)) {
360
+ return NaNString || '';
361
+ } else {
362
+ let formatedValue = '';
363
+ if (unsign) {
364
+ formatedValue = Number(Math.abs(value)).toFixed(fixedTo);
365
+ } else {
366
+ formatedValue = Number(value).toFixed(fixedTo);
367
+ }
368
+
369
+ const valueParts = formatedValue.split('.');
370
+
371
+ if (valueParts[1]) {
372
+ if (toNumber) {
373
+ return Number(`${Number(valueParts[0]).toLocaleString()}.${valueParts[1]}`);
374
+ }
375
+ return `${Number(valueParts[0]).toLocaleString()}.${valueParts[1]}${unit}`;
376
+ }
377
+
378
+ if (toNumber) {
379
+ return Number(valueParts[0]);
380
+ }
381
+ return `${Number(valueParts[0]).toLocaleString()}${unit}`;
382
+ }
383
+ }
384
+
385
+ export const downloadURL = (data: string, fileName: string) => {
386
+ const downloadLink = document.createElement('a');
387
+ downloadLink.href = data;
388
+ downloadLink.download = fileName;
389
+ downloadLink.click();
390
+ downloadLink.remove();
391
+ };
392
+
393
+ export const downloadBlob = (data: ExcelJS.Buffer, fileName: string, mimeType: string) => {
394
+ const blob = new Blob([data], {
395
+ type: mimeType,
396
+ });
397
+ const url = window.URL.createObjectURL(blob);
398
+ downloadURL(url, fileName);
399
+ setTimeout(() => {
400
+ window.URL.revokeObjectURL(url);
401
+ }, 1000);
402
+ };
403
+
404
+ export const isDateRangesEqual = (dateRange1: IDateRange, dateRange2: IDateRange) => {
405
+ return getYear(dateRange1.start) === getYear(dateRange2.start) &&
406
+ getMonth(dateRange1.start) === getMonth(dateRange2.start) &&
407
+ getDate(dateRange1.start) === getDate(dateRange2.start) &&
408
+ getYear(dateRange1.end) === getYear(dateRange2.end) &&
409
+ getMonth(dateRange1.end) === getMonth(dateRange2.end) &&
410
+ getDate(dateRange1.end) === getDate(dateRange2.end);
411
+ }
412
+
413
+ export const gaev = ({ category, action, label, value, cb }: {
414
+ category?: string,
415
+ action?: string,
416
+ label?: string,
417
+ value?: number,
418
+ cb?: () => void,
419
+ } = {}) => {
420
+ const gtm = useGtm();
421
+
422
+ if (gtm?.enabled() && !!event) {
423
+ const data: {
424
+ event: 'GAEV'
425
+ EventCategory?: string,
426
+ EventAction?: string,
427
+ EventLabel?: string,
428
+ EventValue?: number,
429
+ eventCallback?: () => void,
430
+ } = {
431
+ event: 'GAEV',
432
+ EventCategory: category,
433
+ EventAction: action,
434
+ EventLabel: label,
435
+ EventValue: value,
436
+ };
437
+
438
+ if (typeof cb === 'function') {
439
+ data.eventCallback = cb;
440
+ }
441
+
442
+ window.dataLayer?.push(data);
443
+ }
444
+ };
445
+
446
+ export const ga4ev = ({ category, action, label, value, cb }: {
447
+ category?: string,
448
+ action?: string,
449
+ label?: string,
450
+ value?: number,
451
+ cb?: () => void,
452
+ } = {}) => {
453
+ const gtm = useGtm();
454
+
455
+ if (gtm?.enabled() && !!event) {
456
+ const data: {
457
+ event: 'GA4EV',
458
+ EventCategory?: string,
459
+ EventAction?: string,
460
+ EventLabel?: string,
461
+ EventValue?: number,
462
+ eventCallback?: () => void,
463
+ } = {
464
+ event: 'GA4EV',
465
+ EventCategory: category,
466
+ EventAction: action,
467
+ EventLabel: label,
468
+ EventValue: value,
469
+ };
470
+
471
+ if (typeof cb === 'function') {
472
+ data.eventCallback = cb;
473
+ }
474
+
475
+ window.dataLayer?.push(data);
476
+ }
477
+ };
478
+
479
+ export const getWebsiteFavico = (domain: string): Promise<{ domain: string; icoUrl: string; }> => {
480
+ return new Promise((resolve) => {
481
+ const icoUrl = `https://storage.googleapis.com/domains-favicon/${domain.replaceAll(
482
+ '.',
483
+ '_'
484
+ )}.ico`;
485
+ const canvas = document.createElement('canvas');
486
+ canvas.width = 26;
487
+ canvas.height = 26;
488
+ const ctx = canvas.getContext('2d');
489
+
490
+ if (ctx) {
491
+ ctx.fillStyle = '#FFFFFF';
492
+ ctx.fill();
493
+
494
+ ctx.lineWidth = 1;
495
+ ctx.strokeStyle = '#BDBDBD';
496
+ ctx.roundRect(1, 1, 24, 24, 6);
497
+ ctx.stroke();
498
+ }
499
+
500
+ const image = new Image();
501
+ image.setAttribute('crossOrigin', 'Anonymous');
502
+ image.onload = () => {
503
+ ctx?.drawImage(image, 0, 0, image.width, image.height, 6, 6, 14, 14);
504
+
505
+ resolve({ domain, icoUrl: canvas.toDataURL('image/png', 1.0) });
506
+ };
507
+ image.onerror = () => {
508
+ image.src = `${window.location.protocol}//${window.location.host}/assets/images/commons/default-favico.png`;
509
+ };
510
+ image.src = icoUrl;
511
+ });
512
+ };
513
+
514
+ export const httpUrlValidate = (url: string) => /^https?:\/\/(?:www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b(?:[-a-zA-Z0-9()@:%_+.~#?&/=]*)$/.test(url);
515
+ export const httpUrlToHost = (url: string) => {
516
+ if (httpUrlValidate(url)) {
517
+ try {
518
+ const u = new URL(url);
519
+ return u.host;
520
+ } catch {
521
+ return url;
522
+ }
523
+ }
524
+
525
+ return url;
526
+ }
527
+
528
+ export const isValidDate = (d: any) => {
529
+ if (Object.prototype.toString.call(d) === "[object Date]") {
530
+ // it is a date
531
+ if (isNaN(d)) { // d.getTime() or d.valueOf() will also work
532
+ return false;
533
+ } else {
534
+ return true;
535
+ }
536
+ } else {
537
+ return false;
538
+ }
539
+ }