@bigbinary/neeto-molecules 4.0.143 → 4.0.144

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/Schedule.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { createContext, useContext, memo, useMemo, useState, useEffect, useImperativeHandle, forwardRef } from 'react';
2
2
  import { useFormikContext, FieldArray, ErrorMessage, Formik, Form as Form$2 } from 'formik';
3
- import { findIndexBy, isNotPresent, isPresent, toLabelAndValue, isNotEmpty, noop } from '@bigbinary/neeto-cist';
3
+ import { findIndexBy, isNotPresent, isPresent, toLabelAndValue, isNotEmpty, findBy, noop } from '@bigbinary/neeto-cist';
4
4
  import { joinHyphenCase } from '@bigbinary/neeto-commons-frontend/utils/general';
5
5
  import Typography from '@bigbinary/neetoui/Typography';
6
6
  import { useTranslation } from 'react-i18next';
@@ -38,12 +38,17 @@ import '@bigbinary/neeto-commons-frontend/react-utils';
38
38
 
39
39
  var DAYS = ["sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday"];
40
40
  var DEFAULT_SLOT_INTERVAL = 30;
41
+ var HOUR_FORMATS = {
42
+ H24: "24h"};
43
+ var DEFAULT_HOUR_FORMAT = HOUR_FORMATS.H24;
41
44
 
42
45
  // To avoid prop drilling `allowAddPeriod` to `ScheduleRow` component
43
46
  // eslint-disable-next-line @bigbinary/neeto/use-zustand-for-global-state-management
44
47
  var ScheduleContext = /*#__PURE__*/createContext({
45
48
  allowAddPeriod: true,
46
- firstDay: 0
49
+ firstDay: 0,
50
+ slotInterval: DEFAULT_SLOT_INTERVAL,
51
+ hourFormat: DEFAULT_HOUR_FORMAT
47
52
  });
48
53
 
49
54
  var INTERVALS = ["year", "quarter", "month", "week", "day", "hour", "minute", "second"];
@@ -66,9 +71,10 @@ var BLUR_TEXT_WHEN_SELECT_MENU_IS_OPEN = {
66
71
  }
67
72
  };
68
73
  var SLOT_TIME_FORMAT = "hh:mm A";
74
+ var SLOT_TIME_FORMAT_24H = "HH:mm";
69
75
 
70
76
  // eslint-disable-next-line @bigbinary/neeto/use-standard-date-time-formats
71
- var END_OF_DAY = dayjs().endOf("day").format(SLOT_TIME_FORMAT);
77
+ var END_OF_DAY = dayjs().endOf("day").format(SLOT_TIME_FORMAT_24H);
72
78
 
