@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.mjs CHANGED
@@ -1638,6 +1638,7 @@ var DEFAULT_SHIFT_DATA = {
1638
1638
  efficiency: 0,
1639
1639
  output: 0,
1640
1640
  cycleTime: 0,
1641
+ idealCycleTime: 0,
1641
1642
  pph: 0,
1642
1643
  pphThreshold: 0,
1643
1644
  idealOutput: 0,
@@ -4484,6 +4485,7 @@ var dashboardService = {
4484
4485
  avg_efficiency: item.avg_efficiency || 0,
4485
4486
  total_output: item.total_output || 0,
4486
4487
  avg_cycle_time: item.avg_cycle_time || 0,
4488
+ ideal_cycle_time: item.ideal_cycle_time ?? 0,
4487
4489
  ideal_output: item.ideal_output || 0,
4488
4490
  total_day_output: item.total_day_output ?? item.ideal_output ?? 0,
4489
4491
  avg_pph: item.avg_pph || 0,
@@ -17280,7 +17282,7 @@ var useActiveBreaks = (lineIds) => {
17280
17282
  const [isLoading, setIsLoading] = useState(true);
17281
17283
  const [error, setError] = useState(null);
17282
17284
  const supabase = useSupabase();
17283
- const parseTimeToMinutes4 = (timeStr) => {
17285
+ const parseTimeToMinutes5 = (timeStr) => {
17284
17286
  const [hours, minutes] = timeStr.split(":").map(Number);
17285
17287
  return hours * 60 + minutes;
17286
17288
  };
@@ -17289,8 +17291,8 @@ var useActiveBreaks = (lineIds) => {
17289
17291
  return now4.getHours() * 60 + now4.getMinutes();
17290
17292
  };
17291
17293
  const isTimeInBreak = (breakStart, breakEnd, currentMinutes) => {
17292
- const startMinutes = parseTimeToMinutes4(breakStart);
17293
- const endMinutes = parseTimeToMinutes4(breakEnd);
17294
+ const startMinutes = parseTimeToMinutes5(breakStart);
17295
+ const endMinutes = parseTimeToMinutes5(breakEnd);
17294
17296
  if (endMinutes < startMinutes) {
17295
17297
  return currentMinutes >= startMinutes || currentMinutes < endMinutes;
17296
17298
  } else {
@@ -17298,8 +17300,8 @@ var useActiveBreaks = (lineIds) => {
17298
17300
  }
17299
17301
  };
17300
17302
  const calculateBreakProgress = (breakStart, breakEnd, currentMinutes) => {
17301
- const startMinutes = parseTimeToMinutes4(breakStart);
17302
- const endMinutes = parseTimeToMinutes4(breakEnd);
17303
+ const startMinutes = parseTimeToMinutes5(breakStart);
17304
+ const endMinutes = parseTimeToMinutes5(breakEnd);
17303
17305
  let elapsedMinutes = 0;
17304
17306
  let remainingMinutes = 0;
17305
17307
  if (endMinutes < startMinutes) {
@@ -17317,8 +17319,8 @@ var useActiveBreaks = (lineIds) => {
17317
17319
  return { elapsedMinutes, remainingMinutes };
17318
17320
  };
17319
17321
  const isTimeInShift = (startTime, endTime, currentMinutes) => {
17320
- const startMinutes = parseTimeToMinutes4(startTime);
17321
- const endMinutes = parseTimeToMinutes4(endTime);
17322
+ const startMinutes = parseTimeToMinutes5(startTime);
17323
+ const endMinutes = parseTimeToMinutes5(endTime);
17322
17324
  if (endMinutes < startMinutes) {
17323
17325
  return currentMinutes >= startMinutes || currentMinutes < endMinutes;
17324
17326
  } else {
@@ -17378,8 +17380,8 @@ var useActiveBreaks = (lineIds) => {
17378
17380
  const endTime = breakItem.end || breakItem.endTime || "00:00";
17379
17381
  let duration = breakItem.duration || 0;
17380
17382
  if (!duration || duration === 0) {
17381
- const startMinutes = parseTimeToMinutes4(startTime);
17382
- const endMinutes = parseTimeToMinutes4(endTime);
17383
+ const startMinutes = parseTimeToMinutes5(startTime);
17384
+ const endMinutes = parseTimeToMinutes5(endTime);
17383
17385
  duration = endMinutes < startMinutes ? endMinutes + 24 * 60 - startMinutes : endMinutes - startMinutes;
17384
17386
  }
17385
17387
  return {
@@ -17395,8 +17397,8 @@ var useActiveBreaks = (lineIds) => {
17395
17397
  const endTime = breakItem.end || breakItem.endTime || "00:00";
17396
17398
  let duration = breakItem.duration || 0;
17397
17399
  if (!duration || duration === 0) {
17398
- const startMinutes = parseTimeToMinutes4(startTime);
17399
- const endMinutes = parseTimeToMinutes4(endTime);
17400
+ const startMinutes = parseTimeToMinutes5(startTime);
17401
+ const endMinutes = parseTimeToMinutes5(endTime);
17400
17402
  duration = endMinutes < startMinutes ? endMinutes + 24 * 60 - startMinutes : endMinutes - startMinutes;
17401
17403
  }
17402
17404
  return {
@@ -33411,13 +33413,13 @@ var CycleTimeOverTimeChart = ({
33411
33413
  observer.observe(containerRef.current);
33412
33414
  return () => observer.disconnect();
33413
33415
  }, []);
33414
- const parseTimeToMinutes4 = (value) => {
33416
+ const parseTimeToMinutes5 = (value) => {
33415
33417
  const [hours, minutes] = value.split(":").map(Number);
33416
33418
  if (!Number.isFinite(hours) || !Number.isFinite(minutes)) return 0;
33417
33419
  return hours * 60 + minutes;
33418
33420
  };
33419
33421
  const formatHourLabel = (slotIndex) => {
33420
- const baseMinutes = parseTimeToMinutes4(shiftStart);
33422
+ const baseMinutes = parseTimeToMinutes5(shiftStart);
33421
33423
  const absoluteMinutes = baseMinutes + slotIndex * 60;
33422
33424
  const hour24 = Math.floor(absoluteMinutes % (24 * 60) / 60);
33423
33425
  const ampm = hour24 >= 12 ? "PM" : "AM";
@@ -47874,6 +47876,7 @@ var LineMonthlyPdfGenerator = ({
47874
47876
  rangeEnd,
47875
47877
  selectedShiftId,
47876
47878
  availableShifts,
47879
+ lineAssembly = false,
47877
47880
  compact = false,
47878
47881
  className
47879
47882
  }) => {
@@ -48157,8 +48160,8 @@ var LineMonthlyPdfGenerator = ({
48157
48160
  timeZone: "Asia/Kolkata"
48158
48161
  });
48159
48162
  doc.text(dateStr, 25, yPos);
48160
- doc.text(`${shift.total_workspaces - shift.underperforming_workspaces}`, 60, yPos);
48161
- doc.text(`${shift.total_workspaces}`, 95, yPos);
48163
+ doc.text(`${Math.round(shift.output || 0)}`, 60, yPos);
48164
+ doc.text(`${Math.round(shift.idealOutput || 0)}`, 95, yPos);
48162
48165
  doc.text(`${shift.avg_efficiency.toFixed(1)}%`, 135, yPos);
48163
48166
  const statusColor = getEfficiencyColor(shift.avg_efficiency, effectiveLegend);
48164
48167
  if (statusColor === "green") {
@@ -48188,6 +48191,8 @@ var LineMonthlyPdfGenerator = ({
48188
48191
  doc.setTextColor(0, 0, 0);
48189
48192
  }
48190
48193
  const poorestWorkspaces = underperformingWorkspaces[selectedShiftId] || [];
48194
+ 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
+ const showCycleTimePoorestPerformers = !isUptimeMode && poorestWorkspaces.some(isCycleTimeWorkspace);
48191
48196
  if (poorestWorkspaces && poorestWorkspaces.length > 0) {
48192
48197
  doc.addPage();
48193
48198
  doc.setFontSize(14);
@@ -48213,7 +48218,11 @@ var LineMonthlyPdfGenerator = ({
48213
48218
  doc.setFillColor(245, 245, 245);
48214
48219
  doc.roundedRect(20, 45, 170, 8, 1, 1, "F");
48215
48220
  doc.text("Workspace", 25, 50);
48216
- doc.text(isUptimeMode ? "Avg Utilization" : "Avg Efficiency", 120, 50);
48221
+ doc.text(
48222
+ isUptimeMode ? "Avg Utilization" : showCycleTimePoorestPerformers ? "Cycle Time" : "Avg Efficiency",
48223
+ 120,
48224
+ 50
48225
+ );
48217
48226
  doc.text("Last 5 Days", 160, 50);
48218
48227
  doc.setLineWidth(0.2);
48219
48228
  doc.setDrawColor(220, 220, 220);
@@ -48232,7 +48241,16 @@ var LineMonthlyPdfGenerator = ({
48232
48241
  );
48233
48242
  const workspaceName = rawWorkspaceName.length > 30 ? `${rawWorkspaceName.substring(0, 27)}...` : rawWorkspaceName;
48234
48243
  doc.text(workspaceName, 25, yPos2);
48235
- doc.text(`${(workspace.avg_efficiency || 0).toFixed(1)}%`, 120, yPos2);
48244
+ if (isUptimeMode) {
48245
+ doc.text(`${(workspace.avg_efficiency || 0).toFixed(1)}%`, 120, yPos2);
48246
+ } else if (isCycleTimeWorkspace(workspace)) {
48247
+ const actualCycleTime = Number.isFinite(workspace.avg_cycle_time) ? Number(workspace.avg_cycle_time) : null;
48248
+ const targetCycleTime = Number.isFinite(workspace.ideal_cycle_time) ? Number(workspace.ideal_cycle_time) : null;
48249
+ const cycleTimeText = actualCycleTime !== null ? `${actualCycleTime.toFixed(1)}s${targetCycleTime !== null ? ` / ${targetCycleTime.toFixed(1)}s` : ""}` : "-";
48250
+ doc.text(cycleTimeText, 120, yPos2);
48251
+ } else {
48252
+ doc.text(`${(workspace.avg_efficiency || 0).toFixed(1)}%`, 120, yPos2);
48253
+ }
48236
48254
  const squareSize = 3;
48237
48255
  const squareSpacing = 1;
48238
48256
  let squareX = 160;
@@ -48327,12 +48345,279 @@ Underperforming Workspaces: ${lineInfo.metrics.underperforming_workspaces} / ${l
48327
48345
  }
48328
48346
  );
48329
48347
  };
48348
+
48349
+ // src/lib/utils/hourlyTargets.ts
48350
+ var stripSeconds2 = (timeStr) => timeStr ? timeStr.slice(0, 5) : timeStr;
48351
+ var MINUTES_PER_DAY = 24 * 60;
48352
+ var parseTimeToMinutes2 = (timeString) => {
48353
+ const normalized = stripSeconds2(timeString || "");
48354
+ if (!normalized || !/^[0-2]\d:[0-5]\d$/.test(normalized)) return Number.NaN;
48355
+ const [hours, minutes] = normalized.split(":").map(Number);
48356
+ return hours * 60 + minutes;
48357
+ };
48358
+ var normalizeBreaksOnShiftTimeline = (shiftStart, breaks) => {
48359
+ const shiftStartMinutes = parseTimeToMinutes2(shiftStart);
48360
+ if (!Number.isFinite(shiftStartMinutes)) return [];
48361
+ const normalizedBreaks = [];
48362
+ for (const entry of breaks) {
48363
+ const startRaw = parseTimeToMinutes2(entry.startTime);
48364
+ const endRaw = parseTimeToMinutes2(entry.endTime);
48365
+ if (!Number.isFinite(startRaw) || !Number.isFinite(endRaw)) continue;
48366
+ let start = startRaw;
48367
+ let end = endRaw;
48368
+ if (end <= start) {
48369
+ end += 24 * 60;
48370
+ }
48371
+ if (start < shiftStartMinutes) {
48372
+ start += 24 * 60;
48373
+ end += 24 * 60;
48374
+ }
48375
+ const label = entry.remarks?.trim() || "Break";
48376
+ normalizedBreaks.push({ start, end, label });
48377
+ }
48378
+ return normalizedBreaks;
48379
+ };
48380
+ var roundTarget = (value, mode) => {
48381
+ if (!Number.isFinite(value)) return 0;
48382
+ switch (mode) {
48383
+ case "floor":
48384
+ return Math.floor(value);
48385
+ case "ceil":
48386
+ return Math.ceil(value);
48387
+ case "round":
48388
+ default:
48389
+ return Math.round(value);
48390
+ }
48391
+ };
48392
+ var formatDateKey = (date) => {
48393
+ const year = date.getUTCFullYear();
48394
+ const month = `${date.getUTCMonth() + 1}`.padStart(2, "0");
48395
+ const day = `${date.getUTCDate()}`.padStart(2, "0");
48396
+ return `${year}-${month}-${day}`;
48397
+ };
48398
+ var shiftDateKey = (dateKey, deltaDays) => {
48399
+ const [yearPart, monthPart, dayPart] = dateKey.split("-").map(Number);
48400
+ const year = Number.isFinite(yearPart) ? yearPart : 1970;
48401
+ const month = Number.isFinite(monthPart) ? monthPart : 1;
48402
+ const day = Number.isFinite(dayPart) ? dayPart : 1;
48403
+ const date = new Date(Date.UTC(year, month - 1, day));
48404
+ date.setUTCDate(date.getUTCDate() + deltaDays);
48405
+ return formatDateKey(date);
48406
+ };
48407
+ var getZonedNowSnapshot = (timeZone, now4) => {
48408
+ const formatter = new Intl.DateTimeFormat("en-US", {
48409
+ timeZone,
48410
+ year: "numeric",
48411
+ month: "2-digit",
48412
+ day: "2-digit",
48413
+ hour: "2-digit",
48414
+ minute: "2-digit",
48415
+ hourCycle: "h23"
48416
+ });
48417
+ const parts = formatter.formatToParts(now4).reduce((acc, part) => {
48418
+ if (part.type !== "literal") {
48419
+ acc[part.type] = part.value;
48420
+ }
48421
+ return acc;
48422
+ }, {});
48423
+ const year = Number(parts.year);
48424
+ const month = Number(parts.month);
48425
+ const day = Number(parts.day);
48426
+ const hour = Number(parts.hour);
48427
+ const minute = Number(parts.minute);
48428
+ return {
48429
+ dateKey: `${String(year).padStart(4, "0")}-${String(month).padStart(2, "0")}-${String(day).padStart(2, "0")}`,
48430
+ minutesOfDay: (Number.isFinite(hour) ? hour : 0) * 60 + (Number.isFinite(minute) ? minute : 0)
48431
+ };
48432
+ };
48433
+ var getDateKeyInTimeZone = (timeZone, now4 = /* @__PURE__ */ new Date()) => getZonedNowSnapshot(timeZone, now4).dateKey;
48434
+ var buildHourlyIntervals = ({
48435
+ shiftStart,
48436
+ shiftEnd,
48437
+ bucketMinutes = 60,
48438
+ fallbackHours = 11
48439
+ }) => {
48440
+ const startMinutes = parseTimeToMinutes2(shiftStart);
48441
+ if (!Number.isFinite(startMinutes)) return [];
48442
+ const bucket = Number.isFinite(bucketMinutes) && bucketMinutes > 0 ? Math.floor(bucketMinutes) : 60;
48443
+ let totalMinutes;
48444
+ const endRaw = shiftEnd ? parseTimeToMinutes2(shiftEnd) : Number.NaN;
48445
+ if (!Number.isFinite(endRaw)) {
48446
+ totalMinutes = Math.max(0, Math.round(fallbackHours * 60));
48447
+ } else {
48448
+ let endMinutes = endRaw;
48449
+ if (endMinutes <= startMinutes) {
48450
+ endMinutes += 24 * 60;
48451
+ }
48452
+ totalMinutes = endMinutes - startMinutes;
48453
+ }
48454
+ if (!Number.isFinite(totalMinutes) || totalMinutes <= 0) return [];
48455
+ const count = Math.ceil(totalMinutes / bucket);
48456
+ const shiftEndMinutes = startMinutes + totalMinutes;
48457
+ const intervals = [];
48458
+ for (let i = 0; i < count; i += 1) {
48459
+ const start = startMinutes + i * bucket;
48460
+ const end = Math.min(start + bucket, shiftEndMinutes);
48461
+ const minutes = Math.max(0, end - start);
48462
+ if (minutes <= 0) continue;
48463
+ intervals.push({ start, end, minutes });
48464
+ }
48465
+ return intervals;
48466
+ };
48467
+ var computeBreakMinutesByInterval = ({
48468
+ intervals,
48469
+ shiftStart,
48470
+ breaks
48471
+ }) => {
48472
+ if (!intervals.length || !breaks.length) return intervals.map(() => 0);
48473
+ const normalizedBreaks = normalizeBreaksOnShiftTimeline(shiftStart, breaks);
48474
+ return intervals.map((interval) => {
48475
+ if (!normalizedBreaks.length) return 0;
48476
+ let total = 0;
48477
+ for (const brk of normalizedBreaks) {
48478
+ const overlap = Math.max(0, Math.min(interval.end, brk.end) - Math.max(interval.start, brk.start));
48479
+ total += overlap;
48480
+ if (total >= interval.minutes) return interval.minutes;
48481
+ }
48482
+ return Math.min(interval.minutes, total);
48483
+ });
48484
+ };
48485
+ var computeBreakRemarksByInterval = ({
48486
+ intervals,
48487
+ shiftStart,
48488
+ breaks
48489
+ }) => {
48490
+ if (!intervals.length || !breaks.length) return intervals.map(() => "");
48491
+ const normalizedBreaks = normalizeBreaksOnShiftTimeline(shiftStart, breaks);
48492
+ return intervals.map((interval) => {
48493
+ 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);
48494
+ return labels.join(", ");
48495
+ });
48496
+ };
48497
+ var computeEffectiveTargets = ({
48498
+ intervals,
48499
+ breakMinutes,
48500
+ pphThreshold,
48501
+ rounding = "round"
48502
+ }) => {
48503
+ return intervals.map((interval, idx) => {
48504
+ const intervalMinutes = Number(interval?.minutes) || 0;
48505
+ const breakMins = Number(breakMinutes?.[idx]) || 0;
48506
+ const plannedWorkMinutes = Math.max(0, intervalMinutes - breakMins);
48507
+ if (!Number.isFinite(pphThreshold) || pphThreshold <= 0) return 0;
48508
+ if (plannedWorkMinutes <= 0) return 0;
48509
+ return roundTarget(pphThreshold * plannedWorkMinutes / 60, rounding);
48510
+ });
48511
+ };
48512
+ var buildHourlyTargetPlan = ({
48513
+ shiftStart,
48514
+ shiftEnd,
48515
+ breaks = [],
48516
+ pphThreshold,
48517
+ bucketMinutes = 60,
48518
+ fallbackHours = 11,
48519
+ rounding = "round"
48520
+ }) => {
48521
+ const intervals = buildHourlyIntervals({
48522
+ shiftStart,
48523
+ shiftEnd,
48524
+ bucketMinutes,
48525
+ fallbackHours
48526
+ });
48527
+ const breakMinutes = computeBreakMinutesByInterval({
48528
+ intervals,
48529
+ shiftStart,
48530
+ breaks
48531
+ });
48532
+ const breakRemarks = computeBreakRemarksByInterval({
48533
+ intervals,
48534
+ shiftStart,
48535
+ breaks
48536
+ });
48537
+ const productiveMinutes = intervals.map((interval, idx) => Math.max(0, (Number(interval?.minutes) || 0) - (Number(breakMinutes[idx]) || 0)));
48538
+ const targets = computeEffectiveTargets({
48539
+ intervals,
48540
+ breakMinutes,
48541
+ pphThreshold,
48542
+ rounding
48543
+ });
48544
+ return {
48545
+ intervals,
48546
+ breakMinutes,
48547
+ breakRemarks,
48548
+ productiveMinutes,
48549
+ targets
48550
+ };
48551
+ };
48552
+ var isHourlyIntervalComplete = ({
48553
+ reportDate,
48554
+ shiftStart,
48555
+ shiftEnd,
48556
+ interval,
48557
+ timeZone = "Asia/Kolkata",
48558
+ now: now4 = /* @__PURE__ */ new Date()
48559
+ }) => {
48560
+ if (!reportDate) return true;
48561
+ const snapshot = getZonedNowSnapshot(timeZone, now4);
48562
+ const shiftStartMinutes = parseTimeToMinutes2(shiftStart);
48563
+ const shiftEndMinutes = shiftEnd ? parseTimeToMinutes2(shiftEnd) : Number.NaN;
48564
+ const wrapsMidnight = Number.isFinite(shiftStartMinutes) && Number.isFinite(shiftEndMinutes) && shiftEndMinutes <= shiftStartMinutes;
48565
+ if (reportDate === snapshot.dateKey) {
48566
+ return interval.end <= snapshot.minutesOfDay;
48567
+ }
48568
+ if (wrapsMidnight && reportDate === shiftDateKey(snapshot.dateKey, -1)) {
48569
+ return interval.end <= snapshot.minutesOfDay + MINUTES_PER_DAY;
48570
+ }
48571
+ return reportDate < snapshot.dateKey;
48572
+ };
48573
+ var isShiftInProgressForReportDate = ({
48574
+ reportDate,
48575
+ shiftStart,
48576
+ shiftEnd,
48577
+ timeZone = "Asia/Kolkata",
48578
+ now: now4 = /* @__PURE__ */ new Date()
48579
+ }) => {
48580
+ if (!reportDate || !shiftStart || !shiftEnd) return false;
48581
+ const shiftStartMinutes = parseTimeToMinutes2(shiftStart);
48582
+ const shiftEndMinutesRaw = parseTimeToMinutes2(shiftEnd);
48583
+ if (!Number.isFinite(shiftStartMinutes) || !Number.isFinite(shiftEndMinutesRaw)) {
48584
+ return false;
48585
+ }
48586
+ let shiftEndMinutes = shiftEndMinutesRaw;
48587
+ const wrapsMidnight = shiftEndMinutes <= shiftStartMinutes;
48588
+ if (wrapsMidnight) {
48589
+ shiftEndMinutes += MINUTES_PER_DAY;
48590
+ }
48591
+ const snapshot = getZonedNowSnapshot(timeZone, now4);
48592
+ let currentMinutes = null;
48593
+ if (reportDate === snapshot.dateKey) {
48594
+ currentMinutes = snapshot.minutesOfDay;
48595
+ } else if (wrapsMidnight && reportDate === shiftDateKey(snapshot.dateKey, -1)) {
48596
+ currentMinutes = snapshot.minutesOfDay + MINUTES_PER_DAY;
48597
+ }
48598
+ if (currentMinutes === null) {
48599
+ return false;
48600
+ }
48601
+ return shiftStartMinutes <= currentMinutes && currentMinutes < shiftEndMinutes;
48602
+ };
48603
+ var formatOperationalDateKey = (dateKey, options) => {
48604
+ const [yearPart, monthPart, dayPart] = dateKey.split("-").map(Number);
48605
+ const year = Number.isFinite(yearPart) ? yearPart : 1970;
48606
+ const month = Number.isFinite(monthPart) ? monthPart : 1;
48607
+ const day = Number.isFinite(dayPart) ? dayPart : 1;
48608
+ return new Date(Date.UTC(year, month - 1, day, 12)).toLocaleDateString("en-IN", {
48609
+ ...options,
48610
+ timeZone: "UTC"
48611
+ });
48612
+ };
48330
48613
  var LinePdfGenerator = ({
48331
48614
  lineInfo,
48332
48615
  workspaceData,
48333
48616
  issueResolutionSummary,
48334
48617
  shiftName,
48335
- className
48618
+ className,
48619
+ shiftBreaks = [],
48620
+ reportTimezone = "Asia/Kolkata"
48336
48621
  }) => {
48337
48622
  const [isGenerating, setIsGenerating] = useState(false);
48338
48623
  const formatResolutionDuration2 = (seconds) => {
@@ -48359,7 +48644,7 @@ var LinePdfGenerator = ({
48359
48644
  doc.setFontSize(9);
48360
48645
  doc.setFont("helvetica", "normal");
48361
48646
  doc.setTextColor(100, 100, 100);
48362
- const generatedText = `Generated on ${(/* @__PURE__ */ new Date()).toLocaleString("en-IN", { timeZone: "Asia/Kolkata" })}`;
48647
+ const generatedText = `Generated on ${(/* @__PURE__ */ new Date()).toLocaleString("en-IN", { timeZone: reportTimezone })}`;
48363
48648
  const generatedTextWidth = doc.getStringUnitWidth(generatedText) * 9 / doc.internal.scaleFactor;
48364
48649
  doc.text(generatedText, doc.internal.pageSize.width - 20 - generatedTextWidth, 15);
48365
48650
  doc.setDrawColor(200, 200, 200);
@@ -48377,11 +48662,10 @@ var LinePdfGenerator = ({
48377
48662
  const isUptimeMode = lineInfo.monitoring_mode === "uptime";
48378
48663
  const rawShiftType = shiftName || (lineInfo.shift_id === 0 ? "Day" : lineInfo.shift_id === 1 ? "Night" : `Shift ${lineInfo.shift_id}`);
48379
48664
  const shiftType = rawShiftType.toLowerCase().includes("shift") ? rawShiftType : `${rawShiftType} Shift`;
48380
- const date = new Date(lineInfo.date).toLocaleDateString("en-IN", {
48665
+ const date = formatOperationalDateKey(lineInfo.date, {
48381
48666
  weekday: "long",
48382
48667
  day: "numeric",
48383
- month: "long",
48384
- timeZone: "Asia/Kolkata"
48668
+ month: "long"
48385
48669
  });
48386
48670
  const shiftStartTime = lineInfo.metrics.shift_start ? (/* @__PURE__ */ new Date(`2000-01-01 ${lineInfo.metrics.shift_start}`)).toLocaleTimeString("en-IN", {
48387
48671
  hour: "2-digit",
@@ -48389,24 +48673,25 @@ var LinePdfGenerator = ({
48389
48673
  hour12: true,
48390
48674
  timeZone: "Asia/Kolkata"
48391
48675
  }) : "N/A";
48392
- const isToday2 = new Date(lineInfo.date).toDateString() === (/* @__PURE__ */ new Date()).toDateString();
48393
- let reportEndTime;
48394
- if (isToday2) {
48395
- reportEndTime = (/* @__PURE__ */ new Date()).toLocaleTimeString("en-IN", {
48396
- hour: "2-digit",
48397
- minute: "2-digit",
48398
- timeZone: "Asia/Kolkata"
48399
- });
48400
- } else {
48401
- reportEndTime = lineInfo.metrics.shift_end ? (/* @__PURE__ */ new Date(`2000-01-01 ${lineInfo.metrics.shift_end}`)).toLocaleTimeString("en-IN", {
48402
- hour: "2-digit",
48403
- minute: "2-digit",
48404
- hour12: true,
48405
- timeZone: "Asia/Kolkata"
48406
- }) : "N/A";
48407
- }
48676
+ const currentTime = (/* @__PURE__ */ new Date()).toLocaleTimeString("en-IN", {
48677
+ hour: "2-digit",
48678
+ minute: "2-digit",
48679
+ timeZone: reportTimezone
48680
+ });
48681
+ const reportEndTime = isShiftInProgressForReportDate({
48682
+ reportDate: lineInfo.date,
48683
+ shiftStart: lineInfo.metrics.shift_start || "",
48684
+ shiftEnd: lineInfo.metrics.shift_end,
48685
+ timeZone: reportTimezone
48686
+ }) ? currentTime : lineInfo.metrics.shift_end ? (/* @__PURE__ */ new Date(`2000-01-01 ${lineInfo.metrics.shift_end}`)).toLocaleTimeString("en-IN", {
48687
+ hour: "2-digit",
48688
+ minute: "2-digit",
48689
+ hour12: true,
48690
+ timeZone: "Asia/Kolkata"
48691
+ }) : "N/A";
48408
48692
  if (isUptimeMode) {
48409
48693
  const configuredTimezone = "Asia/Kolkata";
48694
+ const effectiveUptimeTimezone = reportTimezone || configuredTimezone;
48410
48695
  const lineShiftStart = lineInfo.metrics.shift_start || "06:00";
48411
48696
  const lineShiftEnd = lineInfo.metrics.shift_end || "14:00";
48412
48697
  const shiftMinutes = getShiftDurationMinutes(lineShiftStart, lineShiftEnd) || 0;
@@ -48420,7 +48705,7 @@ var LinePdfGenerator = ({
48420
48705
  shiftStart,
48421
48706
  shiftEnd,
48422
48707
  shiftDate,
48423
- timezone: configuredTimezone
48708
+ timezone: effectiveUptimeTimezone
48424
48709
  });
48425
48710
  let activeMinutes = uptimeSeries.activeMinutes;
48426
48711
  let idleMinutes = uptimeSeries.idleMinutes;
@@ -48501,7 +48786,7 @@ var LinePdfGenerator = ({
48501
48786
  shiftStart: lineShiftStart,
48502
48787
  shiftEnd: lineShiftEnd,
48503
48788
  shiftDate: lineInfo.date,
48504
- timezone: configuredTimezone
48789
+ timezone: effectiveUptimeTimezone
48505
48790
  });
48506
48791
  hourlyData = buildHourlyFromSeries(lineUptimeSeries);
48507
48792
  }
@@ -48609,13 +48894,13 @@ var LinePdfGenerator = ({
48609
48894
  doc.setFontSize(contentFontSize);
48610
48895
  doc.setFont("helvetica", "normal");
48611
48896
  let yPos2 = headerBottomY2 + 5.5;
48612
- const now5 = /* @__PURE__ */ new Date();
48613
- const currentTimeIST2 = new Date(now5.toLocaleString("en-US", { timeZone: configuredTimezone }));
48614
- const [sYear2, sMonth2, sDay2] = lineInfo.date.split("-").map(Number);
48615
- const [sStartH2, sStartM2] = (lineShiftStart || "06:00").split(":").map(Number);
48616
- const shiftStartBase2 = new Date(sYear2, sMonth2 - 1, sDay2, sStartH2, sStartM2 || 0);
48897
+ const now4 = /* @__PURE__ */ new Date();
48898
+ const currentTimeIST = new Date(now4.toLocaleString("en-US", { timeZone: configuredTimezone }));
48899
+ const [sYear, sMonth, sDay] = lineInfo.date.split("-").map(Number);
48900
+ const [sStartH, sStartM] = (lineShiftStart || "06:00").split(":").map(Number);
48901
+ const shiftStartBase = new Date(sYear, sMonth - 1, sDay, sStartH, sStartM || 0);
48617
48902
  hourlyData.forEach((entry, index) => {
48618
- const bucketStartTime = new Date(shiftStartBase2);
48903
+ const bucketStartTime = new Date(shiftStartBase);
48619
48904
  bucketStartTime.setHours(bucketStartTime.getHours() + index);
48620
48905
  const bucketEndTime = new Date(bucketStartTime);
48621
48906
  bucketEndTime.setHours(bucketEndTime.getHours() + 1);
@@ -48626,7 +48911,7 @@ var LinePdfGenerator = ({
48626
48911
  hour: "numeric",
48627
48912
  hour12: true
48628
48913
  })}`;
48629
- const dataCollected = bucketEndTime.getTime() <= currentTimeIST2.getTime();
48914
+ const dataCollected = bucketEndTime.getTime() <= currentTimeIST.getTime();
48630
48915
  if (index < totalRows2 - 1) {
48631
48916
  const rowBottomY = headerBottomY2 + (index + 1) * rowHeight;
48632
48917
  doc.setDrawColor(200, 200, 200);
@@ -48637,11 +48922,10 @@ var LinePdfGenerator = ({
48637
48922
  doc.text(utilizationStr, 147, yPos2);
48638
48923
  yPos2 += rowHeight;
48639
48924
  });
48640
- const fileDate2 = new Date(lineInfo.date).toLocaleDateString("en-IN", {
48925
+ const fileDate2 = formatOperationalDateKey(lineInfo.date, {
48641
48926
  day: "2-digit",
48642
48927
  month: "short",
48643
- year: "numeric",
48644
- timeZone: "Asia/Kolkata"
48928
+ year: "numeric"
48645
48929
  }).replace(/ /g, "_");
48646
48930
  const fileShift2 = shiftType.replace(/ /g, "_");
48647
48931
  const fileName2 = `${lineInfo.line_name}_${fileDate2}_${fileShift2}.pdf`;
@@ -48694,66 +48978,32 @@ var LinePdfGenerator = ({
48694
48978
  doc.setLineWidth(0.8);
48695
48979
  doc.line(20, 123, 190, 123);
48696
48980
  const hourlyOverviewStartY = 128;
48697
- const parseTimeToMinutes4 = (timeStr) => {
48698
- const [hours, minutes] = timeStr.split(":");
48699
- const hour = parseInt(hours, 10);
48700
- const minute = parseInt(minutes || "0", 10);
48701
- if (Number.isNaN(hour) || Number.isNaN(minute)) {
48702
- return NaN;
48703
- }
48704
- return (hour * 60 + minute) % (24 * 60);
48705
- };
48706
48981
  const formatMinutesLabel = (totalMinutes) => {
48707
48982
  const normalized = (totalMinutes % (24 * 60) + 24 * 60) % (24 * 60);
48708
48983
  const hour = Math.floor(normalized / 60);
48709
48984
  const minute = normalized % 60;
48710
- const time2 = /* @__PURE__ */ new Date();
48711
- time2.setHours(hour);
48712
- time2.setMinutes(minute);
48713
- time2.setSeconds(0);
48714
- time2.setMilliseconds(0);
48985
+ const time2 = new Date(Date.UTC(2e3, 0, 1, hour, minute));
48715
48986
  return time2.toLocaleTimeString("en-IN", {
48716
48987
  hour: "2-digit",
48717
48988
  minute: "2-digit",
48718
48989
  hour12: true,
48719
- timeZone: "Asia/Kolkata"
48720
- });
48721
- };
48722
- const buildRange = (startMinutes, minutes) => {
48723
- const endMinutes = startMinutes + minutes;
48724
- return {
48725
- label: `${formatMinutesLabel(startMinutes)} - ${formatMinutesLabel(endMinutes)}`,
48726
- minutes
48727
- };
48728
- };
48729
- const getHourlyTimeRanges = (startTimeStr, endTimeStr) => {
48730
- const startMinutes = parseTimeToMinutes4(startTimeStr);
48731
- if (Number.isNaN(startMinutes)) {
48732
- return [];
48733
- }
48734
- if (!endTimeStr) {
48735
- const defaultHours = 11;
48736
- return Array.from({ length: defaultHours }, (_, i) => buildRange(startMinutes + i * 60, 60));
48737
- }
48738
- const endMinutes = parseTimeToMinutes4(endTimeStr);
48739
- if (Number.isNaN(endMinutes)) {
48740
- const fallbackHours = 11;
48741
- return Array.from({ length: fallbackHours }, (_, i) => buildRange(startMinutes + i * 60, 60));
48742
- }
48743
- let durationMinutes = endMinutes - startMinutes;
48744
- if (durationMinutes <= 0) {
48745
- durationMinutes += 24 * 60;
48746
- }
48747
- const rangeCount = Math.max(1, Math.ceil(durationMinutes / 60));
48748
- return Array.from({ length: rangeCount }, (_, i) => {
48749
- const remainingMinutes = durationMinutes - i * 60;
48750
- const rangeMinutes = remainingMinutes >= 60 ? 60 : remainingMinutes;
48751
- return buildRange(startMinutes + i * 60, rangeMinutes);
48990
+ timeZone: "UTC"
48752
48991
  });
48753
48992
  };
48754
- const hourlyTimeRanges = lineInfo.metrics.shift_start ? getHourlyTimeRanges(lineInfo.metrics.shift_start, lineInfo.metrics.shift_end) : [];
48993
+ const hourlyTimeRanges = buildHourlyIntervals({
48994
+ shiftStart: lineInfo.metrics.shift_start || "06:00",
48995
+ shiftEnd: lineInfo.metrics.shift_end,
48996
+ fallbackHours: 11
48997
+ });
48998
+ const targetPlan = buildHourlyTargetPlan({
48999
+ shiftStart: lineInfo.metrics.shift_start || "06:00",
49000
+ shiftEnd: lineInfo.metrics.shift_end,
49001
+ breaks: shiftBreaks,
49002
+ pphThreshold: Number(lineInfo.metrics.threshold_pph ?? 0),
49003
+ fallbackHours: Math.max(hourlyTimeRanges.length, 1),
49004
+ rounding: "floor"
49005
+ });
48755
49006
  const shiftDuration = hourlyTimeRanges.length || 11;
48756
- const targetOutputPerHour = Math.round(lineInfo.metrics.threshold_pph ?? 0);
48757
49007
  let hourlyActualOutput = [];
48758
49008
  if (lineInfo.metrics.output_hourly && Object.keys(lineInfo.metrics.output_hourly).length > 0) {
48759
49009
  const [startHourStr, startMinuteStr] = (lineInfo.metrics.shift_start || "6:00").split(":");
@@ -48939,29 +49189,29 @@ var LinePdfGenerator = ({
48939
49189
  doc.text("Remarks", 160, tableHeaderY);
48940
49190
  doc.setFont("helvetica", "normal");
48941
49191
  let yPos = tableStartY;
48942
- const now4 = /* @__PURE__ */ new Date();
48943
- const currentTimeIST = new Date(now4.toLocaleString("en-US", { timeZone: "Asia/Kolkata" }));
48944
- const [sYear, sMonth, sDay] = lineInfo.date.split("-").map(Number);
48945
- const [sStartH, sStartM] = (lineInfo.metrics.shift_start || "06:00").split(":").map(Number);
48946
- const shiftStartBase = new Date(sYear, sMonth - 1, sDay, sStartH, sStartM || 0);
48947
49192
  hourlyTimeRanges.forEach((timeRange, index) => {
48948
49193
  const actualOutput = hourlyActualOutput[index] || 0;
48949
- const bucketStartTime = new Date(shiftStartBase);
48950
- bucketStartTime.setHours(bucketStartTime.getHours() + index);
48951
- const bucketEndTime = new Date(bucketStartTime.getTime() + timeRange.minutes * 60 * 1e3);
48952
- const dataCollected = bucketEndTime.getTime() <= currentTimeIST.getTime();
49194
+ const dataCollected = isHourlyIntervalComplete({
49195
+ reportDate: lineInfo.date,
49196
+ shiftStart: lineInfo.metrics.shift_start || "06:00",
49197
+ shiftEnd: lineInfo.metrics.shift_end,
49198
+ interval: timeRange,
49199
+ timeZone: reportTimezone
49200
+ });
48953
49201
  const outputStr = dataCollected ? actualOutput.toString() : "TBD";
48954
49202
  if (index < totalRows - 1) {
48955
49203
  const rowBottomY = headerBottomY + (index + 1) * rowSpacing;
48956
49204
  doc.setDrawColor(200, 200, 200);
48957
49205
  doc.line(20, rowBottomY, 190, rowBottomY);
48958
49206
  }
48959
- const rangeMinutes = timeRange.minutes || 60;
48960
- const targetForRange = targetOutputPerHour * (rangeMinutes / 60);
48961
- const targetStr = rangeMinutes === 60 ? targetOutputPerHour.toString() : targetForRange.toFixed(1).replace(/\.0$/, "");
48962
- doc.text(timeRange.label, 25, yPos);
49207
+ const targetForRange = targetPlan.targets[index] ?? 0;
49208
+ const targetStr = targetForRange.toString();
49209
+ const remarkText = targetPlan.breakRemarks[index] || "";
49210
+ doc.text(`${formatMinutesLabel(timeRange.start)} - ${formatMinutesLabel(timeRange.end)}`, 25, yPos);
48963
49211
  doc.text(outputStr, 75, yPos);
48964
49212
  doc.text(targetStr, 105, yPos);
49213
+ const remarkDisplay = remarkText ? doc.splitTextToSize(remarkText, 26)[0] : "";
49214
+ doc.text(remarkDisplay, 160, yPos);
48965
49215
  if (!dataCollected) {
48966
49216
  doc.setTextColor(100, 100, 100);
48967
49217
  doc.text("-", 135, yPos);
@@ -48977,11 +49227,10 @@ var LinePdfGenerator = ({
48977
49227
  doc.setTextColor(0, 0, 0);
48978
49228
  yPos += rowSpacing;
48979
49229
  });
48980
- const fileDate = new Date(lineInfo.date).toLocaleDateString("en-IN", {
49230
+ const fileDate = formatOperationalDateKey(lineInfo.date, {
48981
49231
  day: "2-digit",
48982
49232
  month: "short",
48983
- year: "numeric",
48984
- timeZone: "Asia/Kolkata"
49233
+ year: "numeric"
48985
49234
  }).replace(/ /g, "_");
48986
49235
  const fileShift = shiftType.replace(/ /g, "_");
48987
49236
  const fileName = `${lineInfo.line_name}_${fileDate}_${fileShift}.pdf`;
@@ -49909,6 +50158,13 @@ var WorkspaceMonthlyHistory = ({
49909
50158
  }, [analysisMonthlyData, selectedShiftId, isUptimeMode, shiftWorkSeconds]);
49910
50159
  const efficiencyDelta = trendSummary?.avg_efficiency?.delta_pp ?? 0;
49911
50160
  const efficiencyImproved = efficiencyDelta >= 0;
50161
+ const assemblyRangeCycleTime = useMemo(() => {
50162
+ const trendCycleTime = Number(trendSummary?.avg_cycle_time?.current);
50163
+ if (Number.isFinite(trendCycleTime) && trendCycleTime > 0) {
50164
+ return Math.round(trendCycleTime);
50165
+ }
50166
+ return metrics2?.avgCycleTime ?? 0;
50167
+ }, [trendSummary?.avg_cycle_time?.current, metrics2?.avgCycleTime]);
49912
50168
  const cycleDeltaRaw = trendSummary?.avg_cycle_time?.delta_seconds ?? 0;
49913
50169
  const cyclePrev = trendSummary?.avg_cycle_time?.previous ?? 0;
49914
50170
  const cycleDelta = cyclePrev ? cycleDeltaRaw / cyclePrev * 100 : 0;
@@ -50094,7 +50350,7 @@ var WorkspaceMonthlyHistory = ({
50094
50350
  /* @__PURE__ */ jsx("div", { className: "text-sm font-semibold text-gray-600 mb-1", children: "Avg Cycle Time" }),
50095
50351
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 flex-nowrap", children: [
50096
50352
  /* @__PURE__ */ jsxs("div", { className: "text-2xl font-bold text-gray-900", children: [
50097
- metrics2?.avgCycleTime ?? 0,
50353
+ assemblyRangeCycleTime,
50098
50354
  "s"
50099
50355
  ] }),
50100
50356
  /* @__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: [
@@ -50430,7 +50686,25 @@ var WorkspaceWhatsAppShareButton = ({
50430
50686
  }
50431
50687
  );
50432
50688
  };
50433
- var WorkspacePdfGenerator = ({ workspace, className, idleTimeReasons, efficiencyLegend, hourlyCycleTimes }) => {
50689
+ var formatOperationalDateKey2 = (dateKey, options) => {
50690
+ const [yearPart, monthPart, dayPart] = dateKey.split("-").map(Number);
50691
+ const year = Number.isFinite(yearPart) ? yearPart : 1970;
50692
+ const month = Number.isFinite(monthPart) ? monthPart : 1;
50693
+ const day = Number.isFinite(dayPart) ? dayPart : 1;
50694
+ return new Date(Date.UTC(year, month - 1, day, 12)).toLocaleDateString("en-IN", {
50695
+ ...options,
50696
+ timeZone: "UTC"
50697
+ });
50698
+ };
50699
+ var WorkspacePdfGenerator = ({
50700
+ workspace,
50701
+ className,
50702
+ idleTimeReasons,
50703
+ efficiencyLegend,
50704
+ hourlyCycleTimes,
50705
+ shiftBreaks = [],
50706
+ reportTimezone = "Asia/Kolkata"
50707
+ }) => {
50434
50708
  const [isGenerating, setIsGenerating] = useState(false);
50435
50709
  const entityConfig = useEntityConfig();
50436
50710
  const effectiveLegend = efficiencyLegend || DEFAULT_EFFICIENCY_LEGEND;
@@ -50460,7 +50734,7 @@ var WorkspacePdfGenerator = ({ workspace, className, idleTimeReasons, efficiency
50460
50734
  doc.setFontSize(9);
50461
50735
  doc.setFont("helvetica", "normal");
50462
50736
  doc.setTextColor(100, 100, 100);
50463
- const generatedText = `Generated on ${(/* @__PURE__ */ new Date()).toLocaleString("en-IN", { timeZone: "Asia/Kolkata" })}`;
50737
+ const generatedText = `Generated on ${(/* @__PURE__ */ new Date()).toLocaleString("en-IN", { timeZone: reportTimezone })}`;
50464
50738
  const generatedTextWidth = doc.getStringUnitWidth(generatedText) * 9 / doc.internal.scaleFactor;
50465
50739
  doc.text(generatedText, doc.internal.pageSize.width - 20 - generatedTextWidth, 15);
50466
50740
  doc.setDrawColor(200, 200, 200);
@@ -50479,11 +50753,10 @@ var WorkspacePdfGenerator = ({ workspace, className, idleTimeReasons, efficiency
50479
50753
  doc.setFontSize(13);
50480
50754
  doc.setFont("helvetica", "normal");
50481
50755
  doc.setTextColor(60, 60, 60);
50482
- const date = new Date(workspace.date).toLocaleDateString("en-IN", {
50756
+ const date = formatOperationalDateKey2(workspace.date, {
50483
50757
  weekday: "long",
50484
50758
  day: "numeric",
50485
- month: "long",
50486
- timeZone: "Asia/Kolkata"
50759
+ month: "long"
50487
50760
  });
50488
50761
  const rawShiftType = workspace.shift_type || (workspace.shift_id === 0 ? "Day" : workspace.shift_id === 1 ? "Night" : `Shift ${workspace.shift_id}`);
50489
50762
  const shiftType = rawShiftType.toLowerCase().includes("shift") ? rawShiftType : `${rawShiftType} Shift`;
@@ -50492,7 +50765,7 @@ var WorkspacePdfGenerator = ({ workspace, className, idleTimeReasons, efficiency
50492
50765
  const currentTime = (/* @__PURE__ */ new Date()).toLocaleTimeString("en-IN", {
50493
50766
  hour: "2-digit",
50494
50767
  minute: "2-digit",
50495
- timeZone: "Asia/Kolkata"
50768
+ timeZone: reportTimezone
50496
50769
  });
50497
50770
  const shiftStartTime = (/* @__PURE__ */ new Date(`2000-01-01 ${workspace.shift_start}`)).toLocaleTimeString("en-IN", {
50498
50771
  hour: "2-digit",
@@ -50504,29 +50777,12 @@ var WorkspacePdfGenerator = ({ workspace, className, idleTimeReasons, efficiency
50504
50777
  minute: "2-digit",
50505
50778
  hour12: true
50506
50779
  });
50507
- const parseTimeToMinutes4 = (timeValue) => {
50508
- const [hourPart, minutePart] = timeValue.split(":").map(Number);
50509
- const hour = Number.isFinite(hourPart) ? hourPart : 0;
50510
- const minute = Number.isFinite(minutePart) ? minutePart : 0;
50511
- return hour * 60 + minute;
50512
- };
50513
- const toShiftUtcMs = (dateKey, timeValue) => {
50514
- const [yearPart, monthPart, dayPart] = dateKey.split("-").map(Number);
50515
- const year = Number.isFinite(yearPart) ? yearPart : 1970;
50516
- const month = Number.isFinite(monthPart) ? monthPart : 1;
50517
- const day = Number.isFinite(dayPart) ? dayPart : 1;
50518
- const [hourPart, minutePart] = timeValue.split(":").map(Number);
50519
- const hour = Number.isFinite(hourPart) ? hourPart : 0;
50520
- const minute = Number.isFinite(minutePart) ? minutePart : 0;
50521
- const IST_OFFSET_MINUTES = 330;
50522
- return Date.UTC(year, month - 1, day, hour, minute) - IST_OFFSET_MINUTES * 60 * 1e3;
50523
- };
50524
- const shiftStartMinutes = parseTimeToMinutes4(workspace.shift_start);
50525
- const shiftEndMinutes = parseTimeToMinutes4(workspace.shift_end);
50526
- const wrapsMidnight = shiftEndMinutes <= shiftStartMinutes;
50527
- const shiftStartUtcMs = toShiftUtcMs(workspace.date, workspace.shift_start);
50528
- const shiftEndUtcMs = toShiftUtcMs(workspace.date, workspace.shift_end) + (wrapsMidnight ? 24 * 60 * 60 * 1e3 : 0);
50529
- const isShiftInProgress = Date.now() >= shiftStartUtcMs && Date.now() < shiftEndUtcMs;
50780
+ const isShiftInProgress = isShiftInProgressForReportDate({
50781
+ reportDate: workspace.date,
50782
+ shiftStart: workspace.shift_start,
50783
+ shiftEnd: workspace.shift_end,
50784
+ timeZone: reportTimezone
50785
+ });
50530
50786
  const reportPeriodEndTime = isShiftInProgress ? currentTime : shiftEndTime;
50531
50787
  doc.setFontSize(12);
50532
50788
  doc.setTextColor(80, 80, 80);
@@ -50632,7 +50888,7 @@ var WorkspacePdfGenerator = ({ workspace, className, idleTimeReasons, efficiency
50632
50888
  shiftStart: workspace.shift_start,
50633
50889
  shiftEnd: workspace.shift_end,
50634
50890
  shiftDate: workspace.date,
50635
- timezone: "Asia/Kolkata"
50891
+ timezone: reportTimezone
50636
50892
  }) : null;
50637
50893
  const hourlyUptime = uptimeSeries?.points?.length ? Array.from({ length: Math.ceil(uptimeSeries.shiftMinutes / 60) }, (_, index) => {
50638
50894
  const start = index * 60;
@@ -50647,6 +50903,31 @@ var WorkspacePdfGenerator = ({ workspace, className, idleTimeReasons, efficiency
50647
50903
  const hourlyData = isUptimeMode ? hourlyUptime : isAssemblyCycleMode ? hourlyCycleTimes && hourlyCycleTimes.length > 0 ? hourlyCycleTimes : workspace.hourly_action_counts || [] : workspace.hourly_action_counts || [];
50648
50904
  const hourlyTarget = workspace.pph_threshold;
50649
50905
  const cycleTarget = workspace.ideal_cycle_time || 0;
50906
+ const hourlyIntervals = buildHourlyIntervals({
50907
+ shiftStart: workspace.shift_start,
50908
+ shiftEnd: workspace.shift_end,
50909
+ fallbackHours: Math.max(hourlyData.length, 1)
50910
+ });
50911
+ const outputTargetPlan = !isUptimeMode && !isAssemblyCycleMode ? buildHourlyTargetPlan({
50912
+ shiftStart: workspace.shift_start,
50913
+ shiftEnd: workspace.shift_end,
50914
+ breaks: shiftBreaks,
50915
+ pphThreshold: workspace.pph_threshold,
50916
+ fallbackHours: Math.max(hourlyData.length, 1),
50917
+ rounding: "floor"
50918
+ }) : null;
50919
+ const formatIntervalLabel = (totalMinutes) => {
50920
+ const normalized = (totalMinutes % (24 * 60) + 24 * 60) % (24 * 60);
50921
+ const hour = Math.floor(normalized / 60);
50922
+ const minute = normalized % 60;
50923
+ const time2 = new Date(Date.UTC(2e3, 0, 1, hour, minute));
50924
+ return time2.toLocaleTimeString("en-IN", {
50925
+ hour: "numeric",
50926
+ ...minute > 0 ? { minute: "2-digit" } : {},
50927
+ hour12: true,
50928
+ timeZone: "UTC"
50929
+ });
50930
+ };
50650
50931
  const pageHeight = doc.internal.pageSize.height;
50651
50932
  const maxContentY = pageHeight - 15;
50652
50933
  const baseTableStartY = hourlyPerfStartY + 31;
@@ -50714,36 +50995,30 @@ var WorkspacePdfGenerator = ({ workspace, className, idleTimeReasons, efficiency
50714
50995
  doc.setFontSize(contentFontSize);
50715
50996
  doc.setFont("helvetica", "normal");
50716
50997
  let yPos = headerBottomY + 5.5;
50717
- const workspaceDate = new Date(workspace.date);
50718
- const today = /* @__PURE__ */ new Date();
50719
- today.setHours(0, 0, 0, 0);
50720
- workspaceDate.setHours(0, 0, 0, 0);
50721
- const isToday2 = workspaceDate.getTime() === today.getTime();
50998
+ const isToday2 = getDateKeyInTimeZone(reportTimezone) === workspace.date;
50722
50999
  let currentHour = 24;
50723
51000
  if (isToday2) {
50724
51001
  const now4 = /* @__PURE__ */ new Date();
50725
- const currentTimeIST = new Date(now4.toLocaleString("en-US", { timeZone: "Asia/Kolkata" }));
50726
- currentHour = currentTimeIST.getHours();
51002
+ const currentTimeInReportTimezone = new Date(now4.toLocaleString("en-US", { timeZone: reportTimezone }));
51003
+ currentHour = currentTimeInReportTimezone.getHours();
50727
51004
  }
50728
51005
  hourlyData.forEach((entry, index) => {
50729
- const startTime = /* @__PURE__ */ new Date(`2000-01-01 ${workspace.shift_start}`);
50730
- startTime.setHours(startTime.getHours() + index);
50731
- const endTime = new Date(startTime);
50732
- endTime.setHours(endTime.getHours() + 1);
50733
- const timeRange = `${startTime.toLocaleTimeString("en-IN", {
50734
- hour: "numeric",
50735
- hour12: true
50736
- })} - ${endTime.toLocaleTimeString("en-IN", {
50737
- hour: "numeric",
50738
- hour12: true
50739
- })}`;
50740
- const hourNumber = startTime.getHours();
50741
- const dataCollected = !isToday2 || hourNumber < currentHour;
51006
+ const interval = hourlyIntervals[index];
51007
+ const timeRange = interval ? `${formatIntervalLabel(interval.start)} - ${formatIntervalLabel(interval.end)}` : `${index + 1}`;
51008
+ const dataCollected = interval ? isHourlyIntervalComplete({
51009
+ reportDate: workspace.date,
51010
+ shiftStart: workspace.shift_start,
51011
+ shiftEnd: workspace.shift_end,
51012
+ interval,
51013
+ timeZone: reportTimezone
51014
+ }) : !isToday2 || currentHour >= 24;
50742
51015
  const outputValue = isUptimeMode ? entry.activeMinutes ?? 0 : entry;
50743
51016
  const idleValue = isUptimeMode ? entry.idleMinutes ?? 0 : 0;
50744
51017
  const uptimePercent = isUptimeMode ? entry.uptimePercent ?? 0 : 0;
50745
51018
  const outputStr = dataCollected ? outputValue.toString() : "TBD";
50746
- const targetStr = isUptimeMode ? dataCollected ? idleValue.toString() : "TBD" : hourlyTarget.toString();
51019
+ const effectiveTarget = outputTargetPlan?.targets[index] ?? hourlyTarget;
51020
+ const remarkText = outputTargetPlan?.breakRemarks[index] || "";
51021
+ const targetStr = isUptimeMode ? dataCollected ? idleValue.toString() : "TBD" : effectiveTarget.toString();
50747
51022
  if (index < totalRows - 1) {
50748
51023
  const rowBottomY = headerBottomY + (index + 1) * rowHeight;
50749
51024
  doc.setDrawColor(200, 200, 200);
@@ -50775,10 +51050,12 @@ var WorkspacePdfGenerator = ({ workspace, className, idleTimeReasons, efficiency
50775
51050
  } else {
50776
51051
  doc.text(outputStr, 75, yPos);
50777
51052
  doc.text(targetStr, 105, yPos);
51053
+ const remarkDisplay = remarkText ? doc.splitTextToSize(remarkText, 26)[0] : "";
51054
+ doc.text(remarkDisplay, 160, yPos);
50778
51055
  if (!dataCollected) {
50779
51056
  doc.setTextColor(100, 100, 100);
50780
51057
  doc.text("-", 135, yPos);
50781
- } else if (outputValue >= hourlyTarget) {
51058
+ } else if (outputValue >= effectiveTarget) {
50782
51059
  doc.setTextColor(0, 171, 69);
50783
51060
  doc.setFont("ZapfDingbats", "normal");
50784
51061
  doc.text("4", 135, yPos);
@@ -50792,11 +51069,10 @@ var WorkspacePdfGenerator = ({ workspace, className, idleTimeReasons, efficiency
50792
51069
  yPos += rowHeight;
50793
51070
  });
50794
51071
  const workspaceDisplayName = getWorkspaceDisplayName(workspace.workspace_name, workspace.line_id);
50795
- const fileDate = new Date(workspace.date).toLocaleDateString("en-IN", {
51072
+ const fileDate = formatOperationalDateKey2(workspace.date, {
50796
51073
  day: "2-digit",
50797
51074
  month: "short",
50798
- year: "numeric",
50799
- timeZone: "Asia/Kolkata"
51075
+ year: "numeric"
50800
51076
  }).replace(/ /g, "_");
50801
51077
  const fileShift = shiftType.replace(/ /g, "_");
50802
51078
  const fileName = `${workspaceDisplayName}_${fileDate}_${fileShift}.pdf`;
@@ -50842,12 +51118,25 @@ var WorkspaceMonthlyPdfGenerator = ({
50842
51118
  availableShifts,
50843
51119
  shiftConfig,
50844
51120
  efficiencyLegend,
51121
+ trendSummary,
50845
51122
  className,
50846
51123
  compact = false,
50847
51124
  isAssemblyWorkspace = false
50848
51125
  }) => {
50849
51126
  const [isGenerating, setIsGenerating] = useState(false);
50850
51127
  const effectiveLegend = efficiencyLegend || DEFAULT_EFFICIENCY_LEGEND;
51128
+ const drawStatusMark = (doc, x, y, met) => {
51129
+ doc.setLineWidth(0.8);
51130
+ if (met) {
51131
+ doc.setDrawColor(0, 171, 69);
51132
+ doc.line(x - 1.8, y - 0.2, x - 0.5, y + 1.2);
51133
+ doc.line(x - 0.5, y + 1.2, x + 2.1, y - 1.6);
51134
+ return;
51135
+ }
51136
+ doc.setDrawColor(227, 67, 41);
51137
+ doc.line(x - 1.8, y - 1.6, x + 1.8, y + 1.6);
51138
+ doc.line(x - 1.8, y + 1.6, x + 1.8, y - 1.6);
51139
+ };
50851
51140
  const generatePDF = async () => {
50852
51141
  setIsGenerating(true);
50853
51142
  try {
@@ -51042,12 +51331,13 @@ var WorkspaceMonthlyPdfGenerator = ({
51042
51331
  doc.setFont("helvetica", "bold");
51043
51332
  doc.text(`${outputMetrics.underperformingDays} of ${outputMetrics.totalDays}`, 120, kpiStartY + kpiSpacing * 3);
51044
51333
  } else {
51334
+ const medianCycleTime = Number.isFinite(trendSummary?.avg_cycle_time?.current) ? Number(trendSummary?.avg_cycle_time?.current) : outputMetrics.avgCycleTime;
51045
51335
  createKPIBox(kpiStartY);
51046
51336
  doc.setFontSize(11);
51047
51337
  doc.setFont("helvetica", "normal");
51048
51338
  doc.text("Average Cycle Time:", 25, kpiStartY);
51049
51339
  doc.setFont("helvetica", "bold");
51050
- doc.text(`${Math.round(outputMetrics.avgCycleTime)}s`, 120, kpiStartY);
51340
+ doc.text(`${medianCycleTime.toFixed(1)}s`, 120, kpiStartY);
51051
51341
  createKPIBox(kpiStartY + kpiSpacing);
51052
51342
  doc.setFont("helvetica", "normal");
51053
51343
  doc.text("Average Idle Time:", 25, kpiStartY + kpiSpacing);
@@ -51082,8 +51372,8 @@ var WorkspaceMonthlyPdfGenerator = ({
51082
51372
  doc.roundedRect(20, tableHeaderY, 170, 7, 1, 1, "F");
51083
51373
  const textY = tableHeaderY + 5;
51084
51374
  doc.text("Date", 25, textY);
51085
- doc.text(isUptimeMode ? "Productive" : isAssemblyWorkspace ? "Cycle Time" : "Actual", 60, textY);
51086
- doc.text(isUptimeMode ? "Idle" : isAssemblyWorkspace ? "Target CT" : "Standard", 95, textY);
51375
+ doc.text(isUptimeMode ? "Productive" : isAssemblyWorkspace ? "Actual Cycle Time" : "Actual", 60, textY);
51376
+ doc.text(isUptimeMode ? "Idle" : isAssemblyWorkspace ? "Standard Cycle Time" : "Standard", 95, textY);
51087
51377
  doc.text(isUptimeMode ? "Utilization" : "Efficiency", 135, textY);
51088
51378
  doc.text("Status", 170, textY);
51089
51379
  doc.setLineWidth(0.2);
@@ -51115,31 +51405,18 @@ var WorkspaceMonthlyPdfGenerator = ({
51115
51405
  doc.text(formatIdleTime(productiveSeconds), 60, yPos);
51116
51406
  doc.text(formatIdleTime(clampedIdleSeconds), 95, yPos);
51117
51407
  doc.text(`${utilization}%`, 135, yPos);
51118
- if (utilization >= effectiveLegend.green_min) {
51119
- doc.setTextColor(0, 171, 69);
51120
- doc.text("\u2713", 170, yPos);
51121
- } else {
51122
- doc.setTextColor(227, 67, 41);
51123
- doc.text("\xD7", 170, yPos);
51124
- }
51125
- doc.setTextColor(0, 0, 0);
51408
+ drawStatusMark(doc, 171, yPos - 0.3, utilization >= effectiveLegend.green_min);
51126
51409
  } else {
51127
51410
  if (isAssemblyWorkspace) {
51411
+ const targetCycleTime = Number.isFinite(shift.idealCycleTime) && Number(shift.idealCycleTime) > 0 ? Number(shift.idealCycleTime) : shift.pphThreshold > 0 ? 3600 / shift.pphThreshold : null;
51128
51412
  doc.text(`${shift.cycleTime.toFixed(1)}`, 60, yPos);
51129
- doc.text(`${shift.pphThreshold > 0 ? (3600 / shift.pphThreshold).toFixed(1) : "-"}`, 95, yPos);
51413
+ doc.text(targetCycleTime !== null ? `${targetCycleTime.toFixed(1)}` : "-", 95, yPos);
51130
51414
  } else {
51131
51415
  doc.text(`${shift.output}`, 60, yPos);
51132
51416
  doc.text(`${shift.targetOutput}`, 95, yPos);
51133
51417
  }
51134
51418
  doc.text(`${shift.efficiency.toFixed(1)}%`, 135, yPos);
51135
- if (shift.efficiency >= effectiveLegend.green_min) {
51136
- doc.setTextColor(0, 171, 69);
51137
- doc.text("\u2713", 170, yPos);
51138
- } else {
51139
- doc.setTextColor(227, 67, 41);
51140
- doc.text("\xD7", 170, yPos);
51141
- }
51142
- doc.setTextColor(0, 0, 0);
51419
+ drawStatusMark(doc, 171, yPos - 0.3, shift.efficiency >= effectiveLegend.green_min);
51143
51420
  }
51144
51421
  yPos += 8;
51145
51422
  });
@@ -64305,7 +64582,17 @@ var KPIDetailView = ({
64305
64582
  )
64306
64583
  ] }),
64307
64584
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 ml-auto", children: [
64308
- resolvedLineInfo && activeTab === "overview" && /* @__PURE__ */ jsx(LinePdfGenerator, { lineInfo: resolvedLineInfo, workspaceData: resolvedWorkspaces || [], issueResolutionSummary, shiftName: getShiftName(resolvedLineInfo.shift_id) }),
64585
+ resolvedLineInfo && activeTab === "overview" && /* @__PURE__ */ jsx(
64586
+ LinePdfGenerator,
64587
+ {
64588
+ lineInfo: resolvedLineInfo,
64589
+ workspaceData: resolvedWorkspaces || [],
64590
+ issueResolutionSummary,
64591
+ shiftName: getShiftName(resolvedLineInfo.shift_id),
64592
+ shiftBreaks: shiftConfig?.shifts?.find((shift) => shift.shiftId === resolvedLineInfo.shift_id)?.breaks || [],
64593
+ reportTimezone: shiftConfig?.timezone || configuredTimezone
64594
+ }
64595
+ ),
64309
64596
  activeTab === "monthly_history" && !urlDate && !urlShift && /* @__PURE__ */ jsxs(Fragment, { children: [
64310
64597
  /* @__PURE__ */ jsx(
64311
64598
  MonthlyRangeFilter_default,
@@ -64334,6 +64621,8 @@ var KPIDetailView = ({
64334
64621
  rangeStart,
64335
64622
  rangeEnd,
64336
64623
  selectedShiftId,
64624
+ availableShifts: shiftConfig?.shifts?.map((shift) => ({ id: shift.shiftId, name: shift.shiftName })),
64625
+ lineAssembly: resolvedLineInfo?.assembly === true,
64337
64626
  compact: true
64338
64627
  }
64339
64628
  )
@@ -64512,7 +64801,7 @@ var KPIDetailViewWithDisplayNames = withSelectedLineDisplayNames(KPIDetailView);
64512
64801
  var KPIDetailView_default = KPIDetailViewWithDisplayNames;
64513
64802
  var isNonEmptyString = (value) => typeof value === "string" && value.trim().length > 0;
64514
64803
  var resolveCompanyId = (...candidates) => candidates.find(isNonEmptyString);
64515
- var parseTimeToMinutes2 = (value) => {
64804
+ var parseTimeToMinutes3 = (value) => {
64516
64805
  if (!value) return null;
64517
64806
  const [hourStr, minuteStr] = value.split(":");
64518
64807
  const hour = Number.parseInt(hourStr ?? "", 10);
@@ -64524,8 +64813,8 @@ var getShiftEndDate = (shift, timezone) => {
64524
64813
  if (!shift?.date) return null;
64525
64814
  const startTime = shift.startTime || "06:00";
64526
64815
  const endTime = shift.endTime || "18:00";
64527
- const startMinutes = parseTimeToMinutes2(startTime);
64528
- const endMinutes = parseTimeToMinutes2(endTime);
64816
+ const startMinutes = parseTimeToMinutes3(startTime);
64817
+ const endMinutes = parseTimeToMinutes3(endTime);
64529
64818
  if (startMinutes === null || endMinutes === null) return null;
64530
64819
  const shiftStartDate = fromZonedTime(`${shift.date}T${startTime}:00`, timezone);
64531
64820
  let durationMinutes = endMinutes - startMinutes;
@@ -64563,7 +64852,7 @@ var createKpisOverviewUrl = ({
64563
64852
  return queryString ? `/kpis?${queryString}` : "/kpis";
64564
64853
  };
64565
64854
  var getZonedDateAtMidday = (dateKey, timezone) => fromZonedTime(`${dateKey}T12:00:00`, timezone);
64566
- var formatDateKey = (dateKey, timezone, options) => {
64855
+ var formatDateKey2 = (dateKey, timezone, options) => {
64567
64856
  try {
64568
64857
  return new Intl.DateTimeFormat("en-US", {
64569
64858
  ...options,
@@ -65631,7 +65920,7 @@ var KPIsOverviewView = ({
65631
65920
  setActiveTab(newTab);
65632
65921
  }, [activeTab, leaderboardLines.length, lines.length]);
65633
65922
  const formatLocalDate2 = useCallback((dateKey) => {
65634
- return formatDateKey(dateKey, configuredTimezone, {
65923
+ return formatDateKey2(dateKey, configuredTimezone, {
65635
65924
  year: "numeric",
65636
65925
  month: "long",
65637
65926
  day: "numeric"
@@ -65645,8 +65934,8 @@ var KPIsOverviewView = ({
65645
65934
  zonedNow.getMonth(),
65646
65935
  new Date(zonedNow.getFullYear(), zonedNow.getMonth() + 1, 0).getDate()
65647
65936
  );
65648
- const startLabel = formatDateKey(startOfMonthKey, configuredTimezone, { month: "short", day: "numeric" });
65649
- const endLabel = formatDateKey(endOfMonthKey, configuredTimezone, { month: "short", day: "numeric" });
65937
+ const startLabel = formatDateKey2(startOfMonthKey, configuredTimezone, { month: "short", day: "numeric" });
65938
+ const endLabel = formatDateKey2(endOfMonthKey, configuredTimezone, { month: "short", day: "numeric" });
65650
65939
  return `${startLabel} - ${endLabel}, ${zonedNow.getFullYear()}`;
65651
65940
  };
65652
65941
  const isMonthlyMode = activeTab === "leaderboard" && timeRange === "monthly";
@@ -71281,6 +71570,7 @@ var WorkspaceDetailView = ({
71281
71570
  efficiency: monitoringMode === "uptime" ? Number.isFinite(metric.avg_efficiency) ? Number(metric.avg_efficiency) : computedUptimeEfficiency : Number.isFinite(metric.avg_efficiency) ? Number(metric.avg_efficiency) : 0,
71282
71571
  output: metric.total_output || 0,
71283
71572
  cycleTime: metric.avg_cycle_time || 0,
71573
+ idealCycleTime: Number(metric.ideal_cycle_time || 0),
71284
71574
  pph: metric.avg_pph || 0,
71285
71575
  pphThreshold: metric.pph_threshold || 0,
71286
71576
  idealOutput: Number(metric.ideal_output || 0),
@@ -71836,7 +72126,9 @@ var WorkspaceDetailView = ({
71836
72126
  workspace,
71837
72127
  idleTimeReasons: idleTimeChartData,
71838
72128
  efficiencyLegend,
71839
- hourlyCycleTimes: cycleTimeChartData
72129
+ hourlyCycleTimes: cycleTimeChartData,
72130
+ shiftBreaks: shiftConfig?.shifts?.find((shift2) => shift2.shiftId === workspace.shift_id)?.breaks || [],
72131
+ reportTimezone: shiftConfig?.timezone || timezone
71840
72132
  }
71841
72133
  ) }),
71842
72134
  activeTab === "monthly_history" && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
@@ -71871,6 +72163,7 @@ var WorkspaceDetailView = ({
71871
72163
  workspaceId,
71872
72164
  workspaceName: formattedWorkspaceName,
71873
72165
  monthlyData,
72166
+ analysisData: analysisMonthlyData,
71874
72167
  selectedMonth,
71875
72168
  selectedYear,
71876
72169
  monitoringMode: workspace?.monitoring_mode,
@@ -71879,7 +72172,10 @@ var WorkspaceDetailView = ({
71879
72172
  selectedShiftId: selectedShift,
71880
72173
  availableShifts: shiftConfig?.shifts?.map((s) => ({ id: s.shiftId, name: s.shiftName })),
71881
72174
  shiftConfig,
71882
- compact: true
72175
+ efficiencyLegend,
72176
+ trendSummary: workspaceMonthlyTrend,
72177
+ compact: true,
72178
+ isAssemblyWorkspace
71883
72179
  }
71884
72180
  )
71885
72181
  ] })
@@ -80094,7 +80390,7 @@ var useOperationsOverviewRefresh = ({
80094
80390
  };
80095
80391
  }, [companyId, enabled, getIsPageActive, isLiveScope, lineIds.length, refreshFromResume, startPolling, stopPolling, supabase]);
80096
80392
  };
80097
- var parseTimeToMinutes3 = (value) => {
80393
+ var parseTimeToMinutes4 = (value) => {
80098
80394
  if (!value) return null;
80099
80395
  const parts = value.split(":");
80100
80396
  if (parts.length < 2) return null;
@@ -80129,8 +80425,8 @@ var classifyShiftBucket = ({
80129
80425
  return "day";
80130
80426
  }
80131
80427
  }
80132
- const startMinutes = parseTimeToMinutes3(startTime);
80133
- const endMinutes = parseTimeToMinutes3(endTime);
80428
+ const startMinutes = parseTimeToMinutes4(startTime);
80429
+ const endMinutes = parseTimeToMinutes4(endTime);
80134
80430
  if (startMinutes !== null) {
80135
80431
  if (startMinutes >= 4 * 60 && startMinutes < 18 * 60) return "day";
80136
80432
  return "night";
@@ -80189,8 +80485,8 @@ var getShiftWindowsForConfig = (shiftConfig, timezone) => {
80189
80485
  ];
80190
80486
  };
80191
80487
  var normalizeShiftWindowMinutes = (startTime, endTime) => {
80192
- const startMinutes = parseTimeToMinutes3(startTime);
80193
- const endMinutesRaw = parseTimeToMinutes3(endTime);
80488
+ const startMinutes = parseTimeToMinutes4(startTime);
80489
+ const endMinutesRaw = parseTimeToMinutes4(endTime);
80194
80490
  if (startMinutes === null || endMinutesRaw === null) {
80195
80491
  return null;
80196
80492
  }
@@ -80356,7 +80652,7 @@ var PlantHeadView = () => {
80356
80652
  startTime: shift.startTime,
80357
80653
  endTime: shift.endTime
80358
80654
  });
80359
- const startMinutes = parseTimeToMinutes3(shift.startTime);
80655
+ const startMinutes = parseTimeToMinutes4(shift.startTime);
80360
80656
  if (bucket === "day" && startMinutes !== null) {
80361
80657
  candidateStarts.push(startMinutes);
80362
80658
  }
@@ -80366,7 +80662,7 @@ var PlantHeadView = () => {
80366
80662
  scopedLineIds.forEach((lineId) => {
80367
80663
  const shiftConfig = shiftConfigMap.get(lineId) || staticShiftConfig;
80368
80664
  getShiftWindowsForConfig(shiftConfig).forEach((shift) => {
80369
- const startMinutes = parseTimeToMinutes3(shift.startTime);
80665
+ const startMinutes = parseTimeToMinutes4(shift.startTime);
80370
80666
  if (startMinutes !== null) {
80371
80667
  candidateStarts.push(startMinutes);
80372
80668
  }
@@ -80457,7 +80753,7 @@ var PlantHeadView = () => {
80457
80753
  startTime: shift.startTime,
80458
80754
  endTime: shift.endTime
80459
80755
  });
80460
- return bucket === "day" ? parseTimeToMinutes3(shift.startTime) : null;
80756
+ return bucket === "day" ? parseTimeToMinutes4(shift.startTime) : null;
80461
80757
  }).filter((value) => value !== null);
80462
80758
  }) : [];
80463
80759
  if (dayStartCandidates.length > 0) {