@optifye/dashboard-core 6.11.39 → 6.11.41

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/index.js CHANGED
@@ -1,11 +1,11 @@
1
1
  'use strict';
2
2
 
3
+ var dateFns = require('date-fns');
4
+ var dateFnsTz = require('date-fns-tz');
3
5
  var React143 = require('react');
4
6
  var jsxRuntime = require('react/jsx-runtime');
5
7
  var router = require('next/router');
6
8
  var sonner = require('sonner');
7
- var dateFnsTz = require('date-fns-tz');
8
- var dateFns = require('date-fns');
9
9
  var mixpanel = require('mixpanel-browser');
10
10
  var events = require('events');
11
11
  var supabaseJs = require('@supabase/supabase-js');
@@ -1661,6 +1661,149 @@ function isValidPrefetchParams(params) {
1661
1661
  function isValidPrefetchStatus(status) {
1662
1662
  return typeof status === "string" && Object.values(PrefetchStatus).includes(status);
1663
1663
  }
1664
+ var getOperationalDate = (timezone, date = /* @__PURE__ */ new Date(), shiftStartTime = "06:00") => {
1665
+ const zonedDate = dateFnsTz.toZonedTime(date, timezone);
1666
+ const hours = zonedDate.getHours();
1667
+ const minutes = zonedDate.getMinutes();
1668
+ const [startHourRaw, startMinuteRaw] = shiftStartTime.split(":").map(Number);
1669
+ const startHour = Number.isFinite(startHourRaw) ? startHourRaw : 6;
1670
+ const startMinute = Number.isFinite(startMinuteRaw) ? startMinuteRaw : 0;
1671
+ const currentTotalMinutes = hours * 60 + minutes;
1672
+ const shiftStartTotalMinutes = startHour * 60 + startMinute;
1673
+ const operationalDate = currentTotalMinutes < shiftStartTotalMinutes ? dateFns.subDays(zonedDate, 1) : zonedDate;
1674
+ return dateFns.format(operationalDate, "yyyy-MM-dd");
1675
+ };
1676
+ function formatTimeInZone(time2, timezone, formatString = "HH:mm:ss") {
1677
+ const dateObj = typeof time2 === "string" ? dateFns.parseISO(time2) : time2;
1678
+ if (!dateFns.isValid(dateObj)) return "Invalid Date";
1679
+ return dateFnsTz.formatInTimeZone(dateObj, timezone, formatString);
1680
+ }
1681
+ function getCurrentTimeInZone(timezone, formatString) {
1682
+ const now4 = /* @__PURE__ */ new Date();
1683
+ if (formatString) {
1684
+ if (!dateFns.isValid(now4)) return "Invalid Date";
1685
+ return dateFnsTz.formatInTimeZone(now4, timezone, formatString);
1686
+ }
1687
+ return now4;
1688
+ }
1689
+ var pad2 = (value) => String(value).padStart(2, "0");
1690
+ var DATE_KEY_PREFIX_PATTERN = /^(\d{4}-\d{2}-\d{2})/;
1691
+ var buildDateKey = (year, monthIndex, day) => {
1692
+ return `${year}-${pad2(monthIndex + 1)}-${pad2(day)}`;
1693
+ };
1694
+ var getDateKeyFromDate = (date) => {
1695
+ return buildDateKey(date.getFullYear(), date.getMonth(), date.getDate());
1696
+ };
1697
+ var parseDateKeyToDate = (dateKey) => {
1698
+ const [year, month, day] = dateKey.split("-").map(Number);
1699
+ return new Date(year, month - 1, day, 12, 0, 0, 0);
1700
+ };
1701
+ var getDateKeyFromValue = (value) => {
1702
+ if (typeof value === "string") {
1703
+ const keyMatch = value.match(DATE_KEY_PREFIX_PATTERN);
1704
+ if (keyMatch?.[1]) {
1705
+ return keyMatch[1];
1706
+ }
1707
+ const parsed = dateFns.parseISO(value);
1708
+ if (dateFns.isValid(parsed)) {
1709
+ return getDateKeyFromDate(parsed);
1710
+ }
1711
+ return value;
1712
+ }
1713
+ return getDateKeyFromDate(value);
1714
+ };
1715
+ var formatDateKeyForDisplay = (dateKey, formatStr = "MMM d, yyyy") => {
1716
+ return dateFns.format(parseDateKeyToDate(dateKey), formatStr);
1717
+ };
1718
+ var getMonthKeyBounds = (year, monthIndex) => {
1719
+ const startKey = buildDateKey(year, monthIndex, 1);
1720
+ const lastDay = new Date(year, monthIndex + 1, 0).getDate();
1721
+ const endKey = buildDateKey(year, monthIndex, lastDay);
1722
+ return { startKey, endKey };
1723
+ };
1724
+ var getCurrentWeekToDateRange = (timezone, now4 = /* @__PURE__ */ new Date()) => {
1725
+ const todayKey = dateFnsTz.formatInTimeZone(now4, timezone || "UTC", "yyyy-MM-dd");
1726
+ const todayDate = dateFns.parseISO(`${todayKey}T00:00:00`);
1727
+ const dayOfWeek = dateFns.getDay(todayDate);
1728
+ const daysSinceMonday = dayOfWeek === 0 ? 6 : dayOfWeek - 1;
1729
+ const weekStart = dateFns.subDays(todayDate, daysSinceMonday);
1730
+ return {
1731
+ startKey: dateFns.format(weekStart, "yyyy-MM-dd"),
1732
+ endKey: dateFns.format(todayDate, "yyyy-MM-dd")
1733
+ };
1734
+ };
1735
+ var getCurrentWeekFullRange = (timezone, now4 = /* @__PURE__ */ new Date()) => {
1736
+ const currentWeekToDateRange = getCurrentWeekToDateRange(timezone, now4);
1737
+ const weekStart = parseDateKeyToDate(currentWeekToDateRange.startKey);
1738
+ return {
1739
+ startKey: currentWeekToDateRange.startKey,
1740
+ endKey: dateFns.format(dateFns.addDays(weekStart, 6), "yyyy-MM-dd")
1741
+ };
1742
+ };
1743
+ var normalizeDateKeyRange = (startKey, endKey, minKey, maxKey) => {
1744
+ const clampedStart = startKey < minKey ? minKey : startKey > maxKey ? maxKey : startKey;
1745
+ const clampedEnd = endKey < minKey ? minKey : endKey > maxKey ? maxKey : endKey;
1746
+ if (clampedStart <= clampedEnd) {
1747
+ return { startKey: clampedStart, endKey: clampedEnd };
1748
+ }
1749
+ return { startKey: clampedEnd, endKey: clampedStart };
1750
+ };
1751
+ var isFullMonthRange = (range, year, monthIndex) => {
1752
+ const bounds = getMonthKeyBounds(year, monthIndex);
1753
+ return range.startKey === bounds.startKey && range.endKey === bounds.endKey;
1754
+ };
1755
+ var getMonthlyTrendComparisonLabel = (range, year, monthIndex) => {
1756
+ if (isFullMonthRange(range, year, monthIndex)) {
1757
+ return "last month";
1758
+ }
1759
+ return range.startKey === range.endKey ? "previous day" : "previous range";
1760
+ };
1761
+ var getMonthWeekRanges = (year, monthIndex, timezone, maxKey) => {
1762
+ const totalDays = new Date(year, monthIndex + 1, 0).getDate();
1763
+ const ranges = [];
1764
+ let currentStartDay = 1;
1765
+ for (let day = 1; day <= totalDays; day += 1) {
1766
+ const zonedDate = dateFnsTz.toZonedTime(new Date(year, monthIndex, day), timezone);
1767
+ const dayOfWeek = zonedDate.getDay();
1768
+ const isEndOfWeek = dayOfWeek === 0 || day === totalDays;
1769
+ if (isEndOfWeek) {
1770
+ const startKey = buildDateKey(year, monthIndex, currentStartDay);
1771
+ const endKey = buildDateKey(year, monthIndex, day);
1772
+ if (maxKey && startKey > maxKey) {
1773
+ break;
1774
+ }
1775
+ const clampedEndKey = maxKey && endKey > maxKey ? maxKey : endKey;
1776
+ if (clampedEndKey < startKey) {
1777
+ break;
1778
+ }
1779
+ const labelStart = formatDateKeyForDisplay(startKey, "MMM d");
1780
+ const labelEnd = formatDateKeyForDisplay(clampedEndKey, "MMM d");
1781
+ ranges.push({
1782
+ startKey,
1783
+ endKey: clampedEndKey,
1784
+ label: `Week of ${labelStart} - ${labelEnd}`
1785
+ });
1786
+ currentStartDay = day + 1;
1787
+ }
1788
+ }
1789
+ return ranges;
1790
+ };
1791
+ var formatRangeLabel = (range, fullMonthLabel) => {
1792
+ if (!range.startKey || !range.endKey) return fullMonthLabel;
1793
+ if (range.startKey === range.endKey) {
1794
+ return formatDateKeyForDisplay(range.startKey, "MMM d, yyyy");
1795
+ }
1796
+ const startLabel = formatDateKeyForDisplay(range.startKey, "MMM d");
1797
+ const endLabel = formatDateKeyForDisplay(range.endKey, "MMM d, yyyy");
1798
+ return `${startLabel} - ${endLabel}`;
1799
+ };
1800
+ var filterDataByDateKeyRange = (data, range) => {
1801
+ if (!range.startKey || !range.endKey) return data;
1802
+ return (data || []).filter((item) => {
1803
+ const dateKey = item.dateKey || getDateKeyFromValue(item.date);
1804
+ return dateKey >= range.startKey && dateKey <= range.endKey;
1805
+ });
1806
+ };
1664
1807
 
1665
1808
  // src/lib/types/calendar.ts
1666
1809
  var DEFAULT_SHIFT_DATA = {
@@ -1692,6 +1835,9 @@ var hasAnyShiftData = (day) => {
1692
1835
  var getAvailableShiftIds = (day) => {
1693
1836
  return Object.keys(day.shifts).map(Number).sort((a, b) => a - b);
1694
1837
  };
1838
+ var getDayDateKey = (day) => {
1839
+ return day.dateKey || getDateKeyFromDate(day.date);
1840
+ };
1695
1841
 
1696
1842
  // src/components/dashboard/grid/workspace_grid_constants.ts
1697
1843
  var DEFAULT_WORKSPACE_POSITIONS = [
@@ -3347,136 +3493,6 @@ var memoizedOutputArrayAggregation = createMemoizedFunction(
3347
3493
  },
3348
3494
  (arrays) => arrays.map((arr) => arr.length).join("-")
3349
3495
  );
3350
- var getOperationalDate = (timezone, date = /* @__PURE__ */ new Date(), shiftStartTime = "06:00") => {
3351
- const zonedDate = dateFnsTz.toZonedTime(date, timezone);
3352
- const hours = zonedDate.getHours();
3353
- const minutes = zonedDate.getMinutes();
3354
- const [startHourRaw, startMinuteRaw] = shiftStartTime.split(":").map(Number);
3355
- const startHour = Number.isFinite(startHourRaw) ? startHourRaw : 6;
3356
- const startMinute = Number.isFinite(startMinuteRaw) ? startMinuteRaw : 0;
3357
- const currentTotalMinutes = hours * 60 + minutes;
3358
- const shiftStartTotalMinutes = startHour * 60 + startMinute;
3359
- const operationalDate = currentTotalMinutes < shiftStartTotalMinutes ? dateFns.subDays(zonedDate, 1) : zonedDate;
3360
- return dateFns.format(operationalDate, "yyyy-MM-dd");
3361
- };
3362
- function formatTimeInZone(time2, timezone, formatString = "HH:mm:ss") {
3363
- const dateObj = typeof time2 === "string" ? dateFns.parseISO(time2) : time2;
3364
- if (!dateFns.isValid(dateObj)) return "Invalid Date";
3365
- return dateFnsTz.formatInTimeZone(dateObj, timezone, formatString);
3366
- }
3367
- function getCurrentTimeInZone(timezone, formatString) {
3368
- const now4 = /* @__PURE__ */ new Date();
3369
- if (formatString) {
3370
- if (!dateFns.isValid(now4)) return "Invalid Date";
3371
- return dateFnsTz.formatInTimeZone(now4, timezone, formatString);
3372
- }
3373
- return now4;
3374
- }
3375
- var pad2 = (value) => String(value).padStart(2, "0");
3376
- var buildDateKey = (year, monthIndex, day) => {
3377
- return `${year}-${pad2(monthIndex + 1)}-${pad2(day)}`;
3378
- };
3379
- var getDateKeyFromDate = (date) => {
3380
- return date.toISOString().split("T")[0];
3381
- };
3382
- var parseDateKeyToDate = (dateKey) => {
3383
- const [year, month, day] = dateKey.split("-").map(Number);
3384
- return new Date(year, month - 1, day);
3385
- };
3386
- var formatDateKeyForDisplay = (dateKey, formatStr = "MMM d, yyyy") => {
3387
- return dateFns.format(parseDateKeyToDate(dateKey), formatStr);
3388
- };
3389
- var getMonthKeyBounds = (year, monthIndex) => {
3390
- const startKey = buildDateKey(year, monthIndex, 1);
3391
- const lastDay = new Date(year, monthIndex + 1, 0).getDate();
3392
- const endKey = buildDateKey(year, monthIndex, lastDay);
3393
- return { startKey, endKey };
3394
- };
3395
- var getCurrentWeekToDateRange = (timezone, now4 = /* @__PURE__ */ new Date()) => {
3396
- const todayKey = dateFnsTz.formatInTimeZone(now4, timezone || "UTC", "yyyy-MM-dd");
3397
- const todayDate = dateFns.parseISO(`${todayKey}T00:00:00`);
3398
- const dayOfWeek = dateFns.getDay(todayDate);
3399
- const daysSinceMonday = dayOfWeek === 0 ? 6 : dayOfWeek - 1;
3400
- const weekStart = dateFns.subDays(todayDate, daysSinceMonday);
3401
- return {
3402
- startKey: dateFns.format(weekStart, "yyyy-MM-dd"),
3403
- endKey: dateFns.format(todayDate, "yyyy-MM-dd")
3404
- };
3405
- };
3406
- var getCurrentWeekFullRange = (timezone, now4 = /* @__PURE__ */ new Date()) => {
3407
- const currentWeekToDateRange = getCurrentWeekToDateRange(timezone, now4);
3408
- const weekStart = parseDateKeyToDate(currentWeekToDateRange.startKey);
3409
- return {
3410
- startKey: currentWeekToDateRange.startKey,
3411
- endKey: dateFns.format(dateFns.addDays(weekStart, 6), "yyyy-MM-dd")
3412
- };
3413
- };
3414
- var normalizeDateKeyRange = (startKey, endKey, minKey, maxKey) => {
3415
- const clampedStart = startKey < minKey ? minKey : startKey > maxKey ? maxKey : startKey;
3416
- const clampedEnd = endKey < minKey ? minKey : endKey > maxKey ? maxKey : endKey;
3417
- if (clampedStart <= clampedEnd) {
3418
- return { startKey: clampedStart, endKey: clampedEnd };
3419
- }
3420
- return { startKey: clampedEnd, endKey: clampedStart };
3421
- };
3422
- var isFullMonthRange = (range, year, monthIndex) => {
3423
- const bounds = getMonthKeyBounds(year, monthIndex);
3424
- return range.startKey === bounds.startKey && range.endKey === bounds.endKey;
3425
- };
3426
- var getMonthlyTrendComparisonLabel = (range, year, monthIndex) => {
3427
- if (isFullMonthRange(range, year, monthIndex)) {
3428
- return "last month";
3429
- }
3430
- return range.startKey === range.endKey ? "previous day" : "previous range";
3431
- };
3432
- var getMonthWeekRanges = (year, monthIndex, timezone, maxKey) => {
3433
- const totalDays = new Date(year, monthIndex + 1, 0).getDate();
3434
- const ranges = [];
3435
- let currentStartDay = 1;
3436
- for (let day = 1; day <= totalDays; day += 1) {
3437
- const zonedDate = dateFnsTz.toZonedTime(new Date(year, monthIndex, day), timezone);
3438
- const dayOfWeek = zonedDate.getDay();
3439
- const isEndOfWeek = dayOfWeek === 0 || day === totalDays;
3440
- if (isEndOfWeek) {
3441
- const startKey = buildDateKey(year, monthIndex, currentStartDay);
3442
- const endKey = buildDateKey(year, monthIndex, day);
3443
- if (maxKey && startKey > maxKey) {
3444
- break;
3445
- }
3446
- const clampedEndKey = maxKey && endKey > maxKey ? maxKey : endKey;
3447
- if (clampedEndKey < startKey) {
3448
- break;
3449
- }
3450
- const labelStart = formatDateKeyForDisplay(startKey, "MMM d");
3451
- const labelEnd = formatDateKeyForDisplay(clampedEndKey, "MMM d");
3452
- ranges.push({
3453
- startKey,
3454
- endKey: clampedEndKey,
3455
- label: `Week of ${labelStart} - ${labelEnd}`
3456
- });
3457
- currentStartDay = day + 1;
3458
- }
3459
- }
3460
- return ranges;
3461
- };
3462
- var formatRangeLabel = (range, fullMonthLabel) => {
3463
- if (!range.startKey || !range.endKey) return fullMonthLabel;
3464
- if (range.startKey === range.endKey) {
3465
- return formatDateKeyForDisplay(range.startKey, "MMM d, yyyy");
3466
- }
3467
- const startLabel = formatDateKeyForDisplay(range.startKey, "MMM d");
3468
- const endLabel = formatDateKeyForDisplay(range.endKey, "MMM d, yyyy");
3469
- return `${startLabel} - ${endLabel}`;
3470
- };
3471
- var filterDataByDateKeyRange = (data, range) => {
3472
- if (!range.startKey || !range.endKey) return data;
3473
- return (data || []).filter((item) => {
3474
- const dateKey = typeof item.date === "string" ? item.date : getDateKeyFromDate(item.date);
3475
- return dateKey >= range.startKey && dateKey <= range.endKey;
3476
- });
3477
- };
3478
-
3479
- // src/lib/utils/shifts.ts
3480
3496
  var DEFAULT_DAY_SHIFT_START = "06:00";
3481
3497
  var DEFAULT_NIGHT_SHIFT_START = "18:00";
3482
3498
  var DEFAULT_TRANSITION_MINUTES = 15;
@@ -46559,6 +46575,7 @@ var getLineShiftData = (day, shiftId) => {
46559
46575
  }
46560
46576
  return { ...DEFAULT_LINE_SHIFT_DATA };
46561
46577
  };
46578
+ var getLineDayDateKey = (day) => day.dateKey || getDateKeyFromValue(day.date);
46562
46579
  var WEEKDAYS = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
46563
46580
  var LineHistoryCalendar = ({
46564
46581
  data,
@@ -46593,20 +46610,16 @@ var LineHistoryCalendar = ({
46593
46610
  for (let day = 1; day <= totalDays; day++) {
46594
46611
  const currentDate = dateFnsTz.toZonedTime(new Date(year, month, day), configuredTimezone);
46595
46612
  const currentDateString = `${currentDate.getFullYear()}-${String(currentDate.getMonth() + 1).padStart(2, "0")}-${String(currentDate.getDate()).padStart(2, "0")}`;
46596
- const existingData = data.find((d) => {
46597
- if (!d.date) return false;
46598
- const dDate = typeof d.date === "string" ? new Date(d.date) : d.date;
46599
- const dDateIST = dateFnsTz.toZonedTime(dDate, configuredTimezone);
46600
- const dDateString = `${dDateIST.getFullYear()}-${String(dDateIST.getMonth() + 1).padStart(2, "0")}-${String(dDateIST.getDate()).padStart(2, "0")}`;
46601
- return dDateString === currentDateString;
46602
- });
46613
+ const existingData = data.find((d) => d && getLineDayDateKey(d) === currentDateString);
46603
46614
  if (existingData) {
46604
46615
  calendar.push({
46605
46616
  ...existingData,
46617
+ dateKey: getLineDayDateKey(existingData),
46606
46618
  date: currentDate
46607
46619
  });
46608
46620
  } else {
46609
46621
  calendar.push({
46622
+ dateKey: currentDateString,
46610
46623
  date: currentDate,
46611
46624
  shifts: {}
46612
46625
  });
@@ -46678,7 +46691,7 @@ var LineHistoryCalendar = ({
46678
46691
  const isFuture = isFutureDate(day.date instanceof Date ? day.date : new Date(day.date));
46679
46692
  const hasData = hasRealData(shiftData);
46680
46693
  const dateObj = day.date instanceof Date ? day.date : new Date(day.date);
46681
- const dateKey = `${dateObj.getFullYear()}-${String(dateObj.getMonth() + 1).padStart(2, "0")}-${String(dateObj.getDate()).padStart(2, "0")}`;
46694
+ const dateKey = getLineDayDateKey(day);
46682
46695
  const showRange = rangeStart && rangeEnd ? !(rangeStart === monthBounds.startKey && rangeEnd === monthBounds.endKey) : false;
46683
46696
  const inRange = showRange ? dateKey >= rangeStart && dateKey <= rangeEnd : false;
46684
46697
  const isRangeEdge = inRange && (dateKey === rangeStart || dateKey === rangeEnd);
@@ -46689,11 +46702,7 @@ var LineHistoryCalendar = ({
46689
46702
  className: `group h-full ${isFuture || !hasData || isFilteredOut ? "cursor-not-allowed" : "cursor-pointer hover:opacity-90"}`,
46690
46703
  onClick: () => {
46691
46704
  if (!isFuture && hasData && !isFilteredOut) {
46692
- const dateObj2 = day.date instanceof Date ? day.date : new Date(day.date);
46693
- const year2 = dateObj2.getFullYear();
46694
- const month2 = String(dateObj2.getMonth() + 1).padStart(2, "0");
46695
- const dayOfMonth = String(dateObj2.getDate()).padStart(2, "0");
46696
- const date = `${year2}-${month2}-${dayOfMonth}`;
46705
+ const date = getLineDayDateKey(day);
46697
46706
  trackCoreEvent("Line Monthly History Day Clicked", {
46698
46707
  source: "line_kpi",
46699
46708
  line_id: lineId,
@@ -46705,8 +46714,8 @@ var LineHistoryCalendar = ({
46705
46714
  });
46706
46715
  const params = new URLSearchParams();
46707
46716
  params.set("tab", "monthly_history");
46708
- params.set("month", month2.toString());
46709
- params.set("year", year2.toString());
46717
+ params.set("month", month.toString());
46718
+ params.set("year", year.toString());
46710
46719
  if (rangeStart && rangeEnd && !(rangeStart === monthBounds.startKey && rangeEnd === monthBounds.endKey)) {
46711
46720
  params.set("rangeStart", rangeStart);
46712
46721
  params.set("rangeEnd", rangeEnd);
@@ -47175,6 +47184,7 @@ var getShiftData2 = (day, shiftId) => {
47175
47184
  }
47176
47185
  return { ...DEFAULT_PERFORMANCE_DATA };
47177
47186
  };
47187
+ var getLineDayDateKey2 = (day) => day.dateKey || getDateKeyFromValue(day.date);
47178
47188
  var getUptimeTotals = (shift, hasShiftData) => {
47179
47189
  if (!shift) {
47180
47190
  return { availableSeconds: 0, productiveSeconds: 0, idleSeconds: 0 };
@@ -47232,6 +47242,10 @@ var LineMonthlyHistory = ({
47232
47242
  }
47233
47243
  return filterDataByDateKeyRange(monthlyData, normalizedRange);
47234
47244
  }, [analysisData, monthlyData, normalizedRange]);
47245
+ const analysisMonthlyDataByKey = React143.useMemo(
47246
+ () => new Map((analysisMonthlyData || []).map((day) => [getLineDayDateKey2(day), day])),
47247
+ [analysisMonthlyData]
47248
+ );
47235
47249
  const startDate = normalizedRange.startKey;
47236
47250
  const endDate = normalizedRange.endKey;
47237
47251
  const {
@@ -47338,9 +47352,9 @@ var LineMonthlyHistory = ({
47338
47352
  const chartData = React143.useMemo(() => {
47339
47353
  const rangeStartDate = parseDateKeyToDate(normalizedRange.startKey);
47340
47354
  const rangeEndDate = parseDateKeyToDate(normalizedRange.endKey);
47341
- const dayNumbers = [];
47355
+ const rangeDateKeys = [];
47342
47356
  for (let d = new Date(rangeStartDate); d <= rangeEndDate; d.setDate(d.getDate() + 1)) {
47343
- dayNumbers.push(d.getDate());
47357
+ rangeDateKeys.push(buildDateKey(d.getFullYear(), d.getMonth(), d.getDate()));
47344
47358
  }
47345
47359
  if (isUptimeMode) {
47346
47360
  const dailyData2 = [];
@@ -47348,13 +47362,10 @@ var LineMonthlyHistory = ({
47348
47362
  const todayInZone = getCurrentTimeInZone(timezone);
47349
47363
  const todayDate = typeof todayInZone === "string" ? new Date(todayInZone) : todayInZone;
47350
47364
  const todayKey = `${todayDate.getFullYear()}-${String(todayDate.getMonth() + 1).padStart(2, "0")}-${String(todayDate.getDate()).padStart(2, "0")}`;
47351
- for (const day of dayNumbers) {
47352
- const dayKey = `${rangeStartDate.getFullYear()}-${String(rangeStartDate.getMonth() + 1).padStart(2, "0")}-${String(day).padStart(2, "0")}`;
47365
+ for (const dayKey of rangeDateKeys) {
47366
+ const day = Number(dayKey.slice(-2));
47353
47367
  const isFutureDay = dayKey > todayKey;
47354
- const dayData = analysisMonthlyData.find((d) => {
47355
- const date = new Date(d.date);
47356
- return date.getDate() === day;
47357
- });
47368
+ const dayData = analysisMonthlyDataByKey.get(dayKey);
47358
47369
  const shiftData = dayData ? getShiftData2(dayData, selectedShiftId) : null;
47359
47370
  const hasShiftData = Boolean(shiftData && hasRealData(shiftData));
47360
47371
  const efficiencyValue = hasShiftData && Number.isFinite(shiftData?.avg_efficiency) ? Number(shiftData?.avg_efficiency) : 0;
@@ -47376,12 +47387,9 @@ var LineMonthlyHistory = ({
47376
47387
  const dailyData = [];
47377
47388
  let maxOutput = 0;
47378
47389
  let lastSetTarget = 0;
47379
- for (let i = dayNumbers.length - 1; i >= 0; i--) {
47380
- const day = dayNumbers[i];
47381
- const dayData = analysisMonthlyData.find((d) => {
47382
- const date = new Date(d.date);
47383
- return date.getDate() === day;
47384
- });
47390
+ for (let i = rangeDateKeys.length - 1; i >= 0; i--) {
47391
+ const dayKey = rangeDateKeys[i];
47392
+ const dayData = analysisMonthlyDataByKey.get(dayKey);
47385
47393
  const shiftData = dayData ? getShiftData2(dayData, selectedShiftId) : null;
47386
47394
  const idealOutput = shiftData ? shiftData.idealOutput || 0 : 0;
47387
47395
  if (idealOutput > 0) {
@@ -47389,11 +47397,9 @@ var LineMonthlyHistory = ({
47389
47397
  break;
47390
47398
  }
47391
47399
  }
47392
- for (const day of dayNumbers) {
47393
- const dayData = analysisMonthlyData.find((d) => {
47394
- const date = new Date(d.date);
47395
- return date.getDate() === day;
47396
- });
47400
+ for (const dayKey of rangeDateKeys) {
47401
+ const day = Number(dayKey.slice(-2));
47402
+ const dayData = analysisMonthlyDataByKey.get(dayKey);
47397
47403
  const shiftData = dayData ? getShiftData2(dayData, selectedShiftId) : null;
47398
47404
  const output = shiftData && hasRealData(shiftData) ? shiftData.output || 0 : 0;
47399
47405
  const idealOutput = shiftData ? shiftData.idealOutput || 0 : 0;
@@ -47413,7 +47419,7 @@ var LineMonthlyHistory = ({
47413
47419
  const calculatedMax = Math.max(maxOutput, lastSetTarget);
47414
47420
  const yAxisMax = calculatedMax > 0 ? calculatedMax * 1.1 : 100;
47415
47421
  return { data: dailyData, maxOutput, lastSetTarget, yAxisMax };
47416
- }, [analysisMonthlyData, normalizedRange.startKey, normalizedRange.endKey, selectedShiftId, isUptimeMode, timezone]);
47422
+ }, [analysisMonthlyDataByKey, normalizedRange.endKey, normalizedRange.startKey, selectedShiftId, isUptimeMode, timezone]);
47417
47423
  const yAxisTicks = React143.useMemo(() => {
47418
47424
  const max = chartData.yAxisMax;
47419
47425
  const target = chartData.lastSetTarget;
@@ -47901,6 +47907,7 @@ var getShiftDisplayName = (shiftId, availableShifts) => {
47901
47907
  if (shiftId === 1) return "Night Shift";
47902
47908
  return `Shift ${shiftId}`;
47903
47909
  };
47910
+ var getLineDayDateKey3 = (day) => day.dateKey || getDateKeyFromValue(day.date);
47904
47911
  var LineMonthlyPdfGenerator = ({
47905
47912
  lineId,
47906
47913
  lineName,
@@ -47930,13 +47937,20 @@ var LineMonthlyPdfGenerator = ({
47930
47937
  startKey: rangeStart || monthBounds.startKey,
47931
47938
  endKey: rangeEnd || monthBounds.endKey
47932
47939
  };
47940
+ const boundsSourceKey = rangeStart || rangeEnd || monthBounds.startKey;
47941
+ const boundsSourceDate = parseDateKeyToDate(boundsSourceKey);
47942
+ const effectiveBounds = getMonthKeyBounds(boundsSourceDate.getFullYear(), boundsSourceDate.getMonth());
47933
47943
  const normalizedRange = normalizeDateKeyRange(
47934
47944
  requestedRange.startKey,
47935
47945
  requestedRange.endKey,
47936
- monthBounds.startKey,
47937
- monthBounds.endKey
47946
+ effectiveBounds.startKey,
47947
+ effectiveBounds.endKey
47948
+ );
47949
+ const fullRange = isFullMonthRange(
47950
+ normalizedRange,
47951
+ boundsSourceDate.getFullYear(),
47952
+ boundsSourceDate.getMonth()
47938
47953
  );
47939
- const fullRange = isFullMonthRange(normalizedRange, selectedYear, selectedMonth);
47940
47954
  const reportStartDate = parseDateKeyToDate(normalizedRange.startKey);
47941
47955
  const reportEndDate = parseDateKeyToDate(normalizedRange.endKey);
47942
47956
  const reportStartStr = reportStartDate.toLocaleDateString("en-IN", {
@@ -47954,8 +47968,8 @@ var LineMonthlyPdfGenerator = ({
47954
47968
  trackCoreEvent("Line Monthly PDF Export Clicked", {
47955
47969
  line_id: lineId,
47956
47970
  line_name: lineName,
47957
- month: selectedMonth,
47958
- year: selectedYear,
47971
+ month: reportStartDate.getMonth(),
47972
+ year: reportStartDate.getFullYear(),
47959
47973
  shift_id: selectedShiftId,
47960
47974
  range_start: normalizedRange.startKey,
47961
47975
  range_end: normalizedRange.endKey,
@@ -47967,6 +47981,11 @@ var LineMonthlyPdfGenerator = ({
47967
47981
  const maxContentY = footerY - 10;
47968
47982
  const generatedText = `Generated on ${(/* @__PURE__ */ new Date()).toLocaleString("en-IN", { timeZone: "Asia/Kolkata" })}`;
47969
47983
  const dailySectionTitle = isUptimeMode ? "Daily Utilization Summary" : "Daily Performance Summary";
47984
+ const monthName = reportStartDate.toLocaleDateString("en-IN", {
47985
+ month: "long",
47986
+ year: "numeric",
47987
+ timeZone: "Asia/Kolkata"
47988
+ });
47970
47989
  const drawPageChrome = () => {
47971
47990
  doc.setFontSize(14);
47972
47991
  doc.setFont("helvetica", "bold");
@@ -47998,11 +48017,6 @@ var LineMonthlyPdfGenerator = ({
47998
48017
  doc.setFontSize(13);
47999
48018
  doc.setFont("helvetica", "normal");
48000
48019
  doc.setTextColor(60, 60, 60);
48001
- const monthName = new Date(selectedYear, selectedMonth).toLocaleDateString("en-IN", {
48002
- month: "long",
48003
- year: "numeric",
48004
- timeZone: "Asia/Kolkata"
48005
- });
48006
48020
  const shiftType = getShiftDisplayName(selectedShiftId, availableShifts);
48007
48021
  doc.text(`${monthName}`, 20, 55);
48008
48022
  doc.text(`${shiftType}`, 20, 63);
@@ -48015,10 +48029,7 @@ var LineMonthlyPdfGenerator = ({
48015
48029
  const mainSeparatorY = isUptimeMode ? 90 : 85;
48016
48030
  doc.line(20, mainSeparatorY, 190, mainSeparatorY);
48017
48031
  const reportData = analysisData ? analysisData : filterDataByDateKeyRange(monthlyData, normalizedRange);
48018
- const validDays = reportData.filter((day) => {
48019
- const date = new Date(day.date);
48020
- return date.getMonth() === selectedMonth && date.getFullYear() === selectedYear;
48021
- });
48032
+ const validDays = reportData;
48022
48033
  const hasShiftData = (shift) => {
48023
48034
  if (shift.hasData !== void 0) return shift.hasData;
48024
48035
  return shift.total_workspaces > 0 || shift.avg_efficiency > 0 || shift.underperforming_workspaces > 0 || (shift.available_time_seconds ?? 0) > 0 || (shift.idle_time_seconds ?? 0) > 0 || (shift.output ?? 0) > 0;
@@ -48026,7 +48037,7 @@ var LineMonthlyPdfGenerator = ({
48026
48037
  const dailyEntries = validDays.map((dayData) => {
48027
48038
  const shift = getLineShiftData2(dayData, selectedShiftId);
48028
48039
  return { dayData, shift };
48029
- }).filter(({ shift }) => hasShiftData(shift)).sort((left, right) => new Date(right.dayData.date).getTime() - new Date(left.dayData.date).getTime());
48040
+ }).filter(({ shift }) => hasShiftData(shift)).sort((left, right) => getLineDayDateKey3(right.dayData).localeCompare(getLineDayDateKey3(left.dayData)));
48030
48041
  const getUptimeTotals2 = (shift, hasData) => {
48031
48042
  if (!hasData || !shift) {
48032
48043
  return { availableSeconds: 0, productiveSeconds: 0, idleSeconds: 0 };
@@ -49910,6 +49921,7 @@ var formatHours = (value) => {
49910
49921
  if (Math.abs(rounded) < 0.05) return "0h";
49911
49922
  return Number.isInteger(rounded) ? `${rounded}h` : `${rounded.toFixed(1)}h`;
49912
49923
  };
49924
+ var roundToSingleDecimal = (value) => Math.round(value * 10) / 10;
49913
49925
  var formatCycleSeconds = (value) => {
49914
49926
  if (!Number.isFinite(value)) return "0.0s";
49915
49927
  return `${value.toFixed(1)}s`;
@@ -50035,21 +50047,30 @@ var WorkspaceMonthlyHistory = ({
50035
50047
  if (!shiftConfig) return null;
50036
50048
  return getShiftWorkDurationSeconds(shiftConfig, selectedShiftId);
50037
50049
  }, [shiftConfig, selectedShiftId]);
50038
- const chartData = React143.useMemo(() => {
50050
+ const analysisMonthlyDataByKey = React143.useMemo(
50051
+ () => new Map(analysisMonthlyData.map((day) => [getDayDateKey(day), day])),
50052
+ [analysisMonthlyData]
50053
+ );
50054
+ const monthlyDataByKey = React143.useMemo(
50055
+ () => new Map(data.map((day) => [getDayDateKey(day), day])),
50056
+ [data]
50057
+ );
50058
+ const rangeDateKeys = React143.useMemo(() => {
50039
50059
  const rangeStartDate = parseDateKeyToDate(normalizedRange.startKey);
50040
50060
  const rangeEndDate = parseDateKeyToDate(normalizedRange.endKey);
50041
- const dayNumbers = [];
50061
+ const keys = [];
50042
50062
  for (let d = new Date(rangeStartDate); d <= rangeEndDate; d.setDate(d.getDate() + 1)) {
50043
- dayNumbers.push(d.getDate());
50063
+ keys.push(buildDateKey(d.getFullYear(), d.getMonth(), d.getDate()));
50044
50064
  }
50065
+ return keys;
50066
+ }, [normalizedRange.endKey, normalizedRange.startKey]);
50067
+ const chartData = React143.useMemo(() => {
50045
50068
  const dailyData = [];
50046
50069
  if (isUptimeMode) {
50047
50070
  let maxHours = 0;
50048
- for (const day of dayNumbers) {
50049
- const dayData = analysisMonthlyData.find((d) => {
50050
- const date = new Date(d.date);
50051
- return date.getDate() === day;
50052
- });
50071
+ for (const dateKey of rangeDateKeys) {
50072
+ const dayData = analysisMonthlyDataByKey.get(dateKey);
50073
+ const dayNumber = Number(dateKey.slice(-2));
50053
50074
  const shiftData = dayData ? getShiftData(dayData, selectedShiftId) : null;
50054
50075
  const hasShiftData = Boolean(shiftData && hasRealData(shiftData));
50055
50076
  const availableSeconds = hasShiftData ? shiftData.availableTimeSeconds ?? shiftWorkSeconds ?? 0 : 0;
@@ -50076,8 +50097,8 @@ var WorkspaceMonthlyHistory = ({
50076
50097
  }
50077
50098
  maxHours = Math.max(maxHours, idleHours + productiveHours);
50078
50099
  dailyData.push({
50079
- hour: getOrdinal2(day),
50080
- timeRange: `Day ${day}`,
50100
+ hour: getOrdinal2(dayNumber),
50101
+ timeRange: `Day ${dayNumber}`,
50081
50102
  productiveHours,
50082
50103
  idleHours,
50083
50104
  utilization
@@ -50088,12 +50109,9 @@ var WorkspaceMonthlyHistory = ({
50088
50109
  }
50089
50110
  let maxOutput = 0;
50090
50111
  let lastSetTarget = 0;
50091
- for (let i = dayNumbers.length - 1; i >= 0; i--) {
50092
- const day = dayNumbers[i];
50093
- const dayData = analysisMonthlyData.find((d) => {
50094
- const date = new Date(d.date);
50095
- return date.getDate() === day;
50096
- });
50112
+ for (let i = rangeDateKeys.length - 1; i >= 0; i--) {
50113
+ const dateKey = rangeDateKeys[i];
50114
+ const dayData = analysisMonthlyDataByKey.get(dateKey);
50097
50115
  const shiftData = dayData ? getShiftData(dayData, selectedShiftId) : null;
50098
50116
  const idealOutput = shiftData ? shiftData.idealOutput : 0;
50099
50117
  if (idealOutput > 0) {
@@ -50101,20 +50119,18 @@ var WorkspaceMonthlyHistory = ({
50101
50119
  break;
50102
50120
  }
50103
50121
  }
50104
- for (const day of dayNumbers) {
50105
- const dayData = analysisMonthlyData.find((d) => {
50106
- const date = new Date(d.date);
50107
- return date.getDate() === day;
50108
- });
50122
+ for (const dateKey of rangeDateKeys) {
50123
+ const dayData = analysisMonthlyDataByKey.get(dateKey);
50124
+ const dayNumber = Number(dateKey.slice(-2));
50109
50125
  const shiftData = dayData ? getShiftData(dayData, selectedShiftId) : null;
50110
50126
  const output = shiftData && hasRealData(shiftData) ? shiftData.output : 0;
50111
50127
  const idealOutput = shiftData ? shiftData.idealOutput : 0;
50112
50128
  if (output > maxOutput) maxOutput = output;
50113
50129
  const color2 = output >= lastSetTarget ? "#00AB45" : "#E34329";
50114
50130
  dailyData.push({
50115
- hour: getOrdinal2(day),
50131
+ hour: getOrdinal2(dayNumber),
50116
50132
  // Using ordinal format (1st, 2nd, 3rd, etc.)
50117
- timeRange: `Day ${day}`,
50133
+ timeRange: `Day ${dayNumber}`,
50118
50134
  output,
50119
50135
  originalOutput: output,
50120
50136
  // For label display
@@ -50128,7 +50144,7 @@ var WorkspaceMonthlyHistory = ({
50128
50144
  const calculatedMax = Math.max(maxOutput, lastSetTarget);
50129
50145
  const yAxisMax = calculatedMax > 0 ? calculatedMax * 1.1 : 100;
50130
50146
  return { data: dailyData, maxOutput, lastSetTarget, yAxisMax };
50131
- }, [analysisMonthlyData, normalizedRange.startKey, normalizedRange.endKey, selectedShiftId, isUptimeMode, shiftWorkSeconds]);
50147
+ }, [analysisMonthlyDataByKey, rangeDateKeys, selectedShiftId, isUptimeMode, shiftWorkSeconds]);
50132
50148
  const yAxisTicks = React143.useMemo(() => {
50133
50149
  if (isUptimeMode) return void 0;
50134
50150
  const max = chartData.yAxisMax;
@@ -50213,7 +50229,7 @@ var WorkspaceMonthlyHistory = ({
50213
50229
  }
50214
50230
  const avgEfficiency = Math.round(totalEfficiency / filteredShifts.length);
50215
50231
  const avgDailyOutput = Math.round(totalOutput / filteredShifts.length);
50216
- const avgCycleTime = Math.round(totalCycleTime / filteredShifts.length);
50232
+ const avgCycleTime = roundToSingleDecimal(totalCycleTime / filteredShifts.length);
50217
50233
  const avgRank = ranks.length > 0 ? Math.round(ranks.reduce((a, b) => a + b, 0) / ranks.length) : null;
50218
50234
  return {
50219
50235
  avgEfficiency,
@@ -50233,7 +50249,7 @@ var WorkspaceMonthlyHistory = ({
50233
50249
  const assemblyRangeCycleTime = React143.useMemo(() => {
50234
50250
  const trendCycleTime = Number(trendSummary?.avg_cycle_time?.current);
50235
50251
  if (Number.isFinite(trendCycleTime) && trendCycleTime > 0) {
50236
- return Math.round(trendCycleTime);
50252
+ return trendCycleTime;
50237
50253
  }
50238
50254
  return metrics2?.avgCycleTime ?? 0;
50239
50255
  }, [trendSummary?.avg_cycle_time?.current, metrics2?.avgCycleTime]);
@@ -50262,20 +50278,15 @@ var WorkspaceMonthlyHistory = ({
50262
50278
  if (startOffset === -1) startOffset = 6;
50263
50279
  const calendar = Array(startOffset).fill(null);
50264
50280
  for (let day = 1; day <= totalDays; day++) {
50265
- const dayData = data.find((d) => {
50266
- const date = new Date(d.date);
50267
- return date.getDate() === day;
50268
- });
50281
+ const dateKey = buildDateKey(year, month, day);
50282
+ const dayData = monthlyDataByKey.get(dateKey);
50269
50283
  calendar.push(dayData || null);
50270
50284
  }
50271
50285
  return { calendar, startOffset };
50272
- }, [data, month, year]);
50286
+ }, [monthlyDataByKey, month, year]);
50273
50287
  const handleDayClick = React143.useCallback((day) => {
50274
50288
  if (!day) return;
50275
- const year2 = day.date.getFullYear();
50276
- const month2 = String(day.date.getMonth() + 1).padStart(2, "0");
50277
- const dayOfMonth = String(day.date.getDate()).padStart(2, "0");
50278
- const formattedDate = `${year2}-${month2}-${dayOfMonth}`;
50289
+ const formattedDate = getDayDateKey(day);
50279
50290
  trackCoreEvent("Workspace Monthly History Day Clicked", {
50280
50291
  source: "monthly_history",
50281
50292
  workspace_id: workspaceId,
@@ -51221,13 +51232,20 @@ var WorkspaceMonthlyPdfGenerator = ({
51221
51232
  startKey: rangeStart || monthBounds.startKey,
51222
51233
  endKey: rangeEnd || monthBounds.endKey
51223
51234
  };
51235
+ const boundsSourceKey = rangeStart || rangeEnd || monthBounds.startKey;
51236
+ const boundsSourceDate = parseDateKeyToDate(boundsSourceKey);
51237
+ const effectiveBounds = getMonthKeyBounds(boundsSourceDate.getFullYear(), boundsSourceDate.getMonth());
51224
51238
  const normalizedRange = normalizeDateKeyRange(
51225
51239
  requestedRange.startKey,
51226
51240
  requestedRange.endKey,
51227
- monthBounds.startKey,
51228
- monthBounds.endKey
51241
+ effectiveBounds.startKey,
51242
+ effectiveBounds.endKey
51243
+ );
51244
+ const fullRange = isFullMonthRange(
51245
+ normalizedRange,
51246
+ boundsSourceDate.getFullYear(),
51247
+ boundsSourceDate.getMonth()
51229
51248
  );
51230
- const fullRange = isFullMonthRange(normalizedRange, selectedYear, selectedMonth);
51231
51249
  const reportStartDate = parseDateKeyToDate(normalizedRange.startKey);
51232
51250
  const reportEndDate = parseDateKeyToDate(normalizedRange.endKey);
51233
51251
  const reportStartStr = reportStartDate.toLocaleDateString("en-IN", {
@@ -51249,12 +51267,17 @@ var WorkspaceMonthlyPdfGenerator = ({
51249
51267
  const generatedText = `Generated on ${(/* @__PURE__ */ new Date()).toLocaleString("en-IN", { timeZone: "Asia/Kolkata" })}`;
51250
51268
  const resolvedLineName = lineName?.trim() || "Line";
51251
51269
  const dailySectionTitle = isUptimeMode ? "Daily Utilization Summary" : "Daily Performance Summary";
51270
+ const monthName = reportStartDate.toLocaleDateString("en-IN", {
51271
+ month: "long",
51272
+ year: "numeric",
51273
+ timeZone: "Asia/Kolkata"
51274
+ });
51252
51275
  trackCoreEvent("Workspace Monthly PDF Export Clicked", {
51253
51276
  workspace_id: workspaceId,
51254
51277
  workspace_name: workspaceName,
51255
51278
  line_name: resolvedLineName,
51256
- month: selectedMonth,
51257
- year: selectedYear,
51279
+ month: reportStartDate.getMonth(),
51280
+ year: reportStartDate.getFullYear(),
51258
51281
  shift_id: selectedShiftId,
51259
51282
  range_start: normalizedRange.startKey,
51260
51283
  range_end: normalizedRange.endKey,
@@ -51295,11 +51318,6 @@ var WorkspaceMonthlyPdfGenerator = ({
51295
51318
  doc.setFontSize(13);
51296
51319
  doc.setFont("helvetica", "normal");
51297
51320
  doc.setTextColor(60, 60, 60);
51298
- const monthName = new Date(selectedYear, selectedMonth).toLocaleDateString("en-IN", {
51299
- month: "long",
51300
- year: "numeric",
51301
- timeZone: "Asia/Kolkata"
51302
- });
51303
51321
  const shiftType = getShiftDisplayName2(selectedShiftId, availableShifts);
51304
51322
  doc.text(`${monthName}`, 20, 65);
51305
51323
  doc.text(`${shiftType}`, 20, 73);
@@ -51311,15 +51329,12 @@ var WorkspaceMonthlyPdfGenerator = ({
51311
51329
  doc.setLineWidth(0.8);
51312
51330
  doc.line(20, 90, 190, 90);
51313
51331
  const reportData = analysisData ? analysisData : filterDataByDateKeyRange(monthlyData, normalizedRange);
51314
- const validDays = reportData.filter((day) => {
51315
- const date = new Date(day.date);
51316
- return date.getMonth() === selectedMonth && date.getFullYear() === selectedYear;
51317
- });
51332
+ const validDays = reportData;
51318
51333
  const validShifts = validDays.map((day) => getShiftData(day, selectedShiftId)).filter(hasShiftData);
51319
51334
  const dailyEntries = validDays.map((dayData) => {
51320
51335
  const shift = getShiftData(dayData, selectedShiftId);
51321
51336
  return { dayData, shift };
51322
- }).filter(({ shift }) => hasShiftData(shift)).sort((left, right) => new Date(right.dayData.date).getTime() - new Date(left.dayData.date).getTime());
51337
+ }).filter(({ shift }) => hasShiftData(shift)).sort((left, right) => getDayDateKey(right.dayData).localeCompare(getDayDateKey(left.dayData)));
51323
51338
  const filteredShifts = isUptimeMode ? validShifts : validShifts.filter((shift) => (shift.efficiency ?? 0) >= 5);
51324
51339
  const monthlyMetrics = filteredShifts.length > 0 ? isUptimeMode ? (() => {
51325
51340
  const totalIdleTime = filteredShifts.reduce((sum, shift) => sum + shift.idleTime, 0);
@@ -63635,6 +63650,7 @@ var KPIDetailView = ({
63635
63650
  const monthBounds = React143.useMemo(() => getMonthKeyBounds(currentYear, currentMonth), [currentYear, currentMonth]);
63636
63651
  const [rangeStart, setRangeStart] = React143.useState(monthBounds.startKey);
63637
63652
  const [rangeEnd, setRangeEnd] = React143.useState(monthBounds.endKey);
63653
+ const appliedExternalRangeKeyRef = React143.useRef(null);
63638
63654
  const [monthlyData, setMonthlyData] = React143.useState([]);
63639
63655
  const [underperformingWorkspaces, setUnderperformingWorkspaces] = React143.useState({});
63640
63656
  const [selectedShiftId, setSelectedShiftId] = React143.useState(0);
@@ -63677,12 +63693,29 @@ var KPIDetailView = ({
63677
63693
  const range = React143.useMemo(() => ({ startKey: rangeStart, endKey: rangeEnd }), [rangeStart, rangeEnd]);
63678
63694
  const isFullRange = React143.useMemo(() => isFullMonthRange(range, currentYear, currentMonth), [range, currentYear, currentMonth]);
63679
63695
  React143.useEffect(() => {
63696
+ const hasExternalRange = typeof urlRangeStart === "string" || typeof urlRangeEnd === "string";
63697
+ if (!hasExternalRange) {
63698
+ appliedExternalRangeKeyRef.current = null;
63699
+ return;
63700
+ }
63701
+ const externalRangeKey = `${urlRangeStart ?? ""}|${urlRangeEnd ?? ""}`;
63702
+ if (appliedExternalRangeKeyRef.current === externalRangeKey) {
63703
+ return;
63704
+ }
63705
+ appliedExternalRangeKeyRef.current = externalRangeKey;
63706
+ const targetStartKey = typeof urlRangeStart === "string" ? urlRangeStart : typeof urlRangeEnd === "string" ? urlRangeEnd : monthBounds.startKey;
63707
+ const targetStartDate = parseDateKeyToDate(targetStartKey);
63708
+ const targetMonth = targetStartDate.getMonth();
63709
+ const targetYear = targetStartDate.getFullYear();
63710
+ const targetBounds = getMonthKeyBounds(targetYear, targetMonth);
63680
63711
  const normalized = normalizeDateKeyRange(
63681
- typeof urlRangeStart === "string" ? urlRangeStart : monthBounds.startKey,
63682
- typeof urlRangeEnd === "string" ? urlRangeEnd : monthBounds.endKey,
63683
- monthBounds.startKey,
63684
- monthBounds.endKey
63712
+ typeof urlRangeStart === "string" ? urlRangeStart : targetBounds.startKey,
63713
+ typeof urlRangeEnd === "string" ? urlRangeEnd : targetBounds.endKey,
63714
+ targetBounds.startKey,
63715
+ targetBounds.endKey
63685
63716
  );
63717
+ setCurrentMonth(targetMonth);
63718
+ setCurrentYear(targetYear);
63686
63719
  setRangeStart(normalized.startKey);
63687
63720
  setRangeEnd(normalized.endKey);
63688
63721
  }, [urlRangeStart, urlRangeEnd, monthBounds.startKey, monthBounds.endKey]);
@@ -63850,12 +63883,13 @@ var KPIDetailView = ({
63850
63883
  const dayDataMap = /* @__PURE__ */ new Map();
63851
63884
  const resolveMonthlyShiftTimes = (metricShiftId) => resolveShiftTimes(metricShiftId);
63852
63885
  monthlyMetrics.forEach((metric) => {
63853
- const date = new Date(metric.date);
63854
- const dateKey = date.toISOString().split("T")[0];
63886
+ const dateKey = getDateKeyFromValue(metric.date);
63887
+ const date = parseDateKeyToDate(dateKey);
63855
63888
  let dayData = dayDataMap.get(dateKey);
63856
63889
  if (!dayData) {
63857
63890
  dayData = {
63858
63891
  date,
63892
+ dateKey,
63859
63893
  shifts: {}
63860
63894
  // Multi-shift structure: Record<number, ShiftData>
63861
63895
  };
@@ -63902,7 +63936,11 @@ var KPIDetailView = ({
63902
63936
  };
63903
63937
  dayData.shifts[metric.shift_id] = shiftData;
63904
63938
  });
63905
- const transformedMonthlyData = Array.from(dayDataMap.values());
63939
+ const transformedMonthlyData = Array.from(dayDataMap.values()).map((dayData) => ({
63940
+ date: dayData.date,
63941
+ dateKey: dayData.dateKey,
63942
+ shifts: dayData.shifts
63943
+ }));
63906
63944
  console.log("Transformed monthly data for calendar:", transformedMonthlyData);
63907
63945
  setMonthlyData(transformedMonthlyData);
63908
63946
  const mapWorkspaces = (workspaces2) => (workspaces2 || []).map((ws) => ({
@@ -71143,6 +71181,7 @@ var WorkspaceDetailView = ({
71143
71181
  const monthBounds = React143.useMemo(() => getMonthKeyBounds(selectedYear, selectedMonth), [selectedYear, selectedMonth]);
71144
71182
  const [rangeStart, setRangeStart] = React143.useState(monthBounds.startKey);
71145
71183
  const [rangeEnd, setRangeEnd] = React143.useState(monthBounds.endKey);
71184
+ const appliedExternalRangeKeyRef = React143.useRef(null);
71146
71185
  const [selectedShift, setSelectedShift] = React143.useState(0);
71147
71186
  React143.useEffect(() => {
71148
71187
  if (parsedShiftId !== void 0) {
@@ -71152,15 +71191,32 @@ var WorkspaceDetailView = ({
71152
71191
  const range = React143.useMemo(() => ({ startKey: rangeStart, endKey: rangeEnd }), [rangeStart, rangeEnd]);
71153
71192
  const isFullRange = React143.useMemo(() => isFullMonthRange(range, selectedYear, selectedMonth), [range, selectedYear, selectedMonth]);
71154
71193
  React143.useEffect(() => {
71194
+ const hasExternalRange = typeof urlRangeStart === "string" || typeof urlRangeEnd === "string";
71195
+ if (!hasExternalRange) {
71196
+ appliedExternalRangeKeyRef.current = null;
71197
+ return;
71198
+ }
71199
+ const externalRangeKey = `${urlRangeStart ?? ""}|${urlRangeEnd ?? ""}`;
71200
+ if (appliedExternalRangeKeyRef.current === externalRangeKey) {
71201
+ return;
71202
+ }
71203
+ appliedExternalRangeKeyRef.current = externalRangeKey;
71204
+ const targetStartKey = typeof urlRangeStart === "string" ? urlRangeStart : typeof urlRangeEnd === "string" ? urlRangeEnd : monthBounds.startKey;
71205
+ const targetStartDate = parseDateKeyToDate(targetStartKey);
71206
+ const targetMonth = targetStartDate.getMonth();
71207
+ const targetYear = targetStartDate.getFullYear();
71208
+ const targetBounds = getMonthKeyBounds(targetYear, targetMonth);
71155
71209
  const normalized = normalizeDateKeyRange(
71156
- typeof urlRangeStart === "string" ? urlRangeStart : monthBounds.startKey,
71157
- typeof urlRangeEnd === "string" ? urlRangeEnd : monthBounds.endKey,
71158
- monthBounds.startKey,
71159
- monthBounds.endKey
71210
+ typeof urlRangeStart === "string" ? urlRangeStart : targetBounds.startKey,
71211
+ typeof urlRangeEnd === "string" ? urlRangeEnd : targetBounds.endKey,
71212
+ targetBounds.startKey,
71213
+ targetBounds.endKey
71160
71214
  );
71215
+ setSelectedMonth(targetMonth);
71216
+ setSelectedYear(targetYear);
71161
71217
  setRangeStart(normalized.startKey);
71162
71218
  setRangeEnd(normalized.endKey);
71163
- }, [urlRangeStart, urlRangeEnd, monthBounds.startKey, monthBounds.endKey]);
71219
+ }, [urlRangeStart, urlRangeEnd, monthBounds.startKey]);
71164
71220
  const isHistoricView = Boolean(date && parsedShiftId !== void 0);
71165
71221
  const initialTab = getInitialTab(sourceType, defaultTab, fromMonthly, date);
71166
71222
  const [activeTab, setActiveTab] = React143.useState(initialTab);
@@ -71682,12 +71738,13 @@ var WorkspaceDetailView = ({
71682
71738
  console.warn("Skipping invalid metric:", metric);
71683
71739
  return;
71684
71740
  }
71685
- const dateObj = new Date(metric.date);
71686
- const dateKey = dateObj.toISOString().split("T")[0];
71741
+ const dateKey = getDateKeyFromValue(metric.date);
71742
+ const dateObj = parseDateKeyToDate(dateKey);
71687
71743
  let dayEntry = dayDataMap.get(dateKey);
71688
71744
  if (!dayEntry) {
71689
71745
  dayEntry = {
71690
71746
  date: dateObj,
71747
+ dateKey,
71691
71748
  shifts: {}
71692
71749
  // Multi-shift structure: Record<number, CalendarShiftData>
71693
71750
  };
@@ -71732,6 +71789,7 @@ var WorkspaceDetailView = ({
71732
71789
  });
71733
71790
  const processedData = Array.from(dayDataMap.values()).filter((entry) => Object.keys(entry.shifts).length > 0).map((entry) => ({
71734
71791
  date: entry.date,
71792
+ dateKey: entry.dateKey,
71735
71793
  shifts: entry.shifts
71736
71794
  }));
71737
71795
  console.log(`[handleMonthlyDataLoaded] Transformed data for calendar:`, {
@@ -71764,7 +71822,7 @@ var WorkspaceDetailView = ({
71764
71822
  const analysisMonthlyData = React143.useMemo(() => {
71765
71823
  return filterDataByDateKeyRange(monthlyData, range);
71766
71824
  }, [monthlyData, range]);
71767
- const formattedWorkspaceName = displayName || workspace?.workspace_display_name || formatWorkspaceName3(workspace?.workspace_name || "", resolvedLineId);
71825
+ const formattedWorkspaceName = workspace?.workspace_display_name || displayName || formatWorkspaceName3(workspace?.workspace_name || "", resolvedLineId);
71768
71826
  const resolvedLineName = React143.useMemo(() => {
71769
71827
  const workspaceLineName = workspace?.line_name?.trim();
71770
71828
  if (workspaceLineName) {
@@ -72310,6 +72368,9 @@ var WorkspaceDetailView = ({
72310
72368
  onMonthNavigate: (newMonth, newYear) => {
72311
72369
  setSelectedMonth(newMonth);
72312
72370
  setSelectedYear(newYear);
72371
+ const nextBounds = getMonthKeyBounds(newYear, newMonth);
72372
+ setRangeStart(nextBounds.startKey);
72373
+ setRangeEnd(nextBounds.endKey);
72313
72374
  },
72314
72375
  showLabel: false
72315
72376
  }
@@ -81949,6 +82010,8 @@ exports.getCurrentWeekFullRange = getCurrentWeekFullRange;
81949
82010
  exports.getCurrentWeekToDateRange = getCurrentWeekToDateRange;
81950
82011
  exports.getDashboardHeaderTimeInZone = getDashboardHeaderTimeInZone;
81951
82012
  exports.getDateKeyFromDate = getDateKeyFromDate;
82013
+ exports.getDateKeyFromValue = getDateKeyFromValue;
82014
+ exports.getDayDateKey = getDayDateKey;
81952
82015
  exports.getDaysDifferenceInZone = getDaysDifferenceInZone;
81953
82016
  exports.getDefaultCameraStreamUrl = getDefaultCameraStreamUrl;
81954
82017
  exports.getDefaultLineId = getDefaultLineId;