@coveo/quantic 3.37.7 → 3.37.9

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 (22) hide show
  1. package/force-app/main/default/lwc/quanticResult/quanticResult.js +1 -1
  2. package/force-app/main/default/lwc/quanticSearchBoxInput/quanticSearchBoxInput.js +5 -0
  3. package/force-app/main/default/lwc/quanticTimeframeFacet/__tests__/quanticTimeframeFacet.test.js +3 -3
  4. package/force-app/main/default/lwc/quanticTimeframeFacet/quanticTimeframeFacet.js +3 -3
  5. package/force-app/main/default/lwc/quanticUtils/__tests__/quanticUtils.test.js +0 -20
  6. package/force-app/main/default/lwc/quanticUtils/__tests__/timeAndDateUtils.test.js +22 -0
  7. package/force-app/main/default/lwc/quanticUtils/quanticUtils.js +1 -361
  8. package/force-app/main/default/lwc/quanticUtils/timeAndDateUtils.js +407 -0
  9. package/force-app/main/default/staticresources/coveoheadless/case-assist/headless.js +15 -15
  10. package/force-app/main/default/staticresources/coveoheadless/definitions/controllers/core/generated-answer/headless-core-interactive-generated-answer-inline-link.d.ts +44 -0
  11. package/force-app/main/default/staticresources/coveoheadless/definitions/controllers/generated-answer/headless-interactive-generated-answer-inline-link.d.ts +15 -0
  12. package/force-app/main/default/staticresources/coveoheadless/definitions/controllers/smart-snippet/headless-smart-snippet-interactive-inline-links.d.ts +2 -11
  13. package/force-app/main/default/staticresources/coveoheadless/definitions/features/generated-answer/generated-answer-analytics-actions.d.ts +5 -2
  14. package/force-app/main/default/staticresources/coveoheadless/definitions/features/generated-answer/generated-answer-request.d.ts +2 -2
  15. package/force-app/main/default/staticresources/coveoheadless/definitions/features/generated-answer/generated-answer-selectors.d.ts +1 -0
  16. package/force-app/main/default/staticresources/coveoheadless/definitions/index.d.ts +2 -0
  17. package/force-app/main/default/staticresources/coveoheadless/definitions/utils/inline-link.d.ts +10 -0
  18. package/force-app/main/default/staticresources/coveoheadless/headless.js +18 -18
  19. package/force-app/main/default/staticresources/coveoheadless/insight/headless.js +16 -16
  20. package/force-app/main/default/staticresources/coveoheadless/recommendation/headless.js +14 -14
  21. package/force-app/main/default/staticresources/dompurify/purify.min.js +2 -2
  22. package/package.json +7 -6
