@optifye/dashboard-core 6.9.13 → 6.9.14

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
@@ -125,6 +125,32 @@ function isValidPrefetchStatus(status) {
125
125
  return typeof status === "string" && Object.values(PrefetchStatus).includes(status);
126
126
  }
127
127
 
128
+ // src/lib/types/calendar.ts
129
+ var DEFAULT_SHIFT_DATA = {
130
+ efficiency: 0,
131
+ output: 0,
132
+ cycleTime: 0,
133
+ pph: 0,
134
+ pphThreshold: 0,
135
+ idealOutput: 0,
136
+ rank: 0,
137
+ idleTime: 0,
138
+ hasData: false
139
+ };
140
+ var getShiftData = (day, shiftId) => {
141
+ const shift = day.shifts[shiftId];
142
+ if (shift) {
143
+ return { ...shift, hasData: true };
144
+ }
145
+ return { ...DEFAULT_SHIFT_DATA };
146
+ };
147
+ var hasAnyShiftData = (day) => {
148
+ return Object.keys(day.shifts).length > 0;
149
+ };
150
+ var getAvailableShiftIds = (day) => {
151
+ return Object.keys(day.shifts).map(Number).sort((a, b) => a - b);
152
+ };
153
+
128
154
  // src/components/dashboard/grid/workspace_grid_constants.ts
129
155
  var DEFAULT_WORKSPACE_POSITIONS = [
130
156
  // Middle top row - 7 tapping workspaces (conveyor style)
@@ -171,15 +197,21 @@ var DEFAULT_ENTITY_CONFIG = {
171
197
  }
172
198
  };
173
199
  var DEFAULT_SHIFT_CONFIG = {
200
+ shifts: [
201
+ { shiftId: 0, shiftName: "Day Shift", startTime: "06:00", endTime: "18:00", breaks: [], timezone: "UTC" },
202
+ { shiftId: 1, shiftName: "Night Shift", startTime: "18:00", endTime: "06:00", breaks: [], timezone: "UTC" }
203
+ ],
174
204
  dayShift: {
175
205
  id: 0,
176
206
  startTime: "06:00",
177
- endTime: "18:00"
207
+ endTime: "18:00",
208
+ name: "Day Shift"
178
209
  },
179
210
  nightShift: {
180
211
  id: 1,
181
212
  startTime: "18:00",
182
- endTime: "06:00"
213
+ endTime: "06:00",
214
+ name: "Night Shift"
183
215
  },
184
216
  transitionPeriodMinutes: 15
185
217
  };
@@ -529,70 +561,128 @@ var parseTimeToMinutes = (timeString) => {
529
561
  const [hours, minutes] = timeString.split(":").map(Number);
530
562
  return hours * 60 + minutes;
531
563
  };
