@optifye/dashboard-core 6.11.38 → 6.11.40

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.mjs CHANGED
@@ -1,10 +1,10 @@
1
+ import { format, addDays, subMonths, endOfMonth, startOfMonth, endOfDay, eachDayOfInterval, getDay, isSameDay, isWithinInterval, startOfDay, parseISO, subDays, differenceInMinutes, addMinutes, addMonths, isValid, formatDistanceToNow, isToday, isFuture, isBefore } from 'date-fns';
2
+ import { formatInTimeZone, fromZonedTime, toZonedTime } from 'date-fns-tz';
1
3
  import * as React143 from 'react';
2
4
  import React143__default, { createContext, useRef, useCallback, useState, useMemo, useEffect, forwardRef, useImperativeHandle, useLayoutEffect, memo as memo$1, useContext, useSyncExternalStore, useId, Children, isValidElement, useInsertionEffect, startTransition, Fragment as Fragment$1, createElement, Component } from 'react';
3
5
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
4
6
  import { useRouter } from 'next/router';
5
7
  import { toast } from 'sonner';
6
- import { formatInTimeZone, fromZonedTime, toZonedTime } from 'date-fns-tz';
7
- import { format, addDays, subMonths, endOfMonth, startOfMonth, endOfDay, eachDayOfInterval, getDay, isSameDay, isWithinInterval, startOfDay, parseISO, subDays, differenceInMinutes, addMinutes, addMonths, isValid, formatDistanceToNow, isToday, isFuture, isBefore } from 'date-fns';
8
8
  import mixpanel from 'mixpanel-browser';
9
9
  import { EventEmitter } from 'events';
10
10
  import { createClient, REALTIME_SUBSCRIBE_STATES } from '@supabase/supabase-js';
@@ -1632,6 +1632,149 @@ function isValidPrefetchParams(params) {
1632
1632
  function isValidPrefetchStatus(status) {
1633
1633
  return typeof status === "string" && Object.values(PrefetchStatus).includes(status);
1634
1634
  }
1635
+ var getOperationalDate = (timezone, date = /* @__PURE__ */ new Date(), shiftStartTime = "06:00") => {
1636
+ const zonedDate = toZonedTime(date, timezone);
1637
+ const hours = zonedDate.getHours();
1638
+ const minutes = zonedDate.getMinutes();
1639
+ const [startHourRaw, startMinuteRaw] = shiftStartTime.split(":").map(Number);
1640
+ const startHour = Number.isFinite(startHourRaw) ? startHourRaw : 6;
1641
+ const startMinute = Number.isFinite(startMinuteRaw) ? startMinuteRaw : 0;
1642
+ const currentTotalMinutes = hours * 60 + minutes;
1643
+ const shiftStartTotalMinutes = startHour * 60 + startMinute;
1644
+ const operationalDate = currentTotalMinutes < shiftStartTotalMinutes ? subDays(zonedDate, 1) : zonedDate;
1645
+ return format(operationalDate, "yyyy-MM-dd");
1646
+ };
1647
+ function formatTimeInZone(time2, timezone, formatString = "HH:mm:ss") {
1648
+ const dateObj = typeof time2 === "string" ? parseISO(time2) : time2;
1649
+ if (!isValid(dateObj)) return "Invalid Date";
1650
+ return formatInTimeZone(dateObj, timezone, formatString);
1651
+ }
1652
+ function getCurrentTimeInZone(timezone, formatString) {
1653
+ const now4 = /* @__PURE__ */ new Date();
1654
+ if (formatString) {
1655
+ if (!isValid(now4)) return "Invalid Date";
1656
+ return formatInTimeZone(now4, timezone, formatString);
1657
+ }
1658
+ return now4;
1659
+ }
1660
+ var pad2 = (value) => String(value).padStart(2, "0");
1661
+ var DATE_KEY_PREFIX_PATTERN = /^(\d{4}-\d{2}-\d{2})/;
1662
+ var buildDateKey = (year, monthIndex, day) => {
1663
+ return `${year}-${pad2(monthIndex + 1)}-${pad2(day)}`;
1664
+ };
1665
+ var getDateKeyFromDate = (date) => {
1666
+ return buildDateKey(date.getFullYear(), date.getMonth(), date.getDate());
1667
+ };
1668
+ var parseDateKeyToDate = (dateKey) => {
1669
+ const [year, month, day] = dateKey.split("-").map(Number);
1670
+ return new Date(year, month - 1, day, 12, 0, 0, 0);
1671
+ };
1672
+ var getDateKeyFromValue = (value) => {
1673
+ if (typeof value === "string") {
1674
+ const keyMatch = value.match(DATE_KEY_PREFIX_PATTERN);
1675
+ if (keyMatch?.[1]) {
1676
+ return keyMatch[1];
1677
+ }
1678
+ const parsed = parseISO(value);
1679
+ if (isValid(parsed)) {
1680
+ return getDateKeyFromDate(parsed);
1681
+ }
1682
+ return value;
1683
+ }
1684
+ return getDateKeyFromDate(value);
1685
+ };
1686
+ var formatDateKeyForDisplay = (dateKey, formatStr = "MMM d, yyyy") => {
1687
+ return format(parseDateKeyToDate(dateKey), formatStr);
1688
+ };
1689
+ var getMonthKeyBounds = (year, monthIndex) => {
1690
+ const startKey = buildDateKey(year, monthIndex, 1);
1691
+ const lastDay = new Date(year, monthIndex + 1, 0).getDate();
1692
+ const endKey = buildDateKey(year, monthIndex, lastDay);
1693
+ return { startKey, endKey };
1694
+ };
1695
+ var getCurrentWeekToDateRange = (timezone, now4 = /* @__PURE__ */ new Date()) => {
1696
+ const todayKey = formatInTimeZone(now4, timezone || "UTC", "yyyy-MM-dd");
1697
+ const todayDate = parseISO(`${todayKey}T00:00:00`);
1698
+ const dayOfWeek = getDay(todayDate);
1699
+ const daysSinceMonday = dayOfWeek === 0 ? 6 : dayOfWeek - 1;
1700
+ const weekStart = subDays(todayDate, daysSinceMonday);
1701
+ return {
1702
+ startKey: format(weekStart, "yyyy-MM-dd"),
1703
+ endKey: format(todayDate, "yyyy-MM-dd")
1704
+ };
1705
+ };
1706
+ var getCurrentWeekFullRange = (timezone, now4 = /* @__PURE__ */ new Date()) => {
1707
+ const currentWeekToDateRange = getCurrentWeekToDateRange(timezone, now4);
1708
+ const weekStart = parseDateKeyToDate(currentWeekToDateRange.startKey);
1709
+ return {
1710
+ startKey: currentWeekToDateRange.startKey,
1711
+ endKey: format(addDays(weekStart, 6), "yyyy-MM-dd")
1712
+ };
1713
+ };
1714
+ var normalizeDateKeyRange = (startKey, endKey, minKey, maxKey) => {
1715
+ const clampedStart = startKey < minKey ? minKey : startKey > maxKey ? maxKey : startKey;
1716
+ const clampedEnd = endKey < minKey ? minKey : endKey > maxKey ? maxKey : endKey;
1717
+ if (clampedStart <= clampedEnd) {
1718
+ return { startKey: clampedStart, endKey: clampedEnd };
1719
+ }
1720
+ return { startKey: clampedEnd, endKey: clampedStart };
1721
+ };
1722
+ var isFullMonthRange = (range, year, monthIndex) => {
1723
+ const bounds = getMonthKeyBounds(year, monthIndex);
1724
+ return range.startKey === bounds.startKey && range.endKey === bounds.endKey;
1725
+ };
1726
+ var getMonthlyTrendComparisonLabel = (range, year, monthIndex) => {
1727
+ if (isFullMonthRange(range, year, monthIndex)) {
1728
+ return "last month";
1729
+ }
1730
+ return range.startKey === range.endKey ? "previous day" : "previous range";
1731
+ };
1732
+ var getMonthWeekRanges = (year, monthIndex, timezone, maxKey) => {
1733
+ const totalDays = new Date(year, monthIndex + 1, 0).getDate();
1734
+ const ranges = [];
1735
+ let currentStartDay = 1;
1736
+ for (let day = 1; day <= totalDays; day += 1) {
1737
+ const zonedDate = toZonedTime(new Date(year, monthIndex, day), timezone);
1738
+ const dayOfWeek = zonedDate.getDay();
1739
+ const isEndOfWeek = dayOfWeek === 0 || day === totalDays;
1740
+ if (isEndOfWeek) {
1741
+ const startKey = buildDateKey(year, monthIndex, currentStartDay);
1742
+ const endKey = buildDateKey(year, monthIndex, day);
1743
+ if (maxKey && startKey > maxKey) {
1744
+ break;
1745
+ }
1746
+ const clampedEndKey = maxKey && endKey > maxKey ? maxKey : endKey;
1747
+ if (clampedEndKey < startKey) {
1748
+ break;
1749
+ }
1750
+ const labelStart = formatDateKeyForDisplay(startKey, "MMM d");
1751
+ const labelEnd = formatDateKeyForDisplay(clampedEndKey, "MMM d");
1752
+ ranges.push({
1753
+ startKey,
1754
+ endKey: clampedEndKey,
1755
+ label: `Week of ${labelStart} - ${labelEnd}`
1756
+ });
1757
+ currentStartDay = day + 1;
1758
+ }
1759
+ }
1760
+ return ranges;
1761
+ };
1762
+ var formatRangeLabel = (range, fullMonthLabel) => {
1763
+ if (!range.startKey || !range.endKey) return fullMonthLabel;
1764
+ if (range.startKey === range.endKey) {
1765
+ return formatDateKeyForDisplay(range.startKey, "MMM d, yyyy");
1766
+ }
1767
+ const startLabel = formatDateKeyForDisplay(range.startKey, "MMM d");
1768
+ const endLabel = formatDateKeyForDisplay(range.endKey, "MMM d, yyyy");
1769
+ return `${startLabel} - ${endLabel}`;
1770
+ };
1771
+ var filterDataByDateKeyRange = (data, range) => {
1772
+ if (!range.startKey || !range.endKey) return data;
1773
+ return (data || []).filter((item) => {
1774
+ const dateKey = item.dateKey || getDateKeyFromValue(item.date);
1775
+ return dateKey >= range.startKey && dateKey <= range.endKey;
1776
+ });
1777
+ };
1635
1778
 
1636
1779
  // src/lib/types/calendar.ts
1637
1780
  var DEFAULT_SHIFT_DATA = {
@@ -1663,6 +1806,9 @@ var hasAnyShiftData = (day) => {
1663
1806
  var getAvailableShiftIds = (day) => {
1664
1807
  return Object.keys(day.shifts).map(Number).sort((a, b) => a - b);
1665
1808
  };
1809
+ var getDayDateKey = (day) => {
1810
+ return day.dateKey || getDateKeyFromDate(day.date);
1811
+ };
1666
1812
 
1667
1813
  // src/components/dashboard/grid/workspace_grid_constants.ts
1668
1814
  var DEFAULT_WORKSPACE_POSITIONS = [
@@ -3318,130 +3464,6 @@ var memoizedOutputArrayAggregation = createMemoizedFunction(
3318
3464
  },
3319
3465
  (arrays) => arrays.map((arr) => arr.length).join("-")
3320
3466
  );
3321
- var getOperationalDate = (timezone, date = /* @__PURE__ */ new Date(), shiftStartTime = "06:00") => {
3322
- const zonedDate = toZonedTime(date, timezone);
3323
- const hours = zonedDate.getHours();
3324
- const minutes = zonedDate.getMinutes();
3325
- const [startHourRaw, startMinuteRaw] = shiftStartTime.split(":").map(Number);
3326
- const startHour = Number.isFinite(startHourRaw) ? startHourRaw : 6;
3327
- const startMinute = Number.isFinite(startMinuteRaw) ? startMinuteRaw : 0;
3328
- const currentTotalMinutes = hours * 60 + minutes;
3329
- const shiftStartTotalMinutes = startHour * 60 + startMinute;
3330
- const operationalDate = currentTotalMinutes < shiftStartTotalMinutes ? subDays(zonedDate, 1) : zonedDate;
3331
- return format(operationalDate, "yyyy-MM-dd");
3332
- };
3333
- function formatTimeInZone(time2, timezone, formatString = "HH:mm:ss") {
3334
- const dateObj = typeof time2 === "string" ? parseISO(time2) : time2;
3335
- if (!isValid(dateObj)) return "Invalid Date";
3336
- return formatInTimeZone(dateObj, timezone, formatString);
3337
- }
3338
- function getCurrentTimeInZone(timezone, formatString) {
3339
- const now4 = /* @__PURE__ */ new Date();
3340
- if (formatString) {
3341
- if (!isValid(now4)) return "Invalid Date";
3342
- return formatInTimeZone(now4, timezone, formatString);
3343
- }
3344
- return now4;
3345
- }
3346
- var pad2 = (value) => String(value).padStart(2, "0");
3347
- var buildDateKey = (year, monthIndex, day) => {
3348
- return `${year}-${pad2(monthIndex + 1)}-${pad2(day)}`;
3349
- };
3350
- var getDateKeyFromDate = (date) => {
3351
- return date.toISOString().split("T")[0];
3352
- };
3353
- var parseDateKeyToDate = (dateKey) => {
3354
- const [year, month, day] = dateKey.split("-").map(Number);
3355
- return new Date(year, month - 1, day);
3356
- };
3357
- var formatDateKeyForDisplay = (dateKey, formatStr = "MMM d, yyyy") => {
3358
- return format(parseDateKeyToDate(dateKey), formatStr);
3359
- };
3360
- var getMonthKeyBounds = (year, monthIndex) => {
3361
- const startKey = buildDateKey(year, monthIndex, 1);
3362
- const lastDay = new Date(year, monthIndex + 1, 0).getDate();
3363
- const endKey = buildDateKey(year, monthIndex, lastDay);
3364
- return { startKey, endKey };
3365
- };
3366
- var getCurrentWeekToDateRange = (timezone, now4 = /* @__PURE__ */ new Date()) => {
3367
- const todayKey = formatInTimeZone(now4, timezone || "UTC", "yyyy-MM-dd");
3368
- const todayDate = parseISO(`${todayKey}T00:00:00`);
3369
- const dayOfWeek = getDay(todayDate);
3370
- const daysSinceMonday = dayOfWeek === 0 ? 6 : dayOfWeek - 1;
3371
- const weekStart = subDays(todayDate, daysSinceMonday);
3372
- return {
3373
- startKey: format(weekStart, "yyyy-MM-dd"),
3374
- endKey: format(todayDate, "yyyy-MM-dd")
3375
- };
3376
- };
3377
- var getCurrentWeekFullRange = (timezone, now4 = /* @__PURE__ */ new Date()) => {
3378
- const currentWeekToDateRange = getCurrentWeekToDateRange(timezone, now4);
3379
- const weekStart = parseDateKeyToDate(currentWeekToDateRange.startKey);
3380
- return {
3381
- startKey: currentWeekToDateRange.startKey,
3382
- endKey: format(addDays(weekStart, 6), "yyyy-MM-dd")
3383
- };
3384
- };
3385
- var normalizeDateKeyRange = (startKey, endKey, minKey, maxKey) => {
3386
- const clampedStart = startKey < minKey ? minKey : startKey > maxKey ? maxKey : startKey;
3387
- const clampedEnd = endKey < minKey ? minKey : endKey > maxKey ? maxKey : endKey;
3388
- if (clampedStart <= clampedEnd) {
3389
- return { startKey: clampedStart, endKey: clampedEnd };
3390
- }
3391
- return { startKey: clampedEnd, endKey: clampedStart };
3392
- };
3393
- var isFullMonthRange = (range, year, monthIndex) => {
3394
- const bounds = getMonthKeyBounds(year, monthIndex);
3395
- return range.startKey === bounds.startKey && range.endKey === bounds.endKey;
3396
- };
3397
- var getMonthWeekRanges = (year, monthIndex, timezone, maxKey) => {
3398
- const totalDays = new Date(year, monthIndex + 1, 0).getDate();
3399
- const ranges = [];
3400
- let currentStartDay = 1;
3401
- for (let day = 1; day <= totalDays; day += 1) {
3402
- const zonedDate = toZonedTime(new Date(year, monthIndex, day), timezone);
3403
- const dayOfWeek = zonedDate.getDay();
3404
- const isEndOfWeek = dayOfWeek === 0 || day === totalDays;
3405
- if (isEndOfWeek) {
3406
- const startKey = buildDateKey(year, monthIndex, currentStartDay);
3407
- const endKey = buildDateKey(year, monthIndex, day);
3408
- if (maxKey && startKey > maxKey) {
3409
- break;
3410
- }
3411
- const clampedEndKey = maxKey && endKey > maxKey ? maxKey : endKey;
3412
- if (clampedEndKey < startKey) {
3413
- break;
3414
- }
3415
- const labelStart = formatDateKeyForDisplay(startKey, "MMM d");
3416
- const labelEnd = formatDateKeyForDisplay(clampedEndKey, "MMM d");
3417
- ranges.push({
3418
- startKey,
3419
- endKey: clampedEndKey,
3420
- label: `Week of ${labelStart} - ${labelEnd}`
3421
- });
3422
- currentStartDay = day + 1;
3423
- }
3424
- }
3425
- return ranges;
3426
- };
3427
- var formatRangeLabel = (range, fullMonthLabel) => {
3428
- if (!range.startKey || !range.endKey) return fullMonthLabel;
3429
- if (range.startKey === range.endKey) {
3430
- return formatDateKeyForDisplay(range.startKey, "MMM d, yyyy");
3431
- }
3432
- const startLabel = formatDateKeyForDisplay(range.startKey, "MMM d");
3433
- const endLabel = formatDateKeyForDisplay(range.endKey, "MMM d, yyyy");
3434
- return `${startLabel} - ${endLabel}`;
3435
- };
3436
- var filterDataByDateKeyRange = (data, range) => {
3437
- if (!range.startKey || !range.endKey) return data;
3438
- return (data || []).filter((item) => {
3439
- const dateKey = typeof item.date === "string" ? item.date : getDateKeyFromDate(item.date);
3440
- return dateKey >= range.startKey && dateKey <= range.endKey;
3441
- });
3442
- };
3443
-
3444
- // src/lib/utils/shifts.ts
3445
3467
  var DEFAULT_DAY_SHIFT_START = "06:00";
3446
3468
  var DEFAULT_NIGHT_SHIFT_START = "18:00";
3447
3469
  var DEFAULT_TRANSITION_MINUTES = 15;
@@ -12261,6 +12283,7 @@ var toWorkspaceDetailedMetrics = ({
12261
12283
  return {
12262
12284
  workspace_id: data.workspace_id,
12263
12285
  workspace_name: data.workspace_name,
12286
+ workspace_display_name: typeof data.workspace_display_name === "string" ? data.workspace_display_name : typeof data.display_name === "string" ? data.display_name : null,
12264
12287
  line_id: data.line_id,
12265
12288
  line_name: data.line_name || "",
12266
12289
  line_assembly_enabled: data.line_assembly_enabled === true || data.assembly_enabled === true,
@@ -18409,13 +18432,27 @@ var useMonthlyTrend = (params) => {
18409
18432
  if (typeof params.shiftId === "number") {
18410
18433
  searchParams.append("shift_id", params.shiftId.toString());
18411
18434
  }
18435
+ if (params.startDate && params.endDate) {
18436
+ searchParams.append("start_date", params.startDate);
18437
+ searchParams.append("end_date", params.endDate);
18438
+ }
18412
18439
  if (params.entityType === "line") {
18413
18440
  searchParams.append("line_id", params.entityId);
18414
18441
  } else {
18415
18442
  searchParams.append("workspace_id", params.entityId);
18416
18443
  }
18417
18444
  return searchParams.toString();
18418
- }, [params.entityId, params.entityType, params.month, params.year, params.shiftId, entityConfig?.companyId]);
18445
+ }, [
18446
+ params.companyId,
18447
+ params.endDate,
18448
+ params.entityId,
18449
+ params.entityType,
18450
+ params.month,
18451
+ params.shiftId,
18452
+ params.startDate,
18453
+ params.year,
18454
+ entityConfig?.companyId
18455
+ ]);
18419
18456
  useEffect(() => {
18420
18457
  let isMounted = true;
18421
18458
  if (!queryString || !supabase) {
@@ -47261,6 +47298,10 @@ var LineMonthlyHistory = ({
47261
47298
  const efficiencyImproved = efficiencyDelta >= 0;
47262
47299
  const EfficiencyTrendIcon = efficiencyImproved ? ArrowUp : ArrowDown;
47263
47300
  const efficiencyTrendText = `${Math.abs(efficiencyDelta).toFixed(1)}%`;
47301
+ const trendComparisonLabel = useMemo(
47302
+ () => getMonthlyTrendComparisonLabel(normalizedRange, year, month),
47303
+ [month, normalizedRange, year]
47304
+ );
47264
47305
  const outputDelta = trendSummary?.avg_daily_output?.delta_pp ?? 0;
47265
47306
  const outputImproved = outputDelta >= 0;
47266
47307
  const OutputTrendIcon = outputImproved ? ArrowUp : ArrowDown;
@@ -47511,10 +47552,7 @@ var LineMonthlyHistory = ({
47511
47552
  /* @__PURE__ */ jsx("div", { className: "text-base font-bold text-gray-900 whitespace-nowrap", children: uptimeSummary?.avgDailyStoppages ?? 0 }),
47512
47553
  /* @__PURE__ */ jsxs("div", { className: `flex items-center gap-1 ${stoppagesImproved ? "bg-emerald-50 text-emerald-600" : "bg-red-50 text-red-600"} px-1.5 py-0.5 rounded-full text-[10px] font-medium whitespace-nowrap flex-shrink-0`, children: [
47513
47554
  /* @__PURE__ */ jsx(StoppagesTrendIcon, { className: "w-3 h-3" }),
47514
- /* @__PURE__ */ jsxs("span", { children: [
47515
- stoppagesTrendText,
47516
- " vs last month"
47517
- ] })
47555
+ /* @__PURE__ */ jsx("span", { children: `${stoppagesTrendText} vs ${trendComparisonLabel}` })
47518
47556
  ] })
47519
47557
  ] })
47520
47558
  ] }),
@@ -47524,10 +47562,7 @@ var LineMonthlyHistory = ({
47524
47562
  /* @__PURE__ */ jsx("div", { className: "text-base font-bold text-gray-900 whitespace-nowrap", children: formatIdleTime(uptimeSummary?.avgIdleTime ?? 0) }),
47525
47563
  /* @__PURE__ */ jsxs("div", { className: `flex items-center gap-1 ${idleImproved ? "bg-emerald-50 text-emerald-600" : "bg-red-50 text-red-600"} px-1.5 py-0.5 rounded-full text-[10px] font-medium whitespace-nowrap flex-shrink-0`, children: [
47526
47564
  /* @__PURE__ */ jsx(IdleTrendIcon, { className: "w-3 h-3" }),
47527
- /* @__PURE__ */ jsxs("span", { children: [
47528
- idleTrendText,
47529
- " vs last month"
47530
- ] })
47565
+ /* @__PURE__ */ jsx("span", { children: `${idleTrendText} vs ${trendComparisonLabel}` })
47531
47566
  ] })
47532
47567
  ] })
47533
47568
  ] })