@@ -0,0 +1,407 @@
1
+ import LOCALE from '@salesforce/i18n/locale';
2
+ import dayPattern from '@salesforce/label/c.quantic_DatePatternDay';
3
+ import monthPattern from '@salesforce/label/c.quantic_DatePatternMonth';
4
+ import yearPattern from '@salesforce/label/c.quantic_DatePatternYear';
5
+ import nextDay from '@salesforce/label/c.quantic_NextDay';
6
+ import nextDay_plural from '@salesforce/label/c.quantic_NextDay_plural';
7
+ import nextHour from '@salesforce/label/c.quantic_NextHour';
8
+ import nextHour_plural from '@salesforce/label/c.quantic_NextHour_plural';
9
+ import nextMonth from '@salesforce/label/c.quantic_NextMonth';
10
+ import nextMonth_plural from '@salesforce/label/c.quantic_NextMonth_plural';
11
+ import nextQuarter from '@salesforce/label/c.quantic_NextQuarter';
12
+ import nextQuarter_plural from '@salesforce/label/c.quantic_NextQuarter_plural';
13
+ import nextWeek from '@salesforce/label/c.quantic_NextWeek';
14
+ import nextWeek_plural from '@salesforce/label/c.quantic_NextWeek_plural';
15
+ import nextYear from '@salesforce/label/c.quantic_NextYear';
16
+ import nextYear_plural from '@salesforce/label/c.quantic_NextYear_plural';
17
+ import pastDay from '@salesforce/label/c.quantic_PastDay';
18
+ import pastDay_plural from '@salesforce/label/c.quantic_PastDay_plural';
19
+ import pastHour from '@salesforce/label/c.quantic_PastHour';
20
+ import pastHour_plural from '@salesforce/label/c.quantic_PastHour_plural';
21
+ import pastMonth from '@salesforce/label/c.quantic_PastMonth';
22
+ import pastMonth_plural from '@salesforce/label/c.quantic_PastMonth_plural';
23
+ import pastQuarter from '@salesforce/label/c.quantic_PastQuarter';
24
+ import pastQuarter_plural from '@salesforce/label/c.quantic_PastQuarter_plural';
25
+ import pastWeek from '@salesforce/label/c.quantic_PastWeek';
26
+ import pastWeek_plural from '@salesforce/label/c.quantic_PastWeek_plural';
27
+ import pastYear from '@salesforce/label/c.quantic_PastYear';
28
+ import pastYear_plural from '@salesforce/label/c.quantic_PastYear_plural';
29
+
30
+ /** @typedef {{period: string, unit: string, amount: number}} RelativeDate */
31
+
32
+ /**
33
+ * @param {string} stringToFormat
34
+ * @param {...(string|number)} formattingArguments
35
+ * @returns {string}
36
+ */
37
+ function formatString(stringToFormat, ...formattingArguments) {
38
+ if (typeof stringToFormat !== 'string') {
39
+ throw new Error("'stringToFormat' must be a String");
40
+ }
41
+
42
+ return stringToFormat.replace(/{{(\d+)}}/gm, (match, index) =>
43
+ formattingArguments[index] === undefined
44
+ ? ''
45
+ : `${formattingArguments[index]}`
46
+ );
47
+ }
48
+
49
+ /**
50
+ * @param {number} count
51
+ * @returns {boolean}
52
+ */
53
+ function isSingular(count) {
54
+ return new Intl.PluralRules(LOCALE).select(count) === 'one';
55
+ }
56
+
57
+ /**
58
+ * Formats the date in the current locale.
59
+ * @param {Date} date
60
+ * @returns {string} The formatted date.
61
+ */
62
+ export function formatDate(date) {
63
+ return new Intl.DateTimeFormat(LOCALE).format(date);
64
+ }
65
+
66
+ /**
67
+ * Gets the short date pattern for the current locale.
68
+ * @returns {string} The short date pattern.
69
+ * @example `M/d/yyyy` for `en-US`, `d/M/yyyy` for `fr-FR`, etc.
70
+ */
71
+ export function getShortDatePattern() {
72
+ const date = new Date(2000, 2, 4); // month is zero-based
73
+ const dateAsString = formatDate(date);
74
+
75
+ const day = formatString(dayPattern);
76
+ const month = formatString(monthPattern);
77
+ const year = formatString(yearPattern);
78
+
79
+ return dateAsString
80
+ .replace('2000', year.repeat(4))
81
+ .replace('00', year.repeat(2))
82
+ .replace('03', month.repeat(2))
83
+ .replace('3', month)
84
+ .replace('04', day.repeat(2))
85
+ .replace('4', day);
86
+ }
87
+
88
+ /**
89
+ * Utility class for time-based calculations and formatting.
90
+ * Provides methods to convert between different time units and format durations.
91
+ */
92
+ export class TimeSpan {
93
+ /**
94
+ * @param {number} time
95
+ * @param {boolean} [isMilliseconds=true]
96
+ */
97
+ constructor(time, isMilliseconds = true) {
98
+ if (isMilliseconds) {
99
+ this.milliseconds = time;
100
+ } else {
101
+ this.milliseconds = time * 1000;
102
+ }
103
+ }
104
+
105
+ getMilliseconds() {
106
+ return this.milliseconds;
107
+ }
108
+
109
+ getSeconds() {
110
+ return this.getMilliseconds() / 1000;
111
+ }
112
+
113
+ getMinutes() {
114
+ return this.getSeconds() / 60;
115
+ }
116
+
117
+ getHours() {
118
+ return this.getMinutes() / 60;
119
+ }
120
+
121
+ getDays() {
122
+ return this.getHours() / 24;
123
+ }
124
+
125
+ getWeeks() {
126
+ return this.getDays() / 7;
127
+ }
128
+
129
+ getHHMMSS() {
130
+ const hours = Math.floor(this.getHours());
131
+ const minutes = Math.floor(this.getMinutes()) % 60;
132
+ const seconds = Math.floor(this.getSeconds()) % 60;
133
+ let hoursString, minutesString, secondsString;
134
+ if (hours === 0) {
135
+ hoursString = '';
136
+ } else {
137
+ hoursString = hours < 10 ? '0' + hours.toString() : hours.toString();
138
+ }
139
+ minutesString =
140
+ minutes < 10 ? '0' + minutes.toString() : minutes.toString();
141
+ secondsString =
142
+ seconds < 10 ? '0' + seconds.toString() : seconds.toString();
143
+ const hhmmss =
144
+ (hoursString !== '' ? hoursString + ':' : '') +
145
+ minutesString +
146
+ ':' +
147
+ secondsString;
148
+ return hhmmss;
149
+ }
150
+
151
+ getYoutubeFormatTimestamp() {
152
+ const hours = Math.floor(this.getHours());
153
+ const minutes = Math.floor(this.getMinutes()) % 60;
154
+ const seconds = Math.floor(this.getSeconds()) % 60;
155
+
156
+ const formattedSeconds = seconds < 10 ? '0' + seconds : seconds;
157
+
158
+ if (hours > 0) {
159
+ const formattedMinutes = minutes < 10 ? '0' + minutes : minutes;
160
+ return hours + ':' + formattedMinutes + ':' + formattedSeconds;
161
+ }
162
+ const formattedMinutes =
163
+ minutes === 0 ? '0' : minutes < 10 ? '0' + minutes : minutes;
164
+ return formattedMinutes + ':' + formattedSeconds;
165
+ }
166
+
167
+ getCleanHHMMSS() {
168
+ return this.getHHMMSS().replace(/^0+/, '');
169
+ }
170
+ }
171
+
172
+ /**
173
+ * Utility class for date operations and formatting.
174
+ * Handles conversion between different date formats and provides parsing utilities.
175
+ */
176
+ export class DateUtils {
177
+ /**
178
+ * Formats the date in the current locale.
179
+ * @param {Date} date
180
+ * @returns {string} The formatted date.
181
+ */
182
+ static formatDate(date) {
183
+ return formatDate(date);
184
+ }
185
+
186
+ /**
187
+ * Gets the short date pattern for the current locale.
188
+ * @returns {string} The short date pattern.
189
+ * @example `M/d/yyyy` for `en-US`, `d/M/yyyy` for `fr-FR`, etc.
190
+ */
191
+ static getShortDatePattern() {
192
+ return getShortDatePattern();
193
+ }
194
+
195
+ /**
196
+ * Converts a date string from the Coveo Search API format to the ISO-8601 format.
197
+ * Replace `/` characters in date string with `-`.
198
+ * Replace `@` characters in date string with `T`.
199
+ * @param {string} dateString
200
+ * @returns {string}
201
+ */
202
+ static fromSearchApiDate(dateString) {
203
+ return dateString.replaceAll('/', '-').replaceAll('@', 'T');
204
+ }
205
+
206
+ /**
207
+ * Converts a date object to the Search API format (`yyyy/MM/dd@hh:mm:ss`), using local time.
208
+ * @param {Date} date The date object to convert.
209
+ * @returns {string} The formatted date string.
210
+ */
211
+ static toLocalSearchApiDate(date) {
212
+ const year = date.getFullYear().toString().padStart(4, '0');
213
+ const month = (date.getMonth() + 1).toString().padStart(2, '0');
214
+ const day = date.getDate().toString().padStart(2, '0');
215
+ const hours = date.getHours().toString().padStart(2, '0');
216
+ const minutes = date.getMinutes().toString().padStart(2, '0');
217
+ const seconds = date.getSeconds().toString().padStart(2, '0');
218
+
219
+ return `${year}/${month}/${day}@${hours}:${minutes}:${seconds}`;
220
+ }
221
+
222
+ /**
223
+ * Converts a date to the ISO formatted local date.
224
+ * @param {Date} date The date to convert.
225
+ * @returns {string} The formatted date string.
226
+ */
227
+ static toLocalIsoDate(date) {
228
+ const year = date.getFullYear().toString().padStart(4, '0');
229
+ const month = (date.getMonth() + 1).toString().padStart(2, '0');
230
+ const day = date.getDate().toString().padStart(2, '0');
231
+
232
+ return `${year}-${month}-${day}T00:00:00`;
233
+ }
234
+
235
+ /**
236
+ * Parses an ISO-formatted date string to a date object, using the specified local time.
237
+ * @param {string} dateString The ISO formatted date string.
238
+ * @param {number} hours The local hours to set on the date.
239
+ * @param {number} minutes The local minutes to set on the date.
240
+ * @param {number} seconds The local seconds to set on the date.
241
+ * @throws {Error} If specified time is invalid.
242
+ * @returns {Date} The parsed date.
243
+ */
244
+ static fromLocalIsoDate(dateString, hours, minutes, seconds) {
245
+ const isTimeValid =
246
+ hours >= 0 &&
247
+ hours <= 23 &&
248
+ minutes >= 0 &&
249
+ minutes <= 59 &&
250
+ seconds >= 0 &&
251
+ seconds <= 59;
252
+ if (!isTimeValid) {
253
+ throw new Error(
254
+ 'The specified time is invalid. It must be between 00:00:00 and 23:59:59.'
255
+ );
256
+ }
257
+
258
+ const withoutTime = DateUtils.trimIsoTime(dateString);
259
+ const time =
260
+ hours.toString().padStart(2, '0') +
261
+ ':' +
262
+ minutes.toString().padStart(2, '0') +
263
+ ':' +
264
+ seconds.toString().padStart(2, '0');
265
+
266
+ return new Date(`${withoutTime}T${time}`);
267
+ }
268
+
269
+ /**
270
+ * Trims the time portion from an ISO 8601 date string.
271
+ * @param {string} dateString
272
+ * @returns {string}
273
+ */
274
+ static trimIsoTime(dateString) {
275
+ const timeIdx = dateString.indexOf('T');
276
+ return timeIdx !== -1 ? dateString.substring(0, timeIdx) : dateString;
277
+ }
278
+
279
+ /**
280
+ * @param {number} timestamp
281
+ * @returns {boolean}
282
+ */
283
+ static isValidTimestamp(timestamp) {
284
+ let isValid = true;
285
+ try {
286
+ // eslint-disable-next-line no-new
287
+ new Date(timestamp);
288
+ } catch (error) {
289
+ isValid = false;
290
+ }
291
+ return isValid;
292
+ }
293
+
294
+ /**
295
+ * Parses a given timestamp into detailed date components.
296
+ * @param {number} timestamp - The timestamp in milliseconds since January 1, 1970 (epoch time).
297
+ * @returns {Object} An object containing the following date details:
298
+ * - {number} year - The four-digit year (for example, 2024).
299
+ * - {string} month - The full name of the month (for example, "August").
300
+ * - {string} dayOfWeek - The abbreviated name of the day of the week (for example, "Mon").
301
+ * - {number} day - The day of the month (for example, 26).
302
+ * - {number} hours - The hour of the day in 24-hour format (0-23).
303
+ * - {number} minutes - The minutes of the hour (0-59).
304
+ */
305
+ static parseTimestampToDateDetails(timestamp) {
306
+ const daysOfWeek = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
307
+ const months = [
308
+ 'January',
309
+ 'February',
310
+ 'March',
311
+ 'April',
312
+ 'May',
313
+ 'June',
314
+ 'July',
315
+ 'August',
316
+ 'September',
317
+ 'October',
318
+ 'November',
319
+ 'December',
320
+ ];
321
+
322
+ const date = new Date(timestamp);
323
+ const dayOfWeek = daysOfWeek[date.getDay()];
324
+ const month = months[date.getMonth()];
325
+ const day = date.getDate();
326
+ const year = date.getFullYear();
327
+ const hours = date.getHours();
328
+ const minutes = date.getMinutes();
329
+
330
+ return {
331
+ year,
332
+ month,
333
+ dayOfWeek,
334
+ day,
335
+ hours,
336
+ minutes,
337
+ };
338
+ }
339
+ }
340
+
341
+ /**
342
+ * Converts a date string from the Coveo Search API format to the ISO-8601 format.
343
+ * Replace `/` characters in date string with `-`.
344
+ * Replace `@` characters in date string with `T`.
345
+ * @param {string} dateString
346
+ * @returns {string}
347
+ */
348
+ export function fromSearchApiDate(dateString) {
349
+ return DateUtils.fromSearchApiDate(dateString);
350
+ }
351
+
352
+ /**
353
+ * Formats relative date ranges into human-readable strings.
354
+ * Supports past and future date ranges with proper pluralization.
355
+ */
356
+ export class RelativeDateFormatter {
357
+ constructor() {
358
+ this.singularIndex = 0;
359
+ this.pluralIndex = 1;
360
+
361
+ /** @type {Record<string, string[]>} */
362
+ this.labels = {
363
+ 'past-hour': [pastHour, pastHour_plural],
364
+ 'past-day': [pastDay, pastDay_plural],
365
+ 'past-week': [pastWeek, pastWeek_plural],
366
+ 'past-month': [pastMonth, pastMonth_plural],
367
+ 'past-quarter': [pastQuarter, pastQuarter_plural],
368
+ 'past-year': [pastYear, pastYear_plural],
369
+ 'next-hour': [nextHour, nextHour_plural],
370
+ 'next-day': [nextDay, nextDay_plural],
371
+ 'next-week': [nextWeek, nextWeek_plural],
372
+ 'next-month': [nextMonth, nextMonth_plural],
373
+ 'next-quarter': [nextQuarter, nextQuarter_plural],
374
+ 'next-year': [nextYear, nextYear_plural],
375
+ };
376
+ }
377
+
378
+ /**
379
+ * Formats a relative date range into a human-readable string.
380
+ * @param {RelativeDate} begin The beginning of the relative date range.
381
+ * @param {RelativeDate} end The end of the relative date range.
382
+ * @returns {string} The formatted human-readable date range.
383
+ * @throws {Error} If the provided relative date range is invalid.
384
+ * @example
385
+ * begin = { period: 'past', unit: 'day', amount: 2 };
386
+ * end = { period: 'now', unit: 'day', amount: 1 };
387
+ * Output: "2 days ago - 1 day ago"
388
+ */
389
+ formatRange(begin, end) {
390
+ const isPastRange = begin.period === 'past' && end.period === 'now';
391
+ const isNextRange = begin.period === 'now' && end.period === 'next';
392
+
393
+ if (!isPastRange && !isNextRange) {
394
+ throw new Error(
395
+ 'The provided relative date range is invalid. Either "begin" or "end" must have the "period" set to "now".'
396
+ );
397
+ }
398
+
399
+ const relativeDate = isPastRange ? begin : end;
400
+ const label =
401
+ this.labels[`${relativeDate.period}-${relativeDate.unit}`][
402
+ isSingular(relativeDate.amount) ? this.singularIndex : this.pluralIndex
403
+ ];
404
+
405
+ return formatString(label, relativeDate.amount);
406
+ }
407
+ }