532
- var getCurrentShift = (timezone, shiftConfig, now2 = /* @__PURE__ */ new Date()) => {
533
- const dayShiftStartStr = shiftConfig?.dayShift?.startTime || DEFAULT_DAY_SHIFT_START;
534
- const nightShiftStartStr = shiftConfig?.nightShift?.startTime || DEFAULT_NIGHT_SHIFT_START;
535
- const dayShiftId = shiftConfig?.dayShift?.id ?? 0;
536
- const nightShiftId = shiftConfig?.nightShift?.id ?? 1;
537
- const dayShiftStartMinutes = parseTimeToMinutes(dayShiftStartStr);
538
- const nightShiftStartMinutes = parseTimeToMinutes(nightShiftStartStr);
539
- const effectiveDayStart = !isNaN(dayShiftStartMinutes) ? dayShiftStartMinutes : parseTimeToMinutes(DEFAULT_DAY_SHIFT_START);
540
- const effectiveNightStart = !isNaN(nightShiftStartMinutes) ? nightShiftStartMinutes : parseTimeToMinutes(DEFAULT_NIGHT_SHIFT_START);
564
+ var normalizeShiftDefinitions = (timezone, shiftConfig) => {
565
+ if (shiftConfig?.shifts && shiftConfig.shifts.length > 0) {
566
+ return {
567
+ shifts: shiftConfig.shifts,
568
+ timezone: shiftConfig.shifts[0].timezone || shiftConfig.timezone || timezone
569
+ };
570
+ }
571
+ const fallbackTimezone = shiftConfig?.timezone || timezone;
572
+ const legacyShifts = [];
573
+ if (shiftConfig?.dayShift) {
574
+ legacyShifts.push({
575
+ shiftId: shiftConfig.dayShift.id ?? 0,
576
+ shiftName: shiftConfig.dayShift.name || "Day Shift",
577
+ startTime: shiftConfig.dayShift.startTime || DEFAULT_DAY_SHIFT_START,
578
+ endTime: shiftConfig.dayShift.endTime || "18:00",
579
+ breaks: [],
580
+ timezone: fallbackTimezone
581
+ });
582
+ }
583
+ if (shiftConfig?.nightShift) {
584
+ legacyShifts.push({
585
+ shiftId: shiftConfig.nightShift.id ?? 1,
586
+ shiftName: shiftConfig.nightShift.name || "Night Shift",
587
+ startTime: shiftConfig.nightShift.startTime || DEFAULT_NIGHT_SHIFT_START,
588
+ endTime: shiftConfig.nightShift.endTime || "06:00",
589
+ breaks: [],
590
+ timezone: fallbackTimezone
591
+ });
592
+ }
593
+ if (legacyShifts.length === 0) {
594
+ legacyShifts.push(
595
+ {
596
+ shiftId: 0,
597
+ shiftName: "Day Shift",
598
+ startTime: DEFAULT_DAY_SHIFT_START,
599
+ endTime: "18:00",
600
+ breaks: [],
601
+ timezone: fallbackTimezone
602
+ },
603
+ {
604
+ shiftId: 1,
605
+ shiftName: "Night Shift",
606
+ startTime: DEFAULT_NIGHT_SHIFT_START,
607
+ endTime: "06:00",
608
+ breaks: [],
609
+ timezone: fallbackTimezone
610
+ }
611
+ );
612
+ }
613
+ return { shifts: legacyShifts, timezone: fallbackTimezone };
614
+ };
615
+ var determineShiftFromDefinitions = (timezone, shifts, now2 = /* @__PURE__ */ new Date()) => {
541
616
  const zonedNow = dateFnsTz.toZonedTime(now2, timezone);
542
- const currentHour = zonedNow.getHours();
543
- const currentMinutes = zonedNow.getMinutes();
544
- const currentTotalMinutes = currentHour * 60 + currentMinutes;
545
- const operationalDate = getOperationalDate(timezone, zonedNow, dayShiftStartStr);
546
- let determinedShiftId;
547
- if (effectiveDayStart < effectiveNightStart) {
548
- if (currentTotalMinutes >= effectiveDayStart && currentTotalMinutes < effectiveNightStart) {
549
- determinedShiftId = dayShiftId;
550
- } else {
551
- determinedShiftId = nightShiftId;
617
+ const currentMinutes = zonedNow.getHours() * 60 + zonedNow.getMinutes();
618
+ let chosen;
619
+ let operationalDate = getOperationalDate(timezone, zonedNow, shifts[0].startTime);
620
+ for (const shift of shifts) {
621
+ const start = parseTimeToMinutes(shift.startTime);
622
+ const endRaw = parseTimeToMinutes(shift.endTime);
623
+ let end = endRaw;
624
+ const wraps = end <= start;
625
+ if (wraps) end += 1440;
626
+ if (start <= currentMinutes && currentMinutes < end) {
627
+ chosen = shift;
628
+ operationalDate = getOperationalDate(timezone, zonedNow, shift.startTime);
629
+ break;
552
630
  }
553
- } else {
554
- if (currentTotalMinutes >= effectiveDayStart || currentTotalMinutes < effectiveNightStart) {
555
- determinedShiftId = dayShiftId;
556
- } else {
557
- determinedShiftId = nightShiftId;
631
+ if (start <= currentMinutes + 1440 && currentMinutes + 1440 < end) {
632
+ chosen = shift;
633
+ operationalDate = getOperationalDate(timezone, zonedNow, shift.startTime);
634
+ break;
558
635
  }
559
636
  }
560
- return { shiftId: determinedShiftId, date: operationalDate };
637
+ if (!chosen) {
638
+ chosen = shifts[0];
639
+ operationalDate = getOperationalDate(timezone, zonedNow, chosen.startTime);
640
+ }
641
+ return {
642
+ shiftId: chosen.shiftId,
643
+ shiftName: chosen.shiftName,
644
+ startTime: chosen.startTime,
645
+ endTime: chosen.endTime,
646
+ timezone,
647
+ date: operationalDate
648
+ };
649
+ };
650
+ var getCurrentShift = (timezone, shiftConfig, now2 = /* @__PURE__ */ new Date()) => {
651
+ const { shifts, timezone: effectiveTz } = normalizeShiftDefinitions(timezone, shiftConfig);
652
+ return determineShiftFromDefinitions(effectiveTz, shifts, now2);
561
653
  };
562
654
  var isTransitionPeriod = (timezone, shiftConfig, now2 = /* @__PURE__ */ new Date()) => {
563
- const dayShiftStartStr = shiftConfig?.dayShift?.startTime || DEFAULT_DAY_SHIFT_START;
564
- const nightShiftStartStr = shiftConfig?.nightShift?.startTime || DEFAULT_NIGHT_SHIFT_START;
565
655
  const transitionMinutes = shiftConfig?.transitionPeriodMinutes ?? DEFAULT_TRANSITION_MINUTES;
566
- const dayShiftStartMinutes = parseTimeToMinutes(dayShiftStartStr);
567
- const nightShiftStartMinutes = parseTimeToMinutes(nightShiftStartStr);
568
- if (isNaN(dayShiftStartMinutes) || isNaN(nightShiftStartMinutes)) {
569
- return false;
570
- }
571
- const transitionTimes = [dayShiftStartMinutes, nightShiftStartMinutes];
572
- const zonedNow = dateFnsTz.toZonedTime(now2, timezone);
573
- const currentHour = zonedNow.getHours();
574
- const currentMinutes = zonedNow.getMinutes();
575
- const currentTotalMinutes = currentHour * 60 + currentMinutes;
576
- return transitionTimes.some((transitionTime) => {
656
+ const { shifts, timezone: effectiveTz } = normalizeShiftDefinitions(timezone, shiftConfig);
657
+ if (!shifts.length) return false;
658
+ const zonedNow = dateFnsTz.toZonedTime(now2, effectiveTz);
659
+ const currentTotalMinutes = zonedNow.getHours() * 60 + zonedNow.getMinutes();
660
+ return shifts.some((shift) => {
661
+ const transitionTime = parseTimeToMinutes(shift.startTime);
662
+ if (isNaN(transitionTime)) return false;
577
663
  const lowerBoundBefore = (transitionTime - transitionMinutes + 1440) % 1440;
578
664
  const upperBoundBefore = transitionTime;
579
- let isBefore = false;
580
- if (lowerBoundBefore < upperBoundBefore) {
581
- isBefore = currentTotalMinutes >= lowerBoundBefore && currentTotalMinutes < upperBoundBefore;
582
- } else {
583
- isBefore = currentTotalMinutes >= lowerBoundBefore || currentTotalMinutes < upperBoundBefore;
584
- }
585
665
  const lowerBoundAfter = transitionTime;
586
666
  const upperBoundAfter = (transitionTime + transitionMinutes) % 1440;
587
- let isAfter = false;
588
- if (lowerBoundAfter < upperBoundAfter) {
589
- isAfter = currentTotalMinutes >= lowerBoundAfter && currentTotalMinutes < upperBoundAfter;
590
- } else {
591
- isAfter = currentTotalMinutes >= lowerBoundAfter || currentTotalMinutes < upperBoundAfter;
592
- }
593
- return isBefore || isAfter;
667
+ const inBefore = lowerBoundBefore < upperBoundBefore ? currentTotalMinutes >= lowerBoundBefore && currentTotalMinutes < upperBoundBefore : currentTotalMinutes >= lowerBoundBefore || currentTotalMinutes < upperBoundBefore;
668
+ const inAfter = lowerBoundAfter < upperBoundAfter ? currentTotalMinutes >= lowerBoundAfter && currentTotalMinutes < upperBoundAfter : currentTotalMinutes >= lowerBoundAfter || currentTotalMinutes < upperBoundAfter;
669
+ return inBefore || inAfter;
594
670
  });
595
671
  };
672
+ var getShiftNameById = (shiftId, timezone, shiftConfig) => {
673
+ const { shifts } = normalizeShiftDefinitions(timezone, shiftConfig);
674
+ const shift = shifts.find((s) => s.shiftId === shiftId);
675
+ if (shift) {
676
+ return shift.shiftName;
677
+ }
678
+ if (shiftId === 0) return "Day Shift";
679
+ if (shiftId === 1) return "Night Shift";
680
+ return `Shift ${shiftId}`;
681
+ };
682
+ var getShortShiftName = (shiftId, timezone, shiftConfig) => {
683
+ const fullName = getShiftNameById(shiftId, timezone, shiftConfig);
684
+ return fullName.replace(/ Shift$/i, "");
685
+ };
596
686
 
597
687
  // src/lib/utils/database.ts
598
688
  var getCompanyMetricsTableName = (companyId, prefix = "workspace_performance") => {
@@ -1185,12 +1275,12 @@ var dashboardService = {
1185
1275
  throw err;
1186
1276
  }
1187
1277
  },
1188
- async getDetailedLineInfo(lineIdInput, dateProp, shiftProp) {
1278
+ async getDetailedLineInfo(lineIdInput, dateProp, shiftProp, providedShiftConfig) {
1189
1279
  const supabase = _getSupabaseInstance();
1190
1280
  const config = _getDashboardConfigInstance();
1191
1281
  const dbConfig = config.databaseConfig ?? DEFAULT_DATABASE_CONFIG;
1192
1282
  const entityConfig = config.entityConfig ?? DEFAULT_ENTITY_CONFIG;
1193
- const shiftConfig = config.shiftConfig ?? DEFAULT_SHIFT_CONFIG;
1283
+ const shiftConfig = providedShiftConfig || (config.shiftConfig ?? DEFAULT_SHIFT_CONFIG);
1194
1284
  const dateTimeConfig = config.dateTimeConfig ?? DEFAULT_DATE_TIME_CONFIG;
1195
1285
  const workspaceConfig = config.workspaceConfig ?? DEFAULT_WORKSPACE_CONFIG;
1196
1286
  const linesTable = getTable(dbConfig, "lines");
@@ -1277,8 +1367,8 @@ var dashboardService = {
1277
1367
  underperforming_workspaces: combinedMetricsData.underperforming_workspaces,
1278
1368
  line_threshold: combinedMetricsData.line_threshold,
1279
1369
  threshold_pph: combinedMetricsData.threshold_pph / numLines,
1280
- shift_start: metricsData?.[0]?.shift_start || shiftConfig.dayShift?.startTime || "06:00",
1281
- shift_end: metricsData?.[0]?.shift_end || shiftConfig.dayShift?.endTime || "18:00",
1370
+ shift_start: metricsData?.[0]?.shift_start || (shiftConfig.shifts && shiftConfig.shifts.length > 0 ? shiftConfig.shifts.find((s) => s.shiftId === 0)?.startTime || shiftConfig.shifts[0].startTime : shiftConfig.dayShift?.startTime) || "06:00",
1371
+ shift_end: metricsData?.[0]?.shift_end || (shiftConfig.shifts && shiftConfig.shifts.length > 0 ? shiftConfig.shifts.find((s) => s.shiftId === 0)?.endTime || shiftConfig.shifts[0].endTime : shiftConfig.dayShift?.endTime) || "18:00",
1282
1372
  last_updated: (/* @__PURE__ */ new Date()).toISOString(),
1283
1373
  output_array: combinedMetricsData.outputArrays.length > 0 ? memoizedOutputArrayAggregation(combinedMetricsData.outputArrays) : [],
1284
1374
  underperforming_workspace_names: combinedMetricsData.underperforming_workspace_names,
@@ -1319,8 +1409,8 @@ var dashboardService = {
1319
1409
  underperforming_workspaces: metrics2?.underperforming_workspaces ?? 0,
1320
1410
  line_threshold: metrics2?.line_threshold || 0,
1321
1411
  threshold_pph: metrics2?.threshold_pph || 0,
1322
- shift_start: metrics2?.shift_start || shiftConfig.dayShift?.startTime || "06:00",
1323
- shift_end: metrics2?.shift_end || shiftConfig.dayShift?.endTime || "18:00",
1412
+ shift_start: metrics2?.shift_start || (shiftConfig.shifts && shiftConfig.shifts.length > 0 ? shiftConfig.shifts.find((s) => s.shiftId === 0)?.startTime || shiftConfig.shifts[0].startTime : shiftConfig.dayShift?.startTime) || "06:00",
1413
+ shift_end: metrics2?.shift_end || (shiftConfig.shifts && shiftConfig.shifts.length > 0 ? shiftConfig.shifts.find((s) => s.shiftId === 0)?.endTime || shiftConfig.shifts[0].endTime : shiftConfig.dayShift?.endTime) || "18:00",
1324
1414
  last_updated: metrics2?.last_updated || (/* @__PURE__ */ new Date()).toISOString(),
1325
1415
  output_array: metrics2?.output_array || [],
1326
1416
  underperforming_workspace_names: metrics2?.underperforming_workspace_names || [],
@@ -1431,7 +1521,7 @@ var dashboardService = {
1431
1521
  throw err;
1432
1522
  }
1433
1523
  },
1434
- async getUnderperformingWorkspaces(lineIdInput, monthInput, yearInput) {
1524
+ async getUnderperformingWorkspaces(lineIdInput, monthInput, yearInput, shiftIds) {
1435
1525
  _getSupabaseInstance();
1436
1526
  const config = _getDashboardConfigInstance();
1437
1527
  const entityConfig = config.entityConfig ?? DEFAULT_ENTITY_CONFIG;
@@ -1451,13 +1541,14 @@ var dashboardService = {
1451
1541
  const currentDate = /* @__PURE__ */ new Date();
1452
1542
  const currentMonth = monthInput !== void 0 ? monthInput : currentDate.getMonth();
1453
1543
  const currentYear = yearInput !== void 0 ? yearInput : currentDate.getFullYear();
1544
+ const dynamicShiftIds = shiftIds || shiftConfig.shifts?.map((s) => s.shiftId) || [shiftConfig.dayShift?.id ?? 0, shiftConfig.nightShift?.id ?? 1];
1454
1545
  const bodyPayload = {
1455
1546
  lineId: lineIdInput === factoryViewId ? configuredLineIds : lineIdInput,
1456
1547
  month: currentMonth,
1457
1548
  year: currentYear,
1458
1549
  companyId,
1459
1550
  metricsTable,
1460
- shifts: [shiftConfig.dayShift?.id ?? 0, shiftConfig.nightShift?.id ?? 1]
1551
+ shifts: dynamicShiftIds
1461
1552
  };
1462
1553
  const response = await fetch(fullFunctionUrl, {
1463
1554
  method: "POST",
@@ -2164,16 +2255,13 @@ var WorkspaceHealthService = class _WorkspaceHealthService {
2164
2255
  this.cache.set(key, { data, timestamp: Date.now() });
2165
2256
  }
2166
2257
  getShiftTiming(timezone, shiftConfig) {
2167
- const { shiftId, date } = getCurrentShift(timezone, shiftConfig);
2168
- const dayShiftId = shiftConfig?.dayShift?.id ?? 0;
2169
- const isDayShift = shiftId === dayShiftId;
2258
+ const currentShift = getCurrentShift(timezone, shiftConfig);
2259
+ const { shiftId, date, shiftName, startTime, endTime } = currentShift;
2170
2260
  const defaultDayStart = "06:00";
2171
2261
  const defaultDayEnd = "18:00";
2172
- const defaultNightStart = "18:00";
2173
- const defaultNightEnd = "06:00";
2174
- const shiftStartStr = isDayShift ? shiftConfig?.dayShift?.startTime || defaultDayStart : shiftConfig?.nightShift?.startTime || defaultNightStart;
2175
- const shiftEndStr = isDayShift ? shiftConfig?.dayShift?.endTime || defaultDayEnd : shiftConfig?.nightShift?.endTime || defaultNightEnd;
2176
- const shiftLabel = isDayShift ? "Day Shift" : "Night Shift";
2262
+ const shiftStartStr = startTime || defaultDayStart;
2263
+ const shiftEndStr = endTime || defaultDayEnd;
2264
+ const shiftLabel = shiftName || (shiftId === 0 ? "Day Shift" : shiftId === 1 ? "Night Shift" : `Shift ${shiftId}`);
2177
2265
  const parseTime = (value) => {
2178
2266
  const [hourPart = "0", minutePart = "0"] = value.split(":");
2179
2267
  const hour = Number.parseInt(hourPart, 10);
@@ -2248,6 +2336,13 @@ var WorkspaceHealthService = class _WorkspaceHealthService {
2248
2336
  async getWorkspaceHealthStatus(options = {}) {
2249
2337
  const supabase = _getSupabaseInstance();
2250
2338
  if (!supabase) throw new Error("Supabase client not initialized");
2339
+ const dashboardConfig = _getDashboardConfigInstance();
2340
+ if (!options.shiftConfig) {
2341
+ console.warn("[workspaceHealthService.getWorkspaceHealthStatus] \u26A0\uFE0F No shiftConfig passed! Falling back to static config. This may cause incorrect shift_id queries.");
2342
+ }
2343
+ const shiftConfig = options.shiftConfig || dashboardConfig?.shiftConfig;
2344
+ const defaultTimezone = dashboardConfig?.dateTimeConfig?.defaultTimezone || "UTC";
2345
+ const timezone = options.timezone || shiftConfig?.timezone || defaultTimezone;
2251
2346
  let query = supabase.from("workspace_health_status").select("*").order("workspace_display_name", { ascending: true });
2252
2347
  if (options.lineId) {
2253
2348
  query = query.eq("line_id", options.lineId);
@@ -2265,7 +2360,7 @@ var WorkspaceHealthService = class _WorkspaceHealthService {
2265
2360
  let uptimeMap = /* @__PURE__ */ new Map();
2266
2361
  if (companyId) {
2267
2362
  try {
2268
- uptimeMap = await this.calculateWorkspaceUptime(companyId);
2363
+ uptimeMap = await this.calculateWorkspaceUptime(companyId, shiftConfig, timezone);
2269
2364
  } catch (error2) {
2270
2365
  console.error("Error calculating uptime:", error2);
2271
2366
  }
@@ -2343,7 +2438,7 @@ var WorkspaceHealthService = class _WorkspaceHealthService {
2343
2438
  }
2344
2439
  return filteredData;
2345
2440
  }
2346
- async getWorkspaceUptimeTimeline(workspaceId, companyId) {
2441
+ async getWorkspaceUptimeTimeline(workspaceId, companyId, passedShiftConfig, passedTimezone) {
2347
2442
  if (!workspaceId) {
2348
2443
  throw new Error("workspaceId is required to fetch uptime timeline");
2349
2444
  }
@@ -2353,8 +2448,12 @@ var WorkspaceHealthService = class _WorkspaceHealthService {
2353
2448
  const supabase = _getSupabaseInstance();
2354
2449
  if (!supabase) throw new Error("Supabase client not initialized");
2355
2450
  const dashboardConfig = _getDashboardConfigInstance();
2356
- const timezone = dashboardConfig?.dateTimeConfig?.defaultTimezone || "UTC";
2357
- const shiftConfig = dashboardConfig?.shiftConfig;
2451
+ const defaultTimezone = dashboardConfig?.dateTimeConfig?.defaultTimezone || "UTC";
2452
+ if (!passedShiftConfig) {
2453
+ console.warn("[workspaceHealthService.getWorkspaceUptimeTimeline] \u26A0\uFE0F No shiftConfig passed! Falling back to static config. This may cause incorrect shift_id queries.");
2454
+ }
2455
+ const shiftConfig = passedShiftConfig || dashboardConfig?.shiftConfig;
2456
+ const timezone = passedTimezone || shiftConfig?.timezone || defaultTimezone;
2358
2457
  const {
2359
2458
  shiftId,
2360
2459
  shiftLabel,
@@ -2595,18 +2694,22 @@ var WorkspaceHealthService = class _WorkspaceHealthService {
2595
2694
  clearCache() {
2596
2695
  this.cache.clear();
2597
2696
  }
2598
- async calculateWorkspaceUptime(companyId) {
2697
+ async calculateWorkspaceUptime(companyId, passedShiftConfig, timezone) {
2599
2698
  const supabase = _getSupabaseInstance();
2600
2699
  if (!supabase) throw new Error("Supabase client not initialized");
2601
2700
  const dashboardConfig = _getDashboardConfigInstance();
2602
- const timezone = dashboardConfig?.dateTimeConfig?.defaultTimezone || "UTC";
2603
- const shiftConfig = dashboardConfig?.shiftConfig;
2701
+ const defaultTimezone = dashboardConfig?.dateTimeConfig?.defaultTimezone || "UTC";
2702
+ if (!passedShiftConfig) {
2703
+ console.warn("[workspaceHealthService.calculateWorkspaceUptime] \u26A0\uFE0F No shiftConfig passed! Falling back to static config. This may cause incorrect shift_id queries.");
2704
+ }
2705
+ const shiftConfig = passedShiftConfig || dashboardConfig?.shiftConfig;
2706
+ const effectiveTimezone = timezone || shiftConfig?.timezone || defaultTimezone;
2604
2707
  const {
2605
2708
  shiftId,
2606
2709
  date,
2607
2710
  shiftStartDate,
2608
2711
  completedMinutes
2609
- } = this.getShiftTiming(timezone, shiftConfig);
2712
+ } = this.getShiftTiming(effectiveTimezone, shiftConfig);
2610
2713
  const tableName = `performance_metrics_${companyId.replace(/-/g, "_")}`;
2611
2714
  try {
2612
2715
  const { data: queryData, error } = await supabase.from(tableName).select("workspace_id, workspace_display_name, output_hourly, output_array").eq("date", date).eq("shift_id", shiftId);
@@ -2629,7 +2732,7 @@ var WorkspaceHealthService = class _WorkspaceHealthService {
2629
2732
  minuteDate,
2630
2733
  outputHourly,
2631
2734
  outputArray,
2632
- timezone
2735
+ effectiveTimezone
2633
2736
  );
2634
2737
  if (status === "down") {
2635
2738
  currentDownRun += 1;
@@ -4300,7 +4403,7 @@ var useAudioService = () => {
4300
4403
  // src/lib/utils/dateShiftUtils.ts
4301
4404
  function isValidShiftId(shiftId) {
4302
4405
  const id3 = typeof shiftId === "string" ? parseInt(shiftId, 10) : shiftId;
4303
- return id3 === 0 || id3 === 1;
4406
+ return Number.isFinite(id3) && id3 >= 0;
4304
4407
  }
4305
4408
  var getSupabaseClient = () => {
4306
4409
  const url = process.env.NEXT_PUBLIC_SUPABASE_URL;
@@ -6832,11 +6935,12 @@ var useMetrics = (tableName, options) => {
6832
6935
  };
6833
6936
  return { data, isLoading, error, refetch };
6834
6937
  };
6835
- var useWorkspaceDetailedMetrics = (workspaceId, date, shiftId) => {
6938
+ var useWorkspaceDetailedMetrics = (workspaceId, date, shiftId, options) => {
6836
6939
  const entityConfig = useEntityConfig();
6837
6940
  const databaseConfig = useDatabaseConfig();
6838
6941
  const dateTimeConfig = useDateTimeConfig();
6839
- const shiftConfig = useShiftConfig();
6942
+ const staticShiftConfig = useShiftConfig();
6943
+ const shiftConfig = options?.shiftConfig || staticShiftConfig;
6840
6944
  const workspaceConfig = useWorkspaceConfig();
6841
6945
  const supabase = useSupabase();
6842
6946
  const [metrics2, setMetrics] = React23.useState(null);
@@ -6849,11 +6953,12 @@ var useWorkspaceDetailedMetrics = (workspaceId, date, shiftId) => {
6849
6953
  const companyId = entityConfig.companyId || "";
6850
6954
  const metricsTablePrefix = getMetricsTablePrefix();
6851
6955
  const metricsTable = `${metricsTablePrefix}_${companyId.replace(/-/g, "_")}`;
6852
- const defaultTimezone = dateTimeConfig.defaultTimezone;
6956
+ const appTimezone = useAppTimezone();
6957
+ const defaultTimezone = appTimezone || dateTimeConfig.defaultTimezone || "UTC";
6853
6958
  const workspaceMetricsBaseTable = databaseConfig.tables?.workspaces ?? "workspace_metrics";
6854
6959
  const workspaceActionsTable = databaseConfig.tables?.actions ?? "workspace_actions";
6855
6960
  const fetchMetrics = React23.useCallback(async () => {
6856
- if (!workspaceId || isFetchingRef.current) return;
6961
+ if (!workspaceId || isFetchingRef.current || options?.enabled === false) return;
6857
6962
  try {
6858
6963
  isFetchingRef.current = true;
6859
6964
  const currentShift = getCurrentShift(defaultTimezone, shiftConfig);
@@ -6890,6 +6995,16 @@ var useWorkspaceDetailedMetrics = (workspaceId, date, shiftId) => {
6890
6995
  throw new Error(`Invalid JSON response from backend. Received: ${responseText.substring(0, 100)}...`);
6891
6996
  }
6892
6997
  const data = backendData.metrics;
6998
+ if (data && options?.shiftConfig) {
6999
+ const dynamicShiftName = getShiftNameById(
7000
+ data.shift_id,
7001
+ appTimezone || "Asia/Kolkata",
7002
+ // Fallback timezone
7003
+ options.shiftConfig
7004
+ );
7005
+ data.shift_type = dynamicShiftName;
7006
+ console.log(`[useWorkspaceDetailedMetrics] Overriding shift name for ID ${data.shift_id}: ${dynamicShiftName}`);
7007
+ }
6893
7008
  if (!data && !date && shiftId === void 0) {
6894
7009
  console.log("[useWorkspaceDetailedMetrics] No data found for current date/shift, attempting to find most recent data...");
6895
7010
  const fallbackResponse = await fetch(
@@ -7335,7 +7450,7 @@ var useWorkspaceDetailedMetrics = (workspaceId, date, shiftId) => {
7335
7450
  updateQueueRef.current = false;
7336
7451
  setIsLoading(false);
7337
7452
  }
7338
- }, [supabase, workspaceId, date, shiftId, metricsTable, defaultTimezone, shiftConfig, workspaceConfig, companyId]);
7453
+ }, [supabase, workspaceId, date, shiftId, metricsTable, defaultTimezone, shiftConfig, workspaceConfig, companyId, options?.enabled]);
7339
7454
  const queueUpdate = React23.useCallback(() => {
7340
7455
  if (!workspaceId || updateQueueRef.current) return;
7341
7456
  updateQueueRef.current = true;
@@ -7368,7 +7483,7 @@ var useWorkspaceDetailedMetrics = (workspaceId, date, shiftId) => {
7368
7483
  return;
7369
7484
  }
7370
7485
  const channels = [];
7371
- const operationalDate = date || getOperationalDate(defaultTimezone || "UTC");
7486
+ const operationalDate = date || getOperationalDate(defaultTimezone);
7372
7487
  const currentShift = getCurrentShift(defaultTimezone, shiftConfig);
7373
7488
  const queryShiftId = shiftId ?? currentShift.shiftId;
7374
7489
  const metricsChannel = supabase.channel(`workspace-metrics-${workspaceId}`).on(
@@ -7467,11 +7582,170 @@ var useWorkspaceDetailedMetrics = (workspaceId, date, shiftId) => {
7467
7582
  // Force refresh without cache
7468
7583
  };
7469
7584
  };
7585
+ var useLineShiftConfig = (lineId, fallbackConfig) => {
7586
+ const [shiftConfig, setShiftConfig] = React23.useState(fallbackConfig || null);
7587
+ const [isLoading, setIsLoading] = React23.useState(true);
7588
+ const [error, setError] = React23.useState(null);
7589
+ const supabase = useSupabase();
7590
+ React23.useEffect(() => {
7591
+ if (!lineId || lineId === "factory" || lineId === "all") {
7592
+ setShiftConfig(fallbackConfig || null);
7593
+ setIsLoading(false);
7594
+ return;
7595
+ }
7596
+ const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
7597
+ if (!uuidRegex.test(lineId)) {
7598
+ console.warn(`[useShiftConfig] Invalid line ID format: ${lineId}, using fallback`);
7599
+ setShiftConfig(fallbackConfig || null);
7600
+ setIsLoading(false);
7601
+ return;
7602
+ }
7603
+ let mounted = true;
7604
+ const calculateBreakDuration2 = (startTime, endTime) => {
7605
+ const [sh, sm] = startTime.split(":").map(Number);
7606
+ const [eh, em] = endTime.split(":").map(Number);
7607
+ let startMinutes = sh * 60 + sm;
7608
+ let endMinutes = eh * 60 + em;
7609
+ if (endMinutes < startMinutes) {
7610
+ endMinutes += 24 * 60;
7611
+ }
7612
+ return endMinutes - startMinutes;
7613
+ };
7614
+ const fetchShiftConfig = async () => {
7615
+ try {
7616
+ setIsLoading(true);
7617
+ setError(null);
7618
+ console.log(`[useLineShiftConfig] \u{1F50D} Fetching shift config for line: ${lineId}`);
7619
+ const { data: shiftsData, error: shiftsError } = await supabase.from("line_operating_hours").select("shift_id, shift_name, start_time, end_time, breaks, timezone").eq("line_id", lineId);
7620
+ if (shiftsError) {
7621
+ console.error(`[useLineShiftConfig] \u274C Error fetching shifts:`, shiftsError);
7622
+ throw new Error(`Failed to fetch shift config: ${shiftsError.message}`);
7623
+ }
7624
+ if (!shiftsData || shiftsData.length === 0) {
7625
+ console.warn(`[useLineShiftConfig] \u26A0\uFE0F No shift config found for line ${lineId}, using fallback`);
7626
+ if (mounted) {
7627
+ setShiftConfig(fallbackConfig || null);
7628
+ setIsLoading(false);
7629
+ }
7630
+ return;
7631
+ }
7632
+ const stripSeconds = (timeStr) => {
7633
+ if (!timeStr) return timeStr;
7634
+ return timeStr.substring(0, 5);
7635
+ };
7636
+ const mapped = shiftsData.map((shift) => ({
7637
+ shiftId: shift.shift_id,
7638
+ shiftName: shift.shift_name || `Shift ${shift.shift_id}`,
7639
+ startTime: stripSeconds(shift.start_time),
7640
+ endTime: stripSeconds(shift.end_time),
7641
+ breaks: Array.isArray(shift.breaks) ? shift.breaks.map((b) => ({
7642
+ startTime: b.start || b.startTime || "00:00",
7643
+ endTime: b.end || b.endTime || "00:00",
7644
+ duration: calculateBreakDuration2(
7645
+ b.start || b.startTime || "00:00",
7646
+ b.end || b.endTime || "00:00"
7647
+ ),
7648
+ remarks: b.remarks || b.name || ""
7649
+ })) : [],
7650
+ timezone: shift.timezone
7651
+ }));
7652
+ const day = mapped.find((s) => s.shiftId === 0);
7653
+ const night = mapped.find((s) => s.shiftId === 1);
7654
+ const config = {
7655
+ shifts: mapped,
7656
+ timezone: mapped[0]?.timezone,
7657
+ dayShift: day ? { id: day.shiftId, startTime: day.startTime, endTime: day.endTime, name: day.shiftName } : fallbackConfig?.dayShift,
7658
+ nightShift: night ? { id: night.shiftId, startTime: night.startTime, endTime: night.endTime, name: night.shiftName } : fallbackConfig?.nightShift,
7659
+ transitionPeriodMinutes: fallbackConfig?.transitionPeriodMinutes || 0
7660
+ };
7661
+ console.log(`[useLineShiftConfig] \u2705 Built config from DB:`, config);
7662
+ if (mounted) {
7663
+ setShiftConfig(config);
7664
+ setIsLoading(false);
7665
+ }
7666
+ } catch (err) {
7667
+ console.error("[useShiftConfig] Error fetching shift config:", err);
7668
+ if (mounted) {
7669
+ setError(err instanceof Error ? err.message : "Unknown error occurred");
7670
+ setShiftConfig(fallbackConfig || null);
7671
+ setIsLoading(false);
7672
+ }
7673
+ }
7674
+ };
7675
+ fetchShiftConfig();
7676
+ const subscription = supabase.channel(`shift_config_${lineId}`).on(
7677
+ "postgres_changes",
7678
+ {
7679
+ event: "*",
7680
+ // Listen to all events (INSERT, UPDATE, DELETE)
7681
+ schema: "public",
7682
+ table: "line_operating_hours",
7683
+ filter: `line_id=eq.${lineId}`
7684
+ },
7685
+ (payload) => {
7686
+ console.log("[useShiftConfig] Real-time update received:", payload);
7687
+ fetchShiftConfig();
7688
+ }
7689
+ ).subscribe();
7690
+ return () => {
7691
+ mounted = false;
7692
+ subscription.unsubscribe();
7693
+ };
7694
+ }, [lineId, supabase]);
7695
+ return {
7696
+ shiftConfig,
7697
+ isLoading,
7698
+ error
7699
+ };
7700
+ };
7701
+
7702
+ // src/lib/hooks/useDynamicShiftConfig.ts
7703
+ var useDynamicShiftConfig = (lineId) => {
7704
+ const staticShiftConfig = useShiftConfig();
7705
+ const { shiftConfig: dbShiftConfig, isLoading, error } = useLineShiftConfig(lineId, staticShiftConfig);
7706
+ const result = React23.useMemo(() => {
7707
+ console.log(`[useDynamicShiftConfig] \u{1F504} Computing result for lineId: ${lineId}`, {
7708
+ isLoading,
7709
+ hasDbConfig: !!dbShiftConfig,
7710
+ error
7711
+ });
7712
+ if (isLoading) {
7713
+ console.log(`[useDynamicShiftConfig] \u23F3 Still loading, returning null (DO NOT USE until loaded)`);
7714
+ return {
7715
+ shiftConfig: null,
7716
+ isLoading: true,
7717
+ error: null,
7718
+ isFromDatabase: false
7719
+ };
7720
+ }
7721
+ if (dbShiftConfig) {
7722
+ console.log(`[useDynamicShiftConfig] \u2705 Using DB config:`, dbShiftConfig);
7723
+ return {
7724
+ shiftConfig: dbShiftConfig,
7725
+ isLoading: false,
7726
+ error,
7727
+ isFromDatabase: true
7728
+ };
7729
+ }
7730
+ console.log(`[useDynamicShiftConfig] \u26A0\uFE0F No DB config found, falling back to static config`);
7731
+ return {
7732
+ shiftConfig: staticShiftConfig,
7733
+ isLoading: false,
7734
+ error,
7735
+ isFromDatabase: false
7736
+ };
7737
+ }, [dbShiftConfig, staticShiftConfig, isLoading, error, lineId]);
7738
+ return result;
7739
+ };
7740
+
7741
+ // src/lib/hooks/useLineWorkspaceMetrics.ts
7470
7742
  var useLineWorkspaceMetrics = (lineId, options) => {
7471
7743
  const entityConfig = useEntityConfig();
7472
7744
  const databaseConfig = useDatabaseConfig();
7473
7745
  const dateTimeConfig = useDateTimeConfig();
7474
- const shiftConfig = useShiftConfig();
7746
+ const staticShiftConfig = useShiftConfig();
7747
+ const { shiftConfig: dynamicShiftConfig, isLoading: isShiftConfigLoading } = useDynamicShiftConfig(lineId);
7748
+ const shiftConfig = dynamicShiftConfig || staticShiftConfig;
7475
7749
  const timezone = useAppTimezone();
7476
7750
  const supabase = useSupabase();
7477
7751
  const [workspaces, setWorkspaces] = React23.useState([]);
@@ -7479,12 +7753,10 @@ var useLineWorkspaceMetrics = (lineId, options) => {
7479
7753
  const [error, setError] = React23.useState(null);
7480
7754
  const [initialized, setInitialized] = React23.useState(false);
7481
7755
  const queryShiftId = React23.useMemo(() => {
7482
- const currentShift = getCurrentShift(
7483
- dateTimeConfig.defaultTimezone || "Asia/Kolkata",
7484
- shiftConfig
7485
- );
7756
+ const effectiveTimezone = timezone || dateTimeConfig.defaultTimezone || "Asia/Kolkata";
7757
+ const currentShift = getCurrentShift(effectiveTimezone, shiftConfig);
7486
7758
  return options?.initialShiftId !== void 0 ? options.initialShiftId : currentShift.shiftId;
7487
- }, [options?.initialShiftId, dateTimeConfig.defaultTimezone, shiftConfig]);
7759
+ }, [options?.initialShiftId, timezone, dateTimeConfig.defaultTimezone, shiftConfig]);
7488
7760
  const queryDate = React23.useMemo(() => {
7489
7761
  return options?.initialDate || getOperationalDate(timezone || dateTimeConfig.defaultTimezone || "UTC");
7490
7762
  }, [options?.initialDate, timezone, dateTimeConfig.defaultTimezone]);
@@ -7496,7 +7768,7 @@ var useLineWorkspaceMetrics = (lineId, options) => {
7496
7768
  }, [entityConfig.companyId]);
7497
7769
  const schema = databaseConfig.schema ?? "public";
7498
7770
  const fetchWorkspaceMetrics = React23.useCallback(async () => {
7499
- if (!lineId) return;
7771
+ if (!lineId || options?.enabled === false || isShiftConfigLoading) return;
7500
7772
  if (!initialized) {
7501
7773
  setLoading(true);
7502
7774
  }
@@ -7553,7 +7825,7 @@ var useLineWorkspaceMetrics = (lineId, options) => {
7553
7825
  } finally {
7554
7826
  setLoading(false);
7555
7827
  }
7556
- }, [lineId, queryDate, queryShiftId, metricsTable, supabase, entityConfig.companyId]);
7828
+ }, [lineId, queryDate, queryShiftId, metricsTable, supabase, entityConfig.companyId, options?.enabled, isShiftConfigLoading]);
7557
7829
  React23.useEffect(() => {
7558
7830
  if (!initialized) {
7559
7831
  fetchWorkspaceMetrics();
@@ -7583,25 +7855,26 @@ var useLineWorkspaceMetrics = (lineId, options) => {
7583
7855
  supabase.removeChannel(channel);
7584
7856
  }
7585
7857
  };
7586
- }, [lineId, queryDate, queryShiftId, metricsTable, fetchWorkspaceMetrics, initialized, supabase, schema]);
7858
+ }, [lineId, queryDate, queryShiftId, metricsTable, fetchWorkspaceMetrics, initialized, supabase, schema, isShiftConfigLoading]);
7587
7859
  React23.useEffect(() => {
7588
7860
  setInitialized(false);
7589
- }, [lineId, queryDate, queryShiftId]);
7861
+ }, [lineId, queryDate, queryShiftId, isShiftConfigLoading]);
7590
7862
  const refreshWorkspaces = fetchWorkspaceMetrics;
7591
7863
  return React23.useMemo(
7592
7864
  () => ({ workspaces, loading, error, refreshWorkspaces }),
7593
7865
  [workspaces, loading, error, refreshWorkspaces]
7594
7866
  );
7595
7867
  };
7596
- var useHistoricWorkspaceMetrics = (workspaceId, date, shiftId) => {
7868
+ var useHistoricWorkspaceMetrics = (workspaceId, date, shiftId, options) => {
7597
7869
  const supabase = useSupabase();
7598
7870
  const entityConfig = useEntityConfig();
7871
+ const timezone = useAppTimezone();
7599
7872
  const [metrics2, setMetrics] = React23.useState(null);
7600
7873
  const [isLoading, setIsLoading] = React23.useState(true);
7601
7874
  const [error, setError] = React23.useState(null);
7602
7875
  const isFetchingRef = React23.useRef(false);
7603
7876
  const fetchMetrics = React23.useCallback(async () => {
7604
- if (!supabase || !workspaceId || !date || isFetchingRef.current) return;
7877
+ if (!supabase || !workspaceId || !date || isFetchingRef.current || options?.enabled === false) return;
7605
7878
  try {
7606
7879
  isFetchingRef.current = true;
7607
7880
  setIsLoading(true);
@@ -7635,7 +7908,18 @@ var useHistoricWorkspaceMetrics = (workspaceId, date, shiftId) => {
7635
7908
  throw new Error(`Backend API error (${response.status}): ${errorText}`);
7636
7909
  }
7637
7910
  const data = await response.json();
7638
- setMetrics(data.metrics || null);
7911
+ const fetchedMetrics = data.metrics;
7912
+ if (fetchedMetrics && options?.shiftConfig) {
7913
+ const dynamicShiftName = getShiftNameById(
7914
+ fetchedMetrics.shift_id,
7915
+ timezone || "Asia/Kolkata",
7916
+ // Fallback timezone
7917
+ options.shiftConfig
7918
+ );
7919
+ fetchedMetrics.shift_type = dynamicShiftName;
7920
+ console.log(`[useHistoricWorkspaceMetrics] Overriding shift name for ID ${fetchedMetrics.shift_id}: ${dynamicShiftName}`);
7921
+ }
7922
+ setMetrics(fetchedMetrics || null);
7639
7923
  } catch (err) {
7640
7924
  console.error("[useHistoricWorkspaceMetrics] Error fetching historic metrics:", err);
7641
7925
  setError({ message: err.message, code: err.code || "FETCH_ERROR" });
@@ -7644,7 +7928,7 @@ var useHistoricWorkspaceMetrics = (workspaceId, date, shiftId) => {
7644
7928
  setIsLoading(false);
7645
7929
  isFetchingRef.current = false;
7646
7930
  }
7647
- }, [supabase, workspaceId, date, shiftId, entityConfig.companyId]);
7931
+ }, [supabase, workspaceId, date, shiftId, entityConfig.companyId, options?.shiftConfig, timezone, options?.enabled]);
7648
7932
  React23.useEffect(() => {
7649
7933
  fetchMetrics();
7650
7934
  }, [fetchMetrics]);
@@ -7659,8 +7943,11 @@ var useLineDetailedMetrics = (lineIdFromProp) => {
7659
7943
  const entityConfig = useEntityConfig();
7660
7944
  const databaseConfig = useDatabaseConfig();
7661
7945
  const dateTimeConfig = useDateTimeConfig();
7662
- const shiftConfig = useShiftConfig();
7946
+ const staticShiftConfig = useShiftConfig();
7663
7947
  const supabase = useSupabase();
7948
+ const lineIdForShiftConfig = lineIdFromProp === "factory" ? getConfiguredLineIds(entityConfig)[0] : lineIdFromProp;
7949
+ const { shiftConfig: dynamicShiftConfig, isLoading: isShiftConfigLoading } = useDynamicShiftConfig(lineIdForShiftConfig);
7950
+ const shiftConfig = dynamicShiftConfig || staticShiftConfig;
7664
7951
  const [lineData, setLineData] = React23.useState(null);
7665
7952
  const [loading, setLoading] = React23.useState(true);
7666
7953
  const [error, setError] = React23.useState(null);
@@ -7699,8 +7986,10 @@ var useLineDetailedMetrics = (lineIdFromProp) => {
7699
7986
  }
7700
7987
  }, [dashboardService, lineIdToUse, defaultTimezone, shiftConfig, entityConfig]);
7701
7988
  React23.useEffect(() => {
7702
- if (!supabase || !lineIdToUse || !entityConfig.companyId) {
7703
- setLoading(false);
7989
+ if (!supabase || !lineIdToUse || !entityConfig.companyId || isShiftConfigLoading) {
7990
+ if (!isShiftConfigLoading) {
7991
+ setLoading(false);
7992
+ }
7704
7993
  if (!entityConfig.companyId && (!error || error.code !== "SERVICE_ERROR")) {
7705
7994
  setError({ message: "Company ID not configured for metrics subscription.", code: "CONFIG_ERROR" });
7706
7995
  }
@@ -7765,7 +8054,7 @@ var useLineDetailedMetrics = (lineIdFromProp) => {
7765
8054
  channelRef.current = null;
7766
8055
  }
7767
8056
  };
7768
- }, [supabase, lineIdToUse, fetchData, schema, lineMetricsTable, entityConfig, defaultTimezone, shiftConfig, error]);
8057
+ }, [supabase, lineIdToUse, fetchData, schema, lineMetricsTable, entityConfig, defaultTimezone, shiftConfig, isShiftConfigLoading, error]);
7769
8058
  return {
7770
8059
  lineData,
7771
8060
  // This now contains both metrics and line details via LineInfo type
@@ -7778,14 +8067,20 @@ var useLeaderboardMetrics = (date, shiftId, limit = 10, filter2 = "all") => {
7778
8067
  const supabase = useSupabase();
7779
8068
  const entityConfig = useEntityConfig();
7780
8069
  const dateTimeConfig = useDateTimeConfig();
7781
- const shiftConfig = useShiftConfig();
8070
+ const staticShiftConfig = useShiftConfig();
8071
+ const firstLineId = React23.useMemo(() => {
8072
+ const lineIds = getConfiguredLineIds(entityConfig);
8073
+ return lineIds[0];
8074
+ }, [entityConfig]);
8075
+ const { shiftConfig: dynamicShiftConfig, isLoading: isShiftConfigLoading } = useDynamicShiftConfig(firstLineId);
8076
+ const shiftConfig = dynamicShiftConfig || staticShiftConfig;
7782
8077
  const [leaderboard, setLeaderboard] = React23.useState([]);
7783
8078
  const [isLoading, setIsLoading] = React23.useState(true);
7784
8079
  const [error, setError] = React23.useState(null);
7785
8080
  const isFetchingRef = React23.useRef(false);
7786
8081
  const defaultTimezone = dateTimeConfig.defaultTimezone || "UTC";
7787
8082
  const fetchLeaderboard = React23.useCallback(async () => {
7788
- if (!supabase || isFetchingRef.current) return;
8083
+ if (!supabase || isFetchingRef.current || isShiftConfigLoading) return;
7789
8084
  try {
7790
8085
  isFetchingRef.current = true;
7791
8086
  setIsLoading(true);
@@ -7831,7 +8126,7 @@ var useLeaderboardMetrics = (date, shiftId, limit = 10, filter2 = "all") => {
7831
8126
  setIsLoading(false);
7832
8127
  isFetchingRef.current = false;
7833
8128
  }
7834
- }, [supabase, date, shiftId, limit, filter2, entityConfig.companyId, defaultTimezone, shiftConfig]);
8129
+ }, [supabase, date, shiftId, limit, filter2, entityConfig.companyId, defaultTimezone, shiftConfig, isShiftConfigLoading]);
7835
8130
  React23.useEffect(() => {
7836
8131
  fetchLeaderboard();
7837
8132
  }, [fetchLeaderboard]);
@@ -7847,8 +8142,22 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId, userAccessibleLineIds
7847
8142
  const entityConfig = useEntityConfig();
7848
8143
  const databaseConfig = useDatabaseConfig();
7849
8144
  const dateTimeConfig = useDateTimeConfig();
7850
- const shiftConfig = useShiftConfig();
7851
- const defaultTimezone = dateTimeConfig?.defaultTimezone || "UTC";
8145
+ const isFactoryView = lineId === (entityConfig.factoryViewId || "factory");
8146
+ const firstLineId = React23.useMemo(() => {
8147
+ const configuredLineIds = getConfiguredLineIds(entityConfig);
8148
+ return configuredLineIds.length > 0 ? configuredLineIds[0] : void 0;
8149
+ }, [entityConfig]);
8150
+ const lineIdForShiftConfig = isFactoryView ? firstLineId : lineId;
8151
+ const { shiftConfig, isLoading: shiftLoading, isFromDatabase } = useDynamicShiftConfig(lineIdForShiftConfig);
8152
+ console.log(`[useDashboardMetrics] \u{1F3AF} Shift config for line ${lineId}:`, {
8153
+ isFactoryView,
8154
+ lineIdForShiftConfig,
8155
+ firstLineId,
8156
+ isFromDatabase,
8157
+ shiftConfig: shiftConfig ? { shifts: shiftConfig.shifts?.length, timezone: shiftConfig.timezone } : null
8158
+ });
8159
+ const appTimezone = useAppTimezone();
8160
+ const defaultTimezone = appTimezone || dateTimeConfig?.defaultTimezone || "UTC";
7852
8161
  const configuredLineMetricsTable = databaseConfig?.tables?.lineMetrics ?? "line_metrics";
7853
8162
  const schema = databaseConfig?.schema ?? "public";
7854
8163
  const supabase = useSupabase();
@@ -7874,8 +8183,8 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId, userAccessibleLineIds
7874
8183
  const fetchAllMetrics = React23.useCallback(async () => {
7875
8184
  const currentLineIdToUse = lineIdRef.current;
7876
8185
  console.log("[useDashboardMetrics] Fetching from backend API. lineId:", currentLineIdToUse);
7877
- if (!currentLineIdToUse || !supabase || isFetchingRef.current || companySpecificMetricsTable.includes("unknown_company")) {
7878
- if (!metrics2?.workspaceMetrics?.length && !metrics2?.lineMetrics?.length) setIsLoading(false);
8186
+ if (!currentLineIdToUse || !supabase || isFetchingRef.current || shiftLoading || companySpecificMetricsTable.includes("unknown_company")) {
8187
+ if (!metrics2?.workspaceMetrics?.length && !metrics2?.lineMetrics?.length && !shiftLoading) setIsLoading(false);
7879
8188
  if (companySpecificMetricsTable.includes("unknown_company") && !error) {
7880
8189
  setError({ message: "Company ID not configured for metrics table.", code: "CONFIG_ERROR" });
7881
8190
  }
@@ -7894,7 +8203,7 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId, userAccessibleLineIds
7894
8203
  if (targetLineIds.length === 0) {
7895
8204
  throw new Error("No target line IDs available for fetching metrics.");
7896
8205
  }
7897
- const isFactoryView = currentLineIdToUse === (entityConfig.factoryViewId || "factory");
8206
+ const isFactoryView2 = currentLineIdToUse === (entityConfig.factoryViewId || "factory");
7898
8207
  const { data: { session } } = await supabase.auth.getSession();
7899
8208
  console.log("[useDashboardMetrics] Session check:", {
7900
8209
  hasSession: !!session,
@@ -7908,7 +8217,7 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId, userAccessibleLineIds
7908
8217
  if (!apiUrl) {
7909
8218
  throw new Error("Backend URL is not configured. Please set NEXT_PUBLIC_BACKEND_URL in your environment.");
7910
8219
  }
7911
- const lineIdsParam = isFactoryView ? `line_ids=${targetLineIds.join(",")}` : `line_id=${targetLineIds[0]}`;
8220
+ const lineIdsParam = isFactoryView2 ? `line_ids=${targetLineIds.join(",")}` : `line_id=${targetLineIds[0]}`;
7912
8221
  const url = `${apiUrl}/api/dashboard/metrics?${lineIdsParam}&date=${operationalDate}&shift_id=${currentShiftDetails.shiftId}&company_id=${entityConfig.companyId}`;
7913
8222
  console.log("[useDashboardMetrics] Calling backend API:", {
7914
8223
  url,
@@ -7987,8 +8296,10 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId, userAccessibleLineIds
7987
8296
  metrics2?.lineMetrics?.length || 0,
7988
8297
  companySpecificMetricsTable,
7989
8298
  entityConfig,
8299
+ appTimezone,
7990
8300
  defaultTimezone,
7991
- shiftConfig
8301
+ shiftConfig,
8302
+ shiftLoading
7992
8303
  ]);
7993
8304
  const fetchAllMetricsRef = React23.useRef(fetchAllMetrics);
7994
8305
  React23.useEffect(() => {
@@ -8002,10 +8313,10 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId, userAccessibleLineIds
8002
8313
  fetchAllMetricsRef.current();
8003
8314
  }, [supabase]);
8004
8315
  React23.useEffect(() => {
8005
- if (lineId && supabase) {
8316
+ if (lineId && supabase && !shiftLoading) {
8006
8317
  fetchAllMetrics();
8007
8318
  }
8008
- }, [lineId, supabase, fetchAllMetrics]);
8319
+ }, [lineId, supabase, fetchAllMetrics, shiftLoading]);
8009
8320
  React23.useEffect(() => {
8010
8321
  const currentLineIdToUse = lineIdRef.current;
8011
8322
  if (!currentLineIdToUse || !supabase || companySpecificMetricsTable.includes("unknown_company") || !entityConfig.companyId) {
@@ -8050,7 +8361,9 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId, userAccessibleLineIds
8050
8361
  schema,
8051
8362
  entityConfig?.companyId,
8052
8363
  entityConfig?.factoryViewId,
8364
+ appTimezone,
8053
8365
  defaultTimezone,
8366
+ shiftConfig,
8054
8367
  lineId,
8055
8368
  userAccessibleLineIds
8056
8369
  ]);
@@ -8062,145 +8375,7 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId, userAccessibleLineIds
8062
8375
  refetch: fetchAllMetrics
8063
8376
  };
8064
8377
  };
8065
- var useLineShiftConfig = (lineId, fallbackConfig) => {
8066
- const [shiftConfig, setShiftConfig] = React23.useState(fallbackConfig || null);
8067
- const [isLoading, setIsLoading] = React23.useState(true);
8068
- const [error, setError] = React23.useState(null);
8069
- const supabase = useSupabase();
8070
- React23.useEffect(() => {
8071
- if (!lineId || lineId === "factory" || lineId === "all") {
8072
- setShiftConfig(fallbackConfig || null);
8073
- setIsLoading(false);
8074
- return;
8075
- }
8076
- const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
8077
- if (!uuidRegex.test(lineId)) {
8078
- console.warn(`[useShiftConfig] Invalid line ID format: ${lineId}, using fallback`);
8079
- setShiftConfig(fallbackConfig || null);
8080
- setIsLoading(false);
8081
- return;
8082
- }
8083
- let mounted = true;
8084
- const fetchShiftConfig = async () => {
8085
- try {
8086
- setIsLoading(true);
8087
- setError(null);
8088
- console.log(`[useLineShiftConfig] \u{1F50D} Fetching shift config for line: ${lineId}`);
8089
- const { data: dayShift, error: dayError } = await supabase.from("line_operating_hours").select("start_time, end_time, breaks").eq("line_id", lineId).eq("shift_id", 0).maybeSingle();
8090
- const { data: nightShift, error: nightError } = await supabase.from("line_operating_hours").select("start_time, end_time, breaks").eq("line_id", lineId).eq("shift_id", 1).maybeSingle();
8091
- console.log(`[useLineShiftConfig] \u{1F4CA} Day shift data:`, dayShift);
8092
- console.log(`[useLineShiftConfig] \u{1F319} Night shift data:`, nightShift);
8093
- if (dayError || nightError) {
8094
- console.error(`[useLineShiftConfig] \u274C Error fetching:`, { dayError, nightError });
8095
- throw new Error(`Failed to fetch shift config: ${dayError?.message || nightError?.message}`);
8096
- }
8097
- if (!dayShift && !nightShift) {
8098
- console.warn(`[useLineShiftConfig] \u26A0\uFE0F No shift config found for line ${lineId}, using fallback`);
8099
- if (mounted) {
8100
- setShiftConfig(fallbackConfig || null);
8101
- setIsLoading(false);
8102
- }
8103
- return;
8104
- }
8105
- const stripSeconds = (timeStr) => {
8106
- if (!timeStr) return timeStr;
8107
- return timeStr.substring(0, 5);
8108
- };
8109
- const config = {
8110
- dayShift: dayShift ? {
8111
- id: 0,
8112
- startTime: stripSeconds(dayShift.start_time),
8113
- endTime: stripSeconds(dayShift.end_time)
8114
- } : fallbackConfig?.dayShift || { id: 0, startTime: "06:00", endTime: "18:00" },
8115
- nightShift: nightShift ? {
8116
- id: 1,
8117
- startTime: stripSeconds(nightShift.start_time),
8118
- endTime: stripSeconds(nightShift.end_time)
8119
- } : fallbackConfig?.nightShift || { id: 1, startTime: "18:00", endTime: "06:00" },
8120
- transitionPeriodMinutes: fallbackConfig?.transitionPeriodMinutes || 0
8121
- };
8122
- console.log(`[useLineShiftConfig] \u2705 Built config from DB:`, config);
8123
- if (mounted) {
8124
- setShiftConfig(config);
8125
- setIsLoading(false);
8126
- }
8127
- } catch (err) {
8128
- console.error("[useShiftConfig] Error fetching shift config:", err);
8129
- if (mounted) {
8130
- setError(err instanceof Error ? err.message : "Unknown error occurred");
8131
- setShiftConfig(fallbackConfig || null);
8132
- setIsLoading(false);
8133
- }
8134
- }
8135
- };
8136
- fetchShiftConfig();
8137
- const subscription = supabase.channel(`shift_config_${lineId}`).on(
8138
- "postgres_changes",
8139
- {
8140
- event: "*",
8141
- // Listen to all events (INSERT, UPDATE, DELETE)
8142
- schema: "public",
8143
- table: "line_operating_hours",
8144
- filter: `line_id=eq.${lineId}`
8145
- },
8146
- (payload) => {
8147
- console.log("[useShiftConfig] Real-time update received:", payload);
8148
- fetchShiftConfig();
8149
- }
8150
- ).subscribe();
8151
- return () => {
8152
- mounted = false;
8153
- subscription.unsubscribe();
8154
- };
8155
- }, [lineId, supabase]);
8156
- return {
8157
- shiftConfig,
8158
- isLoading,
8159
- error
8160
- };
8161
- };
8162
-
8163
- // src/lib/hooks/useDynamicShiftConfig.ts
8164
- var useDynamicShiftConfig = (lineId) => {
8165
- const staticShiftConfig = useShiftConfig();
8166
- const { shiftConfig: dbShiftConfig, isLoading, error } = useLineShiftConfig(lineId, staticShiftConfig);
8167
- const result = React23.useMemo(() => {
8168
- console.log(`[useDynamicShiftConfig] \u{1F504} Computing result for lineId: ${lineId}`, {
8169
- isLoading,
8170
- hasDbConfig: !!dbShiftConfig,
8171
- error
8172
- });
8173
- if (isLoading) {
8174
- console.log(`[useDynamicShiftConfig] \u23F3 Still loading, using static config temporarily`);
8175
- return {
8176
- shiftConfig: staticShiftConfig,
8177
- isLoading: true,
8178
- error: null,
8179
- isFromDatabase: false
8180
- };
8181
- }
8182
- if (dbShiftConfig) {
8183
- console.log(`[useDynamicShiftConfig] \u2705 Using DB config:`, dbShiftConfig);
8184
- return {
8185
- shiftConfig: dbShiftConfig,
8186
- isLoading: false,
8187
- error,
8188
- isFromDatabase: true
8189
- };
8190
- }
8191
- console.log(`[useDynamicShiftConfig] \u26A0\uFE0F Falling back to static config`);
8192
- return {
8193
- shiftConfig: staticShiftConfig,
8194
- isLoading: false,
8195
- error,
8196
- isFromDatabase: false
8197
- };
8198
- }, [dbShiftConfig, staticShiftConfig, isLoading, error, lineId]);
8199
- return result;
8200
- };
8201
-
8202
- // src/lib/hooks/useLineKPIs.ts
8203
- var useLineKPIs = ({ lineId }) => {
8378
+ var useLineKPIs = ({ lineId, enabled }) => {
8204
8379
  useDashboardConfig();
8205
8380
  const entityConfig = useEntityConfig();
8206
8381
  const isFactoryView = lineId === (entityConfig.factoryViewId || "factory");
@@ -8212,7 +8387,7 @@ var useLineKPIs = ({ lineId }) => {
8212
8387
  return configuredLineIds.length > 0 ? configuredLineIds[0] : void 0;
8213
8388
  }, [entityConfig]);
8214
8389
  const lineIdForShiftConfig = isFactoryView ? firstLineId : lineId;
8215
- const { shiftConfig: dynamicShiftConfig, isFromDatabase } = useDynamicShiftConfig(lineIdForShiftConfig);
8390
+ const { shiftConfig: dynamicShiftConfig, isFromDatabase, isLoading: isShiftConfigLoading } = useDynamicShiftConfig(lineIdForShiftConfig);
8216
8391
  const shiftConfig = dynamicShiftConfig;
8217
8392
  console.log(`[useLineKPIs] \u{1F3AF} Shift config for line ${lineId}:`, {
8218
8393
  isFactoryView,
@@ -8233,7 +8408,8 @@ var useLineKPIs = ({ lineId }) => {
8233
8408
  const updateQueueRef = React23.useRef(false);
8234
8409
  const updateTimeoutRef = React23.useRef(null);
8235
8410
  const queueUpdateRef = React23.useRef(void 0);
8236
- const defaultTimezone = dateTimeConfig.defaultTimezone;
8411
+ const appTimezone = useAppTimezone();
8412
+ const timezone = appTimezone || dateTimeConfig.defaultTimezone || "UTC";
8237
8413
  const schema = databaseConfig.schema ?? "public";
8238
8414
  const lineMetricsTable = databaseConfig.tables?.lineMetrics ?? "line_metrics";
8239
8415
  const companySpecificMetricsTable = React23.useMemo(
@@ -8245,14 +8421,14 @@ var useLineKPIs = ({ lineId }) => {
8245
8421
  }, [lineId]);
8246
8422
  const fetchKPIs = React23.useCallback(async () => {
8247
8423
  const currentLineId = lineIdRef.current;
8248
- if (!currentLineId || isFetchingRef.current) {
8424
+ if (!currentLineId || isFetchingRef.current || enabled === false || isShiftConfigLoading) {
8249
8425
  return;
8250
8426
  }
8251
8427
  isFetchingRef.current = true;
8252
8428
  setIsLoading(true);
8253
8429
  setError(null);
8254
8430
  try {
8255
- const currentShiftDetails = getCurrentShift(defaultTimezone, shiftConfig);
8431
+ const currentShiftDetails = getCurrentShift(timezone, shiftConfig ?? void 0);
8256
8432
  const operationalDate = currentShiftDetails.date;
8257
8433
  const { data: { session } } = await supabase.auth.getSession();
8258
8434
  if (!session?.access_token) {
@@ -8301,7 +8477,7 @@ var useLineKPIs = ({ lineId }) => {
8301
8477
  isFetchingRef.current = false;
8302
8478
  updateQueueRef.current = false;
8303
8479
  }
8304
- }, [defaultTimezone, shiftConfig, entityConfig, supabase]);
8480
+ }, [timezone, shiftConfig, entityConfig, supabase, enabled, isShiftConfigLoading]);
8305
8481
  const queueUpdate = React23.useCallback(() => {
8306
8482
  if (updateTimeoutRef.current) {
8307
8483
  clearTimeout(updateTimeoutRef.current);
@@ -8321,7 +8497,7 @@ var useLineKPIs = ({ lineId }) => {
8321
8497
  return;
8322
8498
  }
8323
8499
  fetchKPIs();
8324
- const currentShiftDetails = getCurrentShift(defaultTimezone);
8500
+ const currentShiftDetails = getCurrentShift(timezone, shiftConfig ?? void 0);
8325
8501
  const operationalDate = currentShiftDetails.date;
8326
8502
  const factoryViewIdentifier = entityConfig.factoryViewId || "factory";
8327
8503
  const targetLineIds = currentLineId === factoryViewIdentifier ? getConfiguredLineIds(entityConfig) : [currentLineId];
@@ -8374,7 +8550,7 @@ var useLineKPIs = ({ lineId }) => {
8374
8550
  clearTimeout(updateTimeoutRef.current);
8375
8551
  }
8376
8552
  };
8377
- }, [lineId, supabase, entityConfig, schema, lineMetricsTable, companySpecificMetricsTable, defaultTimezone, shiftConfig]);
8553
+ }, [lineId, supabase, entityConfig, schema, lineMetricsTable, companySpecificMetricsTable, timezone, shiftConfig, isShiftConfigLoading]);
8378
8554
  return {
8379
8555
  kpis,
8380
8556
  isLoading,
@@ -8386,15 +8562,17 @@ var useRealtimeLineMetrics = ({
8386
8562
  lineId,
8387
8563
  date: urlDate,
8388
8564
  shiftId: urlShiftId,
8389
- onMetricsUpdate
8565
+ onMetricsUpdate,
8566
+ enabled
8390
8567
  }) => {
8391
8568
  const supabase = useSupabase();
8392
8569
  const entityConfig = useEntityConfig();
8393
8570
  useDatabaseConfig();
8394
8571
  const dateTimeConfig = useDateTimeConfig();
8395
- useShiftConfig();
8396
- const { shiftConfig: dynamicShiftConfig } = useDynamicShiftConfig(lineId);
8397
- const shiftConfig = dynamicShiftConfig;
8572
+ const staticShiftConfig = useShiftConfig();
8573
+ const timezone = useAppTimezone();
8574
+ const { shiftConfig: dynamicShiftConfig, isLoading: isShiftConfigLoading } = useDynamicShiftConfig(lineId);
8575
+ const shiftConfig = dynamicShiftConfig || staticShiftConfig;
8398
8576
  const [metrics2, setMetrics] = React23.useState(null);
8399
8577
  const [lineDetails, setLineDetails] = React23.useState(null);
8400
8578
  const [loading, setLoading] = React23.useState(true);
@@ -8405,16 +8583,16 @@ var useRealtimeLineMetrics = ({
8405
8583
  const isFetchingRef = React23.useRef(false);
8406
8584
  const channelsRef = React23.useRef([]);
8407
8585
  const fetchTimeoutRef = React23.useRef(null);
8408
- const currentShift = React23.useMemo(() => getCurrentShift(dateTimeConfig.defaultTimezone || "Asia/Kolkata", shiftConfig), [dateTimeConfig.defaultTimezone, shiftConfig]);
8586
+ const effectiveTimezone = timezone || dateTimeConfig.defaultTimezone || "Asia/Kolkata";
8587
+ const currentShift = React23.useMemo(() => getCurrentShift(effectiveTimezone, shiftConfig), [effectiveTimezone, shiftConfig]);
8409
8588
  const shiftId = React23.useMemo(
8410
8589
  () => urlShiftId !== void 0 ? urlShiftId : currentShift.shiftId,
8411
8590
  [urlShiftId, currentShift.shiftId]
8412
8591
  );
8413
- const timezone = useAppTimezone();
8414
- const date = React23.useMemo(() => urlDate || getOperationalDate(timezone || dateTimeConfig.defaultTimezone || "UTC"), [urlDate, timezone, dateTimeConfig.defaultTimezone]);
8592
+ const date = React23.useMemo(() => urlDate || getOperationalDate(effectiveTimezone), [urlDate, effectiveTimezone]);
8415
8593
  const fetchData = React23.useCallback(async () => {
8416
8594
  try {
8417
- if (!lineIdRef.current || isFetchingRef.current) return;
8595
+ if (!lineIdRef.current || isFetchingRef.current || enabled === false) return;
8418
8596
  isFetchingRef.current = true;
8419
8597
  if (!initialized) {
8420
8598
  setLoading(true);
@@ -8612,7 +8790,7 @@ var useRealtimeLineMetrics = ({
8612
8790
  updateQueueRef.current = false;
8613
8791
  isFetchingRef.current = false;
8614
8792
  }
8615
- }, [supabase, date, shiftId, urlShiftId, onMetricsUpdate, entityConfig, dateTimeConfig.defaultTimezone]);
8793
+ }, [supabase, date, shiftId, urlShiftId, onMetricsUpdate, entityConfig, dateTimeConfig.defaultTimezone, enabled, shiftConfig]);
8616
8794
  const queueUpdate = React23.useCallback(() => {
8617
8795
  console.log("[useRealtimeLineMetrics] Update queued, debouncing...");
8618
8796
  if (fetchTimeoutRef.current) {
@@ -8694,13 +8872,27 @@ var useRealtimeLineMetrics = ({
8694
8872
  });
8695
8873
  channelsRef.current = [lineMetricsChannel, metricsChannel];
8696
8874
  }, [supabase, queueUpdate, urlDate, shiftId, entityConfig, dateTimeConfig.defaultTimezone]);
8875
+ const prevShiftIdRef = React23.useRef(void 0);
8697
8876
  React23.useEffect(() => {
8698
8877
  if (!lineId) return;
8699
8878
  lineIdRef.current = lineId;
8700
- if (!initialized) {
8879
+ const shouldFetch = !initialized && (!isShiftConfigLoading || enabled === false);
8880
+ const shiftIdChanged = prevShiftIdRef.current !== void 0 && prevShiftIdRef.current !== shiftId && !isShiftConfigLoading;
8881
+ if (shouldFetch || shiftIdChanged) {
8882
+ console.log("[useRealtimeLineMetrics] Fetching data:", {
8883
+ initialized,
8884
+ isShiftConfigLoading,
8885
+ enabled,
8886
+ shiftIdChanged,
8887
+ prevShiftId: prevShiftIdRef.current,
8888
+ currentShiftId: shiftId
8889
+ });
8701
8890
  fetchData();
8702
8891
  }
8703
8892
  setupSubscriptions();
8893
+ if (!isShiftConfigLoading) {
8894
+ prevShiftIdRef.current = shiftId;
8895
+ }
8704
8896
  return () => {
8705
8897
  if (fetchTimeoutRef.current) {
8706
8898
  clearTimeout(fetchTimeoutRef.current);
@@ -8715,7 +8907,7 @@ var useRealtimeLineMetrics = ({
8715
8907
  });
8716
8908
  }
8717
8909
  };
8718
- }, [lineId, fetchData, setupSubscriptions, initialized, supabase]);
8910
+ }, [lineId, fetchData, setupSubscriptions, initialized, supabase, isShiftConfigLoading, enabled, shiftId]);
8719
8911
  React23.useEffect(() => {
8720
8912
  setInitialized(false);
8721
8913
  }, [lineId, date, shiftId]);
@@ -9433,14 +9625,20 @@ var useFactoryOverviewMetrics = (date, shiftId) => {
9433
9625
  const supabase = useSupabase();
9434
9626
  const entityConfig = useEntityConfig();
9435
9627
  const dateTimeConfig = useDateTimeConfig();
9436
- const shiftConfig = useShiftConfig();
9628
+ const staticShiftConfig = useShiftConfig();
9629
+ const firstLineId = React23.useMemo(() => {
9630
+ const lineIds = getConfiguredLineIds(entityConfig);
9631
+ return lineIds[0];
9632
+ }, [entityConfig]);
9633
+ const { shiftConfig: dynamicShiftConfig, isLoading: isShiftConfigLoading } = useDynamicShiftConfig(firstLineId);
9634
+ const shiftConfig = dynamicShiftConfig || staticShiftConfig;
9437
9635
  const [metrics2, setMetrics] = React23.useState(null);
9438
9636
  const [isLoading, setIsLoading] = React23.useState(true);
9439
9637
  const [error, setError] = React23.useState(null);
9440
9638
  const isFetchingRef = React23.useRef(false);
9441
9639
  const defaultTimezone = dateTimeConfig.defaultTimezone || "UTC";
9442
9640
  const fetchMetrics = React23.useCallback(async () => {
9443
- if (!supabase || isFetchingRef.current) return;
9641
+ if (!supabase || isFetchingRef.current || isShiftConfigLoading) return;
9444
9642
  try {
9445
9643
  isFetchingRef.current = true;
9446
9644
  setIsLoading(true);
@@ -9489,7 +9687,7 @@ var useFactoryOverviewMetrics = (date, shiftId) => {
9489
9687
  setIsLoading(false);
9490
9688
  isFetchingRef.current = false;
9491
9689
  }
9492
- }, [supabase, date, shiftId, entityConfig, defaultTimezone, shiftConfig]);
9690
+ }, [supabase, date, shiftId, entityConfig, defaultTimezone, shiftConfig, isShiftConfigLoading]);
9493
9691
  React23.useEffect(() => {
9494
9692
  fetchMetrics();
9495
9693
  }, [fetchMetrics]);
@@ -9895,14 +10093,24 @@ var useActiveBreaks = (lineIds) => {
9895
10093
  }
9896
10094
  return { elapsedMinutes, remainingMinutes };
9897
10095
  };
9898
- const getCurrentShift2 = (currentMinutes, dayStart, nightStart) => {
9899
- const dayStartMinutes = parseTimeToMinutes2(dayStart);
9900
- const nightStartMinutes = parseTimeToMinutes2(nightStart);
9901
- if (nightStartMinutes < dayStartMinutes) {
9902
- return currentMinutes >= nightStartMinutes && currentMinutes < dayStartMinutes ? "night" : "day";
10096
+ const isTimeInShift = (startTime, endTime, currentMinutes) => {
10097
+ const startMinutes = parseTimeToMinutes2(startTime);
10098
+ const endMinutes = parseTimeToMinutes2(endTime);
10099
+ if (endMinutes < startMinutes) {
10100
+ return currentMinutes >= startMinutes || currentMinutes < endMinutes;
9903
10101
  } else {
9904
- return currentMinutes >= dayStartMinutes && currentMinutes < nightStartMinutes ? "day" : "night";
10102
+ return currentMinutes >= startMinutes && currentMinutes < endMinutes;
10103
+ }
10104
+ };
10105
+ const findActiveShift = (shifts, currentMinutes) => {
10106
+ for (const shift of shifts) {
10107
+ const startTime = shift.start_time || "00:00";
10108
+ const endTime = shift.end_time || "00:00";
10109
+ if (isTimeInShift(startTime, endTime, currentMinutes)) {
10110
+ return shift;
10111
+ }
9905
10112
  }
10113
+ return null;
9906
10114
  };
9907
10115
  const checkActiveBreaks = React23.useCallback(async () => {
9908
10116
  try {
@@ -9917,23 +10125,28 @@ var useActiveBreaks = (lineIds) => {
9917
10125
  return;
9918
10126
  }
9919
10127
  const currentMinutes = getCurrentTimeInMinutes();
9920
- const { data: dayShifts, error: dayError } = await supabase.from("line_operating_hours").select("line_id, start_time, end_time, breaks").eq("shift_id", 0).in("line_id", validLineIds);
9921
- const { data: nightShifts, error: nightError } = await supabase.from("line_operating_hours").select("line_id, start_time, end_time, breaks").eq("shift_id", 1).in("line_id", validLineIds);
9922
- if (dayError || nightError) {
10128
+ const { data: allShifts, error: shiftsError } = await supabase.from("line_operating_hours").select("line_id, shift_id, shift_name, start_time, end_time, breaks").in("line_id", validLineIds).order("shift_id");
10129
+ if (shiftsError) {
9923
10130
  throw new Error("Failed to fetch shift configurations");
9924
10131
  }
9925
10132
  const foundActiveBreaks = [];
10133
+ const shiftsByLine = /* @__PURE__ */ new Map();
10134
+ for (const shift of allShifts || []) {
10135
+ const lineShifts = shiftsByLine.get(shift.line_id) || [];
10136
+ lineShifts.push(shift);
10137
+ shiftsByLine.set(shift.line_id, lineShifts);
10138
+ }
9926
10139
  for (const lineId of validLineIds) {
9927
- const dayShift = dayShifts?.find((s) => s.line_id === lineId);
9928
- const nightShift = nightShifts?.find((s) => s.line_id === lineId);
9929
- if (!dayShift || !nightShift) continue;
9930
- const currentShift = getCurrentShift2(
9931
- currentMinutes,
9932
- dayShift.start_time || "06:00",
9933
- nightShift.start_time || "18:00"
9934
- );
9935
- const activeShift = currentShift === "day" ? dayShift : nightShift;
9936
- const shiftName = currentShift === "day" ? "Day Shift" : "Night Shift";
10140
+ const lineShifts = shiftsByLine.get(lineId);
10141
+ if (!lineShifts || lineShifts.length === 0) continue;
10142
+ const activeShift = findActiveShift(lineShifts, currentMinutes);
10143
+ if (!activeShift) continue;
10144
+ const getDefaultShiftName = (shiftId) => {
10145
+ if (shiftId === 0) return "Day Shift";
10146
+ if (shiftId === 1) return "Night Shift";
10147
+ return `Shift ${shiftId}`;
10148
+ };
10149
+ const shiftName = activeShift.shift_name || getDefaultShiftName(activeShift.shift_id);
9937
10150
  let breaks = [];
9938
10151
  if (activeShift.breaks) {
9939
10152
  if (Array.isArray(activeShift.breaks)) {
@@ -10008,8 +10221,12 @@ var useAllWorkspaceMetrics = (options) => {
10008
10221
  const entityConfig = useEntityConfig();
10009
10222
  const databaseConfig = useDatabaseConfig();
10010
10223
  const dateTimeConfig = useDateTimeConfig();
10011
- const shiftConfig = useShiftConfig();
10224
+ const staticShiftConfig = useShiftConfig();
10012
10225
  const timezone = useAppTimezone();
10226
+ const configuredLineIds = React23.useMemo(() => getConfiguredLineIds(entityConfig), [entityConfig]);
10227
+ const representativeLineId = options?.allowedLineIds?.[0] || configuredLineIds[0];
10228
+ const { shiftConfig: dynamicShiftConfig, isLoading: isShiftConfigLoading } = useDynamicShiftConfig(representativeLineId);
10229
+ const shiftConfig = dynamicShiftConfig || staticShiftConfig;
10013
10230
  const supabase = useSupabase();
10014
10231
  const [workspaces, setWorkspaces] = React23.useState([]);
10015
10232
  const [loading, setLoading] = React23.useState(true);
@@ -10018,12 +10235,15 @@ var useAllWorkspaceMetrics = (options) => {
10018
10235
  const fetchTimeoutRef = React23.useRef(null);
10019
10236
  const isFetchingRef = React23.useRef(false);
10020
10237
  const queryShiftId = React23.useMemo(() => {
10238
+ if (options?.initialShiftId !== void 0) {
10239
+ return options.initialShiftId;
10240
+ }
10021
10241
  const currentShift = getCurrentShift(
10022
- dateTimeConfig.defaultTimezone || "Asia/Kolkata",
10242
+ timezone || dateTimeConfig.defaultTimezone || "Asia/Kolkata",
10023
10243
  shiftConfig
10024
10244
  );
10025
- return options?.initialShiftId !== void 0 ? options.initialShiftId : currentShift.shiftId;
10026
- }, [options?.initialShiftId, dateTimeConfig.defaultTimezone, shiftConfig]);
10245
+ return currentShift.shiftId;
10246
+ }, [options?.initialShiftId, timezone, dateTimeConfig.defaultTimezone, shiftConfig]);
10027
10247
  const queryDate = React23.useMemo(() => {
10028
10248
  return options?.initialDate || getOperationalDate(timezone || dateTimeConfig.defaultTimezone || "UTC");
10029
10249
  }, [options?.initialDate, timezone, dateTimeConfig.defaultTimezone]);
@@ -10035,7 +10255,7 @@ var useAllWorkspaceMetrics = (options) => {
10035
10255
  }, [entityConfig.companyId]);
10036
10256
  const schema = databaseConfig.schema ?? "public";
10037
10257
  const fetchWorkspaceMetrics = React23.useCallback(async () => {
10038
- if (isFetchingRef.current) {
10258
+ if (isFetchingRef.current || options?.enabled === false || isShiftConfigLoading) {
10039
10259
  return;
10040
10260
  }
10041
10261
  isFetchingRef.current = true;
@@ -10045,9 +10265,9 @@ var useAllWorkspaceMetrics = (options) => {
10045
10265
  setError(null);
10046
10266
  try {
10047
10267
  const allConfiguredLineIds = getConfiguredLineIds(entityConfig);
10048
- const configuredLineIds = options?.allowedLineIds ? allConfiguredLineIds.filter((id3) => options.allowedLineIds.includes(id3)) : allConfiguredLineIds;
10268
+ const configuredLineIds2 = options?.allowedLineIds ? allConfiguredLineIds.filter((id3) => options.allowedLineIds.includes(id3)) : allConfiguredLineIds;
10049
10269
  let enabledWorkspaceIds = [];
10050
- for (const lineId of configuredLineIds) {
10270
+ for (const lineId of configuredLineIds2) {
10051
10271
  const workspaces2 = await workspaceService.getWorkspaces(lineId);
10052
10272
  const enabledIds = workspaces2.filter((ws) => ws.enable === true).map((ws) => ws.id);
10053
10273
  enabledWorkspaceIds.push(...enabledIds);
@@ -10108,7 +10328,7 @@ var useAllWorkspaceMetrics = (options) => {
10108
10328
  setLoading(false);
10109
10329
  isFetchingRef.current = false;
10110
10330
  }
10111
- }, [queryDate, queryShiftId, metricsTable, supabase, entityConfig.companyId, entityConfig, options?.allowedLineIds]);
10331
+ }, [queryDate, queryShiftId, metricsTable, supabase, entityConfig.companyId, entityConfig, options?.allowedLineIds, options?.enabled, isShiftConfigLoading]);
10112
10332
  React23.useEffect(() => {
10113
10333
  if (!initialized) {
10114
10334
  fetchWorkspaceMetrics();
@@ -10587,7 +10807,7 @@ function useClipTypes() {
10587
10807
  refresh: fetchClipTypes
10588
10808
  };
10589
10809
  }
10590
- function useClipTypesWithCounts(workspaceId, date, shiftId, totalOutput) {
10810
+ function useClipTypesWithCounts(workspaceId, date, shiftId, totalOutput, options) {
10591
10811
  const { clipTypes, isLoading: typesLoading, error: typesError, refresh } = useClipTypes();
10592
10812
  const [counts, setCounts] = React23.useState({});
10593
10813
  const [countsLoading, setCountsLoading] = React23.useState(false);
@@ -10599,8 +10819,13 @@ function useClipTypesWithCounts(workspaceId, date, shiftId, totalOutput) {
10599
10819
  workspaceId,
10600
10820
  date,
10601
10821
  shiftId,
10602
- shiftIdType: typeof shiftId
10822
+ shiftIdType: typeof shiftId,
10823
+ enabled: options?.enabled
10603
10824
  });
10825
+ if (!options?.enabled) {
10826
+ console.log("[useClipTypesWithCounts] Skipping counts fetch - disabled");
10827
+ return;
10828
+ }
10604
10829
  if (!s3Service || !workspaceId || !date || shiftId === void 0) {
10605
10830
  console.log("[useClipTypesWithCounts] Skipping counts fetch - missing dependencies");
10606
10831
  return;
@@ -10624,7 +10849,7 @@ function useClipTypesWithCounts(workspaceId, date, shiftId, totalOutput) {
10624
10849
  }
10625
10850
  };
10626
10851
  fetchCounts();
10627
- }, [s3Service, workspaceId, date, shiftId, totalOutput]);
10852
+ }, [s3Service, workspaceId, date, shiftId, totalOutput, options?.enabled]);
10628
10853
  return {
10629
10854
  clipTypes: clipTypes.map((type) => ({
10630
10855
  ...type,
@@ -11034,15 +11259,48 @@ var useWorkspaceUptimeTimeline = (options) => {
11034
11259
  workspaceId,
11035
11260
  companyId,
11036
11261
  enabled = true,
11037
- refreshInterval
11262
+ refreshInterval,
11263
+ lineId,
11264
+ shiftConfig: passedShiftConfig,
11265
+ timezone: passedTimezone
11038
11266
  } = options;
11267
+ const { shiftConfig: dynamicShiftConfig, isLoading: isShiftConfigLoading } = useDynamicShiftConfig(lineId);
11268
+ const appTimezone = useAppTimezone();
11269
+ const shiftConfigPending = !passedShiftConfig && (!lineId || isShiftConfigLoading || !dynamicShiftConfig);
11270
+ const effectiveShiftConfig = passedShiftConfig ?? (shiftConfigPending ? void 0 : dynamicShiftConfig);
11271
+ const effectiveTimezone = passedTimezone || appTimezone || effectiveShiftConfig?.timezone || "UTC";
11272
+ if (process.env.NODE_ENV === "development") {
11273
+ console.log(`[useWorkspaceUptimeTimeline] Shift config state:`, {
11274
+ lineId,
11275
+ hasPassedConfig: !!passedShiftConfig,
11276
+ isShiftConfigLoading,
11277
+ hasDynamicConfig: !!dynamicShiftConfig,
11278
+ shiftConfigPending,
11279
+ hasEffectiveConfig: !!effectiveShiftConfig
11280
+ });
11281
+ }
11039
11282
  const [timeline, setTimeline] = React23.useState(null);
11040
11283
  const [loading, setLoading] = React23.useState(false);
11041
11284
  const [error, setError] = React23.useState(null);
11042
11285
  const isFetchingRef = React23.useRef(false);
11043
11286
  const intervalRef = React23.useRef(null);
11287
+ React23.useEffect(() => {
11288
+ setTimeline(null);
11289
+ setError(null);
11290
+ setLoading(enabled && Boolean(workspaceId && companyId));
11291
+ }, [workspaceId, companyId, lineId, enabled]);
11044
11292
  const fetchTimeline = React23.useCallback(async () => {
11045
11293
  if (!enabled) return;
11294
+ if (shiftConfigPending) {
11295
+ console.log("[useWorkspaceUptimeTimeline] \u23F3 Waiting for shift config to load before fetching");
11296
+ setLoading(true);
11297
+ return;
11298
+ }
11299
+ if (!effectiveShiftConfig) {
11300
+ console.warn("[useWorkspaceUptimeTimeline] \u26A0\uFE0F No effective shift config available, cannot fetch");
11301
+ setLoading(false);
11302
+ return;
11303
+ }
11046
11304
  if (!workspaceId || !companyId) {
11047
11305
  setTimeline(null);
11048
11306
  return;
@@ -11052,9 +11310,16 @@ var useWorkspaceUptimeTimeline = (options) => {
11052
11310
  isFetchingRef.current = true;
11053
11311
  setLoading(true);
11054
11312
  setError(null);
11313
+ console.log("[useWorkspaceUptimeTimeline] \u{1F680} Fetching timeline with shift config:", {
11314
+ workspaceId,
11315
+ shiftId: effectiveShiftConfig?.shifts?.[0]?.shiftId,
11316
+ timezone: effectiveTimezone
11317
+ });
11055
11318
  const data = await workspaceHealthService.getWorkspaceUptimeTimeline(
11056
11319
  workspaceId,
11057
- companyId
11320
+ companyId,
11321
+ effectiveShiftConfig,
11322
+ effectiveTimezone
11058
11323
  );
11059
11324
  setTimeline(data);
11060
11325
  } catch (err) {
@@ -11064,7 +11329,7 @@ var useWorkspaceUptimeTimeline = (options) => {
11064
11329
  setLoading(false);
11065
11330
  isFetchingRef.current = false;
11066
11331
  }
11067
- }, [enabled, workspaceId, companyId]);
11332
+ }, [enabled, workspaceId, companyId, effectiveShiftConfig, effectiveTimezone, shiftConfigPending]);
11068
11333
  React23.useEffect(() => {
11069
11334
  fetchTimeline();
11070
11335
  }, [fetchTimeline]);
@@ -11083,7 +11348,7 @@ var useWorkspaceUptimeTimeline = (options) => {
11083
11348
  }, [refreshInterval, enabled, fetchTimeline]);
11084
11349
  return {
11085
11350
  timeline,
11086
- loading,
11351
+ loading: loading || shiftConfigPending,
11087
11352
  error,
11088
11353
  refetch: fetchTimeline
11089
11354
  };
@@ -26354,26 +26619,62 @@ var VideoControls = ({
26354
26619
  const [isHoveringProgressBar, setIsHoveringProgressBar] = React23.useState(false);
26355
26620
  const [showSpeedMenu, setShowSpeedMenu] = React23.useState(false);
26356
26621
  const speedMenuRef = React23.useRef(null);
26622
+ const progressTrackRef = React23.useRef(null);
26623
+ const activePointerIdRef = React23.useRef(null);
26357
26624
  const progressColor = "#4b5563";
26358
26625
  const controlsVisible = showControls || controlsPinned;
26626
+ const isDraggingRef = React23.useRef(false);
26359
26627
  const getPercentage = (current, total) => {
26360
26628
  if (!total || total === 0) return 0;
26361
26629
  return Math.min(Math.max(current / total * 100, 0), 100);
26362
26630
  };
26363
26631
  const handleSeekChange = (e) => {
26364
- const newTime = parseFloat(e.target.value);
26632
+ const newTime = parseFloat(e.currentTarget.value);
26365
26633
  setDragTime(newTime);
26366
26634
  onSeek(newTime);
26367
26635
  };
26368
26636
  const handleSeekStart = () => {
26369
26637
  setIsDragging(true);
26638
+ isDraggingRef.current = true;
26370
26639
  setDragTime(currentTime);
26371
26640
  onSeekStart?.();
26372
26641
  };
26373
26642
  const handleSeekEnd = () => {
26374
26643
  setIsDragging(false);
26644
+ isDraggingRef.current = false;
26375
26645
  onSeekEnd?.();
26376
26646
  };
26647
+ const updateTimeFromClientX = React23.useCallback((clientX) => {
26648
+ if (!progressTrackRef.current) return;
26649
+ const rect = progressTrackRef.current.getBoundingClientRect();
26650
+ if (rect.width === 0 || duration === 0) return;
26651
+ const pct = Math.min(Math.max((clientX - rect.left) / rect.width, 0), 1);
26652
+ const newTime = pct * duration;
26653
+ setDragTime(newTime);
26654
+ onSeek(newTime);
26655
+ }, [duration, onSeek]);
26656
+ const handlePointerDown = React23.useCallback((e) => {
26657
+ if (duration === 0) return;
26658
+ e.preventDefault();
26659
+ activePointerIdRef.current = e.pointerId;
26660
+ handleSeekStart();
26661
+ updateTimeFromClientX(e.clientX);
26662
+ const handleMove = (ev) => {
26663
+ if (ev.pointerId !== activePointerIdRef.current) return;
26664
+ updateTimeFromClientX(ev.clientX);
26665
+ };
26666
+ const handleUp = (ev) => {
26667
+ if (ev.pointerId !== activePointerIdRef.current) return;
26668
+ activePointerIdRef.current = null;
26669
+ window.removeEventListener("pointermove", handleMove);
26670
+ window.removeEventListener("pointerup", handleUp);
26671
+ window.removeEventListener("pointercancel", handleUp);
26672
+ handleSeekEnd();
26673
+ };
26674
+ window.addEventListener("pointermove", handleMove);
26675
+ window.addEventListener("pointerup", handleUp);
26676
+ window.addEventListener("pointercancel", handleUp);
26677
+ }, [duration, handleSeekStart, handleSeekEnd, updateTimeFromClientX]);
26377
26678
  React23.useEffect(() => {
26378
26679
  const handleClickOutside = (event) => {
26379
26680
  if (speedMenuRef.current && !speedMenuRef.current.contains(event.target)) {
@@ -26385,6 +26686,21 @@ var VideoControls = ({
26385
26686
  document.removeEventListener("mousedown", handleClickOutside);
26386
26687
  };
26387
26688
  }, []);
26689
+ React23.useEffect(() => {
26690
+ const cancelDrag = () => {
26691
+ if (isDraggingRef.current) {
26692
+ handleSeekEnd();
26693
+ }
26694
+ };
26695
+ window.addEventListener("mouseup", cancelDrag);
26696
+ window.addEventListener("touchend", cancelDrag);
26697
+ window.addEventListener("touchcancel", cancelDrag);
26698
+ return () => {
26699
+ window.removeEventListener("mouseup", cancelDrag);
26700
+ window.removeEventListener("touchend", cancelDrag);
26701
+ window.removeEventListener("touchcancel", cancelDrag);
26702
+ };
26703
+ }, []);
26388
26704
  const displayTime = isDragging ? dragTime : currentTime;
26389
26705
  const progressPercent = getPercentage(displayTime, duration);
26390
26706
  const bufferedPercent = getPercentage(buffered, duration);
@@ -26397,11 +26713,13 @@ var VideoControls = ({
26397
26713
  /* @__PURE__ */ jsxRuntime.jsxs(
26398
26714
  "div",
26399
26715
  {
26716
+ ref: progressTrackRef,
26400
26717
  className: "relative h-1 mb-4 group cursor-pointer",
26401
26718
  onMouseEnter: () => setIsHoveringProgressBar(true),
26402
26719
  onMouseLeave: () => setIsHoveringProgressBar(false),
26720
+ onPointerDown: handlePointerDown,
26403
26721
  children: [
26404
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute -top-2 -bottom-2 left-0 right-0 z-20" }),
26722
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute -top-4 -bottom-4 left-0 right-0 z-20" }),
26405
26723
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute top-0 left-0 right-0 bottom-0 bg-white/20 rounded-full overflow-hidden z-0", children: /* @__PURE__ */ jsxRuntime.jsx(
26406
26724
  "div",
26407
26725
  {
@@ -26432,11 +26750,13 @@ var VideoControls = ({
26432
26750
  step: "0.1",
26433
26751
  value: displayTime,
26434
26752
  onChange: handleSeekChange,
26753
+ onInput: handleSeekChange,
26435
26754
  onMouseDown: handleSeekStart,
26436
26755
  onMouseUp: handleSeekEnd,
26437
26756
  onTouchStart: handleSeekStart,
26438
26757
  onTouchEnd: handleSeekEnd,
26439
- className: "absolute inset-0 w-full h-full opacity-0 cursor-pointer z-30 margin-0 padding-0"
26758
+ onPointerDown: handlePointerDown,
26759
+ className: "absolute left-0 right-0 top-[-12px] bottom-[-12px] w-full h-auto opacity-0 cursor-pointer z-30 margin-0 padding-0"
26440
26760
  }
26441
26761
  )
26442
26762
  ]
@@ -26659,6 +26979,7 @@ var HlsVideoPlayer = React23.forwardRef(({
26659
26979
  const [buffered, setBuffered] = React23.useState(0);
26660
26980
  const [playbackRate, setPlaybackRate] = React23.useState(1);
26661
26981
  const userSeekingRef = React23.useRef(false);
26982
+ const wasPlayingRef = React23.useRef(false);
26662
26983
  const controlsTimeoutRef = React23.useRef(null);
26663
26984
  const eventCallbacksRef = React23.useRef({
26664
26985
  onReady,
@@ -26901,10 +27222,6 @@ var HlsVideoPlayer = React23.forwardRef(({
26901
27222
  eventCallbacksRef.current.onPlay?.(player);
26902
27223
  };
26903
27224
  const handlePause = () => {
26904
- if (userSeekingRef.current && videoRef.current) {
26905
- videoRef.current.play().catch((err) => console.warn("Auto-resume after seek pause failed:", err));
26906
- return;
26907
- }
26908
27225
  setIsPlaying(false);
26909
27226
  eventCallbacksRef.current.onPause?.(player);
26910
27227
  };
@@ -27118,14 +27435,17 @@ var HlsVideoPlayer = React23.forwardRef(({
27118
27435
  const handleSeek = React23.useCallback((time2) => {
27119
27436
  if (videoRef.current) {
27120
27437
  videoRef.current.currentTime = time2;
27121
- videoRef.current.play().catch((err) => console.warn("Resume playback failed during seek:", err));
27122
27438
  }
27123
27439
  }, []);
27124
27440
  const handleSeekStart = React23.useCallback(() => {
27441
+ wasPlayingRef.current = !videoRef.current?.paused;
27442
+ if (videoRef.current && !videoRef.current.paused) {
27443
+ videoRef.current.pause();
27444
+ }
27125
27445
  userSeekingRef.current = true;
27126
27446
  }, []);
27127
27447
  const handleSeekEnd = React23.useCallback(() => {
27128
- if (videoRef.current) {
27448
+ if (videoRef.current && wasPlayingRef.current) {
27129
27449
  videoRef.current.play().catch((err) => console.warn("Resume playback failed after seek:", err));
27130
27450
  }
27131
27451
  }, []);
@@ -27267,6 +27587,7 @@ var CroppedHlsVideoPlayer = React23.forwardRef(({
27267
27587
  const [playbackRate, setPlaybackRate] = React23.useState(1);
27268
27588
  const controlsTimeoutRef = React23.useRef(null);
27269
27589
  const userSeekingRef = React23.useRef(false);
27590
+ const wasPlayingRef = React23.useRef(false);
27270
27591
  const [controlsPinned, setControlsPinned] = React23.useState(false);
27271
27592
  const stopCanvasRendering = React23.useCallback(() => {
27272
27593
  if (animationFrameRef.current) {
@@ -27406,7 +27727,7 @@ var CroppedHlsVideoPlayer = React23.forwardRef(({
27406
27727
  }, [crop, renderFrameToCanvas, onPlayProp]);
27407
27728
  const handleVideoPause = React23.useCallback((player) => {
27408
27729
  console.log("[CroppedHlsVideoPlayer] Video paused, stopping canvas rendering (keeping last frame)");
27409
- if (userSeekingRef.current && hiddenVideoRef.current) {
27730
+ if (userSeekingRef.current && wasPlayingRef.current && hiddenVideoRef.current) {
27410
27731
  hiddenVideoRef.current.play()?.catch(() => {
27411
27732
  });
27412
27733
  return;
@@ -27423,6 +27744,7 @@ var CroppedHlsVideoPlayer = React23.forwardRef(({
27423
27744
  setIsProcessing(false);
27424
27745
  setIsPlaying(false);
27425
27746
  userSeekingRef.current = false;
27747
+ wasPlayingRef.current = false;
27426
27748
  onEndedProp?.(player);
27427
27749
  }, [stopCanvasRendering, onEndedProp]);
27428
27750
  const handleSeeking = React23.useCallback((player) => {
@@ -27438,6 +27760,7 @@ var CroppedHlsVideoPlayer = React23.forwardRef(({
27438
27760
  hiddenVideoRef.current?.play()?.catch(() => {
27439
27761
  });
27440
27762
  userSeekingRef.current = false;
27763
+ wasPlayingRef.current = false;
27441
27764
  if (crop) {
27442
27765
  renderFrameToCanvas();
27443
27766
  }
@@ -27534,20 +27857,34 @@ var CroppedHlsVideoPlayer = React23.forwardRef(({
27534
27857
  const handleSeek = React23.useCallback((time2) => {
27535
27858
  if (hiddenVideoRef.current) {
27536
27859
  hiddenVideoRef.current.currentTime(time2);
27537
- hiddenVideoRef.current.play()?.catch(() => {
27538
- });
27539
27860
  setTimeout(() => renderFrameToCanvas(), 50);
27861
+ userSeekingRef.current = true;
27540
27862
  }
27541
27863
  }, [renderFrameToCanvas]);
27542
27864
  const handleSeekStart = React23.useCallback(() => {
27865
+ const videoPaused = hiddenVideoRef.current?.video?.paused ?? hiddenVideoRef.current?.paused();
27866
+ wasPlayingRef.current = videoPaused === false;
27867
+ if (hiddenVideoRef.current && videoPaused === false) {
27868
+ hiddenVideoRef.current.pause();
27869
+ }
27543
27870
  userSeekingRef.current = true;
27544
27871
  }, []);
27545
27872
  const handleSeekEnd = React23.useCallback(() => {
27546
- if (hiddenVideoRef.current) {
27547
- hiddenVideoRef.current.play()?.catch(() => {
27873
+ const shouldResume = wasPlayingRef.current;
27874
+ userSeekingRef.current = shouldResume;
27875
+ if (hiddenVideoRef.current && shouldResume) {
27876
+ hiddenVideoRef.current.play()?.then(() => {
27877
+ if (crop) {
27878
+ setIsProcessing(true);
27879
+ renderFrameToCanvas();
27880
+ }
27881
+ }).catch(() => {
27548
27882
  });
27549
27883
  }
27550
- }, []);
27884
+ if (!shouldResume) {
27885
+ userSeekingRef.current = false;
27886
+ }
27887
+ }, [crop, renderFrameToCanvas]);
27551
27888
  const handlePlaybackRateChange = React23.useCallback((rate) => {
27552
27889
  if (hiddenVideoRef.current) {
27553
27890
  hiddenVideoRef.current.playbackRate(rate);
@@ -29838,6 +30175,7 @@ var BottlenecksContent = ({
29838
30175
  workspaceId,
29839
30176
  workspaceName,
29840
30177
  date,
30178
+ lineId,
29841
30179
  shift,
29842
30180
  className,
29843
30181
  totalOutput,
@@ -29848,27 +30186,36 @@ var BottlenecksContent = ({
29848
30186
  console.log("\u{1F3AB} [BottlenecksContent] Rendered with ticketId:", ticketId || "NONE", "workspaceId:", workspaceId, "date:", date, "shift:", shift);
29849
30187
  const dashboardConfig = useDashboardConfig();
29850
30188
  const timezone = useAppTimezone();
29851
- const { shiftConfig } = useDynamicShiftConfig(workspaceId);
29852
- const effectiveShift = React23.useMemo(() => {
29853
- if (shift !== void 0 && shift !== null) {
30189
+ const { shiftConfig, isLoading: isShiftConfigLoading } = useDynamicShiftConfig(lineId);
30190
+ const { effectiveShift, effectiveDate } = React23.useMemo(() => {
30191
+ if (shift !== void 0 && shift !== null && date) {
29854
30192
  const shiftStr = shift.toString();
29855
- console.log(`[BottlenecksContent] Using provided shift: ${shiftStr} for date: ${date}`);
29856
- return shiftStr;
30193
+ console.log(`[BottlenecksContent] Using explicit date/shift: ${date}, shift ${shiftStr}`);
30194
+ return { effectiveShift: shiftStr, effectiveDate: date };
29857
30195
  }
29858
- if (date) {
29859
- console.log(`[BottlenecksContent] No shift provided for historical date ${date}, defaulting to day shift (0)`);
29860
- return "0";
29861
- } else {
29862
- const currentShift = getCurrentShift(
29863
- timezone,
29864
- // Use dynamic timezone instead of hardcoded default
29865
- shiftConfig
29866
- // Use line-specific shift config from database
29867
- );
29868
- console.log(`[BottlenecksContent] Using current operational shift: ${currentShift.shiftId} with timezone: ${timezone} for workspace: ${workspaceId}`);
29869
- return currentShift.shiftId.toString();
30196
+ if ((shift === void 0 || shift === null) && isShiftConfigLoading) {
30197
+ console.log("[BottlenecksContent] Waiting for shift config before determining effective date/shift");
30198
+ return { effectiveShift: null, effectiveDate: null };
30199
+ }
30200
+ const currentShift = getCurrentShift(
30201
+ timezone,
30202
+ shiftConfig
30203
+ );
30204
+ if (shift !== void 0 && shift !== null) {
30205
+ const shiftStr = shift.toString();
30206
+ return {
30207
+ effectiveShift: shiftStr,
30208
+ effectiveDate: date || currentShift.date
30209
+ };
29870
30210
  }
29871
- }, [shift, date, timezone, shiftConfig, workspaceId]);
30211
+ return {
30212
+ effectiveShift: currentShift.shiftId.toString(),
30213
+ effectiveDate: date || currentShift.date
30214
+ };
30215
+ }, [shift, date, timezone, shiftConfig, isShiftConfigLoading]);
30216
+ const isEffectiveShiftReady = Boolean(effectiveShift && effectiveDate);
30217
+ const effectiveDateString = effectiveDate || "";
30218
+ const effectiveShiftId = effectiveShift ?? "";
29872
30219
  const { crop: workspaceCrop} = useWorkspaceCrop(workspaceId);
29873
30220
  const { metrics: workspaceMetrics } = useWorkspaceDetailedMetrics(
29874
30221
  workspaceId,
@@ -29954,9 +30301,9 @@ var BottlenecksContent = ({
29954
30301
  clearNotification
29955
30302
  } = useClipsRealtimeUpdates({
29956
30303
  workspaceId,
29957
- date: date || getOperationalDate(timezone),
29958
- shiftId: effectiveShift,
29959
- enabled: true,
30304
+ date: effectiveDateString,
30305
+ shiftId: effectiveShiftId,
30306
+ enabled: isEffectiveShiftReady,
29960
30307
  // Supabase implementation
29961
30308
  onNewClips: (notification) => {
29962
30309
  console.log(`[BottlenecksContent] New clips detected:`, notification);
@@ -29997,10 +30344,11 @@ var BottlenecksContent = ({
29997
30344
  counts: dynamicCounts
29998
30345
  } = useClipTypesWithCounts(
29999
30346
  workspaceId,
30000
- date || getOperationalDate(timezone),
30001
- effectiveShift,
30347
+ effectiveDateString,
30348
+ effectiveShiftId,
30002
30349
  // Use same shift as video loading for consistency
30003
- totalOutput
30350
+ totalOutput,
30351
+ { enabled: isEffectiveShiftReady }
30004
30352
  );
30005
30353
  console.log("[BottlenecksContent] Clip types data:", {
30006
30354
  clipTypes,
@@ -30009,8 +30357,8 @@ var BottlenecksContent = ({
30009
30357
  clipTypesError,
30010
30358
  dynamicCounts,
30011
30359
  workspaceId,
30012
- date: date || getOperationalDate(timezone),
30013
- shift: shift || "0"
30360
+ date: effectiveDateString,
30361
+ shift: effectiveShiftId || "0"
30014
30362
  });
30015
30363
  React23.useEffect(() => {
30016
30364
  if (clipTypes.length > 0) {
@@ -30051,16 +30399,16 @@ var BottlenecksContent = ({
30051
30399
  return { ...clipCounts, ...dynamicCounts };
30052
30400
  }, [clipCounts, dynamicCounts]);
30053
30401
  const fetchClipCounts = React23.useCallback(async () => {
30054
- if (!workspaceId || !s3ClipsService || !dashboardConfig?.s3Config || !isMountedRef.current) return;
30055
- const operationKey = `fetchClipCounts:${workspaceId}:${date}:${shift}`;
30402
+ if (!workspaceId || !s3ClipsService || !dashboardConfig?.s3Config || !isMountedRef.current || !isEffectiveShiftReady) return;
30403
+ const operationKey = `fetchClipCounts:${workspaceId}:${effectiveDateString}:${effectiveShiftId}`;
30056
30404
  if (fetchInProgressRef.current.has(operationKey)) {
30057
30405
  console.log(`[BottlenecksContent] Fetch clip counts already in progress for ${operationKey}`);
30058
30406
  return;
30059
30407
  }
30060
30408
  fetchInProgressRef.current.add(operationKey);
30061
30409
  try {
30062
- const operationalDate = date || getOperationalDate(timezone);
30063
- const shiftStr = effectiveShift;
30410
+ const operationalDate = effectiveDateString;
30411
+ const shiftStr = effectiveShiftId;
30064
30412
  console.log(`[BottlenecksContent] Fetching clip counts directly with params:`, {
30065
30413
  workspaceId,
30066
30414
  operationalDate,
@@ -30095,12 +30443,12 @@ var BottlenecksContent = ({
30095
30443
  } finally {
30096
30444
  fetchInProgressRef.current.delete(operationKey);
30097
30445
  }
30098
- }, [workspaceId, date, s3ClipsService, effectiveShift, dashboardConfig, updateClipCounts, timezone, totalOutput]);
30446
+ }, [workspaceId, effectiveDateString, s3ClipsService, effectiveShiftId, dashboardConfig, updateClipCounts, isEffectiveShiftReady, totalOutput]);
30099
30447
  const loadingCategoryRef = React23.useRef(null);
30100
30448
  const loadFirstVideoForCategory = React23.useCallback(async (category) => {
30101
- if (!workspaceId || !s3ClipsService || !isMountedRef.current) return;
30449
+ if (!workspaceId || !s3ClipsService || !isMountedRef.current || !isEffectiveShiftReady) return;
30102
30450
  const targetCategory = category || activeFilterRef.current;
30103
- const operationKey = `loadFirstVideo:${targetCategory}`;
30451
+ const operationKey = `loadFirstVideo:${targetCategory}:${effectiveDateString}:${effectiveShiftId}`;
30104
30452
  if (loadingCategoryRef.current === targetCategory || fetchInProgressRef.current.has(operationKey)) {
30105
30453
  console.log(`[BottlenecksContent] Load first video already in progress for ${targetCategory}`);
30106
30454
  return;
@@ -30111,8 +30459,8 @@ var BottlenecksContent = ({
30111
30459
  setError(null);
30112
30460
  }
30113
30461
  try {
30114
- const operationalDate = date || getOperationalDate(timezone);
30115
- const shiftStr = effectiveShift;
30462
+ const operationalDate = effectiveDateString;
30463
+ const shiftStr = effectiveShiftId;
30116
30464
  console.log(`[BottlenecksContent] Loading first video for category: ${targetCategory}`);
30117
30465
  try {
30118
30466
  const firstVideo = await s3ClipsService.getFirstClipForCategory(
@@ -30185,7 +30533,7 @@ var BottlenecksContent = ({
30185
30533
  loadingCategoryRef.current = null;
30186
30534
  fetchInProgressRef.current.delete(operationKey);
30187
30535
  }
30188
- }, [workspaceId, date, s3ClipsService, mergedCounts, effectiveShift, timezone]);
30536
+ }, [workspaceId, effectiveDateString, s3ClipsService, mergedCounts, effectiveShiftId, isEffectiveShiftReady]);
30189
30537
  const handleRefreshClips = React23.useCallback(async () => {
30190
30538
  console.log("[BottlenecksContent] Refreshing clips after new additions");
30191
30539
  acknowledgeNewClips();
@@ -30196,10 +30544,10 @@ var BottlenecksContent = ({
30196
30544
  }
30197
30545
  }, [acknowledgeNewClips, fetchClipCounts, activeFilter, mergedCounts, loadFirstVideoForCategory, invalidateMetadataCache]);
30198
30546
  React23.useEffect(() => {
30199
- if (s3ClipsService) {
30547
+ if (s3ClipsService && isEffectiveShiftReady) {
30200
30548
  fetchClipCounts();
30201
30549
  }
30202
- }, [workspaceId, date, effectiveShift, s3ClipsService, fetchClipCounts]);
30550
+ }, [workspaceId, effectiveDateString, effectiveShiftId, s3ClipsService, fetchClipCounts, isEffectiveShiftReady]);
30203
30551
  const getAuthToken4 = React23.useCallback(async () => {
30204
30552
  try {
30205
30553
  const { createClient: createClient5 } = await import('@supabase/supabase-js');
@@ -30215,7 +30563,7 @@ var BottlenecksContent = ({
30215
30563
  }
30216
30564
  }, []);
30217
30565
  React23.useEffect(() => {
30218
- if (!triageMode || !workspaceId) return;
30566
+ if (!triageMode || !workspaceId || !isEffectiveShiftReady) return;
30219
30567
  const fetchTriageClips = async () => {
30220
30568
  setIsLoadingTriageClips(true);
30221
30569
  try {
@@ -30234,8 +30582,8 @@ var BottlenecksContent = ({
30234
30582
  body: JSON.stringify({
30235
30583
  action: "metadata",
30236
30584
  workspaceId,
30237
- date: date || getOperationalDate(timezone),
30238
- shift: effectiveShift,
30585
+ date: effectiveDateString,
30586
+ shift: effectiveShiftId,
30239
30587
  category: categoryId,
30240
30588
  page: 1,
30241
30589
  limit: 100
@@ -30267,7 +30615,7 @@ var BottlenecksContent = ({
30267
30615
  }
30268
30616
  };
30269
30617
  fetchTriageClips();
30270
- }, [triageMode, workspaceId, date, effectiveShift, timezone, getAuthToken4]);
30618
+ }, [triageMode, workspaceId, effectiveDateString, effectiveShiftId, getAuthToken4, isEffectiveShiftReady]);
30271
30619
  React23.useEffect(() => {
30272
30620
  if (s3ClipsService && (mergedCounts[activeFilter] || 0) > 0) {
30273
30621
  const hasVideosForCurrentFilter = allVideos.some((video) => {
@@ -30368,8 +30716,12 @@ var BottlenecksContent = ({
30368
30716
  if (!workspaceId) {
30369
30717
  return;
30370
30718
  }
30371
- const resolvedDate = date || getOperationalDate(timezone);
30372
- const cacheKey = `${categoryId}-${resolvedDate}-${effectiveShift}`;
30719
+ if (!isEffectiveShiftReady) {
30720
+ console.log("[BottlenecksContent] Skipping metadata load - shift/date not ready");
30721
+ return;
30722
+ }
30723
+ const resolvedDate = effectiveDateString;
30724
+ const cacheKey = `${categoryId}-${resolvedDate}-${effectiveShiftId}`;
30373
30725
  const cachedMetadata = !forceRefresh ? metadataCache[cacheKey] : void 0;
30374
30726
  try {
30375
30727
  if (cachedMetadata) {
@@ -30423,7 +30775,7 @@ var BottlenecksContent = ({
30423
30775
  startDate: `${resolvedDate}T00:00:00Z`,
30424
30776
  endDate: `${resolvedDate}T23:59:59Z`,
30425
30777
  percentile: 10,
30426
- shiftId: effectiveShift,
30778
+ shiftId: effectiveShiftId,
30427
30779
  limit: 100
30428
30780
  })
30429
30781
  });
@@ -30438,7 +30790,7 @@ var BottlenecksContent = ({
30438
30790
  action: "clip-metadata",
30439
30791
  workspaceId,
30440
30792
  date: resolvedDate,
30441
- shift: effectiveShift,
30793
+ shift: effectiveShiftId,
30442
30794
  category: categoryId,
30443
30795
  page: 1,
30444
30796
  limit: 1e3
@@ -30497,7 +30849,7 @@ var BottlenecksContent = ({
30497
30849
  } finally {
30498
30850
  setIsCategoryLoading(false);
30499
30851
  }
30500
- }, [workspaceId, date, effectiveShift, isPercentileCategory, metadataCache, s3ClipsService, timezone, clearLoadingState]);
30852
+ }, [workspaceId, effectiveDateString, effectiveShiftId, isPercentileCategory, metadataCache, s3ClipsService, clearLoadingState, isEffectiveShiftReady]);
30501
30853
  const loadAndPlayClipById = React23.useCallback(async (clipId, categoryId, position) => {
30502
30854
  if (!workspaceId || !s3ClipsService || !isMountedRef.current) return;
30503
30855
  console.log(`[BottlenecksContent] Loading clip by ID: ${clipId}, category=${categoryId}, position=${position}`);
@@ -30562,10 +30914,10 @@ var BottlenecksContent = ({
30562
30914
  }, [workspaceId, s3ClipsService, updateActiveFilter, clearLoadingState, loadCategoryMetadata]);
30563
30915
  React23.useCallback(async (categoryId, clipIndex) => {
30564
30916
  console.warn("[BottlenecksContent] loadAndPlayClip is deprecated, use loadAndPlayClipById instead");
30565
- if (!workspaceId || !s3ClipsService || !isMountedRef.current) return;
30917
+ if (!workspaceId || !s3ClipsService || !isMountedRef.current || !isEffectiveShiftReady) return;
30566
30918
  try {
30567
- const operationalDate = date || getOperationalDate(timezone);
30568
- const shiftStr = effectiveShift;
30919
+ const operationalDate = effectiveDateString;
30920
+ const shiftStr = effectiveShiftId;
30569
30921
  const video = await s3ClipsService.getClipByIndex(
30570
30922
  workspaceId,
30571
30923
  operationalDate,
@@ -30586,7 +30938,7 @@ var BottlenecksContent = ({
30586
30938
  });
30587
30939
  setIsNavigating(false);
30588
30940
  }
30589
- }, [workspaceId, s3ClipsService, date, effectiveShift, loadAndPlayClipById, timezone]);
30941
+ }, [workspaceId, s3ClipsService, effectiveDateString, effectiveShiftId, loadAndPlayClipById, isEffectiveShiftReady]);
30590
30942
  const handleNext = React23.useCallback(async () => {
30591
30943
  if (!isMountedRef.current) return;
30592
30944
  const currentFilter = activeFilterRef.current;
@@ -31245,8 +31597,8 @@ var BottlenecksContent = ({
31245
31597
  currentVideoId: currentVideo?.id,
31246
31598
  counts: mergedCounts,
31247
31599
  workspaceId,
31248
- date: date || getOperationalDate(timezone),
31249
- shift: effectiveShift,
31600
+ date: effectiveDateString,
31601
+ shift: effectiveShiftId,
31250
31602
  targetCycleTime: workspaceTargetCycleTime,
31251
31603
  onFilterChange: (filterId) => {
31252
31604
  updateActiveFilter(filterId);
@@ -31444,6 +31796,7 @@ var BottleneckClipsModal = ({
31444
31796
  onClose,
31445
31797
  workspaceId,
31446
31798
  workspaceName,
31799
+ lineId,
31447
31800
  date,
31448
31801
  shift,
31449
31802
  totalOutput,
@@ -31568,6 +31921,7 @@ var BottleneckClipsModal = ({
31568
31921
  {
31569
31922
  workspaceId,
31570
31923
  workspaceName,
31924
+ lineId,
31571
31925
  date,
31572
31926
  shift,
31573
31927
  totalOutput,
@@ -32514,7 +32868,7 @@ var EncouragementOverlay = ({
32514
32868
  };
32515
32869
  var ShiftDisplay = React23.memo(({ className, variant = "default", lineId }) => {
32516
32870
  const { dateTimeConfig } = useDashboardConfig();
32517
- const { shiftConfig } = useDynamicShiftConfig(lineId);
32871
+ const { shiftConfig, isLoading: isShiftConfigLoading } = useDynamicShiftConfig(lineId);
32518
32872
  const getShiftInfo = () => {
32519
32873
  const tz = dateTimeConfig?.defaultTimezone;
32520
32874
  if (!tz || !shiftConfig || !shiftConfig.dayShift || !shiftConfig.nightShift || !shiftConfig.dayShift.startTime || !shiftConfig.nightShift.startTime) {
@@ -32528,7 +32882,7 @@ var ShiftDisplay = React23.memo(({ className, variant = "default", lineId }) =>
32528
32882
  return null;
32529
32883
  }
32530
32884
  };
32531
- const getShiftIcon = (shift) => {
32885
+ const getShiftIcon2 = (shift) => {
32532
32886
  if (shift === "Day") {
32533
32887
  return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ jsxRuntime.jsx("path", { fillRule: "evenodd", d: "M10 2a1 1 0 011 1v1a1 1 0 11-2 0V3a1 1 0 011-1zm4 8a4 4 0 11-8 0 4 4 0 018 0zm-.464 4.95l.707.707a1 1 0 001.414-1.414l-.707-.707a1 1 0 00-1.414 1.414zm2.12-10.607a1 1 0 010 1.414l-.706.707a1 1 0 11-1.414-1.414l.707-.707a1 1 0 011.414 0zM17 11a1 1 0 100-2h-1a1 1 0 100 2h1zm-7 4a1 1 0 011 1v1a1 1 0 11-2 0v-1a1 1 0 011-1zM5.05 6.464A1 1 0 106.465 5.05l-.708-.707a1 1 0 00-1.414 1.414l.707.707zm1.414 8.486l-.707.707a1 1 0 01-1.414-1.414l.707-.707a1 1 0 011.414 1.414zM4 11a1 1 0 100-2H3a1 1 0 000 2h1z", clipRule: "evenodd" }) });
32534
32888
  } else {
@@ -32542,13 +32896,19 @@ var ShiftDisplay = React23.memo(({ className, variant = "default", lineId }) =>
32542
32896
  setCurrentShiftText(getShiftInfo());
32543
32897
  }, 1e3);
32544
32898
  return () => clearInterval(interval);
32545
- }, [dateTimeConfig?.defaultTimezone, shiftConfig]);
32899
+ }, [dateTimeConfig?.defaultTimezone, shiftConfig, isShiftConfigLoading]);
32900
+ if (isShiftConfigLoading) {
32901
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `inline-flex items-center gap-2 bg-gray-100 rounded-lg px-3 py-1.5 ${className ?? ""}`, children: [
32902
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-4 h-4 bg-gray-200 rounded animate-pulse" }),
32903
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-16 h-4 bg-gray-200 rounded animate-pulse" })
32904
+ ] });
32905
+ }
32546
32906
  if (!currentShiftText) {
32547
32907
  return null;
32548
32908
  }
32549
32909
  if (variant === "enhanced") {
32550
32910
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `inline-flex items-center gap-2 bg-blue-50 rounded-lg px-3 py-1.5 ${className ?? ""}`, children: [
32551
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-blue-800", children: getShiftIcon(currentShiftText) }),
32911
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-blue-800", children: getShiftIcon2(currentShiftText) }),
32552
32912
  /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-base font-medium text-blue-800", children: [
32553
32913
  currentShiftText,
32554
32914
  " Shift"
@@ -32556,7 +32916,7 @@ var ShiftDisplay = React23.memo(({ className, variant = "default", lineId }) =>
32556
32916
  ] });
32557
32917
  }
32558
32918
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `inline-flex items-center gap-2 bg-blue-50 rounded-lg px-3 py-1.5 ${className ?? ""}`, children: [
32559
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-blue-800", children: getShiftIcon(currentShiftText) }),
32919
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-blue-800", children: getShiftIcon2(currentShiftText) }),
32560
32920
  /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-base font-medium text-blue-800", children: [
32561
32921
  currentShiftText,
32562
32922
  " Shift"
@@ -33020,13 +33380,26 @@ var LinePdfExportButton = ({
33020
33380
  }
33021
33381
  );
33022
33382
  };
33383
+ var DEFAULT_LINE_SHIFT_DATA = {
33384
+ avg_efficiency: 0,
33385
+ underperforming_workspaces: 0,
33386
+ total_workspaces: 0,
33387
+ hasData: false
33388
+ };
33389
+ var getLineShiftData = (day, shiftId) => {
33390
+ const shift = day.shifts[shiftId];
33391
+ if (shift) {
33392
+ return { ...shift, hasData: true };
33393
+ }
33394
+ return { ...DEFAULT_LINE_SHIFT_DATA };
33395
+ };
33023
33396
  var WEEKDAYS = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
33024
33397
  var LineHistoryCalendar = ({
33025
33398
  data,
33026
33399
  month,
33027
33400
  year,
33028
33401
  lineId,
33029
- selectedShift,
33402
+ selectedShiftId,
33030
33403
  onDateSelect,
33031
33404
  className = ""
33032
33405
  }) => {
@@ -33062,8 +33435,7 @@ var LineHistoryCalendar = ({
33062
33435
  } else {
33063
33436
  calendar.push({
33064
33437
  date: currentDate,
33065
- dayShift: { avg_efficiency: 0, underperforming_workspaces: 0, total_workspaces: 0, hasData: false },
33066
- nightShift: { avg_efficiency: 0, underperforming_workspaces: 0, total_workspaces: 0, hasData: false }
33438
+ shifts: {}
33067
33439
  });
33068
33440
  }
33069
33441
  }
@@ -33114,8 +33486,7 @@ var LineHistoryCalendar = ({
33114
33486
  };
33115
33487
  const renderDayCell = (day) => {
33116
33488
  if (!day) return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-full border border-gray-100 dark:border-gray-700 rounded-lg bg-gray-50 dark:bg-gray-800" });
33117
- const shiftData = selectedShift === "day" ? day.dayShift : day.nightShift;
33118
- if (!shiftData) return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-full border border-gray-100 dark:border-gray-700 rounded-lg bg-gray-50 dark:bg-gray-800" });
33489
+ const shiftData = getLineShiftData(day, selectedShiftId);
33119
33490
  const isToday = isCurrentDate(day.date instanceof Date ? day.date : new Date(day.date));
33120
33491
  const isFuture = isFutureDate(day.date instanceof Date ? day.date : new Date(day.date));
33121
33492
  const hasData = hasRealData(shiftData);
@@ -33131,21 +33502,20 @@ var LineHistoryCalendar = ({
33131
33502
  const month2 = String(dateObj2.getMonth() + 1).padStart(2, "0");
33132
33503
  const dayOfMonth = String(dateObj2.getDate()).padStart(2, "0");
33133
33504
  const date = `${year2}-${month2}-${dayOfMonth}`;
33134
- const shiftId = selectedShift === "day" ? "0" : "1";
33135
33505
  trackCoreEvent("Line Monthly History Day Clicked", {
33136
33506
  source: "line_kpi",
33137
33507
  line_id: lineId,
33138
33508
  date,
33139
- shift: selectedShift,
33509
+ shift_id: selectedShiftId,
33140
33510
  efficiency: shiftData.avg_efficiency || 0,
33141
33511
  underperforming_workspaces: shiftData.underperforming_workspaces || 0,
33142
33512
  total_workspaces: shiftData.total_workspaces || 0
33143
33513
  });
33144
33514
  const returnTo = `/kpis/${lineId}?tab=monthly_history&month=${month2}&year=${year2}`;
33145
33515
  if (onDateSelect) {
33146
- onDateSelect(date, shiftId);
33516
+ onDateSelect(date, selectedShiftId);
33147
33517
  } else {
33148
- router.navigate(`/kpis/${lineId}?date=${date}&shift=${shiftId}&sourceType=lineMonthlyHistory&returnTo=${encodeURIComponent(returnTo)}`);
33518
+ router.navigate(`/kpis/${lineId}?date=${date}&shift=${selectedShiftId}&sourceType=lineMonthlyHistory&returnTo=${encodeURIComponent(returnTo)}`);
33149
33519
  }
33150
33520
  }
33151
33521
  },
@@ -33169,14 +33539,28 @@ var LineHistoryCalendar = ({
33169
33539
  ] });
33170
33540
  };
33171
33541
  var LineHistoryCalendar_default = LineHistoryCalendar;
33542
+ var DEFAULT_PERFORMANCE_DATA = {
33543
+ avg_efficiency: 0,
33544
+ underperforming_workspaces: 0,
33545
+ total_workspaces: 0,
33546
+ hasData: false
33547
+ };
33548
+ var getShiftData2 = (day, shiftId) => {
33549
+ const shift = day.shifts[shiftId];
33550
+ if (shift) {
33551
+ return { ...shift, hasData: true };
33552
+ }
33553
+ return { ...DEFAULT_PERFORMANCE_DATA };
33554
+ };
33172
33555
  var LineMonthlyHistory = ({
33173
33556
  month,
33174
33557
  year,
33175
33558
  monthlyData = [],
33176
- underperformingWorkspaces = { dayShift: [], nightShift: [] },
33559
+ underperformingWorkspaces = {},
33177
33560
  lineId,
33178
- selectedShift = "day",
33561
+ selectedShiftId = 0,
33179
33562
  onShiftChange,
33563
+ availableShifts,
33180
33564
  onWorkspaceSelect,
33181
33565
  onCalendarDateSelect,
33182
33566
  onCalendarMonthChange,
@@ -33185,7 +33569,7 @@ var LineMonthlyHistory = ({
33185
33569
  const navigation = useNavigation();
33186
33570
  const averages = (monthlyData || []).reduce(
33187
33571
  (acc, day) => {
33188
- const shiftData = selectedShift === "day" ? day.dayShift : day.nightShift;
33572
+ const shiftData = getShiftData2(day, selectedShiftId);
33189
33573
  if (!shiftData || shiftData?.avg_efficiency < 10) {
33190
33574
  return acc;
33191
33575
  }
@@ -33259,28 +33643,22 @@ var LineMonthlyHistory = ({
33259
33643
  line_id: lineId,
33260
33644
  workspace_id: workspace.workspace_uuid,
33261
33645
  workspace_name: workspace.workspace_name,
33262
- selected_shift: selectedShift
33646
+ selected_shift_id: selectedShiftId
33263
33647
  });
33264
33648
  };
33265
33649
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: clsx("flex flex-col gap-2 min-h-0 overflow-y-auto pb-6", className), children: [
33266
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-center mb-4", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-1 border border-gray-200 rounded-lg p-1 bg-gray-50", children: [
33267
- /* @__PURE__ */ jsxRuntime.jsx(
33268
- "button",
33269
- {
33270
- onClick: () => onShiftChange?.("day"),
33271
- className: `px-4 py-2 text-sm font-medium rounded-md transition-all duration-200 ${selectedShift === "day" ? "bg-white text-blue-600 shadow-sm ring-1 ring-gray-200" : "text-gray-600 hover:text-gray-900 hover:bg-gray-100"}`,
33272
- children: "Day Shift"
33273
- }
33274
- ),
33275
- /* @__PURE__ */ jsxRuntime.jsx(
33276
- "button",
33277
- {
33278
- onClick: () => onShiftChange?.("night"),
33279
- className: `px-4 py-2 text-sm font-medium rounded-md transition-all duration-200 ${selectedShift === "night" ? "bg-white text-blue-600 shadow-sm ring-1 ring-gray-200" : "text-gray-600 hover:text-gray-900 hover:bg-gray-100"}`,
33280
- children: "Night Shift"
33281
- }
33282
- )
33283
- ] }) }),
33650
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-center mb-4", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex gap-1 border border-gray-200 rounded-lg p-1 bg-gray-50", children: (availableShifts && availableShifts.length > 0 ? availableShifts : [
33651
+ { id: 0, name: "Day Shift" },
33652
+ { id: 1, name: "Night Shift" }
33653
+ ]).sort((a, b) => a.id - b.id).map((shift) => /* @__PURE__ */ jsxRuntime.jsx(
33654
+ "button",
33655
+ {
33656
+ onClick: () => onShiftChange?.(shift.id),
33657
+ className: `px-4 py-2 text-sm font-medium rounded-md transition-all duration-200 ${selectedShiftId === shift.id ? "bg-white text-blue-600 shadow-sm ring-1 ring-gray-200" : "text-gray-600 hover:text-gray-900 hover:bg-gray-100"}`,
33658
+ children: shift.name
33659
+ },
33660
+ shift.id
33661
+ )) }) }),
33284
33662
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-1 lg:grid-cols-2 gap-6 mt-6", children: [
33285
33663
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-white rounded-xl shadow-sm border border-gray-100 p-6", children: [
33286
33664
  /* @__PURE__ */ jsxRuntime.jsxs("h2", { className: "text-lg font-semibold text-gray-700 mb-4 text-center", children: [
@@ -33295,7 +33673,7 @@ var LineMonthlyHistory = ({
33295
33673
  month,
33296
33674
  year,
33297
33675
  lineId,
33298
- selectedShift,
33676
+ selectedShiftId,
33299
33677
  onDateSelect: onCalendarDateSelect
33300
33678
  }
33301
33679
  )
@@ -33332,7 +33710,7 @@ var LineMonthlyHistory = ({
33332
33710
  new Date(year, month).toLocaleString("default", { month: "long", year: "numeric" })
33333
33711
  ] }),
33334
33712
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4", children: [
33335
- (selectedShift === "day" ? underperformingWorkspaces.dayShift : underperformingWorkspaces.nightShift)?.map((workspace) => /* @__PURE__ */ jsxRuntime.jsx(
33713
+ (underperformingWorkspaces[selectedShiftId] || []).map((workspace) => /* @__PURE__ */ jsxRuntime.jsx(
33336
33714
  "button",
33337
33715
  {
33338
33716
  onClick: () => handleWorkspaceClick(workspace),
@@ -33354,13 +33732,33 @@ var LineMonthlyHistory = ({
33354
33732
  },
33355
33733
  workspace.workspace_uuid
33356
33734
  )),
33357
- (!underperformingWorkspaces || (selectedShift === "day" ? !underperformingWorkspaces.dayShift?.length : !underperformingWorkspaces.nightShift?.length)) && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-center text-gray-500 py-4", children: "No consistently underperforming workspaces found" })
33735
+ (!underperformingWorkspaces || !underperformingWorkspaces[selectedShiftId]?.length) && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-center text-gray-500 py-4", children: "No consistently underperforming workspaces found" })
33358
33736
  ] })
33359
33737
  ] })
33360
33738
  ] })
33361
33739
  ] })
33362
33740
  ] });
33363
33741
  };
33742
+ var DEFAULT_PERFORMANCE_DATA2 = {
33743
+ avg_efficiency: 0,
33744
+ underperforming_workspaces: 0,
33745
+ total_workspaces: 0,
33746
+ hasData: false
33747
+ };
33748
+ var getLineShiftData2 = (day, shiftId) => {
33749
+ const shift = day.shifts[shiftId];
33750
+ if (shift) {
33751
+ return { ...shift, hasData: true };
33752
+ }
33753
+ return { ...DEFAULT_PERFORMANCE_DATA2 };
33754
+ };
33755
+ var getShiftDisplayName = (shiftId, availableShifts) => {
33756
+ const shift = availableShifts?.find((s) => s.id === shiftId);
33757
+ if (shift) return shift.name;
33758
+ if (shiftId === 0) return "Day Shift";
33759
+ if (shiftId === 1) return "Night Shift";
33760
+ return `Shift ${shiftId}`;
33761
+ };
33364
33762
  var LineMonthlyPdfGenerator = ({
33365
33763
  lineId,
33366
33764
  lineName,
@@ -33368,7 +33766,8 @@ var LineMonthlyPdfGenerator = ({
33368
33766
  underperformingWorkspaces,
33369
33767
  selectedMonth,
33370
33768
  selectedYear,
33371
- selectedShift,
33769
+ selectedShiftId,
33770
+ availableShifts,
33372
33771
  className
33373
33772
  }) => {
33374
33773
  const [isGenerating, setIsGenerating] = React23.useState(false);
@@ -33380,7 +33779,7 @@ var LineMonthlyPdfGenerator = ({
33380
33779
  line_name: lineName,
33381
33780
  month: selectedMonth,
33382
33781
  year: selectedYear,
33383
- shift: selectedShift
33782
+ shift_id: selectedShiftId
33384
33783
  });
33385
33784
  const doc = new jsPDF.jsPDF();
33386
33785
  doc.setFontSize(14);
@@ -33410,7 +33809,7 @@ var LineMonthlyPdfGenerator = ({
33410
33809
  year: "numeric",
33411
33810
  timeZone: "Asia/Kolkata"
33412
33811
  });
33413
- const shiftType = selectedShift === "day" ? "Day Shift" : "Night Shift";
33812
+ const shiftType = getShiftDisplayName(selectedShiftId, availableShifts);
33414
33813
  doc.text(`${monthName}`, 20, 55);
33415
33814
  doc.text(`${shiftType}`, 20, 63);
33416
33815
  const startDate = new Date(selectedYear, selectedMonth, 1);
@@ -33439,7 +33838,7 @@ var LineMonthlyPdfGenerator = ({
33439
33838
  return date.getMonth() === selectedMonth && date.getFullYear() === selectedYear;
33440
33839
  });
33441
33840
  const validShifts = validDays.map(
33442
- (day) => selectedShift === "day" ? day.dayShift : day.nightShift
33841
+ (day) => getLineShiftData2(day, selectedShiftId)
33443
33842
  ).filter((shift) => shift.avg_efficiency > 0);
33444
33843
  const monthlyMetrics = validShifts.length > 0 ? {
33445
33844
  avgEfficiency: validShifts.reduce((sum, shift) => sum + shift.avg_efficiency, 0) / validShifts.length,
@@ -33521,8 +33920,8 @@ var LineMonthlyPdfGenerator = ({
33521
33920
  const recentDays = validDays.slice(-10).reverse();
33522
33921
  recentDays.forEach((dayData, index) => {
33523
33922
  if (yPos > 245) return;
33524
- const shift = selectedShift === "day" ? dayData.dayShift : dayData.nightShift;
33525
- if (shift.avg_efficiency <= 0) return;
33923
+ const shift = getLineShiftData2(dayData, selectedShiftId);
33924
+ if (shift.avg_efficiency <= 0 || !shift.hasData) return;
33526
33925
  if (index % 2 === 0) {
33527
33926
  doc.setFillColor(252, 252, 252);
33528
33927
  doc.roundedRect(20, yPos - 4, 170, 7, 1, 1, "F");
@@ -33556,7 +33955,7 @@ var LineMonthlyPdfGenerator = ({
33556
33955
  doc.text("No daily data available for this month", 25, 200);
33557
33956
  doc.setTextColor(0, 0, 0);
33558
33957
  }
33559
- const poorestWorkspaces = selectedShift === "day" ? underperformingWorkspaces.dayShift : underperformingWorkspaces.nightShift;
33958
+ const poorestWorkspaces = underperformingWorkspaces[selectedShiftId] || [];
33560
33959
  if (poorestWorkspaces && poorestWorkspaces.length > 0) {
33561
33960
  doc.addPage();
33562
33961
  doc.setFontSize(14);
@@ -33684,6 +34083,7 @@ Underperforming Workspaces: ${lineInfo.metrics.underperforming_workspaces} / ${l
33684
34083
  var LinePdfGenerator = ({
33685
34084
  lineInfo,
33686
34085
  workspaceData,
34086
+ shiftName,
33687
34087
  className
33688
34088
  }) => {
33689
34089
  const [isGenerating, setIsGenerating] = React23.useState(false);
@@ -33735,7 +34135,8 @@ var LinePdfGenerator = ({
33735
34135
  doc.text(lineInfo.line_name, 20, 30);
33736
34136
  doc.setFontSize(14);
33737
34137
  doc.setFont("helvetica", "normal");
33738
- const shiftType = lineInfo.shift_id === 0 ? "Day Shift" : "Night Shift";
34138
+ const rawShiftType = shiftName || (lineInfo.shift_id === 0 ? "Day" : lineInfo.shift_id === 1 ? "Night" : `Shift ${lineInfo.shift_id}`);
34139
+ const shiftType = rawShiftType.toLowerCase().includes("shift") ? rawShiftType : `${rawShiftType} Shift`;
33739
34140
  const date = new Date(lineInfo.date).toLocaleDateString("en-IN", {
33740
34141
  weekday: "long",
33741
34142
  day: "numeric",
@@ -34410,9 +34811,10 @@ var WorkspaceHistoryCalendar = ({
34410
34811
  month,
34411
34812
  year,
34412
34813
  workspaceId,
34413
- selectedShift = "day",
34814
+ selectedShiftId = 0,
34414
34815
  onMonthNavigate,
34415
34816
  onShiftChange,
34817
+ availableShifts,
34416
34818
  className
34417
34819
  }) => {
34418
34820
  const { dateTimeConfig } = useDashboardConfig();
@@ -34477,7 +34879,7 @@ var WorkspaceHistoryCalendar = ({
34477
34879
  if (compareDate > istNow) {
34478
34880
  return [];
34479
34881
  }
34480
- const shiftData = selectedShift === "day" ? day.dayShift : day.nightShift;
34882
+ const shiftData = getShiftData(day, selectedShiftId);
34481
34883
  if (hasRealData(shiftData)) {
34482
34884
  return [shiftData];
34483
34885
  }
@@ -34494,31 +34896,32 @@ var WorkspaceHistoryCalendar = ({
34494
34896
  badDaysCount: badShiftsCount,
34495
34897
  totalDays: validShifts.length
34496
34898
  };
34497
- }, [data, month, year, configuredTimezone, selectedShift]);
34498
- const handleDayClick = React23.useCallback((day, shift) => {
34899
+ }, [data, month, year, configuredTimezone, selectedShiftId]);
34900
+ const handleDayClick = React23.useCallback((day, shiftId) => {
34499
34901
  if (!day || isFutureDate(day.date)) return;
34500
34902
  const year2 = day.date.getFullYear();
34501
34903
  const month2 = String(day.date.getMonth() + 1).padStart(2, "0");
34502
34904
  const dayOfMonth = String(day.date.getDate()).padStart(2, "0");
34503
34905
  const formattedDate = `${year2}-${month2}-${dayOfMonth}`;
34504
- const shiftData = shift === "day" ? day.dayShift : day.nightShift;
34906
+ const shiftData = getShiftData(day, shiftId);
34505
34907
  trackCoreEvent("Workspace Monthly History Day Clicked", {
34506
34908
  source: "workspace_detail",
34507
34909
  workspace_id: workspaceId,
34508
34910
  date: formattedDate,
34911
+ shift_id: shiftId,
34509
34912
  efficiency: shiftData.efficiency,
34510
34913
  output: shiftData.output,
34511
34914
  cycle_time: shiftData.cycleTime
34512
34915
  });
34513
- onDateSelect(formattedDate);
34916
+ onDateSelect(formattedDate, shiftId);
34514
34917
  }, [workspaceId, onDateSelect]);
34515
- const handleShiftChange = React23.useCallback((shift) => {
34918
+ const handleShiftChange = React23.useCallback((shiftId) => {
34516
34919
  trackCoreEvent("Workspace Calendar Shift Changed", {
34517
34920
  workspace_id: workspaceId,
34518
- new_shift: shift
34921
+ new_shift_id: shiftId
34519
34922
  });
34520
34923
  if (onShiftChange) {
34521
- onShiftChange(shift);
34924
+ onShiftChange(shiftId);
34522
34925
  }
34523
34926
  }, [workspaceId, onShiftChange]);
34524
34927
  const isCurrentDate = React23.useCallback((date) => {
@@ -34599,13 +35002,13 @@ var WorkspaceHistoryCalendar = ({
34599
35002
  }
34600
35003
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: `h-full border border-gray-200 rounded-lg ${bgColor} ${animationComplete ? "transition-all duration-300 ease-in-out" : ""} cursor-not-allowed opacity-60`, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-1 sm:p-2", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: `text-xs sm:text-sm lg:text-base font-medium ${textColor} ${isToday ? "text-blue-500" : ""}`, children: dayNumber }) }) });
34601
35004
  }
34602
- const shiftData = selectedShift === "day" ? day.dayShift : day.nightShift;
35005
+ const shiftData = getShiftData(day, selectedShiftId);
34603
35006
  const hasData = hasRealData(shiftData);
34604
35007
  return /* @__PURE__ */ jsxRuntime.jsx(
34605
35008
  "div",
34606
35009
  {
34607
35010
  className: `group h-full ${animationComplete ? "transition-all duration-300 ease-in-out" : ""} ${!isFuture && hasData && animationComplete ? "cursor-pointer hover:opacity-90 hover:scale-105" : "cursor-not-allowed"}`,
34608
- onClick: () => !isFuture && hasData && handleDayClick(day, selectedShift),
35011
+ onClick: () => !isFuture && hasData && handleDayClick(day, selectedShiftId),
34609
35012
  children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `
34610
35013
  ${getPerformanceColor(shiftData.efficiency, day.date, hasData)}
34611
35014
  rounded-lg h-full p-1 sm:p-2 relative ${animationComplete ? "transition-all duration-300 ease-in-out" : ""} shadow-sm
@@ -34619,31 +35022,25 @@ var WorkspaceHistoryCalendar = ({
34619
35022
  ] })
34620
35023
  }
34621
35024
  );
34622
- }, [selectedShift, isCurrentDate, isFutureDate, getPerformanceColor, handleDayClick, year, month, configuredTimezone, animationComplete, hasRealData]);
35025
+ }, [selectedShiftId, isCurrentDate, isFutureDate, getPerformanceColor, handleDayClick, year, month, configuredTimezone, animationComplete, hasRealData]);
34623
35026
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `calendar-wrapper space-y-6 ${className || ""} ${animationComplete ? "animation-complete" : ""}`, children: [
34624
35027
  /* @__PURE__ */ jsxRuntime.jsx("style", { dangerouslySetInnerHTML: { __html: styles } }),
34625
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-center", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-1 border border-gray-200 rounded-lg p-1 bg-gray-50", children: [
34626
- /* @__PURE__ */ jsxRuntime.jsx(
34627
- "button",
34628
- {
34629
- onClick: () => handleShiftChange("day"),
34630
- className: `px-4 py-2 text-sm font-medium rounded-md ${animationComplete ? "transition-all duration-200" : ""} ${selectedShift === "day" ? "bg-white text-blue-600 shadow-sm ring-1 ring-gray-200" : `text-gray-600 ${animationComplete ? "hover:text-gray-900 hover:bg-gray-100" : ""}`}`,
34631
- children: "Day Shift"
34632
- }
34633
- ),
34634
- /* @__PURE__ */ jsxRuntime.jsx(
34635
- "button",
34636
- {
34637
- onClick: () => handleShiftChange("night"),
34638
- className: `px-4 py-2 text-sm font-medium rounded-md ${animationComplete ? "transition-all duration-200" : ""} ${selectedShift === "night" ? "bg-white text-blue-600 shadow-sm ring-1 ring-gray-200" : `text-gray-600 ${animationComplete ? "hover:text-gray-900 hover:bg-gray-100" : ""}`}`,
34639
- children: "Night Shift"
34640
- }
34641
- )
34642
- ] }) }),
35028
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-center", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex gap-1 border border-gray-200 rounded-lg p-1 bg-gray-50", children: (availableShifts && availableShifts.length > 0 ? availableShifts : [
35029
+ { id: 0, name: "Day Shift" },
35030
+ { id: 1, name: "Night Shift" }
35031
+ ]).sort((a, b) => a.id - b.id).map((shift) => /* @__PURE__ */ jsxRuntime.jsx(
35032
+ "button",
35033
+ {
35034
+ onClick: () => handleShiftChange(shift.id),
35035
+ className: `px-4 py-2 text-sm font-medium rounded-md ${animationComplete ? "transition-all duration-200" : ""} ${selectedShiftId === shift.id ? "bg-white text-blue-600 shadow-sm ring-1 ring-gray-200" : `text-gray-600 ${animationComplete ? "hover:text-gray-900 hover:bg-gray-100" : ""}`}`,
35036
+ children: shift.name
35037
+ },
35038
+ shift.id
35039
+ )) }) }),
34643
35040
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-1 lg:grid-cols-2 gap-4 lg:gap-8", children: [
34644
35041
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "calendar-container bg-white rounded-xl shadow-sm border border-gray-100 p-3 sm:p-4 lg:p-6 transition-all duration-200 ease-in-out", children: [
34645
35042
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-3 sm:mb-4 lg:mb-6", children: [
34646
- /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "font-semibold text-gray-900 text-base sm:text-lg", children: selectedShift === "day" ? "Day Shifts" : "Night Shifts" }),
35043
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "font-semibold text-gray-900 text-base sm:text-lg", children: (availableShifts?.find((s) => s.id === selectedShiftId)?.name || (selectedShiftId === 0 ? "Day" : selectedShiftId === 1 ? "Night" : `Shift ${selectedShiftId}`)) + "s" }),
34647
35044
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs sm:text-sm text-gray-500 mt-1", children: "Calendar view of daily performance" })
34648
35045
  ] }),
34649
35046
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-3 sm:gap-4 lg:gap-6", children: [
@@ -34659,7 +35056,7 @@ var WorkspaceHistoryCalendar = ({
34659
35056
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-3 sm:mb-4 lg:mb-6", children: [
34660
35057
  /* @__PURE__ */ jsxRuntime.jsxs("h3", { className: "font-semibold text-gray-900 text-base sm:text-lg", children: [
34661
35058
  "Monthly Summary - ",
34662
- selectedShift === "day" ? "Day Shift" : "Night Shift"
35059
+ availableShifts?.find((s) => s.id === selectedShiftId)?.name || (selectedShiftId === 0 ? "Day Shift" : selectedShiftId === 1 ? "Night Shift" : `Shift ${selectedShiftId}`)
34663
35060
  ] }),
34664
35061
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs sm:text-sm text-gray-500 mt-1", children: "Overview of monthly performance metrics" })
34665
35062
  ] }),
@@ -34733,10 +35130,11 @@ var WorkspaceMonthlyHistory = ({
34733
35130
  month,
34734
35131
  year,
34735
35132
  workspaceId,
34736
- selectedShift = "day",
35133
+ selectedShiftId = 0,
34737
35134
  onDateSelect,
34738
35135
  onMonthNavigate,
34739
35136
  onShiftChange,
35137
+ availableShifts,
34740
35138
  monthlyDataLoading = false,
34741
35139
  className = ""
34742
35140
  }) => {
@@ -34754,7 +35152,7 @@ var WorkspaceMonthlyHistory = ({
34754
35152
  const date = new Date(d.date);
34755
35153
  return date.getDate() === day;
34756
35154
  });
34757
- const shiftData = dayData ? selectedShift === "day" ? dayData.dayShift : dayData.nightShift : null;
35155
+ const shiftData = dayData ? getShiftData(dayData, selectedShiftId) : null;
34758
35156
  const idealOutput = shiftData ? shiftData.idealOutput : 0;
34759
35157
  if (idealOutput > 0) {
34760
35158
  lastSetTarget = idealOutput;
@@ -34766,7 +35164,7 @@ var WorkspaceMonthlyHistory = ({
34766
35164
  const date = new Date(d.date);
34767
35165
  return date.getDate() === day;
34768
35166
  });
34769
- const shiftData = dayData ? selectedShift === "day" ? dayData.dayShift : dayData.nightShift : null;
35167
+ const shiftData = dayData ? getShiftData(dayData, selectedShiftId) : null;
34770
35168
  const output = shiftData && hasRealData(shiftData) ? shiftData.output : 0;
34771
35169
  const idealOutput = shiftData ? shiftData.idealOutput : 0;
34772
35170
  if (output > maxOutput) maxOutput = output;
@@ -34788,7 +35186,7 @@ var WorkspaceMonthlyHistory = ({
34788
35186
  const calculatedMax = Math.max(maxOutput, lastSetTarget);
34789
35187
  const yAxisMax = calculatedMax > 0 ? calculatedMax * 1.1 : 100;
34790
35188
  return { data: dailyData, maxOutput, lastSetTarget, yAxisMax };
34791
- }, [data, month, year, selectedShift]);
35189
+ }, [data, month, year, selectedShiftId]);
34792
35190
  const yAxisTicks = React23.useMemo(() => {
34793
35191
  const max = chartData.yAxisMax;
34794
35192
  const target = chartData.lastSetTarget;
@@ -34811,7 +35209,7 @@ var WorkspaceMonthlyHistory = ({
34811
35209
  return Array.from(new Set(ticks)).filter((v) => v >= 0 && v <= max).sort((a, b) => a - b);
34812
35210
  }, [chartData.yAxisMax, chartData.lastSetTarget]);
34813
35211
  const pieChartData = React23.useMemo(() => {
34814
- const validShifts = data.map((d) => selectedShift === "day" ? d.dayShift : d.nightShift).filter(hasRealData);
35212
+ const validShifts = data.map((d) => getShiftData(d, selectedShiftId)).filter(hasRealData);
34815
35213
  if (validShifts.length === 0) return [];
34816
35214
  const totalIdleTime = validShifts.reduce((sum, shift) => sum + shift.idleTime, 0);
34817
35215
  const totalShiftTime = validShifts.length * 8 * 3600;
@@ -34820,9 +35218,9 @@ var WorkspaceMonthlyHistory = ({
34820
35218
  { name: "Productive", value: Math.round(activeTime / totalShiftTime * 100) },
34821
35219
  { name: "Idle", value: Math.round(totalIdleTime / totalShiftTime * 100) }
34822
35220
  ];
34823
- }, [data, selectedShift]);
35221
+ }, [data, selectedShiftId]);
34824
35222
  const metrics2 = React23.useMemo(() => {
34825
- const validShifts = data.map((d) => selectedShift === "day" ? d.dayShift : d.nightShift).filter(hasRealData);
35223
+ const validShifts = data.map((d) => getShiftData(d, selectedShiftId)).filter(hasRealData);
34826
35224
  if (validShifts.length === 0) return null;
34827
35225
  const totalEfficiency = validShifts.reduce((sum, shift) => sum + shift.efficiency, 0);
34828
35226
  const totalCycleTime = validShifts.reduce((sum, shift) => sum + shift.cycleTime, 0);
@@ -34842,7 +35240,7 @@ var WorkspaceMonthlyHistory = ({
34842
35240
  totalOutput,
34843
35241
  avgIdleTime: Math.round(totalIdleTime / validShifts.length)
34844
35242
  };
34845
- }, [data, selectedShift]);
35243
+ }, [data, selectedShiftId]);
34846
35244
  const calendarData = React23.useMemo(() => {
34847
35245
  const startOfMonth = new Date(year, month, 1);
34848
35246
  const endOfMonth = new Date(year, month + 1, 0);
@@ -34869,17 +35267,17 @@ var WorkspaceMonthlyHistory = ({
34869
35267
  source: "monthly_history",
34870
35268
  workspace_id: workspaceId,
34871
35269
  date: formattedDate,
34872
- shift: selectedShift
35270
+ shift_id: selectedShiftId
34873
35271
  });
34874
- onDateSelect(formattedDate, selectedShift);
34875
- }, [workspaceId, selectedShift, onDateSelect]);
34876
- const handleShiftChange = React23.useCallback((shift) => {
35272
+ onDateSelect(formattedDate, selectedShiftId);
35273
+ }, [workspaceId, selectedShiftId, onDateSelect]);
35274
+ const handleShiftChange = React23.useCallback((shiftId) => {
34877
35275
  trackCoreEvent("Workspace Monthly History Shift Changed", {
34878
35276
  workspace_id: workspaceId,
34879
- new_shift: shift
35277
+ new_shift_id: shiftId
34880
35278
  });
34881
35279
  if (onShiftChange) {
34882
- onShiftChange(shift);
35280
+ onShiftChange(shiftId);
34883
35281
  }
34884
35282
  }, [workspaceId, onShiftChange]);
34885
35283
  if (monthlyDataLoading) {
@@ -34892,24 +35290,18 @@ var WorkspaceMonthlyHistory = ({
34892
35290
  ) });
34893
35291
  }
34894
35292
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `flex flex-col gap-2 min-h-0 overflow-y-auto pb-6 ${className}`, children: [
34895
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-center mb-4", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-1 border border-gray-200 rounded-lg p-1 bg-gray-50", children: [
34896
- /* @__PURE__ */ jsxRuntime.jsx(
34897
- "button",
34898
- {
34899
- onClick: () => handleShiftChange("day"),
34900
- className: `px-4 py-2 text-sm font-medium rounded-md transition-all duration-200 ${selectedShift === "day" ? "bg-white text-blue-600 shadow-sm ring-1 ring-gray-200" : "text-gray-600 hover:text-gray-900 hover:bg-gray-100"}`,
34901
- children: "Day Shift"
34902
- }
34903
- ),
34904
- /* @__PURE__ */ jsxRuntime.jsx(
34905
- "button",
34906
- {
34907
- onClick: () => handleShiftChange("night"),
34908
- className: `px-4 py-2 text-sm font-medium rounded-md transition-all duration-200 ${selectedShift === "night" ? "bg-white text-blue-600 shadow-sm ring-1 ring-gray-200" : "text-gray-600 hover:text-gray-900 hover:bg-gray-100"}`,
34909
- children: "Night Shift"
34910
- }
34911
- )
34912
- ] }) }),
35293
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-center mb-4", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex gap-1 border border-gray-200 rounded-lg p-1 bg-gray-50", children: (availableShifts && availableShifts.length > 0 ? availableShifts : [
35294
+ { id: 0, name: "Day Shift" },
35295
+ { id: 1, name: "Night Shift" }
35296
+ ]).sort((a, b) => a.id - b.id).map((shift) => /* @__PURE__ */ jsxRuntime.jsx(
35297
+ "button",
35298
+ {
35299
+ onClick: () => handleShiftChange(shift.id),
35300
+ className: `px-4 py-2 text-sm font-medium rounded-md transition-all duration-200 ${selectedShiftId === shift.id ? "bg-white text-blue-600 shadow-sm ring-1 ring-gray-200" : "text-gray-600 hover:text-gray-900 hover:bg-gray-100"}`,
35301
+ children: shift.name
35302
+ },
35303
+ shift.id
35304
+ )) }) }),
34913
35305
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-1 lg:grid-cols-2 gap-6 mt-6", children: [
34914
35306
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-white rounded-xl shadow-sm border border-gray-100 p-6", children: [
34915
35307
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-center items-center mb-6 space-x-4", children: [
@@ -34973,7 +35365,7 @@ var WorkspaceMonthlyHistory = ({
34973
35365
  if (!dayNumber || dayNumber > new Date(year, month + 1, 0).getDate()) {
34974
35366
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "aspect-square relative", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-full border border-gray-100 dark:border-gray-700 rounded-lg bg-gray-50 dark:bg-gray-800" }) }, index);
34975
35367
  }
34976
- const shiftData = day ? selectedShift === "day" ? day.dayShift : day.nightShift : null;
35368
+ const shiftData = day ? getShiftData(day, selectedShiftId) : null;
34977
35369
  const hasData = shiftData ? hasRealData(shiftData) : false;
34978
35370
  const isToday = (/* @__PURE__ */ new Date()).getDate() === dayNumber && (/* @__PURE__ */ new Date()).getMonth() === month && (/* @__PURE__ */ new Date()).getFullYear() === year;
34979
35371
  const isFuture = new Date(year, month, dayNumber) > /* @__PURE__ */ new Date();
@@ -35300,7 +35692,8 @@ var WorkspacePdfGenerator = ({ workspace, className }) => {
35300
35692
  month: "long",
35301
35693
  timeZone: "Asia/Kolkata"
35302
35694
  });
35303
- const shiftType = "Day Shift";
35695
+ const rawShiftType = workspace.shift_type || (workspace.shift_id === 0 ? "Day" : workspace.shift_id === 1 ? "Night" : `Shift ${workspace.shift_id}`);
35696
+ const shiftType = rawShiftType.toLowerCase().includes("shift") ? rawShiftType : `${rawShiftType} Shift`;
35304
35697
  doc.text(`${date}`, 20, 63);
35305
35698
  doc.text(`${shiftType}`, 20, 71);
35306
35699
  const currentTime = (/* @__PURE__ */ new Date()).toLocaleTimeString("en-IN", {
@@ -35450,13 +35843,21 @@ var WorkspacePdfGenerator = ({ workspace, className }) => {
35450
35843
  }
35451
35844
  );
35452
35845
  };
35846
+ var getShiftDisplayName2 = (shiftId, availableShifts) => {
35847
+ const shift = availableShifts?.find((s) => s.id === shiftId);
35848
+ if (shift) return shift.name;
35849
+ if (shiftId === 0) return "Day Shift";
35850
+ if (shiftId === 1) return "Night Shift";
35851
+ return `Shift ${shiftId}`;
35852
+ };
35453
35853
  var WorkspaceMonthlyPdfGenerator = ({
35454
35854
  workspaceId,
35455
35855
  workspaceName,
35456
35856
  monthlyData,
35457
35857
  selectedMonth,
35458
35858
  selectedYear,
35459
- selectedShift,
35859
+ selectedShiftId,
35860
+ availableShifts,
35460
35861
  className
35461
35862
  }) => {
35462
35863
  const [isGenerating, setIsGenerating] = React23.useState(false);
@@ -35468,7 +35869,7 @@ var WorkspaceMonthlyPdfGenerator = ({
35468
35869
  workspace_name: workspaceName,
35469
35870
  month: selectedMonth,
35470
35871
  year: selectedYear,
35471
- shift: selectedShift
35872
+ shift_id: selectedShiftId
35472
35873
  });
35473
35874
  const doc = new jsPDF.jsPDF();
35474
35875
  doc.setFontSize(14);
@@ -35502,7 +35903,7 @@ var WorkspaceMonthlyPdfGenerator = ({
35502
35903
  year: "numeric",
35503
35904
  timeZone: "Asia/Kolkata"
35504
35905
  });
35505
- const shiftType = selectedShift === "day" ? "Day Shift" : "Night Shift";
35906
+ const shiftType = getShiftDisplayName2(selectedShiftId, availableShifts);
35506
35907
  doc.text(`${monthName}`, 20, 65);
35507
35908
  doc.text(`${shiftType}`, 20, 73);
35508
35909
  const startDate = new Date(selectedYear, selectedMonth, 1);
@@ -35531,7 +35932,7 @@ var WorkspaceMonthlyPdfGenerator = ({
35531
35932
  return date.getMonth() === selectedMonth && date.getFullYear() === selectedYear;
35532
35933
  });
35533
35934
  const validShifts = validDays.map(
35534
- (day) => selectedShift === "day" ? day.dayShift : day.nightShift
35935
+ (day) => getShiftData(day, selectedShiftId)
35535
35936
  ).filter((shift) => shift.efficiency > 0);
35536
35937
  const monthlyMetrics = validShifts.length > 0 ? {
35537
35938
  avgEfficiency: validShifts.reduce((sum, shift) => sum + shift.efficiency, 0) / validShifts.length,
@@ -35619,7 +36020,7 @@ var WorkspaceMonthlyPdfGenerator = ({
35619
36020
  const recentDays = validDays.slice(-10).reverse();
35620
36021
  recentDays.forEach((dayData, index) => {
35621
36022
  if (yPos > 260) return;
35622
- const shift = selectedShift === "day" ? dayData.dayShift : dayData.nightShift;
36023
+ const shift = getShiftData(dayData, selectedShiftId);
35623
36024
  if (shift.efficiency <= 0) return;
35624
36025
  if (index % 2 === 0) {
35625
36026
  doc.setFillColor(252, 252, 252);
@@ -37006,19 +37407,26 @@ var HealthStatusGrid = ({
37006
37407
  };
37007
37408
  var Timer2 = Timer_default;
37008
37409
  var DashboardHeader = React23.memo(({ lineTitle, className = "", headerControls, lineId }) => {
37009
- const { shiftConfig } = useDynamicShiftConfig(lineId);
37410
+ const { shiftConfig, isLoading: isShiftConfigLoading } = useDynamicShiftConfig(lineId);
37010
37411
  const timezone = useAppTimezone();
37011
37412
  const getShiftName = () => {
37012
37413
  const currentShift = getCurrentShift(timezone, shiftConfig);
37013
- return currentShift.shiftId === 0 ? "Day" : "Night";
37414
+ const rawName = currentShift.shiftName || "Day";
37415
+ return rawName.toLowerCase().includes("shift") ? rawName : `${rawName} Shift`;
37014
37416
  };
37015
- const getShiftIcon = () => {
37016
- const shift = getShiftName();
37017
- if (shift === "Day") {
37417
+ const getShiftIcon2 = () => {
37418
+ const currentShift = getCurrentShift(timezone, shiftConfig);
37419
+ const shiftName = (currentShift.shiftName || "").toLowerCase();
37420
+ if (shiftName.includes("day") || shiftName.includes("morning") || currentShift.shiftId === 0) {
37018
37421
  return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" }) });
37019
- } else {
37422
+ }
37423
+ if (shiftName.includes("afternoon") || shiftName.includes("noon") || shiftName.includes("midday")) {
37424
+ return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" }) });
37425
+ }
37426
+ if (shiftName.includes("night") || shiftName.includes("evening") || currentShift.shiftId === 1) {
37020
37427
  return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z" }) });
37021
37428
  }
37429
+ return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" }) });
37022
37430
  };
37023
37431
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `flex flex-col sm:flex-row items-start sm:items-center justify-between w-full gap-2 sm:gap-4 ${className}`, children: [
37024
37432
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col", children: [
@@ -37028,13 +37436,10 @@ var DashboardHeader = React23.memo(({ lineTitle, className = "", headerControls,
37028
37436
  ] }),
37029
37437
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-0.5 sm:mt-2 inline-flex flex-wrap items-center gap-1.5 sm:gap-3", children: [
37030
37438
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-[10px] sm:text-xs md:text-sm font-medium text-gray-500 sm:text-gray-600 whitespace-nowrap", children: /* @__PURE__ */ jsxRuntime.jsx(Timer2, {}) }),
37031
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "inline-flex items-center gap-0.5 sm:gap-1", children: [
37032
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-gray-500 sm:text-gray-600 scale-90 sm:scale-100", children: getShiftIcon() }),
37033
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-[10px] sm:text-xs md:text-sm font-medium text-gray-500 sm:text-gray-600 whitespace-nowrap", children: [
37034
- getShiftName(),
37035
- " Shift"
37036
- ] })
37037
- ] })
37439
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "inline-flex items-center gap-0.5 sm:gap-1", children: isShiftConfigLoading ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-4 w-16 sm:w-20 bg-gray-200 rounded animate-pulse" }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
37440
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-gray-500 sm:text-gray-600 scale-90 sm:scale-100", children: getShiftIcon2() }),
37441
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] sm:text-xs md:text-sm font-medium text-gray-500 sm:text-gray-600 whitespace-nowrap", children: getShiftName() })
37442
+ ] }) })
37038
37443
  ] })
37039
37444
  ] }),
37040
37445
  headerControls && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-1.5 sm:gap-3 md:gap-4 w-full sm:w-auto justify-end", children: headerControls })
@@ -42051,18 +42456,23 @@ var FactoryView = ({
42051
42456
  fetchHourlyData();
42052
42457
  }
42053
42458
  }, [supabase, lineDataHooks, effectiveLineIds, lineNames, factoryName, timezone, shiftConfig, productIds]);
42459
+ const getCurrentShiftInfo = () => {
42460
+ return getCurrentShift(timezone, shiftConfig);
42461
+ };
42054
42462
  const getShiftName = () => {
42055
- const now2 = /* @__PURE__ */ new Date();
42056
- const currentHour = now2.getHours();
42057
- return currentHour >= 6 && currentHour < 18 ? "Day" : "Night";
42463
+ const currentShift = getCurrentShiftInfo();
42464
+ return (currentShift.shiftName || "Day").replace(/ Shift$/i, "");
42058
42465
  };
42059
- const getShiftIcon = () => {
42060
- const shift = getShiftName();
42061
- if (shift === "Day") {
42466
+ const getShiftIcon2 = () => {
42467
+ const currentShift = getCurrentShiftInfo();
42468
+ const shiftNameLower = (currentShift.shiftName || "").toLowerCase();
42469
+ if (shiftNameLower.includes("day") || shiftNameLower.includes("morning") || currentShift.shiftId === 0) {
42062
42470
  return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" }) });
42063
- } else {
42471
+ }
42472
+ if (shiftNameLower.includes("night") || shiftNameLower.includes("evening") || currentShift.shiftId === 1) {
42064
42473
  return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z" }) });
42065
42474
  }
42475
+ return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" }) });
42066
42476
  };
42067
42477
  if (loading || lineDataHooks.some((hookData) => hookData.hook.loading)) {
42068
42478
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-4", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "animate-pulse space-y-4", children: [
@@ -42091,7 +42501,7 @@ var FactoryView = ({
42091
42501
  " IST"
42092
42502
  ] }),
42093
42503
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "inline-flex items-center gap-1", children: [
42094
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-gray-600", children: getShiftIcon() }),
42504
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-gray-600", children: getShiftIcon2() }),
42095
42505
  /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-sm font-medium text-gray-600", children: [
42096
42506
  getShiftName(),
42097
42507
  " Shift"
@@ -43591,8 +44001,8 @@ var KPIDetailView = ({
43591
44001
  return (/* @__PURE__ */ new Date()).getFullYear();
43592
44002
  });
43593
44003
  const [monthlyData, setMonthlyData] = React23.useState([]);
43594
- const [underperformingWorkspaces, setUnderperformingWorkspaces] = React23.useState({ dayShift: [], nightShift: [] });
43595
- const [selectedShift, setSelectedShift] = React23.useState("day");
44004
+ const [underperformingWorkspaces, setUnderperformingWorkspaces] = React23.useState({});
44005
+ const [selectedShiftId, setSelectedShiftId] = React23.useState(0);
43596
44006
  const [showLineDataNotFound, setShowLineDataNotFound] = React23.useState(false);
43597
44007
  const navigation = useNavigation(navigate);
43598
44008
  const handleNavigate = navigate || navigation.navigate;
@@ -43622,20 +44032,22 @@ var KPIDetailView = ({
43622
44032
  setActiveTab("overview");
43623
44033
  }
43624
44034
  }, [urlDate, urlShift, urlTab]);
44035
+ const { shiftConfig, isLoading: isShiftConfigLoading } = useDynamicShiftConfig(lineId);
43625
44036
  const getShiftName = React23.useCallback((shiftId) => {
43626
- return shiftId === 0 ? "Day" : "Night";
43627
- }, []);
43628
- const getShiftIcon = React23.useCallback((shiftId) => {
43629
- const shift = getShiftName(shiftId);
43630
- if (shift === "Day") {
44037
+ return getShiftNameById(shiftId, configuredTimezone, shiftConfig);
44038
+ }, [configuredTimezone, shiftConfig]);
44039
+ const getShiftIcon2 = React23.useCallback((shiftId) => {
44040
+ if (shiftId === 0) {
43631
44041
  return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" }) });
43632
- } else {
44042
+ }
44043
+ if (shiftId === 1) {
43633
44044
  return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z" }) });
43634
44045
  }
43635
- }, [getShiftName]);
44046
+ return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" }) });
44047
+ }, []);
43636
44048
  const getDaysDifference2 = React23.useCallback((date) => {
43637
44049
  const compareDate = new Date(date);
43638
- const shiftStartTime = dashboardConfig.shiftConfig?.dayShift?.startTime || "06:00";
44050
+ const shiftStartTime = shiftConfig?.dayShift?.startTime || shiftConfig?.shifts?.[0]?.startTime || "06:00";
43639
44051
  const operationalTodayString = getOperationalDate(configuredTimezone, /* @__PURE__ */ new Date(), shiftStartTime);
43640
44052
  const operationalTodayDate = new Date(operationalTodayString);
43641
44053
  const compareDateInZone = new Date(compareDate.toLocaleString("en-US", { timeZone: configuredTimezone }));
@@ -43649,7 +44061,7 @@ var KPIDetailView = ({
43649
44061
  if (diffDays < -1) return `${Math.abs(diffDays)} days ago`;
43650
44062
  if (diffDays > 1) return `${diffDays} days ahead`;
43651
44063
  return "Today";
43652
- }, [configuredTimezone, dashboardConfig.shiftConfig]);
44064
+ }, [configuredTimezone, shiftConfig]);
43653
44065
  const {
43654
44066
  metrics: metrics2,
43655
44067
  lineDetails,
@@ -43659,7 +44071,9 @@ var KPIDetailView = ({
43659
44071
  } = useRealtimeLineMetrics({
43660
44072
  lineId,
43661
44073
  date: typeof urlDate === "string" ? urlDate : void 0,
43662
- shiftId: parsedShiftId
44074
+ shiftId: parsedShiftId,
44075
+ enabled: !isShiftConfigLoading
44076
+ // Pass enabled flag to useRealtimeLineMetrics if supported, or we need to add it
43663
44077
  });
43664
44078
  const {
43665
44079
  workspaces,
@@ -43668,7 +44082,9 @@ var KPIDetailView = ({
43668
44082
  refreshWorkspaces
43669
44083
  } = useLineWorkspaceMetrics(lineId, {
43670
44084
  initialDate: typeof urlDate === "string" ? urlDate : void 0,
43671
- initialShiftId: parsedShiftId
44085
+ initialShiftId: parsedShiftId,
44086
+ enabled: !isShiftConfigLoading
44087
+ // Pass enabled flag to useLineWorkspaceMetrics if supported, or we need to add it
43672
44088
  });
43673
44089
  React23.useEffect(() => {
43674
44090
  if (activeTab === "monthly_history" && lineId) {
@@ -43681,7 +44097,9 @@ var KPIDetailView = ({
43681
44097
  dashboardService.getUnderperformingWorkspaces(
43682
44098
  lineId,
43683
44099
  currentMonth,
43684
- currentYear
44100
+ currentYear,
44101
+ shiftConfig?.shifts?.map((s) => s.shiftId)
44102
+ // Pass dynamic shift IDs
43685
44103
  )
43686
44104
  ]).then(([monthlyMetrics, underperformingData]) => {
43687
44105
  console.log("Fetched monthly metrics data:", monthlyMetrics);
@@ -43693,18 +44111,8 @@ var KPIDetailView = ({
43693
44111
  if (!dayData) {
43694
44112
  dayData = {
43695
44113
  date,
43696
- dayShift: {
43697
- avg_efficiency: 0,
43698
- underperforming_workspaces: 0,
43699
- total_workspaces: 0,
43700
- compliance_percentage: 0
43701
- },
43702
- nightShift: {
43703
- avg_efficiency: 0,
43704
- underperforming_workspaces: 0,
43705
- total_workspaces: 0,
43706
- compliance_percentage: 0
43707
- }
44114
+ shifts: {}
44115
+ // Multi-shift structure: Record<number, ShiftData>
43708
44116
  };
43709
44117
  dayDataMap.set(dateKey, dayData);
43710
44118
  }
@@ -43712,46 +44120,46 @@ var KPIDetailView = ({
43712
44120
  avg_efficiency: metric.avg_efficiency || 0,
43713
44121
  underperforming_workspaces: metric.underperforming_workspaces || 0,
43714
44122
  total_workspaces: metric.total_workspaces || 0,
43715
- compliance_percentage: 95 + Math.random() * 5
44123
+ compliance_percentage: 95 + Math.random() * 5,
43716
44124
  // Mock data: random value between 95-100%
44125
+ hasData: true
43717
44126
  };
43718
- if (metric.shift_id === 0) {
43719
- dayData.dayShift = shiftData;
43720
- } else {
43721
- dayData.nightShift = shiftData;
43722
- }
44127
+ dayData.shifts[metric.shift_id] = shiftData;
43723
44128
  });
43724
44129
  const transformedMonthlyData = Array.from(dayDataMap.values());
43725
44130
  console.log("Transformed monthly data for calendar:", transformedMonthlyData);
43726
44131
  setMonthlyData(transformedMonthlyData);
43727
- const mappedData = {
43728
- dayShift: (underperformingData.dayShift || []).map((ws) => ({
43729
- workspace_name: ws.workspace_name || "Unknown Workspace",
43730
- workspace_uuid: ws.workspace_uuid || ws.workspace_name || `unknown-${Math.random()}`,
43731
- avg_efficiency: ws.avg_efficiency || 0,
43732
- last_5_days: (ws.last_5_days || []).map((day) => ({
43733
- date: day.date,
43734
- efficiency: day.efficiency ?? 0,
43735
- performance_score: day.performance_score
43736
- }))
43737
- })),
43738
- nightShift: (underperformingData.nightShift || []).map((ws) => ({
43739
- workspace_name: ws.workspace_name || "Unknown Workspace",
43740
- workspace_uuid: ws.workspace_uuid || ws.workspace_name || `unknown-${Math.random()}`,
43741
- avg_efficiency: ws.avg_efficiency || 0,
43742
- last_5_days: (ws.last_5_days || []).map((day) => ({
43743
- date: day.date,
43744
- efficiency: day.efficiency ?? 0,
43745
- performance_score: day.performance_score
43746
- }))
44132
+ const mapWorkspaces = (workspaces2) => (workspaces2 || []).map((ws) => ({
44133
+ workspace_name: ws.workspace_name || "Unknown Workspace",
44134
+ workspace_uuid: ws.workspace_uuid || ws.workspace_name || `unknown-${Math.random()}`,
44135
+ avg_efficiency: ws.avg_efficiency || 0,
44136
+ last_5_days: (ws.last_5_days || []).map((day) => ({
44137
+ date: day.date,
44138
+ efficiency: day.efficiency ?? 0,
44139
+ performance_score: day.performance_score
43747
44140
  }))
43748
- };
44141
+ }));
44142
+ const mappedData = {};
44143
+ if (underperformingData.dayShift) {
44144
+ mappedData[0] = mapWorkspaces(underperformingData.dayShift);
44145
+ }
44146
+ if (underperformingData.nightShift) {
44147
+ mappedData[1] = mapWorkspaces(underperformingData.nightShift);
44148
+ }
44149
+ Object.entries(underperformingData).forEach(([key, value]) => {
44150
+ if (key !== "dayShift" && key !== "nightShift" && Array.isArray(value)) {
44151
+ const shiftId = parseInt(key);
44152
+ if (!isNaN(shiftId)) {
44153
+ mappedData[shiftId] = mapWorkspaces(value);
44154
+ }
44155
+ }
44156
+ });
43749
44157
  setUnderperformingWorkspaces(mappedData);
43750
44158
  }).catch((error) => {
43751
44159
  console.error("Error fetching monthly data:", error);
43752
44160
  });
43753
44161
  }
43754
- }, [activeTab, lineId, currentMonth, currentYear, supabase, dashboardConfig]);
44162
+ }, [activeTab, lineId, currentMonth, currentYear, supabase, dashboardConfig, shiftConfig]);
43755
44163
  const lineInfo = React23.useMemo(() => {
43756
44164
  if (!metrics2 || !lineDetails || !lineDetails.factory) {
43757
44165
  return null;
@@ -43996,7 +44404,7 @@ var KPIDetailView = ({
43996
44404
  handleNavigate(backUrl);
43997
44405
  }
43998
44406
  }, [urlDate, urlShift, lineInfo, onBackClick, backLinkUrl, handleNavigate, urlMonth, urlYear, lineId, currentMonth, currentYear]);
43999
- if ((lineMetricsLoading || workspacesLoading) && !lineInfo && !metrics2) {
44407
+ if ((lineMetricsLoading || workspacesLoading || isShiftConfigLoading) && !lineInfo && !metrics2) {
44000
44408
  return /* @__PURE__ */ jsxRuntime.jsx(LoadingPage, { message: "Loading line metrics..." });
44001
44409
  }
44002
44410
  if (lineMetricsError || workspacesError) {
@@ -44102,8 +44510,11 @@ var KPIDetailView = ({
44102
44510
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "sm:hidden mt-3 flex items-center justify-center gap-2", children: [
44103
44511
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "inline-flex items-center px-2.5 py-1 bg-gray-100 rounded-full", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-gray-700", children: metrics2 && formatLocalDate(new Date(metrics2.date)) }) }),
44104
44512
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "inline-flex items-center gap-1 px-2.5 py-1 bg-gray-100 rounded-full", children: [
44105
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-gray-700 scale-90", children: getShiftIcon(metrics2.shift_id ?? 0) }),
44106
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-gray-700", children: getShiftName(metrics2.shift_id ?? 0) })
44513
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-gray-700 scale-90", children: getShiftIcon2(metrics2.shift_id ?? 0) }),
44514
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs font-medium text-gray-700", children: [
44515
+ getShiftName(metrics2.shift_id ?? 0).replace(/ Shift$/i, ""),
44516
+ " Shift"
44517
+ ] })
44107
44518
  ] }),
44108
44519
  !urlDate && !urlShift ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "inline-flex items-center px-2.5 py-1 bg-green-100 rounded-full", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-green-700", children: /* @__PURE__ */ jsxRuntime.jsx(ISTTimer_default, {}) }) }) : urlDate && metrics2.date ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "inline-flex items-center px-2.5 py-1 bg-blue-100 rounded-full", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-blue-700", children: getDaysDifference2(metrics2.date) }) }) : null
44109
44520
  ] }),
@@ -44119,9 +44530,9 @@ var KPIDetailView = ({
44119
44530
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-px h-4 bg-blue-300" })
44120
44531
  ] }),
44121
44532
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
44122
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-blue-600", children: getShiftIcon(metrics2.shift_id ?? 0) }),
44533
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-blue-600", children: getShiftIcon2(metrics2.shift_id ?? 0) }),
44123
44534
  /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-sm md:text-base font-medium text-blue-600", children: [
44124
- getShiftName(metrics2.shift_id ?? 0),
44535
+ getShiftName(metrics2.shift_id ?? 0).replace(/ Shift$/i, ""),
44125
44536
  " Shift"
44126
44537
  ] })
44127
44538
  ] })
@@ -44166,7 +44577,7 @@ var KPIDetailView = ({
44166
44577
  )
44167
44578
  ] }),
44168
44579
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center space-x-3 ml-auto", children: [
44169
- lineInfo && activeTab === "overview" && /* @__PURE__ */ jsxRuntime.jsx(LinePdfGenerator, { lineInfo, workspaceData: workspaces || [] }),
44580
+ lineInfo && activeTab === "overview" && /* @__PURE__ */ jsxRuntime.jsx(LinePdfGenerator, { lineInfo, workspaceData: workspaces || [], shiftName: getShiftName(lineInfo.shift_id) }),
44170
44581
  activeTab === "monthly_history" && /* @__PURE__ */ jsxRuntime.jsx(
44171
44582
  LineMonthlyPdfGenerator,
44172
44583
  {
@@ -44176,7 +44587,7 @@ var KPIDetailView = ({
44176
44587
  underperformingWorkspaces,
44177
44588
  selectedMonth: currentMonth,
44178
44589
  selectedYear: currentYear,
44179
- selectedShift
44590
+ selectedShiftId
44180
44591
  }
44181
44592
  )
44182
44593
  ] })
@@ -44279,8 +44690,9 @@ var KPIDetailView = ({
44279
44690
  monthlyData,
44280
44691
  month: currentMonth,
44281
44692
  year: currentYear,
44282
- selectedShift,
44283
- onShiftChange: setSelectedShift
44693
+ selectedShiftId,
44694
+ onShiftChange: setSelectedShiftId,
44695
+ availableShifts: shiftConfig?.shifts?.map((s) => ({ id: s.shiftId, name: s.shiftName }))
44284
44696
  }
44285
44697
  )
44286
44698
  ]
@@ -44431,7 +44843,8 @@ var KPIsOverviewView = ({
44431
44843
  const dashboardConfig = useDashboardConfig();
44432
44844
  const navigation = useNavigation(navigate);
44433
44845
  const dateTimeConfig = useDateTimeConfig();
44434
- const shiftConfig = useShiftConfig();
44846
+ const representativeLineId = lineIds?.[0] || lines[0]?.id;
44847
+ const { shiftConfig, isLoading: isShiftConfigLoading } = useDynamicShiftConfig(representativeLineId);
44435
44848
  const supervisorEnabled = dashboardConfig?.supervisorConfig?.enabled || false;
44436
44849
  const dbTimezone = useAppTimezone();
44437
44850
  const configuredTimezone = dbTimezone || dateTimeConfig.defaultTimezone || "UTC";
@@ -44493,15 +44906,21 @@ var KPIsOverviewView = ({
44493
44906
  return date.toLocaleDateString("en-US", options);
44494
44907
  };
44495
44908
  const currentShiftDetails = getCurrentShift(configuredTimezone, shiftConfig);
44496
- const shiftName = currentShiftDetails.shiftId === 0 ? "Day" : "Night";
44497
- const getShiftIcon = (shiftId) => {
44498
- if (shiftId === 0) {
44909
+ const shiftName = (currentShiftDetails.shiftName || "Day").replace(/ Shift$/i, "");
44910
+ const getShiftIcon2 = (shiftId) => {
44911
+ const shiftNameLower = shiftName.toLowerCase();
44912
+ if (shiftNameLower.includes("day") || shiftNameLower.includes("morning") || shiftId === 0) {
44499
44913
  return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" }) });
44500
- } else {
44914
+ }
44915
+ if (shiftNameLower.includes("afternoon") || shiftNameLower.includes("noon") || shiftNameLower.includes("midday")) {
44916
+ return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" }) });
44917
+ }
44918
+ if (shiftNameLower.includes("night") || shiftNameLower.includes("evening") || shiftId === 1) {
44501
44919
  return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z" }) });
44502
44920
  }
44921
+ return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" }) });
44503
44922
  };
44504
- if (loading) {
44923
+ if (loading || isShiftConfigLoading) {
44505
44924
  return /* @__PURE__ */ jsxRuntime.jsx(LoadingPage, { message: "Loading production lines..." });
44506
44925
  }
44507
44926
  if (error) {
@@ -44609,7 +45028,7 @@ var KPIsOverviewView = ({
44609
45028
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "sm:hidden mt-3 flex items-center justify-center gap-2", children: [
44610
45029
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "inline-flex items-center px-2.5 py-1 bg-gray-100 rounded-full", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-gray-700", children: formatLocalDate2(/* @__PURE__ */ new Date()) }) }),
44611
45030
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "inline-flex items-center gap-1 px-2.5 py-1 bg-gray-100 rounded-full", children: [
44612
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-gray-700 scale-90", children: getShiftIcon(currentShiftDetails.shiftId) }),
45031
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-gray-700 scale-90", children: getShiftIcon2(currentShiftDetails.shiftId) }),
44613
45032
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-gray-700", children: shiftName })
44614
45033
  ] }),
44615
45034
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "inline-flex items-center px-2.5 py-1 bg-green-100 rounded-full", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-green-700", children: /* @__PURE__ */ jsxRuntime.jsx(ISTTimer_default, {}) }) })
@@ -44620,7 +45039,7 @@ var KPIsOverviewView = ({
44620
45039
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm md:text-base font-medium text-blue-600", children: formatLocalDate2(/* @__PURE__ */ new Date()) }),
44621
45040
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-px h-4 bg-blue-300" }),
44622
45041
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
44623
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-blue-600", children: getShiftIcon(currentShiftDetails.shiftId) }),
45042
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-blue-600", children: getShiftIcon2(currentShiftDetails.shiftId) }),
44624
45043
  /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-sm md:text-base font-medium text-blue-600", children: [
44625
45044
  shiftName,
44626
45045
  " Shift"
@@ -44648,10 +45067,10 @@ var HeaderRibbon = React23.memo(({
44648
45067
  currentDate,
44649
45068
  currentMobileDate,
44650
45069
  shiftId,
44651
- getShiftIcon,
45070
+ getShiftIcon: getShiftIcon2,
44652
45071
  getShiftName
44653
45072
  }) => {
44654
- const shiftIcon = React23.useMemo(() => getShiftIcon(shiftId), [getShiftIcon, shiftId]);
45073
+ const shiftIcon = React23.useMemo(() => getShiftIcon2(shiftId), [getShiftIcon2, shiftId]);
44655
45074
  const shiftName = React23.useMemo(() => getShiftName(shiftId), [getShiftName, shiftId]);
44656
45075
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
44657
45076
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "sm:hidden mt-3 flex items-center justify-center gap-2", children: [
@@ -44670,7 +45089,7 @@ var HeaderRibbon = React23.memo(({
44670
45089
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
44671
45090
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-blue-600", children: shiftIcon }),
44672
45091
  /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-sm md:text-base font-medium text-blue-600", children: [
44673
- shiftName,
45092
+ shiftName.replace(/ Shift$/i, ""),
44674
45093
  " Shift"
44675
45094
  ] })
44676
45095
  ] })
@@ -44797,6 +45216,7 @@ var LeaderboardDetailView = React23.memo(({
44797
45216
  const navigation = useNavigation();
44798
45217
  const entityConfig = useEntityConfig();
44799
45218
  const [sortAscending, setSortAscending] = React23.useState(false);
45219
+ const timezone = useAppTimezone();
44800
45220
  const [isMobile, setIsMobile] = React23.useState(false);
44801
45221
  React23__namespace.default.useEffect(() => {
44802
45222
  const checkMobile = () => setIsMobile(window.innerWidth < 640);
@@ -44825,6 +45245,9 @@ var LeaderboardDetailView = React23.memo(({
44825
45245
  () => typeof shift === "number" ? shift : typeof shift === "string" ? parseInt(shift) : void 0,
44826
45246
  [shift]
44827
45247
  );
45248
+ const availableLineId = Object.keys(configuredLineNames)[0];
45249
+ const effectiveLineId = lineId || userAccessibleLineIds?.[0] || availableLineId;
45250
+ const { shiftConfig, isLoading: isShiftConfigLoading } = useDynamicShiftConfig(effectiveLineId);
44828
45251
  const {
44829
45252
  workspaces,
44830
45253
  loading: workspacesLoading,
@@ -44833,20 +45256,31 @@ var LeaderboardDetailView = React23.memo(({
44833
45256
  } = useAllWorkspaceMetrics({
44834
45257
  initialDate: date,
44835
45258
  initialShiftId: typeof shift === "number" ? shift : typeof shift === "string" ? parseInt(shift) : void 0,
44836
- allowedLineIds: userAccessibleLineIds
45259
+ allowedLineIds: userAccessibleLineIds,
44837
45260
  // Filter to user's accessible lines only
45261
+ enabled: !isShiftConfigLoading
45262
+ // Pass enabled flag
44838
45263
  });
44839
45264
  const getShiftName = React23.useCallback((shiftId2) => {
44840
- if (shiftId2 === void 0) return "Day";
44841
- return shiftId2 === 0 ? "Day" : "Night";
44842
- }, []);
44843
- const getShiftIcon = React23.useCallback((shiftId2) => {
44844
- const shift2 = getShiftName(shiftId2);
44845
- if (shift2 === "Day") {
45265
+ if (shiftId2 !== void 0) {
45266
+ return getShiftNameById(shiftId2, timezone || "Asia/Kolkata", shiftConfig);
45267
+ }
45268
+ const currentShift = getCurrentShift(timezone || "Asia/Kolkata", shiftConfig);
45269
+ return currentShift.shiftName || getShiftNameById(currentShift.shiftId, timezone || "Asia/Kolkata", shiftConfig);
45270
+ }, [timezone, shiftConfig]);
45271
+ const getShiftIcon2 = React23.useCallback((shiftId2) => {
45272
+ const effectiveShiftId = shiftId2 !== void 0 ? shiftId2 : getCurrentShift(timezone || "Asia/Kolkata", shiftConfig).shiftId;
45273
+ const shiftNameLower = getShiftName(effectiveShiftId).toLowerCase();
45274
+ if (shiftNameLower.includes("day") || shiftNameLower.includes("morning")) {
44846
45275
  return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" }) });
44847
- } else {
45276
+ }
45277
+ if (shiftNameLower.includes("afternoon") || shiftNameLower.includes("noon") || shiftNameLower.includes("midday")) {
45278
+ return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" }) });
45279
+ }
45280
+ if (shiftNameLower.includes("night") || shiftNameLower.includes("evening")) {
44848
45281
  return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z" }) });
44849
45282
  }
45283
+ return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" }) });
44850
45284
  }, [getShiftName]);
44851
45285
  const formatDate = React23.useCallback((date2) => {
44852
45286
  return new Intl.DateTimeFormat("en-US", {
@@ -44896,13 +45330,27 @@ var LeaderboardDetailView = React23.memo(({
44896
45330
  });
44897
45331
  const displayName = workspace.displayName || getWorkspaceDisplayName(workspace.workspace_name, workspace.line_id);
44898
45332
  const navParams = workspace.workspace_uuid ? getWorkspaceNavigationParams(workspace.workspace_uuid, displayName, workspace.line_id) : "";
44899
- const returnToParam = `&returnTo=${encodeURIComponent(`/leaderboard`)}`;
45333
+ const contextParams = new URLSearchParams();
45334
+ if (date) {
45335
+ contextParams.set("date", date);
45336
+ }
45337
+ if (shiftId !== void 0) {
45338
+ contextParams.set("shift", shiftId.toString());
45339
+ }
45340
+ contextParams.set("returnTo", encodeURIComponent("/leaderboard"));
45341
+ const contextParamString = contextParams.toString();
44900
45342
  if (onWorkspaceClick) {
44901
- onWorkspaceClick(workspace, rank);
45343
+ const combinedParams = navParams ? `${navParams}&${contextParamString}` : `?${contextParamString}`;
45344
+ const enhancedWorkspace = {
45345
+ ...workspace,
45346
+ navParams: combinedParams
45347
+ };
45348
+ onWorkspaceClick(enhancedWorkspace, rank);
44902
45349
  } else {
44903
- navigation.navigate(`/workspace/${workspace.workspace_uuid}${navParams}${returnToParam}`);
45350
+ const combinedParams = navParams ? `${navParams}&${contextParamString}` : `?${contextParamString}`;
45351
+ navigation.navigate(`/workspace/${workspace.workspace_uuid}${combinedParams}`);
44904
45352
  }
44905
- }, [onWorkspaceClick, navigation, lineId, workspacesLength]);
45353
+ }, [onWorkspaceClick, navigation, workspacesLength, date, shiftId]);
44906
45354
  const workspaceDisplayData = React23.useMemo(() => {
44907
45355
  if (!workspaces) return [];
44908
45356
  return workspaces.map((ws) => ({
@@ -44918,7 +45366,7 @@ var LeaderboardDetailView = React23.memo(({
44918
45366
  return sortAscending ? effA - effB : effB - effA;
44919
45367
  });
44920
45368
  }, [workspaceDisplayData, sortAscending]);
44921
- const loading = workspacesLoading;
45369
+ const loading = workspacesLoading || isShiftConfigLoading;
44922
45370
  const error = workspacesError;
44923
45371
  const currentDateFormatted = React23.useMemo(() => {
44924
45372
  const dateStr = (/* @__PURE__ */ new Date()).toDateString();
@@ -45030,7 +45478,7 @@ var LeaderboardDetailView = React23.memo(({
45030
45478
  currentDate: currentDateFormatted,
45031
45479
  currentMobileDate: currentMobileDateFormatted,
45032
45480
  shiftId,
45033
- getShiftIcon,
45481
+ getShiftIcon: getShiftIcon2,
45034
45482
  getShiftName
45035
45483
  }
45036
45484
  )
@@ -45389,6 +45837,23 @@ var ProfileView = () => {
45389
45837
  ] }) });
45390
45838
  };
45391
45839
  var ProfileView_default = ProfileView;
45840
+ var DEFAULT_TIMEZONE = "Asia/Kolkata";
45841
+ var DEFAULT_SHIFTS = [
45842
+ {
45843
+ shiftId: 0,
45844
+ shiftName: "Day Shift",
45845
+ startTime: "08:00",
45846
+ endTime: "16:00",
45847
+ breaks: []
45848
+ },
45849
+ {
45850
+ shiftId: 1,
45851
+ shiftName: "Night Shift",
45852
+ startTime: "20:00",
45853
+ endTime: "04:00",
45854
+ breaks: []
45855
+ }
45856
+ ];
45392
45857
  var calculateShiftHours = (startTime, endTime, breaks = []) => {
45393
45858
  if (!startTime || !endTime) return 8;
45394
45859
  const [startHour, startMinute] = startTime.split(":").map(Number);
@@ -45455,6 +45920,19 @@ var formatBreaks = (breaks) => {
45455
45920
  }))
45456
45921
  };
45457
45922
  };
45923
+ var getShiftIcon = (shiftId, shiftName) => {
45924
+ const nameLower = shiftName.toLowerCase();
45925
+ if (nameLower.includes("day") || nameLower.includes("morning") || shiftId === 0) {
45926
+ return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-5 h-5 text-gray-600", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" }) });
45927
+ }
45928
+ if (nameLower.includes("afternoon") || nameLower.includes("noon") || nameLower.includes("midday")) {
45929
+ return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-5 h-5 text-gray-600", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" }) });
45930
+ }
45931
+ if (nameLower.includes("night") || nameLower.includes("evening") || shiftId === 1) {
45932
+ return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-5 h-5 text-gray-600", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z" }) });
45933
+ }
45934
+ return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Clock, { className: "w-5 h-5 text-gray-600" });
45935
+ };
45458
45936
  var BreakRow = React23.memo(({
45459
45937
  break: breakItem,
45460
45938
  onUpdate,
@@ -45582,9 +46060,13 @@ var ShiftPanel = React23.memo(({
45582
46060
  onBreakUpdate,
45583
46061
  onBreakRemove,
45584
46062
  onBreakAdd,
45585
- shiftHours
46063
+ shiftHours,
46064
+ shiftId,
46065
+ onShiftNameChange,
46066
+ canDelete = false,
46067
+ onDelete
45586
46068
  }) => {
45587
- const panelId = `panel-${title.toLowerCase().replace(/\s+/g, "-")}`;
46069
+ const panelId = `panel-${title.toLowerCase().replace(/\s+/g, "-")}-${shiftId ?? 0}`;
45588
46070
  const storageKey = `shift_panel_${panelId}_minimized`;
45589
46071
  const [isMinimized, setIsMinimized] = React23.useState(true);
45590
46072
  React23.useEffect(() => {
@@ -45611,7 +46093,7 @@ var ShiftPanel = React23.memo(({
45611
46093
  "button",
45612
46094
  {
45613
46095
  onClick: toggleMinimize,
45614
- className: "flex items-center gap-2 sm:gap-3 text-base sm:text-lg font-medium transition-colors duration-200 \n focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 rounded-lg \n hover:bg-blue-50 px-2 sm:px-3 py-1.5 sm:py-2 group w-full sm:w-auto justify-start",
46096
+ className: "flex items-center gap-2 sm:gap-3 text-base sm:text-lg font-medium transition-colors duration-200\n focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 rounded-lg\n hover:bg-blue-50 px-2 sm:px-3 py-1.5 sm:py-2 group w-full sm:w-auto justify-start",
45615
46097
  "aria-expanded": !isMinimized,
45616
46098
  "aria-controls": panelId,
45617
46099
  children: [
@@ -45628,15 +46110,42 @@ var ShiftPanel = React23.memo(({
45628
46110
  ]
45629
46111
  }
45630
46112
  ),
45631
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs sm:text-sm font-medium text-gray-600 text-center sm:text-right sm:mr-2", children: [
45632
- "Total Shift Hours: ",
45633
- shiftHours,
45634
- " hours"
46113
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 sm:gap-4", children: [
46114
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs sm:text-sm font-medium text-gray-600 text-center sm:text-right", children: [
46115
+ "Total Shift Hours: ",
46116
+ shiftHours,
46117
+ " hours"
46118
+ ] }),
46119
+ canDelete && onDelete && /* @__PURE__ */ jsxRuntime.jsx(
46120
+ "button",
46121
+ {
46122
+ onClick: (e) => {
46123
+ e.stopPropagation();
46124
+ onDelete();
46125
+ },
46126
+ className: "p-1.5 text-gray-400 hover:text-red-500 hover:bg-red-50 rounded transition-colors",
46127
+ "aria-label": "Delete shift",
46128
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { className: "w-4 h-4" })
46129
+ }
46130
+ )
45635
46131
  ] })
45636
46132
  ] })
45637
46133
  }
45638
46134
  ),
45639
46135
  !isMinimized && /* @__PURE__ */ jsxRuntime.jsxs("div", { id: panelId, className: "p-3 sm:p-4 md:p-6 border-t border-gray-200 w-full bg-white", children: [
46136
+ onShiftNameChange && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-4 sm:mb-6", children: [
46137
+ /* @__PURE__ */ jsxRuntime.jsx("label", { className: "block text-xs sm:text-sm font-medium text-gray-700 mb-1", children: "Shift Name" }),
46138
+ /* @__PURE__ */ jsxRuntime.jsx(
46139
+ "input",
46140
+ {
46141
+ type: "text",
46142
+ value: title,
46143
+ onChange: (e) => onShiftNameChange(e.target.value),
46144
+ placeholder: "Enter shift name",
46145
+ className: "w-full sm:w-64 px-3 py-2 border border-gray-300 rounded-md text-sm focus:outline-none focus:ring-2 focus:ring-blue-500"
46146
+ }
46147
+ )
46148
+ ] }),
45640
46149
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-1 sm:grid-cols-2 gap-3 sm:gap-4 md:gap-6 mb-4 sm:mb-6 w-full", children: [
45641
46150
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-full", children: [
45642
46151
  /* @__PURE__ */ jsxRuntime.jsx("label", { className: "block text-xs sm:text-sm font-medium text-gray-700 mb-1", children: "Shift Start Time" }),
@@ -45730,16 +46239,9 @@ var ShiftsView = ({
45730
46239
  () => lineIds.map((id3) => ({
45731
46240
  id: id3,
45732
46241
  name: lineNames[id3] || `Line ${id3.substring(0, 4)}`,
45733
- dayShift: {
45734
- startTime: "08:00",
45735
- endTime: "16:00",
45736
- breaks: []
45737
- },
45738
- nightShift: {
45739
- startTime: "20:00",
45740
- endTime: "04:00",
45741
- breaks: []
45742
- },
46242
+ timezone: DEFAULT_TIMEZONE,
46243
+ shifts: DEFAULT_SHIFTS.map((s) => ({ ...s })),
46244
+ // Clone default shifts
45743
46245
  isOpen: true,
45744
46246
  isSaving: false,
45745
46247
  saveSuccess: false
@@ -45763,60 +46265,47 @@ var ShiftsView = ({
45763
46265
  try {
45764
46266
  setLoading(true);
45765
46267
  setError(null);
45766
- const { data: dayShiftOperatingHours, error: dayShiftError } = await supabase.from("line_operating_hours").select("line_id, start_time, end_time, breaks").eq("shift_id", 0).in("line_id", lineIds);
45767
- if (dayShiftError) {
45768
- console.error("Error fetching day shift operating hours:", dayShiftError);
45769
- showToast("error", "Error loading day shift data");
45770
- setError("Failed to load day shift data");
45771
- return;
45772
- }
45773
- const { data: nightShiftOperatingHours, error: nightShiftError } = await supabase.from("line_operating_hours").select("line_id, start_time, end_time, breaks").eq("shift_id", 1).in("line_id", lineIds);
45774
- if (nightShiftError) {
45775
- console.error("Error fetching night shift operating hours:", nightShiftError);
45776
- showToast("error", "Error loading night shift data");
45777
- setError("Failed to load night shift data");
46268
+ const { data: allShiftsData, error: shiftsError } = await supabase.from("line_operating_hours").select("line_id, shift_id, shift_name, start_time, end_time, breaks, timezone").in("line_id", lineIds).order("shift_id", { ascending: true });
46269
+ if (shiftsError) {
46270
+ console.error("[ShiftsView] Error fetching shift configurations:", shiftsError);
46271
+ showToast("error", "Error loading shift data");
46272
+ setError("Failed to load shift data");
45778
46273
  return;
45779
46274
  }
45780
- const dayShiftHoursMap = (dayShiftOperatingHours || []).reduce((map, item) => {
45781
- map[item.line_id] = {
45782
- startTime: item.start_time,
45783
- endTime: item.end_time,
45784
- breaks: parseBreaksFromDB(item.breaks)
45785
- };
45786
- return map;
45787
- }, {});
45788
- const nightShiftHoursMap = (nightShiftOperatingHours || []).reduce((map, item) => {
45789
- map[item.line_id] = {
45790
- startTime: item.start_time,
45791
- endTime: item.end_time,
45792
- breaks: parseBreaksFromDB(item.breaks)
45793
- };
45794
- return map;
45795
- }, {});
45796
- setLineConfigs((prev) => prev.map((config) => {
45797
- const typedConfig = config;
45798
- const lineId = typedConfig.id;
45799
- const newConfig = { ...typedConfig };
45800
- if (dayShiftHoursMap[lineId]) {
45801
- newConfig.dayShift = {
45802
- ...newConfig.dayShift,
45803
- ...dayShiftHoursMap[lineId]
45804
- };
45805
- }
45806
- if (nightShiftHoursMap[lineId]) {
45807
- newConfig.nightShift = {
45808
- ...newConfig.nightShift,
45809
- ...nightShiftHoursMap[lineId]
45810
- };
45811
- }
45812
- if (newConfig.isOpen === void 0) {
45813
- newConfig.isOpen = getStoredLineState(lineId);
46275
+ console.log("[ShiftsView] Fetched shifts from DB:", allShiftsData);
46276
+ const shiftsByLine = {};
46277
+ const timezoneByLine = {};
46278
+ (allShiftsData || []).forEach((row) => {
46279
+ if (!shiftsByLine[row.line_id]) {
46280
+ shiftsByLine[row.line_id] = [];
46281
+ }
46282
+ shiftsByLine[row.line_id].push({
46283
+ shiftId: row.shift_id,
46284
+ shiftName: row.shift_name || `Shift ${row.shift_id}`,
46285
+ startTime: row.start_time || "08:00",
46286
+ endTime: row.end_time || "16:00",
46287
+ breaks: parseBreaksFromDB(row.breaks),
46288
+ timezone: row.timezone
46289
+ });
46290
+ if (row.timezone && !timezoneByLine[row.line_id]) {
46291
+ timezoneByLine[row.line_id] = row.timezone;
45814
46292
  }
45815
- return newConfig;
46293
+ });
46294
+ setLineConfigs((prev) => prev.map((config) => {
46295
+ const lineId = config.id;
46296
+ const lineShifts = shiftsByLine[lineId];
46297
+ const lineTimezone = timezoneByLine[lineId] || DEFAULT_TIMEZONE;
46298
+ const shifts = lineShifts && lineShifts.length > 0 ? lineShifts.sort((a, b) => a.shiftId - b.shiftId) : DEFAULT_SHIFTS.map((s) => ({ ...s }));
46299
+ return {
46300
+ ...config,
46301
+ timezone: lineTimezone,
46302
+ shifts,
46303
+ isOpen: config.isOpen ?? getStoredLineState(lineId)
46304
+ };
45816
46305
  }));
45817
46306
  setLoading(false);
45818
46307
  } catch (error2) {
45819
- console.error("Error fetching shift configurations:", error2);
46308
+ console.error("[ShiftsView] Error fetching shift configurations:", error2);
45820
46309
  showToast("error", "Failed to load shift configurations");
45821
46310
  setError("Failed to load shift configurations");
45822
46311
  setLoading(false);
@@ -45826,195 +46315,125 @@ var ShiftsView = ({
45826
46315
  }, [lineIds, showToast]);
45827
46316
  React23.useCallback((lineId) => {
45828
46317
  setLineConfigs((prev) => {
45829
- const typedPrev = prev;
45830
- const newIsOpen = !typedPrev.find((config) => config.id === lineId)?.isOpen;
46318
+ const newIsOpen = !prev.find((config) => config.id === lineId)?.isOpen;
45831
46319
  localStorage.setItem(`line_${lineId}_open`, JSON.stringify(newIsOpen));
45832
- return typedPrev.map(
46320
+ return prev.map(
45833
46321
  (config) => config.id === lineId ? { ...config, isOpen: newIsOpen } : config
45834
46322
  );
45835
46323
  });
45836
46324
  }, []);
45837
- const updateDayShiftStartTime = React23.useCallback((lineId, value) => {
45838
- setLineConfigs((prev) => prev.map((config) => {
45839
- const typedConfig = config;
45840
- if (typedConfig.id === lineId) {
45841
- const updatedDayShift = { ...typedConfig.dayShift, startTime: value };
45842
- return {
45843
- ...typedConfig,
45844
- dayShift: updatedDayShift
45845
- };
45846
- }
45847
- return typedConfig;
45848
- }));
45849
- }, []);
45850
- const updateDayShiftEndTime = React23.useCallback((lineId, value) => {
46325
+ const updateShiftTime = React23.useCallback((lineId, shiftId, field, value) => {
45851
46326
  setLineConfigs((prev) => prev.map((config) => {
45852
- const typedConfig = config;
45853
- if (typedConfig.id === lineId) {
45854
- const updatedDayShift = { ...typedConfig.dayShift, endTime: value };
45855
- return {
45856
- ...typedConfig,
45857
- dayShift: updatedDayShift
45858
- };
45859
- }
45860
- return typedConfig;
45861
- }));
45862
- }, []);
45863
- const updateNightShiftStartTime = React23.useCallback((lineId, value) => {
45864
- setLineConfigs((prev) => prev.map((config) => {
45865
- const typedConfig = config;
45866
- if (typedConfig.id === lineId) {
45867
- const updatedNightShift = { ...typedConfig.nightShift, startTime: value };
45868
- return {
45869
- ...typedConfig,
45870
- nightShift: updatedNightShift
45871
- };
46327
+ if (config.id === lineId) {
46328
+ const updatedShifts = config.shifts.map(
46329
+ (shift) => shift.shiftId === shiftId ? { ...shift, [field]: value } : shift
46330
+ );
46331
+ return { ...config, shifts: updatedShifts };
45872
46332
  }
45873
- return typedConfig;
46333
+ return config;
45874
46334
  }));
45875
46335
  }, []);
45876
- const updateNightShiftEndTime = React23.useCallback((lineId, value) => {
46336
+ const updateShiftName = React23.useCallback((lineId, shiftId, value) => {
45877
46337
  setLineConfigs((prev) => prev.map((config) => {
45878
- const typedConfig = config;
45879
- if (typedConfig.id === lineId) {
45880
- const updatedNightShift = { ...typedConfig.nightShift, endTime: value };
45881
- return {
45882
- ...typedConfig,
45883
- nightShift: updatedNightShift
45884
- };
46338
+ if (config.id === lineId) {
46339
+ const updatedShifts = config.shifts.map(
46340
+ (shift) => shift.shiftId === shiftId ? { ...shift, shiftName: value } : shift
46341
+ );
46342
+ return { ...config, shifts: updatedShifts };
45885
46343
  }
45886
- return typedConfig;
46344
+ return config;
45887
46345
  }));
45888
46346
  }, []);
45889
- const addDayShiftBreak = React23.useCallback((lineId) => {
45890
- setLineConfigs((prev) => prev.map((config) => {
45891
- const typedConfig = config;
45892
- if (typedConfig.id === lineId) {
45893
- const dayShift = { ...typedConfig.dayShift };
45894
- const newBreak = {
45895
- startTime: dayShift.startTime,
45896
- endTime: dayShift.startTime,
45897
- duration: 0,
45898
- remarks: ""
45899
- };
45900
- return {
45901
- ...typedConfig,
45902
- dayShift: {
45903
- ...dayShift,
45904
- breaks: [...dayShift.breaks, newBreak]
45905
- }
45906
- };
45907
- }
45908
- return typedConfig;
45909
- }));
46347
+ React23.useCallback((lineId, value) => {
46348
+ setLineConfigs((prev) => prev.map(
46349
+ (config) => config.id === lineId ? { ...config, timezone: value } : config
46350
+ ));
45910
46351
  }, []);
45911
- const addNightShiftBreak = React23.useCallback((lineId) => {
46352
+ const addBreak = React23.useCallback((lineId, shiftId) => {
45912
46353
  setLineConfigs((prev) => prev.map((config) => {
45913
- const typedConfig = config;
45914
- if (typedConfig.id === lineId) {
45915
- const nightShift = { ...typedConfig.nightShift };
45916
- const newBreak = {
45917
- startTime: nightShift.startTime,
45918
- endTime: nightShift.startTime,
45919
- duration: 0
45920
- };
45921
- return {
45922
- ...typedConfig,
45923
- nightShift: {
45924
- ...nightShift,
45925
- breaks: [...nightShift.breaks, newBreak]
46354
+ if (config.id === lineId) {
46355
+ const updatedShifts = config.shifts.map((shift) => {
46356
+ if (shift.shiftId === shiftId) {
46357
+ const newBreak = {
46358
+ startTime: shift.startTime,
46359
+ endTime: shift.startTime,
46360
+ duration: 0,
46361
+ remarks: ""
46362
+ };
46363
+ return { ...shift, breaks: [...shift.breaks, newBreak] };
45926
46364
  }
45927
- };
46365
+ return shift;
46366
+ });
46367
+ return { ...config, shifts: updatedShifts };
45928
46368
  }
45929
- return typedConfig;
46369
+ return config;
45930
46370
  }));
45931
46371
  }, []);
45932
- const updateDayShiftBreak = React23.useCallback((lineId, index, field, value) => {
46372
+ const updateBreak = React23.useCallback((lineId, shiftId, breakIndex, field, value) => {
45933
46373
  setLineConfigs((prev) => prev.map((config) => {
45934
- const typedConfig = config;
45935
- if (typedConfig.id === lineId) {
45936
- const dayShift = { ...typedConfig.dayShift };
45937
- const newBreaks = [...dayShift.breaks];
45938
- newBreaks[index] = { ...newBreaks[index], [field]: value };
45939
- if (field === "startTime" || field === "endTime") {
45940
- const startParts = newBreaks[index].startTime.split(":").map(Number);
45941
- const endParts = newBreaks[index].endTime.split(":").map(Number);
45942
- let startMinutes = startParts[0] * 60 + startParts[1];
45943
- let endMinutes = endParts[0] * 60 + endParts[1];
45944
- if (endMinutes < startMinutes) {
45945
- endMinutes += 24 * 60;
45946
- }
45947
- newBreaks[index].duration = endMinutes - startMinutes;
45948
- }
45949
- return {
45950
- ...typedConfig,
45951
- dayShift: {
45952
- ...dayShift,
45953
- breaks: newBreaks
46374
+ if (config.id === lineId) {
46375
+ const updatedShifts = config.shifts.map((shift) => {
46376
+ if (shift.shiftId === shiftId) {
46377
+ const newBreaks = [...shift.breaks];
46378
+ newBreaks[breakIndex] = { ...newBreaks[breakIndex], [field]: value };
46379
+ if (field === "startTime" || field === "endTime") {
46380
+ newBreaks[breakIndex].duration = calculateBreakDuration(
46381
+ newBreaks[breakIndex].startTime,
46382
+ newBreaks[breakIndex].endTime
46383
+ );
46384
+ }
46385
+ return { ...shift, breaks: newBreaks };
45954
46386
  }
45955
- };
46387
+ return shift;
46388
+ });
46389
+ return { ...config, shifts: updatedShifts };
45956
46390
  }
45957
- return typedConfig;
46391
+ return config;
45958
46392
  }));
45959
46393
  }, []);
45960
- const updateNightShiftBreak = React23.useCallback((lineId, index, field, value) => {
46394
+ const removeBreak = React23.useCallback((lineId, shiftId, breakIndex) => {
45961
46395
  setLineConfigs((prev) => prev.map((config) => {
45962
- const typedConfig = config;
45963
- if (typedConfig.id === lineId) {
45964
- const nightShift = { ...typedConfig.nightShift };
45965
- const newBreaks = [...nightShift.breaks];
45966
- newBreaks[index] = { ...newBreaks[index], [field]: value };
45967
- if (field === "startTime" || field === "endTime") {
45968
- const startParts = newBreaks[index].startTime.split(":").map(Number);
45969
- const endParts = newBreaks[index].endTime.split(":").map(Number);
45970
- let startMinutes = startParts[0] * 60 + startParts[1];
45971
- let endMinutes = endParts[0] * 60 + endParts[1];
45972
- if (endMinutes < startMinutes) {
45973
- endMinutes += 24 * 60;
45974
- }
45975
- newBreaks[index].duration = endMinutes - startMinutes;
45976
- }
45977
- return {
45978
- ...typedConfig,
45979
- nightShift: {
45980
- ...nightShift,
45981
- breaks: newBreaks
46396
+ if (config.id === lineId) {
46397
+ const updatedShifts = config.shifts.map((shift) => {
46398
+ if (shift.shiftId === shiftId) {
46399
+ return { ...shift, breaks: shift.breaks.filter((_, i) => i !== breakIndex) };
45982
46400
  }
45983
- };
46401
+ return shift;
46402
+ });
46403
+ return { ...config, shifts: updatedShifts };
45984
46404
  }
45985
- return typedConfig;
46405
+ return config;
45986
46406
  }));
45987
46407
  }, []);
45988
- const removeDayShiftBreak = React23.useCallback((lineId, index) => {
46408
+ React23.useCallback((lineId) => {
45989
46409
  setLineConfigs((prev) => prev.map((config) => {
45990
46410
  if (config.id === lineId) {
45991
- const dayShift = { ...config.dayShift };
45992
- return {
45993
- ...config,
45994
- dayShift: {
45995
- ...dayShift,
45996
- breaks: dayShift.breaks.filter((_, i) => i !== index)
45997
- }
46411
+ const maxShiftId = Math.max(...config.shifts.map((s) => s.shiftId), -1);
46412
+ const newShiftId = maxShiftId + 1;
46413
+ const newShift = {
46414
+ shiftId: newShiftId,
46415
+ shiftName: `Shift ${newShiftId}`,
46416
+ startTime: "08:00",
46417
+ endTime: "16:00",
46418
+ breaks: []
45998
46419
  };
46420
+ return { ...config, shifts: [...config.shifts, newShift] };
45999
46421
  }
46000
46422
  return config;
46001
46423
  }));
46002
46424
  }, []);
46003
- const removeNightShiftBreak = React23.useCallback((lineId, index) => {
46425
+ const removeShift = React23.useCallback((lineId, shiftId) => {
46004
46426
  setLineConfigs((prev) => prev.map((config) => {
46005
46427
  if (config.id === lineId) {
46006
- const nightShift = { ...config.nightShift };
46007
- return {
46008
- ...config,
46009
- nightShift: {
46010
- ...nightShift,
46011
- breaks: nightShift.breaks.filter((_, i) => i !== index)
46012
- }
46013
- };
46428
+ if (config.shifts.length <= 1) {
46429
+ showToast("error", "Cannot remove the last shift");
46430
+ return config;
46431
+ }
46432
+ return { ...config, shifts: config.shifts.filter((s) => s.shiftId !== shiftId) };
46014
46433
  }
46015
46434
  return config;
46016
46435
  }));
46017
- }, []);
46436
+ }, [showToast]);
46018
46437
  const handleSaveShifts = React23.useCallback(async (lineId) => {
46019
46438
  setLineConfigs((prev) => prev.map(
46020
46439
  (config) => config.id === lineId ? { ...config, isSaving: true, saveSuccess: false } : config
@@ -46024,27 +46443,31 @@ var ShiftsView = ({
46024
46443
  if (!lineConfig) {
46025
46444
  throw new Error("Line configuration not found");
46026
46445
  }
46027
- const dayShiftData = {
46028
- line_id: lineId,
46029
- shift_id: 0,
46030
- start_time: lineConfig.dayShift.startTime,
46031
- end_time: lineConfig.dayShift.endTime,
46032
- breaks: formatBreaks(lineConfig.dayShift.breaks)
46033
- };
46034
- const nightShiftData = {
46035
- line_id: lineId,
46036
- shift_id: 1,
46037
- start_time: lineConfig.nightShift.startTime,
46038
- end_time: lineConfig.nightShift.endTime,
46039
- breaks: formatBreaks(lineConfig.nightShift.breaks)
46040
- };
46041
- const dayResult = await supabase.from("line_operating_hours").upsert(dayShiftData).select();
46042
- if (dayResult.error) {
46043
- throw new Error(`Failed to save day shift: ${dayResult.error.message}`);
46446
+ console.log("[ShiftsView] Saving shifts for line:", lineId, lineConfig.shifts);
46447
+ for (const shift of lineConfig.shifts) {
46448
+ const shiftData = {
46449
+ line_id: lineId,
46450
+ shift_id: shift.shiftId,
46451
+ shift_name: shift.shiftName,
46452
+ start_time: shift.startTime,
46453
+ end_time: shift.endTime,
46454
+ breaks: formatBreaks(shift.breaks),
46455
+ timezone: lineConfig.timezone
46456
+ };
46457
+ const { error: upsertError } = await supabase.from("line_operating_hours").upsert(shiftData).select();
46458
+ if (upsertError) {
46459
+ throw new Error(`Failed to save shift ${shift.shiftId}: ${upsertError.message}`);
46460
+ }
46044
46461
  }
46045
- const nightResult = await supabase.from("line_operating_hours").upsert(nightShiftData).select();
46046
- if (nightResult.error) {
46047
- throw new Error(`Failed to save night shift: ${nightResult.error.message}`);
46462
+ const { data: existingShifts } = await supabase.from("line_operating_hours").select("shift_id").eq("line_id", lineId);
46463
+ const currentShiftIds = lineConfig.shifts.map((s) => s.shiftId);
46464
+ const shiftsToDelete = (existingShifts || []).filter((s) => !currentShiftIds.includes(s.shift_id)).map((s) => s.shift_id);
46465
+ if (shiftsToDelete.length > 0) {
46466
+ console.log("[ShiftsView] Deleting removed shifts:", shiftsToDelete);
46467
+ const { error: deleteError } = await supabase.from("line_operating_hours").delete().eq("line_id", lineId).in("shift_id", shiftsToDelete);
46468
+ if (deleteError) {
46469
+ console.error("[ShiftsView] Error deleting shifts:", deleteError);
46470
+ }
46048
46471
  }
46049
46472
  setLineConfigs((prev) => prev.map(
46050
46473
  (config) => config.id === lineId ? { ...config, isSaving: false, saveSuccess: true } : config
@@ -46056,7 +46479,7 @@ var ShiftsView = ({
46056
46479
  ));
46057
46480
  }, 3e3);
46058
46481
  } catch (error2) {
46059
- console.error("Error saving shift configurations:", error2);
46482
+ console.error("[ShiftsView] Error saving shift configurations:", error2);
46060
46483
  showToast("error", "Failed to save shift configurations");
46061
46484
  setLineConfigs((prev) => prev.map(
46062
46485
  (config) => config.id === lineId ? { ...config, isSaving: false, saveSuccess: false } : config
@@ -46076,7 +46499,7 @@ var ShiftsView = ({
46076
46499
  ) }),
46077
46500
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 flex flex-col items-center mt-2 sm:mt-0", children: [
46078
46501
  /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-lg sm:text-xl md:text-2xl lg:text-3xl font-semibold text-gray-900 text-center", children: "Shift Management" }),
46079
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs sm:text-sm text-gray-500 mt-0.5 sm:mt-1 text-center px-2 sm:px-0", children: "Configure day and night shift timings and breaks for each production line" })
46502
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs sm:text-sm text-gray-500 mt-0.5 sm:mt-1 text-center px-2 sm:px-0", children: "Configure shift timings and breaks for each production line" })
46080
46503
  ] }),
46081
46504
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "hidden sm:block absolute right-0 w-24" })
46082
46505
  ] }) }) }),
@@ -46096,6 +46519,11 @@ var ShiftsView = ({
46096
46519
  /* @__PURE__ */ jsxRuntime.jsxs("h2", { className: "text-base sm:text-lg font-semibold text-gray-800", children: [
46097
46520
  config.name,
46098
46521
  " Shifts"
46522
+ ] }),
46523
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-gray-400", children: [
46524
+ "(",
46525
+ config.shifts.length,
46526
+ " shifts)"
46099
46527
  ] })
46100
46528
  ] }),
46101
46529
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col sm:flex-row items-start sm:items-center gap-2 sm:gap-4 w-full sm:w-auto", children: [
@@ -46123,48 +46551,27 @@ var ShiftsView = ({
46123
46551
  )
46124
46552
  ] })
46125
46553
  ] }) }),
46126
- /* @__PURE__ */ jsxRuntime.jsxs("div", { id: `shift-panel-${config.id}`, className: "p-3 sm:p-4 md:p-6 border-t border-gray-200 w-full", children: [
46127
- /* @__PURE__ */ jsxRuntime.jsx(
46128
- ShiftPanel,
46129
- {
46130
- title: "Day Shift",
46131
- icon: /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-5 h-5 text-gray-600", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" }) }),
46132
- startTime: config.dayShift.startTime,
46133
- endTime: config.dayShift.endTime,
46134
- breaks: config.dayShift.breaks,
46135
- onStartTimeChange: (value) => updateDayShiftStartTime(config.id, value),
46136
- onEndTimeChange: (value) => updateDayShiftEndTime(config.id, value),
46137
- onBreakUpdate: (index, field, value) => updateDayShiftBreak(config.id, index, field, value),
46138
- onBreakRemove: (index) => removeDayShiftBreak(config.id, index),
46139
- onBreakAdd: () => addDayShiftBreak(config.id),
46140
- shiftHours: calculateShiftHours(
46141
- config.dayShift.startTime,
46142
- config.dayShift.endTime,
46143
- config.dayShift.breaks
46144
- )
46145
- }
46146
- ),
46147
- /* @__PURE__ */ jsxRuntime.jsx(
46148
- ShiftPanel,
46149
- {
46150
- title: "Night Shift",
46151
- icon: /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-5 h-5 text-gray-600", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z" }) }),
46152
- startTime: config.nightShift.startTime,
46153
- endTime: config.nightShift.endTime,
46154
- breaks: config.nightShift.breaks,
46155
- onStartTimeChange: (value) => updateNightShiftStartTime(config.id, value),
46156
- onEndTimeChange: (value) => updateNightShiftEndTime(config.id, value),
46157
- onBreakUpdate: (index, field, value) => updateNightShiftBreak(config.id, index, field, value),
46158
- onBreakRemove: (index) => removeNightShiftBreak(config.id, index),
46159
- onBreakAdd: () => addNightShiftBreak(config.id),
46160
- shiftHours: calculateShiftHours(
46161
- config.nightShift.startTime,
46162
- config.nightShift.endTime,
46163
- config.nightShift.breaks
46164
- )
46165
- }
46166
- )
46167
- ] })
46554
+ /* @__PURE__ */ jsxRuntime.jsx("div", { id: `shift-panel-${config.id}`, className: "p-3 sm:p-4 md:p-6 border-t border-gray-200 w-full", children: config.shifts.map((shift) => /* @__PURE__ */ jsxRuntime.jsx(
46555
+ ShiftPanel,
46556
+ {
46557
+ title: shift.shiftName,
46558
+ icon: getShiftIcon(shift.shiftId, shift.shiftName),
46559
+ startTime: shift.startTime,
46560
+ endTime: shift.endTime,
46561
+ breaks: shift.breaks,
46562
+ onStartTimeChange: (value) => updateShiftTime(config.id, shift.shiftId, "startTime", value),
46563
+ onEndTimeChange: (value) => updateShiftTime(config.id, shift.shiftId, "endTime", value),
46564
+ onBreakUpdate: (index, field, value) => updateBreak(config.id, shift.shiftId, index, field, value),
46565
+ onBreakRemove: (index) => removeBreak(config.id, shift.shiftId, index),
46566
+ onBreakAdd: () => addBreak(config.id, shift.shiftId),
46567
+ shiftHours: calculateShiftHours(shift.startTime, shift.endTime, shift.breaks),
46568
+ shiftId: shift.shiftId,
46569
+ onShiftNameChange: (value) => updateShiftName(config.id, shift.shiftId, value),
46570
+ canDelete: config.shifts.length > 1,
46571
+ onDelete: () => removeShift(config.id, shift.shiftId)
46572
+ },
46573
+ `${config.id}-shift-${shift.shiftId}`
46574
+ )) })
46168
46575
  ] }, config.id)) })
46169
46576
  ] })
46170
46577
  ] });
@@ -46991,6 +47398,10 @@ var TargetsViewUI = ({
46991
47398
  savingLines,
46992
47399
  saveSuccess,
46993
47400
  selectedShift,
47401
+ shiftOptions = [
47402
+ { id: 0, name: "Day Shift" },
47403
+ { id: 1, name: "Night Shift" }
47404
+ ],
46994
47405
  isBulkConfigureOpen,
46995
47406
  navItems = [],
46996
47407
  currentPathname = "/targets",
@@ -47043,24 +47454,15 @@ var TargetsViewUI = ({
47043
47454
  ] }) }),
47044
47455
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 overflow-auto", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-4 sm:px-6 md:px-8 py-4 sm:py-5 md:py-6", children: [
47045
47456
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-4 sm:mb-6 bg-gradient-to-r from-blue-50 to-blue-50/50 p-3 sm:p-4 rounded-xl border border-blue-100", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs sm:text-sm text-blue-700 font-medium text-center sm:text-left", children: "Click on a line to expand and configure individual workspace targets." }) }),
47046
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-4 sm:mb-6 flex justify-center relative", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "inline-flex bg-gray-100 p-1 rounded-lg w-full max-w-xs sm:w-auto", children: [
47047
- /* @__PURE__ */ jsxRuntime.jsx(
47048
- "button",
47049
- {
47050
- onClick: () => onShiftChange(0),
47051
- className: `flex-1 sm:flex-none px-3 sm:px-4 py-2 text-xs sm:text-sm font-medium rounded-md transition-all ${selectedShift === 0 ? "bg-white text-blue-600 shadow-sm" : "text-gray-600 hover:text-gray-900"}`,
47052
- children: "Day Shift"
47053
- }
47054
- ),
47055
- /* @__PURE__ */ jsxRuntime.jsx(
47056
- "button",
47057
- {
47058
- onClick: () => onShiftChange(1),
47059
- className: `flex-1 sm:flex-none px-3 sm:px-4 py-2 text-xs sm:text-sm font-medium rounded-md transition-all ${selectedShift === 1 ? "bg-white text-blue-600 shadow-sm" : "text-gray-600 hover:text-gray-900"}`,
47060
- children: "Night Shift"
47061
- }
47062
- )
47063
- ] }) }),
47457
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-4 sm:mb-6 flex justify-center relative", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "inline-flex bg-gray-100 p-1 rounded-lg w-full max-w-xl sm:w-auto overflow-x-auto", children: shiftOptions.map((option) => /* @__PURE__ */ jsxRuntime.jsx(
47458
+ "button",
47459
+ {
47460
+ onClick: () => onShiftChange(option.id),
47461
+ className: `flex-1 sm:flex-none px-3 sm:px-4 py-2 text-xs sm:text-sm font-medium rounded-md transition-all whitespace-nowrap ${selectedShift === option.id ? "bg-white text-blue-600 shadow-sm" : "text-gray-600 hover:text-gray-900"}`,
47462
+ children: option.name
47463
+ },
47464
+ option.id
47465
+ )) }) }),
47064
47466
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-6", children: Object.entries(lineWorkspaces).map(([lineId, line]) => /* @__PURE__ */ jsxRuntime.jsxs(
47065
47467
  "div",
47066
47468
  {
@@ -47387,12 +47789,7 @@ var TargetsView = ({
47387
47789
  [lineId]: getStoredLineState2(lineId)
47388
47790
  }), {});
47389
47791
  });
47390
- const [allShiftsData, setAllShiftsData] = React23.useState({
47391
- 0: initialLineWorkspaces,
47392
- // Day shift
47393
- 1: initialLineWorkspaces
47394
- // Night shift (will be populated on first load)
47395
- });
47792
+ const [allShiftsData, setAllShiftsData] = React23.useState({});
47396
47793
  const [actionIds, setActionIds] = React23.useState(null);
47397
47794
  const [savingLines, setSavingLines] = React23.useState(
47398
47795
  () => lineIds.reduce((acc, id3) => ({ ...acc, [id3]: false }), {})
@@ -47404,6 +47801,7 @@ var TargetsView = ({
47404
47801
  const [isBulkConfigureOpen, setIsBulkConfigureOpen] = React23.useState(false);
47405
47802
  const [selectedWorkspaces, setSelectedWorkspaces] = React23.useState([]);
47406
47803
  const [selectedShift, setSelectedShift] = React23.useState(0);
47804
+ const [shiftOptions, setShiftOptions] = React23.useState([]);
47407
47805
  const canSaveTargets = useCanSaveTargets();
47408
47806
  const [dbValues, setDbValues] = React23.useState({ 0: {}, 1: {} });
47409
47807
  const [userEditedFields, setUserEditedFields] = React23.useState(/* @__PURE__ */ new Set());
@@ -47436,12 +47834,28 @@ var TargetsView = ({
47436
47834
  setIsLoading(true);
47437
47835
  try {
47438
47836
  const currentDate = getOperationalDate(timezone);
47837
+ const { data: shiftsData, error: shiftsError } = await supabase.from("line_operating_hours").select("line_id, shift_id, shift_name").in("line_id", lineIds);
47838
+ if (shiftsError) {
47839
+ console.warn("[TargetsView] Error fetching shift definitions, falling back to defaults", shiftsError);
47840
+ }
47841
+ const derivedShiftOptions = (shiftsData || []).reduce((acc, row) => {
47842
+ if (acc.some((s) => s.id === row.shift_id)) return acc;
47843
+ acc.push({ id: row.shift_id, name: row.shift_name || `Shift ${row.shift_id}` });
47844
+ return acc;
47845
+ }, []);
47846
+ const effectiveShiftOptions = derivedShiftOptions.length > 0 ? derivedShiftOptions.sort((a, b) => a.id - b.id) : [
47847
+ { id: 0, name: "Day Shift" },
47848
+ { id: 1, name: "Night Shift" }
47849
+ ];
47850
+ setShiftOptions(effectiveShiftOptions);
47851
+ const defaultShiftId = effectiveShiftOptions[0].id;
47852
+ setSelectedShift(defaultShiftId);
47439
47853
  const bulkResponse = await workspaceService.fetchBulkTargets({
47440
47854
  companyId,
47441
47855
  lineIds,
47442
47856
  date: currentDate,
47443
- shifts: [0, 1],
47444
- // Fetch both shifts at once
47857
+ shifts: effectiveShiftOptions.map((s) => s.id),
47858
+ // Fetch all configured shifts
47445
47859
  includeSkus: skuEnabled,
47446
47860
  includeActions: true
47447
47861
  });
@@ -47459,10 +47873,14 @@ var TargetsView = ({
47459
47873
  packaging: packagingAction.id
47460
47874
  };
47461
47875
  setActionIds(actionIdsData);
47462
- const newAllShiftsData = { 0: {}, 1: {} };
47463
- const newDbValues = { 0: {}, 1: {} };
47876
+ const newAllShiftsData = {};
47877
+ const newDbValues = {};
47878
+ effectiveShiftOptions.forEach((opt) => {
47879
+ newAllShiftsData[opt.id] = {};
47880
+ newDbValues[opt.id] = {};
47881
+ });
47464
47882
  Object.entries(data.lines).forEach(([lineId, lineData]) => {
47465
- [0, 1].forEach((shiftId) => {
47883
+ effectiveShiftOptions.forEach(({ id: shiftId }) => {
47466
47884
  const shiftData = lineData.shifts[shiftId.toString()];
47467
47885
  if (!shiftData) {
47468
47886
  console.warn(`No shift ${shiftId} data for line ${lineId}`);
@@ -47633,7 +48051,7 @@ var TargetsView = ({
47633
48051
  setUserEditedFields(/* @__PURE__ */ new Set());
47634
48052
  if (dbValues[shiftId] && Object.keys(dbValues[shiftId]).length > 0) {
47635
48053
  setAllShiftsData((prev) => {
47636
- const updatedShiftData = { ...prev[shiftId] };
48054
+ const updatedShiftData = { ...prev[shiftId] || {} };
47637
48055
  for (const lineId of Object.keys(updatedShiftData)) {
47638
48056
  if (dbValues[shiftId][lineId]) {
47639
48057
  updatedShiftData[lineId] = {
@@ -47855,6 +48273,7 @@ var TargetsView = ({
47855
48273
  savingLines,
47856
48274
  saveSuccess,
47857
48275
  selectedShift,
48276
+ shiftOptions,
47858
48277
  isBulkConfigureOpen,
47859
48278
  navItems: [],
47860
48279
  currentPathname: "/targets",
@@ -47986,12 +48405,10 @@ var WorkspaceDetailView = ({
47986
48405
  const today = new Date((/* @__PURE__ */ new Date()).toLocaleString("en-US", { timeZone: timezone }));
47987
48406
  const [selectedMonth, setSelectedMonth] = React23.useState(today.getMonth());
47988
48407
  const [selectedYear, setSelectedYear] = React23.useState(today.getFullYear());
47989
- const [selectedShift, setSelectedShift] = React23.useState("day");
48408
+ const [selectedShift, setSelectedShift] = React23.useState(0);
47990
48409
  React23.useEffect(() => {
47991
- if (parsedShiftId === 1) {
47992
- setSelectedShift("night");
47993
- } else if (parsedShiftId === 0) {
47994
- setSelectedShift("day");
48410
+ if (parsedShiftId !== void 0) {
48411
+ setSelectedShift(parsedShiftId);
47995
48412
  }
47996
48413
  }, [parsedShiftId]);
47997
48414
  const isHistoricView = Boolean(date && parsedShiftId !== void 0);
@@ -48003,6 +48420,13 @@ var WorkspaceDetailView = ({
48003
48420
  const dashboardConfig = useDashboardConfig();
48004
48421
  const isClipsEnabled = dashboardConfig?.clipsConfig?.enabled ?? true;
48005
48422
  dashboardConfig?.supervisorConfig?.enabled || false;
48423
+ const effectiveLineId = lineId || selectedLineId;
48424
+ const { shiftConfig, isLoading: isShiftConfigLoading } = useDynamicShiftConfig(effectiveLineId);
48425
+ const calculatedOperationalDate = React23.useMemo(() => {
48426
+ if (isShiftConfigLoading || !shiftConfig) return null;
48427
+ const currentShift = getCurrentShift(timezone, shiftConfig);
48428
+ return currentShift.date;
48429
+ }, [isShiftConfigLoading, shiftConfig, timezone]);
48006
48430
  const {
48007
48431
  workspace: workspaceHealth,
48008
48432
  loading: healthLoading,
@@ -48063,7 +48487,9 @@ var WorkspaceDetailView = ({
48063
48487
  } = useHistoricWorkspaceMetrics(
48064
48488
  workspaceId || "",
48065
48489
  date || "",
48066
- parsedShiftId
48490
+ parsedShiftId,
48491
+ { shiftConfig, enabled: !isShiftConfigLoading }
48492
+ // Pass dynamic shift config and enabled flag
48067
48493
  );
48068
48494
  const {
48069
48495
  metrics: liveMetrics,
@@ -48071,11 +48497,13 @@ var WorkspaceDetailView = ({
48071
48497
  error: liveError
48072
48498
  } = useWorkspaceDetailedMetrics(
48073
48499
  workspaceId || "",
48074
- getOperationalDate(timezone),
48075
- void 0
48500
+ calculatedOperationalDate || getOperationalDate(timezone),
48501
+ void 0,
48502
+ { shiftConfig, enabled: !isShiftConfigLoading }
48503
+ // Pass the dynamic shift config here and enabled flag
48076
48504
  );
48077
48505
  const workspace = isHistoricView ? historicMetrics : liveMetrics;
48078
- const loading = isHistoricView ? historicLoading : liveLoading;
48506
+ const loading = (isHistoricView ? historicLoading : liveLoading) || isShiftConfigLoading;
48079
48507
  const error = isHistoricView ? historicError : liveError;
48080
48508
  const { supervisorName } = useLineSupervisor(workspace?.line_id || lineId);
48081
48509
  React23.useEffect(() => {
@@ -48095,7 +48523,7 @@ var WorkspaceDetailView = ({
48095
48523
  }, [isClipsEnabled, activeTab]);
48096
48524
  React23.useEffect(() => {
48097
48525
  if (liveMetrics && !date && !shift) {
48098
- const currentDate = getOperationalDate(timezone);
48526
+ const currentDate = calculatedOperationalDate || getOperationalDate(timezone);
48099
48527
  if (liveMetrics.date !== currentDate) {
48100
48528
  setUsingFallbackData(true);
48101
48529
  if (activeTab !== "monthly_history") {
@@ -48105,7 +48533,7 @@ var WorkspaceDetailView = ({
48105
48533
  setUsingFallbackData(false);
48106
48534
  }
48107
48535
  }
48108
- }, [liveMetrics, date, shift, activeTab]);
48536
+ }, [liveMetrics, date, shift, activeTab, calculatedOperationalDate]);
48109
48537
  React23.useMemo(() => {
48110
48538
  if (isHistoricView && date) {
48111
48539
  try {
@@ -48113,11 +48541,11 @@ var WorkspaceDetailView = ({
48113
48541
  return date;
48114
48542
  } catch (e) {
48115
48543
  console.error("Error parsing historic date:", e);
48116
- return getOperationalDate(timezone);
48544
+ return calculatedOperationalDate || getOperationalDate(timezone);
48117
48545
  }
48118
48546
  }
48119
- return getOperationalDate(timezone);
48120
- }, [isHistoricView, date]);
48547
+ return calculatedOperationalDate || getOperationalDate(timezone);
48548
+ }, [isHistoricView, date, calculatedOperationalDate, timezone]);
48121
48549
  const handleMonthlyDataLoaded = React23.useCallback((data) => {
48122
48550
  console.log("[handleMonthlyDataLoaded] Received data:", {
48123
48551
  dataLength: data?.length,
@@ -48141,10 +48569,8 @@ var WorkspaceDetailView = ({
48141
48569
  if (!dayEntry) {
48142
48570
  dayEntry = {
48143
48571
  date: dateObj,
48144
- dayShift: null,
48145
- // Start with null instead of zeros
48146
- nightShift: null
48147
- // Start with null instead of zeros
48572
+ shifts: {}
48573
+ // Multi-shift structure: Record<number, CalendarShiftData>
48148
48574
  };
48149
48575
  dayDataMap.set(dateKey, dayEntry);
48150
48576
  }
@@ -48156,19 +48582,14 @@ var WorkspaceDetailView = ({
48156
48582
  pphThreshold: metric.pph_threshold || 0,
48157
48583
  idealOutput: metric.ideal_output || 0,
48158
48584
  rank: metric.workspace_rank || 0,
48159
- idleTime: metric.idle_time || 0
48585
+ idleTime: metric.idle_time || 0,
48586
+ hasData: true
48160
48587
  };
48161
- if (metric.shift_id === 0) {
48162
- dayEntry.dayShift = shiftData;
48163
- } else {
48164
- dayEntry.nightShift = shiftData;
48165
- }
48588
+ dayEntry.shifts[metric.shift_id] = shiftData;
48166
48589
  });
48167
- const processedData = Array.from(dayDataMap.values()).filter((entry) => entry.dayShift !== null || entry.nightShift !== null).map((entry) => ({
48590
+ const processedData = Array.from(dayDataMap.values()).filter((entry) => Object.keys(entry.shifts).length > 0).map((entry) => ({
48168
48591
  date: entry.date,
48169
- // If a shift is null (no data), provide zeros for compatibility
48170
- dayShift: entry.dayShift || { efficiency: 0, output: 0, cycleTime: 0, pph: 0, pphThreshold: 0, idealOutput: 0, rank: 0, idleTime: 0 },
48171
- nightShift: entry.nightShift || { efficiency: 0, output: 0, cycleTime: 0, pph: 0, pphThreshold: 0, idealOutput: 0, rank: 0, idleTime: 0 }
48592
+ shifts: entry.shifts
48172
48593
  }));
48173
48594
  console.log(`[handleMonthlyDataLoaded] Transformed data for calendar:`, {
48174
48595
  count: processedData.length,
@@ -48176,7 +48597,6 @@ var WorkspaceDetailView = ({
48176
48597
  });
48177
48598
  setMonthlyData(processedData);
48178
48599
  }, []);
48179
- const effectiveLineId = lineId || selectedLineId;
48180
48600
  const formattedWorkspaceName = displayName || formatWorkspaceName3(workspace?.workspace_name || "", effectiveLineId);
48181
48601
  const shouldShowCycleTimeChart = showCycleTimeChart ?? formattedWorkspaceName.startsWith("FINAL ASSY");
48182
48602
  const handleBackNavigation = () => {
@@ -48197,7 +48617,7 @@ var WorkspaceDetailView = ({
48197
48617
  if (onNavigate) {
48198
48618
  const params = new URLSearchParams();
48199
48619
  params.set("fromMonthly", "true");
48200
- params.set("shift", selectedShift === "night" ? "1" : "0");
48620
+ params.set("shift", selectedShift.toString());
48201
48621
  if (effectiveLineId) {
48202
48622
  params.set("lineId", effectiveLineId);
48203
48623
  }
@@ -48209,7 +48629,7 @@ var WorkspaceDetailView = ({
48209
48629
  if (onNavigate) {
48210
48630
  const params = new URLSearchParams();
48211
48631
  params.set("fromMonthly", "true");
48212
- params.set("shift", selectedShift === "night" ? "1" : "0");
48632
+ params.set("shift", selectedShift.toString());
48213
48633
  if (effectiveLineId) {
48214
48634
  params.set("lineId", effectiveLineId);
48215
48635
  }
@@ -48222,11 +48642,16 @@ var WorkspaceDetailView = ({
48222
48642
  }
48223
48643
  }
48224
48644
  };
48225
- const getShiftIcon = (shiftType) => {
48226
- if (shiftType === "Day") {
48645
+ const getShiftIcon2 = (shiftType) => {
48646
+ const shiftTypeLower = shiftType?.toLowerCase() || "";
48647
+ if (shiftTypeLower.includes("day") || shiftTypeLower.includes("morning")) {
48227
48648
  return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" }) });
48228
- } else {
48649
+ } else if (shiftTypeLower.includes("afternoon") || shiftTypeLower.includes("noon") || shiftTypeLower.includes("midday")) {
48650
+ return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" }) });
48651
+ } else if (shiftTypeLower.includes("night") || shiftTypeLower.includes("evening")) {
48229
48652
  return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z" }) });
48653
+ } else {
48654
+ return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" }) });
48230
48655
  }
48231
48656
  };
48232
48657
  if (loading) {
@@ -48377,7 +48802,7 @@ var WorkspaceDetailView = ({
48377
48802
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "sm:hidden mt-3 flex items-center justify-center gap-2", children: [
48378
48803
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "inline-flex items-center px-2.5 py-1 bg-gray-100 rounded-full", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-gray-700", children: formatISTDate2(new Date(workspace.date)) }) }),
48379
48804
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "inline-flex items-center gap-1 px-2.5 py-1 bg-gray-100 rounded-full", children: [
48380
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-gray-700 scale-90", children: getShiftIcon(workspace.shift_type) }),
48805
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-gray-700 scale-90", children: getShiftIcon2(workspace.shift_type) }),
48381
48806
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-gray-700", children: workspace.shift_type })
48382
48807
  ] }),
48383
48808
  !date && !shift && !usingFallbackData ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "inline-flex items-center px-2.5 py-1 bg-green-100 rounded-full", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-green-700", children: /* @__PURE__ */ jsxRuntime.jsx(LiveTimer, {}) }) }) : date ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "inline-flex items-center px-2.5 py-1 bg-blue-100 rounded-full", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-blue-700", children: getDaysDifference(workspace.date, timezone, dashboardConfig?.shiftConfig?.dayShift?.startTime || "06:00") }) }) : usingFallbackData ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "inline-flex items-center px-2.5 py-1 bg-amber-100 rounded-full", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-amber-700", children: getDaysDifference(workspace.date, timezone, dashboardConfig?.shiftConfig?.dayShift?.startTime || "06:00") }) }) : null
@@ -48402,11 +48827,8 @@ var WorkspaceDetailView = ({
48402
48827
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-px h-4 bg-blue-300" })
48403
48828
  ] }),
48404
48829
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
48405
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-blue-600", children: getShiftIcon(workspace.shift_type) }),
48406
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-sm md:text-base font-medium text-blue-600", children: [
48407
- workspace.shift_type,
48408
- " Shift"
48409
- ] })
48830
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-blue-600", children: getShiftIcon2(workspace.shift_type) }),
48831
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm md:text-base font-medium text-blue-600", children: workspace.shift_type })
48410
48832
  ] })
48411
48833
  ] }) })
48412
48834
  ] }),
@@ -48473,7 +48895,7 @@ var WorkspaceDetailView = ({
48473
48895
  monthlyData,
48474
48896
  selectedMonth,
48475
48897
  selectedYear,
48476
- selectedShift
48898
+ selectedShiftId: selectedShift
48477
48899
  }
48478
48900
  ) })
48479
48901
  ] })
@@ -48742,15 +49164,16 @@ var WorkspaceDetailView = ({
48742
49164
  month: selectedMonth,
48743
49165
  year: selectedYear,
48744
49166
  workspaceId,
48745
- selectedShift,
49167
+ selectedShiftId: selectedShift,
48746
49168
  monthlyDataLoading,
48747
- onDateSelect: (selectedDate, shift2) => {
49169
+ availableShifts: shiftConfig?.shifts?.map((s) => ({ id: s.shiftId, name: s.shiftName })),
49170
+ onDateSelect: (selectedDate, shiftId) => {
48748
49171
  if (onDateSelect) {
48749
- onDateSelect(selectedDate, shift2);
49172
+ onDateSelect(selectedDate, shiftId);
48750
49173
  } else if (onNavigate) {
48751
49174
  const params = new URLSearchParams();
48752
49175
  params.set("date", selectedDate);
48753
- params.set("shift", shift2 === "day" ? "0" : "1");
49176
+ params.set("shift", shiftId.toString());
48754
49177
  params.set("fromMonthly", "true");
48755
49178
  if (effectiveLineId) {
48756
49179
  params.set("lineId", effectiveLineId);
@@ -48773,6 +49196,7 @@ var WorkspaceDetailView = ({
48773
49196
  workspaceId,
48774
49197
  workspaceName: formattedWorkspaceName,
48775
49198
  date,
49199
+ lineId: effectiveLineId,
48776
49200
  shift,
48777
49201
  totalOutput: workspace?.total_actions,
48778
49202
  className: "h-[calc(100vh-10rem)]"
@@ -48929,6 +49353,13 @@ var SKUManagementView = () => {
48929
49353
  var useWorkspaceHealth = (options) => {
48930
49354
  const supabase = useSupabase();
48931
49355
  const databaseConfig = useDatabaseConfig();
49356
+ const entityConfig = useEntityConfig();
49357
+ const configuredLineIds = React23.useMemo(() => getConfiguredLineIds(entityConfig), [entityConfig]);
49358
+ const firstConfiguredLineId = configuredLineIds[0];
49359
+ const isFactoryView = !options.lineId || options.lineId === (entityConfig?.factoryViewId || "factory");
49360
+ const effectiveLineIdForShiftConfig = isFactoryView ? firstConfiguredLineId : options.lineId;
49361
+ const { shiftConfig, isLoading: isShiftConfigLoading } = useDynamicShiftConfig(effectiveLineIdForShiftConfig);
49362
+ const timezone = useAppTimezone() || "UTC";
48932
49363
  const [workspaces, setWorkspaces] = React23.useState([]);
48933
49364
  const [summary, setSummary] = React23.useState({
48934
49365
  totalWorkspaces: 0,
@@ -48975,6 +49406,14 @@ var useWorkspaceHealth = (options) => {
48975
49406
  }, []);
48976
49407
  const fetchWorkspacesHealth = React23.useCallback(async () => {
48977
49408
  if (isFetchingRef.current) return;
49409
+ if (isShiftConfigLoading) {
49410
+ console.log("[useWorkspaceHealth] \u23F3 Waiting for shift config to load");
49411
+ return;
49412
+ }
49413
+ if (!shiftConfig) {
49414
+ console.warn("[useWorkspaceHealth] \u26A0\uFE0F Shift config is null, waiting for it to load");
49415
+ return;
49416
+ }
48978
49417
  if (!options.companyId) {
48979
49418
  setWorkspaces([]);
48980
49419
  setSummary(computeSummary([]));
@@ -48985,9 +49424,16 @@ var useWorkspaceHealth = (options) => {
48985
49424
  isFetchingRef.current = true;
48986
49425
  setLoading(true);
48987
49426
  setError(null);
49427
+ console.log("[useWorkspaceHealth] \u{1F680} Fetching health status with shift config:", {
49428
+ lineId: options.lineId,
49429
+ hasShiftConfig: !!shiftConfig,
49430
+ shiftId: shiftConfig?.shifts?.[0]?.shiftId
49431
+ });
48988
49432
  const workspacesWithStatus = await workspaceHealthService.getWorkspaceHealthStatus({
48989
49433
  lineId: options.lineId,
48990
- companyId: options.companyId
49434
+ companyId: options.companyId,
49435
+ shiftConfig,
49436
+ timezone
48991
49437
  });
48992
49438
  setWorkspaces(workspacesWithStatus);
48993
49439
  setSummary(computeSummary(workspacesWithStatus));
@@ -48999,7 +49445,7 @@ var useWorkspaceHealth = (options) => {
48999
49445
  setLoading(false);
49000
49446
  isFetchingRef.current = false;
49001
49447
  }
49002
- }, [options.companyId, options.lineId, computeSummary]);
49448
+ }, [options.companyId, options.lineId, computeSummary, shiftConfig, isShiftConfigLoading, timezone]);
49003
49449
  React23.useEffect(() => {
49004
49450
  fetchWorkspacesHealth();
49005
49451
  }, [fetchWorkspacesHealth]);
@@ -49039,9 +49485,12 @@ var useWorkspaceHealth = (options) => {
49039
49485
  return {
49040
49486
  workspaces,
49041
49487
  summary,
49042
- loading,
49488
+ loading: loading || isShiftConfigLoading || !shiftConfig,
49043
49489
  error,
49044
- refetch: fetchWorkspacesHealth
49490
+ refetch: fetchWorkspacesHealth,
49491
+ // Expose shift config so consumers can pass it to child components
49492
+ shiftConfig,
49493
+ isShiftConfigLoading
49045
49494
  };
49046
49495
  };
49047
49496
  var STATUS_COLORS = {
@@ -49240,7 +49689,8 @@ var formatTimeRange = (start, end, timezone) => {
49240
49689
  var WorkspaceUptimeDetailModal = ({
49241
49690
  workspace,
49242
49691
  isOpen,
49243
- onClose
49692
+ onClose,
49693
+ shiftConfig: passedShiftConfig
49244
49694
  }) => {
49245
49695
  const timezone = useAppTimezone() || "UTC";
49246
49696
  const logsContainerRef = React23.useRef(null);
@@ -49254,7 +49704,12 @@ var WorkspaceUptimeDetailModal = ({
49254
49704
  workspaceId: workspace?.workspace_id,
49255
49705
  companyId: workspace?.company_id,
49256
49706
  enabled: isOpen && Boolean(workspace?.workspace_id && workspace?.company_id),
49257
- refreshInterval: 6e4
49707
+ refreshInterval: 6e4,
49708
+ lineId: workspace?.line_id,
49709
+ // Pass shift config from parent if available - avoids duplicate DB queries
49710
+ // and ensures consistent shift timing across the view
49711
+ shiftConfig: passedShiftConfig || void 0,
49712
+ timezone
49258
49713
  });
49259
49714
  React23.useEffect(() => {
49260
49715
  if (!isOpen || !workspace) return;
@@ -49441,32 +49896,48 @@ var WorkspaceHealthView = ({
49441
49896
  }) => {
49442
49897
  const router$1 = router.useRouter();
49443
49898
  const [groupBy, setGroupBy] = React23.useState("line");
49899
+ const entityConfig = useEntityConfig();
49900
+ const configuredLineIds = React23.useMemo(() => getConfiguredLineIds(entityConfig), [entityConfig]);
49901
+ const firstConfiguredLineId = configuredLineIds[0];
49902
+ const factoryViewId = entityConfig?.factoryViewId || "factory";
49903
+ const isFactoryView = !lineId || lineId === factoryViewId;
49904
+ const effectiveLineId = isFactoryView ? firstConfiguredLineId : lineId;
49444
49905
  const timezone = useAppTimezone();
49906
+ const { shiftConfig, isLoading: isShiftConfigLoading } = useDynamicShiftConfig(effectiveLineId);
49445
49907
  const [selectedWorkspace, setSelectedWorkspace] = React23.useState(null);
49446
- const operationalDate = getOperationalDate(timezone || "UTC");
49447
- const currentHour = (/* @__PURE__ */ new Date()).getHours();
49448
- const isNightShift = currentHour >= 18 || currentHour < 6;
49449
- const shiftType = isNightShift ? "Night" : "Day";
49908
+ const effectiveTimezone = timezone || "UTC";
49909
+ const currentShiftDetails = getCurrentShift(effectiveTimezone, shiftConfig);
49910
+ const operationalDate = currentShiftDetails.date;
49911
+ const shiftType = (currentShiftDetails.shiftName || "Day").replace(/ Shift$/i, "");
49450
49912
  const formatDate = (date) => {
49451
49913
  const d = new Date(date);
49452
49914
  return d.toLocaleDateString("en-IN", {
49453
49915
  month: "long",
49454
49916
  day: "numeric",
49455
49917
  year: "numeric",
49456
- timeZone: "Asia/Kolkata"
49918
+ timeZone: effectiveTimezone
49457
49919
  });
49458
49920
  };
49459
- const getShiftIcon = (shift) => {
49460
- return shift === "Night" ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Moon, { className: "h-4 w-4" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Sun, { className: "h-4 w-4" });
49921
+ const getShiftIcon2 = () => {
49922
+ const shiftName = (currentShiftDetails.shiftName || "").toLowerCase();
49923
+ if (shiftName.includes("night") || shiftName.includes("evening") || currentShiftDetails.shiftId === 1) {
49924
+ return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Moon, { className: "h-4 w-4" });
49925
+ }
49926
+ if (shiftName.includes("afternoon") || shiftName.includes("noon") || shiftName.includes("midday")) {
49927
+ return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Sun, { className: "h-4 w-4" });
49928
+ }
49929
+ return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Sun, { className: "h-4 w-4" });
49461
49930
  };
49462
49931
  const {
49463
49932
  workspaces,
49464
49933
  summary,
49465
49934
  loading,
49466
49935
  error,
49467
- refetch
49936
+ refetch,
49937
+ shiftConfig: loadedShiftConfig
49938
+ // Get shift config from the hook to pass to modal
49468
49939
  } = useWorkspaceHealth({
49469
- lineId,
49940
+ lineId: effectiveLineId,
49470
49941
  companyId,
49471
49942
  enableRealtime: true,
49472
49943
  refreshInterval: 1e4
@@ -49528,7 +49999,7 @@ var WorkspaceHealthView = ({
49528
49999
  if (percentage >= 90) return "text-yellow-600 dark:text-yellow-400";
49529
50000
  return "text-red-600 dark:text-red-400";
49530
50001
  };
49531
- if (loading && !summary) {
50002
+ if (loading && !summary || isShiftConfigLoading) {
49532
50003
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-h-screen bg-gray-50 dark:bg-gray-900 p-4", children: /* @__PURE__ */ jsxRuntime.jsx(LoadingState, {}) });
49533
50004
  }
49534
50005
  if (error) {
@@ -49638,7 +50109,7 @@ var WorkspaceHealthView = ({
49638
50109
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs sm:text-sm md:text-base font-medium text-blue-600", children: formatDate(operationalDate) }),
49639
50110
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "hidden sm:block w-px h-4 bg-blue-300" }),
49640
50111
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1 sm:gap-2", children: [
49641
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-blue-600", children: getShiftIcon(shiftType) }),
50112
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-blue-600", children: getShiftIcon2() }),
49642
50113
  /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs sm:text-sm md:text-base font-medium text-blue-600", children: [
49643
50114
  shiftType,
49644
50115
  " Shift"
@@ -49726,7 +50197,8 @@ var WorkspaceHealthView = ({
49726
50197
  {
49727
50198
  workspace: selectedWorkspace,
49728
50199
  isOpen: Boolean(selectedWorkspace),
49729
- onClose: handleCloseDetails
50200
+ onClose: handleCloseDetails,
50201
+ shiftConfig: loadedShiftConfig
49730
50202
  }
49731
50203
  )
49732
50204
  ] });
@@ -51763,25 +52235,15 @@ var TeamManagementView_default = TeamManagementView;
51763
52235
  function BottleneckClipsView({
51764
52236
  workspaceId: propWorkspaceId,
51765
52237
  workspaceName: propWorkspaceName,
52238
+ lineId: propLineId,
51766
52239
  date: propDate,
51767
52240
  shift: propShift,
51768
52241
  totalOutput: propTotalOutput
51769
52242
  }) {
51770
52243
  const router$1 = router.useRouter();
51771
- const dashboardConfig = useDashboardConfig();
51772
- const timezone = useAppTimezone();
51773
52244
  const workspaceId = propWorkspaceId || router$1.query.workspaceId;
51774
52245
  const workspaceName = propWorkspaceName || router$1.query.workspaceName || "Workstation";
51775
- const operationalDate = React23.useMemo(() => {
51776
- if (propDate) return propDate;
51777
- return getOperationalDate(timezone || dashboardConfig.dateTimeConfig?.defaultTimezone || "UTC");
51778
- }, [propDate, timezone, dashboardConfig]);
51779
- const currentShift = React23.useMemo(() => {
51780
- if (propShift !== void 0) return propShift;
51781
- const tz = timezone || dashboardConfig.dateTimeConfig?.defaultTimezone || "UTC";
51782
- const shiftResult = getCurrentShift(tz, dashboardConfig?.shiftConfig);
51783
- return shiftResult.shiftId;
51784
- }, [propShift, dashboardConfig, timezone]);
52246
+ const lineId = propLineId || router$1.query.lineId;
51785
52247
  if (!workspaceId) {
51786
52248
  return /* @__PURE__ */ jsxRuntime.jsx(LoadingPage_default, { message: "Loading workspace data..." });
51787
52249
  }
@@ -51830,8 +52292,9 @@ function BottleneckClipsView({
51830
52292
  {
51831
52293
  workspaceId,
51832
52294
  workspaceName,
51833
- date: operationalDate,
51834
- shift: currentShift,
52295
+ lineId,
52296
+ date: propDate,
52297
+ shift: propShift,
51835
52298
  totalOutput: propTotalOutput,
51836
52299
  className: "h-full"
51837
52300
  }
@@ -53349,6 +53812,7 @@ exports.DEFAULT_ENDPOINTS_CONFIG = DEFAULT_ENDPOINTS_CONFIG;
53349
53812
  exports.DEFAULT_ENTITY_CONFIG = DEFAULT_ENTITY_CONFIG;
53350
53813
  exports.DEFAULT_MAP_VIEW_CONFIG = DEFAULT_MAP_VIEW_CONFIG;
53351
53814
  exports.DEFAULT_SHIFT_CONFIG = DEFAULT_SHIFT_CONFIG;
53815
+ exports.DEFAULT_SHIFT_DATA = DEFAULT_SHIFT_DATA;
53352
53816
  exports.DEFAULT_THEME_CONFIG = DEFAULT_THEME_CONFIG;
53353
53817
  exports.DEFAULT_VIDEO_CONFIG = DEFAULT_VIDEO_CONFIG;
53354
53818
  exports.DEFAULT_WORKSPACE_CONFIG = DEFAULT_WORKSPACE_CONFIG;
@@ -53532,6 +53996,7 @@ exports.getAllLineDisplayNames = getAllLineDisplayNames;
53532
53996
  exports.getAllThreadMessages = getAllThreadMessages;
53533
53997
  exports.getAllWorkspaceDisplayNamesAsync = getAllWorkspaceDisplayNamesAsync;
53534
53998
  exports.getAnonClient = getAnonClient;
53999
+ exports.getAvailableShiftIds = getAvailableShiftIds;
53535
54000
  exports.getBrowserName = getBrowserName;
53536
54001
  exports.getCameraNumber = getCameraNumber;
53537
54002
  exports.getCompanyMetricsTableName = getCompanyMetricsTableName;
@@ -53554,6 +54019,9 @@ exports.getNextUpdateInterval = getNextUpdateInterval;
53554
54019
  exports.getOperationalDate = getOperationalDate;
53555
54020
  exports.getS3SignedUrl = getS3SignedUrl;
53556
54021
  exports.getS3VideoSrc = getS3VideoSrc;
54022
+ exports.getShiftData = getShiftData;
54023
+ exports.getShiftNameById = getShiftNameById;
54024
+ exports.getShortShiftName = getShortShiftName;
53557
54025
  exports.getShortWorkspaceDisplayName = getShortWorkspaceDisplayName;
53558
54026
  exports.getShortWorkspaceDisplayNameAsync = getShortWorkspaceDisplayNameAsync;
53559
54027
  exports.getStoredWorkspaceMappings = getStoredWorkspaceMappings;
@@ -53566,6 +54034,7 @@ exports.getWorkspaceDisplayNameAsync = getWorkspaceDisplayNameAsync;
53566
54034
  exports.getWorkspaceDisplayNamesMap = getWorkspaceDisplayNamesMap;
53567
54035
  exports.getWorkspaceFromUrl = getWorkspaceFromUrl;
53568
54036
  exports.getWorkspaceNavigationParams = getWorkspaceNavigationParams;
54037
+ exports.hasAnyShiftData = hasAnyShiftData;
53569
54038
  exports.identifyCoreUser = identifyCoreUser;
53570
54039
  exports.initializeCoreMixpanel = initializeCoreMixpanel;
53571
54040
  exports.isLegacyConfiguration = isLegacyConfiguration;