73
79
  var DayjsRange = /*#__PURE__*/function () {
74
80
  function DayjsRange(startDate, endDate) {
@@ -106,7 +112,7 @@ var DayjsRange = /*#__PURE__*/function () {
106
112
  var endTime = this.endDate.add(1, "days");
107
113
  var allTimes = [];
108
114
  while (startTime < endTime) {
109
- allTimes.push(startTime.format(SLOT_TIME_FORMAT));
115
+ allTimes.push(startTime.format(SLOT_TIME_FORMAT_24H));
110
116
  startTime = startTime.add(interval, "minutes");
111
117
  }
112
118
  return allTimes;
@@ -172,7 +178,7 @@ yup.addMethod(yup.array, "ensureSlotsCantOverlap", function () {
172
178
  });
173
179
  var isFromAndToSame = function isFromAndToSame(startTime, endTime) {
174
180
  if (!startTime || !endTime) return true;
175
- return dayjs(startTime, SLOT_TIME_FORMAT).isSame(dayjs(endTime, SLOT_TIME_FORMAT));
181
+ return dayjs(startTime, SLOT_TIME_FORMAT_24H).isSame(dayjs(endTime, SLOT_TIME_FORMAT_24H));
176
182
  };
177
183
  var sortDays = function sortDays(chosenIndex) {
178
184
  if (chosenIndex < 0 || chosenIndex >= 7) return DAYS;
@@ -212,7 +218,7 @@ var getTimeZoneAndTime = function getTimeZoneAndTime() {
212
218
  return "".concat(humanReadableTimezone, ": ").concat(dayjs().tz(timeZone).format(SLOT_TIME_FORMAT));
213
219
  };
214
220
  var isTimeBehind = function isTimeBehind(timeA, timeB) {
215
- return dayjs(timeA, SLOT_TIME_FORMAT).isBefore(dayjs(timeB, SLOT_TIME_FORMAT));
221
+ return dayjs(timeA, SLOT_TIME_FORMAT_24H).isBefore(dayjs(timeB, SLOT_TIME_FORMAT_24H));
216
222
  };
217
223
  var sortPeriodsByKey = function sortPeriodsByKey(_ref) {
218
224
  var periods = _ref.periods,
@@ -253,8 +259,8 @@ var checkForOverlapBetweenPeriods = function checkForOverlapBetweenPeriods(perio
253
259
  value = _step$value[1];
254
260
  var seg1 = value;
255
261
  var seg2 = slotsSortedByStartTime[index + 1];
256
- var range1 = dayjsExtended.range(dayjsExtended(seg1.startTime, SLOT_TIME_FORMAT), dayjsExtended(seg1.endTime, SLOT_TIME_FORMAT));
257
- var range2 = dayjsExtended.range(dayjsExtended(seg2.startTime, SLOT_TIME_FORMAT), dayjsExtended(seg2.endTime, SLOT_TIME_FORMAT));
262
+ var range1 = dayjsExtended.range(dayjsExtended(seg1.startTime, SLOT_TIME_FORMAT_24H), dayjsExtended(seg1.endTime, SLOT_TIME_FORMAT_24H));
263
+ var range2 = dayjsExtended.range(dayjsExtended(seg2.startTime, SLOT_TIME_FORMAT_24H), dayjsExtended(seg2.endTime, SLOT_TIME_FORMAT_24H));
258
264
  if (range1.isOverlap(range2)) {
259
265
  response = {
260
266
  exists: true,
@@ -276,10 +282,10 @@ var findIndicesOfOverlappingRangesInPeriods = function findIndicesOfOverlappingR
276
282
  range2 = _ref2.range2,
277
283
  periods = _ref2.periods;
278
284
  var firstIndex = findIndexBy({
279
- startTime: range1.startDate.format(SLOT_TIME_FORMAT)
285
+ startTime: range1.startDate.format(SLOT_TIME_FORMAT_24H)
280
286
  }, periods);
281
287
  var secondIndex = periods.findIndex(function (slot, index) {
282
- return index > firstIndex && slot.startTime === range2.startDate.format(SLOT_TIME_FORMAT);
288
+ return index > firstIndex && slot.startTime === range2.startDate.format(SLOT_TIME_FORMAT_24H);
283
289
  });
284
290
  return {
285
291
  firstIndex: firstIndex,
@@ -342,13 +348,26 @@ var processFormValues = function processFormValues(values, firstDay) {
342
348
  })
343
349
  };
344
350
  };
351
+ var convert24hTo12h = function convert24hTo12h(time) {
352
+ return (
353
+ // eslint-disable-next-line @bigbinary/neeto/use-standard-date-time-formats
354
+ dayjs(time, SLOT_TIME_FORMAT_24H).format(SLOT_TIME_FORMAT)
355
+ );
356
+ };
345
357
 
346
358
  var DisplayAvailability = function DisplayAvailability(_ref) {
347
359
  var periods = _ref.periods;
348
360
  var _useTranslation = useTranslation(),
349
361
  t = _useTranslation.t;
350
362
  var _useContext = useContext(ScheduleContext),
351
- firstDay = _useContext.firstDay;
363
+ firstDay = _useContext.firstDay,
364
+ hourFormat = _useContext.hourFormat;
365
+ var formatHour = function formatHour(hour) {
366
+ if (hourFormat === HOUR_FORMATS.H24) {
367
+ return hour;
368
+ }
369
+ return convert24hTo12h(hour);
370
+ };
352
371
  return /*#__PURE__*/jsx("div", {
353
372
  className: "flex w-full flex-col gap-y-3",
354
373
  children: sortDays(firstDay).map(function (day) {
@@ -377,7 +396,7 @@ var DisplayAvailability = function DisplayAvailability(_ref) {
377
396
  style: "h5",
378
397
  weight: "semibold",
379
398
  "data-testid": joinHyphenCase(day, period.startTime, "start-time-text"),
380
- children: period.startTime
399
+ children: formatHour(period.startTime)
381
400
  }), /*#__PURE__*/jsx(Typography, {
382
401
  className: "neeto-ui-text-gray-600",
383
402
  component: "span",
@@ -388,7 +407,7 @@ var DisplayAvailability = function DisplayAvailability(_ref) {
388
407
  style: "h5",
389
408
  weight: "semibold",
390
409
  "data-testid": joinHyphenCase(day, period.endTime, "start-time-text"),
391
- children: period.endTime
410
+ children: formatHour(period.endTime)
392
411
  })]
393
412
  }, period.id);
394
413
  }) : /*#__PURE__*/jsx(Typography, {
@@ -406,16 +425,32 @@ var DisplayAvailability = function DisplayAvailability(_ref) {
406
425
 
407
426
  var buildSlotIntervals = function buildSlotIntervals(_ref) {
408
427
  var interval = _ref.interval,
409
- bookedSlots = _ref.bookedSlots;
428
+ bookedSlots = _ref.bookedSlots,
429
+ _ref$hourFormat = _ref.hourFormat,
430
+ hourFormat = _ref$hourFormat === void 0 ? DEFAULT_HOUR_FORMAT : _ref$hourFormat;
410
431
  var allIntervalsForADay = dayjsExtended.timeIntervalsForDay(interval);
411
432
  allIntervalsForADay.push(END_OF_DAY);
412
433
  return function (slotType) {
413
434
  var selectedValue = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
414
435
  var uniqBookedSlots = uniq(pluck(slotType, bookedSlots));
415
436
  var slotsAvailableForBooking = difference(allIntervalsForADay, uniqBookedSlots);
416
- var slots = slotsAvailableForBooking.map(toLabelAndValue);
437
+ var slots;
438
+ if (hourFormat === "12h") {
439
+ slots = slotsAvailableForBooking.map(function (value) {
440
+ return {
441
+ value: value,
442
+ label: convert24hTo12h(value)
443
+ };
444
+ });
445
+ } else {
446
+ slots = slotsAvailableForBooking.map(toLabelAndValue);
447
+ }
417
448
  if (!selectedValue) return slots;
418
- return sortSlots([toLabelAndValue(selectedValue)].concat(_toConsumableArray(slots)));
449
+ var selectedSlot = {
450
+ value: selectedValue,
451
+ label: hourFormat === "12h" ? convert24hTo12h(selectedValue) : selectedValue
452
+ };
453
+ return sortSlots([selectedSlot].concat(_toConsumableArray(slots)));
419
454
  };
420
455
  };
421
456
  var sortSlots = function sortSlots(slots) {
@@ -437,28 +472,33 @@ var filterSlots = function filterSlots(option, searchTerm) {
437
472
  };
438
473
  var formatCreateLabel = identity;
439
474
  var isValidTimeSlotOption = function isValidTimeSlotOption(value) {
440
- // Allow HH:MM AM/PM, H:MM AM/PM, H:MM am/pm, or HH:MM (24h)
441
- // Accepts 1 or 2 digit hour (1-12) with AM/PM OR 00-23:00-59 for 24h, AM/PM (any case) optional, optional leading zero
442
- // eslint-disable-next-line prettier/prettier
443
- var timeRegex = /^(((0?[1-9]|1[0-2]):[0-5]\d ?[AaPp][Mm])|([01]?\d|2[0-3]):[0-5]\d)$/;
444
- return timeRegex.test(value);
475
+ if (!value || typeof value !== "string") return false;
476
+ var valueTrimmed = value.trim();
477
+
478
+ // Try 24h format (e.g. "14:30")
479
+ var time = dayjsExtended(valueTrimmed, SLOT_TIME_FORMAT_24H, true);
480
+ if (time.isValid()) return true;
481
+
482
+ // Try 12h format with padded hour
483
+ time = dayjsExtended(valueTrimmed, SLOT_TIME_FORMAT, true);
484
+ return time.isValid();
445
485
  };
446
486
  var formatTimeSlotOption = function formatTimeSlotOption(v) {
447
- var value = (v || "").toUpperCase();
487
+ var value = v || "";
448
488
  if (isNotEmpty(value)) {
449
489
  // If value is in 24h format and missing AM/PM, convert to 12h with AM/PM
450
- var time24hMatch = value.match(/^([01]?\d|2[0-3]):([0-5]\d)$/);
451
- if (time24hMatch) {
452
- var _time24hMatch = _slicedToArray(time24hMatch, 3),
453
- hours = _time24hMatch[1],
454
- minutes = _time24hMatch[2];
455
- var hoursInt = parseInt(hours, 10);
456
- var suffix = hoursInt >= 12 ? "PM" : "AM";
457
- var hour12 = hoursInt % 12 || 12;
458
- value = "".concat(hour12.toString().padStart(2, "0"), ":").concat(minutes, " ").concat(suffix);
459
- } else if (value[1] === ":") {
460
- // Pad hour with 0 if single digit (legacy logic)
461
- value = "0".concat(value);
490
+ // Use dayjs to parse and format instead of manual regex, etc.
491
+ var parsed24h = dayjsExtended(value, SLOT_TIME_FORMAT_24H, true);
492
+ if (parsed24h.isValid()) {
493
+ value = parsed24h.format(SLOT_TIME_FORMAT_24H);
494
+ } else {
495
+ var parsed12h = dayjsExtended(value, SLOT_TIME_FORMAT, true);
496
+ if (parsed12h.isValid()) {
497
+ value = parsed12h.format(SLOT_TIME_FORMAT_24H);
498
+ } else if (value[1] === ":") {
499
+ // Pad hour with 0 if single digit (legacy logic)
500
+ value = "0".concat(value);
501
+ }
462
502
  }
463
503
  }
464
504
  return value;
@@ -470,19 +510,19 @@ var roundToNearestHour = function roundToNearestHour(time) {
470
510
  };
471
511
  var generateNewPeriod = function generateNewPeriod(periods, wday) {
472
512
  var lastEndTime = periods[periods.length - 1].endTime;
473
- var newStartTime = roundToNearestHour(dayjsExtended(lastEndTime, SLOT_TIME_FORMAT));
474
- var newEndTime = dayjsExtended(newStartTime, SLOT_TIME_FORMAT).add(1, "hour");
513
+ var newStartTime = roundToNearestHour(dayjsExtended(lastEndTime, SLOT_TIME_FORMAT_24H));
514
+ var newEndTime = dayjsExtended(newStartTime, SLOT_TIME_FORMAT_24H).add(1, "hour");
475
515
  return {
476
- startTime: dayjsExtended(newStartTime).format(SLOT_TIME_FORMAT),
477
- endTime: dayjsExtended(newEndTime).format(SLOT_TIME_FORMAT),
516
+ startTime: dayjsExtended(newStartTime).format(SLOT_TIME_FORMAT_24H),
517
+ endTime: dayjsExtended(newEndTime).format(SLOT_TIME_FORMAT_24H),
478
518
  wday: wday
479
519
  };
480
520
  };
481
521
  var addDefaultPeriod = function addDefaultPeriod(wday) {
482
522
  return {
483
523
  wday: wday,
484
- startTime: dayjsExtended().hour(9).minute(0).format(SLOT_TIME_FORMAT),
485
- endTime: dayjsExtended().hour(17).minute(0).format(SLOT_TIME_FORMAT)
524
+ startTime: dayjsExtended().hour(9).minute(0).format(SLOT_TIME_FORMAT_24H),
525
+ endTime: dayjsExtended().hour(17).minute(0).format(SLOT_TIME_FORMAT_24H)
486
526
  };
487
527
  };
488
528
 
@@ -494,15 +534,23 @@ var ScheduleRow = function ScheduleRow(_ref) {
494
534
  var bookedSlots = values.wdays[day].periods;
495
535
  var _useContext = useContext(ScheduleContext),
496
536
  allowAddPeriod = _useContext.allowAddPeriod,
497
- slotInterval = _useContext.slotInterval;
537
+ slotInterval = _useContext.slotInterval,
538
+ hourFormat = _useContext.hourFormat;
498
539
  var _useTranslation = useTranslation(),
499
540
  t = _useTranslation.t;
500
541
  var sortSlotsInterval = useMemo(function () {
501
542
  return buildSlotIntervals({
502
543
  interval: slotInterval,
503
- bookedSlots: bookedSlots
544
+ bookedSlots: bookedSlots,
545
+ hourFormat: hourFormat
504
546
  });
505
- }, [slotInterval, bookedSlots]);
547
+ }, [slotInterval, bookedSlots, hourFormat]);
548
+ var startTimeOptions = function startTimeOptions(period) {
549
+ return sortSlotsInterval("startTime", period === null || period === void 0 ? void 0 : period.startTime);
550
+ };
551
+ var endTimeOptions = function endTimeOptions(period) {
552
+ return sortSlotsInterval("endTime", period === null || period === void 0 ? void 0 : period.endTime);
553
+ };
506
554
  var handleChange = function handleChange(index, field, e) {
507
555
  var value = formatTimeSlotOption(e === null || e === void 0 ? void 0 : e.value);
508
556
  setFieldValue("wdays.".concat(day, ".periods[").concat(index, "].").concat(field), value);
@@ -543,11 +591,13 @@ var ScheduleRow = function ScheduleRow(_ref) {
543
591
  filterOption: filterSlots,
544
592
  isValidNewOption: isValidTimeSlotOption,
545
593
  name: "wdays.".concat(day, ".periods[").concat(index, "].startTime"),
594
+ options: startTimeOptions(period),
546
595
  placeholder: t("neetoMolecules.schedule.startTime"),
547
596
  strategy: "fixed",
548
597
  styles: BLUR_TEXT_WHEN_SELECT_MENU_IS_OPEN,
549
- options: sortSlotsInterval("startTime", period === null || period === void 0 ? void 0 : period.startTime),
550
- value: slotsSelectComponentDefaultValue(period === null || period === void 0 ? void 0 : period.startTime),
598
+ value: findBy({
599
+ value: period === null || period === void 0 ? void 0 : period.startTime
600
+ }, startTimeOptions(period)),
551
601
  onChange: function onChange(e) {
552
602
  return handleChange(index, "startTime", e);
553
603
  }
@@ -561,11 +611,13 @@ var ScheduleRow = function ScheduleRow(_ref) {
561
611
  filterOption: filterSlots,
562
612
  isValidNewOption: isValidTimeSlotOption,
563
613
  name: "wdays.".concat(day, ".periods[").concat(index, "].endTime"),
564
- options: sortSlotsInterval("endTime", period === null || period === void 0 ? void 0 : period.endTime),
614
+ options: endTimeOptions(period),
565
615
  placeholder: t("neetoMolecules.schedule.endTime"),
566
616
  strategy: "fixed",
567
617
  styles: BLUR_TEXT_WHEN_SELECT_MENU_IS_OPEN,
568
- value: slotsSelectComponentDefaultValue(period === null || period === void 0 ? void 0 : period.endTime),
618
+ value: findBy({
619
+ value: period === null || period === void 0 ? void 0 : period.endTime
620
+ }, endTimeOptions(period)),
569
621
  onChange: function onChange(e) {
570
622
  return handleChange(index, "endTime", e);
571
623
  }
@@ -901,7 +953,9 @@ var Schedule = /*#__PURE__*/forwardRef(function (_ref, scheduleRef) {
901
953
  _ref$showTimeZone = _ref.showTimeZone,
902
954
  showTimeZone = _ref$showTimeZone === void 0 ? true : _ref$showTimeZone,
903
955
  _ref$slotInterval = _ref.slotInterval,
904
- slotInterval = _ref$slotInterval === void 0 ? DEFAULT_SLOT_INTERVAL : _ref$slotInterval;
956
+ slotInterval = _ref$slotInterval === void 0 ? DEFAULT_SLOT_INTERVAL : _ref$slotInterval,
957
+ _ref$hourFormat = _ref.hourFormat,
958
+ hourFormat = _ref$hourFormat === void 0 ? DEFAULT_HOUR_FORMAT : _ref$hourFormat;
905
959
  var validationSchema = useMemo(getScheduleValidationSchema, []);
906
960
  var getInitialFormValues = function getInitialFormValues() {
907
961
  var isSubmitHandler = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
@@ -919,7 +973,8 @@ var Schedule = /*#__PURE__*/forwardRef(function (_ref, scheduleRef) {
919
973
  value: {
920
974
  allowAddPeriod: allowAddPeriod,
921
975
  firstDay: firstDay,
922
- slotInterval: slotInterval
976
+ slotInterval: slotInterval,
977
+ hourFormat: hourFormat
923
978
  },
924
979
  children: /*#__PURE__*/jsx("div", {
925
980
  className: "neeto-molecules-schedule neeto-ui-border-gray-200 flex-shrink-0",