@@ -47541,10 +47576,7 @@ var LineMonthlyHistory = ({
47541
47576
  ] }),
47542
47577
  /* @__PURE__ */ jsxs("div", { className: `flex items-center gap-1 ${efficiencyImproved ? "bg-emerald-50 text-emerald-600" : "bg-red-50 text-red-600"} px-1.5 py-0.5 rounded-full text-[10px] font-medium whitespace-nowrap flex-shrink-0`, children: [
47543
47578
  /* @__PURE__ */ jsx(EfficiencyTrendIcon, { className: "w-3 h-3" }),
47544
- /* @__PURE__ */ jsxs("span", { children: [
47545
- efficiencyTrendText,
47546
- " vs last month"
47547
- ] })
47579
+ /* @__PURE__ */ jsx("span", { children: `${efficiencyTrendText} vs ${trendComparisonLabel}` })
47548
47580
  ] })
47549
47581
  ] })
47550
47582
  ] }),
@@ -47554,10 +47586,7 @@ var LineMonthlyHistory = ({
47554
47586
  /* @__PURE__ */ jsx("div", { className: "text-xl font-bold text-gray-900", children: Math.round(avgOutput).toLocaleString() }),
47555
47587
  /* @__PURE__ */ jsxs("div", { className: `flex items-center gap-1 ${outputImproved ? "bg-emerald-50 text-emerald-600" : "bg-red-50 text-red-600"} px-1.5 py-0.5 rounded-full text-[10px] font-medium whitespace-nowrap flex-shrink-0`, children: [
47556
47588
  /* @__PURE__ */ jsx(OutputTrendIcon, { className: "w-3 h-3" }),
47557
- /* @__PURE__ */ jsxs("span", { children: [
47558
- outputTrendText,
47559
- " vs last month"
47560
- ] })
47589
+ /* @__PURE__ */ jsx("span", { children: `${outputTrendText} vs ${trendComparisonLabel}` })
47561
47590
  ] })
47562
47591
  ] })
47563
47592
  ] })
@@ -47568,10 +47597,7 @@ var LineMonthlyHistory = ({
47568
47597
  /* @__PURE__ */ jsx("h3", { className: "text-xs sm:text-sm font-bold text-gray-700 text-left", children: "Utilization" }),
47569
47598
  /* @__PURE__ */ jsxs("div", { className: `flex items-center gap-1 ${utilizationImproved ? "bg-emerald-50 text-emerald-600" : "bg-red-50 text-red-600"} px-1.5 py-0.5 rounded-full text-[10px] font-medium whitespace-nowrap flex-shrink-0`, children: [
47570
47599
  /* @__PURE__ */ jsx(UtilizationTrendIcon, { className: "w-3 h-3" }),
47571
- /* @__PURE__ */ jsxs("span", { children: [
47572
- utilizationTrendText,
47573
- " vs last month"
47574
- ] })
47600
+ /* @__PURE__ */ jsx("span", { children: `${utilizationTrendText} vs ${trendComparisonLabel}` })
47575
47601
  ] })
47576
47602
  ] }),
