@optifye/dashboard-core 6.11.35 → 6.11.36

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
@@ -1667,6 +1667,7 @@ var DEFAULT_SHIFT_DATA = {
1667
1667
  efficiency: 0,
1668
1668
  output: 0,
1669
1669
  cycleTime: 0,
1670
+ idealCycleTime: 0,
1670
1671
  pph: 0,
1671
1672
  pphThreshold: 0,
1672
1673
  idealOutput: 0,
@@ -4513,6 +4514,7 @@ var dashboardService = {
4513
4514
  avg_efficiency: item.avg_efficiency || 0,
4514
4515
  total_output: item.total_output || 0,
4515
4516
  avg_cycle_time: item.avg_cycle_time || 0,
4517
+ ideal_cycle_time: item.ideal_cycle_time ?? 0,
4516
4518
  ideal_output: item.ideal_output || 0,
4517
4519
  total_day_output: item.total_day_output ?? item.ideal_output ?? 0,
4518
4520
  avg_pph: item.avg_pph || 0,
@@ -17309,7 +17311,7 @@ var useActiveBreaks = (lineIds) => {
17309
17311
  const [isLoading, setIsLoading] = React143.useState(true);
17310
17312
  const [error, setError] = React143.useState(null);
17311
17313
  const supabase = useSupabase();
17312
- const parseTimeToMinutes4 = (timeStr) => {
17314
+ const parseTimeToMinutes5 = (timeStr) => {
17313
17315
  const [hours, minutes] = timeStr.split(":").map(Number);
17314
17316
  return hours * 60 + minutes;
17315
17317
  };
@@ -17318,8 +17320,8 @@ var useActiveBreaks = (lineIds) => {
17318
17320
  return now4.getHours() * 60 + now4.getMinutes();
17319
17321
  };
17320
17322
  const isTimeInBreak = (breakStart, breakEnd, currentMinutes) => {
17321
- const startMinutes = parseTimeToMinutes4(breakStart);
17322
- const endMinutes = parseTimeToMinutes4(breakEnd);
17323
+ const startMinutes = parseTimeToMinutes5(breakStart);
17324
+ const endMinutes = parseTimeToMinutes5(breakEnd);
17323
17325
  if (endMinutes < startMinutes) {
17324
17326
  return currentMinutes >= startMinutes || currentMinutes < endMinutes;
17325
17327
  } else {
@@ -17327,8 +17329,8 @@ var useActiveBreaks = (lineIds) => {
17327
17329
  }
17328
17330
  };
17329
17331
  const calculateBreakProgress = (breakStart, breakEnd, currentMinutes) => {
17330
- const startMinutes = parseTimeToMinutes4(breakStart);
17331
- const endMinutes = parseTimeToMinutes4(breakEnd);
17332
+ const startMinutes = parseTimeToMinutes5(breakStart);
17333
+ const endMinutes = parseTimeToMinutes5(breakEnd);
17332
17334
  let elapsedMinutes = 0;
17333
17335
  let remainingMinutes = 0;
17334
17336
  if (endMinutes < startMinutes) {
@@ -17346,8 +17348,8 @@ var useActiveBreaks = (lineIds) => {
17346
17348
  return { elapsedMinutes, remainingMinutes };
17347
17349
  };
17348
17350
  const isTimeInShift = (startTime, endTime, currentMinutes) => {
17349
- const startMinutes = parseTimeToMinutes4(startTime);
17350
- const endMinutes = parseTimeToMinutes4(endTime);
17351
+ const startMinutes = parseTimeToMinutes5(startTime);
17352
+ const endMinutes = parseTimeToMinutes5(endTime);
17351
17353
  if (endMinutes < startMinutes) {
17352
17354
  return currentMinutes >= startMinutes || currentMinutes < endMinutes;
17353
17355
  } else {
@@ -17407,8 +17409,8 @@ var useActiveBreaks = (lineIds) => {
17407
17409
  const endTime = breakItem.end || breakItem.endTime || "00:00";
17408
17410
  let duration = breakItem.duration || 0;
17409
17411
  if (!duration || duration === 0) {
17410
- const startMinutes = parseTimeToMinutes4(startTime);
17411
- const endMinutes = parseTimeToMinutes4(endTime);
17412
+ const startMinutes = parseTimeToMinutes5(startTime);
17413
+ const endMinutes = parseTimeToMinutes5(endTime);
17412
17414
  duration = endMinutes < startMinutes ? endMinutes + 24 * 60 - startMinutes : endMinutes - startMinutes;
17413
17415
  }
17414
17416
  return {
@@ -17424,8 +17426,8 @@ var useActiveBreaks = (lineIds) => {
17424
17426
  const endTime = breakItem.end || breakItem.endTime || "00:00";
17425
17427
  let duration = breakItem.duration || 0;
17426
17428
  if (!duration || duration === 0) {
17427
- const startMinutes = parseTimeToMinutes4(startTime);
17428
- const endMinutes = parseTimeToMinutes4(endTime);
17429
+ const startMinutes = parseTimeToMinutes5(startTime);
17430
+ const endMinutes = parseTimeToMinutes5(endTime);
17429
17431
  duration = endMinutes < startMinutes ? endMinutes + 24 * 60 - startMinutes : endMinutes - startMinutes;
17430
17432
  }
17431
17433
  return {
@@ -33440,13 +33442,13 @@ var CycleTimeOverTimeChart = ({
33440
33442
  observer.observe(containerRef.current);
33441
33443
  return () => observer.disconnect();
33442
33444
  }, []);
33443
- const parseTimeToMinutes4 = (value) => {
33445
+ const parseTimeToMinutes5 = (value) => {
33444
33446
  const [hours, minutes] = value.split(":").map(Number);
33445
33447
  if (!Number.isFinite(hours) || !Number.isFinite(minutes)) return 0;
33446
33448
  return hours * 60 + minutes;
33447
33449
  };
33448
33450
  const formatHourLabel = (slotIndex) => {
33449
- const baseMinutes = parseTimeToMinutes4(shiftStart);
33451
+ const baseMinutes = parseTimeToMinutes5(shiftStart);
33450
33452
  const absoluteMinutes = baseMinutes + slotIndex * 60;
33451
33453
  const hour24 = Math.floor(absoluteMinutes % (24 * 60) / 60);
33452
33454
  const ampm = hour24 >= 12 ? "PM" : "AM";
@@ -47903,6 +47905,7 @@ var LineMonthlyPdfGenerator = ({
47903
47905
  rangeEnd,
47904
47906
  selectedShiftId,
47905
47907
  availableShifts,
47908
+ lineAssembly = false,
47906
47909
  compact = false,
47907
47910
  className
47908
47911
  }) => {
@@ -48186,8 +48189,8 @@ var LineMonthlyPdfGenerator = ({
48186
48189
  timeZone: "Asia/Kolkata"
48187
48190
  });
48188
48191
  doc.text(dateStr, 25, yPos);
48189
- doc.text(`${shift.total_workspaces - shift.underperforming_workspaces}`, 60, yPos);
48190
- doc.text(`${shift.total_workspaces}`, 95, yPos);
48192
+ doc.text(`${Math.round(shift.output || 0)}`, 60, yPos);
48193
+ doc.text(`${Math.round(shift.idealOutput || 0)}`, 95, yPos);
48191
48194
  doc.text(`${shift.avg_efficiency.toFixed(1)}%`, 135, yPos);
48192
48195
  const statusColor = getEfficiencyColor(shift.avg_efficiency, effectiveLegend);
48193
48196
  if (statusColor === "green") {
@@ -48217,6 +48220,8 @@ var LineMonthlyPdfGenerator = ({
48217
48220
  doc.setTextColor(0, 0, 0);
48218
48221
  }
48219
48222
  const poorestWorkspaces = underperformingWorkspaces[selectedShiftId] || [];
48223
+ 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);
48224
+ const showCycleTimePoorestPerformers = !isUptimeMode && poorestWorkspaces.some(isCycleTimeWorkspace);
48220
48225
  if (poorestWorkspaces && poorestWorkspaces.length > 0) {
48221
48226
  doc.addPage();
48222
48227
  doc.setFontSize(14);
@@ -48242,7 +48247,11 @@ var LineMonthlyPdfGenerator = ({
48242
48247
  doc.setFillColor(245, 245, 245);
48243
48248
  doc.roundedRect(20, 45, 170, 8, 1, 1, "F");
48244
48249
  doc.text("Workspace", 25, 50);
48245
- doc.text(isUptimeMode ? "Avg Utilization" : "Avg Efficiency", 120, 50);
48250
+ doc.text(
48251
+ isUptimeMode ? "Avg Utilization" : showCycleTimePoorestPerformers ? "Cycle Time" : "Avg Efficiency",
48252
+ 120,
48253
+ 50
48254
+ );
48246
48255
  doc.text("Last 5 Days", 160, 50);
48247
48256
  doc.setLineWidth(0.2);
48248
48257
  doc.setDrawColor(220, 220, 220);
@@ -48261,7 +48270,16 @@ var LineMonthlyPdfGenerator = ({
48261
48270
  );
48262
48271
  const workspaceName = rawWorkspaceName.length > 30 ? `${rawWorkspaceName.substring(0, 27)}...` : rawWorkspaceName;
48263
48272
  doc.text(workspaceName, 25, yPos2);
48264
- doc.text(`${(workspace.avg_efficiency || 0).toFixed(1)}%`, 120, yPos2);
48273
+ if (isUptimeMode) {
48274
+ doc.text(`${(workspace.avg_efficiency || 0).toFixed(1)}%`, 120, yPos2);
48275
+ } else if (isCycleTimeWorkspace(workspace)) {
48276
+ const actualCycleTime = Number.isFinite(workspace.avg_cycle_time) ? Number(workspace.avg_cycle_time) : null;
48277
+ const targetCycleTime = Number.isFinite(workspace.ideal_cycle_time) ? Number(workspace.ideal_cycle_time) : null;
48278
+ const cycleTimeText = actualCycleTime !== null ? `${actualCycleTime.toFixed(1)}s${targetCycleTime !== null ? ` / ${targetCycleTime.toFixed(1)}s` : ""}` : "-";
48279
+ doc.text(cycleTimeText, 120, yPos2);
48280
+ } else {
48281
+ doc.text(`${(workspace.avg_efficiency || 0).toFixed(1)}%`, 120, yPos2);
48282
+ }
48265
48283
  const squareSize = 3;
48266
48284
  const squareSpacing = 1;
48267
48285
  let squareX = 160;
@@ -48356,12 +48374,279 @@ Underperforming Workspaces: ${lineInfo.metrics.underperforming_workspaces} / ${l
48356
48374
  }
48357
48375
  );
48358
48376
  };
48377
+
48378
+ // src/lib/utils/hourlyTargets.ts
48379
+ var stripSeconds2 = (timeStr) => timeStr ? timeStr.slice(0, 5) : timeStr;
48380
+ var MINUTES_PER_DAY = 24 * 60;
48381
+ var parseTimeToMinutes2 = (timeString) => {
48382
+ const normalized = stripSeconds2(timeString || "");
48383
+ if (!normalized || !/^[0-2]\d:[0-5]\d$/.test(normalized)) return Number.NaN;
48384
+ const [hours, minutes] = normalized.split(":").map(Number);
48385
+ return hours * 60 + minutes;
48386
+ };
48387
+ var normalizeBreaksOnShiftTimeline = (shiftStart, breaks) => {
48388
+ const shiftStartMinutes = parseTimeToMinutes2(shiftStart);
48389
+ if (!Number.isFinite(shiftStartMinutes)) return [];
48390
+ const normalizedBreaks = [];
48391
+ for (const entry of breaks) {
48392
+ const startRaw = parseTimeToMinutes2(entry.startTime);
48393
+ const endRaw = parseTimeToMinutes2(entry.endTime);
48394
+ if (!Number.isFinite(startRaw) || !Number.isFinite(endRaw)) continue;
48395
+ let start = startRaw;
48396
+ let end = endRaw;
48397
+ if (end <= start) {
48398
+ end += 24 * 60;
48399
+ }
48400
+ if (start < shiftStartMinutes) {
48401
+ start += 24 * 60;
48402
+ end += 24 * 60;
48403
+ }
48404
+ const label = entry.remarks?.trim() || "Break";
48405
+ normalizedBreaks.push({ start, end, label });
48406
+ }
48407
+ return normalizedBreaks;
48408
+ };
48409
+ var roundTarget = (value, mode) => {
48410
+ if (!Number.isFinite(value)) return 0;
48411
+ switch (mode) {
48412
+ case "floor":
48413
+ return Math.floor(value);
48414
+ case "ceil":
48415
+ return Math.ceil(value);
48416
+ case "round":
48417
+ default:
48418
+ return Math.round(value);
48419
+ }
48420
+ };
48421
+ var formatDateKey = (date) => {
48422
+ const year = date.getUTCFullYear();
48423
+ const month = `${date.getUTCMonth() + 1}`.padStart(2, "0");
48424
+ const day = `${date.getUTCDate()}`.padStart(2, "0");
48425
+ return `${year}-${month}-${day}`;
48426
+ };
48427
+ var shiftDateKey = (dateKey, deltaDays) => {
48428
+ const [yearPart, monthPart, dayPart] = dateKey.split("-").map(Number);
48429
+ const year = Number.isFinite(yearPart) ? yearPart : 1970;
48430
+ const month = Number.isFinite(monthPart) ? monthPart : 1;
48431
+ const day = Number.isFinite(dayPart) ? dayPart : 1;
48432
+ const date = new Date(Date.UTC(year, month - 1, day));
48433
+ date.setUTCDate(date.getUTCDate() + deltaDays);
48434
+ return formatDateKey(date);
48435
+ };
48436
+ var getZonedNowSnapshot = (timeZone, now4) => {
48437
+ const formatter = new Intl.DateTimeFormat("en-US", {
48438
+ timeZone,
48439
+ year: "numeric",
48440
+ month: "2-digit",
48441
+ day: "2-digit",
48442
+ hour: "2-digit",
48443
+ minute: "2-digit",
48444
+ hourCycle: "h23"
48445
+ });
48446
+ const parts = formatter.formatToParts(now4).reduce((acc, part) => {
48447
+ if (part.type !== "literal") {
48448
+ acc[part.type] = part.value;
48449
+ }
48450
+ return acc;
48451
+ }, {});
48452
+ const year = Number(parts.year);
48453
+ const month = Number(parts.month);
48454
+ const day = Number(parts.day);
48455
+ const hour = Number(parts.hour);
48456
+ const minute = Number(parts.minute);
48457
+ return {
48458
+ dateKey: `${String(year).padStart(4, "0")}-${String(month).padStart(2, "0")}-${String(day).padStart(2, "0")}`,
48459
+ minutesOfDay: (Number.isFinite(hour) ? hour : 0) * 60 + (Number.isFinite(minute) ? minute : 0)
48460
+ };
48461
+ };
48462
+ var getDateKeyInTimeZone = (timeZone, now4 = /* @__PURE__ */ new Date()) => getZonedNowSnapshot(timeZone, now4).dateKey;
48463
+ var buildHourlyIntervals = ({
48464
+ shiftStart,
48465
+ shiftEnd,
48466
+ bucketMinutes = 60,
48467
+ fallbackHours = 11
48468
+ }) => {
48469
+ const startMinutes = parseTimeToMinutes2(shiftStart);
48470
+ if (!Number.isFinite(startMinutes)) return [];
48471
+ const bucket = Number.isFinite(bucketMinutes) && bucketMinutes > 0 ? Math.floor(bucketMinutes) : 60;
48472
+ let totalMinutes;
48473
+ const endRaw = shiftEnd ? parseTimeToMinutes2(shiftEnd) : Number.NaN;
48474
+ if (!Number.isFinite(endRaw)) {
48475
+ totalMinutes = Math.max(0, Math.round(fallbackHours * 60));
48476
+ } else {
48477
+ let endMinutes = endRaw;
48478
+ if (endMinutes <= startMinutes) {
48479
+ endMinutes += 24 * 60;
48480
+ }
48481
+ totalMinutes = endMinutes - startMinutes;
48482
+ }
48483
+ if (!Number.isFinite(totalMinutes) || totalMinutes <= 0) return [];
48484
+ const count = Math.ceil(totalMinutes / bucket);
48485
+ const shiftEndMinutes = startMinutes + totalMinutes;
48486
+ const intervals = [];
48487
+ for (let i = 0; i < count; i += 1) {
48488
+ const start = startMinutes + i * bucket;
48489
+ const end = Math.min(start + bucket, shiftEndMinutes);
48490
+ const minutes = Math.max(0, end - start);
48491
+ if (minutes <= 0) continue;
48492
+ intervals.push({ start, end, minutes });
48493
+ }
48494
+ return intervals;
48495
+ };
48496
+ var computeBreakMinutesByInterval = ({
48497
+ intervals,
48498
+ shiftStart,
48499
+ breaks
48500
+ }) => {
48501
+ if (!intervals.length || !breaks.length) return intervals.map(() => 0);
48502
+ const normalizedBreaks = normalizeBreaksOnShiftTimeline(shiftStart, breaks);
48503
+ return intervals.map((interval) => {
48504
+ if (!normalizedBreaks.length) return 0;
48505
+ let total = 0;
48506
+ for (const brk of normalizedBreaks) {
48507
+ const overlap = Math.max(0, Math.min(interval.end, brk.end) - Math.max(interval.start, brk.start));
48508
+ total += overlap;
48509
+ if (total >= interval.minutes) return interval.minutes;
48510
+ }
48511
+ return Math.min(interval.minutes, total);
48512
+ });
48513
+ };
48514
+ var computeBreakRemarksByInterval = ({
48515
+ intervals,
48516
+ shiftStart,
48517
+ breaks
48518
+ }) => {
48519
+ if (!intervals.length || !breaks.length) return intervals.map(() => "");
48520
+ const normalizedBreaks = normalizeBreaksOnShiftTimeline(shiftStart, breaks);
48521
+ return intervals.map((interval) => {
48522
+ const labels = normalizedBreaks.filter((brk) => Math.max(0, Math.min(interval.end, brk.end) - Math.max(interval.start, brk.start)) > 0).map((brk) => brk.label).filter((label, index, values) => label && values.indexOf(label) === index);
48523
+ return labels.join(", ");
48524
+ });
48525
+ };
48526
+ var computeEffectiveTargets = ({
48527
+ intervals,
48528
+ breakMinutes,
48529
+ pphThreshold,
48530
+ rounding = "round"
48531
+ }) => {
48532
+ return intervals.map((interval, idx) => {
48533
+ const intervalMinutes = Number(interval?.minutes) || 0;
48534
+ const breakMins = Number(breakMinutes?.[idx]) || 0;
48535
+ const plannedWorkMinutes = Math.max(0, intervalMinutes - breakMins);
48536
+ if (!Number.isFinite(pphThreshold) || pphThreshold <= 0) return 0;
48537
+ if (plannedWorkMinutes <= 0) return 0;
48538
+ return roundTarget(pphThreshold * plannedWorkMinutes / 60, rounding);
48539
+ });
48540
+ };
48541
+ var buildHourlyTargetPlan = ({
48542
+ shiftStart,
48543
+ shiftEnd,
48544
+ breaks = [],
48545
+ pphThreshold,
48546
+ bucketMinutes = 60,
48547
+ fallbackHours = 11,
48548
+ rounding = "round"
48549
+ }) => {
48550
+ const intervals = buildHourlyIntervals({
48551
+ shiftStart,
48552
+ shiftEnd,
48553
+ bucketMinutes,
48554
+ fallbackHours
48555
+ });
48556
+ const breakMinutes = computeBreakMinutesByInterval({
48557
+ intervals,
48558
+ shiftStart,
48559
+ breaks
48560
+ });
48561
+ const breakRemarks = computeBreakRemarksByInterval({
48562
+ intervals,
48563
+ shiftStart,
48564
+ breaks
48565
+ });
48566
+ const productiveMinutes = intervals.map((interval, idx) => Math.max(0, (Number(interval?.minutes) || 0) - (Number(breakMinutes[idx]) || 0)));
48567
+ const targets = computeEffectiveTargets({
48568
+ intervals,
48569
+ breakMinutes,
48570
+ pphThreshold,
48571
+ rounding
48572
+ });
48573
+ return {
48574
+ intervals,
48575
+ breakMinutes,
48576
+ breakRemarks,
48577
+ productiveMinutes,
48578
+ targets
48579
+ };
48580
+ };
48581
+ var isHourlyIntervalComplete = ({
48582
+ reportDate,
48583
+ shiftStart,
48584
+ shiftEnd,
48585
+ interval,
48586
+ timeZone = "Asia/Kolkata",
48587
+ now: now4 = /* @__PURE__ */ new Date()
48588
+ }) => {
48589
+ if (!reportDate) return true;
48590
+ const snapshot = getZonedNowSnapshot(timeZone, now4);
48591
+ const shiftStartMinutes = parseTimeToMinutes2(shiftStart);
48592
+ const shiftEndMinutes = shiftEnd ? parseTimeToMinutes2(shiftEnd) : Number.NaN;
48593
+ const wrapsMidnight = Number.isFinite(shiftStartMinutes) && Number.isFinite(shiftEndMinutes) && shiftEndMinutes <= shiftStartMinutes;
48594
+ if (reportDate === snapshot.dateKey) {
48595
+ return interval.end <= snapshot.minutesOfDay;
48596
+ }
48597
+ if (wrapsMidnight && reportDate === shiftDateKey(snapshot.dateKey, -1)) {
48598
+ return interval.end <= snapshot.minutesOfDay + MINUTES_PER_DAY;
48599
+ }
48600
+ return reportDate < snapshot.dateKey;
48601
+ };
48602
+ var isShiftInProgressForReportDate = ({
48603
+ reportDate,
48604
+ shiftStart,
48605
+ shiftEnd,
48606
+ timeZone = "Asia/Kolkata",
48607
+ now: now4 = /* @__PURE__ */ new Date()
48608
+ }) => {
48609
+ if (!reportDate || !shiftStart || !shiftEnd) return false;
48610
+ const shiftStartMinutes = parseTimeToMinutes2(shiftStart);
48611
+ const shiftEndMinutesRaw = parseTimeToMinutes2(shiftEnd);
48612
+ if (!Number.isFinite(shiftStartMinutes) || !Number.isFinite(shiftEndMinutesRaw)) {
48613
+ return false;
48614
+ }
48615
+ let shiftEndMinutes = shiftEndMinutesRaw;
48616
+ const wrapsMidnight = shiftEndMinutes <= shiftStartMinutes;
48617
+ if (wrapsMidnight) {
48618
+ shiftEndMinutes += MINUTES_PER_DAY;
48619
+ }
48620
+ const snapshot = getZonedNowSnapshot(timeZone, now4);
48621
+ let currentMinutes = null;
48622
+ if (reportDate === snapshot.dateKey) {
48623
+ currentMinutes = snapshot.minutesOfDay;
48624
+ } else if (wrapsMidnight && reportDate === shiftDateKey(snapshot.dateKey, -1)) {
48625
+ currentMinutes = snapshot.minutesOfDay + MINUTES_PER_DAY;
48626
+ }
48627
+ if (currentMinutes === null) {
48628
+ return false;
48629
+ }
48630
+ return shiftStartMinutes <= currentMinutes && currentMinutes < shiftEndMinutes;
48631
+ };
48632
+ var formatOperationalDateKey = (dateKey, options) => {
48633
+ const [yearPart, monthPart, dayPart] = dateKey.split("-").map(Number);
48634
+ const year = Number.isFinite(yearPart) ? yearPart : 1970;
48635
+ const month = Number.isFinite(monthPart) ? monthPart : 1;
48636
+ const day = Number.isFinite(dayPart) ? dayPart : 1;
48637
+ return new Date(Date.UTC(year, month - 1, day, 12)).toLocaleDateString("en-IN", {
48638
+ ...options,
48639
+ timeZone: "UTC"
48640
+ });
48641
+ };
48359
48642
  var LinePdfGenerator = ({
48360
48643
  lineInfo,
48361
48644
  workspaceData,
48362
48645
  issueResolutionSummary,
48363
48646
  shiftName,
48364
- className
48647
+ className,
48648
+ shiftBreaks = [],
48649
+ reportTimezone = "Asia/Kolkata"
48365
48650
  }) => {
48366
48651
  const [isGenerating, setIsGenerating] = React143.useState(false);
48367
48652
  const formatResolutionDuration2 = (seconds) => {
@@ -48388,7 +48673,7 @@ var LinePdfGenerator = ({
48388
48673
  doc.setFontSize(9);
48389
48674
  doc.setFont("helvetica", "normal");
48390
48675
  doc.setTextColor(100, 100, 100);
48391
- const generatedText = `Generated on ${(/* @__PURE__ */ new Date()).toLocaleString("en-IN", { timeZone: "Asia/Kolkata" })}`;
48676
+ const generatedText = `Generated on ${(/* @__PURE__ */ new Date()).toLocaleString("en-IN", { timeZone: reportTimezone })}`;
48392
48677
  const generatedTextWidth = doc.getStringUnitWidth(generatedText) * 9 / doc.internal.scaleFactor;
48393
48678
  doc.text(generatedText, doc.internal.pageSize.width - 20 - generatedTextWidth, 15);
48394
48679
  doc.setDrawColor(200, 200, 200);
@@ -48406,11 +48691,10 @@ var LinePdfGenerator = ({
48406
48691
  const isUptimeMode = lineInfo.monitoring_mode === "uptime";
48407
48692
  const rawShiftType = shiftName || (lineInfo.shift_id === 0 ? "Day" : lineInfo.shift_id === 1 ? "Night" : `Shift ${lineInfo.shift_id}`);
48408
48693
  const shiftType = rawShiftType.toLowerCase().includes("shift") ? rawShiftType : `${rawShiftType} Shift`;
48409
- const date = new Date(lineInfo.date).toLocaleDateString("en-IN", {
48694
+ const date = formatOperationalDateKey(lineInfo.date, {
48410
48695
  weekday: "long",
48411
48696
  day: "numeric",
48412
- month: "long",
48413
- timeZone: "Asia/Kolkata"
48697
+ month: "long"
48414
48698
  });
48415
48699
  const shiftStartTime = lineInfo.metrics.shift_start ? (/* @__PURE__ */ new Date(`2000-01-01 ${lineInfo.metrics.shift_start}`)).toLocaleTimeString("en-IN", {
48416
48700
  hour: "2-digit",
@@ -48418,24 +48702,25 @@ var LinePdfGenerator = ({
48418
48702
  hour12: true,
48419
48703
  timeZone: "Asia/Kolkata"
48420
48704
  }) : "N/A";
48421
- const isToday2 = new Date(lineInfo.date).toDateString() === (/* @__PURE__ */ new Date()).toDateString();
48422
- let reportEndTime;
48423
- if (isToday2) {
48424
- reportEndTime = (/* @__PURE__ */ new Date()).toLocaleTimeString("en-IN", {
48425
- hour: "2-digit",
48426
- minute: "2-digit",
48427
- timeZone: "Asia/Kolkata"
48428
- });
48429
- } else {
48430
- reportEndTime = lineInfo.metrics.shift_end ? (/* @__PURE__ */ new Date(`2000-01-01 ${lineInfo.metrics.shift_end}`)).toLocaleTimeString("en-IN", {
48431
- hour: "2-digit",
48432
- minute: "2-digit",
48433
- hour12: true,
48434
- timeZone: "Asia/Kolkata"
48435
- }) : "N/A";
48436
- }
48705
+ const currentTime = (/* @__PURE__ */ new Date()).toLocaleTimeString("en-IN", {
48706
+ hour: "2-digit",
48707
+ minute: "2-digit",
48708
+ timeZone: reportTimezone
48709
+ });
48710
+ const reportEndTime = isShiftInProgressForReportDate({
48711
+ reportDate: lineInfo.date,
48712
+ shiftStart: lineInfo.metrics.shift_start || "",
48713
+ shiftEnd: lineInfo.metrics.shift_end,
48714
+ timeZone: reportTimezone
48715
+ }) ? currentTime : lineInfo.metrics.shift_end ? (/* @__PURE__ */ new Date(`2000-01-01 ${lineInfo.metrics.shift_end}`)).toLocaleTimeString("en-IN", {
48716
+ hour: "2-digit",
48717
+ minute: "2-digit",
48718
+ hour12: true,
48719
+ timeZone: "Asia/Kolkata"
48720
+ }) : "N/A";
48437
48721
  if (isUptimeMode) {
48438
48722
  const configuredTimezone = "Asia/Kolkata";
48723
+ const effectiveUptimeTimezone = reportTimezone || configuredTimezone;
48439
48724
  const lineShiftStart = lineInfo.metrics.shift_start || "06:00";
48440
48725
  const lineShiftEnd = lineInfo.metrics.shift_end || "14:00";
48441
48726
  const shiftMinutes = getShiftDurationMinutes(lineShiftStart, lineShiftEnd) || 0;
@@ -48449,7 +48734,7 @@ var LinePdfGenerator = ({
48449
48734
  shiftStart,
48450
48735
  shiftEnd,
48451
48736
  shiftDate,
48452
- timezone: configuredTimezone
48737
+ timezone: effectiveUptimeTimezone
48453
48738
  });
48454
48739
  let activeMinutes = uptimeSeries.activeMinutes;
48455
48740
  let idleMinutes = uptimeSeries.idleMinutes;
@@ -48530,7 +48815,7 @@ var LinePdfGenerator = ({
48530
48815
  shiftStart: lineShiftStart,
48531
48816
  shiftEnd: lineShiftEnd,
48532
48817
  shiftDate: lineInfo.date,
48533
- timezone: configuredTimezone
48818
+ timezone: effectiveUptimeTimezone
48534
48819
  });
48535
48820
  hourlyData = buildHourlyFromSeries(lineUptimeSeries);
48536
48821
  }
@@ -48638,13 +48923,13 @@ var LinePdfGenerator = ({
48638
48923
  doc.setFontSize(contentFontSize);
48639
48924
  doc.setFont("helvetica", "normal");
48640
48925
  let yPos2 = headerBottomY2 + 5.5;
48641
- const now5 = /* @__PURE__ */ new Date();
48642
- const currentTimeIST2 = new Date(now5.toLocaleString("en-US", { timeZone: configuredTimezone }));
48643
- const [sYear2, sMonth2, sDay2] = lineInfo.date.split("-").map(Number);
48644
- const [sStartH2, sStartM2] = (lineShiftStart || "06:00").split(":").map(Number);
48645
- const shiftStartBase2 = new Date(sYear2, sMonth2 - 1, sDay2, sStartH2, sStartM2 || 0);
48926
+ const now4 = /* @__PURE__ */ new Date();
48927
+ const currentTimeIST = new Date(now4.toLocaleString("en-US", { timeZone: configuredTimezone }));
48928
+ const [sYear, sMonth, sDay] = lineInfo.date.split("-").map(Number);
48929
+ const [sStartH, sStartM] = (lineShiftStart || "06:00").split(":").map(Number);
48930
+ const shiftStartBase = new Date(sYear, sMonth - 1, sDay, sStartH, sStartM || 0);
48646
48931
  hourlyData.forEach((entry, index) => {
48647
- const bucketStartTime = new Date(shiftStartBase2);
48932
+ const bucketStartTime = new Date(shiftStartBase);
48648
48933
  bucketStartTime.setHours(bucketStartTime.getHours() + index);
48649
48934
  const bucketEndTime = new Date(bucketStartTime);
48650
48935
  bucketEndTime.setHours(bucketEndTime.getHours() + 1);
@@ -48655,7 +48940,7 @@ var LinePdfGenerator = ({
48655
48940
  hour: "numeric",
48656
48941
  hour12: true
48657
48942
  })}`;
48658
- const dataCollected = bucketEndTime.getTime() <= currentTimeIST2.getTime();
48943
+ const dataCollected = bucketEndTime.getTime() <= currentTimeIST.getTime();
48659
48944
  if (index < totalRows2 - 1) {
48660
48945
  const rowBottomY = headerBottomY2 + (index + 1) * rowHeight;
48661
48946
  doc.setDrawColor(200, 200, 200);
@@ -48666,11 +48951,10 @@ var LinePdfGenerator = ({
48666
48951
  doc.text(utilizationStr, 147, yPos2);
48667
48952
  yPos2 += rowHeight;
48668
48953
  });
48669
- const fileDate2 = new Date(lineInfo.date).toLocaleDateString("en-IN", {
48954
+ const fileDate2 = formatOperationalDateKey(lineInfo.date, {
48670
48955
  day: "2-digit",
48671
48956
  month: "short",
48672
- year: "numeric",
48673
- timeZone: "Asia/Kolkata"
48957
+ year: "numeric"
48674
48958
  }).replace(/ /g, "_");
48675
48959
  const fileShift2 = shiftType.replace(/ /g, "_");
48676
48960
  const fileName2 = `${lineInfo.line_name}_${fileDate2}_${fileShift2}.pdf`;
@@ -48723,66 +49007,32 @@ var LinePdfGenerator = ({
48723
49007
  doc.setLineWidth(0.8);
48724
49008
  doc.line(20, 123, 190, 123);
48725
49009
  const hourlyOverviewStartY = 128;
48726
- const parseTimeToMinutes4 = (timeStr) => {
48727
- const [hours, minutes] = timeStr.split(":");
48728
- const hour = parseInt(hours, 10);
48729
- const minute = parseInt(minutes || "0", 10);
48730
- if (Number.isNaN(hour) || Number.isNaN(minute)) {
48731
- return NaN;
48732
- }
48733
- return (hour * 60 + minute) % (24 * 60);
48734
- };
48735
49010
  const formatMinutesLabel = (totalMinutes) => {
48736
49011
  const normalized = (totalMinutes % (24 * 60) + 24 * 60) % (24 * 60);
48737
49012
  const hour = Math.floor(normalized / 60);
48738
49013
  const minute = normalized % 60;
48739
- const time2 = /* @__PURE__ */ new Date();
48740
- time2.setHours(hour);
48741
- time2.setMinutes(minute);
48742
- time2.setSeconds(0);
48743
- time2.setMilliseconds(0);
49014
+ const time2 = new Date(Date.UTC(2e3, 0, 1, hour, minute));
48744
49015
  return time2.toLocaleTimeString("en-IN", {
48745
49016
  hour: "2-digit",
48746
49017
  minute: "2-digit",
48747
49018
  hour12: true,
48748
- timeZone: "Asia/Kolkata"
48749
- });
48750
- };
48751
- const buildRange = (startMinutes, minutes) => {
48752
- const endMinutes = startMinutes + minutes;
48753
- return {
48754
- label: `${formatMinutesLabel(startMinutes)} - ${formatMinutesLabel(endMinutes)}`,
48755
- minutes
48756
- };
48757
- };
48758
- const getHourlyTimeRanges = (startTimeStr, endTimeStr) => {
48759
- const startMinutes = parseTimeToMinutes4(startTimeStr);
48760
- if (Number.isNaN(startMinutes)) {
48761
- return [];
48762
- }
48763
- if (!endTimeStr) {
48764
- const defaultHours = 11;
48765
- return Array.from({ length: defaultHours }, (_, i) => buildRange(startMinutes + i * 60, 60));
48766
- }
48767
- const endMinutes = parseTimeToMinutes4(endTimeStr);
48768
- if (Number.isNaN(endMinutes)) {
48769
- const fallbackHours = 11;
48770
- return Array.from({ length: fallbackHours }, (_, i) => buildRange(startMinutes + i * 60, 60));
48771
- }
48772
- let durationMinutes = endMinutes - startMinutes;
48773
- if (durationMinutes <= 0) {
48774
- durationMinutes += 24 * 60;
48775
- }
48776
- const rangeCount = Math.max(1, Math.ceil(durationMinutes / 60));
48777
- return Array.from({ length: rangeCount }, (_, i) => {
48778
- const remainingMinutes = durationMinutes - i * 60;
48779
- const rangeMinutes = remainingMinutes >= 60 ? 60 : remainingMinutes;
48780
- return buildRange(startMinutes + i * 60, rangeMinutes);
49019
+ timeZone: "UTC"
48781
49020
  });
48782
49021
  };
48783
- const hourlyTimeRanges = lineInfo.metrics.shift_start ? getHourlyTimeRanges(lineInfo.metrics.shift_start, lineInfo.metrics.shift_end) : [];
49022
+ const hourlyTimeRanges = buildHourlyIntervals({
49023
+ shiftStart: lineInfo.metrics.shift_start || "06:00",
49024
+ shiftEnd: lineInfo.metrics.shift_end,
49025
+ fallbackHours: 11
49026
+ });
49027
+ const targetPlan = buildHourlyTargetPlan({
49028
+ shiftStart: lineInfo.metrics.shift_start || "06:00",
49029
+ shiftEnd: lineInfo.metrics.shift_end,
49030
+ breaks: shiftBreaks,
49031
+ pphThreshold: Number(lineInfo.metrics.threshold_pph ?? 0),
49032
+ fallbackHours: Math.max(hourlyTimeRanges.length, 1),
49033
+ rounding: "floor"
49034
+ });
48784
49035
  const shiftDuration = hourlyTimeRanges.length || 11;
48785
- const targetOutputPerHour = Math.round(lineInfo.metrics.threshold_pph ?? 0);
48786
49036
  let hourlyActualOutput = [];
48787
49037
  if (lineInfo.metrics.output_hourly && Object.keys(lineInfo.metrics.output_hourly).length > 0) {
48788
49038
  const [startHourStr, startMinuteStr] = (lineInfo.metrics.shift_start || "6:00").split(":");
@@ -48968,29 +49218,29 @@ var LinePdfGenerator = ({
48968
49218
  doc.text("Remarks", 160, tableHeaderY);
48969
49219
  doc.setFont("helvetica", "normal");
48970
49220
  let yPos = tableStartY;
48971
- const now4 = /* @__PURE__ */ new Date();
48972
- const currentTimeIST = new Date(now4.toLocaleString("en-US", { timeZone: "Asia/Kolkata" }));
48973
- const [sYear, sMonth, sDay] = lineInfo.date.split("-").map(Number);
48974
- const [sStartH, sStartM] = (lineInfo.metrics.shift_start || "06:00").split(":").map(Number);
48975
- const shiftStartBase = new Date(sYear, sMonth - 1, sDay, sStartH, sStartM || 0);
48976
49221
  hourlyTimeRanges.forEach((timeRange, index) => {
48977
49222
  const actualOutput = hourlyActualOutput[index] || 0;
48978
- const bucketStartTime = new Date(shiftStartBase);
48979
- bucketStartTime.setHours(bucketStartTime.getHours() + index);
48980
- const bucketEndTime = new Date(bucketStartTime.getTime() + timeRange.minutes * 60 * 1e3);
48981
- const dataCollected = bucketEndTime.getTime() <= currentTimeIST.getTime();
49223
+ const dataCollected = isHourlyIntervalComplete({
49224
+ reportDate: lineInfo.date,
49225
+ shiftStart: lineInfo.metrics.shift_start || "06:00",
49226
+ shiftEnd: lineInfo.metrics.shift_end,
49227
+ interval: timeRange,
49228
+ timeZone: reportTimezone
49229
+ });
48982
49230
  const outputStr = dataCollected ? actualOutput.toString() : "TBD";
48983
49231
  if (index < totalRows - 1) {
48984
49232
  const rowBottomY = headerBottomY + (index + 1) * rowSpacing;
48985
49233
  doc.setDrawColor(200, 200, 200);
48986
49234
  doc.line(20, rowBottomY, 190, rowBottomY);
48987
49235
  }
48988
- const rangeMinutes = timeRange.minutes || 60;
48989
- const targetForRange = targetOutputPerHour * (rangeMinutes / 60);
48990
- const targetStr = rangeMinutes === 60 ? targetOutputPerHour.toString() : targetForRange.toFixed(1).replace(/\.0$/, "");
48991
- doc.text(timeRange.label, 25, yPos);
49236
+ const targetForRange = targetPlan.targets[index] ?? 0;
49237
+ const targetStr = targetForRange.toString();
49238
+ const remarkText = targetPlan.breakRemarks[index] || "";
49239
+ doc.text(`${formatMinutesLabel(timeRange.start)} - ${formatMinutesLabel(timeRange.end)}`, 25, yPos);
48992
49240
  doc.text(outputStr, 75, yPos);
48993
49241
  doc.text(targetStr, 105, yPos);
49242
+ const remarkDisplay = remarkText ? doc.splitTextToSize(remarkText, 26)[0] : "";
49243
+ doc.text(remarkDisplay, 160, yPos);
48994
49244
  if (!dataCollected) {
48995
49245
  doc.setTextColor(100, 100, 100);
48996
49246
  doc.text("-", 135, yPos);
@@ -49006,11 +49256,10 @@ var LinePdfGenerator = ({
49006
49256
  doc.setTextColor(0, 0, 0);
49007
49257
  yPos += rowSpacing;
49008
49258
  });
49009
- const fileDate = new Date(lineInfo.date).toLocaleDateString("en-IN", {
49259
+ const fileDate = formatOperationalDateKey(lineInfo.date, {
49010
49260
  day: "2-digit",
49011
49261
  month: "short",
49012
- year: "numeric",
49013
- timeZone: "Asia/Kolkata"
49262
+ year: "numeric"
49014
49263
  }).replace(/ /g, "_");
49015
49264
  const fileShift = shiftType.replace(/ /g, "_");
49016
49265
  const fileName = `${lineInfo.line_name}_${fileDate}_${fileShift}.pdf`;
@@ -49938,6 +50187,13 @@ var WorkspaceMonthlyHistory = ({
49938
50187
  }, [analysisMonthlyData, selectedShiftId, isUptimeMode, shiftWorkSeconds]);
49939
50188
  const efficiencyDelta = trendSummary?.avg_efficiency?.delta_pp ?? 0;
49940
50189
  const efficiencyImproved = efficiencyDelta >= 0;
50190
+ const assemblyRangeCycleTime = React143.useMemo(() => {
50191
+ const trendCycleTime = Number(trendSummary?.avg_cycle_time?.current);
50192
+ if (Number.isFinite(trendCycleTime) && trendCycleTime > 0) {
50193
+ return Math.round(trendCycleTime);
50194
+ }
50195
+ return metrics2?.avgCycleTime ?? 0;
50196
+ }, [trendSummary?.avg_cycle_time?.current, metrics2?.avgCycleTime]);
49941
50197
  const cycleDeltaRaw = trendSummary?.avg_cycle_time?.delta_seconds ?? 0;
49942
50198
  const cyclePrev = trendSummary?.avg_cycle_time?.previous ?? 0;
49943
50199
  const cycleDelta = cyclePrev ? cycleDeltaRaw / cyclePrev * 100 : 0;
@@ -50123,7 +50379,7 @@ var WorkspaceMonthlyHistory = ({
50123
50379
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm font-semibold text-gray-600 mb-1", children: "Avg Cycle Time" }),
50124
50380
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 flex-nowrap", children: [
50125
50381
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-2xl font-bold text-gray-900", children: [
50126
- metrics2?.avgCycleTime ?? 0,
50382
+ assemblyRangeCycleTime,
50127
50383
  "s"
50128
50384
  ] }),
50129
50385
  /* @__PURE__ */ jsxRuntime.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: [
@@ -50459,7 +50715,25 @@ var WorkspaceWhatsAppShareButton = ({
50459
50715
  }
50460
50716
  );
50461
50717
  };
50462
- var WorkspacePdfGenerator = ({ workspace, className, idleTimeReasons, efficiencyLegend, hourlyCycleTimes }) => {
50718
+ var formatOperationalDateKey2 = (dateKey, options) => {
50719
+ const [yearPart, monthPart, dayPart] = dateKey.split("-").map(Number);
50720
+ const year = Number.isFinite(yearPart) ? yearPart : 1970;
50721
+ const month = Number.isFinite(monthPart) ? monthPart : 1;
50722
+ const day = Number.isFinite(dayPart) ? dayPart : 1;
50723
+ return new Date(Date.UTC(year, month - 1, day, 12)).toLocaleDateString("en-IN", {
50724
+ ...options,
50725
+ timeZone: "UTC"
50726
+ });
50727
+ };
50728
+ var WorkspacePdfGenerator = ({
50729
+ workspace,
50730
+ className,
50731
+ idleTimeReasons,
50732
+ efficiencyLegend,
50733
+ hourlyCycleTimes,
50734
+ shiftBreaks = [],
50735
+ reportTimezone = "Asia/Kolkata"
50736
+ }) => {
50463
50737
  const [isGenerating, setIsGenerating] = React143.useState(false);
50464
50738
  const entityConfig = useEntityConfig();
50465
50739
  const effectiveLegend = efficiencyLegend || DEFAULT_EFFICIENCY_LEGEND;
@@ -50489,7 +50763,7 @@ var WorkspacePdfGenerator = ({ workspace, className, idleTimeReasons, efficiency
50489
50763
  doc.setFontSize(9);
50490
50764
  doc.setFont("helvetica", "normal");
50491
50765
  doc.setTextColor(100, 100, 100);
50492
- const generatedText = `Generated on ${(/* @__PURE__ */ new Date()).toLocaleString("en-IN", { timeZone: "Asia/Kolkata" })}`;
50766
+ const generatedText = `Generated on ${(/* @__PURE__ */ new Date()).toLocaleString("en-IN", { timeZone: reportTimezone })}`;
50493
50767
  const generatedTextWidth = doc.getStringUnitWidth(generatedText) * 9 / doc.internal.scaleFactor;
50494
50768
  doc.text(generatedText, doc.internal.pageSize.width - 20 - generatedTextWidth, 15);
50495
50769
  doc.setDrawColor(200, 200, 200);
@@ -50508,11 +50782,10 @@ var WorkspacePdfGenerator = ({ workspace, className, idleTimeReasons, efficiency
50508
50782
  doc.setFontSize(13);
50509
50783
  doc.setFont("helvetica", "normal");
50510
50784
  doc.setTextColor(60, 60, 60);
50511
- const date = new Date(workspace.date).toLocaleDateString("en-IN", {
50785
+ const date = formatOperationalDateKey2(workspace.date, {
50512
50786
  weekday: "long",
50513
50787
  day: "numeric",
50514
- month: "long",
50515
- timeZone: "Asia/Kolkata"
50788
+ month: "long"
50516
50789
  });
50517
50790
  const rawShiftType = workspace.shift_type || (workspace.shift_id === 0 ? "Day" : workspace.shift_id === 1 ? "Night" : `Shift ${workspace.shift_id}`);
50518
50791
  const shiftType = rawShiftType.toLowerCase().includes("shift") ? rawShiftType : `${rawShiftType} Shift`;
@@ -50521,7 +50794,7 @@ var WorkspacePdfGenerator = ({ workspace, className, idleTimeReasons, efficiency
50521
50794
  const currentTime = (/* @__PURE__ */ new Date()).toLocaleTimeString("en-IN", {
50522
50795
  hour: "2-digit",
50523
50796
  minute: "2-digit",
50524
- timeZone: "Asia/Kolkata"
50797
+ timeZone: reportTimezone
50525
50798
  });
50526
50799
  const shiftStartTime = (/* @__PURE__ */ new Date(`2000-01-01 ${workspace.shift_start}`)).toLocaleTimeString("en-IN", {
50527
50800
  hour: "2-digit",
@@ -50533,29 +50806,12 @@ var WorkspacePdfGenerator = ({ workspace, className, idleTimeReasons, efficiency
50533
50806
  minute: "2-digit",
50534
50807
  hour12: true
50535
50808
  });
50536
- const parseTimeToMinutes4 = (timeValue) => {
50537
- const [hourPart, minutePart] = timeValue.split(":").map(Number);
50538
- const hour = Number.isFinite(hourPart) ? hourPart : 0;
50539
- const minute = Number.isFinite(minutePart) ? minutePart : 0;
50540
- return hour * 60 + minute;
50541
- };
50542
- const toShiftUtcMs = (dateKey, timeValue) => {
50543
- const [yearPart, monthPart, dayPart] = dateKey.split("-").map(Number);
50544
- const year = Number.isFinite(yearPart) ? yearPart : 1970;
50545
- const month = Number.isFinite(monthPart) ? monthPart : 1;
50546
- const day = Number.isFinite(dayPart) ? dayPart : 1;
50547
- const [hourPart, minutePart] = timeValue.split(":").map(Number);
50548
- const hour = Number.isFinite(hourPart) ? hourPart : 0;
50549
- const minute = Number.isFinite(minutePart) ? minutePart : 0;
50550
- const IST_OFFSET_MINUTES = 330;
50551
- return Date.UTC(year, month - 1, day, hour, minute) - IST_OFFSET_MINUTES * 60 * 1e3;
50552
- };
50553
- const shiftStartMinutes = parseTimeToMinutes4(workspace.shift_start);
50554
- const shiftEndMinutes = parseTimeToMinutes4(workspace.shift_end);
50555
- const wrapsMidnight = shiftEndMinutes <= shiftStartMinutes;
50556
- const shiftStartUtcMs = toShiftUtcMs(workspace.date, workspace.shift_start);
50557
- const shiftEndUtcMs = toShiftUtcMs(workspace.date, workspace.shift_end) + (wrapsMidnight ? 24 * 60 * 60 * 1e3 : 0);
50558
- const isShiftInProgress = Date.now() >= shiftStartUtcMs && Date.now() < shiftEndUtcMs;
50809
+ const isShiftInProgress = isShiftInProgressForReportDate({
50810
+ reportDate: workspace.date,
50811
+ shiftStart: workspace.shift_start,
50812
+ shiftEnd: workspace.shift_end,
50813
+ timeZone: reportTimezone
50814
+ });
50559
50815
  const reportPeriodEndTime = isShiftInProgress ? currentTime : shiftEndTime;
50560
50816
  doc.setFontSize(12);
50561
50817
  doc.setTextColor(80, 80, 80);
@@ -50661,7 +50917,7 @@ var WorkspacePdfGenerator = ({ workspace, className, idleTimeReasons, efficiency
50661
50917
  shiftStart: workspace.shift_start,
50662
50918
  shiftEnd: workspace.shift_end,
50663
50919
  shiftDate: workspace.date,
50664
- timezone: "Asia/Kolkata"
50920
+ timezone: reportTimezone
50665
50921
  }) : null;
50666
50922
  const hourlyUptime = uptimeSeries?.points?.length ? Array.from({ length: Math.ceil(uptimeSeries.shiftMinutes / 60) }, (_, index) => {
50667
50923
  const start = index * 60;
@@ -50676,6 +50932,31 @@ var WorkspacePdfGenerator = ({ workspace, className, idleTimeReasons, efficiency
50676
50932
  const hourlyData = isUptimeMode ? hourlyUptime : isAssemblyCycleMode ? hourlyCycleTimes && hourlyCycleTimes.length > 0 ? hourlyCycleTimes : workspace.hourly_action_counts || [] : workspace.hourly_action_counts || [];
50677
50933
  const hourlyTarget = workspace.pph_threshold;
50678
50934
  const cycleTarget = workspace.ideal_cycle_time || 0;
50935
+ const hourlyIntervals = buildHourlyIntervals({
50936
+ shiftStart: workspace.shift_start,
50937
+ shiftEnd: workspace.shift_end,
50938
+ fallbackHours: Math.max(hourlyData.length, 1)
50939
+ });
50940
+ const outputTargetPlan = !isUptimeMode && !isAssemblyCycleMode ? buildHourlyTargetPlan({
50941
+ shiftStart: workspace.shift_start,
50942
+ shiftEnd: workspace.shift_end,
50943
+ breaks: shiftBreaks,
50944
+ pphThreshold: workspace.pph_threshold,
50945
+ fallbackHours: Math.max(hourlyData.length, 1),
50946
+ rounding: "floor"
50947
+ }) : null;
50948
+ const formatIntervalLabel = (totalMinutes) => {
50949
+ const normalized = (totalMinutes % (24 * 60) + 24 * 60) % (24 * 60);
50950
+ const hour = Math.floor(normalized / 60);
50951
+ const minute = normalized % 60;
50952
+ const time2 = new Date(Date.UTC(2e3, 0, 1, hour, minute));
50953
+ return time2.toLocaleTimeString("en-IN", {
50954
+ hour: "numeric",
50955
+ ...minute > 0 ? { minute: "2-digit" } : {},
50956
+ hour12: true,
50957
+ timeZone: "UTC"
50958
+ });
50959
+ };
50679
50960
  const pageHeight = doc.internal.pageSize.height;
50680
50961
  const maxContentY = pageHeight - 15;
50681
50962
  const baseTableStartY = hourlyPerfStartY + 31;
@@ -50743,36 +51024,30 @@ var WorkspacePdfGenerator = ({ workspace, className, idleTimeReasons, efficiency
50743
51024
  doc.setFontSize(contentFontSize);
50744
51025
  doc.setFont("helvetica", "normal");
50745
51026
  let yPos = headerBottomY + 5.5;
50746
- const workspaceDate = new Date(workspace.date);
50747
- const today = /* @__PURE__ */ new Date();
50748
- today.setHours(0, 0, 0, 0);
50749
- workspaceDate.setHours(0, 0, 0, 0);
50750
- const isToday2 = workspaceDate.getTime() === today.getTime();
51027
+ const isToday2 = getDateKeyInTimeZone(reportTimezone) === workspace.date;
50751
51028
  let currentHour = 24;
50752
51029
  if (isToday2) {
50753
51030
  const now4 = /* @__PURE__ */ new Date();
50754
- const currentTimeIST = new Date(now4.toLocaleString("en-US", { timeZone: "Asia/Kolkata" }));
50755
- currentHour = currentTimeIST.getHours();
51031
+ const currentTimeInReportTimezone = new Date(now4.toLocaleString("en-US", { timeZone: reportTimezone }));
51032
+ currentHour = currentTimeInReportTimezone.getHours();
50756
51033
  }
50757
51034
  hourlyData.forEach((entry, index) => {
50758
- const startTime = /* @__PURE__ */ new Date(`2000-01-01 ${workspace.shift_start}`);
50759
- startTime.setHours(startTime.getHours() + index);
50760
- const endTime = new Date(startTime);
50761
- endTime.setHours(endTime.getHours() + 1);
50762
- const timeRange = `${startTime.toLocaleTimeString("en-IN", {
50763
- hour: "numeric",
50764
- hour12: true
50765
- })} - ${endTime.toLocaleTimeString("en-IN", {
50766
- hour: "numeric",
50767
- hour12: true
50768
- })}`;
50769
- const hourNumber = startTime.getHours();
50770
- const dataCollected = !isToday2 || hourNumber < currentHour;
51035
+ const interval = hourlyIntervals[index];
51036
+ const timeRange = interval ? `${formatIntervalLabel(interval.start)} - ${formatIntervalLabel(interval.end)}` : `${index + 1}`;
51037
+ const dataCollected = interval ? isHourlyIntervalComplete({
51038
+ reportDate: workspace.date,
51039
+ shiftStart: workspace.shift_start,
51040
+ shiftEnd: workspace.shift_end,
51041
+ interval,
51042
+ timeZone: reportTimezone
51043
+ }) : !isToday2 || currentHour >= 24;
50771
51044
  const outputValue = isUptimeMode ? entry.activeMinutes ?? 0 : entry;
50772
51045
  const idleValue = isUptimeMode ? entry.idleMinutes ?? 0 : 0;
50773
51046
  const uptimePercent = isUptimeMode ? entry.uptimePercent ?? 0 : 0;
50774
51047
  const outputStr = dataCollected ? outputValue.toString() : "TBD";
50775
- const targetStr = isUptimeMode ? dataCollected ? idleValue.toString() : "TBD" : hourlyTarget.toString();
51048
+ const effectiveTarget = outputTargetPlan?.targets[index] ?? hourlyTarget;
51049
+ const remarkText = outputTargetPlan?.breakRemarks[index] || "";
51050
+ const targetStr = isUptimeMode ? dataCollected ? idleValue.toString() : "TBD" : effectiveTarget.toString();
50776
51051
  if (index < totalRows - 1) {
50777
51052
  const rowBottomY = headerBottomY + (index + 1) * rowHeight;
50778
51053
  doc.setDrawColor(200, 200, 200);
@@ -50804,10 +51079,12 @@ var WorkspacePdfGenerator = ({ workspace, className, idleTimeReasons, efficiency
50804
51079
  } else {
50805
51080
  doc.text(outputStr, 75, yPos);
50806
51081
  doc.text(targetStr, 105, yPos);
51082
+ const remarkDisplay = remarkText ? doc.splitTextToSize(remarkText, 26)[0] : "";
51083
+ doc.text(remarkDisplay, 160, yPos);
50807
51084
  if (!dataCollected) {
50808
51085
  doc.setTextColor(100, 100, 100);
50809
51086
  doc.text("-", 135, yPos);
50810
- } else if (outputValue >= hourlyTarget) {
51087
+ } else if (outputValue >= effectiveTarget) {
50811
51088
  doc.setTextColor(0, 171, 69);
50812
51089
  doc.setFont("ZapfDingbats", "normal");
50813
51090
  doc.text("4", 135, yPos);
@@ -50821,11 +51098,10 @@ var WorkspacePdfGenerator = ({ workspace, className, idleTimeReasons, efficiency
50821
51098
  yPos += rowHeight;
50822
51099
  });
50823
51100
  const workspaceDisplayName = getWorkspaceDisplayName(workspace.workspace_name, workspace.line_id);
50824
- const fileDate = new Date(workspace.date).toLocaleDateString("en-IN", {
51101
+ const fileDate = formatOperationalDateKey2(workspace.date, {
50825
51102
  day: "2-digit",
50826
51103
  month: "short",
50827
- year: "numeric",
50828
- timeZone: "Asia/Kolkata"
51104
+ year: "numeric"
50829
51105
  }).replace(/ /g, "_");
50830
51106
  const fileShift = shiftType.replace(/ /g, "_");
50831
51107
  const fileName = `${workspaceDisplayName}_${fileDate}_${fileShift}.pdf`;
@@ -50871,12 +51147,25 @@ var WorkspaceMonthlyPdfGenerator = ({
50871
51147
  availableShifts,
50872
51148
  shiftConfig,
50873
51149
  efficiencyLegend,
51150
+ trendSummary,
50874
51151
  className,
50875
51152
  compact = false,
50876
51153
  isAssemblyWorkspace = false
50877
51154
  }) => {
50878
51155
  const [isGenerating, setIsGenerating] = React143.useState(false);
50879
51156
  const effectiveLegend = efficiencyLegend || DEFAULT_EFFICIENCY_LEGEND;
51157
+ const drawStatusMark = (doc, x, y, met) => {
51158
+ doc.setLineWidth(0.8);
51159
+ if (met) {
51160
+ doc.setDrawColor(0, 171, 69);
51161
+ doc.line(x - 1.8, y - 0.2, x - 0.5, y + 1.2);
51162
+ doc.line(x - 0.5, y + 1.2, x + 2.1, y - 1.6);
51163
+ return;
51164
+ }
51165
+ doc.setDrawColor(227, 67, 41);
51166
+ doc.line(x - 1.8, y - 1.6, x + 1.8, y + 1.6);
51167
+ doc.line(x - 1.8, y + 1.6, x + 1.8, y - 1.6);
51168
+ };
50880
51169
  const generatePDF = async () => {
50881
51170
  setIsGenerating(true);
50882
51171
  try {
@@ -51071,12 +51360,13 @@ var WorkspaceMonthlyPdfGenerator = ({
51071
51360
  doc.setFont("helvetica", "bold");
51072
51361
  doc.text(`${outputMetrics.underperformingDays} of ${outputMetrics.totalDays}`, 120, kpiStartY + kpiSpacing * 3);
51073
51362
  } else {
51363
+ const medianCycleTime = Number.isFinite(trendSummary?.avg_cycle_time?.current) ? Number(trendSummary?.avg_cycle_time?.current) : outputMetrics.avgCycleTime;
51074
51364
  createKPIBox(kpiStartY);
51075
51365
  doc.setFontSize(11);
51076
51366
  doc.setFont("helvetica", "normal");
51077
51367
  doc.text("Average Cycle Time:", 25, kpiStartY);
51078
51368
  doc.setFont("helvetica", "bold");
51079
- doc.text(`${Math.round(outputMetrics.avgCycleTime)}s`, 120, kpiStartY);
51369
+ doc.text(`${medianCycleTime.toFixed(1)}s`, 120, kpiStartY);
51080
51370
  createKPIBox(kpiStartY + kpiSpacing);
51081
51371
  doc.setFont("helvetica", "normal");
51082
51372
  doc.text("Average Idle Time:", 25, kpiStartY + kpiSpacing);
@@ -51111,8 +51401,8 @@ var WorkspaceMonthlyPdfGenerator = ({
51111
51401
  doc.roundedRect(20, tableHeaderY, 170, 7, 1, 1, "F");
51112
51402
  const textY = tableHeaderY + 5;
51113
51403
  doc.text("Date", 25, textY);
51114
- doc.text(isUptimeMode ? "Productive" : isAssemblyWorkspace ? "Cycle Time" : "Actual", 60, textY);
51115
- doc.text(isUptimeMode ? "Idle" : isAssemblyWorkspace ? "Target CT" : "Standard", 95, textY);
51404
+ doc.text(isUptimeMode ? "Productive" : isAssemblyWorkspace ? "Actual Cycle Time" : "Actual", 60, textY);
51405
+ doc.text(isUptimeMode ? "Idle" : isAssemblyWorkspace ? "Standard Cycle Time" : "Standard", 95, textY);
51116
51406
  doc.text(isUptimeMode ? "Utilization" : "Efficiency", 135, textY);
51117
51407
  doc.text("Status", 170, textY);
51118
51408
  doc.setLineWidth(0.2);
@@ -51144,31 +51434,18 @@ var WorkspaceMonthlyPdfGenerator = ({
51144
51434
  doc.text(formatIdleTime(productiveSeconds), 60, yPos);
51145
51435
  doc.text(formatIdleTime(clampedIdleSeconds), 95, yPos);
51146
51436
  doc.text(`${utilization}%`, 135, yPos);
51147
- if (utilization >= effectiveLegend.green_min) {
51148
- doc.setTextColor(0, 171, 69);
51149
- doc.text("\u2713", 170, yPos);
51150
- } else {
51151
- doc.setTextColor(227, 67, 41);
51152
- doc.text("\xD7", 170, yPos);
51153
- }
51154
- doc.setTextColor(0, 0, 0);
51437
+ drawStatusMark(doc, 171, yPos - 0.3, utilization >= effectiveLegend.green_min);
51155
51438
  } else {
51156
51439
  if (isAssemblyWorkspace) {
51440
+ const targetCycleTime = Number.isFinite(shift.idealCycleTime) && Number(shift.idealCycleTime) > 0 ? Number(shift.idealCycleTime) : shift.pphThreshold > 0 ? 3600 / shift.pphThreshold : null;
51157
51441
  doc.text(`${shift.cycleTime.toFixed(1)}`, 60, yPos);
51158
- doc.text(`${shift.pphThreshold > 0 ? (3600 / shift.pphThreshold).toFixed(1) : "-"}`, 95, yPos);
51442
+ doc.text(targetCycleTime !== null ? `${targetCycleTime.toFixed(1)}` : "-", 95, yPos);
51159
51443
  } else {
51160
51444
  doc.text(`${shift.output}`, 60, yPos);
51161
51445
  doc.text(`${shift.targetOutput}`, 95, yPos);
51162
51446
  }
51163
51447
  doc.text(`${shift.efficiency.toFixed(1)}%`, 135, yPos);
51164
- if (shift.efficiency >= effectiveLegend.green_min) {
51165
- doc.setTextColor(0, 171, 69);
51166
- doc.text("\u2713", 170, yPos);
51167
- } else {
51168
- doc.setTextColor(227, 67, 41);
51169
- doc.text("\xD7", 170, yPos);
51170
- }
51171
- doc.setTextColor(0, 0, 0);
51448
+ drawStatusMark(doc, 171, yPos - 0.3, shift.efficiency >= effectiveLegend.green_min);
51172
51449
  }
51173
51450
  yPos += 8;
51174
51451
  });
@@ -64334,7 +64611,17 @@ var KPIDetailView = ({
64334
64611
  )
64335
64612
  ] }),
64336
64613
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 ml-auto", children: [
64337
- resolvedLineInfo && activeTab === "overview" && /* @__PURE__ */ jsxRuntime.jsx(LinePdfGenerator, { lineInfo: resolvedLineInfo, workspaceData: resolvedWorkspaces || [], issueResolutionSummary, shiftName: getShiftName(resolvedLineInfo.shift_id) }),
64614
+ resolvedLineInfo && activeTab === "overview" && /* @__PURE__ */ jsxRuntime.jsx(
64615
+ LinePdfGenerator,
64616
+ {
64617
+ lineInfo: resolvedLineInfo,
64618
+ workspaceData: resolvedWorkspaces || [],
64619
+ issueResolutionSummary,
64620
+ shiftName: getShiftName(resolvedLineInfo.shift_id),
64621
+ shiftBreaks: shiftConfig?.shifts?.find((shift) => shift.shiftId === resolvedLineInfo.shift_id)?.breaks || [],
64622
+ reportTimezone: shiftConfig?.timezone || configuredTimezone
64623
+ }
64624
+ ),
64338
64625
  activeTab === "monthly_history" && !urlDate && !urlShift && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
64339
64626
  /* @__PURE__ */ jsxRuntime.jsx(
64340
64627
  MonthlyRangeFilter_default,
@@ -64363,6 +64650,8 @@ var KPIDetailView = ({
64363
64650
  rangeStart,
64364
64651
  rangeEnd,
64365
64652
  selectedShiftId,
64653
+ availableShifts: shiftConfig?.shifts?.map((shift) => ({ id: shift.shiftId, name: shift.shiftName })),
64654
+ lineAssembly: resolvedLineInfo?.assembly === true,
64366
64655
  compact: true
64367
64656
  }
64368
64657
  )
@@ -64541,7 +64830,7 @@ var KPIDetailViewWithDisplayNames = withSelectedLineDisplayNames(KPIDetailView);
64541
64830
  var KPIDetailView_default = KPIDetailViewWithDisplayNames;
64542
64831
  var isNonEmptyString = (value) => typeof value === "string" && value.trim().length > 0;
64543
64832
  var resolveCompanyId = (...candidates) => candidates.find(isNonEmptyString);
64544
- var parseTimeToMinutes2 = (value) => {
64833
+ var parseTimeToMinutes3 = (value) => {
64545
64834
  if (!value) return null;
64546
64835
  const [hourStr, minuteStr] = value.split(":");
64547
64836
  const hour = Number.parseInt(hourStr ?? "", 10);
@@ -64553,8 +64842,8 @@ var getShiftEndDate = (shift, timezone) => {
64553
64842
  if (!shift?.date) return null;
64554
64843
  const startTime = shift.startTime || "06:00";
64555
64844
  const endTime = shift.endTime || "18:00";
64556
- const startMinutes = parseTimeToMinutes2(startTime);
64557
- const endMinutes = parseTimeToMinutes2(endTime);
64845
+ const startMinutes = parseTimeToMinutes3(startTime);
64846
+ const endMinutes = parseTimeToMinutes3(endTime);
64558
64847
  if (startMinutes === null || endMinutes === null) return null;
64559
64848
  const shiftStartDate = dateFnsTz.fromZonedTime(`${shift.date}T${startTime}:00`, timezone);
64560
64849
  let durationMinutes = endMinutes - startMinutes;
@@ -64592,7 +64881,7 @@ var createKpisOverviewUrl = ({
64592
64881
  return queryString ? `/kpis?${queryString}` : "/kpis";
64593
64882
  };
64594
64883
  var getZonedDateAtMidday = (dateKey, timezone) => dateFnsTz.fromZonedTime(`${dateKey}T12:00:00`, timezone);
64595
- var formatDateKey = (dateKey, timezone, options) => {
64884
+ var formatDateKey2 = (dateKey, timezone, options) => {
64596
64885
  try {
64597
64886
  return new Intl.DateTimeFormat("en-US", {
64598
64887
  ...options,
@@ -65660,7 +65949,7 @@ var KPIsOverviewView = ({
65660
65949
  setActiveTab(newTab);
65661
65950
  }, [activeTab, leaderboardLines.length, lines.length]);
65662
65951
  const formatLocalDate2 = React143.useCallback((dateKey) => {
65663
- return formatDateKey(dateKey, configuredTimezone, {
65952
+ return formatDateKey2(dateKey, configuredTimezone, {
65664
65953
  year: "numeric",
65665
65954
  month: "long",
65666
65955
  day: "numeric"
@@ -65674,8 +65963,8 @@ var KPIsOverviewView = ({
65674
65963
  zonedNow.getMonth(),
65675
65964
  new Date(zonedNow.getFullYear(), zonedNow.getMonth() + 1, 0).getDate()
65676
65965
  );
65677
- const startLabel = formatDateKey(startOfMonthKey, configuredTimezone, { month: "short", day: "numeric" });
65678
- const endLabel = formatDateKey(endOfMonthKey, configuredTimezone, { month: "short", day: "numeric" });
65966
+ const startLabel = formatDateKey2(startOfMonthKey, configuredTimezone, { month: "short", day: "numeric" });
65967
+ const endLabel = formatDateKey2(endOfMonthKey, configuredTimezone, { month: "short", day: "numeric" });
65679
65968
  return `${startLabel} - ${endLabel}, ${zonedNow.getFullYear()}`;
65680
65969
  };
65681
65970
  const isMonthlyMode = activeTab === "leaderboard" && timeRange === "monthly";
@@ -71310,6 +71599,7 @@ var WorkspaceDetailView = ({
71310
71599
  efficiency: monitoringMode === "uptime" ? Number.isFinite(metric.avg_efficiency) ? Number(metric.avg_efficiency) : computedUptimeEfficiency : Number.isFinite(metric.avg_efficiency) ? Number(metric.avg_efficiency) : 0,
71311
71600
  output: metric.total_output || 0,
71312
71601
  cycleTime: metric.avg_cycle_time || 0,
71602
+ idealCycleTime: Number(metric.ideal_cycle_time || 0),
71313
71603
  pph: metric.avg_pph || 0,
71314
71604
  pphThreshold: metric.pph_threshold || 0,
71315
71605
  idealOutput: Number(metric.ideal_output || 0),
@@ -71865,7 +72155,9 @@ var WorkspaceDetailView = ({
71865
72155
  workspace,
71866
72156
  idleTimeReasons: idleTimeChartData,
71867
72157
  efficiencyLegend,
71868
- hourlyCycleTimes: cycleTimeChartData
72158
+ hourlyCycleTimes: cycleTimeChartData,
72159
+ shiftBreaks: shiftConfig?.shifts?.find((shift2) => shift2.shiftId === workspace.shift_id)?.breaks || [],
72160
+ reportTimezone: shiftConfig?.timezone || timezone
71869
72161
  }
71870
72162
  ) }),
71871
72163
  activeTab === "monthly_history" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
@@ -71900,6 +72192,7 @@ var WorkspaceDetailView = ({
71900
72192
  workspaceId,
71901
72193
  workspaceName: formattedWorkspaceName,
71902
72194
  monthlyData,
72195
+ analysisData: analysisMonthlyData,
71903
72196
  selectedMonth,
71904
72197
  selectedYear,
71905
72198
  monitoringMode: workspace?.monitoring_mode,
@@ -71908,7 +72201,10 @@ var WorkspaceDetailView = ({
71908
72201
  selectedShiftId: selectedShift,
71909
72202
  availableShifts: shiftConfig?.shifts?.map((s) => ({ id: s.shiftId, name: s.shiftName })),
71910
72203
  shiftConfig,
71911
- compact: true
72204
+ efficiencyLegend,
72205
+ trendSummary: workspaceMonthlyTrend,
72206
+ compact: true,
72207
+ isAssemblyWorkspace
71912
72208
  }
71913
72209
  )
71914
72210
  ] })
@@ -80123,7 +80419,7 @@ var useOperationsOverviewRefresh = ({
80123
80419
  };
80124
80420
  }, [companyId, enabled, getIsPageActive, isLiveScope, lineIds.length, refreshFromResume, startPolling, stopPolling, supabase]);
80125
80421
  };
80126
- var parseTimeToMinutes3 = (value) => {
80422
+ var parseTimeToMinutes4 = (value) => {
80127
80423
  if (!value) return null;
80128
80424
  const parts = value.split(":");
80129
80425
  if (parts.length < 2) return null;
@@ -80158,8 +80454,8 @@ var classifyShiftBucket = ({
80158
80454
  return "day";
80159
80455
  }
80160
80456
  }
80161
- const startMinutes = parseTimeToMinutes3(startTime);
80162
- const endMinutes = parseTimeToMinutes3(endTime);
80457
+ const startMinutes = parseTimeToMinutes4(startTime);
80458
+ const endMinutes = parseTimeToMinutes4(endTime);
80163
80459
  if (startMinutes !== null) {
80164
80460
  if (startMinutes >= 4 * 60 && startMinutes < 18 * 60) return "day";
80165
80461
  return "night";
@@ -80218,8 +80514,8 @@ var getShiftWindowsForConfig = (shiftConfig, timezone) => {
80218
80514
  ];
80219
80515
  };
80220
80516
  var normalizeShiftWindowMinutes = (startTime, endTime) => {
80221
- const startMinutes = parseTimeToMinutes3(startTime);
80222
- const endMinutesRaw = parseTimeToMinutes3(endTime);
80517
+ const startMinutes = parseTimeToMinutes4(startTime);
80518
+ const endMinutesRaw = parseTimeToMinutes4(endTime);
80223
80519
  if (startMinutes === null || endMinutesRaw === null) {
80224
80520
  return null;
80225
80521
  }
@@ -80385,7 +80681,7 @@ var PlantHeadView = () => {
80385
80681
  startTime: shift.startTime,
80386
80682
  endTime: shift.endTime
80387
80683
  });
80388
- const startMinutes = parseTimeToMinutes3(shift.startTime);
80684
+ const startMinutes = parseTimeToMinutes4(shift.startTime);
80389
80685
  if (bucket === "day" && startMinutes !== null) {
80390
80686
  candidateStarts.push(startMinutes);
80391
80687
  }
@@ -80395,7 +80691,7 @@ var PlantHeadView = () => {
80395
80691
  scopedLineIds.forEach((lineId) => {
80396
80692
  const shiftConfig = shiftConfigMap.get(lineId) || staticShiftConfig;
80397
80693
  getShiftWindowsForConfig(shiftConfig).forEach((shift) => {
80398
- const startMinutes = parseTimeToMinutes3(shift.startTime);
80694
+ const startMinutes = parseTimeToMinutes4(shift.startTime);
80399
80695
  if (startMinutes !== null) {
80400
80696
  candidateStarts.push(startMinutes);
80401
80697
  }
@@ -80486,7 +80782,7 @@ var PlantHeadView = () => {
80486
80782
  startTime: shift.startTime,
80487
80783
  endTime: shift.endTime
80488
80784
  });
80489
- return bucket === "day" ? parseTimeToMinutes3(shift.startTime) : null;
80785
+ return bucket === "day" ? parseTimeToMinutes4(shift.startTime) : null;
80490
80786
  }).filter((value) => value !== null);
80491
80787
  }) : [];
80492
80788
  if (dayStartCandidates.length > 0) {