47577
47603
  pieChartData.length > 0 ? /* @__PURE__ */ jsxs("div", { className: "w-full h-[140px] sm:h-[160px] flex items-center overflow-hidden", children: [
@@ -47923,19 +47949,33 @@ var LineMonthlyPdfGenerator = ({
47923
47949
  is_full_month: fullRange
47924
47950
  });
47925
47951
  const doc = new jsPDF$1();
47926
- doc.setFontSize(14);
47927
- doc.setFont("helvetica", "bold");
47928
- doc.setTextColor(50, 50, 50);
47929
- doc.text("OPTIFYE.AI", 20, 15);
47930
- doc.setFontSize(11);
47931
- doc.setFont("helvetica", "normal");
47932
- doc.setTextColor(80, 80, 80);
47933
- const reportText = isUptimeMode ? "MONTHLY UTILIZATION REPORT" : "MONTHLY PERFORMANCE REPORT";
47934
- const reportTextWidth = doc.getStringUnitWidth(reportText) * 11 / doc.internal.scaleFactor;
47935
- doc.text(reportText, doc.internal.pageSize.width - 20 - reportTextWidth, 15);
47936
- doc.setDrawColor(200, 200, 200);
47937
- doc.setLineWidth(0.5);
47938
- doc.line(20, 20, 190, 20);
47952
+ const pageHeight = typeof doc.internal.pageSize.height === "number" ? Number(doc.internal.pageSize.height) : 297;
47953
+ const footerY = pageHeight - 17;
47954
+ const maxContentY = footerY - 10;
47955
+ const generatedText = `Generated on ${(/* @__PURE__ */ new Date()).toLocaleString("en-IN", { timeZone: "Asia/Kolkata" })}`;
47956
+ const dailySectionTitle = isUptimeMode ? "Daily Utilization Summary" : "Daily Performance Summary";
47957
+ const drawPageChrome = () => {
47958
+ doc.setFontSize(14);
47959
+ doc.setFont("helvetica", "bold");
47960
+ doc.setTextColor(50, 50, 50);
47961
+ doc.text("OPTIFYE.AI", 20, 15);
47962
+ doc.setFontSize(11);
47963
+ doc.setFont("helvetica", "normal");
47964
+ doc.setTextColor(80, 80, 80);
47965
+ const reportText = isUptimeMode ? "MONTHLY UTILIZATION REPORT" : "MONTHLY PERFORMANCE REPORT";
47966
+ const reportTextWidth = doc.getStringUnitWidth(reportText) * 11 / doc.internal.scaleFactor;
47967
+ doc.text(reportText, doc.internal.pageSize.width - 20 - reportTextWidth, 15);
47968
+ doc.setDrawColor(200, 200, 200);
47969
+ doc.setLineWidth(0.5);
47970
+ doc.line(20, 20, 190, 20);
47971
+ };
47972
+ const drawFooter = () => {
47973
+ doc.setFontSize(9);
47974
+ doc.setTextColor(130, 130, 130);
47975
+ doc.text(generatedText, 20, footerY);
47976
+ doc.setTextColor(0, 0, 0);
47977
+ };
47978
+ drawPageChrome();
47939
47979
  doc.setFillColor(250, 250, 250);
47940
47980
  doc.roundedRect(15, 25, 180, 55, 3, 3, "F");
47941
47981
  doc.setFontSize(32);
@@ -47970,6 +48010,10 @@ var LineMonthlyPdfGenerator = ({
47970
48010
  if (shift.hasData !== void 0) return shift.hasData;
47971
48011
  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;
47972
48012
  };
48013
+ const dailyEntries = validDays.map((dayData) => {
48014
+ const shift = getLineShiftData2(dayData, selectedShiftId);
48015
+ return { dayData, shift };
48016
+ }).filter(({ shift }) => hasShiftData(shift)).sort((left, right) => new Date(right.dayData.date).getTime() - new Date(left.dayData.date).getTime());
47973
48017
  const getUptimeTotals2 = (shift, hasData) => {
47974
48018
  if (!hasData || !shift) {
47975
48019
  return { availableSeconds: 0, productiveSeconds: 0, idleSeconds: 0 };
@@ -48096,46 +48140,45 @@ var LineMonthlyPdfGenerator = ({
48096
48140
  }
48097
48141
  const dailySeparatorY = isUptimeMode ? 180 : 165;
48098
48142
  const dailySectionStartY = isUptimeMode ? 185 : 170;
48099
- const dailyTitleY = isUptimeMode ? 195 : 180;
48100
- const dailyHeaderY = isUptimeMode ? 200 : 185;
48101
- const dailyHeaderTextY = isUptimeMode ? 205 : 190;
48102
- const dailyHeaderLineY = isUptimeMode ? 208 : 193;
48103
48143
  const dailyContentStartY = isUptimeMode ? 215 : 200;
48104
- const dailyMaxY = isUptimeMode ? 260 : 245;
48105
48144
  doc.setDrawColor(180, 180, 180);
48106
48145
  doc.setLineWidth(0.8);
48107
48146
  doc.line(20, dailySeparatorY, 190, dailySeparatorY);
48108
- doc.setFillColor(245, 245, 245);
48109
- doc.roundedRect(15, dailySectionStartY, 180, 85, 3, 3, "F");
48110
- doc.setFontSize(18);
48111
- doc.setFont("helvetica", "bold");
48112
- doc.setTextColor(40, 40, 40);
48113
- doc.text(isUptimeMode ? "Daily Utilization Summary" : "Daily Performance Summary", 20, dailyTitleY);
48114
- doc.setTextColor(0, 0, 0);
48115
- if (validDays.length > 0) {
48147
+ const renderDailyTablePage = (startIndex, sectionY, title) => {
48148
+ const rowHeight = 8;
48149
+ const tableHeaderY = sectionY + 15;
48150
+ const headerTextY = tableHeaderY + 5;
48151
+ const firstRowY = headerTextY + 10;
48152
+ const rowsPerPage = Math.max(1, Math.floor((maxContentY - firstRowY) / rowHeight));
48153
+ const pageEntries = dailyEntries.slice(startIndex, startIndex + rowsPerPage);
48154
+ const endY = firstRowY + pageEntries.length * rowHeight;
48155
+ const sectionHeight = Math.max(40, endY - sectionY + 5);
48156
+ doc.setFillColor(245, 245, 245);
48157
+ doc.roundedRect(15, sectionY, 180, sectionHeight, 3, 3, "F");
48158
+ doc.setFontSize(18);
48159
+ doc.setFont("helvetica", "bold");
48160
+ doc.setTextColor(40, 40, 40);
48161
+ doc.text(title, 20, sectionY + 10);
48162
+ doc.setTextColor(0, 0, 0);
48116
48163
  doc.setFontSize(10);
48117
48164
  doc.setFont("helvetica", "bold");
48118
48165
  doc.setFillColor(240, 240, 240);
48119
- doc.roundedRect(20, dailyHeaderY, 170, 7, 1, 1, "F");
48120
- doc.text("Date", 25, dailyHeaderTextY);
48166
+ doc.roundedRect(20, tableHeaderY, 170, 7, 1, 1, "F");
48167
+ doc.text("Date", 25, headerTextY);
48121
48168
  if (isUptimeMode) {
48122
- doc.text("Utilization", 95, dailyHeaderTextY);
48169
+ doc.text("Utilization", 95, headerTextY);
48123
48170
  } else {
48124
- doc.text("Actual", 60, dailyHeaderTextY);
48125
- doc.text("Standard", 95, dailyHeaderTextY);
48126
- doc.text("Efficiency", 135, dailyHeaderTextY);
48127
- doc.text("Status", 170, dailyHeaderTextY);
48171
+ doc.text("Actual", 60, headerTextY);
48172
+ doc.text("Standard", 95, headerTextY);
48173
+ doc.text("Efficiency", 135, headerTextY);
48174
+ doc.text("Status", 170, headerTextY);
48128
48175
  }
48129
48176
  doc.setLineWidth(0.2);
48130
48177
  doc.setDrawColor(220, 220, 220);
48131
- doc.line(20, dailyHeaderLineY, 190, dailyHeaderLineY);
48178
+ doc.line(20, headerTextY + 3, 190, headerTextY + 3);
48132
48179
  doc.setFont("helvetica", "normal");
48133
- let yPos = dailyContentStartY;
48134
- const recentDays = validDays.slice(-10).reverse();
48135
- recentDays.forEach((dayData, index) => {
48136
- if (yPos > dailyMaxY) return;
48137
- const shift = getLineShiftData2(dayData, selectedShiftId);
48138
- if (!hasShiftData(shift)) return;
48180
+ let yPos = firstRowY;
48181
+ pageEntries.forEach(({ dayData, shift }, index) => {
48139
48182
  if (isUptimeMode) {
48140
48183
  doc.setDrawColor(200, 200, 200);
48141
48184
  doc.setLineWidth(0.1);
@@ -48176,12 +48219,34 @@ var LineMonthlyPdfGenerator = ({
48176
48219
  }
48177
48220
  doc.setTextColor(0, 0, 0);
48178
48221
  }
48179
- yPos += 8;
48222
+ yPos += rowHeight;
48180
48223
  });
48181
48224
  if (!isUptimeMode) {
48182
48225
  doc.setLineWidth(0.2);
48183
48226
  doc.setDrawColor(220, 220, 220);
48184
- doc.roundedRect(20, dailyHeaderY, 170, yPos - dailyHeaderY - 3, 1, 1, "S");
48227
+ doc.roundedRect(20, tableHeaderY, 170, yPos - tableHeaderY - 3, 1, 1, "S");
48228
+ }
48229
+ return startIndex + pageEntries.length;
48230
+ };
48231
+ if (dailyEntries.length > 0) {
48232
+ let renderedEntries = renderDailyTablePage(0, dailySectionStartY, dailySectionTitle);
48233
+ while (renderedEntries < dailyEntries.length) {
48234
+ drawFooter();
48235
+ doc.addPage();
48236
+ drawPageChrome();
48237
+ doc.setFontSize(12);
48238
+ doc.setFont("helvetica", "bold");
48239
+ doc.setTextColor(40, 40, 40);
48240
+ doc.text(lineName || "Line", 20, 32);
48241
+ doc.setFont("helvetica", "normal");
48242
+ doc.setTextColor(90, 90, 90);
48243
+ doc.text(`${monthName} \u2022 ${shiftType} \u2022 ${reportStartStr} - ${reportEndStr}`, 20, 40);
48244
+ doc.setTextColor(0, 0, 0);
48245
+ renderedEntries = renderDailyTablePage(
48246
+ renderedEntries,
48247
+ 48,
48248
+ `${dailySectionTitle} (cont.)`
48249
+ );
48185
48250
  }
48186
48251
  } else {
48187
48252
  doc.setFontSize(12);
@@ -48194,20 +48259,9 @@ var LineMonthlyPdfGenerator = ({
48194
48259
  const isCycleTimeWorkspace = (workspace) => workspace.metric_mode === "cycle_time" || lineAssembly && (workspace.avg_cycle_time !== void 0 || workspace.ideal_cycle_time !== void 0 || workspace.cycle_ratio !== void 0);
48195
48260
  const showCycleTimePoorestPerformers = !isUptimeMode && poorestWorkspaces.some(isCycleTimeWorkspace);
48196
48261
  if (poorestWorkspaces && poorestWorkspaces.length > 0) {
48262
+ drawFooter();
48197
48263
  doc.addPage();
48198
- doc.setFontSize(14);
48199
- doc.setFont("helvetica", "bold");
48200
- doc.setTextColor(50, 50, 50);
48201
- doc.text("OPTIFYE.AI", 20, 15);
48202
- doc.setFontSize(11);
48203
- doc.setFont("helvetica", "normal");
48204
- doc.setTextColor(80, 80, 80);
48205
- const reportText2 = isUptimeMode ? "MONTHLY UTILIZATION REPORT" : "MONTHLY PERFORMANCE REPORT";
48206
- const reportTextWidth2 = doc.getStringUnitWidth(reportText2) * 11 / doc.internal.scaleFactor;
48207
- doc.text(reportText2, doc.internal.pageSize.width - 20 - reportTextWidth2, 15);
48208
- doc.setDrawColor(200, 200, 200);
48209
- doc.setLineWidth(0.5);
48210
- doc.line(20, 20, 190, 20);
48264
+ drawPageChrome();
48211
48265
  doc.setFontSize(18);
48212
48266
  doc.setFont("helvetica", "bold");
48213
48267
  doc.setTextColor(40, 40, 40);
@@ -48273,10 +48327,7 @@ var LineMonthlyPdfGenerator = ({
48273
48327
  doc.setDrawColor(220, 220, 220);
48274
48328
  doc.roundedRect(20, 45, 170, yPos2 - 45 - 5, 1, 1, "S");
48275
48329
  }
48276
- doc.setFontSize(9);
48277
- doc.setTextColor(130, 130, 130);
48278
- const generatedText = `Generated on ${(/* @__PURE__ */ new Date()).toLocaleString("en-IN", { timeZone: "Asia/Kolkata" })}`;
48279
- doc.text(generatedText, 20, 280);
48330
+ drawFooter();
48280
48331
  const fileName = `${lineName || "Line"}_${monthName.replace(" ", "_")}_${shiftType.replace(" ", "_")}.pdf`;
48281
48332
  doc.save(fileName);
48282
48333
  } catch (error) {
@@ -49846,6 +49897,11 @@ var formatHours = (value) => {
49846
49897
  if (Math.abs(rounded) < 0.05) return "0h";
49847
49898
  return Number.isInteger(rounded) ? `${rounded}h` : `${rounded.toFixed(1)}h`;
49848
49899
  };
49900
+ var roundToSingleDecimal = (value) => Math.round(value * 10) / 10;
49901
+ var formatCycleSeconds = (value) => {
49902
+ if (!Number.isFinite(value)) return "0.0s";
49903
+ return `${value.toFixed(1)}s`;
49904
+ };
49849
49905
  var CustomTooltip3 = ({ active, payload, label, isUptimeMode }) => {
49850
49906
  if (!active || !payload || payload.length === 0) return null;
49851
49907
  if (isUptimeMode) {
@@ -49967,21 +50023,30 @@ var WorkspaceMonthlyHistory = ({
49967
50023
  if (!shiftConfig) return null;
49968
50024
  return getShiftWorkDurationSeconds(shiftConfig, selectedShiftId);
49969
50025
  }, [shiftConfig, selectedShiftId]);
49970
- const chartData = useMemo(() => {
50026
+ const analysisMonthlyDataByKey = useMemo(
50027
+ () => new Map(analysisMonthlyData.map((day) => [getDayDateKey(day), day])),
50028
+ [analysisMonthlyData]
50029
+ );
50030
+ const monthlyDataByKey = useMemo(
50031
+ () => new Map(data.map((day) => [getDayDateKey(day), day])),
50032
+ [data]
50033
+ );
50034
+ const rangeDateKeys = useMemo(() => {
49971
50035
  const rangeStartDate = parseDateKeyToDate(normalizedRange.startKey);
49972
50036
  const rangeEndDate = parseDateKeyToDate(normalizedRange.endKey);
49973
- const dayNumbers = [];
50037
+ const keys = [];
49974
50038
  for (let d = new Date(rangeStartDate); d <= rangeEndDate; d.setDate(d.getDate() + 1)) {
49975
- dayNumbers.push(d.getDate());
50039
+ keys.push(buildDateKey(d.getFullYear(), d.getMonth(), d.getDate()));
49976
50040
  }
50041
+ return keys;
50042
+ }, [normalizedRange.endKey, normalizedRange.startKey]);
50043
+ const chartData = useMemo(() => {
49977
50044
  const dailyData = [];
49978
50045
  if (isUptimeMode) {
49979
50046
  let maxHours = 0;
49980
- for (const day of dayNumbers) {
49981
- const dayData = analysisMonthlyData.find((d) => {
49982
- const date = new Date(d.date);
49983
- return date.getDate() === day;
49984
- });
50047
+ for (const dateKey of rangeDateKeys) {
50048
+ const dayData = analysisMonthlyDataByKey.get(dateKey);
50049
+ const dayNumber = Number(dateKey.slice(-2));
49985
50050
  const shiftData = dayData ? getShiftData(dayData, selectedShiftId) : null;
49986
50051
  const hasShiftData = Boolean(shiftData && hasRealData(shiftData));
49987
50052
  const availableSeconds = hasShiftData ? shiftData.availableTimeSeconds ?? shiftWorkSeconds ?? 0 : 0;
@@ -50008,8 +50073,8 @@ var WorkspaceMonthlyHistory = ({
50008
50073
  }
50009
50074
  maxHours = Math.max(maxHours, idleHours + productiveHours);
50010
50075
  dailyData.push({
50011
- hour: getOrdinal2(day),
50012
- timeRange: `Day ${day}`,
50076
+ hour: getOrdinal2(dayNumber),
50077
+ timeRange: `Day ${dayNumber}`,
50013
50078
  productiveHours,
50014
50079
  idleHours,
50015
50080
  utilization
@@ -50020,12 +50085,9 @@ var WorkspaceMonthlyHistory = ({
50020
50085
  }
50021
50086
  let maxOutput = 0;
50022
50087
  let lastSetTarget = 0;
50023
- for (let i = dayNumbers.length - 1; i >= 0; i--) {
50024
- const day = dayNumbers[i];
50025
- const dayData = analysisMonthlyData.find((d) => {
50026
- const date = new Date(d.date);
50027
- return date.getDate() === day;
50028
- });
50088
+ for (let i = rangeDateKeys.length - 1; i >= 0; i--) {
50089
+ const dateKey = rangeDateKeys[i];
50090
+ const dayData = analysisMonthlyDataByKey.get(dateKey);
50029
50091
  const shiftData = dayData ? getShiftData(dayData, selectedShiftId) : null;
50030
50092
  const idealOutput = shiftData ? shiftData.idealOutput : 0;
50031
50093
  if (idealOutput > 0) {
@@ -50033,20 +50095,18 @@ var WorkspaceMonthlyHistory = ({
50033
50095
  break;
50034
50096
  }
50035
50097
  }
50036
- for (const day of dayNumbers) {
50037
- const dayData = analysisMonthlyData.find((d) => {
50038
- const date = new Date(d.date);
50039
- return date.getDate() === day;
50040
- });
50098
+ for (const dateKey of rangeDateKeys) {
50099
+ const dayData = analysisMonthlyDataByKey.get(dateKey);
50100
+ const dayNumber = Number(dateKey.slice(-2));
50041
50101
  const shiftData = dayData ? getShiftData(dayData, selectedShiftId) : null;
50042
50102
  const output = shiftData && hasRealData(shiftData) ? shiftData.output : 0;
50043
50103
  const idealOutput = shiftData ? shiftData.idealOutput : 0;
50044
50104
  if (output > maxOutput) maxOutput = output;
50045
50105
  const color2 = output >= lastSetTarget ? "#00AB45" : "#E34329";
50046
50106
  dailyData.push({
50047
- hour: getOrdinal2(day),
50107
+ hour: getOrdinal2(dayNumber),
50048
50108
  // Using ordinal format (1st, 2nd, 3rd, etc.)
50049
- timeRange: `Day ${day}`,
50109
+ timeRange: `Day ${dayNumber}`,
50050
50110
  output,
50051
50111
  originalOutput: output,
50052
50112
  // For label display
@@ -50060,7 +50120,7 @@ var WorkspaceMonthlyHistory = ({
50060
50120
  const calculatedMax = Math.max(maxOutput, lastSetTarget);
50061
50121
  const yAxisMax = calculatedMax > 0 ? calculatedMax * 1.1 : 100;
50062
50122
  return { data: dailyData, maxOutput, lastSetTarget, yAxisMax };
50063
- }, [analysisMonthlyData, normalizedRange.startKey, normalizedRange.endKey, selectedShiftId, isUptimeMode, shiftWorkSeconds]);
50123
+ }, [analysisMonthlyDataByKey, rangeDateKeys, selectedShiftId, isUptimeMode, shiftWorkSeconds]);
50064
50124
  const yAxisTicks = useMemo(() => {
50065
50125
  if (isUptimeMode) return void 0;
50066
50126
  const max = chartData.yAxisMax;
@@ -50145,7 +50205,7 @@ var WorkspaceMonthlyHistory = ({
50145
50205
  }
50146
50206
  const avgEfficiency = Math.round(totalEfficiency / filteredShifts.length);
50147
50207
  const avgDailyOutput = Math.round(totalOutput / filteredShifts.length);
50148
- const avgCycleTime = Math.round(totalCycleTime / filteredShifts.length);
50208
+ const avgCycleTime = roundToSingleDecimal(totalCycleTime / filteredShifts.length);
50149
50209
  const avgRank = ranks.length > 0 ? Math.round(ranks.reduce((a, b) => a + b, 0) / ranks.length) : null;
50150
50210
  return {
50151
50211
  avgEfficiency,
@@ -50156,12 +50216,16 @@ var WorkspaceMonthlyHistory = ({
50156
50216
  avgIdleTime: Math.round(totalIdleTime / filteredShifts.length)
50157
50217
  };
50158
50218
  }, [analysisMonthlyData, selectedShiftId, isUptimeMode, shiftWorkSeconds]);
50219
+ const trendComparisonLabel = useMemo(
50220
+ () => getMonthlyTrendComparisonLabel(normalizedRange, year, month),
50221
+ [month, normalizedRange, year]
50222
+ );
50159
50223
  const efficiencyDelta = trendSummary?.avg_efficiency?.delta_pp ?? 0;
50160
50224
  const efficiencyImproved = efficiencyDelta >= 0;
50161
50225
  const assemblyRangeCycleTime = useMemo(() => {
50162
50226
  const trendCycleTime = Number(trendSummary?.avg_cycle_time?.current);
50163
50227
  if (Number.isFinite(trendCycleTime) && trendCycleTime > 0) {
50164
- return Math.round(trendCycleTime);
50228
+ return trendCycleTime;
50165
50229
  }
50166
50230
  return metrics2?.avgCycleTime ?? 0;
50167
50231
  }, [trendSummary?.avg_cycle_time?.current, metrics2?.avgCycleTime]);
@@ -50171,17 +50235,17 @@ var WorkspaceMonthlyHistory = ({
50171
50235
  const cycleWorsened = cycleDelta > 0;
50172
50236
  const utilizationDelta = efficiencyDelta;
50173
50237
  const utilizationImproved = utilizationDelta >= 0;
50174
- const utilizationTrendText = `${Math.abs(utilizationDelta).toFixed(1)}% vs last month`;
50238
+ const utilizationTrendText = `${Math.abs(utilizationDelta).toFixed(1)}%`;
50175
50239
  const idleDeltaRaw = trendSummary?.avg_idle_time?.delta_seconds ?? 0;
50176
50240
  const idlePrev = trendSummary?.avg_idle_time?.previous ?? 0;
50177
50241
  const idleDelta = idlePrev ? idleDeltaRaw / idlePrev * 100 : 0;
50178
50242
  const idleImproved = idleDelta <= 0;
50179
- const idleTrendText = `${Math.abs(idleDelta).toFixed(1)}% vs last month`;
50243
+ const idleTrendText = `${Math.abs(idleDelta).toFixed(1)}%`;
50180
50244
  const stoppagesDeltaRaw = trendSummary?.avg_daily_stoppages?.delta_count ?? 0;
50181
50245
  const stoppagesPrev = trendSummary?.avg_daily_stoppages?.previous ?? 0;
50182
50246
  const stoppagesDelta = stoppagesPrev ? stoppagesDeltaRaw / stoppagesPrev * 100 : 0;
50183
50247
  const stoppagesImproved = stoppagesDelta <= 0;
50184
- const stoppagesTrendText = `${Math.abs(stoppagesDelta).toFixed(1)}% vs last month`;
50248
+ const stoppagesTrendText = `${Math.abs(stoppagesDelta).toFixed(1)}%`;
50185
50249
  const calendarData = useMemo(() => {
50186
50250
  const startOfMonth2 = new Date(year, month, 1);
50187
50251
  const endOfMonth2 = new Date(year, month + 1, 0);
@@ -50190,20 +50254,15 @@ var WorkspaceMonthlyHistory = ({
50190
50254
  if (startOffset === -1) startOffset = 6;
50191
50255
  const calendar = Array(startOffset).fill(null);
50192
50256
  for (let day = 1; day <= totalDays; day++) {
50193
- const dayData = data.find((d) => {
50194
- const date = new Date(d.date);
50195
- return date.getDate() === day;
50196
- });
50257
+ const dateKey = buildDateKey(year, month, day);
50258
+ const dayData = monthlyDataByKey.get(dateKey);
50197
50259
  calendar.push(dayData || null);
50198
50260
  }
50199
50261
  return { calendar, startOffset };
50200
- }, [data, month, year]);
50262
+ }, [monthlyDataByKey, month, year]);
50201
50263
  const handleDayClick = useCallback((day) => {
50202
50264
  if (!day) return;
50203
- const year2 = day.date.getFullYear();
50204
- const month2 = String(day.date.getMonth() + 1).padStart(2, "0");
50205
- const dayOfMonth = String(day.date.getDate()).padStart(2, "0");
50206
- const formattedDate = `${year2}-${month2}-${dayOfMonth}`;
50265
+ const formattedDate = getDayDateKey(day);
50207
50266
  trackCoreEvent("Workspace Monthly History Day Clicked", {
50208
50267
  source: "monthly_history",
50209
50268
  workspace_id: workspaceId,
@@ -50342,20 +50401,17 @@ var WorkspaceMonthlyHistory = ({
50342
50401
  /* @__PURE__ */ jsx("div", { className: "text-2xl font-bold text-gray-900", children: formatIdleTime(metrics2?.avgIdleTime ?? 0) }),
50343
50402
  /* @__PURE__ */ jsxs("div", { className: `flex items-center gap-1 ${idleImproved ? "bg-emerald-50 text-emerald-600" : "bg-red-50 text-red-600"} px-2 py-0.5 rounded-full text-[10px] font-medium whitespace-nowrap flex-shrink-0`, children: [
50344
50403
  idleImproved ? /* @__PURE__ */ jsx(ArrowDown, { className: "w-3 h-3" }) : /* @__PURE__ */ jsx(ArrowUp, { className: "w-3 h-3" }),
50345
- /* @__PURE__ */ jsx("span", { children: idleTrendText })
50404
+ /* @__PURE__ */ jsx("span", { children: `${idleTrendText} vs ${trendComparisonLabel}` })
50346
50405
  ] })
50347
50406
  ] })
50348
50407
  ] }),
50349
50408
  /* @__PURE__ */ jsxs("div", { className: "bg-white rounded-lg shadow-sm border border-gray-100 p-4 flex flex-col justify-between", children: [
50350
50409
  /* @__PURE__ */ jsx("div", { className: "text-sm font-semibold text-gray-600 mb-1", children: "Avg Cycle Time" }),
50351
50410
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 flex-nowrap", children: [
50352
- /* @__PURE__ */ jsxs("div", { className: "text-2xl font-bold text-gray-900", children: [
50353
- assemblyRangeCycleTime,
50354
- "s"
50355
- ] }),
50411
+ /* @__PURE__ */ jsx("div", { className: "text-2xl font-bold text-gray-900", children: formatCycleSeconds(assemblyRangeCycleTime) }),
50356
50412
  /* @__PURE__ */ jsxs("div", { className: `flex items-center gap-1 ${cycleWorsened ? "bg-red-50 text-red-600" : "bg-emerald-50 text-emerald-600"} px-2 py-0.5 rounded-full text-[10px] font-medium whitespace-nowrap flex-shrink-0`, children: [
50357
50413
  cycleWorsened ? /* @__PURE__ */ jsx(ArrowUp, { className: "w-3 h-3" }) : /* @__PURE__ */ jsx(ArrowDown, { className: "w-3 h-3" }),
50358
- /* @__PURE__ */ jsx("span", { children: `${Math.abs(cycleDelta).toFixed(1)}% vs last month` })
50414
+ /* @__PURE__ */ jsx("span", { children: `${Math.abs(cycleDelta).toFixed(1)}% vs ${trendComparisonLabel}` })
50359
50415
  ] })
50360
50416
  ] })
50361
50417
  ] })
@@ -50366,10 +50422,10 @@ var WorkspaceMonthlyHistory = ({
50366
50422
  /* @__PURE__ */ jsx("div", { className: "text-2xl font-bold text-gray-900", children: isUptimeMode ? `${metrics2?.avgUtilization ?? 0}%` : `${metrics2?.avgEfficiency ?? 0}%` }),
50367
50423
  isUptimeMode ? /* @__PURE__ */ jsxs("div", { className: `flex items-center gap-1 ${utilizationImproved ? "bg-emerald-50 text-emerald-600" : "bg-red-50 text-red-600"} px-2 py-0.5 rounded-full text-[10px] font-medium whitespace-nowrap flex-shrink-0`, children: [
50368
50424
  utilizationImproved ? /* @__PURE__ */ jsx(ArrowUp, { className: "w-3 h-3" }) : /* @__PURE__ */ jsx(ArrowDown, { className: "w-3 h-3" }),
50369
- /* @__PURE__ */ jsx("span", { children: utilizationTrendText })
50425
+ /* @__PURE__ */ jsx("span", { children: `${utilizationTrendText} vs ${trendComparisonLabel}` })
50370
50426
  ] }) : /* @__PURE__ */ jsxs("div", { className: `flex items-center gap-1 ${efficiencyImproved ? "bg-emerald-50 text-emerald-600" : "bg-red-50 text-red-600"} px-2 py-0.5 rounded-full text-[10px] font-medium whitespace-nowrap flex-shrink-0`, children: [
50371
50427
  efficiencyImproved ? /* @__PURE__ */ jsx(ArrowUp, { className: "w-3 h-3" }) : /* @__PURE__ */ jsx(ArrowDown, { className: "w-3 h-3" }),
50372
- /* @__PURE__ */ jsx("span", { children: `${Math.abs(efficiencyDelta).toFixed(1)}% vs last month` })
50428
+ /* @__PURE__ */ jsx("span", { children: `${Math.abs(efficiencyDelta).toFixed(1)}% vs ${trendComparisonLabel}` })
50373
50429
  ] })
50374
50430
  ] })
50375
50431
  ] }),
@@ -50379,7 +50435,7 @@ var WorkspaceMonthlyHistory = ({
50379
50435
  /* @__PURE__ */ jsx("div", { className: "text-2xl font-bold text-gray-900", children: formatIdleTime(metrics2?.avgIdleTime ?? 0) }),
50380
50436
  /* @__PURE__ */ jsxs("div", { className: `flex items-center gap-1 ${idleImproved ? "bg-emerald-50 text-emerald-600" : "bg-red-50 text-red-600"} px-2 py-0.5 rounded-full text-[10px] font-medium whitespace-nowrap flex-shrink-0`, children: [
50381
50437
  idleImproved ? /* @__PURE__ */ jsx(ArrowDown, { className: "w-3 h-3" }) : /* @__PURE__ */ jsx(ArrowUp, { className: "w-3 h-3" }),
50382
- /* @__PURE__ */ jsx("span", { children: idleTrendText })
50438
+ /* @__PURE__ */ jsx("span", { children: `${idleTrendText} vs ${trendComparisonLabel}` })
50383
50439
  ] })
50384
50440
  ] })
50385
50441
  ] }),
@@ -50392,10 +50448,10 @@ var WorkspaceMonthlyHistory = ({
50392
50448
  ] }),
50393
50449
  isUptimeMode ? /* @__PURE__ */ jsxs("div", { className: `flex items-center gap-1 ${stoppagesImproved ? "bg-emerald-50 text-emerald-600" : "bg-red-50 text-red-600"} px-2 py-0.5 rounded-full text-[10px] font-medium whitespace-nowrap flex-shrink-0`, children: [
50394
50450
  stoppagesImproved ? /* @__PURE__ */ jsx(ArrowDown, { className: "w-3 h-3" }) : /* @__PURE__ */ jsx(ArrowUp, { className: "w-3 h-3" }),
50395
- /* @__PURE__ */ jsx("span", { children: stoppagesTrendText })
50451
+ /* @__PURE__ */ jsx("span", { children: `${stoppagesTrendText} vs ${trendComparisonLabel}` })
50396
50452
  ] }) : /* @__PURE__ */ jsxs("div", { className: `flex items-center gap-1 ${cycleWorsened ? "bg-red-50 text-red-600" : "bg-emerald-50 text-emerald-600"} px-2 py-0.5 rounded-full text-[10px] font-medium whitespace-nowrap flex-shrink-0`, children: [
50397
50453
  cycleWorsened ? /* @__PURE__ */ jsx(ArrowUp, { className: "w-3 h-3" }) : /* @__PURE__ */ jsx(ArrowDown, { className: "w-3 h-3" }),
50398
- /* @__PURE__ */ jsx("span", { children: `${Math.abs(cycleDelta).toFixed(1)}% vs last month` })
50454
+ /* @__PURE__ */ jsx("span", { children: `${Math.abs(cycleDelta).toFixed(1)}% vs ${trendComparisonLabel}` })
50399
50455
  ] })
50400
50456
  ] })
50401
50457
  ] })
@@ -51107,6 +51163,7 @@ var getShiftDisplayName2 = (shiftId, availableShifts) => {
51107
51163
  var WorkspaceMonthlyPdfGenerator = ({
51108
51164
  workspaceId,
51109
51165
  workspaceName,
51166
+ lineName,
51110
51167
  monthlyData,
51111
51168
  analysisData,
51112
51169
  selectedMonth,
@@ -51151,13 +51208,20 @@ var WorkspaceMonthlyPdfGenerator = ({
51151
51208
  startKey: rangeStart || monthBounds.startKey,
51152
51209
  endKey: rangeEnd || monthBounds.endKey
51153
51210
  };
51211
+ const boundsSourceKey = rangeStart || rangeEnd || monthBounds.startKey;
51212
+ const boundsSourceDate = parseDateKeyToDate(boundsSourceKey);
51213
+ const effectiveBounds = getMonthKeyBounds(boundsSourceDate.getFullYear(), boundsSourceDate.getMonth());
51154
51214
  const normalizedRange = normalizeDateKeyRange(
51155
51215
  requestedRange.startKey,
51156
51216
  requestedRange.endKey,
51157
- monthBounds.startKey,
51158
- monthBounds.endKey
51217
+ effectiveBounds.startKey,
51218
+ effectiveBounds.endKey
51219
+ );
51220
+ const fullRange = isFullMonthRange(
51221
+ normalizedRange,
51222
+ boundsSourceDate.getFullYear(),
51223
+ boundsSourceDate.getMonth()
51159
51224
  );
51160
- const fullRange = isFullMonthRange(normalizedRange, selectedYear, selectedMonth);
51161
51225
  const reportStartDate = parseDateKeyToDate(normalizedRange.startKey);
51162
51226
  const reportEndDate = parseDateKeyToDate(normalizedRange.endKey);
51163
51227
  const reportStartStr = reportStartDate.toLocaleDateString("en-IN", {
@@ -51172,36 +51236,57 @@ var WorkspaceMonthlyPdfGenerator = ({
51172
51236
  year: "numeric",
51173
51237
  timeZone: "Asia/Kolkata"
51174
51238
  });
51239
+ const doc = new jsPDF$1();
51240
+ const pageHeight = typeof doc.internal.pageSize.height === "number" ? Number(doc.internal.pageSize.height) : 297;
51241
+ const footerY = pageHeight - 17;
51242
+ const maxContentY = footerY - 10;
51243
+ const generatedText = `Generated on ${(/* @__PURE__ */ new Date()).toLocaleString("en-IN", { timeZone: "Asia/Kolkata" })}`;
51244
+ const resolvedLineName = lineName?.trim() || "Line";
51245
+ const dailySectionTitle = isUptimeMode ? "Daily Utilization Summary" : "Daily Performance Summary";
51246
+ const monthName = reportStartDate.toLocaleDateString("en-IN", {
51247
+ month: "long",
51248
+ year: "numeric",
51249
+ timeZone: "Asia/Kolkata"
51250
+ });
51175
51251
  trackCoreEvent("Workspace Monthly PDF Export Clicked", {
51176
51252
  workspace_id: workspaceId,
51177
51253
  workspace_name: workspaceName,
51178
- month: selectedMonth,
51179
- year: selectedYear,
51254
+ line_name: resolvedLineName,
51255
+ month: reportStartDate.getMonth(),
51256
+ year: reportStartDate.getFullYear(),
51180
51257
  shift_id: selectedShiftId,
51181
51258
  range_start: normalizedRange.startKey,
51182
51259
  range_end: normalizedRange.endKey,
51183
51260
  is_full_month: fullRange
51184
51261
  });
51185
- const doc = new jsPDF$1();
51186
- doc.setFontSize(14);
51187
- doc.setFont("helvetica", "bold");
51188
- doc.setTextColor(50, 50, 50);
51189
- doc.text("OPTIFYE.AI", 20, 15);
51190
- doc.setFontSize(11);
51191
- doc.setFont("helvetica", "normal");
51192
- doc.setTextColor(80, 80, 80);
51193
- const reportText = isUptimeMode ? "MONTHLY UTILIZATION REPORT" : "MONTHLY PERFORMANCE REPORT";
51194
- const reportTextWidth = doc.getStringUnitWidth(reportText) * 11 / doc.internal.scaleFactor;
51195
- doc.text(reportText, doc.internal.pageSize.width - 20 - reportTextWidth, 15);
51196
- doc.setDrawColor(200, 200, 200);
51197
- doc.setLineWidth(0.5);
51198
- doc.line(20, 20, 190, 20);
51262
+ const drawPageChrome = () => {
51263
+ doc.setFontSize(14);
51264
+ doc.setFont("helvetica", "bold");
51265
+ doc.setTextColor(50, 50, 50);
51266
+ doc.text("OPTIFYE.AI", 20, 15);
51267
+ doc.setFontSize(11);
51268
+ doc.setFont("helvetica", "normal");
51269
+ doc.setTextColor(80, 80, 80);
51270
+ const reportText = isUptimeMode ? "MONTHLY UTILIZATION REPORT" : "MONTHLY PERFORMANCE REPORT";
51271
+ const reportTextWidth = doc.getStringUnitWidth(reportText) * 11 / doc.internal.scaleFactor;
51272
+ doc.text(reportText, doc.internal.pageSize.width - 20 - reportTextWidth, 15);
51273
+ doc.setDrawColor(200, 200, 200);
51274
+ doc.setLineWidth(0.5);
51275
+ doc.line(20, 20, 190, 20);
51276
+ };
51277
+ const drawFooter = () => {
51278
+ doc.setFontSize(9);
51279
+ doc.setTextColor(130, 130, 130);
51280
+ doc.text(generatedText, 20, footerY);
51281
+ doc.setTextColor(0, 0, 0);
51282
+ };
51283
+ drawPageChrome();
51199
51284
  doc.setFillColor(250, 250, 250);
51200
51285
  doc.roundedRect(15, 25, 180, 55, 3, 3, "F");
51201
51286
  doc.setFontSize(32);
51202
51287
  doc.setFont("helvetica", "bold");
51203
51288
  doc.setTextColor(0, 0, 0);
51204
- doc.text("Line 1", 20, 40);
51289
+ doc.text(resolvedLineName, 20, 40);
51205
51290
  doc.setFontSize(22);
51206
51291
  doc.setFont("helvetica", "normal");
51207
51292
  doc.setTextColor(40, 40, 40);
@@ -51209,11 +51294,6 @@ var WorkspaceMonthlyPdfGenerator = ({
51209
51294
  doc.setFontSize(13);
51210
51295
  doc.setFont("helvetica", "normal");
51211
51296
  doc.setTextColor(60, 60, 60);
51212
- const monthName = new Date(selectedYear, selectedMonth).toLocaleDateString("en-IN", {
51213
- month: "long",
51214
- year: "numeric",
51215
- timeZone: "Asia/Kolkata"
51216
- });
51217
51297
  const shiftType = getShiftDisplayName2(selectedShiftId, availableShifts);
51218
51298
  doc.text(`${monthName}`, 20, 65);
51219
51299
  doc.text(`${shiftType}`, 20, 73);
@@ -51225,11 +51305,12 @@ var WorkspaceMonthlyPdfGenerator = ({
51225
51305
  doc.setLineWidth(0.8);
51226
51306
  doc.line(20, 90, 190, 90);
51227
51307
  const reportData = analysisData ? analysisData : filterDataByDateKeyRange(monthlyData, normalizedRange);
51228
- const validDays = reportData.filter((day) => {
51229
- const date = new Date(day.date);
51230
- return date.getMonth() === selectedMonth && date.getFullYear() === selectedYear;
51231
- });
51308
+ const validDays = reportData;
51232
51309
  const validShifts = validDays.map((day) => getShiftData(day, selectedShiftId)).filter(hasShiftData);
51310
+ const dailyEntries = validDays.map((dayData) => {
51311
+ const shift = getShiftData(dayData, selectedShiftId);
51312
+ return { dayData, shift };
51313
+ }).filter(({ shift }) => hasShiftData(shift)).sort((left, right) => getDayDateKey(right.dayData).localeCompare(getDayDateKey(left.dayData)));
51233
51314
  const filteredShifts = isUptimeMode ? validShifts : validShifts.filter((shift) => (shift.efficiency ?? 0) >= 5);
51234
51315
  const monthlyMetrics = filteredShifts.length > 0 ? isUptimeMode ? (() => {
51235
51316
  const totalIdleTime = filteredShifts.reduce((sum, shift) => sum + shift.idleTime, 0);
@@ -51356,21 +51437,27 @@ var WorkspaceMonthlyPdfGenerator = ({
51356
51437
  doc.setLineWidth(0.8);
51357
51438
  const separatorY = isAssemblyWorkspaceAndNotUptime ? 150 : 180;
51358
51439
  doc.line(20, separatorY, 190, separatorY);
51359
- doc.setFillColor(245, 245, 245);
51360
51440
  const dailySectionY = isAssemblyWorkspaceAndNotUptime ? 155 : 185;
51361
- doc.roundedRect(15, dailySectionY, 180, 85, 3, 3, "F");
51362
- doc.setFontSize(18);
51363
- doc.setFont("helvetica", "bold");
51364
- doc.setTextColor(40, 40, 40);
51365
- doc.text(isUptimeMode ? "Daily Utilization Summary" : "Daily Performance Summary", 20, dailySectionY + 10);
51366
- doc.setTextColor(0, 0, 0);
51367
- if (validDays.length > 0) {
51441
+ const renderDailyTablePage = (startIndex, sectionY, title) => {
51442
+ const rowHeight = 8;
51443
+ const tableHeaderY = sectionY + 15;
51444
+ const textY = tableHeaderY + 5;
51445
+ const firstRowY = textY + 10;
51446
+ const rowsPerPage = Math.max(1, Math.floor((maxContentY - firstRowY) / rowHeight));
51447
+ const pageEntries = dailyEntries.slice(startIndex, startIndex + rowsPerPage);
51448
+ const endY = firstRowY + pageEntries.length * rowHeight;
51449
+ const sectionHeight = Math.max(40, endY - sectionY + 5);
51450
+ doc.setFillColor(245, 245, 245);
51451
+ doc.roundedRect(15, sectionY, 180, sectionHeight, 3, 3, "F");
51452
+ doc.setFontSize(18);
51453
+ doc.setFont("helvetica", "bold");
51454
+ doc.setTextColor(40, 40, 40);
51455
+ doc.text(title, 20, sectionY + 10);
51456
+ doc.setTextColor(0, 0, 0);
51368
51457
  doc.setFontSize(10);
51369
51458
  doc.setFont("helvetica", "bold");
51370
51459
  doc.setFillColor(240, 240, 240);
51371
- const tableHeaderY = dailySectionY + 15;
51372
51460
  doc.roundedRect(20, tableHeaderY, 170, 7, 1, 1, "F");
51373
- const textY = tableHeaderY + 5;
51374
51461
  doc.text("Date", 25, textY);
51375
51462
  doc.text(isUptimeMode ? "Productive" : isAssemblyWorkspace ? "Actual Cycle Time" : "Actual", 60, textY);
51376
51463
  doc.text(isUptimeMode ? "Idle" : isAssemblyWorkspace ? "Standard Cycle Time" : "Standard", 95, textY);
@@ -51380,12 +51467,8 @@ var WorkspaceMonthlyPdfGenerator = ({
51380
51467
  doc.setDrawColor(220, 220, 220);
51381
51468
  doc.line(20, textY + 3, 190, textY + 3);
51382
51469
  doc.setFont("helvetica", "normal");
51383
- let yPos = textY + 10;
51384
- const recentDays = validDays.slice(-10).reverse();
51385
- recentDays.forEach((dayData, index) => {
51386
- if (yPos > 260) return;
51387
- const shift = getShiftData(dayData, selectedShiftId);
51388
- if (!hasShiftData(shift)) return;
51470
+ let yPos = firstRowY;
51471
+ pageEntries.forEach(({ dayData, shift }, index) => {
51389
51472
  if (index % 2 === 0) {
51390
51473
  doc.setFillColor(252, 252, 252);
51391
51474
  doc.roundedRect(20, yPos - 4, 170, 7, 1, 1, "F");
@@ -51418,11 +51501,35 @@ var WorkspaceMonthlyPdfGenerator = ({
51418
51501
  doc.text(`${shift.efficiency.toFixed(1)}%`, 135, yPos);
51419
51502
  drawStatusMark(doc, 171, yPos - 0.3, shift.efficiency >= effectiveLegend.green_min);
51420
51503
  }
51421
- yPos += 8;
51504
+ yPos += rowHeight;
51422
51505
  });
51423
51506
  doc.setLineWidth(0.2);
51424
51507
  doc.setDrawColor(220, 220, 220);
51425
51508
  doc.roundedRect(20, tableHeaderY, 170, yPos - tableHeaderY - 3, 1, 1, "S");
51509
+ return startIndex + pageEntries.length;
51510
+ };
51511
+ if (dailyEntries.length > 0) {
51512
+ let renderedEntries = renderDailyTablePage(0, dailySectionY, dailySectionTitle);
51513
+ while (renderedEntries < dailyEntries.length) {
51514
+ drawFooter();
51515
+ doc.addPage();
51516
+ drawPageChrome();
51517
+ doc.setFontSize(12);
51518
+ doc.setFont("helvetica", "bold");
51519
+ doc.setTextColor(40, 40, 40);
51520
+ doc.text(resolvedLineName, 20, 32);
51521
+ doc.setFont("helvetica", "normal");
51522
+ doc.text(getWorkspaceDisplayName(workspaceName), 20, 40);
51523
+ doc.setFontSize(10);
51524
+ doc.setTextColor(90, 90, 90);
51525
+ doc.text(`${monthName} \u2022 ${shiftType} \u2022 ${reportStartStr} - ${reportEndStr}`, 20, 48);
51526
+ doc.setTextColor(0, 0, 0);
51527
+ renderedEntries = renderDailyTablePage(
51528
+ renderedEntries,
51529
+ 56,
51530
+ `${dailySectionTitle} (cont.)`
51531
+ );
51532
+ }
51426
51533
  } else {
51427
51534
  doc.setFontSize(12);
51428
51535
  doc.setFont("helvetica", "normal");
@@ -51430,10 +51537,7 @@ var WorkspaceMonthlyPdfGenerator = ({
51430
51537
  doc.text("No daily data available for this month", 25, dailySectionY + 30);
51431
51538
  doc.setTextColor(0, 0, 0);
51432
51539
  }
51433
- doc.setFontSize(9);
51434
- doc.setTextColor(130, 130, 130);
51435
- const generatedText = `Generated on ${(/* @__PURE__ */ new Date()).toLocaleString("en-IN", { timeZone: "Asia/Kolkata" })}`;
51436
- doc.text(generatedText, 20, 280);
51540
+ drawFooter();
51437
51541
  const fileName = `${getWorkspaceDisplayName(workspaceName)}_${monthName.replace(" ", "_")}_${shiftType.replace(" ", "_")}.pdf`;
51438
51542
  doc.save(fileName);
51439
51543
  } catch (error) {
@@ -63582,7 +63686,9 @@ var KPIDetailView = ({
63582
63686
  month: currentMonth,
63583
63687
  year: currentYear,
63584
63688
  shiftId: selectedShiftId,
63585
- companyId: resolvedCompanyId
63689
+ companyId: resolvedCompanyId,
63690
+ startDate: isFullRange ? void 0 : rangeStart,
63691
+ endDate: isFullRange ? void 0 : rangeEnd
63586
63692
  });
63587
63693
  const configuredTimezone = timezone || dashboardConfig.dateTimeConfig?.defaultTimezone || "UTC";
63588
63694
  useMemo(() => getCurrentTimeInZone(configuredTimezone), [configuredTimezone]);
@@ -71037,15 +71143,26 @@ var WorkspaceDetailView = ({
71037
71143
  const range = useMemo(() => ({ startKey: rangeStart, endKey: rangeEnd }), [rangeStart, rangeEnd]);
71038
71144
  const isFullRange = useMemo(() => isFullMonthRange(range, selectedYear, selectedMonth), [range, selectedYear, selectedMonth]);
71039
71145
  useEffect(() => {
71146
+ const hasExternalRange = typeof urlRangeStart === "string" || typeof urlRangeEnd === "string";
71147
+ if (!hasExternalRange) {
71148
+ return;
71149
+ }
71150
+ const targetStartKey = typeof urlRangeStart === "string" ? urlRangeStart : typeof urlRangeEnd === "string" ? urlRangeEnd : monthBounds.startKey;
71151
+ const targetStartDate = parseDateKeyToDate(targetStartKey);
71152
+ const targetMonth = targetStartDate.getMonth();
71153
+ const targetYear = targetStartDate.getFullYear();
71154
+ const targetBounds = getMonthKeyBounds(targetYear, targetMonth);
71040
71155
  const normalized = normalizeDateKeyRange(
71041
- typeof urlRangeStart === "string" ? urlRangeStart : monthBounds.startKey,
71042
- typeof urlRangeEnd === "string" ? urlRangeEnd : monthBounds.endKey,
71043
- monthBounds.startKey,
71044
- monthBounds.endKey
71156
+ typeof urlRangeStart === "string" ? urlRangeStart : targetBounds.startKey,
71157
+ typeof urlRangeEnd === "string" ? urlRangeEnd : targetBounds.endKey,
71158
+ targetBounds.startKey,
71159
+ targetBounds.endKey
71045
71160
  );
71161
+ setSelectedMonth(targetMonth);
71162
+ setSelectedYear(targetYear);
71046
71163
  setRangeStart(normalized.startKey);
71047
71164
  setRangeEnd(normalized.endKey);
71048
- }, [urlRangeStart, urlRangeEnd, monthBounds.startKey, monthBounds.endKey]);
71165
+ }, [urlRangeStart, urlRangeEnd, monthBounds.startKey]);
71049
71166
  const isHistoricView = Boolean(date && parsedShiftId !== void 0);
71050
71167
  const initialTab = getInitialTab(sourceType, defaultTab, fromMonthly, date);
71051
71168
  const [activeTab, setActiveTab] = useState(initialTab);
@@ -71065,7 +71182,9 @@ var WorkspaceDetailView = ({
71065
71182
  month: selectedMonth,
71066
71183
  year: selectedYear,
71067
71184
  shiftId: selectedShift,
71068
- companyId: dashboardConfig?.entityConfig?.companyId
71185
+ companyId: dashboardConfig?.entityConfig?.companyId,
71186
+ startDate: isFullRange ? void 0 : rangeStart,
71187
+ endDate: isFullRange ? void 0 : rangeEnd
71069
71188
  });
71070
71189
  const {
71071
71190
  isFastSlowClipFiltersEnabled,
@@ -71332,6 +71451,7 @@ var WorkspaceDetailView = ({
71332
71451
  line_name: "",
71333
71452
  line_assembly_enabled: cachedOverviewMetrics.assembly_enabled === true,
71334
71453
  workspace_name: cachedOverviewMetrics.workspace_name,
71454
+ workspace_display_name: cachedOverviewMetrics.displayName ?? null,
71335
71455
  workspace_id: cachedOverviewMetrics.workspace_uuid || "",
71336
71456
  company_id: cachedOverviewMetrics.company_id,
71337
71457
  company_name: "",
@@ -71564,12 +71684,13 @@ var WorkspaceDetailView = ({
71564
71684
  console.warn("Skipping invalid metric:", metric);
71565
71685
  return;
71566
71686
  }
71567
- const dateObj = new Date(metric.date);
71568
- const dateKey = dateObj.toISOString().split("T")[0];
71687
+ const dateKey = getDateKeyFromValue(metric.date);
71688
+ const dateObj = parseDateKeyToDate(dateKey);
71569
71689
  let dayEntry = dayDataMap.get(dateKey);
71570
71690
  if (!dayEntry) {
71571
71691
  dayEntry = {
71572
71692
  date: dateObj,
71693
+ dateKey,
71573
71694
  shifts: {}
71574
71695
  // Multi-shift structure: Record<number, CalendarShiftData>
71575
71696
  };
@@ -71614,6 +71735,7 @@ var WorkspaceDetailView = ({
71614
71735
  });
71615
71736
  const processedData = Array.from(dayDataMap.values()).filter((entry) => Object.keys(entry.shifts).length > 0).map((entry) => ({
71616
71737
  date: entry.date,
71738
+ dateKey: entry.dateKey,
71617
71739
  shifts: entry.shifts
71618
71740
  }));
71619
71741
  console.log(`[handleMonthlyDataLoaded] Transformed data for calendar:`, {
@@ -71646,7 +71768,17 @@ var WorkspaceDetailView = ({
71646
71768
  const analysisMonthlyData = useMemo(() => {
71647
71769
  return filterDataByDateKeyRange(monthlyData, range);
71648
71770
  }, [monthlyData, range]);
71649
- const formattedWorkspaceName = displayName || formatWorkspaceName3(workspace?.workspace_name || "", resolvedLineId);
71771
+ const formattedWorkspaceName = displayName || workspace?.workspace_display_name || formatWorkspaceName3(workspace?.workspace_name || "", resolvedLineId);
71772
+ const resolvedLineName = useMemo(() => {
71773
+ const workspaceLineName = workspace?.line_name?.trim();
71774
+ if (workspaceLineName) {
71775
+ return workspaceLineName;
71776
+ }
71777
+ if (resolvedLineId && dashboardConfig?.entityConfig) {
71778
+ return getLineDisplayName(dashboardConfig.entityConfig, resolvedLineId);
71779
+ }
71780
+ return "Line";
71781
+ }, [dashboardConfig?.entityConfig, resolvedLineId, workspace?.line_name]);
71650
71782
  const workspaceCycleTimeEligibility = workspace ? {
71651
71783
  line_assembly_enabled: workspace.line_assembly_enabled,
71652
71784
  action_family: workspace.action_family,
@@ -72191,6 +72323,7 @@ var WorkspaceDetailView = ({
72191
72323
  {
72192
72324
  workspaceId,
72193
72325
  workspaceName: formattedWorkspaceName,
72326
+ lineName: resolvedLineName,
72194
72327
  monthlyData,
72195
72328
  analysisData: analysisMonthlyData,
72196
72329
  selectedMonth,
@@ -81495,4 +81628,4 @@ var streamProxyConfig = {
81495
81628
  }
81496
81629
  };
81497
81630
 
81498
- export { ACTION_FAMILIES, ACTION_NAMES, AIAgentView_default as AIAgentView, AcceptInvite, AcceptInviteView_default as AcceptInviteView, AdvancedFilterDialog, AdvancedFilterPanel, AudioService, AuthCallback, AuthCallbackView_default as AuthCallbackView, AuthProvider, AuthService, AuthenticatedBottleneckClipsView, AuthenticatedFactoryView, AuthenticatedHelpView, AuthenticatedHomeView, AuthenticatedShiftsView, AuthenticatedTargetsView, AuthenticatedTicketsView, AuthenticatedWorkspaceHealthView, AvatarUpload, AxelNotificationPopup, AxelOrb, BackButton, BackButtonMinimal, BarChart, BaseHistoryCalendar, BottleneckClipsModal, BottleneckClipsView_default as BottleneckClipsView, BottlenecksContent, BreakNotificationPopup, CachePrefetchStatus, Card2 as Card, CardContent2 as CardContent, CardDescription2 as CardDescription, CardFooter2 as CardFooter, CardHeader2 as CardHeader, CardTitle2 as CardTitle, ChangeRoleDialog, ClipFilterProvider, ClipsCostView_default as ClipsCostView, CompactWorkspaceHealthCard, ConfirmRemoveUserDialog, CongratulationsOverlay, CroppedHlsVideoPlayer, CroppedVideoPlayer, CycleTimeChart, CycleTimeOverTimeChart, DEFAULT_ANALYTICS_CONFIG, DEFAULT_AUTH_CONFIG, DEFAULT_CONFIG, DEFAULT_DATABASE_CONFIG, DEFAULT_DATE_TIME_CONFIG, DEFAULT_ENDPOINTS_CONFIG, DEFAULT_ENTITY_CONFIG, DEFAULT_HOME_VIEW_CONFIG, DEFAULT_MAP_VIEW_CONFIG, DEFAULT_SHIFT_CONFIG, DEFAULT_SHIFT_DATA, DEFAULT_THEME_CONFIG, DEFAULT_VIDEO_CONFIG, DEFAULT_WORKSPACE_CONFIG, DEFAULT_WORKSPACE_POSITIONS, DashboardHeader, DashboardLayout, DashboardOverridesProvider, DashboardProvider, DateDisplay_default as DateDisplay, DateTimeDisplay, DebugAuth, DebugAuthView_default as DebugAuthView, DetailedHealthStatus, DiagnosisVideoModal, EFFICIENCY_ON_TRACK_THRESHOLD, EmptyStateMessage, EncouragementOverlay, FactoryAssignmentDropdown, FactoryView_default as FactoryView, FileManagerFilters, FilterDialogTrigger, FirstTimeLoginDebug, FirstTimeLoginHandler, FittingTitle, GaugeChart, GridComponentsPlaceholder, HamburgerButton, Header, HealthDateShiftSelector, HealthStatusGrid, HealthStatusIndicator, HelpView_default as HelpView, HlsVideoPlayer, HomeView_default as HomeView, HourlyOutputChart2 as HourlyOutputChart, HourlyUptimeChart, ISTTimer_default as ISTTimer, IdleTimeVlmConfigProvider, ImprovementCenterView_default as ImprovementCenterView, InlineEditableText, InteractiveOnboardingTour, InvitationService, InvitationsTable, InviteUserDialog, KPICard, KPIDetailView_default as KPIDetailView, KPIGrid, KPIHeader, KPISection, KPIsOverviewView_default as KPIsOverviewView, LINE_1_UUID, LINE_2_UUID, LargeOutputProgressChart, LeaderboardDetailView_default as LeaderboardDetailView, Legend5 as Legend, LineAssignmentDropdown, LineChart, LineHistoryCalendar, LineMonthlyHistory, LineMonthlyPdfGenerator, LinePdfExportButton, LinePdfGenerator, LineWhatsAppShareButton, LinesService, LiveTimer, LoadingInline, LoadingOverlay_default as LoadingOverlay, LoadingPage_default as LoadingPage, LoadingSkeleton, LoadingState, LoginPage, LoginView_default as LoginView, Logo, MainLayout, MapGridView, MetricCard_default as MetricCard, MinimalOnboardingPopup, MobileMenuProvider, NewClipsNotification, NoWorkspaceData, OnboardingDemo, OnboardingTour, OptifyeAgentClient, OptifyeLogoLoader_default as OptifyeLogoLoader, OutputProgressChart, PageHeader, PieChart4 as PieChart, PlantHeadView_default as PlantHeadView, PlayPauseIndicator, PrefetchConfigurationError, PrefetchError, PrefetchEvents, PrefetchStatus, PrefetchTimeoutError, ProfileView_default as ProfileView, ROOT_DASHBOARD_EVENT_NAMES, RegistryProvider, RoleBadge, S3ClipsSupabaseService as S3ClipsService, S3Service, SKUManagementView, SOPComplianceChart, SSEChatClient, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, SessionTracker, SessionTrackingContext, SessionTrackingProvider, SettingsPopup, ShiftDisplay_default as ShiftDisplay, ShiftsView_default as ShiftsView, SideNavBar, SignupWithInvitation, SilentErrorBoundary, SimpleOnboardingPopup, SingleVideoStream_default as SingleVideoStream, Skeleton, SubscriptionManager, SubscriptionManagerProvider, SupabaseProvider, SupervisorDropdown_default as SupervisorDropdown, SupervisorManagementView_default as SupervisorManagementView, SupervisorService, TargetWorkspaceGrid, TargetsView_default as TargetsView, TeamManagementView_default as TeamManagementView, ThreadSidebar, TicketHistory_default as TicketHistory, TicketHistoryService, TicketsView_default as TicketsView, TimeDisplay_default as TimeDisplay, TimePickerDropdown, Timer_default as Timer, TimezoneProvider, TimezoneService, UptimeDonutChart, UptimeLineChart, UptimeMetricCards, UserAvatar, UserManagementService, UserManagementTable, UserService, UserUsageDetailModal, UserUsageStats, VideoCard, VideoGridView, VideoPlayer, VideoPreloader, WORKSPACE_POSITIONS, WhatsAppShareButton, WorkspaceCard, WorkspaceCycleTimeMetricCards, WorkspaceDetailView_default as WorkspaceDetailView, WorkspaceDisplayNameExample, WorkspaceGrid, WorkspaceGridItem, WorkspaceHealthCard, WorkspaceHealthView_default as WorkspaceHealthView, WorkspaceHistoryCalendar, WorkspaceMetricCards, WorkspaceMetricCardsImpl, WorkspaceMonthlyDataFetcher, WorkspaceMonthlyHistory, WorkspaceMonthlyPdfGenerator, WorkspacePdfExportButton, WorkspacePdfGenerator, WorkspaceWhatsAppShareButton, actionService, aggregateKPIsFromLineMetricsRows, alertsService, apiUtils, areAllLinesOnSameShift, authCoreService, authOTPService, authRateLimitService, awardsService, buildDateKey, buildKPIsFromLineMetricsRow, buildShiftGroupsKey, canRoleAccessDashboardPath, canRoleAccessTeamManagement, canRoleAssignFactories, canRoleAssignLines, canRoleChangeRole, canRoleInviteRole, canRoleManageCompany, canRoleManageTargets, canRoleManageUsers, canRoleRemoveUser, canRoleViewClipsCost, canRoleViewUsageStats, captureHandledFrontendException, captureSentryException, captureSentryMessage, checkRateLimit2 as checkRateLimit, clearAllRateLimits2 as clearAllRateLimits, clearRateLimit2 as clearRateLimit, clearS3VideoCache, clearS3VideoFromCache, clearSentryContext, clearWorkspaceDisplayNamesCache, cn, createDefaultKPIs, createInvitationService, createLinesService, createSessionTracker, createStorageService, createStreamProxyHandler, createSupabaseClient, createSupervisorService, createThrottledReload, createUserManagementService, createUserService, dashboardService, deleteThread, fetchIdleTimeReasons, filterDataByDateKeyRange, forceRefreshWorkspaceDisplayNames, formatAwardMonth, formatDateInZone, formatDateKeyForDisplay, formatDateTimeInZone, formatDuration2 as formatDuration, formatISTDate, formatIdleTime, formatRangeLabel, formatReasonLabel, formatRelativeTime, formatTimeInZone, fromUrlFriendlyName, getActionDisplayName, getActiveShift, getAllLineDisplayNames, getAllThreadMessages, getAllWorkspaceDisplayNamesAsync, getAllWorkspaceDisplayNamesSnapshot, getAnonClient, getAssignableRoles, getAssignmentColumnLabel, getAvailableShiftIds, getAwardBadgeType, getAwardDescription, getAwardTitle, getBrowserName, getCameraNumber, getCompanyMetricsTableName, getConfigurableShortWorkspaceDisplayName, getConfigurableWorkspaceDisplayName, getConfiguredLineIds, getCoreSessionRecordingProperties, getCoreSessionReplayUrl, getCurrentShift, getCurrentShiftForLine, getCurrentTimeInZone, getCurrentWeekFullRange, getCurrentWeekToDateRange, getDashboardHeaderTimeInZone, getDateKeyFromDate, getDaysDifferenceInZone, getDefaultCameraStreamUrl, getDefaultLineId, getDefaultTabForWorkspace, getInitials, getLineDisplayName, getManufacturingInsights, getMetricsTablePrefix, getMonthKeyBounds, getMonthWeekRanges, getNextUpdateInterval, getOperationalDate, getRoleAssignmentKind, getRoleDescription, getRoleLabel, getRoleMetadata, getRoleNavPaths, getS3SignedUrl, getS3VideoSrc, getShiftData, getShiftNameById, getShiftWorkDurationSeconds, getShortShiftName, getShortWorkspaceDisplayName, getShortWorkspaceDisplayNameAsync, getStoredWorkspaceMappings, getSubscriptionManager, getThreadMessages, getUniformShiftGroup, getUserThreads, getUserThreadsPaginated, getVisibleRolesForCurrentUser, getWorkspaceDisplayName, getWorkspaceDisplayNameAsync, getWorkspaceDisplayNamesMap, getWorkspaceFromUrl, getWorkspaceNavigationParams, groupLinesByShift, hasAnyShiftData, identifyCoreUser, initializeCoreMixpanel, isEfficiencyOnTrack, isFactoryScopedRole, isFullMonthRange, isIgnorableFrontendError, isLegacyConfiguration, isLoopbackHostname, isPrefetchError, isRecentFlowVideoGridMetricMode, isSafari, isSupervisorRole, isTransitionPeriod, isUrlPermanentlyFailed, isValidFactoryViewConfiguration, isValidLineInfoPayload, isValidPrefetchParams, isValidPrefetchStatus, isValidWorkspaceDetailedMetricsPayload, isValidWorkspaceMetricsPayload, isWipGatedVideoGridMetricMode, isWorkspaceDisplayNamesLoaded, isWorkspaceDisplayNamesLoading, lineLeaderboardService, linesService, mergeWithDefaultConfig, migrateLegacyConfiguration, normalizeActionFamily, normalizeDateKeyRange, normalizeRoleLevel, normalizeVideoGridMetricMode, optifyeAgentClient, parseDateKeyToDate, parseS3Uri, preInitializeWorkspaceDisplayNames, preloadS3Video, preloadS3VideoUrl, preloadS3VideosUrl, preloadVideoUrl, preloadVideosUrl, qualityService, realtimeService, refreshWorkspaceDisplayNames, resetCoreMixpanel, resetFailedUrl, resetSubscriptionManager, s3VideoPreloader, setSentryUserContext, setSentryWorkspaceContext, shouldEnableLocalDevTestLogin, shuffleArray, simulateApiDelay, skuService, startCoreSessionRecording, stopCoreSessionRecording, storeWorkspaceMapping, streamProxyConfig, subscribeWorkspaceDisplayNames, throttledReloadDashboard, toUrlFriendlyName, trackCoreEvent, trackCorePageView, transformToChartData, updateThreadTitle, upsertWorkspaceDisplayNameInCache, useAccessControl, useActiveBreaks, useActiveLineId, useAllWorkspaceMetrics, useAnalyticsConfig, useAppTimezone, useAudioService, useAuth, useAuthConfig, useAxelNotifications, useCanSaveTargets, useClipFilter, useClipTypes, useClipTypesWithCounts, useClipsInit, useCompanyClipsCost, useCompanyFastSlowClipFiltersEnabled, useCompanyHasVlmEnabledLine, useCompanyUsersUsage, useComponentOverride, useCustomConfig, useDashboardConfig, useDashboardMetrics, useDatabaseConfig, useDateFormatter, useDateTimeConfig, useDynamicShiftConfig, useEndpointsConfig, useEntityConfig, useFactoryOverviewMetrics, useFeatureFlags, useFormatNumber, useHasLineAccess, useHideMobileHeader, useHistoricWorkspaceMetrics, useHlsStream, useHlsStreamWithCropping, useHookOverride, useHourEndTimer, useHourlyTargetAchievements, useHourlyTargetMisses, useIdleTimeClipClassifications, useIdleTimeReasons, useIdleTimeVlmConfig, useKpiTrends, useLeaderboardMetrics, useLineDetailedMetrics, useLineKPIs, useLineMetrics, useLineShiftConfig, useLineSupervisor, useLineWorkspaceMetrics, useLines, useMessages, useMetrics, useMobileMenu, useMonthlyTrend, useMultiLineShiftConfigs, useNavigation, useOperationalShiftKey, useOptionalSupabase, useOverrides, usePageOverride, usePrefetchClipCounts, useRealtimeLineMetrics, useRegistry, useSKUs, useSessionKeepAlive, useSessionTracking, useSessionTrackingContext, useShiftConfig, useShiftGroups, useShifts, useSubscriptionManager, useSubscriptionManagerSafe, useSupabase, useSupabaseClient, useSupervisorsByLineIds, useTargets, useTeamManagementPermissions, useTheme, useThemeConfig, useThreads, useTicketHistory, useTimezoneContext, useUserLineAccess, useUserUsage, useVideoConfig, useWorkspaceConfig, useWorkspaceDetailedMetrics, useWorkspaceDisplayName, useWorkspaceDisplayNames, useWorkspaceDisplayNamesMap, useWorkspaceHealthById, useWorkspaceHealthLastSeen, useWorkspaceHealthStatus, useWorkspaceMetrics, useWorkspaceNavigation, useWorkspaceOperators, useWorkspaceUptimeTimeline, useWorkspaceVideoStreams, userService, videoPrefetchManager, videoPreloader, weeklyTopPerformerService, whatsappService, withAccessControl, withAuth, withRegistry, withTimezone, workspaceHealthService, workspaceService };
81631
+ export { ACTION_FAMILIES, ACTION_NAMES, AIAgentView_default as AIAgentView, AcceptInvite, AcceptInviteView_default as AcceptInviteView, AdvancedFilterDialog, AdvancedFilterPanel, AudioService, AuthCallback, AuthCallbackView_default as AuthCallbackView, AuthProvider, AuthService, AuthenticatedBottleneckClipsView, AuthenticatedFactoryView, AuthenticatedHelpView, AuthenticatedHomeView, AuthenticatedShiftsView, AuthenticatedTargetsView, AuthenticatedTicketsView, AuthenticatedWorkspaceHealthView, AvatarUpload, AxelNotificationPopup, AxelOrb, BackButton, BackButtonMinimal, BarChart, BaseHistoryCalendar, BottleneckClipsModal, BottleneckClipsView_default as BottleneckClipsView, BottlenecksContent, BreakNotificationPopup, CachePrefetchStatus, Card2 as Card, CardContent2 as CardContent, CardDescription2 as CardDescription, CardFooter2 as CardFooter, CardHeader2 as CardHeader, CardTitle2 as CardTitle, ChangeRoleDialog, ClipFilterProvider, ClipsCostView_default as ClipsCostView, CompactWorkspaceHealthCard, ConfirmRemoveUserDialog, CongratulationsOverlay, CroppedHlsVideoPlayer, CroppedVideoPlayer, CycleTimeChart, CycleTimeOverTimeChart, DEFAULT_ANALYTICS_CONFIG, DEFAULT_AUTH_CONFIG, DEFAULT_CONFIG, DEFAULT_DATABASE_CONFIG, DEFAULT_DATE_TIME_CONFIG, DEFAULT_ENDPOINTS_CONFIG, DEFAULT_ENTITY_CONFIG, DEFAULT_HOME_VIEW_CONFIG, DEFAULT_MAP_VIEW_CONFIG, DEFAULT_SHIFT_CONFIG, DEFAULT_SHIFT_DATA, DEFAULT_THEME_CONFIG, DEFAULT_VIDEO_CONFIG, DEFAULT_WORKSPACE_CONFIG, DEFAULT_WORKSPACE_POSITIONS, DashboardHeader, DashboardLayout, DashboardOverridesProvider, DashboardProvider, DateDisplay_default as DateDisplay, DateTimeDisplay, DebugAuth, DebugAuthView_default as DebugAuthView, DetailedHealthStatus, DiagnosisVideoModal, EFFICIENCY_ON_TRACK_THRESHOLD, EmptyStateMessage, EncouragementOverlay, FactoryAssignmentDropdown, FactoryView_default as FactoryView, FileManagerFilters, FilterDialogTrigger, FirstTimeLoginDebug, FirstTimeLoginHandler, FittingTitle, GaugeChart, GridComponentsPlaceholder, HamburgerButton, Header, HealthDateShiftSelector, HealthStatusGrid, HealthStatusIndicator, HelpView_default as HelpView, HlsVideoPlayer, HomeView_default as HomeView, HourlyOutputChart2 as HourlyOutputChart, HourlyUptimeChart, ISTTimer_default as ISTTimer, IdleTimeVlmConfigProvider, ImprovementCenterView_default as ImprovementCenterView, InlineEditableText, InteractiveOnboardingTour, InvitationService, InvitationsTable, InviteUserDialog, KPICard, KPIDetailView_default as KPIDetailView, KPIGrid, KPIHeader, KPISection, KPIsOverviewView_default as KPIsOverviewView, LINE_1_UUID, LINE_2_UUID, LargeOutputProgressChart, LeaderboardDetailView_default as LeaderboardDetailView, Legend5 as Legend, LineAssignmentDropdown, LineChart, LineHistoryCalendar, LineMonthlyHistory, LineMonthlyPdfGenerator, LinePdfExportButton, LinePdfGenerator, LineWhatsAppShareButton, LinesService, LiveTimer, LoadingInline, LoadingOverlay_default as LoadingOverlay, LoadingPage_default as LoadingPage, LoadingSkeleton, LoadingState, LoginPage, LoginView_default as LoginView, Logo, MainLayout, MapGridView, MetricCard_default as MetricCard, MinimalOnboardingPopup, MobileMenuProvider, NewClipsNotification, NoWorkspaceData, OnboardingDemo, OnboardingTour, OptifyeAgentClient, OptifyeLogoLoader_default as OptifyeLogoLoader, OutputProgressChart, PageHeader, PieChart4 as PieChart, PlantHeadView_default as PlantHeadView, PlayPauseIndicator, PrefetchConfigurationError, PrefetchError, PrefetchEvents, PrefetchStatus, PrefetchTimeoutError, ProfileView_default as ProfileView, ROOT_DASHBOARD_EVENT_NAMES, RegistryProvider, RoleBadge, S3ClipsSupabaseService as S3ClipsService, S3Service, SKUManagementView, SOPComplianceChart, SSEChatClient, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, SessionTracker, SessionTrackingContext, SessionTrackingProvider, SettingsPopup, ShiftDisplay_default as ShiftDisplay, ShiftsView_default as ShiftsView, SideNavBar, SignupWithInvitation, SilentErrorBoundary, SimpleOnboardingPopup, SingleVideoStream_default as SingleVideoStream, Skeleton, SubscriptionManager, SubscriptionManagerProvider, SupabaseProvider, SupervisorDropdown_default as SupervisorDropdown, SupervisorManagementView_default as SupervisorManagementView, SupervisorService, TargetWorkspaceGrid, TargetsView_default as TargetsView, TeamManagementView_default as TeamManagementView, ThreadSidebar, TicketHistory_default as TicketHistory, TicketHistoryService, TicketsView_default as TicketsView, TimeDisplay_default as TimeDisplay, TimePickerDropdown, Timer_default as Timer, TimezoneProvider, TimezoneService, UptimeDonutChart, UptimeLineChart, UptimeMetricCards, UserAvatar, UserManagementService, UserManagementTable, UserService, UserUsageDetailModal, UserUsageStats, VideoCard, VideoGridView, VideoPlayer, VideoPreloader, WORKSPACE_POSITIONS, WhatsAppShareButton, WorkspaceCard, WorkspaceCycleTimeMetricCards, WorkspaceDetailView_default as WorkspaceDetailView, WorkspaceDisplayNameExample, WorkspaceGrid, WorkspaceGridItem, WorkspaceHealthCard, WorkspaceHealthView_default as WorkspaceHealthView, WorkspaceHistoryCalendar, WorkspaceMetricCards, WorkspaceMetricCardsImpl, WorkspaceMonthlyDataFetcher, WorkspaceMonthlyHistory, WorkspaceMonthlyPdfGenerator, WorkspacePdfExportButton, WorkspacePdfGenerator, WorkspaceWhatsAppShareButton, actionService, aggregateKPIsFromLineMetricsRows, alertsService, apiUtils, areAllLinesOnSameShift, authCoreService, authOTPService, authRateLimitService, awardsService, buildDateKey, buildKPIsFromLineMetricsRow, buildShiftGroupsKey, canRoleAccessDashboardPath, canRoleAccessTeamManagement, canRoleAssignFactories, canRoleAssignLines, canRoleChangeRole, canRoleInviteRole, canRoleManageCompany, canRoleManageTargets, canRoleManageUsers, canRoleRemoveUser, canRoleViewClipsCost, canRoleViewUsageStats, captureHandledFrontendException, captureSentryException, captureSentryMessage, checkRateLimit2 as checkRateLimit, clearAllRateLimits2 as clearAllRateLimits, clearRateLimit2 as clearRateLimit, clearS3VideoCache, clearS3VideoFromCache, clearSentryContext, clearWorkspaceDisplayNamesCache, cn, createDefaultKPIs, createInvitationService, createLinesService, createSessionTracker, createStorageService, createStreamProxyHandler, createSupabaseClient, createSupervisorService, createThrottledReload, createUserManagementService, createUserService, dashboardService, deleteThread, fetchIdleTimeReasons, filterDataByDateKeyRange, forceRefreshWorkspaceDisplayNames, formatAwardMonth, formatDateInZone, formatDateKeyForDisplay, formatDateTimeInZone, formatDuration2 as formatDuration, formatISTDate, formatIdleTime, formatRangeLabel, formatReasonLabel, formatRelativeTime, formatTimeInZone, fromUrlFriendlyName, getActionDisplayName, getActiveShift, getAllLineDisplayNames, getAllThreadMessages, getAllWorkspaceDisplayNamesAsync, getAllWorkspaceDisplayNamesSnapshot, getAnonClient, getAssignableRoles, getAssignmentColumnLabel, getAvailableShiftIds, getAwardBadgeType, getAwardDescription, getAwardTitle, getBrowserName, getCameraNumber, getCompanyMetricsTableName, getConfigurableShortWorkspaceDisplayName, getConfigurableWorkspaceDisplayName, getConfiguredLineIds, getCoreSessionRecordingProperties, getCoreSessionReplayUrl, getCurrentShift, getCurrentShiftForLine, getCurrentTimeInZone, getCurrentWeekFullRange, getCurrentWeekToDateRange, getDashboardHeaderTimeInZone, getDateKeyFromDate, getDateKeyFromValue, getDayDateKey, getDaysDifferenceInZone, getDefaultCameraStreamUrl, getDefaultLineId, getDefaultTabForWorkspace, getInitials, getLineDisplayName, getManufacturingInsights, getMetricsTablePrefix, getMonthKeyBounds, getMonthWeekRanges, getMonthlyTrendComparisonLabel, getNextUpdateInterval, getOperationalDate, getRoleAssignmentKind, getRoleDescription, getRoleLabel, getRoleMetadata, getRoleNavPaths, getS3SignedUrl, getS3VideoSrc, getShiftData, getShiftNameById, getShiftWorkDurationSeconds, getShortShiftName, getShortWorkspaceDisplayName, getShortWorkspaceDisplayNameAsync, getStoredWorkspaceMappings, getSubscriptionManager, getThreadMessages, getUniformShiftGroup, getUserThreads, getUserThreadsPaginated, getVisibleRolesForCurrentUser, getWorkspaceDisplayName, getWorkspaceDisplayNameAsync, getWorkspaceDisplayNamesMap, getWorkspaceFromUrl, getWorkspaceNavigationParams, groupLinesByShift, hasAnyShiftData, identifyCoreUser, initializeCoreMixpanel, isEfficiencyOnTrack, isFactoryScopedRole, isFullMonthRange, isIgnorableFrontendError, isLegacyConfiguration, isLoopbackHostname, isPrefetchError, isRecentFlowVideoGridMetricMode, isSafari, isSupervisorRole, isTransitionPeriod, isUrlPermanentlyFailed, isValidFactoryViewConfiguration, isValidLineInfoPayload, isValidPrefetchParams, isValidPrefetchStatus, isValidWorkspaceDetailedMetricsPayload, isValidWorkspaceMetricsPayload, isWipGatedVideoGridMetricMode, isWorkspaceDisplayNamesLoaded, isWorkspaceDisplayNamesLoading, lineLeaderboardService, linesService, mergeWithDefaultConfig, migrateLegacyConfiguration, normalizeActionFamily, normalizeDateKeyRange, normalizeRoleLevel, normalizeVideoGridMetricMode, optifyeAgentClient, parseDateKeyToDate, parseS3Uri, preInitializeWorkspaceDisplayNames, preloadS3Video, preloadS3VideoUrl, preloadS3VideosUrl, preloadVideoUrl, preloadVideosUrl, qualityService, realtimeService, refreshWorkspaceDisplayNames, resetCoreMixpanel, resetFailedUrl, resetSubscriptionManager, s3VideoPreloader, setSentryUserContext, setSentryWorkspaceContext, shouldEnableLocalDevTestLogin, shuffleArray, simulateApiDelay, skuService, startCoreSessionRecording, stopCoreSessionRecording, storeWorkspaceMapping, streamProxyConfig, subscribeWorkspaceDisplayNames, throttledReloadDashboard, toUrlFriendlyName, trackCoreEvent, trackCorePageView, transformToChartData, updateThreadTitle, upsertWorkspaceDisplayNameInCache, useAccessControl, useActiveBreaks, useActiveLineId, useAllWorkspaceMetrics, useAnalyticsConfig, useAppTimezone, useAudioService, useAuth, useAuthConfig, useAxelNotifications, useCanSaveTargets, useClipFilter, useClipTypes, useClipTypesWithCounts, useClipsInit, useCompanyClipsCost, useCompanyFastSlowClipFiltersEnabled, useCompanyHasVlmEnabledLine, useCompanyUsersUsage, useComponentOverride, useCustomConfig, useDashboardConfig, useDashboardMetrics, useDatabaseConfig, useDateFormatter, useDateTimeConfig, useDynamicShiftConfig, useEndpointsConfig, useEntityConfig, useFactoryOverviewMetrics, useFeatureFlags, useFormatNumber, useHasLineAccess, useHideMobileHeader, useHistoricWorkspaceMetrics, useHlsStream, useHlsStreamWithCropping, useHookOverride, useHourEndTimer, useHourlyTargetAchievements, useHourlyTargetMisses, useIdleTimeClipClassifications, useIdleTimeReasons, useIdleTimeVlmConfig, useKpiTrends, useLeaderboardMetrics, useLineDetailedMetrics, useLineKPIs, useLineMetrics, useLineShiftConfig, useLineSupervisor, useLineWorkspaceMetrics, useLines, useMessages, useMetrics, useMobileMenu, useMonthlyTrend, useMultiLineShiftConfigs, useNavigation, useOperationalShiftKey, useOptionalSupabase, useOverrides, usePageOverride, usePrefetchClipCounts, useRealtimeLineMetrics, useRegistry, useSKUs, useSessionKeepAlive, useSessionTracking, useSessionTrackingContext, useShiftConfig, useShiftGroups, useShifts, useSubscriptionManager, useSubscriptionManagerSafe, useSupabase, useSupabaseClient, useSupervisorsByLineIds, useTargets, useTeamManagementPermissions, useTheme, useThemeConfig, useThreads, useTicketHistory, useTimezoneContext, useUserLineAccess, useUserUsage, useVideoConfig, useWorkspaceConfig, useWorkspaceDetailedMetrics, useWorkspaceDisplayName, useWorkspaceDisplayNames, useWorkspaceDisplayNamesMap, useWorkspaceHealthById, useWorkspaceHealthLastSeen, useWorkspaceHealthStatus, useWorkspaceMetrics, useWorkspaceNavigation, useWorkspaceOperators, useWorkspaceUptimeTimeline, useWorkspaceVideoStreams, userService, videoPrefetchManager, videoPreloader, weeklyTopPerformerService, whatsappService, withAccessControl, withAuth, withRegistry, withTimezone, workspaceHealthService, workspaceService };