@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.mjs CHANGED
@@ -11,7 +11,7 @@ import Hls3, { Events, ErrorTypes } from 'hls.js';
11
11
  import useSWR from 'swr';
12
12
  import { noop, warning, invariant, progress, secondsToMilliseconds, millisecondsToSeconds, memo as memo$1 } from 'motion-utils';
13
13
  import { getValueTransition, hover, press, isPrimaryPointer, GroupPlaybackControls, setDragLock, supportsLinearEasing, attachTimeline, isGenerator, calcGeneratorDuration, isWaapiSupportedEasing, mapEasingToNativeEasing, maxGeneratorDuration, generateLinearEasing, isBezierDefinition } from 'motion-dom';
14
- import { Camera, ChevronDown, ChevronUp, Check, Map as Map$1, Video, ShieldCheck, Star, Award, ArrowLeft, X, Coffee, Plus, Clock, Calendar, Save, AlertCircle, Loader2, Minus, ArrowDown, ArrowUp, ChevronLeft, ChevronRight, Pause, Play, XCircle, Sparkles, TrendingUp, Settings2, CheckCircle2, RefreshCw, TrendingDown, FolderOpen, Folder, HelpCircle, Sliders, Activity, Layers, Filter, Search, Edit2, AlertTriangle, CheckCircle, Building2, Mail, Users, User, Lock, ArrowRight, Info, Share2, Trophy, Target, Download, Sun, Moon, MousePointer, MessageSquare, Trash2, Menu, Send, Copy, UserCheck, LogOut, Package, UserPlus, Settings, LifeBuoy, EyeOff, Eye, MoreVertical, UserCog, Zap, Shield, UserCircle } from 'lucide-react';
14
+ import { Camera, ChevronDown, ChevronUp, Check, Map as Map$1, Video, ShieldCheck, Star, Award, ArrowLeft, X, Trash2, Coffee, Plus, Clock, Calendar, Save, AlertCircle, Loader2, Minus, ArrowDown, ArrowUp, ChevronLeft, ChevronRight, Pause, Play, XCircle, Sparkles, TrendingUp, Settings2, CheckCircle2, RefreshCw, TrendingDown, FolderOpen, Folder, HelpCircle, Sliders, Activity, Layers, Filter, Search, Edit2, AlertTriangle, CheckCircle, Building2, Mail, Users, User, Lock, ArrowRight, Info, Share2, Trophy, Target, Download, Sun, Moon, MousePointer, MessageSquare, Menu, Send, Copy, UserCheck, LogOut, Package, UserPlus, Settings, LifeBuoy, EyeOff, Eye, MoreVertical, UserCog, Zap, Shield, UserCircle } from 'lucide-react';
15
15
  import { toast } from 'sonner';
16
16
  import { BarChart as BarChart$1, CartesianGrid, XAxis, YAxis, Tooltip, Legend, Bar, LabelList, ResponsiveContainer, LineChart as LineChart$1, Line, PieChart, Pie, Cell, ReferenceLine, ComposedChart, Area, ScatterChart, Scatter } from 'recharts';
17
17
  import { Slot } from '@radix-ui/react-slot';
@@ -96,6 +96,32 @@ function isValidPrefetchStatus(status) {
96
96
  return typeof status === "string" && Object.values(PrefetchStatus).includes(status);
97
97
  }
98
98
 
99
+ // src/lib/types/calendar.ts
100
+ var DEFAULT_SHIFT_DATA = {
101
+ efficiency: 0,
102
+ output: 0,
103
+ cycleTime: 0,
104
+ pph: 0,
105
+ pphThreshold: 0,
106
+ idealOutput: 0,
107
+ rank: 0,
108
+ idleTime: 0,
109
+ hasData: false
110
+ };
111
+ var getShiftData = (day, shiftId) => {
112
+ const shift = day.shifts[shiftId];
113
+ if (shift) {
114
+ return { ...shift, hasData: true };
115
+ }
116
+ return { ...DEFAULT_SHIFT_DATA };
117
+ };
118
+ var hasAnyShiftData = (day) => {
119
+ return Object.keys(day.shifts).length > 0;
120
+ };
121
+ var getAvailableShiftIds = (day) => {
122
+ return Object.keys(day.shifts).map(Number).sort((a, b) => a - b);
123
+ };
124
+
99
125
  // src/components/dashboard/grid/workspace_grid_constants.ts
100
126
  var DEFAULT_WORKSPACE_POSITIONS = [
101
127
  // Middle top row - 7 tapping workspaces (conveyor style)
@@ -142,15 +168,21 @@ var DEFAULT_ENTITY_CONFIG = {
142
168
  }
143
169
  };
144
170
  var DEFAULT_SHIFT_CONFIG = {
171
+ shifts: [
172
+ { shiftId: 0, shiftName: "Day Shift", startTime: "06:00", endTime: "18:00", breaks: [], timezone: "UTC" },
173
+ { shiftId: 1, shiftName: "Night Shift", startTime: "18:00", endTime: "06:00", breaks: [], timezone: "UTC" }
174
+ ],
145
175
  dayShift: {
146
176
  id: 0,
147
177
  startTime: "06:00",
148
- endTime: "18:00"
178
+ endTime: "18:00",
179
+ name: "Day Shift"
149
180
  },
150
181
  nightShift: {
151
182
  id: 1,
152
183
  startTime: "18:00",
153
- endTime: "06:00"
184
+ endTime: "06:00",
185
+ name: "Night Shift"
154
186
  },
155
187
  transitionPeriodMinutes: 15
156
188
  };
@@ -500,70 +532,128 @@ var parseTimeToMinutes = (timeString) => {
500
532
  const [hours, minutes] = timeString.split(":").map(Number);
501
533
  return hours * 60 + minutes;
502
534
  };
503
- var getCurrentShift = (timezone, shiftConfig, now2 = /* @__PURE__ */ new Date()) => {
504
- const dayShiftStartStr = shiftConfig?.dayShift?.startTime || DEFAULT_DAY_SHIFT_START;
505
- const nightShiftStartStr = shiftConfig?.nightShift?.startTime || DEFAULT_NIGHT_SHIFT_START;
506
- const dayShiftId = shiftConfig?.dayShift?.id ?? 0;
507
- const nightShiftId = shiftConfig?.nightShift?.id ?? 1;
508
- const dayShiftStartMinutes = parseTimeToMinutes(dayShiftStartStr);
509
- const nightShiftStartMinutes = parseTimeToMinutes(nightShiftStartStr);
510
- const effectiveDayStart = !isNaN(dayShiftStartMinutes) ? dayShiftStartMinutes : parseTimeToMinutes(DEFAULT_DAY_SHIFT_START);
511
- const effectiveNightStart = !isNaN(nightShiftStartMinutes) ? nightShiftStartMinutes : parseTimeToMinutes(DEFAULT_NIGHT_SHIFT_START);
535
+ var normalizeShiftDefinitions = (timezone, shiftConfig) => {
536
+ if (shiftConfig?.shifts && shiftConfig.shifts.length > 0) {
537
+ return {
538
+ shifts: shiftConfig.shifts,
539
+ timezone: shiftConfig.shifts[0].timezone || shiftConfig.timezone || timezone
540
+ };
541
+ }
542
+ const fallbackTimezone = shiftConfig?.timezone || timezone;
543
+ const legacyShifts = [];
544
+ if (shiftConfig?.dayShift) {
545
+ legacyShifts.push({
546
+ shiftId: shiftConfig.dayShift.id ?? 0,
547
+ shiftName: shiftConfig.dayShift.name || "Day Shift",
548
+ startTime: shiftConfig.dayShift.startTime || DEFAULT_DAY_SHIFT_START,
549
+ endTime: shiftConfig.dayShift.endTime || "18:00",
550
+ breaks: [],
551
+ timezone: fallbackTimezone
552
+ });
553
+ }
554
+ if (shiftConfig?.nightShift) {
555
+ legacyShifts.push({
556
+ shiftId: shiftConfig.nightShift.id ?? 1,
557
+ shiftName: shiftConfig.nightShift.name || "Night Shift",
558
+ startTime: shiftConfig.nightShift.startTime || DEFAULT_NIGHT_SHIFT_START,
559
+ endTime: shiftConfig.nightShift.endTime || "06:00",
560
+ breaks: [],
561
+ timezone: fallbackTimezone
562
+ });
563
+ }
564
+ if (legacyShifts.length === 0) {
565
+ legacyShifts.push(
566
+ {
567
+ shiftId: 0,
568
+ shiftName: "Day Shift",
569
+ startTime: DEFAULT_DAY_SHIFT_START,
570
+ endTime: "18:00",
571
+ breaks: [],
572
+ timezone: fallbackTimezone
573
+ },
574
+ {
575
+ shiftId: 1,
576
+ shiftName: "Night Shift",
577
+ startTime: DEFAULT_NIGHT_SHIFT_START,
578
+ endTime: "06:00",
579
+ breaks: [],
580
+ timezone: fallbackTimezone
581
+ }
582
+ );
583
+ }
584
+ return { shifts: legacyShifts, timezone: fallbackTimezone };
585
+ };
586
+ var determineShiftFromDefinitions = (timezone, shifts, now2 = /* @__PURE__ */ new Date()) => {
512
587
  const zonedNow = toZonedTime(now2, timezone);
513
- const currentHour = zonedNow.getHours();
514
- const currentMinutes = zonedNow.getMinutes();
515
- const currentTotalMinutes = currentHour * 60 + currentMinutes;
516
- const operationalDate = getOperationalDate(timezone, zonedNow, dayShiftStartStr);
517
- let determinedShiftId;
518
- if (effectiveDayStart < effectiveNightStart) {
519
- if (currentTotalMinutes >= effectiveDayStart && currentTotalMinutes < effectiveNightStart) {
520
- determinedShiftId = dayShiftId;
521
- } else {
522
- determinedShiftId = nightShiftId;
588
+ const currentMinutes = zonedNow.getHours() * 60 + zonedNow.getMinutes();
589
+ let chosen;
590
+ let operationalDate = getOperationalDate(timezone, zonedNow, shifts[0].startTime);
591
+ for (const shift of shifts) {
592
+ const start = parseTimeToMinutes(shift.startTime);
593
+ const endRaw = parseTimeToMinutes(shift.endTime);
594
+ let end = endRaw;
595
+ const wraps = end <= start;
596
+ if (wraps) end += 1440;
597
+ if (start <= currentMinutes && currentMinutes < end) {
598
+ chosen = shift;
599
+ operationalDate = getOperationalDate(timezone, zonedNow, shift.startTime);
600
+ break;
523
601
  }
524
- } else {
525
- if (currentTotalMinutes >= effectiveDayStart || currentTotalMinutes < effectiveNightStart) {
526
- determinedShiftId = dayShiftId;
527
- } else {
528
- determinedShiftId = nightShiftId;
602
+ if (start <= currentMinutes + 1440 && currentMinutes + 1440 < end) {
603
+ chosen = shift;
604
+ operationalDate = getOperationalDate(timezone, zonedNow, shift.startTime);
605
+ break;
529
606
  }
530
607
  }
531
- return { shiftId: determinedShiftId, date: operationalDate };
608
+ if (!chosen) {
609
+ chosen = shifts[0];
610
+ operationalDate = getOperationalDate(timezone, zonedNow, chosen.startTime);
611
+ }
612
+ return {
613
+ shiftId: chosen.shiftId,
614
+ shiftName: chosen.shiftName,
615
+ startTime: chosen.startTime,
616
+ endTime: chosen.endTime,
617
+ timezone,
618
+ date: operationalDate
619
+ };
620
+ };
621
+ var getCurrentShift = (timezone, shiftConfig, now2 = /* @__PURE__ */ new Date()) => {
622
+ const { shifts, timezone: effectiveTz } = normalizeShiftDefinitions(timezone, shiftConfig);
623
+ return determineShiftFromDefinitions(effectiveTz, shifts, now2);
532
624
  };
533
625
  var isTransitionPeriod = (timezone, shiftConfig, now2 = /* @__PURE__ */ new Date()) => {
534
- const dayShiftStartStr = shiftConfig?.dayShift?.startTime || DEFAULT_DAY_SHIFT_START;
535
- const nightShiftStartStr = shiftConfig?.nightShift?.startTime || DEFAULT_NIGHT_SHIFT_START;
536
626
  const transitionMinutes = shiftConfig?.transitionPeriodMinutes ?? DEFAULT_TRANSITION_MINUTES;
537
- const dayShiftStartMinutes = parseTimeToMinutes(dayShiftStartStr);
538
- const nightShiftStartMinutes = parseTimeToMinutes(nightShiftStartStr);
539
- if (isNaN(dayShiftStartMinutes) || isNaN(nightShiftStartMinutes)) {
540
- return false;
541
- }
542
- const transitionTimes = [dayShiftStartMinutes, nightShiftStartMinutes];
543
- const zonedNow = toZonedTime(now2, timezone);
544
- const currentHour = zonedNow.getHours();
545
- const currentMinutes = zonedNow.getMinutes();
546
- const currentTotalMinutes = currentHour * 60 + currentMinutes;
547
- return transitionTimes.some((transitionTime) => {
627
+ const { shifts, timezone: effectiveTz } = normalizeShiftDefinitions(timezone, shiftConfig);
628
+ if (!shifts.length) return false;
629
+ const zonedNow = toZonedTime(now2, effectiveTz);
630
+ const currentTotalMinutes = zonedNow.getHours() * 60 + zonedNow.getMinutes();
631
+ return shifts.some((shift) => {
632
+ const transitionTime = parseTimeToMinutes(shift.startTime);
633
+ if (isNaN(transitionTime)) return false;
548
634
  const lowerBoundBefore = (transitionTime - transitionMinutes + 1440) % 1440;
549
635
  const upperBoundBefore = transitionTime;
550
- let isBefore = false;
551
- if (lowerBoundBefore < upperBoundBefore) {
552
- isBefore = currentTotalMinutes >= lowerBoundBefore && currentTotalMinutes < upperBoundBefore;
553
- } else {
554
- isBefore = currentTotalMinutes >= lowerBoundBefore || currentTotalMinutes < upperBoundBefore;
555
- }
556
636
  const lowerBoundAfter = transitionTime;
557
637
  const upperBoundAfter = (transitionTime + transitionMinutes) % 1440;
558
- let isAfter = false;
559
- if (lowerBoundAfter < upperBoundAfter) {
560
- isAfter = currentTotalMinutes >= lowerBoundAfter && currentTotalMinutes < upperBoundAfter;
561
- } else {
562
- isAfter = currentTotalMinutes >= lowerBoundAfter || currentTotalMinutes < upperBoundAfter;
563
- }
564
- return isBefore || isAfter;
638
+ const inBefore = lowerBoundBefore < upperBoundBefore ? currentTotalMinutes >= lowerBoundBefore && currentTotalMinutes < upperBoundBefore : currentTotalMinutes >= lowerBoundBefore || currentTotalMinutes < upperBoundBefore;
639
+ const inAfter = lowerBoundAfter < upperBoundAfter ? currentTotalMinutes >= lowerBoundAfter && currentTotalMinutes < upperBoundAfter : currentTotalMinutes >= lowerBoundAfter || currentTotalMinutes < upperBoundAfter;
640
+ return inBefore || inAfter;
565
641
  });
566
642
  };
643
+ var getShiftNameById = (shiftId, timezone, shiftConfig) => {
644
+ const { shifts } = normalizeShiftDefinitions(timezone, shiftConfig);
645
+ const shift = shifts.find((s) => s.shiftId === shiftId);
646
+ if (shift) {
647
+ return shift.shiftName;
648
+ }
649
+ if (shiftId === 0) return "Day Shift";
650
+ if (shiftId === 1) return "Night Shift";
651
+ return `Shift ${shiftId}`;
652
+ };
653
+ var getShortShiftName = (shiftId, timezone, shiftConfig) => {
654
+ const fullName = getShiftNameById(shiftId, timezone, shiftConfig);
655
+ return fullName.replace(/ Shift$/i, "");
656
+ };
567
657
 
568
658
  // src/lib/utils/database.ts
569
659
  var getCompanyMetricsTableName = (companyId, prefix = "workspace_performance") => {
@@ -1156,12 +1246,12 @@ var dashboardService = {
1156
1246
  throw err;
1157
1247
  }
1158
1248
  },
1159
- async getDetailedLineInfo(lineIdInput, dateProp, shiftProp) {
1249
+ async getDetailedLineInfo(lineIdInput, dateProp, shiftProp, providedShiftConfig) {
1160
1250
  const supabase = _getSupabaseInstance();
1161
1251
  const config = _getDashboardConfigInstance();
1162
1252
  const dbConfig = config.databaseConfig ?? DEFAULT_DATABASE_CONFIG;
1163
1253
  const entityConfig = config.entityConfig ?? DEFAULT_ENTITY_CONFIG;
1164
- const shiftConfig = config.shiftConfig ?? DEFAULT_SHIFT_CONFIG;
1254
+ const shiftConfig = providedShiftConfig || (config.shiftConfig ?? DEFAULT_SHIFT_CONFIG);
1165
1255
  const dateTimeConfig = config.dateTimeConfig ?? DEFAULT_DATE_TIME_CONFIG;
1166
1256
  const workspaceConfig = config.workspaceConfig ?? DEFAULT_WORKSPACE_CONFIG;
1167
1257
  const linesTable = getTable(dbConfig, "lines");
@@ -1248,8 +1338,8 @@ var dashboardService = {
1248
1338
  underperforming_workspaces: combinedMetricsData.underperforming_workspaces,
1249
1339
  line_threshold: combinedMetricsData.line_threshold,
1250
1340
  threshold_pph: combinedMetricsData.threshold_pph / numLines,
1251
- shift_start: metricsData?.[0]?.shift_start || shiftConfig.dayShift?.startTime || "06:00",
1252
- shift_end: metricsData?.[0]?.shift_end || shiftConfig.dayShift?.endTime || "18:00",
1341
+ 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",
1342
+ 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",
1253
1343
  last_updated: (/* @__PURE__ */ new Date()).toISOString(),
1254
1344
  output_array: combinedMetricsData.outputArrays.length > 0 ? memoizedOutputArrayAggregation(combinedMetricsData.outputArrays) : [],
1255
1345
  underperforming_workspace_names: combinedMetricsData.underperforming_workspace_names,
@@ -1290,8 +1380,8 @@ var dashboardService = {
1290
1380
  underperforming_workspaces: metrics2?.underperforming_workspaces ?? 0,
1291
1381
  line_threshold: metrics2?.line_threshold || 0,
1292
1382
  threshold_pph: metrics2?.threshold_pph || 0,
1293
- shift_start: metrics2?.shift_start || shiftConfig.dayShift?.startTime || "06:00",
1294
- shift_end: metrics2?.shift_end || shiftConfig.dayShift?.endTime || "18:00",
1383
+ 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",
1384
+ 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",
1295
1385
  last_updated: metrics2?.last_updated || (/* @__PURE__ */ new Date()).toISOString(),
1296
1386
  output_array: metrics2?.output_array || [],
1297
1387
  underperforming_workspace_names: metrics2?.underperforming_workspace_names || [],
@@ -1402,7 +1492,7 @@ var dashboardService = {
1402
1492
  throw err;
1403
1493
  }
1404
1494
  },
1405
- async getUnderperformingWorkspaces(lineIdInput, monthInput, yearInput) {
1495
+ async getUnderperformingWorkspaces(lineIdInput, monthInput, yearInput, shiftIds) {
1406
1496
  _getSupabaseInstance();
1407
1497
  const config = _getDashboardConfigInstance();
1408
1498
  const entityConfig = config.entityConfig ?? DEFAULT_ENTITY_CONFIG;
@@ -1422,13 +1512,14 @@ var dashboardService = {
1422
1512
  const currentDate = /* @__PURE__ */ new Date();
1423
1513
  const currentMonth = monthInput !== void 0 ? monthInput : currentDate.getMonth();
1424
1514
  const currentYear = yearInput !== void 0 ? yearInput : currentDate.getFullYear();
1515
+ const dynamicShiftIds = shiftIds || shiftConfig.shifts?.map((s) => s.shiftId) || [shiftConfig.dayShift?.id ?? 0, shiftConfig.nightShift?.id ?? 1];
1425
1516
  const bodyPayload = {
1426
1517
  lineId: lineIdInput === factoryViewId ? configuredLineIds : lineIdInput,
1427
1518
  month: currentMonth,
1428
1519
  year: currentYear,
1429
1520
  companyId,
1430
1521
  metricsTable,
1431
- shifts: [shiftConfig.dayShift?.id ?? 0, shiftConfig.nightShift?.id ?? 1]
1522
+ shifts: dynamicShiftIds
1432
1523
  };
1433
1524
  const response = await fetch(fullFunctionUrl, {
1434
1525
  method: "POST",
@@ -2135,16 +2226,13 @@ var WorkspaceHealthService = class _WorkspaceHealthService {
2135
2226
  this.cache.set(key, { data, timestamp: Date.now() });
2136
2227
  }
2137
2228
  getShiftTiming(timezone, shiftConfig) {
2138
- const { shiftId, date } = getCurrentShift(timezone, shiftConfig);
2139
- const dayShiftId = shiftConfig?.dayShift?.id ?? 0;
2140
- const isDayShift = shiftId === dayShiftId;
2229
+ const currentShift = getCurrentShift(timezone, shiftConfig);
2230
+ const { shiftId, date, shiftName, startTime, endTime } = currentShift;
2141
2231
  const defaultDayStart = "06:00";
2142
2232
  const defaultDayEnd = "18:00";
2143
- const defaultNightStart = "18:00";
2144
- const defaultNightEnd = "06:00";
2145
- const shiftStartStr = isDayShift ? shiftConfig?.dayShift?.startTime || defaultDayStart : shiftConfig?.nightShift?.startTime || defaultNightStart;
2146
- const shiftEndStr = isDayShift ? shiftConfig?.dayShift?.endTime || defaultDayEnd : shiftConfig?.nightShift?.endTime || defaultNightEnd;
2147
- const shiftLabel = isDayShift ? "Day Shift" : "Night Shift";
2233
+ const shiftStartStr = startTime || defaultDayStart;
2234
+ const shiftEndStr = endTime || defaultDayEnd;
2235
+ const shiftLabel = shiftName || (shiftId === 0 ? "Day Shift" : shiftId === 1 ? "Night Shift" : `Shift ${shiftId}`);
2148
2236
  const parseTime = (value) => {
2149
2237
  const [hourPart = "0", minutePart = "0"] = value.split(":");
2150
2238
  const hour = Number.parseInt(hourPart, 10);
@@ -2219,6 +2307,13 @@ var WorkspaceHealthService = class _WorkspaceHealthService {
2219
2307
  async getWorkspaceHealthStatus(options = {}) {
2220
2308
  const supabase = _getSupabaseInstance();
2221
2309
  if (!supabase) throw new Error("Supabase client not initialized");
2310
+ const dashboardConfig = _getDashboardConfigInstance();
2311
+ if (!options.shiftConfig) {
2312
+ console.warn("[workspaceHealthService.getWorkspaceHealthStatus] \u26A0\uFE0F No shiftConfig passed! Falling back to static config. This may cause incorrect shift_id queries.");
2313
+ }
2314
+ const shiftConfig = options.shiftConfig || dashboardConfig?.shiftConfig;
2315
+ const defaultTimezone = dashboardConfig?.dateTimeConfig?.defaultTimezone || "UTC";
2316
+ const timezone = options.timezone || shiftConfig?.timezone || defaultTimezone;
2222
2317
  let query = supabase.from("workspace_health_status").select("*").order("workspace_display_name", { ascending: true });
2223
2318
  if (options.lineId) {
2224
2319
  query = query.eq("line_id", options.lineId);
@@ -2236,7 +2331,7 @@ var WorkspaceHealthService = class _WorkspaceHealthService {
2236
2331
  let uptimeMap = /* @__PURE__ */ new Map();
2237
2332
  if (companyId) {
2238
2333
  try {
2239
- uptimeMap = await this.calculateWorkspaceUptime(companyId);
2334
+ uptimeMap = await this.calculateWorkspaceUptime(companyId, shiftConfig, timezone);
2240
2335
  } catch (error2) {
2241
2336
  console.error("Error calculating uptime:", error2);
2242
2337
  }
@@ -2314,7 +2409,7 @@ var WorkspaceHealthService = class _WorkspaceHealthService {
2314
2409
  }
2315
2410
  return filteredData;
2316
2411
  }
2317
- async getWorkspaceUptimeTimeline(workspaceId, companyId) {
2412
+ async getWorkspaceUptimeTimeline(workspaceId, companyId, passedShiftConfig, passedTimezone) {
2318
2413
  if (!workspaceId) {
2319
2414
  throw new Error("workspaceId is required to fetch uptime timeline");
2320
2415
  }
@@ -2324,8 +2419,12 @@ var WorkspaceHealthService = class _WorkspaceHealthService {
2324
2419
  const supabase = _getSupabaseInstance();
2325
2420
  if (!supabase) throw new Error("Supabase client not initialized");
2326
2421
  const dashboardConfig = _getDashboardConfigInstance();
2327
- const timezone = dashboardConfig?.dateTimeConfig?.defaultTimezone || "UTC";
2328
- const shiftConfig = dashboardConfig?.shiftConfig;
2422
+ const defaultTimezone = dashboardConfig?.dateTimeConfig?.defaultTimezone || "UTC";
2423
+ if (!passedShiftConfig) {
2424
+ console.warn("[workspaceHealthService.getWorkspaceUptimeTimeline] \u26A0\uFE0F No shiftConfig passed! Falling back to static config. This may cause incorrect shift_id queries.");
2425
+ }
2426
+ const shiftConfig = passedShiftConfig || dashboardConfig?.shiftConfig;
2427
+ const timezone = passedTimezone || shiftConfig?.timezone || defaultTimezone;
2329
2428
  const {
2330
2429
  shiftId,
2331
2430
  shiftLabel,
@@ -2566,18 +2665,22 @@ var WorkspaceHealthService = class _WorkspaceHealthService {
2566
2665
  clearCache() {
2567
2666
  this.cache.clear();
2568
2667
  }
2569
- async calculateWorkspaceUptime(companyId) {
2668
+ async calculateWorkspaceUptime(companyId, passedShiftConfig, timezone) {
2570
2669
  const supabase = _getSupabaseInstance();
2571
2670
  if (!supabase) throw new Error("Supabase client not initialized");
2572
2671
  const dashboardConfig = _getDashboardConfigInstance();
2573
- const timezone = dashboardConfig?.dateTimeConfig?.defaultTimezone || "UTC";
2574
- const shiftConfig = dashboardConfig?.shiftConfig;
2672
+ const defaultTimezone = dashboardConfig?.dateTimeConfig?.defaultTimezone || "UTC";
2673
+ if (!passedShiftConfig) {
2674
+ console.warn("[workspaceHealthService.calculateWorkspaceUptime] \u26A0\uFE0F No shiftConfig passed! Falling back to static config. This may cause incorrect shift_id queries.");
2675
+ }
2676
+ const shiftConfig = passedShiftConfig || dashboardConfig?.shiftConfig;
2677
+ const effectiveTimezone = timezone || shiftConfig?.timezone || defaultTimezone;
2575
2678
  const {
2576
2679
  shiftId,
2577
2680
  date,
2578
2681
  shiftStartDate,
2579
2682
  completedMinutes
2580
- } = this.getShiftTiming(timezone, shiftConfig);
2683
+ } = this.getShiftTiming(effectiveTimezone, shiftConfig);
2581
2684
  const tableName = `performance_metrics_${companyId.replace(/-/g, "_")}`;
2582
2685
  try {
2583
2686
  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);
@@ -2600,7 +2703,7 @@ var WorkspaceHealthService = class _WorkspaceHealthService {
2600
2703
  minuteDate,
2601
2704
  outputHourly,
2602
2705
  outputArray,
2603
- timezone
2706
+ effectiveTimezone
2604
2707
  );
2605
2708
  if (status === "down") {
2606
2709
  currentDownRun += 1;
@@ -4271,7 +4374,7 @@ var useAudioService = () => {
4271
4374
  // src/lib/utils/dateShiftUtils.ts
4272
4375
  function isValidShiftId(shiftId) {
4273
4376
  const id3 = typeof shiftId === "string" ? parseInt(shiftId, 10) : shiftId;
4274
- return id3 === 0 || id3 === 1;
4377
+ return Number.isFinite(id3) && id3 >= 0;
4275
4378
  }
4276
4379
  var getSupabaseClient = () => {
4277
4380
  const url = process.env.NEXT_PUBLIC_SUPABASE_URL;
@@ -6803,11 +6906,12 @@ var useMetrics = (tableName, options) => {
6803
6906
  };
6804
6907
  return { data, isLoading, error, refetch };
6805
6908
  };
6806
- var useWorkspaceDetailedMetrics = (workspaceId, date, shiftId) => {
6909
+ var useWorkspaceDetailedMetrics = (workspaceId, date, shiftId, options) => {
6807
6910
  const entityConfig = useEntityConfig();
6808
6911
  const databaseConfig = useDatabaseConfig();
6809
6912
  const dateTimeConfig = useDateTimeConfig();
6810
- const shiftConfig = useShiftConfig();
6913
+ const staticShiftConfig = useShiftConfig();
6914
+ const shiftConfig = options?.shiftConfig || staticShiftConfig;
6811
6915
  const workspaceConfig = useWorkspaceConfig();
6812
6916
  const supabase = useSupabase();
6813
6917
  const [metrics2, setMetrics] = useState(null);
@@ -6820,11 +6924,12 @@ var useWorkspaceDetailedMetrics = (workspaceId, date, shiftId) => {
6820
6924
  const companyId = entityConfig.companyId || "";
6821
6925
  const metricsTablePrefix = getMetricsTablePrefix();
6822
6926
  const metricsTable = `${metricsTablePrefix}_${companyId.replace(/-/g, "_")}`;
6823
- const defaultTimezone = dateTimeConfig.defaultTimezone;
6927
+ const appTimezone = useAppTimezone();
6928
+ const defaultTimezone = appTimezone || dateTimeConfig.defaultTimezone || "UTC";
6824
6929
  const workspaceMetricsBaseTable = databaseConfig.tables?.workspaces ?? "workspace_metrics";
6825
6930
  const workspaceActionsTable = databaseConfig.tables?.actions ?? "workspace_actions";
6826
6931
  const fetchMetrics = useCallback(async () => {
6827
- if (!workspaceId || isFetchingRef.current) return;
6932
+ if (!workspaceId || isFetchingRef.current || options?.enabled === false) return;
6828
6933
  try {
6829
6934
  isFetchingRef.current = true;
6830
6935
  const currentShift = getCurrentShift(defaultTimezone, shiftConfig);
@@ -6861,6 +6966,16 @@ var useWorkspaceDetailedMetrics = (workspaceId, date, shiftId) => {
6861
6966
  throw new Error(`Invalid JSON response from backend. Received: ${responseText.substring(0, 100)}...`);
6862
6967
  }
6863
6968
  const data = backendData.metrics;
6969
+ if (data && options?.shiftConfig) {
6970
+ const dynamicShiftName = getShiftNameById(
6971
+ data.shift_id,
6972
+ appTimezone || "Asia/Kolkata",
6973
+ // Fallback timezone
6974
+ options.shiftConfig
6975
+ );
6976
+ data.shift_type = dynamicShiftName;
6977
+ console.log(`[useWorkspaceDetailedMetrics] Overriding shift name for ID ${data.shift_id}: ${dynamicShiftName}`);
6978
+ }
6864
6979
  if (!data && !date && shiftId === void 0) {
6865
6980
  console.log("[useWorkspaceDetailedMetrics] No data found for current date/shift, attempting to find most recent data...");
6866
6981
  const fallbackResponse = await fetch(
@@ -7306,7 +7421,7 @@ var useWorkspaceDetailedMetrics = (workspaceId, date, shiftId) => {
7306
7421
  updateQueueRef.current = false;
7307
7422
  setIsLoading(false);
7308
7423
  }
7309
- }, [supabase, workspaceId, date, shiftId, metricsTable, defaultTimezone, shiftConfig, workspaceConfig, companyId]);
7424
+ }, [supabase, workspaceId, date, shiftId, metricsTable, defaultTimezone, shiftConfig, workspaceConfig, companyId, options?.enabled]);
7310
7425
  const queueUpdate = useCallback(() => {
7311
7426
  if (!workspaceId || updateQueueRef.current) return;
7312
7427
  updateQueueRef.current = true;
@@ -7339,7 +7454,7 @@ var useWorkspaceDetailedMetrics = (workspaceId, date, shiftId) => {
7339
7454
  return;
7340
7455
  }
7341
7456
  const channels = [];
7342
- const operationalDate = date || getOperationalDate(defaultTimezone || "UTC");
7457
+ const operationalDate = date || getOperationalDate(defaultTimezone);
7343
7458
  const currentShift = getCurrentShift(defaultTimezone, shiftConfig);
7344
7459
  const queryShiftId = shiftId ?? currentShift.shiftId;
7345
7460
  const metricsChannel = supabase.channel(`workspace-metrics-${workspaceId}`).on(
@@ -7438,11 +7553,170 @@ var useWorkspaceDetailedMetrics = (workspaceId, date, shiftId) => {
7438
7553
  // Force refresh without cache
7439
7554
  };
7440
7555
  };
7556
+ var useLineShiftConfig = (lineId, fallbackConfig) => {
7557
+ const [shiftConfig, setShiftConfig] = useState(fallbackConfig || null);
7558
+ const [isLoading, setIsLoading] = useState(true);
7559
+ const [error, setError] = useState(null);
7560
+ const supabase = useSupabase();
7561
+ useEffect(() => {
7562
+ if (!lineId || lineId === "factory" || lineId === "all") {
7563
+ setShiftConfig(fallbackConfig || null);
7564
+ setIsLoading(false);
7565
+ return;
7566
+ }
7567
+ const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
7568
+ if (!uuidRegex.test(lineId)) {
7569
+ console.warn(`[useShiftConfig] Invalid line ID format: ${lineId}, using fallback`);
7570
+ setShiftConfig(fallbackConfig || null);
7571
+ setIsLoading(false);
7572
+ return;
7573
+ }
7574
+ let mounted = true;
7575
+ const calculateBreakDuration2 = (startTime, endTime) => {
7576
+ const [sh, sm] = startTime.split(":").map(Number);
7577
+ const [eh, em] = endTime.split(":").map(Number);
7578
+ let startMinutes = sh * 60 + sm;
7579
+ let endMinutes = eh * 60 + em;
7580
+ if (endMinutes < startMinutes) {
7581
+ endMinutes += 24 * 60;
7582
+ }
7583
+ return endMinutes - startMinutes;
7584
+ };
7585
+ const fetchShiftConfig = async () => {
7586
+ try {
7587
+ setIsLoading(true);
7588
+ setError(null);
7589
+ console.log(`[useLineShiftConfig] \u{1F50D} Fetching shift config for line: ${lineId}`);
7590
+ 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);
7591
+ if (shiftsError) {
7592
+ console.error(`[useLineShiftConfig] \u274C Error fetching shifts:`, shiftsError);
7593
+ throw new Error(`Failed to fetch shift config: ${shiftsError.message}`);
7594
+ }
7595
+ if (!shiftsData || shiftsData.length === 0) {
7596
+ console.warn(`[useLineShiftConfig] \u26A0\uFE0F No shift config found for line ${lineId}, using fallback`);
7597
+ if (mounted) {
7598
+ setShiftConfig(fallbackConfig || null);
7599
+ setIsLoading(false);
7600
+ }
7601
+ return;
7602
+ }
7603
+ const stripSeconds = (timeStr) => {
7604
+ if (!timeStr) return timeStr;
7605
+ return timeStr.substring(0, 5);
7606
+ };
7607
+ const mapped = shiftsData.map((shift) => ({
7608
+ shiftId: shift.shift_id,
7609
+ shiftName: shift.shift_name || `Shift ${shift.shift_id}`,
7610
+ startTime: stripSeconds(shift.start_time),
7611
+ endTime: stripSeconds(shift.end_time),
7612
+ breaks: Array.isArray(shift.breaks) ? shift.breaks.map((b) => ({
7613
+ startTime: b.start || b.startTime || "00:00",
7614
+ endTime: b.end || b.endTime || "00:00",
7615
+ duration: calculateBreakDuration2(
7616
+ b.start || b.startTime || "00:00",
7617
+ b.end || b.endTime || "00:00"
7618
+ ),
7619
+ remarks: b.remarks || b.name || ""
7620
+ })) : [],
7621
+ timezone: shift.timezone
7622
+ }));
7623
+ const day = mapped.find((s) => s.shiftId === 0);
7624
+ const night = mapped.find((s) => s.shiftId === 1);
7625
+ const config = {
7626
+ shifts: mapped,
7627
+ timezone: mapped[0]?.timezone,
7628
+ dayShift: day ? { id: day.shiftId, startTime: day.startTime, endTime: day.endTime, name: day.shiftName } : fallbackConfig?.dayShift,
7629
+ nightShift: night ? { id: night.shiftId, startTime: night.startTime, endTime: night.endTime, name: night.shiftName } : fallbackConfig?.nightShift,
7630
+ transitionPeriodMinutes: fallbackConfig?.transitionPeriodMinutes || 0
7631
+ };
7632
+ console.log(`[useLineShiftConfig] \u2705 Built config from DB:`, config);
7633
+ if (mounted) {
7634
+ setShiftConfig(config);
7635
+ setIsLoading(false);
7636
+ }
7637
+ } catch (err) {
7638
+ console.error("[useShiftConfig] Error fetching shift config:", err);
7639
+ if (mounted) {
7640
+ setError(err instanceof Error ? err.message : "Unknown error occurred");
7641
+ setShiftConfig(fallbackConfig || null);
7642
+ setIsLoading(false);
7643
+ }
7644
+ }
7645
+ };
7646
+ fetchShiftConfig();
7647
+ const subscription = supabase.channel(`shift_config_${lineId}`).on(
7648
+ "postgres_changes",
7649
+ {
7650
+ event: "*",
7651
+ // Listen to all events (INSERT, UPDATE, DELETE)
7652
+ schema: "public",
7653
+ table: "line_operating_hours",
7654
+ filter: `line_id=eq.${lineId}`
7655
+ },
7656
+ (payload) => {
7657
+ console.log("[useShiftConfig] Real-time update received:", payload);
7658
+ fetchShiftConfig();
7659
+ }
7660
+ ).subscribe();
7661
+ return () => {
7662
+ mounted = false;
7663
+ subscription.unsubscribe();
7664
+ };
7665
+ }, [lineId, supabase]);
7666
+ return {
7667
+ shiftConfig,
7668
+ isLoading,
7669
+ error
7670
+ };
7671
+ };
7672
+
7673
+ // src/lib/hooks/useDynamicShiftConfig.ts
7674
+ var useDynamicShiftConfig = (lineId) => {
7675
+ const staticShiftConfig = useShiftConfig();
7676
+ const { shiftConfig: dbShiftConfig, isLoading, error } = useLineShiftConfig(lineId, staticShiftConfig);
7677
+ const result = useMemo(() => {
7678
+ console.log(`[useDynamicShiftConfig] \u{1F504} Computing result for lineId: ${lineId}`, {
7679
+ isLoading,
7680
+ hasDbConfig: !!dbShiftConfig,
7681
+ error
7682
+ });
7683
+ if (isLoading) {
7684
+ console.log(`[useDynamicShiftConfig] \u23F3 Still loading, returning null (DO NOT USE until loaded)`);
7685
+ return {
7686
+ shiftConfig: null,
7687
+ isLoading: true,
7688
+ error: null,
7689
+ isFromDatabase: false
7690
+ };
7691
+ }
7692
+ if (dbShiftConfig) {
7693
+ console.log(`[useDynamicShiftConfig] \u2705 Using DB config:`, dbShiftConfig);
7694
+ return {
7695
+ shiftConfig: dbShiftConfig,
7696
+ isLoading: false,
7697
+ error,
7698
+ isFromDatabase: true
7699
+ };
7700
+ }
7701
+ console.log(`[useDynamicShiftConfig] \u26A0\uFE0F No DB config found, falling back to static config`);
7702
+ return {
7703
+ shiftConfig: staticShiftConfig,
7704
+ isLoading: false,
7705
+ error,
7706
+ isFromDatabase: false
7707
+ };
7708
+ }, [dbShiftConfig, staticShiftConfig, isLoading, error, lineId]);
7709
+ return result;
7710
+ };
7711
+
7712
+ // src/lib/hooks/useLineWorkspaceMetrics.ts
7441
7713
  var useLineWorkspaceMetrics = (lineId, options) => {
7442
7714
  const entityConfig = useEntityConfig();
7443
7715
  const databaseConfig = useDatabaseConfig();
7444
7716
  const dateTimeConfig = useDateTimeConfig();
7445
- const shiftConfig = useShiftConfig();
7717
+ const staticShiftConfig = useShiftConfig();
7718
+ const { shiftConfig: dynamicShiftConfig, isLoading: isShiftConfigLoading } = useDynamicShiftConfig(lineId);
7719
+ const shiftConfig = dynamicShiftConfig || staticShiftConfig;
7446
7720
  const timezone = useAppTimezone();
7447
7721
  const supabase = useSupabase();
7448
7722
  const [workspaces, setWorkspaces] = useState([]);
@@ -7450,12 +7724,10 @@ var useLineWorkspaceMetrics = (lineId, options) => {
7450
7724
  const [error, setError] = useState(null);
7451
7725
  const [initialized, setInitialized] = useState(false);
7452
7726
  const queryShiftId = useMemo(() => {
7453
- const currentShift = getCurrentShift(
7454
- dateTimeConfig.defaultTimezone || "Asia/Kolkata",
7455
- shiftConfig
7456
- );
7727
+ const effectiveTimezone = timezone || dateTimeConfig.defaultTimezone || "Asia/Kolkata";
7728
+ const currentShift = getCurrentShift(effectiveTimezone, shiftConfig);
7457
7729
  return options?.initialShiftId !== void 0 ? options.initialShiftId : currentShift.shiftId;
7458
- }, [options?.initialShiftId, dateTimeConfig.defaultTimezone, shiftConfig]);
7730
+ }, [options?.initialShiftId, timezone, dateTimeConfig.defaultTimezone, shiftConfig]);
7459
7731
  const queryDate = useMemo(() => {
7460
7732
  return options?.initialDate || getOperationalDate(timezone || dateTimeConfig.defaultTimezone || "UTC");
7461
7733
  }, [options?.initialDate, timezone, dateTimeConfig.defaultTimezone]);
@@ -7467,7 +7739,7 @@ var useLineWorkspaceMetrics = (lineId, options) => {
7467
7739
  }, [entityConfig.companyId]);
7468
7740
  const schema = databaseConfig.schema ?? "public";
7469
7741
  const fetchWorkspaceMetrics = useCallback(async () => {
7470
- if (!lineId) return;
7742
+ if (!lineId || options?.enabled === false || isShiftConfigLoading) return;
7471
7743
  if (!initialized) {
7472
7744
  setLoading(true);
7473
7745
  }
@@ -7524,7 +7796,7 @@ var useLineWorkspaceMetrics = (lineId, options) => {
7524
7796
  } finally {
7525
7797
  setLoading(false);
7526
7798
  }
7527
- }, [lineId, queryDate, queryShiftId, metricsTable, supabase, entityConfig.companyId]);
7799
+ }, [lineId, queryDate, queryShiftId, metricsTable, supabase, entityConfig.companyId, options?.enabled, isShiftConfigLoading]);
7528
7800
  useEffect(() => {
7529
7801
  if (!initialized) {
7530
7802
  fetchWorkspaceMetrics();
@@ -7554,25 +7826,26 @@ var useLineWorkspaceMetrics = (lineId, options) => {
7554
7826
  supabase.removeChannel(channel);
7555
7827
  }
7556
7828
  };
7557
- }, [lineId, queryDate, queryShiftId, metricsTable, fetchWorkspaceMetrics, initialized, supabase, schema]);
7829
+ }, [lineId, queryDate, queryShiftId, metricsTable, fetchWorkspaceMetrics, initialized, supabase, schema, isShiftConfigLoading]);
7558
7830
  useEffect(() => {
7559
7831
  setInitialized(false);
7560
- }, [lineId, queryDate, queryShiftId]);
7832
+ }, [lineId, queryDate, queryShiftId, isShiftConfigLoading]);
7561
7833
  const refreshWorkspaces = fetchWorkspaceMetrics;
7562
7834
  return useMemo(
7563
7835
  () => ({ workspaces, loading, error, refreshWorkspaces }),
7564
7836
  [workspaces, loading, error, refreshWorkspaces]
7565
7837
  );
7566
7838
  };
7567
- var useHistoricWorkspaceMetrics = (workspaceId, date, shiftId) => {
7839
+ var useHistoricWorkspaceMetrics = (workspaceId, date, shiftId, options) => {
7568
7840
  const supabase = useSupabase();
7569
7841
  const entityConfig = useEntityConfig();
7842
+ const timezone = useAppTimezone();
7570
7843
  const [metrics2, setMetrics] = useState(null);
7571
7844
  const [isLoading, setIsLoading] = useState(true);
7572
7845
  const [error, setError] = useState(null);
7573
7846
  const isFetchingRef = useRef(false);
7574
7847
  const fetchMetrics = useCallback(async () => {
7575
- if (!supabase || !workspaceId || !date || isFetchingRef.current) return;
7848
+ if (!supabase || !workspaceId || !date || isFetchingRef.current || options?.enabled === false) return;
7576
7849
  try {
7577
7850
  isFetchingRef.current = true;
7578
7851
  setIsLoading(true);
@@ -7606,7 +7879,18 @@ var useHistoricWorkspaceMetrics = (workspaceId, date, shiftId) => {
7606
7879
  throw new Error(`Backend API error (${response.status}): ${errorText}`);
7607
7880
  }
7608
7881
  const data = await response.json();
7609
- setMetrics(data.metrics || null);
7882
+ const fetchedMetrics = data.metrics;
7883
+ if (fetchedMetrics && options?.shiftConfig) {
7884
+ const dynamicShiftName = getShiftNameById(
7885
+ fetchedMetrics.shift_id,
7886
+ timezone || "Asia/Kolkata",
7887
+ // Fallback timezone
7888
+ options.shiftConfig
7889
+ );
7890
+ fetchedMetrics.shift_type = dynamicShiftName;
7891
+ console.log(`[useHistoricWorkspaceMetrics] Overriding shift name for ID ${fetchedMetrics.shift_id}: ${dynamicShiftName}`);
7892
+ }
7893
+ setMetrics(fetchedMetrics || null);
7610
7894
  } catch (err) {
7611
7895
  console.error("[useHistoricWorkspaceMetrics] Error fetching historic metrics:", err);
7612
7896
  setError({ message: err.message, code: err.code || "FETCH_ERROR" });
@@ -7615,7 +7899,7 @@ var useHistoricWorkspaceMetrics = (workspaceId, date, shiftId) => {
7615
7899
  setIsLoading(false);
7616
7900
  isFetchingRef.current = false;
7617
7901
  }
7618
- }, [supabase, workspaceId, date, shiftId, entityConfig.companyId]);
7902
+ }, [supabase, workspaceId, date, shiftId, entityConfig.companyId, options?.shiftConfig, timezone, options?.enabled]);
7619
7903
  useEffect(() => {
7620
7904
  fetchMetrics();
7621
7905
  }, [fetchMetrics]);
@@ -7630,8 +7914,11 @@ var useLineDetailedMetrics = (lineIdFromProp) => {
7630
7914
  const entityConfig = useEntityConfig();
7631
7915
  const databaseConfig = useDatabaseConfig();
7632
7916
  const dateTimeConfig = useDateTimeConfig();
7633
- const shiftConfig = useShiftConfig();
7917
+ const staticShiftConfig = useShiftConfig();
7634
7918
  const supabase = useSupabase();
7919
+ const lineIdForShiftConfig = lineIdFromProp === "factory" ? getConfiguredLineIds(entityConfig)[0] : lineIdFromProp;
7920
+ const { shiftConfig: dynamicShiftConfig, isLoading: isShiftConfigLoading } = useDynamicShiftConfig(lineIdForShiftConfig);
7921
+ const shiftConfig = dynamicShiftConfig || staticShiftConfig;
7635
7922
  const [lineData, setLineData] = useState(null);
7636
7923
  const [loading, setLoading] = useState(true);
7637
7924
  const [error, setError] = useState(null);
@@ -7670,8 +7957,10 @@ var useLineDetailedMetrics = (lineIdFromProp) => {
7670
7957
  }
7671
7958
  }, [dashboardService, lineIdToUse, defaultTimezone, shiftConfig, entityConfig]);
7672
7959
  useEffect(() => {
7673
- if (!supabase || !lineIdToUse || !entityConfig.companyId) {
7674
- setLoading(false);
7960
+ if (!supabase || !lineIdToUse || !entityConfig.companyId || isShiftConfigLoading) {
7961
+ if (!isShiftConfigLoading) {
7962
+ setLoading(false);
7963
+ }
7675
7964
  if (!entityConfig.companyId && (!error || error.code !== "SERVICE_ERROR")) {
7676
7965
  setError({ message: "Company ID not configured for metrics subscription.", code: "CONFIG_ERROR" });
7677
7966
  }
@@ -7736,7 +8025,7 @@ var useLineDetailedMetrics = (lineIdFromProp) => {
7736
8025
  channelRef.current = null;
7737
8026
  }
7738
8027
  };
7739
- }, [supabase, lineIdToUse, fetchData, schema, lineMetricsTable, entityConfig, defaultTimezone, shiftConfig, error]);
8028
+ }, [supabase, lineIdToUse, fetchData, schema, lineMetricsTable, entityConfig, defaultTimezone, shiftConfig, isShiftConfigLoading, error]);
7740
8029
  return {
7741
8030
  lineData,
7742
8031
  // This now contains both metrics and line details via LineInfo type
@@ -7749,14 +8038,20 @@ var useLeaderboardMetrics = (date, shiftId, limit = 10, filter2 = "all") => {
7749
8038
  const supabase = useSupabase();
7750
8039
  const entityConfig = useEntityConfig();
7751
8040
  const dateTimeConfig = useDateTimeConfig();
7752
- const shiftConfig = useShiftConfig();
8041
+ const staticShiftConfig = useShiftConfig();
8042
+ const firstLineId = useMemo(() => {
8043
+ const lineIds = getConfiguredLineIds(entityConfig);
8044
+ return lineIds[0];
8045
+ }, [entityConfig]);
8046
+ const { shiftConfig: dynamicShiftConfig, isLoading: isShiftConfigLoading } = useDynamicShiftConfig(firstLineId);
8047
+ const shiftConfig = dynamicShiftConfig || staticShiftConfig;
7753
8048
  const [leaderboard, setLeaderboard] = useState([]);
7754
8049
  const [isLoading, setIsLoading] = useState(true);
7755
8050
  const [error, setError] = useState(null);
7756
8051
  const isFetchingRef = useRef(false);
7757
8052
  const defaultTimezone = dateTimeConfig.defaultTimezone || "UTC";
7758
8053
  const fetchLeaderboard = useCallback(async () => {
7759
- if (!supabase || isFetchingRef.current) return;
8054
+ if (!supabase || isFetchingRef.current || isShiftConfigLoading) return;
7760
8055
  try {
7761
8056
  isFetchingRef.current = true;
7762
8057
  setIsLoading(true);
@@ -7802,7 +8097,7 @@ var useLeaderboardMetrics = (date, shiftId, limit = 10, filter2 = "all") => {
7802
8097
  setIsLoading(false);
7803
8098
  isFetchingRef.current = false;
7804
8099
  }
7805
- }, [supabase, date, shiftId, limit, filter2, entityConfig.companyId, defaultTimezone, shiftConfig]);
8100
+ }, [supabase, date, shiftId, limit, filter2, entityConfig.companyId, defaultTimezone, shiftConfig, isShiftConfigLoading]);
7806
8101
  useEffect(() => {
7807
8102
  fetchLeaderboard();
7808
8103
  }, [fetchLeaderboard]);
@@ -7818,8 +8113,22 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId, userAccessibleLineIds
7818
8113
  const entityConfig = useEntityConfig();
7819
8114
  const databaseConfig = useDatabaseConfig();
7820
8115
  const dateTimeConfig = useDateTimeConfig();
7821
- const shiftConfig = useShiftConfig();
7822
- const defaultTimezone = dateTimeConfig?.defaultTimezone || "UTC";
8116
+ const isFactoryView = lineId === (entityConfig.factoryViewId || "factory");
8117
+ const firstLineId = useMemo(() => {
8118
+ const configuredLineIds = getConfiguredLineIds(entityConfig);
8119
+ return configuredLineIds.length > 0 ? configuredLineIds[0] : void 0;
8120
+ }, [entityConfig]);
8121
+ const lineIdForShiftConfig = isFactoryView ? firstLineId : lineId;
8122
+ const { shiftConfig, isLoading: shiftLoading, isFromDatabase } = useDynamicShiftConfig(lineIdForShiftConfig);
8123
+ console.log(`[useDashboardMetrics] \u{1F3AF} Shift config for line ${lineId}:`, {
8124
+ isFactoryView,
8125
+ lineIdForShiftConfig,
8126
+ firstLineId,
8127
+ isFromDatabase,
8128
+ shiftConfig: shiftConfig ? { shifts: shiftConfig.shifts?.length, timezone: shiftConfig.timezone } : null
8129
+ });
8130
+ const appTimezone = useAppTimezone();
8131
+ const defaultTimezone = appTimezone || dateTimeConfig?.defaultTimezone || "UTC";
7823
8132
  const configuredLineMetricsTable = databaseConfig?.tables?.lineMetrics ?? "line_metrics";
7824
8133
  const schema = databaseConfig?.schema ?? "public";
7825
8134
  const supabase = useSupabase();
@@ -7845,8 +8154,8 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId, userAccessibleLineIds
7845
8154
  const fetchAllMetrics = useCallback(async () => {
7846
8155
  const currentLineIdToUse = lineIdRef.current;
7847
8156
  console.log("[useDashboardMetrics] Fetching from backend API. lineId:", currentLineIdToUse);
7848
- if (!currentLineIdToUse || !supabase || isFetchingRef.current || companySpecificMetricsTable.includes("unknown_company")) {
7849
- if (!metrics2?.workspaceMetrics?.length && !metrics2?.lineMetrics?.length) setIsLoading(false);
8157
+ if (!currentLineIdToUse || !supabase || isFetchingRef.current || shiftLoading || companySpecificMetricsTable.includes("unknown_company")) {
8158
+ if (!metrics2?.workspaceMetrics?.length && !metrics2?.lineMetrics?.length && !shiftLoading) setIsLoading(false);
7850
8159
  if (companySpecificMetricsTable.includes("unknown_company") && !error) {
7851
8160
  setError({ message: "Company ID not configured for metrics table.", code: "CONFIG_ERROR" });
7852
8161
  }
@@ -7865,7 +8174,7 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId, userAccessibleLineIds
7865
8174
  if (targetLineIds.length === 0) {
7866
8175
  throw new Error("No target line IDs available for fetching metrics.");
7867
8176
  }
7868
- const isFactoryView = currentLineIdToUse === (entityConfig.factoryViewId || "factory");
8177
+ const isFactoryView2 = currentLineIdToUse === (entityConfig.factoryViewId || "factory");
7869
8178
  const { data: { session } } = await supabase.auth.getSession();
7870
8179
  console.log("[useDashboardMetrics] Session check:", {
7871
8180
  hasSession: !!session,
@@ -7879,7 +8188,7 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId, userAccessibleLineIds
7879
8188
  if (!apiUrl) {
7880
8189
  throw new Error("Backend URL is not configured. Please set NEXT_PUBLIC_BACKEND_URL in your environment.");
7881
8190
  }
7882
- const lineIdsParam = isFactoryView ? `line_ids=${targetLineIds.join(",")}` : `line_id=${targetLineIds[0]}`;
8191
+ const lineIdsParam = isFactoryView2 ? `line_ids=${targetLineIds.join(",")}` : `line_id=${targetLineIds[0]}`;
7883
8192
  const url = `${apiUrl}/api/dashboard/metrics?${lineIdsParam}&date=${operationalDate}&shift_id=${currentShiftDetails.shiftId}&company_id=${entityConfig.companyId}`;
7884
8193
  console.log("[useDashboardMetrics] Calling backend API:", {
7885
8194
  url,
@@ -7958,8 +8267,10 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId, userAccessibleLineIds
7958
8267
  metrics2?.lineMetrics?.length || 0,
7959
8268
  companySpecificMetricsTable,
7960
8269
  entityConfig,
8270
+ appTimezone,
7961
8271
  defaultTimezone,
7962
- shiftConfig
8272
+ shiftConfig,
8273
+ shiftLoading
7963
8274
  ]);
7964
8275
  const fetchAllMetricsRef = useRef(fetchAllMetrics);
7965
8276
  useEffect(() => {
@@ -7973,10 +8284,10 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId, userAccessibleLineIds
7973
8284
  fetchAllMetricsRef.current();
7974
8285
  }, [supabase]);
7975
8286
  useEffect(() => {
7976
- if (lineId && supabase) {
8287
+ if (lineId && supabase && !shiftLoading) {
7977
8288
  fetchAllMetrics();
7978
8289
  }
7979
- }, [lineId, supabase, fetchAllMetrics]);
8290
+ }, [lineId, supabase, fetchAllMetrics, shiftLoading]);
7980
8291
  useEffect(() => {
7981
8292
  const currentLineIdToUse = lineIdRef.current;
7982
8293
  if (!currentLineIdToUse || !supabase || companySpecificMetricsTable.includes("unknown_company") || !entityConfig.companyId) {
@@ -8021,7 +8332,9 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId, userAccessibleLineIds
8021
8332
  schema,
8022
8333
  entityConfig?.companyId,
8023
8334
  entityConfig?.factoryViewId,
8335
+ appTimezone,
8024
8336
  defaultTimezone,
8337
+ shiftConfig,
8025
8338
  lineId,
8026
8339
  userAccessibleLineIds
8027
8340
  ]);
@@ -8033,145 +8346,7 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId, userAccessibleLineIds
8033
8346
  refetch: fetchAllMetrics
8034
8347
  };
8035
8348
  };
8036
- var useLineShiftConfig = (lineId, fallbackConfig) => {
8037
- const [shiftConfig, setShiftConfig] = useState(fallbackConfig || null);
8038
- const [isLoading, setIsLoading] = useState(true);
8039
- const [error, setError] = useState(null);
8040
- const supabase = useSupabase();
8041
- useEffect(() => {
8042
- if (!lineId || lineId === "factory" || lineId === "all") {
8043
- setShiftConfig(fallbackConfig || null);
8044
- setIsLoading(false);
8045
- return;
8046
- }
8047
- const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
8048
- if (!uuidRegex.test(lineId)) {
8049
- console.warn(`[useShiftConfig] Invalid line ID format: ${lineId}, using fallback`);
8050
- setShiftConfig(fallbackConfig || null);
8051
- setIsLoading(false);
8052
- return;
8053
- }
8054
- let mounted = true;
8055
- const fetchShiftConfig = async () => {
8056
- try {
8057
- setIsLoading(true);
8058
- setError(null);
8059
- console.log(`[useLineShiftConfig] \u{1F50D} Fetching shift config for line: ${lineId}`);
8060
- 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();
8061
- 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();
8062
- console.log(`[useLineShiftConfig] \u{1F4CA} Day shift data:`, dayShift);
8063
- console.log(`[useLineShiftConfig] \u{1F319} Night shift data:`, nightShift);
8064
- if (dayError || nightError) {
8065
- console.error(`[useLineShiftConfig] \u274C Error fetching:`, { dayError, nightError });
8066
- throw new Error(`Failed to fetch shift config: ${dayError?.message || nightError?.message}`);
8067
- }
8068
- if (!dayShift && !nightShift) {
8069
- console.warn(`[useLineShiftConfig] \u26A0\uFE0F No shift config found for line ${lineId}, using fallback`);
8070
- if (mounted) {
8071
- setShiftConfig(fallbackConfig || null);
8072
- setIsLoading(false);
8073
- }
8074
- return;
8075
- }
8076
- const stripSeconds = (timeStr) => {
8077
- if (!timeStr) return timeStr;
8078
- return timeStr.substring(0, 5);
8079
- };
8080
- const config = {
8081
- dayShift: dayShift ? {
8082
- id: 0,
8083
- startTime: stripSeconds(dayShift.start_time),
8084
- endTime: stripSeconds(dayShift.end_time)
8085
- } : fallbackConfig?.dayShift || { id: 0, startTime: "06:00", endTime: "18:00" },
8086
- nightShift: nightShift ? {
8087
- id: 1,
8088
- startTime: stripSeconds(nightShift.start_time),
8089
- endTime: stripSeconds(nightShift.end_time)
8090
- } : fallbackConfig?.nightShift || { id: 1, startTime: "18:00", endTime: "06:00" },
8091
- transitionPeriodMinutes: fallbackConfig?.transitionPeriodMinutes || 0
8092
- };
8093
- console.log(`[useLineShiftConfig] \u2705 Built config from DB:`, config);
8094
- if (mounted) {
8095
- setShiftConfig(config);
8096
- setIsLoading(false);
8097
- }
8098
- } catch (err) {
8099
- console.error("[useShiftConfig] Error fetching shift config:", err);
8100
- if (mounted) {
8101
- setError(err instanceof Error ? err.message : "Unknown error occurred");
8102
- setShiftConfig(fallbackConfig || null);
8103
- setIsLoading(false);
8104
- }
8105
- }
8106
- };
8107
- fetchShiftConfig();
8108
- const subscription = supabase.channel(`shift_config_${lineId}`).on(
8109
- "postgres_changes",
8110
- {
8111
- event: "*",
8112
- // Listen to all events (INSERT, UPDATE, DELETE)
8113
- schema: "public",
8114
- table: "line_operating_hours",
8115
- filter: `line_id=eq.${lineId}`
8116
- },
8117
- (payload) => {
8118
- console.log("[useShiftConfig] Real-time update received:", payload);
8119
- fetchShiftConfig();
8120
- }
8121
- ).subscribe();
8122
- return () => {
8123
- mounted = false;
8124
- subscription.unsubscribe();
8125
- };
8126
- }, [lineId, supabase]);
8127
- return {
8128
- shiftConfig,
8129
- isLoading,
8130
- error
8131
- };
8132
- };
8133
-
8134
- // src/lib/hooks/useDynamicShiftConfig.ts
8135
- var useDynamicShiftConfig = (lineId) => {
8136
- const staticShiftConfig = useShiftConfig();
8137
- const { shiftConfig: dbShiftConfig, isLoading, error } = useLineShiftConfig(lineId, staticShiftConfig);
8138
- const result = useMemo(() => {
8139
- console.log(`[useDynamicShiftConfig] \u{1F504} Computing result for lineId: ${lineId}`, {
8140
- isLoading,
8141
- hasDbConfig: !!dbShiftConfig,
8142
- error
8143
- });
8144
- if (isLoading) {
8145
- console.log(`[useDynamicShiftConfig] \u23F3 Still loading, using static config temporarily`);
8146
- return {
8147
- shiftConfig: staticShiftConfig,
8148
- isLoading: true,
8149
- error: null,
8150
- isFromDatabase: false
8151
- };
8152
- }
8153
- if (dbShiftConfig) {
8154
- console.log(`[useDynamicShiftConfig] \u2705 Using DB config:`, dbShiftConfig);
8155
- return {
8156
- shiftConfig: dbShiftConfig,
8157
- isLoading: false,
8158
- error,
8159
- isFromDatabase: true
8160
- };
8161
- }
8162
- console.log(`[useDynamicShiftConfig] \u26A0\uFE0F Falling back to static config`);
8163
- return {
8164
- shiftConfig: staticShiftConfig,
8165
- isLoading: false,
8166
- error,
8167
- isFromDatabase: false
8168
- };
8169
- }, [dbShiftConfig, staticShiftConfig, isLoading, error, lineId]);
8170
- return result;
8171
- };
8172
-
8173
- // src/lib/hooks/useLineKPIs.ts
8174
- var useLineKPIs = ({ lineId }) => {
8349
+ var useLineKPIs = ({ lineId, enabled }) => {
8175
8350
  useDashboardConfig();
8176
8351
  const entityConfig = useEntityConfig();
8177
8352
  const isFactoryView = lineId === (entityConfig.factoryViewId || "factory");
@@ -8183,7 +8358,7 @@ var useLineKPIs = ({ lineId }) => {
8183
8358
  return configuredLineIds.length > 0 ? configuredLineIds[0] : void 0;
8184
8359
  }, [entityConfig]);
8185
8360
  const lineIdForShiftConfig = isFactoryView ? firstLineId : lineId;
8186
- const { shiftConfig: dynamicShiftConfig, isFromDatabase } = useDynamicShiftConfig(lineIdForShiftConfig);
8361
+ const { shiftConfig: dynamicShiftConfig, isFromDatabase, isLoading: isShiftConfigLoading } = useDynamicShiftConfig(lineIdForShiftConfig);
8187
8362
  const shiftConfig = dynamicShiftConfig;
8188
8363
  console.log(`[useLineKPIs] \u{1F3AF} Shift config for line ${lineId}:`, {
8189
8364
  isFactoryView,
@@ -8204,7 +8379,8 @@ var useLineKPIs = ({ lineId }) => {
8204
8379
  const updateQueueRef = useRef(false);
8205
8380
  const updateTimeoutRef = useRef(null);
8206
8381
  const queueUpdateRef = useRef(void 0);
8207
- const defaultTimezone = dateTimeConfig.defaultTimezone;
8382
+ const appTimezone = useAppTimezone();
8383
+ const timezone = appTimezone || dateTimeConfig.defaultTimezone || "UTC";
8208
8384
  const schema = databaseConfig.schema ?? "public";
8209
8385
  const lineMetricsTable = databaseConfig.tables?.lineMetrics ?? "line_metrics";
8210
8386
  const companySpecificMetricsTable = useMemo(
@@ -8216,14 +8392,14 @@ var useLineKPIs = ({ lineId }) => {
8216
8392
  }, [lineId]);
8217
8393
  const fetchKPIs = useCallback(async () => {
8218
8394
  const currentLineId = lineIdRef.current;
8219
- if (!currentLineId || isFetchingRef.current) {
8395
+ if (!currentLineId || isFetchingRef.current || enabled === false || isShiftConfigLoading) {
8220
8396
  return;
8221
8397
  }
8222
8398
  isFetchingRef.current = true;
8223
8399
  setIsLoading(true);
8224
8400
  setError(null);
8225
8401
  try {
8226
- const currentShiftDetails = getCurrentShift(defaultTimezone, shiftConfig);
8402
+ const currentShiftDetails = getCurrentShift(timezone, shiftConfig ?? void 0);
8227
8403
  const operationalDate = currentShiftDetails.date;
8228
8404
  const { data: { session } } = await supabase.auth.getSession();
8229
8405
  if (!session?.access_token) {
@@ -8272,7 +8448,7 @@ var useLineKPIs = ({ lineId }) => {
8272
8448
  isFetchingRef.current = false;
8273
8449
  updateQueueRef.current = false;
8274
8450
  }
8275
- }, [defaultTimezone, shiftConfig, entityConfig, supabase]);
8451
+ }, [timezone, shiftConfig, entityConfig, supabase, enabled, isShiftConfigLoading]);
8276
8452
  const queueUpdate = useCallback(() => {
8277
8453
  if (updateTimeoutRef.current) {
8278
8454
  clearTimeout(updateTimeoutRef.current);
@@ -8292,7 +8468,7 @@ var useLineKPIs = ({ lineId }) => {
8292
8468
  return;
8293
8469
  }
8294
8470
  fetchKPIs();
8295
- const currentShiftDetails = getCurrentShift(defaultTimezone);
8471
+ const currentShiftDetails = getCurrentShift(timezone, shiftConfig ?? void 0);
8296
8472
  const operationalDate = currentShiftDetails.date;
8297
8473
  const factoryViewIdentifier = entityConfig.factoryViewId || "factory";
8298
8474
  const targetLineIds = currentLineId === factoryViewIdentifier ? getConfiguredLineIds(entityConfig) : [currentLineId];
@@ -8345,7 +8521,7 @@ var useLineKPIs = ({ lineId }) => {
8345
8521
  clearTimeout(updateTimeoutRef.current);
8346
8522
  }
8347
8523
  };
8348
- }, [lineId, supabase, entityConfig, schema, lineMetricsTable, companySpecificMetricsTable, defaultTimezone, shiftConfig]);
8524
+ }, [lineId, supabase, entityConfig, schema, lineMetricsTable, companySpecificMetricsTable, timezone, shiftConfig, isShiftConfigLoading]);
8349
8525
  return {
8350
8526
  kpis,
8351
8527
  isLoading,
@@ -8357,15 +8533,17 @@ var useRealtimeLineMetrics = ({
8357
8533
  lineId,
8358
8534
  date: urlDate,
8359
8535
  shiftId: urlShiftId,
8360
- onMetricsUpdate
8536
+ onMetricsUpdate,
8537
+ enabled
8361
8538
  }) => {
8362
8539
  const supabase = useSupabase();
8363
8540
  const entityConfig = useEntityConfig();
8364
8541
  useDatabaseConfig();
8365
8542
  const dateTimeConfig = useDateTimeConfig();
8366
- useShiftConfig();
8367
- const { shiftConfig: dynamicShiftConfig } = useDynamicShiftConfig(lineId);
8368
- const shiftConfig = dynamicShiftConfig;
8543
+ const staticShiftConfig = useShiftConfig();
8544
+ const timezone = useAppTimezone();
8545
+ const { shiftConfig: dynamicShiftConfig, isLoading: isShiftConfigLoading } = useDynamicShiftConfig(lineId);
8546
+ const shiftConfig = dynamicShiftConfig || staticShiftConfig;
8369
8547
  const [metrics2, setMetrics] = useState(null);
8370
8548
  const [lineDetails, setLineDetails] = useState(null);
8371
8549
  const [loading, setLoading] = useState(true);
@@ -8376,16 +8554,16 @@ var useRealtimeLineMetrics = ({
8376
8554
  const isFetchingRef = useRef(false);
8377
8555
  const channelsRef = useRef([]);
8378
8556
  const fetchTimeoutRef = useRef(null);
8379
- const currentShift = useMemo(() => getCurrentShift(dateTimeConfig.defaultTimezone || "Asia/Kolkata", shiftConfig), [dateTimeConfig.defaultTimezone, shiftConfig]);
8557
+ const effectiveTimezone = timezone || dateTimeConfig.defaultTimezone || "Asia/Kolkata";
8558
+ const currentShift = useMemo(() => getCurrentShift(effectiveTimezone, shiftConfig), [effectiveTimezone, shiftConfig]);
8380
8559
  const shiftId = useMemo(
8381
8560
  () => urlShiftId !== void 0 ? urlShiftId : currentShift.shiftId,
8382
8561
  [urlShiftId, currentShift.shiftId]
8383
8562
  );
8384
- const timezone = useAppTimezone();
8385
- const date = useMemo(() => urlDate || getOperationalDate(timezone || dateTimeConfig.defaultTimezone || "UTC"), [urlDate, timezone, dateTimeConfig.defaultTimezone]);
8563
+ const date = useMemo(() => urlDate || getOperationalDate(effectiveTimezone), [urlDate, effectiveTimezone]);
8386
8564
  const fetchData = useCallback(async () => {
8387
8565
  try {
8388
- if (!lineIdRef.current || isFetchingRef.current) return;
8566
+ if (!lineIdRef.current || isFetchingRef.current || enabled === false) return;
8389
8567
  isFetchingRef.current = true;
8390
8568
  if (!initialized) {
8391
8569
  setLoading(true);
@@ -8583,7 +8761,7 @@ var useRealtimeLineMetrics = ({
8583
8761
  updateQueueRef.current = false;
8584
8762
  isFetchingRef.current = false;
8585
8763
  }
8586
- }, [supabase, date, shiftId, urlShiftId, onMetricsUpdate, entityConfig, dateTimeConfig.defaultTimezone]);
8764
+ }, [supabase, date, shiftId, urlShiftId, onMetricsUpdate, entityConfig, dateTimeConfig.defaultTimezone, enabled, shiftConfig]);
8587
8765
  const queueUpdate = useCallback(() => {
8588
8766
  console.log("[useRealtimeLineMetrics] Update queued, debouncing...");
8589
8767
  if (fetchTimeoutRef.current) {
@@ -8665,13 +8843,27 @@ var useRealtimeLineMetrics = ({
8665
8843
  });
8666
8844
  channelsRef.current = [lineMetricsChannel, metricsChannel];
8667
8845
  }, [supabase, queueUpdate, urlDate, shiftId, entityConfig, dateTimeConfig.defaultTimezone]);
8846
+ const prevShiftIdRef = useRef(void 0);
8668
8847
  useEffect(() => {
8669
8848
  if (!lineId) return;
8670
8849
  lineIdRef.current = lineId;
8671
- if (!initialized) {
8850
+ const shouldFetch = !initialized && (!isShiftConfigLoading || enabled === false);
8851
+ const shiftIdChanged = prevShiftIdRef.current !== void 0 && prevShiftIdRef.current !== shiftId && !isShiftConfigLoading;
8852
+ if (shouldFetch || shiftIdChanged) {
8853
+ console.log("[useRealtimeLineMetrics] Fetching data:", {
8854
+ initialized,
8855
+ isShiftConfigLoading,
8856
+ enabled,
8857
+ shiftIdChanged,
8858
+ prevShiftId: prevShiftIdRef.current,
8859
+ currentShiftId: shiftId
8860
+ });
8672
8861
  fetchData();
8673
8862
  }
8674
8863
  setupSubscriptions();
8864
+ if (!isShiftConfigLoading) {
8865
+ prevShiftIdRef.current = shiftId;
8866
+ }
8675
8867
  return () => {
8676
8868
  if (fetchTimeoutRef.current) {
8677
8869
  clearTimeout(fetchTimeoutRef.current);
@@ -8686,7 +8878,7 @@ var useRealtimeLineMetrics = ({
8686
8878
  });
8687
8879
  }
8688
8880
  };
8689
- }, [lineId, fetchData, setupSubscriptions, initialized, supabase]);
8881
+ }, [lineId, fetchData, setupSubscriptions, initialized, supabase, isShiftConfigLoading, enabled, shiftId]);
8690
8882
  useEffect(() => {
8691
8883
  setInitialized(false);
8692
8884
  }, [lineId, date, shiftId]);
@@ -9404,14 +9596,20 @@ var useFactoryOverviewMetrics = (date, shiftId) => {
9404
9596
  const supabase = useSupabase();
9405
9597
  const entityConfig = useEntityConfig();
9406
9598
  const dateTimeConfig = useDateTimeConfig();
9407
- const shiftConfig = useShiftConfig();
9599
+ const staticShiftConfig = useShiftConfig();
9600
+ const firstLineId = useMemo(() => {
9601
+ const lineIds = getConfiguredLineIds(entityConfig);
9602
+ return lineIds[0];
9603
+ }, [entityConfig]);
9604
+ const { shiftConfig: dynamicShiftConfig, isLoading: isShiftConfigLoading } = useDynamicShiftConfig(firstLineId);
9605
+ const shiftConfig = dynamicShiftConfig || staticShiftConfig;
9408
9606
  const [metrics2, setMetrics] = useState(null);
9409
9607
  const [isLoading, setIsLoading] = useState(true);
9410
9608
  const [error, setError] = useState(null);
9411
9609
  const isFetchingRef = useRef(false);
9412
9610
  const defaultTimezone = dateTimeConfig.defaultTimezone || "UTC";
9413
9611
  const fetchMetrics = useCallback(async () => {
9414
- if (!supabase || isFetchingRef.current) return;
9612
+ if (!supabase || isFetchingRef.current || isShiftConfigLoading) return;
9415
9613
  try {
9416
9614
  isFetchingRef.current = true;
9417
9615
  setIsLoading(true);
@@ -9460,7 +9658,7 @@ var useFactoryOverviewMetrics = (date, shiftId) => {
9460
9658
  setIsLoading(false);
9461
9659
  isFetchingRef.current = false;
9462
9660
  }
9463
- }, [supabase, date, shiftId, entityConfig, defaultTimezone, shiftConfig]);
9661
+ }, [supabase, date, shiftId, entityConfig, defaultTimezone, shiftConfig, isShiftConfigLoading]);
9464
9662
  useEffect(() => {
9465
9663
  fetchMetrics();
9466
9664
  }, [fetchMetrics]);
@@ -9866,14 +10064,24 @@ var useActiveBreaks = (lineIds) => {
9866
10064
  }
9867
10065
  return { elapsedMinutes, remainingMinutes };
9868
10066
  };
9869
- const getCurrentShift2 = (currentMinutes, dayStart, nightStart) => {
9870
- const dayStartMinutes = parseTimeToMinutes2(dayStart);
9871
- const nightStartMinutes = parseTimeToMinutes2(nightStart);
9872
- if (nightStartMinutes < dayStartMinutes) {
9873
- return currentMinutes >= nightStartMinutes && currentMinutes < dayStartMinutes ? "night" : "day";
10067
+ const isTimeInShift = (startTime, endTime, currentMinutes) => {
10068
+ const startMinutes = parseTimeToMinutes2(startTime);
10069
+ const endMinutes = parseTimeToMinutes2(endTime);
10070
+ if (endMinutes < startMinutes) {
10071
+ return currentMinutes >= startMinutes || currentMinutes < endMinutes;
9874
10072
  } else {
9875
- return currentMinutes >= dayStartMinutes && currentMinutes < nightStartMinutes ? "day" : "night";
10073
+ return currentMinutes >= startMinutes && currentMinutes < endMinutes;
10074
+ }
10075
+ };
10076
+ const findActiveShift = (shifts, currentMinutes) => {
10077
+ for (const shift of shifts) {
10078
+ const startTime = shift.start_time || "00:00";
10079
+ const endTime = shift.end_time || "00:00";
10080
+ if (isTimeInShift(startTime, endTime, currentMinutes)) {
10081
+ return shift;
10082
+ }
9876
10083
  }
10084
+ return null;
9877
10085
  };
9878
10086
  const checkActiveBreaks = useCallback(async () => {
9879
10087
  try {
@@ -9888,23 +10096,28 @@ var useActiveBreaks = (lineIds) => {
9888
10096
  return;
9889
10097
  }
9890
10098
  const currentMinutes = getCurrentTimeInMinutes();
9891
- 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);
9892
- 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);
9893
- if (dayError || nightError) {
10099
+ 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");
10100
+ if (shiftsError) {
9894
10101
  throw new Error("Failed to fetch shift configurations");
9895
10102
  }
9896
10103
  const foundActiveBreaks = [];
10104
+ const shiftsByLine = /* @__PURE__ */ new Map();
10105
+ for (const shift of allShifts || []) {
10106
+ const lineShifts = shiftsByLine.get(shift.line_id) || [];
10107
+ lineShifts.push(shift);
10108
+ shiftsByLine.set(shift.line_id, lineShifts);
10109
+ }
9897
10110
  for (const lineId of validLineIds) {
9898
- const dayShift = dayShifts?.find((s) => s.line_id === lineId);
9899
- const nightShift = nightShifts?.find((s) => s.line_id === lineId);
9900
- if (!dayShift || !nightShift) continue;
9901
- const currentShift = getCurrentShift2(
9902
- currentMinutes,
9903
- dayShift.start_time || "06:00",
9904
- nightShift.start_time || "18:00"
9905
- );
9906
- const activeShift = currentShift === "day" ? dayShift : nightShift;
9907
- const shiftName = currentShift === "day" ? "Day Shift" : "Night Shift";
10111
+ const lineShifts = shiftsByLine.get(lineId);
10112
+ if (!lineShifts || lineShifts.length === 0) continue;
10113
+ const activeShift = findActiveShift(lineShifts, currentMinutes);
10114
+ if (!activeShift) continue;
10115
+ const getDefaultShiftName = (shiftId) => {
10116
+ if (shiftId === 0) return "Day Shift";
10117
+ if (shiftId === 1) return "Night Shift";
10118
+ return `Shift ${shiftId}`;
10119
+ };
10120
+ const shiftName = activeShift.shift_name || getDefaultShiftName(activeShift.shift_id);
9908
10121
  let breaks = [];
9909
10122
  if (activeShift.breaks) {
9910
10123
  if (Array.isArray(activeShift.breaks)) {
@@ -9979,8 +10192,12 @@ var useAllWorkspaceMetrics = (options) => {
9979
10192
  const entityConfig = useEntityConfig();
9980
10193
  const databaseConfig = useDatabaseConfig();
9981
10194
  const dateTimeConfig = useDateTimeConfig();
9982
- const shiftConfig = useShiftConfig();
10195
+ const staticShiftConfig = useShiftConfig();
9983
10196
  const timezone = useAppTimezone();
10197
+ const configuredLineIds = useMemo(() => getConfiguredLineIds(entityConfig), [entityConfig]);
10198
+ const representativeLineId = options?.allowedLineIds?.[0] || configuredLineIds[0];
10199
+ const { shiftConfig: dynamicShiftConfig, isLoading: isShiftConfigLoading } = useDynamicShiftConfig(representativeLineId);
10200
+ const shiftConfig = dynamicShiftConfig || staticShiftConfig;
9984
10201
  const supabase = useSupabase();
9985
10202
  const [workspaces, setWorkspaces] = useState([]);
9986
10203
  const [loading, setLoading] = useState(true);
@@ -9989,12 +10206,15 @@ var useAllWorkspaceMetrics = (options) => {
9989
10206
  const fetchTimeoutRef = useRef(null);
9990
10207
  const isFetchingRef = useRef(false);
9991
10208
  const queryShiftId = useMemo(() => {
10209
+ if (options?.initialShiftId !== void 0) {
10210
+ return options.initialShiftId;
10211
+ }
9992
10212
  const currentShift = getCurrentShift(
9993
- dateTimeConfig.defaultTimezone || "Asia/Kolkata",
10213
+ timezone || dateTimeConfig.defaultTimezone || "Asia/Kolkata",
9994
10214
  shiftConfig
9995
10215
  );
9996
- return options?.initialShiftId !== void 0 ? options.initialShiftId : currentShift.shiftId;
9997
- }, [options?.initialShiftId, dateTimeConfig.defaultTimezone, shiftConfig]);
10216
+ return currentShift.shiftId;
10217
+ }, [options?.initialShiftId, timezone, dateTimeConfig.defaultTimezone, shiftConfig]);
9998
10218
  const queryDate = useMemo(() => {
9999
10219
  return options?.initialDate || getOperationalDate(timezone || dateTimeConfig.defaultTimezone || "UTC");
10000
10220
  }, [options?.initialDate, timezone, dateTimeConfig.defaultTimezone]);
@@ -10006,7 +10226,7 @@ var useAllWorkspaceMetrics = (options) => {
10006
10226
  }, [entityConfig.companyId]);
10007
10227
  const schema = databaseConfig.schema ?? "public";
10008
10228
  const fetchWorkspaceMetrics = useCallback(async () => {
10009
- if (isFetchingRef.current) {
10229
+ if (isFetchingRef.current || options?.enabled === false || isShiftConfigLoading) {
10010
10230
  return;
10011
10231
  }
10012
10232
  isFetchingRef.current = true;
@@ -10016,9 +10236,9 @@ var useAllWorkspaceMetrics = (options) => {
10016
10236
  setError(null);
10017
10237
  try {
10018
10238
  const allConfiguredLineIds = getConfiguredLineIds(entityConfig);
10019
- const configuredLineIds = options?.allowedLineIds ? allConfiguredLineIds.filter((id3) => options.allowedLineIds.includes(id3)) : allConfiguredLineIds;
10239
+ const configuredLineIds2 = options?.allowedLineIds ? allConfiguredLineIds.filter((id3) => options.allowedLineIds.includes(id3)) : allConfiguredLineIds;
10020
10240
  let enabledWorkspaceIds = [];
10021
- for (const lineId of configuredLineIds) {
10241
+ for (const lineId of configuredLineIds2) {
10022
10242
  const workspaces2 = await workspaceService.getWorkspaces(lineId);
10023
10243
  const enabledIds = workspaces2.filter((ws) => ws.enable === true).map((ws) => ws.id);
10024
10244
  enabledWorkspaceIds.push(...enabledIds);
@@ -10079,7 +10299,7 @@ var useAllWorkspaceMetrics = (options) => {
10079
10299
  setLoading(false);
10080
10300
  isFetchingRef.current = false;
10081
10301
  }
10082
- }, [queryDate, queryShiftId, metricsTable, supabase, entityConfig.companyId, entityConfig, options?.allowedLineIds]);
10302
+ }, [queryDate, queryShiftId, metricsTable, supabase, entityConfig.companyId, entityConfig, options?.allowedLineIds, options?.enabled, isShiftConfigLoading]);
10083
10303
  useEffect(() => {
10084
10304
  if (!initialized) {
10085
10305
  fetchWorkspaceMetrics();
@@ -10558,7 +10778,7 @@ function useClipTypes() {
10558
10778
  refresh: fetchClipTypes
10559
10779
  };
10560
10780
  }
10561
- function useClipTypesWithCounts(workspaceId, date, shiftId, totalOutput) {
10781
+ function useClipTypesWithCounts(workspaceId, date, shiftId, totalOutput, options) {
10562
10782
  const { clipTypes, isLoading: typesLoading, error: typesError, refresh } = useClipTypes();
10563
10783
  const [counts, setCounts] = useState({});
10564
10784
  const [countsLoading, setCountsLoading] = useState(false);
@@ -10570,8 +10790,13 @@ function useClipTypesWithCounts(workspaceId, date, shiftId, totalOutput) {
10570
10790
  workspaceId,
10571
10791
  date,
10572
10792
  shiftId,
10573
- shiftIdType: typeof shiftId
10793
+ shiftIdType: typeof shiftId,
10794
+ enabled: options?.enabled
10574
10795
  });
10796
+ if (!options?.enabled) {
10797
+ console.log("[useClipTypesWithCounts] Skipping counts fetch - disabled");
10798
+ return;
10799
+ }
10575
10800
  if (!s3Service || !workspaceId || !date || shiftId === void 0) {
10576
10801
  console.log("[useClipTypesWithCounts] Skipping counts fetch - missing dependencies");
10577
10802
  return;
@@ -10595,7 +10820,7 @@ function useClipTypesWithCounts(workspaceId, date, shiftId, totalOutput) {
10595
10820
  }
10596
10821
  };
10597
10822
  fetchCounts();
10598
- }, [s3Service, workspaceId, date, shiftId, totalOutput]);
10823
+ }, [s3Service, workspaceId, date, shiftId, totalOutput, options?.enabled]);
10599
10824
  return {
10600
10825
  clipTypes: clipTypes.map((type) => ({
10601
10826
  ...type,
@@ -11005,15 +11230,48 @@ var useWorkspaceUptimeTimeline = (options) => {
11005
11230
  workspaceId,
11006
11231
  companyId,
11007
11232
  enabled = true,
11008
- refreshInterval
11233
+ refreshInterval,
11234
+ lineId,
11235
+ shiftConfig: passedShiftConfig,
11236
+ timezone: passedTimezone
11009
11237
  } = options;
11238
+ const { shiftConfig: dynamicShiftConfig, isLoading: isShiftConfigLoading } = useDynamicShiftConfig(lineId);
11239
+ const appTimezone = useAppTimezone();
11240
+ const shiftConfigPending = !passedShiftConfig && (!lineId || isShiftConfigLoading || !dynamicShiftConfig);
11241
+ const effectiveShiftConfig = passedShiftConfig ?? (shiftConfigPending ? void 0 : dynamicShiftConfig);
11242
+ const effectiveTimezone = passedTimezone || appTimezone || effectiveShiftConfig?.timezone || "UTC";
11243
+ if (process.env.NODE_ENV === "development") {
11244
+ console.log(`[useWorkspaceUptimeTimeline] Shift config state:`, {
11245
+ lineId,
11246
+ hasPassedConfig: !!passedShiftConfig,
11247
+ isShiftConfigLoading,
11248
+ hasDynamicConfig: !!dynamicShiftConfig,
11249
+ shiftConfigPending,
11250
+ hasEffectiveConfig: !!effectiveShiftConfig
11251
+ });
11252
+ }
11010
11253
  const [timeline, setTimeline] = useState(null);
11011
11254
  const [loading, setLoading] = useState(false);
11012
11255
  const [error, setError] = useState(null);
11013
11256
  const isFetchingRef = useRef(false);
11014
11257
  const intervalRef = useRef(null);
11258
+ useEffect(() => {
11259
+ setTimeline(null);
11260
+ setError(null);
11261
+ setLoading(enabled && Boolean(workspaceId && companyId));
11262
+ }, [workspaceId, companyId, lineId, enabled]);
11015
11263
  const fetchTimeline = useCallback(async () => {
11016
11264
  if (!enabled) return;
11265
+ if (shiftConfigPending) {
11266
+ console.log("[useWorkspaceUptimeTimeline] \u23F3 Waiting for shift config to load before fetching");
11267
+ setLoading(true);
11268
+ return;
11269
+ }
11270
+ if (!effectiveShiftConfig) {
11271
+ console.warn("[useWorkspaceUptimeTimeline] \u26A0\uFE0F No effective shift config available, cannot fetch");
11272
+ setLoading(false);
11273
+ return;
11274
+ }
11017
11275
  if (!workspaceId || !companyId) {
11018
11276
  setTimeline(null);
11019
11277
  return;
@@ -11023,9 +11281,16 @@ var useWorkspaceUptimeTimeline = (options) => {
11023
11281
  isFetchingRef.current = true;
11024
11282
  setLoading(true);
11025
11283
  setError(null);
11284
+ console.log("[useWorkspaceUptimeTimeline] \u{1F680} Fetching timeline with shift config:", {
11285
+ workspaceId,
11286
+ shiftId: effectiveShiftConfig?.shifts?.[0]?.shiftId,
11287
+ timezone: effectiveTimezone
11288
+ });
11026
11289
  const data = await workspaceHealthService.getWorkspaceUptimeTimeline(
11027
11290
  workspaceId,
11028
- companyId
11291
+ companyId,
11292
+ effectiveShiftConfig,
11293
+ effectiveTimezone
11029
11294
  );
11030
11295
  setTimeline(data);
11031
11296
  } catch (err) {
@@ -11035,7 +11300,7 @@ var useWorkspaceUptimeTimeline = (options) => {
11035
11300
  setLoading(false);
11036
11301
  isFetchingRef.current = false;
11037
11302
  }
11038
- }, [enabled, workspaceId, companyId]);
11303
+ }, [enabled, workspaceId, companyId, effectiveShiftConfig, effectiveTimezone, shiftConfigPending]);
11039
11304
  useEffect(() => {
11040
11305
  fetchTimeline();
11041
11306
  }, [fetchTimeline]);
@@ -11054,7 +11319,7 @@ var useWorkspaceUptimeTimeline = (options) => {
11054
11319
  }, [refreshInterval, enabled, fetchTimeline]);
11055
11320
  return {
11056
11321
  timeline,
11057
- loading,
11322
+ loading: loading || shiftConfigPending,
11058
11323
  error,
11059
11324
  refetch: fetchTimeline
11060
11325
  };
@@ -26325,26 +26590,62 @@ var VideoControls = ({
26325
26590
  const [isHoveringProgressBar, setIsHoveringProgressBar] = useState(false);
26326
26591
  const [showSpeedMenu, setShowSpeedMenu] = useState(false);
26327
26592
  const speedMenuRef = useRef(null);
26593
+ const progressTrackRef = useRef(null);
26594
+ const activePointerIdRef = useRef(null);
26328
26595
  const progressColor = "#4b5563";
26329
26596
  const controlsVisible = showControls || controlsPinned;
26597
+ const isDraggingRef = useRef(false);
26330
26598
  const getPercentage = (current, total) => {
26331
26599
  if (!total || total === 0) return 0;
26332
26600
  return Math.min(Math.max(current / total * 100, 0), 100);
26333
26601
  };
26334
26602
  const handleSeekChange = (e) => {
26335
- const newTime = parseFloat(e.target.value);
26603
+ const newTime = parseFloat(e.currentTarget.value);
26336
26604
  setDragTime(newTime);
26337
26605
  onSeek(newTime);
26338
26606
  };
26339
26607
  const handleSeekStart = () => {
26340
26608
  setIsDragging(true);
26609
+ isDraggingRef.current = true;
26341
26610
  setDragTime(currentTime);
26342
26611
  onSeekStart?.();
26343
26612
  };
26344
26613
  const handleSeekEnd = () => {
26345
26614
  setIsDragging(false);
26615
+ isDraggingRef.current = false;
26346
26616
  onSeekEnd?.();
26347
26617
  };
26618
+ const updateTimeFromClientX = useCallback((clientX) => {
26619
+ if (!progressTrackRef.current) return;
26620
+ const rect = progressTrackRef.current.getBoundingClientRect();
26621
+ if (rect.width === 0 || duration === 0) return;
26622
+ const pct = Math.min(Math.max((clientX - rect.left) / rect.width, 0), 1);
26623
+ const newTime = pct * duration;
26624
+ setDragTime(newTime);
26625
+ onSeek(newTime);
26626
+ }, [duration, onSeek]);
26627
+ const handlePointerDown = useCallback((e) => {
26628
+ if (duration === 0) return;
26629
+ e.preventDefault();
26630
+ activePointerIdRef.current = e.pointerId;
26631
+ handleSeekStart();
26632
+ updateTimeFromClientX(e.clientX);
26633
+ const handleMove = (ev) => {
26634
+ if (ev.pointerId !== activePointerIdRef.current) return;
26635
+ updateTimeFromClientX(ev.clientX);
26636
+ };
26637
+ const handleUp = (ev) => {
26638
+ if (ev.pointerId !== activePointerIdRef.current) return;
26639
+ activePointerIdRef.current = null;
26640
+ window.removeEventListener("pointermove", handleMove);
26641
+ window.removeEventListener("pointerup", handleUp);
26642
+ window.removeEventListener("pointercancel", handleUp);
26643
+ handleSeekEnd();
26644
+ };
26645
+ window.addEventListener("pointermove", handleMove);
26646
+ window.addEventListener("pointerup", handleUp);
26647
+ window.addEventListener("pointercancel", handleUp);
26648
+ }, [duration, handleSeekStart, handleSeekEnd, updateTimeFromClientX]);
26348
26649
  useEffect(() => {
26349
26650
  const handleClickOutside = (event) => {
26350
26651
  if (speedMenuRef.current && !speedMenuRef.current.contains(event.target)) {
@@ -26356,6 +26657,21 @@ var VideoControls = ({
26356
26657
  document.removeEventListener("mousedown", handleClickOutside);
26357
26658
  };
26358
26659
  }, []);
26660
+ useEffect(() => {
26661
+ const cancelDrag = () => {
26662
+ if (isDraggingRef.current) {
26663
+ handleSeekEnd();
26664
+ }
26665
+ };
26666
+ window.addEventListener("mouseup", cancelDrag);
26667
+ window.addEventListener("touchend", cancelDrag);
26668
+ window.addEventListener("touchcancel", cancelDrag);
26669
+ return () => {
26670
+ window.removeEventListener("mouseup", cancelDrag);
26671
+ window.removeEventListener("touchend", cancelDrag);
26672
+ window.removeEventListener("touchcancel", cancelDrag);
26673
+ };
26674
+ }, []);
26359
26675
  const displayTime = isDragging ? dragTime : currentTime;
26360
26676
  const progressPercent = getPercentage(displayTime, duration);
26361
26677
  const bufferedPercent = getPercentage(buffered, duration);
@@ -26368,11 +26684,13 @@ var VideoControls = ({
26368
26684
  /* @__PURE__ */ jsxs(
26369
26685
  "div",
26370
26686
  {
26687
+ ref: progressTrackRef,
26371
26688
  className: "relative h-1 mb-4 group cursor-pointer",
26372
26689
  onMouseEnter: () => setIsHoveringProgressBar(true),
26373
26690
  onMouseLeave: () => setIsHoveringProgressBar(false),
26691
+ onPointerDown: handlePointerDown,
26374
26692
  children: [
26375
- /* @__PURE__ */ jsx("div", { className: "absolute -top-2 -bottom-2 left-0 right-0 z-20" }),
26693
+ /* @__PURE__ */ jsx("div", { className: "absolute -top-4 -bottom-4 left-0 right-0 z-20" }),
26376
26694
  /* @__PURE__ */ jsx("div", { className: "absolute top-0 left-0 right-0 bottom-0 bg-white/20 rounded-full overflow-hidden z-0", children: /* @__PURE__ */ jsx(
26377
26695
  "div",
26378
26696
  {
@@ -26403,11 +26721,13 @@ var VideoControls = ({
26403
26721
  step: "0.1",
26404
26722
  value: displayTime,
26405
26723
  onChange: handleSeekChange,
26724
+ onInput: handleSeekChange,
26406
26725
  onMouseDown: handleSeekStart,
26407
26726
  onMouseUp: handleSeekEnd,
26408
26727
  onTouchStart: handleSeekStart,
26409
26728
  onTouchEnd: handleSeekEnd,
26410
- className: "absolute inset-0 w-full h-full opacity-0 cursor-pointer z-30 margin-0 padding-0"
26729
+ onPointerDown: handlePointerDown,
26730
+ className: "absolute left-0 right-0 top-[-12px] bottom-[-12px] w-full h-auto opacity-0 cursor-pointer z-30 margin-0 padding-0"
26411
26731
  }
26412
26732
  )
26413
26733
  ]
@@ -26630,6 +26950,7 @@ var HlsVideoPlayer = forwardRef(({
26630
26950
  const [buffered, setBuffered] = useState(0);
26631
26951
  const [playbackRate, setPlaybackRate] = useState(1);
26632
26952
  const userSeekingRef = useRef(false);
26953
+ const wasPlayingRef = useRef(false);
26633
26954
  const controlsTimeoutRef = useRef(null);
26634
26955
  const eventCallbacksRef = useRef({
26635
26956
  onReady,
@@ -26872,10 +27193,6 @@ var HlsVideoPlayer = forwardRef(({
26872
27193
  eventCallbacksRef.current.onPlay?.(player);
26873
27194
  };
26874
27195
  const handlePause = () => {
26875
- if (userSeekingRef.current && videoRef.current) {
26876
- videoRef.current.play().catch((err) => console.warn("Auto-resume after seek pause failed:", err));
26877
- return;
26878
- }
26879
27196
  setIsPlaying(false);
26880
27197
  eventCallbacksRef.current.onPause?.(player);
26881
27198
  };
@@ -27089,14 +27406,17 @@ var HlsVideoPlayer = forwardRef(({
27089
27406
  const handleSeek = useCallback((time2) => {
27090
27407
  if (videoRef.current) {
27091
27408
  videoRef.current.currentTime = time2;
27092
- videoRef.current.play().catch((err) => console.warn("Resume playback failed during seek:", err));
27093
27409
  }
27094
27410
  }, []);
27095
27411
  const handleSeekStart = useCallback(() => {
27412
+ wasPlayingRef.current = !videoRef.current?.paused;
27413
+ if (videoRef.current && !videoRef.current.paused) {
27414
+ videoRef.current.pause();
27415
+ }
27096
27416
  userSeekingRef.current = true;
27097
27417
  }, []);
27098
27418
  const handleSeekEnd = useCallback(() => {
27099
- if (videoRef.current) {
27419
+ if (videoRef.current && wasPlayingRef.current) {
27100
27420
  videoRef.current.play().catch((err) => console.warn("Resume playback failed after seek:", err));
27101
27421
  }
27102
27422
  }, []);
@@ -27238,6 +27558,7 @@ var CroppedHlsVideoPlayer = forwardRef(({
27238
27558
  const [playbackRate, setPlaybackRate] = useState(1);
27239
27559
  const controlsTimeoutRef = useRef(null);
27240
27560
  const userSeekingRef = useRef(false);
27561
+ const wasPlayingRef = useRef(false);
27241
27562
  const [controlsPinned, setControlsPinned] = useState(false);
27242
27563
  const stopCanvasRendering = useCallback(() => {
27243
27564
  if (animationFrameRef.current) {
@@ -27377,7 +27698,7 @@ var CroppedHlsVideoPlayer = forwardRef(({
27377
27698
  }, [crop, renderFrameToCanvas, onPlayProp]);
27378
27699
  const handleVideoPause = useCallback((player) => {
27379
27700
  console.log("[CroppedHlsVideoPlayer] Video paused, stopping canvas rendering (keeping last frame)");
27380
- if (userSeekingRef.current && hiddenVideoRef.current) {
27701
+ if (userSeekingRef.current && wasPlayingRef.current && hiddenVideoRef.current) {
27381
27702
  hiddenVideoRef.current.play()?.catch(() => {
27382
27703
  });
27383
27704
  return;
@@ -27394,6 +27715,7 @@ var CroppedHlsVideoPlayer = forwardRef(({
27394
27715
  setIsProcessing(false);
27395
27716
  setIsPlaying(false);
27396
27717
  userSeekingRef.current = false;
27718
+ wasPlayingRef.current = false;
27397
27719
  onEndedProp?.(player);
27398
27720
  }, [stopCanvasRendering, onEndedProp]);
27399
27721
  const handleSeeking = useCallback((player) => {
@@ -27409,6 +27731,7 @@ var CroppedHlsVideoPlayer = forwardRef(({
27409
27731
  hiddenVideoRef.current?.play()?.catch(() => {
27410
27732
  });
27411
27733
  userSeekingRef.current = false;
27734
+ wasPlayingRef.current = false;
27412
27735
  if (crop) {
27413
27736
  renderFrameToCanvas();
27414
27737
  }
@@ -27505,20 +27828,34 @@ var CroppedHlsVideoPlayer = forwardRef(({
27505
27828
  const handleSeek = useCallback((time2) => {
27506
27829
  if (hiddenVideoRef.current) {
27507
27830
  hiddenVideoRef.current.currentTime(time2);
27508
- hiddenVideoRef.current.play()?.catch(() => {
27509
- });
27510
27831
  setTimeout(() => renderFrameToCanvas(), 50);
27832
+ userSeekingRef.current = true;
27511
27833
  }
27512
27834
  }, [renderFrameToCanvas]);
27513
27835
  const handleSeekStart = useCallback(() => {
27836
+ const videoPaused = hiddenVideoRef.current?.video?.paused ?? hiddenVideoRef.current?.paused();
27837
+ wasPlayingRef.current = videoPaused === false;
27838
+ if (hiddenVideoRef.current && videoPaused === false) {
27839
+ hiddenVideoRef.current.pause();
27840
+ }
27514
27841
  userSeekingRef.current = true;
27515
27842
  }, []);
27516
27843
  const handleSeekEnd = useCallback(() => {
27517
- if (hiddenVideoRef.current) {
27518
- hiddenVideoRef.current.play()?.catch(() => {
27844
+ const shouldResume = wasPlayingRef.current;
27845
+ userSeekingRef.current = shouldResume;
27846
+ if (hiddenVideoRef.current && shouldResume) {
27847
+ hiddenVideoRef.current.play()?.then(() => {
27848
+ if (crop) {
27849
+ setIsProcessing(true);
27850
+ renderFrameToCanvas();
27851
+ }
27852
+ }).catch(() => {
27519
27853
  });
27520
27854
  }
27521
- }, []);
27855
+ if (!shouldResume) {
27856
+ userSeekingRef.current = false;
27857
+ }
27858
+ }, [crop, renderFrameToCanvas]);
27522
27859
  const handlePlaybackRateChange = useCallback((rate) => {
27523
27860
  if (hiddenVideoRef.current) {
27524
27861
  hiddenVideoRef.current.playbackRate(rate);
@@ -29809,6 +30146,7 @@ var BottlenecksContent = ({
29809
30146
  workspaceId,
29810
30147
  workspaceName,
29811
30148
  date,
30149
+ lineId,
29812
30150
  shift,
29813
30151
  className,
29814
30152
  totalOutput,
@@ -29819,27 +30157,36 @@ var BottlenecksContent = ({
29819
30157
  console.log("\u{1F3AB} [BottlenecksContent] Rendered with ticketId:", ticketId || "NONE", "workspaceId:", workspaceId, "date:", date, "shift:", shift);
29820
30158
  const dashboardConfig = useDashboardConfig();
29821
30159
  const timezone = useAppTimezone();
29822
- const { shiftConfig } = useDynamicShiftConfig(workspaceId);
29823
- const effectiveShift = useMemo(() => {
29824
- if (shift !== void 0 && shift !== null) {
30160
+ const { shiftConfig, isLoading: isShiftConfigLoading } = useDynamicShiftConfig(lineId);
30161
+ const { effectiveShift, effectiveDate } = useMemo(() => {
30162
+ if (shift !== void 0 && shift !== null && date) {
29825
30163
  const shiftStr = shift.toString();
29826
- console.log(`[BottlenecksContent] Using provided shift: ${shiftStr} for date: ${date}`);
29827
- return shiftStr;
30164
+ console.log(`[BottlenecksContent] Using explicit date/shift: ${date}, shift ${shiftStr}`);
30165
+ return { effectiveShift: shiftStr, effectiveDate: date };
29828
30166
  }
29829
- if (date) {
29830
- console.log(`[BottlenecksContent] No shift provided for historical date ${date}, defaulting to day shift (0)`);
29831
- return "0";
29832
- } else {
29833
- const currentShift = getCurrentShift(
29834
- timezone,
29835
- // Use dynamic timezone instead of hardcoded default
29836
- shiftConfig
29837
- // Use line-specific shift config from database
29838
- );
29839
- console.log(`[BottlenecksContent] Using current operational shift: ${currentShift.shiftId} with timezone: ${timezone} for workspace: ${workspaceId}`);
29840
- return currentShift.shiftId.toString();
30167
+ if ((shift === void 0 || shift === null) && isShiftConfigLoading) {
30168
+ console.log("[BottlenecksContent] Waiting for shift config before determining effective date/shift");
30169
+ return { effectiveShift: null, effectiveDate: null };
30170
+ }
30171
+ const currentShift = getCurrentShift(
30172
+ timezone,
30173
+ shiftConfig
30174
+ );
30175
+ if (shift !== void 0 && shift !== null) {
30176
+ const shiftStr = shift.toString();
30177
+ return {
30178
+ effectiveShift: shiftStr,
30179
+ effectiveDate: date || currentShift.date
30180
+ };
29841
30181
  }
29842
- }, [shift, date, timezone, shiftConfig, workspaceId]);
30182
+ return {
30183
+ effectiveShift: currentShift.shiftId.toString(),
30184
+ effectiveDate: date || currentShift.date
30185
+ };
30186
+ }, [shift, date, timezone, shiftConfig, isShiftConfigLoading]);
30187
+ const isEffectiveShiftReady = Boolean(effectiveShift && effectiveDate);
30188
+ const effectiveDateString = effectiveDate || "";
30189
+ const effectiveShiftId = effectiveShift ?? "";
29843
30190
  const { crop: workspaceCrop} = useWorkspaceCrop(workspaceId);
29844
30191
  const { metrics: workspaceMetrics } = useWorkspaceDetailedMetrics(
29845
30192
  workspaceId,
@@ -29925,9 +30272,9 @@ var BottlenecksContent = ({
29925
30272
  clearNotification
29926
30273
  } = useClipsRealtimeUpdates({
29927
30274
  workspaceId,
29928
- date: date || getOperationalDate(timezone),
29929
- shiftId: effectiveShift,
29930
- enabled: true,
30275
+ date: effectiveDateString,
30276
+ shiftId: effectiveShiftId,
30277
+ enabled: isEffectiveShiftReady,
29931
30278
  // Supabase implementation
29932
30279
  onNewClips: (notification) => {
29933
30280
  console.log(`[BottlenecksContent] New clips detected:`, notification);
@@ -29968,10 +30315,11 @@ var BottlenecksContent = ({
29968
30315
  counts: dynamicCounts
29969
30316
  } = useClipTypesWithCounts(
29970
30317
  workspaceId,
29971
- date || getOperationalDate(timezone),
29972
- effectiveShift,
30318
+ effectiveDateString,
30319
+ effectiveShiftId,
29973
30320
  // Use same shift as video loading for consistency
29974
- totalOutput
30321
+ totalOutput,
30322
+ { enabled: isEffectiveShiftReady }
29975
30323
  );
29976
30324
  console.log("[BottlenecksContent] Clip types data:", {
29977
30325
  clipTypes,
@@ -29980,8 +30328,8 @@ var BottlenecksContent = ({
29980
30328
  clipTypesError,
29981
30329
  dynamicCounts,
29982
30330
  workspaceId,
29983
- date: date || getOperationalDate(timezone),
29984
- shift: shift || "0"
30331
+ date: effectiveDateString,
30332
+ shift: effectiveShiftId || "0"
29985
30333
  });
29986
30334
  useEffect(() => {
29987
30335
  if (clipTypes.length > 0) {
@@ -30022,16 +30370,16 @@ var BottlenecksContent = ({
30022
30370
  return { ...clipCounts, ...dynamicCounts };
30023
30371
  }, [clipCounts, dynamicCounts]);
30024
30372
  const fetchClipCounts = useCallback(async () => {
30025
- if (!workspaceId || !s3ClipsService || !dashboardConfig?.s3Config || !isMountedRef.current) return;
30026
- const operationKey = `fetchClipCounts:${workspaceId}:${date}:${shift}`;
30373
+ if (!workspaceId || !s3ClipsService || !dashboardConfig?.s3Config || !isMountedRef.current || !isEffectiveShiftReady) return;
30374
+ const operationKey = `fetchClipCounts:${workspaceId}:${effectiveDateString}:${effectiveShiftId}`;
30027
30375
  if (fetchInProgressRef.current.has(operationKey)) {
30028
30376
  console.log(`[BottlenecksContent] Fetch clip counts already in progress for ${operationKey}`);
30029
30377
  return;
30030
30378
  }
30031
30379
  fetchInProgressRef.current.add(operationKey);
30032
30380
  try {
30033
- const operationalDate = date || getOperationalDate(timezone);
30034
- const shiftStr = effectiveShift;
30381
+ const operationalDate = effectiveDateString;
30382
+ const shiftStr = effectiveShiftId;
30035
30383
  console.log(`[BottlenecksContent] Fetching clip counts directly with params:`, {
30036
30384
  workspaceId,
30037
30385
  operationalDate,
@@ -30066,12 +30414,12 @@ var BottlenecksContent = ({
30066
30414
  } finally {
30067
30415
  fetchInProgressRef.current.delete(operationKey);
30068
30416
  }
30069
- }, [workspaceId, date, s3ClipsService, effectiveShift, dashboardConfig, updateClipCounts, timezone, totalOutput]);
30417
+ }, [workspaceId, effectiveDateString, s3ClipsService, effectiveShiftId, dashboardConfig, updateClipCounts, isEffectiveShiftReady, totalOutput]);
30070
30418
  const loadingCategoryRef = useRef(null);
30071
30419
  const loadFirstVideoForCategory = useCallback(async (category) => {
30072
- if (!workspaceId || !s3ClipsService || !isMountedRef.current) return;
30420
+ if (!workspaceId || !s3ClipsService || !isMountedRef.current || !isEffectiveShiftReady) return;
30073
30421
  const targetCategory = category || activeFilterRef.current;
30074
- const operationKey = `loadFirstVideo:${targetCategory}`;
30422
+ const operationKey = `loadFirstVideo:${targetCategory}:${effectiveDateString}:${effectiveShiftId}`;
30075
30423
  if (loadingCategoryRef.current === targetCategory || fetchInProgressRef.current.has(operationKey)) {
30076
30424
  console.log(`[BottlenecksContent] Load first video already in progress for ${targetCategory}`);
30077
30425
  return;
@@ -30082,8 +30430,8 @@ var BottlenecksContent = ({
30082
30430
  setError(null);
30083
30431
  }
30084
30432
  try {
30085
- const operationalDate = date || getOperationalDate(timezone);
30086
- const shiftStr = effectiveShift;
30433
+ const operationalDate = effectiveDateString;
30434
+ const shiftStr = effectiveShiftId;
30087
30435
  console.log(`[BottlenecksContent] Loading first video for category: ${targetCategory}`);
30088
30436
  try {
30089
30437
  const firstVideo = await s3ClipsService.getFirstClipForCategory(
@@ -30156,7 +30504,7 @@ var BottlenecksContent = ({
30156
30504
  loadingCategoryRef.current = null;
30157
30505
  fetchInProgressRef.current.delete(operationKey);
30158
30506
  }
30159
- }, [workspaceId, date, s3ClipsService, mergedCounts, effectiveShift, timezone]);
30507
+ }, [workspaceId, effectiveDateString, s3ClipsService, mergedCounts, effectiveShiftId, isEffectiveShiftReady]);
30160
30508
  const handleRefreshClips = useCallback(async () => {
30161
30509
  console.log("[BottlenecksContent] Refreshing clips after new additions");
30162
30510
  acknowledgeNewClips();
@@ -30167,10 +30515,10 @@ var BottlenecksContent = ({
30167
30515
  }
30168
30516
  }, [acknowledgeNewClips, fetchClipCounts, activeFilter, mergedCounts, loadFirstVideoForCategory, invalidateMetadataCache]);
30169
30517
  useEffect(() => {
30170
- if (s3ClipsService) {
30518
+ if (s3ClipsService && isEffectiveShiftReady) {
30171
30519
  fetchClipCounts();
30172
30520
  }
30173
- }, [workspaceId, date, effectiveShift, s3ClipsService, fetchClipCounts]);
30521
+ }, [workspaceId, effectiveDateString, effectiveShiftId, s3ClipsService, fetchClipCounts, isEffectiveShiftReady]);
30174
30522
  const getAuthToken4 = useCallback(async () => {
30175
30523
  try {
30176
30524
  const { createClient: createClient5 } = await import('@supabase/supabase-js');
@@ -30186,7 +30534,7 @@ var BottlenecksContent = ({
30186
30534
  }
30187
30535
  }, []);
30188
30536
  useEffect(() => {
30189
- if (!triageMode || !workspaceId) return;
30537
+ if (!triageMode || !workspaceId || !isEffectiveShiftReady) return;
30190
30538
  const fetchTriageClips = async () => {
30191
30539
  setIsLoadingTriageClips(true);
30192
30540
  try {
@@ -30205,8 +30553,8 @@ var BottlenecksContent = ({
30205
30553
  body: JSON.stringify({
30206
30554
  action: "metadata",
30207
30555
  workspaceId,
30208
- date: date || getOperationalDate(timezone),
30209
- shift: effectiveShift,
30556
+ date: effectiveDateString,
30557
+ shift: effectiveShiftId,
30210
30558
  category: categoryId,
30211
30559
  page: 1,
30212
30560
  limit: 100
@@ -30238,7 +30586,7 @@ var BottlenecksContent = ({
30238
30586
  }
30239
30587
  };
30240
30588
  fetchTriageClips();
30241
- }, [triageMode, workspaceId, date, effectiveShift, timezone, getAuthToken4]);
30589
+ }, [triageMode, workspaceId, effectiveDateString, effectiveShiftId, getAuthToken4, isEffectiveShiftReady]);
30242
30590
  useEffect(() => {
30243
30591
  if (s3ClipsService && (mergedCounts[activeFilter] || 0) > 0) {
30244
30592
  const hasVideosForCurrentFilter = allVideos.some((video) => {
@@ -30339,8 +30687,12 @@ var BottlenecksContent = ({
30339
30687
  if (!workspaceId) {
30340
30688
  return;
30341
30689
  }
30342
- const resolvedDate = date || getOperationalDate(timezone);
30343
- const cacheKey = `${categoryId}-${resolvedDate}-${effectiveShift}`;
30690
+ if (!isEffectiveShiftReady) {
30691
+ console.log("[BottlenecksContent] Skipping metadata load - shift/date not ready");
30692
+ return;
30693
+ }
30694
+ const resolvedDate = effectiveDateString;
30695
+ const cacheKey = `${categoryId}-${resolvedDate}-${effectiveShiftId}`;
30344
30696
  const cachedMetadata = !forceRefresh ? metadataCache[cacheKey] : void 0;
30345
30697
  try {
30346
30698
  if (cachedMetadata) {
@@ -30394,7 +30746,7 @@ var BottlenecksContent = ({
30394
30746
  startDate: `${resolvedDate}T00:00:00Z`,
30395
30747
  endDate: `${resolvedDate}T23:59:59Z`,
30396
30748
  percentile: 10,
30397
- shiftId: effectiveShift,
30749
+ shiftId: effectiveShiftId,
30398
30750
  limit: 100
30399
30751
  })
30400
30752
  });
@@ -30409,7 +30761,7 @@ var BottlenecksContent = ({
30409
30761
  action: "clip-metadata",
30410
30762
  workspaceId,
30411
30763
  date: resolvedDate,
30412
- shift: effectiveShift,
30764
+ shift: effectiveShiftId,
30413
30765
  category: categoryId,
30414
30766
  page: 1,
30415
30767
  limit: 1e3
@@ -30468,7 +30820,7 @@ var BottlenecksContent = ({
30468
30820
  } finally {
30469
30821
  setIsCategoryLoading(false);
30470
30822
  }
30471
- }, [workspaceId, date, effectiveShift, isPercentileCategory, metadataCache, s3ClipsService, timezone, clearLoadingState]);
30823
+ }, [workspaceId, effectiveDateString, effectiveShiftId, isPercentileCategory, metadataCache, s3ClipsService, clearLoadingState, isEffectiveShiftReady]);
30472
30824
  const loadAndPlayClipById = useCallback(async (clipId, categoryId, position) => {
30473
30825
  if (!workspaceId || !s3ClipsService || !isMountedRef.current) return;
30474
30826
  console.log(`[BottlenecksContent] Loading clip by ID: ${clipId}, category=${categoryId}, position=${position}`);
@@ -30533,10 +30885,10 @@ var BottlenecksContent = ({
30533
30885
  }, [workspaceId, s3ClipsService, updateActiveFilter, clearLoadingState, loadCategoryMetadata]);
30534
30886
  useCallback(async (categoryId, clipIndex) => {
30535
30887
  console.warn("[BottlenecksContent] loadAndPlayClip is deprecated, use loadAndPlayClipById instead");
30536
- if (!workspaceId || !s3ClipsService || !isMountedRef.current) return;
30888
+ if (!workspaceId || !s3ClipsService || !isMountedRef.current || !isEffectiveShiftReady) return;
30537
30889
  try {
30538
- const operationalDate = date || getOperationalDate(timezone);
30539
- const shiftStr = effectiveShift;
30890
+ const operationalDate = effectiveDateString;
30891
+ const shiftStr = effectiveShiftId;
30540
30892
  const video = await s3ClipsService.getClipByIndex(
30541
30893
  workspaceId,
30542
30894
  operationalDate,
@@ -30557,7 +30909,7 @@ var BottlenecksContent = ({
30557
30909
  });
30558
30910
  setIsNavigating(false);
30559
30911
  }
30560
- }, [workspaceId, s3ClipsService, date, effectiveShift, loadAndPlayClipById, timezone]);
30912
+ }, [workspaceId, s3ClipsService, effectiveDateString, effectiveShiftId, loadAndPlayClipById, isEffectiveShiftReady]);
30561
30913
  const handleNext = useCallback(async () => {
30562
30914
  if (!isMountedRef.current) return;
30563
30915
  const currentFilter = activeFilterRef.current;
@@ -31216,8 +31568,8 @@ var BottlenecksContent = ({
31216
31568
  currentVideoId: currentVideo?.id,
31217
31569
  counts: mergedCounts,
31218
31570
  workspaceId,
31219
- date: date || getOperationalDate(timezone),
31220
- shift: effectiveShift,
31571
+ date: effectiveDateString,
31572
+ shift: effectiveShiftId,
31221
31573
  targetCycleTime: workspaceTargetCycleTime,
31222
31574
  onFilterChange: (filterId) => {
31223
31575
  updateActiveFilter(filterId);
@@ -31415,6 +31767,7 @@ var BottleneckClipsModal = ({
31415
31767
  onClose,
31416
31768
  workspaceId,
31417
31769
  workspaceName,
31770
+ lineId,
31418
31771
  date,
31419
31772
  shift,
31420
31773
  totalOutput,
@@ -31539,6 +31892,7 @@ var BottleneckClipsModal = ({
31539
31892
  {
31540
31893
  workspaceId,
31541
31894
  workspaceName,
31895
+ lineId,
31542
31896
  date,
31543
31897
  shift,
31544
31898
  totalOutput,
@@ -32485,7 +32839,7 @@ var EncouragementOverlay = ({
32485
32839
  };
32486
32840
  var ShiftDisplay = memo(({ className, variant = "default", lineId }) => {
32487
32841
  const { dateTimeConfig } = useDashboardConfig();
32488
- const { shiftConfig } = useDynamicShiftConfig(lineId);
32842
+ const { shiftConfig, isLoading: isShiftConfigLoading } = useDynamicShiftConfig(lineId);
32489
32843
  const getShiftInfo = () => {
32490
32844
  const tz = dateTimeConfig?.defaultTimezone;
32491
32845
  if (!tz || !shiftConfig || !shiftConfig.dayShift || !shiftConfig.nightShift || !shiftConfig.dayShift.startTime || !shiftConfig.nightShift.startTime) {
@@ -32499,7 +32853,7 @@ var ShiftDisplay = memo(({ className, variant = "default", lineId }) => {
32499
32853
  return null;
32500
32854
  }
32501
32855
  };
32502
- const getShiftIcon = (shift) => {
32856
+ const getShiftIcon2 = (shift) => {
32503
32857
  if (shift === "Day") {
32504
32858
  return /* @__PURE__ */ jsx("svg", { className: "w-4 h-4", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ 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" }) });
32505
32859
  } else {
@@ -32513,13 +32867,19 @@ var ShiftDisplay = memo(({ className, variant = "default", lineId }) => {
32513
32867
  setCurrentShiftText(getShiftInfo());
32514
32868
  }, 1e3);
32515
32869
  return () => clearInterval(interval);
32516
- }, [dateTimeConfig?.defaultTimezone, shiftConfig]);
32870
+ }, [dateTimeConfig?.defaultTimezone, shiftConfig, isShiftConfigLoading]);
32871
+ if (isShiftConfigLoading) {
32872
+ return /* @__PURE__ */ jsxs("div", { className: `inline-flex items-center gap-2 bg-gray-100 rounded-lg px-3 py-1.5 ${className ?? ""}`, children: [
32873
+ /* @__PURE__ */ jsx("div", { className: "w-4 h-4 bg-gray-200 rounded animate-pulse" }),
32874
+ /* @__PURE__ */ jsx("div", { className: "w-16 h-4 bg-gray-200 rounded animate-pulse" })
32875
+ ] });
32876
+ }
32517
32877
  if (!currentShiftText) {
32518
32878
  return null;
32519
32879
  }
32520
32880
  if (variant === "enhanced") {
32521
32881
  return /* @__PURE__ */ jsxs("div", { className: `inline-flex items-center gap-2 bg-blue-50 rounded-lg px-3 py-1.5 ${className ?? ""}`, children: [
32522
- /* @__PURE__ */ jsx("div", { className: "text-blue-800", children: getShiftIcon(currentShiftText) }),
32882
+ /* @__PURE__ */ jsx("div", { className: "text-blue-800", children: getShiftIcon2(currentShiftText) }),
32523
32883
  /* @__PURE__ */ jsxs("span", { className: "text-base font-medium text-blue-800", children: [
32524
32884
  currentShiftText,
32525
32885
  " Shift"
@@ -32527,7 +32887,7 @@ var ShiftDisplay = memo(({ className, variant = "default", lineId }) => {
32527
32887
  ] });
32528
32888
  }
32529
32889
  return /* @__PURE__ */ jsxs("div", { className: `inline-flex items-center gap-2 bg-blue-50 rounded-lg px-3 py-1.5 ${className ?? ""}`, children: [
32530
- /* @__PURE__ */ jsx("div", { className: "text-blue-800", children: getShiftIcon(currentShiftText) }),
32890
+ /* @__PURE__ */ jsx("div", { className: "text-blue-800", children: getShiftIcon2(currentShiftText) }),
32531
32891
  /* @__PURE__ */ jsxs("span", { className: "text-base font-medium text-blue-800", children: [
32532
32892
  currentShiftText,
32533
32893
  " Shift"
@@ -32991,13 +33351,26 @@ var LinePdfExportButton = ({
32991
33351
  }
32992
33352
  );
32993
33353
  };
33354
+ var DEFAULT_LINE_SHIFT_DATA = {
33355
+ avg_efficiency: 0,
33356
+ underperforming_workspaces: 0,
33357
+ total_workspaces: 0,
33358
+ hasData: false
33359
+ };
33360
+ var getLineShiftData = (day, shiftId) => {
33361
+ const shift = day.shifts[shiftId];
33362
+ if (shift) {
33363
+ return { ...shift, hasData: true };
33364
+ }
33365
+ return { ...DEFAULT_LINE_SHIFT_DATA };
33366
+ };
32994
33367
  var WEEKDAYS = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
32995
33368
  var LineHistoryCalendar = ({
32996
33369
  data,
32997
33370
  month,
32998
33371
  year,
32999
33372
  lineId,
33000
- selectedShift,
33373
+ selectedShiftId,
33001
33374
  onDateSelect,
33002
33375
  className = ""
33003
33376
  }) => {
@@ -33033,8 +33406,7 @@ var LineHistoryCalendar = ({
33033
33406
  } else {
33034
33407
  calendar.push({
33035
33408
  date: currentDate,
33036
- dayShift: { avg_efficiency: 0, underperforming_workspaces: 0, total_workspaces: 0, hasData: false },
33037
- nightShift: { avg_efficiency: 0, underperforming_workspaces: 0, total_workspaces: 0, hasData: false }
33409
+ shifts: {}
33038
33410
  });
33039
33411
  }
33040
33412
  }
@@ -33085,8 +33457,7 @@ var LineHistoryCalendar = ({
33085
33457
  };
33086
33458
  const renderDayCell = (day) => {
33087
33459
  if (!day) return /* @__PURE__ */ jsx("div", { className: "h-full border border-gray-100 dark:border-gray-700 rounded-lg bg-gray-50 dark:bg-gray-800" });
33088
- const shiftData = selectedShift === "day" ? day.dayShift : day.nightShift;
33089
- if (!shiftData) return /* @__PURE__ */ jsx("div", { className: "h-full border border-gray-100 dark:border-gray-700 rounded-lg bg-gray-50 dark:bg-gray-800" });
33460
+ const shiftData = getLineShiftData(day, selectedShiftId);
33090
33461
  const isToday = isCurrentDate(day.date instanceof Date ? day.date : new Date(day.date));
33091
33462
  const isFuture = isFutureDate(day.date instanceof Date ? day.date : new Date(day.date));
33092
33463
  const hasData = hasRealData(shiftData);
@@ -33102,21 +33473,20 @@ var LineHistoryCalendar = ({
33102
33473
  const month2 = String(dateObj2.getMonth() + 1).padStart(2, "0");
33103
33474
  const dayOfMonth = String(dateObj2.getDate()).padStart(2, "0");
33104
33475
  const date = `${year2}-${month2}-${dayOfMonth}`;
33105
- const shiftId = selectedShift === "day" ? "0" : "1";
33106
33476
  trackCoreEvent("Line Monthly History Day Clicked", {
33107
33477
  source: "line_kpi",
33108
33478
  line_id: lineId,
33109
33479
  date,
33110
- shift: selectedShift,
33480
+ shift_id: selectedShiftId,
33111
33481
  efficiency: shiftData.avg_efficiency || 0,
33112
33482
  underperforming_workspaces: shiftData.underperforming_workspaces || 0,
33113
33483
  total_workspaces: shiftData.total_workspaces || 0
33114
33484
  });
33115
33485
  const returnTo = `/kpis/${lineId}?tab=monthly_history&month=${month2}&year=${year2}`;
33116
33486
  if (onDateSelect) {
33117
- onDateSelect(date, shiftId);
33487
+ onDateSelect(date, selectedShiftId);
33118
33488
  } else {
33119
- router.navigate(`/kpis/${lineId}?date=${date}&shift=${shiftId}&sourceType=lineMonthlyHistory&returnTo=${encodeURIComponent(returnTo)}`);
33489
+ router.navigate(`/kpis/${lineId}?date=${date}&shift=${selectedShiftId}&sourceType=lineMonthlyHistory&returnTo=${encodeURIComponent(returnTo)}`);
33120
33490
  }
33121
33491
  }
33122
33492
  },
@@ -33140,14 +33510,28 @@ var LineHistoryCalendar = ({
33140
33510
  ] });
33141
33511
  };
33142
33512
  var LineHistoryCalendar_default = LineHistoryCalendar;
33513
+ var DEFAULT_PERFORMANCE_DATA = {
33514
+ avg_efficiency: 0,
33515
+ underperforming_workspaces: 0,
33516
+ total_workspaces: 0,
33517
+ hasData: false
33518
+ };
33519
+ var getShiftData2 = (day, shiftId) => {
33520
+ const shift = day.shifts[shiftId];
33521
+ if (shift) {
33522
+ return { ...shift, hasData: true };
33523
+ }
33524
+ return { ...DEFAULT_PERFORMANCE_DATA };
33525
+ };
33143
33526
  var LineMonthlyHistory = ({
33144
33527
  month,
33145
33528
  year,
33146
33529
  monthlyData = [],
33147
- underperformingWorkspaces = { dayShift: [], nightShift: [] },
33530
+ underperformingWorkspaces = {},
33148
33531
  lineId,
33149
- selectedShift = "day",
33532
+ selectedShiftId = 0,
33150
33533
  onShiftChange,
33534
+ availableShifts,
33151
33535
  onWorkspaceSelect,
33152
33536
  onCalendarDateSelect,
33153
33537
  onCalendarMonthChange,
@@ -33156,7 +33540,7 @@ var LineMonthlyHistory = ({
33156
33540
  const navigation = useNavigation();
33157
33541
  const averages = (monthlyData || []).reduce(
33158
33542
  (acc, day) => {
33159
- const shiftData = selectedShift === "day" ? day.dayShift : day.nightShift;
33543
+ const shiftData = getShiftData2(day, selectedShiftId);
33160
33544
  if (!shiftData || shiftData?.avg_efficiency < 10) {
33161
33545
  return acc;
33162
33546
  }
@@ -33230,28 +33614,22 @@ var LineMonthlyHistory = ({
33230
33614
  line_id: lineId,
33231
33615
  workspace_id: workspace.workspace_uuid,
33232
33616
  workspace_name: workspace.workspace_name,
33233
- selected_shift: selectedShift
33617
+ selected_shift_id: selectedShiftId
33234
33618
  });
33235
33619
  };
33236
33620
  return /* @__PURE__ */ jsxs("div", { className: clsx("flex flex-col gap-2 min-h-0 overflow-y-auto pb-6", className), children: [
33237
- /* @__PURE__ */ jsx("div", { className: "flex justify-center mb-4", children: /* @__PURE__ */ jsxs("div", { className: "flex gap-1 border border-gray-200 rounded-lg p-1 bg-gray-50", children: [
33238
- /* @__PURE__ */ jsx(
33239
- "button",
33240
- {
33241
- onClick: () => onShiftChange?.("day"),
33242
- 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"}`,
33243
- children: "Day Shift"
33244
- }
33245
- ),
33246
- /* @__PURE__ */ jsx(
33247
- "button",
33248
- {
33249
- onClick: () => onShiftChange?.("night"),
33250
- 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"}`,
33251
- children: "Night Shift"
33252
- }
33253
- )
33254
- ] }) }),
33621
+ /* @__PURE__ */ jsx("div", { className: "flex justify-center mb-4", children: /* @__PURE__ */ jsx("div", { className: "flex gap-1 border border-gray-200 rounded-lg p-1 bg-gray-50", children: (availableShifts && availableShifts.length > 0 ? availableShifts : [
33622
+ { id: 0, name: "Day Shift" },
33623
+ { id: 1, name: "Night Shift" }
33624
+ ]).sort((a, b) => a.id - b.id).map((shift) => /* @__PURE__ */ jsx(
33625
+ "button",
33626
+ {
33627
+ onClick: () => onShiftChange?.(shift.id),
33628
+ 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"}`,
33629
+ children: shift.name
33630
+ },
33631
+ shift.id
33632
+ )) }) }),
33255
33633
  /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 lg:grid-cols-2 gap-6 mt-6", children: [
33256
33634
  /* @__PURE__ */ jsxs("div", { className: "bg-white rounded-xl shadow-sm border border-gray-100 p-6", children: [
33257
33635
  /* @__PURE__ */ jsxs("h2", { className: "text-lg font-semibold text-gray-700 mb-4 text-center", children: [
@@ -33266,7 +33644,7 @@ var LineMonthlyHistory = ({
33266
33644
  month,
33267
33645
  year,
33268
33646
  lineId,
33269
- selectedShift,
33647
+ selectedShiftId,
33270
33648
  onDateSelect: onCalendarDateSelect
33271
33649
  }
33272
33650
  )
@@ -33303,7 +33681,7 @@ var LineMonthlyHistory = ({
33303
33681
  new Date(year, month).toLocaleString("default", { month: "long", year: "numeric" })
33304
33682
  ] }),
33305
33683
  /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
33306
- (selectedShift === "day" ? underperformingWorkspaces.dayShift : underperformingWorkspaces.nightShift)?.map((workspace) => /* @__PURE__ */ jsx(
33684
+ (underperformingWorkspaces[selectedShiftId] || []).map((workspace) => /* @__PURE__ */ jsx(
33307
33685
  "button",
33308
33686
  {
33309
33687
  onClick: () => handleWorkspaceClick(workspace),
@@ -33325,13 +33703,33 @@ var LineMonthlyHistory = ({
33325
33703
  },
33326
33704
  workspace.workspace_uuid
33327
33705
  )),
33328
- (!underperformingWorkspaces || (selectedShift === "day" ? !underperformingWorkspaces.dayShift?.length : !underperformingWorkspaces.nightShift?.length)) && /* @__PURE__ */ jsx("div", { className: "text-center text-gray-500 py-4", children: "No consistently underperforming workspaces found" })
33706
+ (!underperformingWorkspaces || !underperformingWorkspaces[selectedShiftId]?.length) && /* @__PURE__ */ jsx("div", { className: "text-center text-gray-500 py-4", children: "No consistently underperforming workspaces found" })
33329
33707
  ] })
33330
33708
  ] })
33331
33709
  ] })
33332
33710
  ] })
33333
33711
  ] });
33334
33712
  };
33713
+ var DEFAULT_PERFORMANCE_DATA2 = {
33714
+ avg_efficiency: 0,
33715
+ underperforming_workspaces: 0,
33716
+ total_workspaces: 0,
33717
+ hasData: false
33718
+ };
33719
+ var getLineShiftData2 = (day, shiftId) => {
33720
+ const shift = day.shifts[shiftId];
33721
+ if (shift) {
33722
+ return { ...shift, hasData: true };
33723
+ }
33724
+ return { ...DEFAULT_PERFORMANCE_DATA2 };
33725
+ };
33726
+ var getShiftDisplayName = (shiftId, availableShifts) => {
33727
+ const shift = availableShifts?.find((s) => s.id === shiftId);
33728
+ if (shift) return shift.name;
33729
+ if (shiftId === 0) return "Day Shift";
33730
+ if (shiftId === 1) return "Night Shift";
33731
+ return `Shift ${shiftId}`;
33732
+ };
33335
33733
  var LineMonthlyPdfGenerator = ({
33336
33734
  lineId,
33337
33735
  lineName,
@@ -33339,7 +33737,8 @@ var LineMonthlyPdfGenerator = ({
33339
33737
  underperformingWorkspaces,
33340
33738
  selectedMonth,
33341
33739
  selectedYear,
33342
- selectedShift,
33740
+ selectedShiftId,
33741
+ availableShifts,
33343
33742
  className
33344
33743
  }) => {
33345
33744
  const [isGenerating, setIsGenerating] = useState(false);
@@ -33351,7 +33750,7 @@ var LineMonthlyPdfGenerator = ({
33351
33750
  line_name: lineName,
33352
33751
  month: selectedMonth,
33353
33752
  year: selectedYear,
33354
- shift: selectedShift
33753
+ shift_id: selectedShiftId
33355
33754
  });
33356
33755
  const doc = new jsPDF$1();
33357
33756
  doc.setFontSize(14);
@@ -33381,7 +33780,7 @@ var LineMonthlyPdfGenerator = ({
33381
33780
  year: "numeric",
33382
33781
  timeZone: "Asia/Kolkata"
33383
33782
  });
33384
- const shiftType = selectedShift === "day" ? "Day Shift" : "Night Shift";
33783
+ const shiftType = getShiftDisplayName(selectedShiftId, availableShifts);
33385
33784
  doc.text(`${monthName}`, 20, 55);
33386
33785
  doc.text(`${shiftType}`, 20, 63);
33387
33786
  const startDate = new Date(selectedYear, selectedMonth, 1);
@@ -33410,7 +33809,7 @@ var LineMonthlyPdfGenerator = ({
33410
33809
  return date.getMonth() === selectedMonth && date.getFullYear() === selectedYear;
33411
33810
  });
33412
33811
  const validShifts = validDays.map(
33413
- (day) => selectedShift === "day" ? day.dayShift : day.nightShift
33812
+ (day) => getLineShiftData2(day, selectedShiftId)
33414
33813
  ).filter((shift) => shift.avg_efficiency > 0);
33415
33814
  const monthlyMetrics = validShifts.length > 0 ? {
33416
33815
  avgEfficiency: validShifts.reduce((sum, shift) => sum + shift.avg_efficiency, 0) / validShifts.length,
@@ -33492,8 +33891,8 @@ var LineMonthlyPdfGenerator = ({
33492
33891
  const recentDays = validDays.slice(-10).reverse();
33493
33892
  recentDays.forEach((dayData, index) => {
33494
33893
  if (yPos > 245) return;
33495
- const shift = selectedShift === "day" ? dayData.dayShift : dayData.nightShift;
33496
- if (shift.avg_efficiency <= 0) return;
33894
+ const shift = getLineShiftData2(dayData, selectedShiftId);
33895
+ if (shift.avg_efficiency <= 0 || !shift.hasData) return;
33497
33896
  if (index % 2 === 0) {
33498
33897
  doc.setFillColor(252, 252, 252);
33499
33898
  doc.roundedRect(20, yPos - 4, 170, 7, 1, 1, "F");
@@ -33527,7 +33926,7 @@ var LineMonthlyPdfGenerator = ({
33527
33926
  doc.text("No daily data available for this month", 25, 200);
33528
33927
  doc.setTextColor(0, 0, 0);
33529
33928
  }
33530
- const poorestWorkspaces = selectedShift === "day" ? underperformingWorkspaces.dayShift : underperformingWorkspaces.nightShift;
33929
+ const poorestWorkspaces = underperformingWorkspaces[selectedShiftId] || [];
33531
33930
  if (poorestWorkspaces && poorestWorkspaces.length > 0) {
33532
33931
  doc.addPage();
33533
33932
  doc.setFontSize(14);
@@ -33655,6 +34054,7 @@ Underperforming Workspaces: ${lineInfo.metrics.underperforming_workspaces} / ${l
33655
34054
  var LinePdfGenerator = ({
33656
34055
  lineInfo,
33657
34056
  workspaceData,
34057
+ shiftName,
33658
34058
  className
33659
34059
  }) => {
33660
34060
  const [isGenerating, setIsGenerating] = useState(false);
@@ -33706,7 +34106,8 @@ var LinePdfGenerator = ({
33706
34106
  doc.text(lineInfo.line_name, 20, 30);
33707
34107
  doc.setFontSize(14);
33708
34108
  doc.setFont("helvetica", "normal");
33709
- const shiftType = lineInfo.shift_id === 0 ? "Day Shift" : "Night Shift";
34109
+ const rawShiftType = shiftName || (lineInfo.shift_id === 0 ? "Day" : lineInfo.shift_id === 1 ? "Night" : `Shift ${lineInfo.shift_id}`);
34110
+ const shiftType = rawShiftType.toLowerCase().includes("shift") ? rawShiftType : `${rawShiftType} Shift`;
33710
34111
  const date = new Date(lineInfo.date).toLocaleDateString("en-IN", {
33711
34112
  weekday: "long",
33712
34113
  day: "numeric",
@@ -34381,9 +34782,10 @@ var WorkspaceHistoryCalendar = ({
34381
34782
  month,
34382
34783
  year,
34383
34784
  workspaceId,
34384
- selectedShift = "day",
34785
+ selectedShiftId = 0,
34385
34786
  onMonthNavigate,
34386
34787
  onShiftChange,
34788
+ availableShifts,
34387
34789
  className
34388
34790
  }) => {
34389
34791
  const { dateTimeConfig } = useDashboardConfig();
@@ -34448,7 +34850,7 @@ var WorkspaceHistoryCalendar = ({
34448
34850
  if (compareDate > istNow) {
34449
34851
  return [];
34450
34852
  }
34451
- const shiftData = selectedShift === "day" ? day.dayShift : day.nightShift;
34853
+ const shiftData = getShiftData(day, selectedShiftId);
34452
34854
  if (hasRealData(shiftData)) {
34453
34855
  return [shiftData];
34454
34856
  }
@@ -34465,31 +34867,32 @@ var WorkspaceHistoryCalendar = ({
34465
34867
  badDaysCount: badShiftsCount,
34466
34868
  totalDays: validShifts.length
34467
34869
  };
34468
- }, [data, month, year, configuredTimezone, selectedShift]);
34469
- const handleDayClick = useCallback((day, shift) => {
34870
+ }, [data, month, year, configuredTimezone, selectedShiftId]);
34871
+ const handleDayClick = useCallback((day, shiftId) => {
34470
34872
  if (!day || isFutureDate(day.date)) return;
34471
34873
  const year2 = day.date.getFullYear();
34472
34874
  const month2 = String(day.date.getMonth() + 1).padStart(2, "0");
34473
34875
  const dayOfMonth = String(day.date.getDate()).padStart(2, "0");
34474
34876
  const formattedDate = `${year2}-${month2}-${dayOfMonth}`;
34475
- const shiftData = shift === "day" ? day.dayShift : day.nightShift;
34877
+ const shiftData = getShiftData(day, shiftId);
34476
34878
  trackCoreEvent("Workspace Monthly History Day Clicked", {
34477
34879
  source: "workspace_detail",
34478
34880
  workspace_id: workspaceId,
34479
34881
  date: formattedDate,
34882
+ shift_id: shiftId,
34480
34883
  efficiency: shiftData.efficiency,
34481
34884
  output: shiftData.output,
34482
34885
  cycle_time: shiftData.cycleTime
34483
34886
  });
34484
- onDateSelect(formattedDate);
34887
+ onDateSelect(formattedDate, shiftId);
34485
34888
  }, [workspaceId, onDateSelect]);
34486
- const handleShiftChange = useCallback((shift) => {
34889
+ const handleShiftChange = useCallback((shiftId) => {
34487
34890
  trackCoreEvent("Workspace Calendar Shift Changed", {
34488
34891
  workspace_id: workspaceId,
34489
- new_shift: shift
34892
+ new_shift_id: shiftId
34490
34893
  });
34491
34894
  if (onShiftChange) {
34492
- onShiftChange(shift);
34895
+ onShiftChange(shiftId);
34493
34896
  }
34494
34897
  }, [workspaceId, onShiftChange]);
34495
34898
  const isCurrentDate = useCallback((date) => {
@@ -34570,13 +34973,13 @@ var WorkspaceHistoryCalendar = ({
34570
34973
  }
34571
34974
  return /* @__PURE__ */ 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__ */ jsx("div", { className: "p-1 sm:p-2", children: /* @__PURE__ */ jsx("div", { className: `text-xs sm:text-sm lg:text-base font-medium ${textColor} ${isToday ? "text-blue-500" : ""}`, children: dayNumber }) }) });
34572
34975
  }
34573
- const shiftData = selectedShift === "day" ? day.dayShift : day.nightShift;
34976
+ const shiftData = getShiftData(day, selectedShiftId);
34574
34977
  const hasData = hasRealData(shiftData);
34575
34978
  return /* @__PURE__ */ jsx(
34576
34979
  "div",
34577
34980
  {
34578
34981
  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"}`,
34579
- onClick: () => !isFuture && hasData && handleDayClick(day, selectedShift),
34982
+ onClick: () => !isFuture && hasData && handleDayClick(day, selectedShiftId),
34580
34983
  children: /* @__PURE__ */ jsxs("div", { className: `
34581
34984
  ${getPerformanceColor(shiftData.efficiency, day.date, hasData)}
34582
34985
  rounded-lg h-full p-1 sm:p-2 relative ${animationComplete ? "transition-all duration-300 ease-in-out" : ""} shadow-sm
@@ -34590,31 +34993,25 @@ var WorkspaceHistoryCalendar = ({
34590
34993
  ] })
34591
34994
  }
34592
34995
  );
34593
- }, [selectedShift, isCurrentDate, isFutureDate, getPerformanceColor, handleDayClick, year, month, configuredTimezone, animationComplete, hasRealData]);
34996
+ }, [selectedShiftId, isCurrentDate, isFutureDate, getPerformanceColor, handleDayClick, year, month, configuredTimezone, animationComplete, hasRealData]);
34594
34997
  return /* @__PURE__ */ jsxs("div", { className: `calendar-wrapper space-y-6 ${className || ""} ${animationComplete ? "animation-complete" : ""}`, children: [
34595
34998
  /* @__PURE__ */ jsx("style", { dangerouslySetInnerHTML: { __html: styles } }),
34596
- /* @__PURE__ */ jsx("div", { className: "flex justify-center", children: /* @__PURE__ */ jsxs("div", { className: "flex gap-1 border border-gray-200 rounded-lg p-1 bg-gray-50", children: [
34597
- /* @__PURE__ */ jsx(
34598
- "button",
34599
- {
34600
- onClick: () => handleShiftChange("day"),
34601
- 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" : ""}`}`,
34602
- children: "Day Shift"
34603
- }
34604
- ),
34605
- /* @__PURE__ */ jsx(
34606
- "button",
34607
- {
34608
- onClick: () => handleShiftChange("night"),
34609
- 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" : ""}`}`,
34610
- children: "Night Shift"
34611
- }
34612
- )
34613
- ] }) }),
34999
+ /* @__PURE__ */ jsx("div", { className: "flex justify-center", children: /* @__PURE__ */ jsx("div", { className: "flex gap-1 border border-gray-200 rounded-lg p-1 bg-gray-50", children: (availableShifts && availableShifts.length > 0 ? availableShifts : [
35000
+ { id: 0, name: "Day Shift" },
35001
+ { id: 1, name: "Night Shift" }
35002
+ ]).sort((a, b) => a.id - b.id).map((shift) => /* @__PURE__ */ jsx(
35003
+ "button",
35004
+ {
35005
+ onClick: () => handleShiftChange(shift.id),
35006
+ 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" : ""}`}`,
35007
+ children: shift.name
35008
+ },
35009
+ shift.id
35010
+ )) }) }),
34614
35011
  /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 lg:grid-cols-2 gap-4 lg:gap-8", children: [
34615
35012
  /* @__PURE__ */ 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: [
34616
35013
  /* @__PURE__ */ jsxs("div", { className: "mb-3 sm:mb-4 lg:mb-6", children: [
34617
- /* @__PURE__ */ jsx("h3", { className: "font-semibold text-gray-900 text-base sm:text-lg", children: selectedShift === "day" ? "Day Shifts" : "Night Shifts" }),
35014
+ /* @__PURE__ */ 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" }),
34618
35015
  /* @__PURE__ */ jsx("p", { className: "text-xs sm:text-sm text-gray-500 mt-1", children: "Calendar view of daily performance" })
34619
35016
  ] }),
34620
35017
  /* @__PURE__ */ jsxs("div", { className: "grid gap-3 sm:gap-4 lg:gap-6", children: [
@@ -34630,7 +35027,7 @@ var WorkspaceHistoryCalendar = ({
34630
35027
  /* @__PURE__ */ jsxs("div", { className: "mb-3 sm:mb-4 lg:mb-6", children: [
34631
35028
  /* @__PURE__ */ jsxs("h3", { className: "font-semibold text-gray-900 text-base sm:text-lg", children: [
34632
35029
  "Monthly Summary - ",
34633
- selectedShift === "day" ? "Day Shift" : "Night Shift"
35030
+ availableShifts?.find((s) => s.id === selectedShiftId)?.name || (selectedShiftId === 0 ? "Day Shift" : selectedShiftId === 1 ? "Night Shift" : `Shift ${selectedShiftId}`)
34634
35031
  ] }),
34635
35032
  /* @__PURE__ */ jsx("p", { className: "text-xs sm:text-sm text-gray-500 mt-1", children: "Overview of monthly performance metrics" })
34636
35033
  ] }),
@@ -34704,10 +35101,11 @@ var WorkspaceMonthlyHistory = ({
34704
35101
  month,
34705
35102
  year,
34706
35103
  workspaceId,
34707
- selectedShift = "day",
35104
+ selectedShiftId = 0,
34708
35105
  onDateSelect,
34709
35106
  onMonthNavigate,
34710
35107
  onShiftChange,
35108
+ availableShifts,
34711
35109
  monthlyDataLoading = false,
34712
35110
  className = ""
34713
35111
  }) => {
@@ -34725,7 +35123,7 @@ var WorkspaceMonthlyHistory = ({
34725
35123
  const date = new Date(d.date);
34726
35124
  return date.getDate() === day;
34727
35125
  });
34728
- const shiftData = dayData ? selectedShift === "day" ? dayData.dayShift : dayData.nightShift : null;
35126
+ const shiftData = dayData ? getShiftData(dayData, selectedShiftId) : null;
34729
35127
  const idealOutput = shiftData ? shiftData.idealOutput : 0;
34730
35128
  if (idealOutput > 0) {
34731
35129
  lastSetTarget = idealOutput;
@@ -34737,7 +35135,7 @@ var WorkspaceMonthlyHistory = ({
34737
35135
  const date = new Date(d.date);
34738
35136
  return date.getDate() === day;
34739
35137
  });
34740
- const shiftData = dayData ? selectedShift === "day" ? dayData.dayShift : dayData.nightShift : null;
35138
+ const shiftData = dayData ? getShiftData(dayData, selectedShiftId) : null;
34741
35139
  const output = shiftData && hasRealData(shiftData) ? shiftData.output : 0;
34742
35140
  const idealOutput = shiftData ? shiftData.idealOutput : 0;
34743
35141
  if (output > maxOutput) maxOutput = output;
@@ -34759,7 +35157,7 @@ var WorkspaceMonthlyHistory = ({
34759
35157
  const calculatedMax = Math.max(maxOutput, lastSetTarget);
34760
35158
  const yAxisMax = calculatedMax > 0 ? calculatedMax * 1.1 : 100;
34761
35159
  return { data: dailyData, maxOutput, lastSetTarget, yAxisMax };
34762
- }, [data, month, year, selectedShift]);
35160
+ }, [data, month, year, selectedShiftId]);
34763
35161
  const yAxisTicks = useMemo(() => {
34764
35162
  const max = chartData.yAxisMax;
34765
35163
  const target = chartData.lastSetTarget;
@@ -34782,7 +35180,7 @@ var WorkspaceMonthlyHistory = ({
34782
35180
  return Array.from(new Set(ticks)).filter((v) => v >= 0 && v <= max).sort((a, b) => a - b);
34783
35181
  }, [chartData.yAxisMax, chartData.lastSetTarget]);
34784
35182
  const pieChartData = useMemo(() => {
34785
- const validShifts = data.map((d) => selectedShift === "day" ? d.dayShift : d.nightShift).filter(hasRealData);
35183
+ const validShifts = data.map((d) => getShiftData(d, selectedShiftId)).filter(hasRealData);
34786
35184
  if (validShifts.length === 0) return [];
34787
35185
  const totalIdleTime = validShifts.reduce((sum, shift) => sum + shift.idleTime, 0);
34788
35186
  const totalShiftTime = validShifts.length * 8 * 3600;
@@ -34791,9 +35189,9 @@ var WorkspaceMonthlyHistory = ({
34791
35189
  { name: "Productive", value: Math.round(activeTime / totalShiftTime * 100) },
34792
35190
  { name: "Idle", value: Math.round(totalIdleTime / totalShiftTime * 100) }
34793
35191
  ];
34794
- }, [data, selectedShift]);
35192
+ }, [data, selectedShiftId]);
34795
35193
  const metrics2 = useMemo(() => {
34796
- const validShifts = data.map((d) => selectedShift === "day" ? d.dayShift : d.nightShift).filter(hasRealData);
35194
+ const validShifts = data.map((d) => getShiftData(d, selectedShiftId)).filter(hasRealData);
34797
35195
  if (validShifts.length === 0) return null;
34798
35196
  const totalEfficiency = validShifts.reduce((sum, shift) => sum + shift.efficiency, 0);
34799
35197
  const totalCycleTime = validShifts.reduce((sum, shift) => sum + shift.cycleTime, 0);
@@ -34813,7 +35211,7 @@ var WorkspaceMonthlyHistory = ({
34813
35211
  totalOutput,
34814
35212
  avgIdleTime: Math.round(totalIdleTime / validShifts.length)
34815
35213
  };
34816
- }, [data, selectedShift]);
35214
+ }, [data, selectedShiftId]);
34817
35215
  const calendarData = useMemo(() => {
34818
35216
  const startOfMonth = new Date(year, month, 1);
34819
35217
  const endOfMonth = new Date(year, month + 1, 0);
@@ -34840,17 +35238,17 @@ var WorkspaceMonthlyHistory = ({
34840
35238
  source: "monthly_history",
34841
35239
  workspace_id: workspaceId,
34842
35240
  date: formattedDate,
34843
- shift: selectedShift
35241
+ shift_id: selectedShiftId
34844
35242
  });
34845
- onDateSelect(formattedDate, selectedShift);
34846
- }, [workspaceId, selectedShift, onDateSelect]);
34847
- const handleShiftChange = useCallback((shift) => {
35243
+ onDateSelect(formattedDate, selectedShiftId);
35244
+ }, [workspaceId, selectedShiftId, onDateSelect]);
35245
+ const handleShiftChange = useCallback((shiftId) => {
34848
35246
  trackCoreEvent("Workspace Monthly History Shift Changed", {
34849
35247
  workspace_id: workspaceId,
34850
- new_shift: shift
35248
+ new_shift_id: shiftId
34851
35249
  });
34852
35250
  if (onShiftChange) {
34853
- onShiftChange(shift);
35251
+ onShiftChange(shiftId);
34854
35252
  }
34855
35253
  }, [workspaceId, onShiftChange]);
34856
35254
  if (monthlyDataLoading) {
@@ -34863,24 +35261,18 @@ var WorkspaceMonthlyHistory = ({
34863
35261
  ) });
34864
35262
  }
34865
35263
  return /* @__PURE__ */ jsxs("div", { className: `flex flex-col gap-2 min-h-0 overflow-y-auto pb-6 ${className}`, children: [
34866
- /* @__PURE__ */ jsx("div", { className: "flex justify-center mb-4", children: /* @__PURE__ */ jsxs("div", { className: "flex gap-1 border border-gray-200 rounded-lg p-1 bg-gray-50", children: [
34867
- /* @__PURE__ */ jsx(
34868
- "button",
34869
- {
34870
- onClick: () => handleShiftChange("day"),
34871
- 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"}`,
34872
- children: "Day Shift"
34873
- }
34874
- ),
34875
- /* @__PURE__ */ jsx(
34876
- "button",
34877
- {
34878
- onClick: () => handleShiftChange("night"),
34879
- 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"}`,
34880
- children: "Night Shift"
34881
- }
34882
- )
34883
- ] }) }),
35264
+ /* @__PURE__ */ jsx("div", { className: "flex justify-center mb-4", children: /* @__PURE__ */ jsx("div", { className: "flex gap-1 border border-gray-200 rounded-lg p-1 bg-gray-50", children: (availableShifts && availableShifts.length > 0 ? availableShifts : [
35265
+ { id: 0, name: "Day Shift" },
35266
+ { id: 1, name: "Night Shift" }
35267
+ ]).sort((a, b) => a.id - b.id).map((shift) => /* @__PURE__ */ jsx(
35268
+ "button",
35269
+ {
35270
+ onClick: () => handleShiftChange(shift.id),
35271
+ 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"}`,
35272
+ children: shift.name
35273
+ },
35274
+ shift.id
35275
+ )) }) }),
34884
35276
  /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 lg:grid-cols-2 gap-6 mt-6", children: [
34885
35277
  /* @__PURE__ */ jsxs("div", { className: "bg-white rounded-xl shadow-sm border border-gray-100 p-6", children: [
34886
35278
  /* @__PURE__ */ jsxs("div", { className: "flex justify-center items-center mb-6 space-x-4", children: [
@@ -34944,7 +35336,7 @@ var WorkspaceMonthlyHistory = ({
34944
35336
  if (!dayNumber || dayNumber > new Date(year, month + 1, 0).getDate()) {
34945
35337
  return /* @__PURE__ */ jsx("div", { className: "aspect-square relative", children: /* @__PURE__ */ jsx("div", { className: "h-full border border-gray-100 dark:border-gray-700 rounded-lg bg-gray-50 dark:bg-gray-800" }) }, index);
34946
35338
  }
34947
- const shiftData = day ? selectedShift === "day" ? day.dayShift : day.nightShift : null;
35339
+ const shiftData = day ? getShiftData(day, selectedShiftId) : null;
34948
35340
  const hasData = shiftData ? hasRealData(shiftData) : false;
34949
35341
  const isToday = (/* @__PURE__ */ new Date()).getDate() === dayNumber && (/* @__PURE__ */ new Date()).getMonth() === month && (/* @__PURE__ */ new Date()).getFullYear() === year;
34950
35342
  const isFuture = new Date(year, month, dayNumber) > /* @__PURE__ */ new Date();
@@ -35271,7 +35663,8 @@ var WorkspacePdfGenerator = ({ workspace, className }) => {
35271
35663
  month: "long",
35272
35664
  timeZone: "Asia/Kolkata"
35273
35665
  });
35274
- const shiftType = "Day Shift";
35666
+ const rawShiftType = workspace.shift_type || (workspace.shift_id === 0 ? "Day" : workspace.shift_id === 1 ? "Night" : `Shift ${workspace.shift_id}`);
35667
+ const shiftType = rawShiftType.toLowerCase().includes("shift") ? rawShiftType : `${rawShiftType} Shift`;
35275
35668
  doc.text(`${date}`, 20, 63);
35276
35669
  doc.text(`${shiftType}`, 20, 71);
35277
35670
  const currentTime = (/* @__PURE__ */ new Date()).toLocaleTimeString("en-IN", {
@@ -35421,13 +35814,21 @@ var WorkspacePdfGenerator = ({ workspace, className }) => {
35421
35814
  }
35422
35815
  );
35423
35816
  };
35817
+ var getShiftDisplayName2 = (shiftId, availableShifts) => {
35818
+ const shift = availableShifts?.find((s) => s.id === shiftId);
35819
+ if (shift) return shift.name;
35820
+ if (shiftId === 0) return "Day Shift";
35821
+ if (shiftId === 1) return "Night Shift";
35822
+ return `Shift ${shiftId}`;
35823
+ };
35424
35824
  var WorkspaceMonthlyPdfGenerator = ({
35425
35825
  workspaceId,
35426
35826
  workspaceName,
35427
35827
  monthlyData,
35428
35828
  selectedMonth,
35429
35829
  selectedYear,
35430
- selectedShift,
35830
+ selectedShiftId,
35831
+ availableShifts,
35431
35832
  className
35432
35833
  }) => {
35433
35834
  const [isGenerating, setIsGenerating] = useState(false);
@@ -35439,7 +35840,7 @@ var WorkspaceMonthlyPdfGenerator = ({
35439
35840
  workspace_name: workspaceName,
35440
35841
  month: selectedMonth,
35441
35842
  year: selectedYear,
35442
- shift: selectedShift
35843
+ shift_id: selectedShiftId
35443
35844
  });
35444
35845
  const doc = new jsPDF$1();
35445
35846
  doc.setFontSize(14);
@@ -35473,7 +35874,7 @@ var WorkspaceMonthlyPdfGenerator = ({
35473
35874
  year: "numeric",
35474
35875
  timeZone: "Asia/Kolkata"
35475
35876
  });
35476
- const shiftType = selectedShift === "day" ? "Day Shift" : "Night Shift";
35877
+ const shiftType = getShiftDisplayName2(selectedShiftId, availableShifts);
35477
35878
  doc.text(`${monthName}`, 20, 65);
35478
35879
  doc.text(`${shiftType}`, 20, 73);
35479
35880
  const startDate = new Date(selectedYear, selectedMonth, 1);
@@ -35502,7 +35903,7 @@ var WorkspaceMonthlyPdfGenerator = ({
35502
35903
  return date.getMonth() === selectedMonth && date.getFullYear() === selectedYear;
35503
35904
  });
35504
35905
  const validShifts = validDays.map(
35505
- (day) => selectedShift === "day" ? day.dayShift : day.nightShift
35906
+ (day) => getShiftData(day, selectedShiftId)
35506
35907
  ).filter((shift) => shift.efficiency > 0);
35507
35908
  const monthlyMetrics = validShifts.length > 0 ? {
35508
35909
  avgEfficiency: validShifts.reduce((sum, shift) => sum + shift.efficiency, 0) / validShifts.length,
@@ -35590,7 +35991,7 @@ var WorkspaceMonthlyPdfGenerator = ({
35590
35991
  const recentDays = validDays.slice(-10).reverse();
35591
35992
  recentDays.forEach((dayData, index) => {
35592
35993
  if (yPos > 260) return;
35593
- const shift = selectedShift === "day" ? dayData.dayShift : dayData.nightShift;
35994
+ const shift = getShiftData(dayData, selectedShiftId);
35594
35995
  if (shift.efficiency <= 0) return;
35595
35996
  if (index % 2 === 0) {
35596
35997
  doc.setFillColor(252, 252, 252);
@@ -36977,19 +37378,26 @@ var HealthStatusGrid = ({
36977
37378
  };
36978
37379
  var Timer2 = Timer_default;
36979
37380
  var DashboardHeader = memo(({ lineTitle, className = "", headerControls, lineId }) => {
36980
- const { shiftConfig } = useDynamicShiftConfig(lineId);
37381
+ const { shiftConfig, isLoading: isShiftConfigLoading } = useDynamicShiftConfig(lineId);
36981
37382
  const timezone = useAppTimezone();
36982
37383
  const getShiftName = () => {
36983
37384
  const currentShift = getCurrentShift(timezone, shiftConfig);
36984
- return currentShift.shiftId === 0 ? "Day" : "Night";
37385
+ const rawName = currentShift.shiftName || "Day";
37386
+ return rawName.toLowerCase().includes("shift") ? rawName : `${rawName} Shift`;
36985
37387
  };
36986
- const getShiftIcon = () => {
36987
- const shift = getShiftName();
36988
- if (shift === "Day") {
37388
+ const getShiftIcon2 = () => {
37389
+ const currentShift = getCurrentShift(timezone, shiftConfig);
37390
+ const shiftName = (currentShift.shiftName || "").toLowerCase();
37391
+ if (shiftName.includes("day") || shiftName.includes("morning") || currentShift.shiftId === 0) {
36989
37392
  return /* @__PURE__ */ jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ 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" }) });
36990
- } else {
37393
+ }
37394
+ if (shiftName.includes("afternoon") || shiftName.includes("noon") || shiftName.includes("midday")) {
37395
+ return /* @__PURE__ */ jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ 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" }) });
37396
+ }
37397
+ if (shiftName.includes("night") || shiftName.includes("evening") || currentShift.shiftId === 1) {
36991
37398
  return /* @__PURE__ */ jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ 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" }) });
36992
37399
  }
37400
+ return /* @__PURE__ */ jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" }) });
36993
37401
  };
36994
37402
  return /* @__PURE__ */ 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: [
36995
37403
  /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
@@ -36999,13 +37407,10 @@ var DashboardHeader = memo(({ lineTitle, className = "", headerControls, lineId
36999
37407
  ] }),
37000
37408
  /* @__PURE__ */ jsxs("div", { className: "mt-0.5 sm:mt-2 inline-flex flex-wrap items-center gap-1.5 sm:gap-3", children: [
37001
37409
  /* @__PURE__ */ jsx("div", { className: "text-[10px] sm:text-xs md:text-sm font-medium text-gray-500 sm:text-gray-600 whitespace-nowrap", children: /* @__PURE__ */ jsx(Timer2, {}) }),
37002
- /* @__PURE__ */ jsxs("div", { className: "inline-flex items-center gap-0.5 sm:gap-1", children: [
37003
- /* @__PURE__ */ jsx("div", { className: "text-gray-500 sm:text-gray-600 scale-90 sm:scale-100", children: getShiftIcon() }),
37004
- /* @__PURE__ */ jsxs("span", { className: "text-[10px] sm:text-xs md:text-sm font-medium text-gray-500 sm:text-gray-600 whitespace-nowrap", children: [
37005
- getShiftName(),
37006
- " Shift"
37007
- ] })
37008
- ] })
37410
+ /* @__PURE__ */ jsx("div", { className: "inline-flex items-center gap-0.5 sm:gap-1", children: isShiftConfigLoading ? /* @__PURE__ */ jsx("div", { className: "h-4 w-16 sm:w-20 bg-gray-200 rounded animate-pulse" }) : /* @__PURE__ */ jsxs(Fragment, { children: [
37411
+ /* @__PURE__ */ jsx("div", { className: "text-gray-500 sm:text-gray-600 scale-90 sm:scale-100", children: getShiftIcon2() }),
37412
+ /* @__PURE__ */ jsx("span", { className: "text-[10px] sm:text-xs md:text-sm font-medium text-gray-500 sm:text-gray-600 whitespace-nowrap", children: getShiftName() })
37413
+ ] }) })
37009
37414
  ] })
37010
37415
  ] }),
37011
37416
  headerControls && /* @__PURE__ */ jsx("div", { className: "flex items-center gap-1.5 sm:gap-3 md:gap-4 w-full sm:w-auto justify-end", children: headerControls })
@@ -42022,18 +42427,23 @@ var FactoryView = ({
42022
42427
  fetchHourlyData();
42023
42428
  }
42024
42429
  }, [supabase, lineDataHooks, effectiveLineIds, lineNames, factoryName, timezone, shiftConfig, productIds]);
42430
+ const getCurrentShiftInfo = () => {
42431
+ return getCurrentShift(timezone, shiftConfig);
42432
+ };
42025
42433
  const getShiftName = () => {
42026
- const now2 = /* @__PURE__ */ new Date();
42027
- const currentHour = now2.getHours();
42028
- return currentHour >= 6 && currentHour < 18 ? "Day" : "Night";
42434
+ const currentShift = getCurrentShiftInfo();
42435
+ return (currentShift.shiftName || "Day").replace(/ Shift$/i, "");
42029
42436
  };
42030
- const getShiftIcon = () => {
42031
- const shift = getShiftName();
42032
- if (shift === "Day") {
42437
+ const getShiftIcon2 = () => {
42438
+ const currentShift = getCurrentShiftInfo();
42439
+ const shiftNameLower = (currentShift.shiftName || "").toLowerCase();
42440
+ if (shiftNameLower.includes("day") || shiftNameLower.includes("morning") || currentShift.shiftId === 0) {
42033
42441
  return /* @__PURE__ */ jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ 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" }) });
42034
- } else {
42442
+ }
42443
+ if (shiftNameLower.includes("night") || shiftNameLower.includes("evening") || currentShift.shiftId === 1) {
42035
42444
  return /* @__PURE__ */ jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ 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" }) });
42036
42445
  }
42446
+ return /* @__PURE__ */ jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" }) });
42037
42447
  };
42038
42448
  if (loading || lineDataHooks.some((hookData) => hookData.hook.loading)) {
42039
42449
  return /* @__PURE__ */ jsx("div", { className: "p-4", children: /* @__PURE__ */ jsxs("div", { className: "animate-pulse space-y-4", children: [
@@ -42062,7 +42472,7 @@ var FactoryView = ({
42062
42472
  " IST"
42063
42473
  ] }),
42064
42474
  /* @__PURE__ */ jsxs("div", { className: "inline-flex items-center gap-1", children: [
42065
- /* @__PURE__ */ jsx("div", { className: "text-gray-600", children: getShiftIcon() }),
42475
+ /* @__PURE__ */ jsx("div", { className: "text-gray-600", children: getShiftIcon2() }),
42066
42476
  /* @__PURE__ */ jsxs("span", { className: "text-sm font-medium text-gray-600", children: [
42067
42477
  getShiftName(),
42068
42478
  " Shift"
@@ -43562,8 +43972,8 @@ var KPIDetailView = ({
43562
43972
  return (/* @__PURE__ */ new Date()).getFullYear();
43563
43973
  });
43564
43974
  const [monthlyData, setMonthlyData] = useState([]);
43565
- const [underperformingWorkspaces, setUnderperformingWorkspaces] = useState({ dayShift: [], nightShift: [] });
43566
- const [selectedShift, setSelectedShift] = useState("day");
43975
+ const [underperformingWorkspaces, setUnderperformingWorkspaces] = useState({});
43976
+ const [selectedShiftId, setSelectedShiftId] = useState(0);
43567
43977
  const [showLineDataNotFound, setShowLineDataNotFound] = useState(false);
43568
43978
  const navigation = useNavigation(navigate);
43569
43979
  const handleNavigate = navigate || navigation.navigate;
@@ -43593,20 +44003,22 @@ var KPIDetailView = ({
43593
44003
  setActiveTab("overview");
43594
44004
  }
43595
44005
  }, [urlDate, urlShift, urlTab]);
44006
+ const { shiftConfig, isLoading: isShiftConfigLoading } = useDynamicShiftConfig(lineId);
43596
44007
  const getShiftName = useCallback((shiftId) => {
43597
- return shiftId === 0 ? "Day" : "Night";
43598
- }, []);
43599
- const getShiftIcon = useCallback((shiftId) => {
43600
- const shift = getShiftName(shiftId);
43601
- if (shift === "Day") {
44008
+ return getShiftNameById(shiftId, configuredTimezone, shiftConfig);
44009
+ }, [configuredTimezone, shiftConfig]);
44010
+ const getShiftIcon2 = useCallback((shiftId) => {
44011
+ if (shiftId === 0) {
43602
44012
  return /* @__PURE__ */ jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ 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" }) });
43603
- } else {
44013
+ }
44014
+ if (shiftId === 1) {
43604
44015
  return /* @__PURE__ */ jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ 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" }) });
43605
44016
  }
43606
- }, [getShiftName]);
44017
+ return /* @__PURE__ */ jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" }) });
44018
+ }, []);
43607
44019
  const getDaysDifference2 = useCallback((date) => {
43608
44020
  const compareDate = new Date(date);
43609
- const shiftStartTime = dashboardConfig.shiftConfig?.dayShift?.startTime || "06:00";
44021
+ const shiftStartTime = shiftConfig?.dayShift?.startTime || shiftConfig?.shifts?.[0]?.startTime || "06:00";
43610
44022
  const operationalTodayString = getOperationalDate(configuredTimezone, /* @__PURE__ */ new Date(), shiftStartTime);
43611
44023
  const operationalTodayDate = new Date(operationalTodayString);
43612
44024
  const compareDateInZone = new Date(compareDate.toLocaleString("en-US", { timeZone: configuredTimezone }));
@@ -43620,7 +44032,7 @@ var KPIDetailView = ({
43620
44032
  if (diffDays < -1) return `${Math.abs(diffDays)} days ago`;
43621
44033
  if (diffDays > 1) return `${diffDays} days ahead`;
43622
44034
  return "Today";
43623
- }, [configuredTimezone, dashboardConfig.shiftConfig]);
44035
+ }, [configuredTimezone, shiftConfig]);
43624
44036
  const {
43625
44037
  metrics: metrics2,
43626
44038
  lineDetails,
@@ -43630,7 +44042,9 @@ var KPIDetailView = ({
43630
44042
  } = useRealtimeLineMetrics({
43631
44043
  lineId,
43632
44044
  date: typeof urlDate === "string" ? urlDate : void 0,
43633
- shiftId: parsedShiftId
44045
+ shiftId: parsedShiftId,
44046
+ enabled: !isShiftConfigLoading
44047
+ // Pass enabled flag to useRealtimeLineMetrics if supported, or we need to add it
43634
44048
  });
43635
44049
  const {
43636
44050
  workspaces,
@@ -43639,7 +44053,9 @@ var KPIDetailView = ({
43639
44053
  refreshWorkspaces
43640
44054
  } = useLineWorkspaceMetrics(lineId, {
43641
44055
  initialDate: typeof urlDate === "string" ? urlDate : void 0,
43642
- initialShiftId: parsedShiftId
44056
+ initialShiftId: parsedShiftId,
44057
+ enabled: !isShiftConfigLoading
44058
+ // Pass enabled flag to useLineWorkspaceMetrics if supported, or we need to add it
43643
44059
  });
43644
44060
  useEffect(() => {
43645
44061
  if (activeTab === "monthly_history" && lineId) {
@@ -43652,7 +44068,9 @@ var KPIDetailView = ({
43652
44068
  dashboardService.getUnderperformingWorkspaces(
43653
44069
  lineId,
43654
44070
  currentMonth,
43655
- currentYear
44071
+ currentYear,
44072
+ shiftConfig?.shifts?.map((s) => s.shiftId)
44073
+ // Pass dynamic shift IDs
43656
44074
  )
43657
44075
  ]).then(([monthlyMetrics, underperformingData]) => {
43658
44076
  console.log("Fetched monthly metrics data:", monthlyMetrics);
@@ -43664,18 +44082,8 @@ var KPIDetailView = ({
43664
44082
  if (!dayData) {
43665
44083
  dayData = {
43666
44084
  date,
43667
- dayShift: {
43668
- avg_efficiency: 0,
43669
- underperforming_workspaces: 0,
43670
- total_workspaces: 0,
43671
- compliance_percentage: 0
43672
- },
43673
- nightShift: {
43674
- avg_efficiency: 0,
43675
- underperforming_workspaces: 0,
43676
- total_workspaces: 0,
43677
- compliance_percentage: 0
43678
- }
44085
+ shifts: {}
44086
+ // Multi-shift structure: Record<number, ShiftData>
43679
44087
  };
43680
44088
  dayDataMap.set(dateKey, dayData);
43681
44089
  }
@@ -43683,46 +44091,46 @@ var KPIDetailView = ({
43683
44091
  avg_efficiency: metric.avg_efficiency || 0,
43684
44092
  underperforming_workspaces: metric.underperforming_workspaces || 0,
43685
44093
  total_workspaces: metric.total_workspaces || 0,
43686
- compliance_percentage: 95 + Math.random() * 5
44094
+ compliance_percentage: 95 + Math.random() * 5,
43687
44095
  // Mock data: random value between 95-100%
44096
+ hasData: true
43688
44097
  };
43689
- if (metric.shift_id === 0) {
43690
- dayData.dayShift = shiftData;
43691
- } else {
43692
- dayData.nightShift = shiftData;
43693
- }
44098
+ dayData.shifts[metric.shift_id] = shiftData;
43694
44099
  });
43695
44100
  const transformedMonthlyData = Array.from(dayDataMap.values());
43696
44101
  console.log("Transformed monthly data for calendar:", transformedMonthlyData);
43697
44102
  setMonthlyData(transformedMonthlyData);
43698
- const mappedData = {
43699
- dayShift: (underperformingData.dayShift || []).map((ws) => ({
43700
- workspace_name: ws.workspace_name || "Unknown Workspace",
43701
- workspace_uuid: ws.workspace_uuid || ws.workspace_name || `unknown-${Math.random()}`,
43702
- avg_efficiency: ws.avg_efficiency || 0,
43703
- last_5_days: (ws.last_5_days || []).map((day) => ({
43704
- date: day.date,
43705
- efficiency: day.efficiency ?? 0,
43706
- performance_score: day.performance_score
43707
- }))
43708
- })),
43709
- nightShift: (underperformingData.nightShift || []).map((ws) => ({
43710
- workspace_name: ws.workspace_name || "Unknown Workspace",
43711
- workspace_uuid: ws.workspace_uuid || ws.workspace_name || `unknown-${Math.random()}`,
43712
- avg_efficiency: ws.avg_efficiency || 0,
43713
- last_5_days: (ws.last_5_days || []).map((day) => ({
43714
- date: day.date,
43715
- efficiency: day.efficiency ?? 0,
43716
- performance_score: day.performance_score
43717
- }))
44103
+ const mapWorkspaces = (workspaces2) => (workspaces2 || []).map((ws) => ({
44104
+ workspace_name: ws.workspace_name || "Unknown Workspace",
44105
+ workspace_uuid: ws.workspace_uuid || ws.workspace_name || `unknown-${Math.random()}`,
44106
+ avg_efficiency: ws.avg_efficiency || 0,
44107
+ last_5_days: (ws.last_5_days || []).map((day) => ({
44108
+ date: day.date,
44109
+ efficiency: day.efficiency ?? 0,
44110
+ performance_score: day.performance_score
43718
44111
  }))
43719
- };
44112
+ }));
44113
+ const mappedData = {};
44114
+ if (underperformingData.dayShift) {
44115
+ mappedData[0] = mapWorkspaces(underperformingData.dayShift);
44116
+ }
44117
+ if (underperformingData.nightShift) {
44118
+ mappedData[1] = mapWorkspaces(underperformingData.nightShift);
44119
+ }
44120
+ Object.entries(underperformingData).forEach(([key, value]) => {
44121
+ if (key !== "dayShift" && key !== "nightShift" && Array.isArray(value)) {
44122
+ const shiftId = parseInt(key);
44123
+ if (!isNaN(shiftId)) {
44124
+ mappedData[shiftId] = mapWorkspaces(value);
44125
+ }
44126
+ }
44127
+ });
43720
44128
  setUnderperformingWorkspaces(mappedData);
43721
44129
  }).catch((error) => {
43722
44130
  console.error("Error fetching monthly data:", error);
43723
44131
  });
43724
44132
  }
43725
- }, [activeTab, lineId, currentMonth, currentYear, supabase, dashboardConfig]);
44133
+ }, [activeTab, lineId, currentMonth, currentYear, supabase, dashboardConfig, shiftConfig]);
43726
44134
  const lineInfo = useMemo(() => {
43727
44135
  if (!metrics2 || !lineDetails || !lineDetails.factory) {
43728
44136
  return null;
@@ -43967,7 +44375,7 @@ var KPIDetailView = ({
43967
44375
  handleNavigate(backUrl);
43968
44376
  }
43969
44377
  }, [urlDate, urlShift, lineInfo, onBackClick, backLinkUrl, handleNavigate, urlMonth, urlYear, lineId, currentMonth, currentYear]);
43970
- if ((lineMetricsLoading || workspacesLoading) && !lineInfo && !metrics2) {
44378
+ if ((lineMetricsLoading || workspacesLoading || isShiftConfigLoading) && !lineInfo && !metrics2) {
43971
44379
  return /* @__PURE__ */ jsx(LoadingPage, { message: "Loading line metrics..." });
43972
44380
  }
43973
44381
  if (lineMetricsError || workspacesError) {
@@ -44073,8 +44481,11 @@ var KPIDetailView = ({
44073
44481
  /* @__PURE__ */ jsxs("div", { className: "sm:hidden mt-3 flex items-center justify-center gap-2", children: [
44074
44482
  /* @__PURE__ */ jsx("div", { className: "inline-flex items-center px-2.5 py-1 bg-gray-100 rounded-full", children: /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-gray-700", children: metrics2 && formatLocalDate(new Date(metrics2.date)) }) }),
44075
44483
  /* @__PURE__ */ jsxs("div", { className: "inline-flex items-center gap-1 px-2.5 py-1 bg-gray-100 rounded-full", children: [
44076
- /* @__PURE__ */ jsx("div", { className: "text-gray-700 scale-90", children: getShiftIcon(metrics2.shift_id ?? 0) }),
44077
- /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-gray-700", children: getShiftName(metrics2.shift_id ?? 0) })
44484
+ /* @__PURE__ */ jsx("div", { className: "text-gray-700 scale-90", children: getShiftIcon2(metrics2.shift_id ?? 0) }),
44485
+ /* @__PURE__ */ jsxs("span", { className: "text-xs font-medium text-gray-700", children: [
44486
+ getShiftName(metrics2.shift_id ?? 0).replace(/ Shift$/i, ""),
44487
+ " Shift"
44488
+ ] })
44078
44489
  ] }),
44079
44490
  !urlDate && !urlShift ? /* @__PURE__ */ jsx("div", { className: "inline-flex items-center px-2.5 py-1 bg-green-100 rounded-full", children: /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-green-700", children: /* @__PURE__ */ jsx(ISTTimer_default, {}) }) }) : urlDate && metrics2.date ? /* @__PURE__ */ jsx("div", { className: "inline-flex items-center px-2.5 py-1 bg-blue-100 rounded-full", children: /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-blue-700", children: getDaysDifference2(metrics2.date) }) }) : null
44080
44491
  ] }),
@@ -44090,9 +44501,9 @@ var KPIDetailView = ({
44090
44501
  /* @__PURE__ */ jsx("div", { className: "w-px h-4 bg-blue-300" })
44091
44502
  ] }),
44092
44503
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
44093
- /* @__PURE__ */ jsx("div", { className: "text-blue-600", children: getShiftIcon(metrics2.shift_id ?? 0) }),
44504
+ /* @__PURE__ */ jsx("div", { className: "text-blue-600", children: getShiftIcon2(metrics2.shift_id ?? 0) }),
44094
44505
  /* @__PURE__ */ jsxs("span", { className: "text-sm md:text-base font-medium text-blue-600", children: [
44095
- getShiftName(metrics2.shift_id ?? 0),
44506
+ getShiftName(metrics2.shift_id ?? 0).replace(/ Shift$/i, ""),
44096
44507
  " Shift"
44097
44508
  ] })
44098
44509
  ] })
@@ -44137,7 +44548,7 @@ var KPIDetailView = ({
44137
44548
  )
44138
44549
  ] }),
44139
44550
  /* @__PURE__ */ jsxs("div", { className: "flex items-center space-x-3 ml-auto", children: [
44140
- lineInfo && activeTab === "overview" && /* @__PURE__ */ jsx(LinePdfGenerator, { lineInfo, workspaceData: workspaces || [] }),
44551
+ lineInfo && activeTab === "overview" && /* @__PURE__ */ jsx(LinePdfGenerator, { lineInfo, workspaceData: workspaces || [], shiftName: getShiftName(lineInfo.shift_id) }),
44141
44552
  activeTab === "monthly_history" && /* @__PURE__ */ jsx(
44142
44553
  LineMonthlyPdfGenerator,
44143
44554
  {
@@ -44147,7 +44558,7 @@ var KPIDetailView = ({
44147
44558
  underperformingWorkspaces,
44148
44559
  selectedMonth: currentMonth,
44149
44560
  selectedYear: currentYear,
44150
- selectedShift
44561
+ selectedShiftId
44151
44562
  }
44152
44563
  )
44153
44564
  ] })
@@ -44250,8 +44661,9 @@ var KPIDetailView = ({
44250
44661
  monthlyData,
44251
44662
  month: currentMonth,
44252
44663
  year: currentYear,
44253
- selectedShift,
44254
- onShiftChange: setSelectedShift
44664
+ selectedShiftId,
44665
+ onShiftChange: setSelectedShiftId,
44666
+ availableShifts: shiftConfig?.shifts?.map((s) => ({ id: s.shiftId, name: s.shiftName }))
44255
44667
  }
44256
44668
  )
44257
44669
  ]
@@ -44402,7 +44814,8 @@ var KPIsOverviewView = ({
44402
44814
  const dashboardConfig = useDashboardConfig();
44403
44815
  const navigation = useNavigation(navigate);
44404
44816
  const dateTimeConfig = useDateTimeConfig();
44405
- const shiftConfig = useShiftConfig();
44817
+ const representativeLineId = lineIds?.[0] || lines[0]?.id;
44818
+ const { shiftConfig, isLoading: isShiftConfigLoading } = useDynamicShiftConfig(representativeLineId);
44406
44819
  const supervisorEnabled = dashboardConfig?.supervisorConfig?.enabled || false;
44407
44820
  const dbTimezone = useAppTimezone();
44408
44821
  const configuredTimezone = dbTimezone || dateTimeConfig.defaultTimezone || "UTC";
@@ -44464,15 +44877,21 @@ var KPIsOverviewView = ({
44464
44877
  return date.toLocaleDateString("en-US", options);
44465
44878
  };
44466
44879
  const currentShiftDetails = getCurrentShift(configuredTimezone, shiftConfig);
44467
- const shiftName = currentShiftDetails.shiftId === 0 ? "Day" : "Night";
44468
- const getShiftIcon = (shiftId) => {
44469
- if (shiftId === 0) {
44880
+ const shiftName = (currentShiftDetails.shiftName || "Day").replace(/ Shift$/i, "");
44881
+ const getShiftIcon2 = (shiftId) => {
44882
+ const shiftNameLower = shiftName.toLowerCase();
44883
+ if (shiftNameLower.includes("day") || shiftNameLower.includes("morning") || shiftId === 0) {
44470
44884
  return /* @__PURE__ */ jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ 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" }) });
44471
- } else {
44885
+ }
44886
+ if (shiftNameLower.includes("afternoon") || shiftNameLower.includes("noon") || shiftNameLower.includes("midday")) {
44887
+ return /* @__PURE__ */ jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ 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" }) });
44888
+ }
44889
+ if (shiftNameLower.includes("night") || shiftNameLower.includes("evening") || shiftId === 1) {
44472
44890
  return /* @__PURE__ */ jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ 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" }) });
44473
44891
  }
44892
+ return /* @__PURE__ */ jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" }) });
44474
44893
  };
44475
- if (loading) {
44894
+ if (loading || isShiftConfigLoading) {
44476
44895
  return /* @__PURE__ */ jsx(LoadingPage, { message: "Loading production lines..." });
44477
44896
  }
44478
44897
  if (error) {
@@ -44580,7 +44999,7 @@ var KPIsOverviewView = ({
44580
44999
  /* @__PURE__ */ jsxs("div", { className: "sm:hidden mt-3 flex items-center justify-center gap-2", children: [
44581
45000
  /* @__PURE__ */ jsx("div", { className: "inline-flex items-center px-2.5 py-1 bg-gray-100 rounded-full", children: /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-gray-700", children: formatLocalDate2(/* @__PURE__ */ new Date()) }) }),
44582
45001
  /* @__PURE__ */ jsxs("div", { className: "inline-flex items-center gap-1 px-2.5 py-1 bg-gray-100 rounded-full", children: [
44583
- /* @__PURE__ */ jsx("div", { className: "text-gray-700 scale-90", children: getShiftIcon(currentShiftDetails.shiftId) }),
45002
+ /* @__PURE__ */ jsx("div", { className: "text-gray-700 scale-90", children: getShiftIcon2(currentShiftDetails.shiftId) }),
44584
45003
  /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-gray-700", children: shiftName })
44585
45004
  ] }),
44586
45005
  /* @__PURE__ */ jsx("div", { className: "inline-flex items-center px-2.5 py-1 bg-green-100 rounded-full", children: /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-green-700", children: /* @__PURE__ */ jsx(ISTTimer_default, {}) }) })
@@ -44591,7 +45010,7 @@ var KPIsOverviewView = ({
44591
45010
  /* @__PURE__ */ jsx("span", { className: "text-sm md:text-base font-medium text-blue-600", children: formatLocalDate2(/* @__PURE__ */ new Date()) }),
44592
45011
  /* @__PURE__ */ jsx("div", { className: "w-px h-4 bg-blue-300" }),
44593
45012
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
44594
- /* @__PURE__ */ jsx("div", { className: "text-blue-600", children: getShiftIcon(currentShiftDetails.shiftId) }),
45013
+ /* @__PURE__ */ jsx("div", { className: "text-blue-600", children: getShiftIcon2(currentShiftDetails.shiftId) }),
44595
45014
  /* @__PURE__ */ jsxs("span", { className: "text-sm md:text-base font-medium text-blue-600", children: [
44596
45015
  shiftName,
44597
45016
  " Shift"
@@ -44619,10 +45038,10 @@ var HeaderRibbon = memo(({
44619
45038
  currentDate,
44620
45039
  currentMobileDate,
44621
45040
  shiftId,
44622
- getShiftIcon,
45041
+ getShiftIcon: getShiftIcon2,
44623
45042
  getShiftName
44624
45043
  }) => {
44625
- const shiftIcon = useMemo(() => getShiftIcon(shiftId), [getShiftIcon, shiftId]);
45044
+ const shiftIcon = useMemo(() => getShiftIcon2(shiftId), [getShiftIcon2, shiftId]);
44626
45045
  const shiftName = useMemo(() => getShiftName(shiftId), [getShiftName, shiftId]);
44627
45046
  return /* @__PURE__ */ jsxs(Fragment, { children: [
44628
45047
  /* @__PURE__ */ jsxs("div", { className: "sm:hidden mt-3 flex items-center justify-center gap-2", children: [
@@ -44641,7 +45060,7 @@ var HeaderRibbon = memo(({
44641
45060
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
44642
45061
  /* @__PURE__ */ jsx("div", { className: "text-blue-600", children: shiftIcon }),
44643
45062
  /* @__PURE__ */ jsxs("span", { className: "text-sm md:text-base font-medium text-blue-600", children: [
44644
- shiftName,
45063
+ shiftName.replace(/ Shift$/i, ""),
44645
45064
  " Shift"
44646
45065
  ] })
44647
45066
  ] })
@@ -44768,6 +45187,7 @@ var LeaderboardDetailView = memo(({
44768
45187
  const navigation = useNavigation();
44769
45188
  const entityConfig = useEntityConfig();
44770
45189
  const [sortAscending, setSortAscending] = useState(false);
45190
+ const timezone = useAppTimezone();
44771
45191
  const [isMobile, setIsMobile] = useState(false);
44772
45192
  React23__default.useEffect(() => {
44773
45193
  const checkMobile = () => setIsMobile(window.innerWidth < 640);
@@ -44796,6 +45216,9 @@ var LeaderboardDetailView = memo(({
44796
45216
  () => typeof shift === "number" ? shift : typeof shift === "string" ? parseInt(shift) : void 0,
44797
45217
  [shift]
44798
45218
  );
45219
+ const availableLineId = Object.keys(configuredLineNames)[0];
45220
+ const effectiveLineId = lineId || userAccessibleLineIds?.[0] || availableLineId;
45221
+ const { shiftConfig, isLoading: isShiftConfigLoading } = useDynamicShiftConfig(effectiveLineId);
44799
45222
  const {
44800
45223
  workspaces,
44801
45224
  loading: workspacesLoading,
@@ -44804,20 +45227,31 @@ var LeaderboardDetailView = memo(({
44804
45227
  } = useAllWorkspaceMetrics({
44805
45228
  initialDate: date,
44806
45229
  initialShiftId: typeof shift === "number" ? shift : typeof shift === "string" ? parseInt(shift) : void 0,
44807
- allowedLineIds: userAccessibleLineIds
45230
+ allowedLineIds: userAccessibleLineIds,
44808
45231
  // Filter to user's accessible lines only
45232
+ enabled: !isShiftConfigLoading
45233
+ // Pass enabled flag
44809
45234
  });
44810
45235
  const getShiftName = useCallback((shiftId2) => {
44811
- if (shiftId2 === void 0) return "Day";
44812
- return shiftId2 === 0 ? "Day" : "Night";
44813
- }, []);
44814
- const getShiftIcon = useCallback((shiftId2) => {
44815
- const shift2 = getShiftName(shiftId2);
44816
- if (shift2 === "Day") {
45236
+ if (shiftId2 !== void 0) {
45237
+ return getShiftNameById(shiftId2, timezone || "Asia/Kolkata", shiftConfig);
45238
+ }
45239
+ const currentShift = getCurrentShift(timezone || "Asia/Kolkata", shiftConfig);
45240
+ return currentShift.shiftName || getShiftNameById(currentShift.shiftId, timezone || "Asia/Kolkata", shiftConfig);
45241
+ }, [timezone, shiftConfig]);
45242
+ const getShiftIcon2 = useCallback((shiftId2) => {
45243
+ const effectiveShiftId = shiftId2 !== void 0 ? shiftId2 : getCurrentShift(timezone || "Asia/Kolkata", shiftConfig).shiftId;
45244
+ const shiftNameLower = getShiftName(effectiveShiftId).toLowerCase();
45245
+ if (shiftNameLower.includes("day") || shiftNameLower.includes("morning")) {
44817
45246
  return /* @__PURE__ */ jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ 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" }) });
44818
- } else {
45247
+ }
45248
+ if (shiftNameLower.includes("afternoon") || shiftNameLower.includes("noon") || shiftNameLower.includes("midday")) {
45249
+ return /* @__PURE__ */ jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ 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" }) });
45250
+ }
45251
+ if (shiftNameLower.includes("night") || shiftNameLower.includes("evening")) {
44819
45252
  return /* @__PURE__ */ jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ 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" }) });
44820
45253
  }
45254
+ return /* @__PURE__ */ jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" }) });
44821
45255
  }, [getShiftName]);
44822
45256
  const formatDate = useCallback((date2) => {
44823
45257
  return new Intl.DateTimeFormat("en-US", {
@@ -44867,13 +45301,27 @@ var LeaderboardDetailView = memo(({
44867
45301
  });
44868
45302
  const displayName = workspace.displayName || getWorkspaceDisplayName(workspace.workspace_name, workspace.line_id);
44869
45303
  const navParams = workspace.workspace_uuid ? getWorkspaceNavigationParams(workspace.workspace_uuid, displayName, workspace.line_id) : "";
44870
- const returnToParam = `&returnTo=${encodeURIComponent(`/leaderboard`)}`;
45304
+ const contextParams = new URLSearchParams();
45305
+ if (date) {
45306
+ contextParams.set("date", date);
45307
+ }
45308
+ if (shiftId !== void 0) {
45309
+ contextParams.set("shift", shiftId.toString());
45310
+ }
45311
+ contextParams.set("returnTo", encodeURIComponent("/leaderboard"));
45312
+ const contextParamString = contextParams.toString();
44871
45313
  if (onWorkspaceClick) {
44872
- onWorkspaceClick(workspace, rank);
45314
+ const combinedParams = navParams ? `${navParams}&${contextParamString}` : `?${contextParamString}`;
45315
+ const enhancedWorkspace = {
45316
+ ...workspace,
45317
+ navParams: combinedParams
45318
+ };
45319
+ onWorkspaceClick(enhancedWorkspace, rank);
44873
45320
  } else {
44874
- navigation.navigate(`/workspace/${workspace.workspace_uuid}${navParams}${returnToParam}`);
45321
+ const combinedParams = navParams ? `${navParams}&${contextParamString}` : `?${contextParamString}`;
45322
+ navigation.navigate(`/workspace/${workspace.workspace_uuid}${combinedParams}`);
44875
45323
  }
44876
- }, [onWorkspaceClick, navigation, lineId, workspacesLength]);
45324
+ }, [onWorkspaceClick, navigation, workspacesLength, date, shiftId]);
44877
45325
  const workspaceDisplayData = useMemo(() => {
44878
45326
  if (!workspaces) return [];
44879
45327
  return workspaces.map((ws) => ({
@@ -44889,7 +45337,7 @@ var LeaderboardDetailView = memo(({
44889
45337
  return sortAscending ? effA - effB : effB - effA;
44890
45338
  });
44891
45339
  }, [workspaceDisplayData, sortAscending]);
44892
- const loading = workspacesLoading;
45340
+ const loading = workspacesLoading || isShiftConfigLoading;
44893
45341
  const error = workspacesError;
44894
45342
  const currentDateFormatted = useMemo(() => {
44895
45343
  const dateStr = (/* @__PURE__ */ new Date()).toDateString();
@@ -45001,7 +45449,7 @@ var LeaderboardDetailView = memo(({
45001
45449
  currentDate: currentDateFormatted,
45002
45450
  currentMobileDate: currentMobileDateFormatted,
45003
45451
  shiftId,
45004
- getShiftIcon,
45452
+ getShiftIcon: getShiftIcon2,
45005
45453
  getShiftName
45006
45454
  }
45007
45455
  )
@@ -45360,6 +45808,23 @@ var ProfileView = () => {
45360
45808
  ] }) });
45361
45809
  };
45362
45810
  var ProfileView_default = ProfileView;
45811
+ var DEFAULT_TIMEZONE = "Asia/Kolkata";
45812
+ var DEFAULT_SHIFTS = [
45813
+ {
45814
+ shiftId: 0,
45815
+ shiftName: "Day Shift",
45816
+ startTime: "08:00",
45817
+ endTime: "16:00",
45818
+ breaks: []
45819
+ },
45820
+ {
45821
+ shiftId: 1,
45822
+ shiftName: "Night Shift",
45823
+ startTime: "20:00",
45824
+ endTime: "04:00",
45825
+ breaks: []
45826
+ }
45827
+ ];
45363
45828
  var calculateShiftHours = (startTime, endTime, breaks = []) => {
45364
45829
  if (!startTime || !endTime) return 8;
45365
45830
  const [startHour, startMinute] = startTime.split(":").map(Number);
@@ -45426,6 +45891,19 @@ var formatBreaks = (breaks) => {
45426
45891
  }))
45427
45892
  };
45428
45893
  };
45894
+ var getShiftIcon = (shiftId, shiftName) => {
45895
+ const nameLower = shiftName.toLowerCase();
45896
+ if (nameLower.includes("day") || nameLower.includes("morning") || shiftId === 0) {
45897
+ return /* @__PURE__ */ jsx("svg", { className: "w-5 h-5 text-gray-600", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ 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" }) });
45898
+ }
45899
+ if (nameLower.includes("afternoon") || nameLower.includes("noon") || nameLower.includes("midday")) {
45900
+ return /* @__PURE__ */ jsx("svg", { className: "w-5 h-5 text-gray-600", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ 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" }) });
45901
+ }
45902
+ if (nameLower.includes("night") || nameLower.includes("evening") || shiftId === 1) {
45903
+ return /* @__PURE__ */ jsx("svg", { className: "w-5 h-5 text-gray-600", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ 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" }) });
45904
+ }
45905
+ return /* @__PURE__ */ jsx(Clock, { className: "w-5 h-5 text-gray-600" });
45906
+ };
45429
45907
  var BreakRow = memo(({
45430
45908
  break: breakItem,
45431
45909
  onUpdate,
@@ -45553,9 +46031,13 @@ var ShiftPanel = memo(({
45553
46031
  onBreakUpdate,
45554
46032
  onBreakRemove,
45555
46033
  onBreakAdd,
45556
- shiftHours
46034
+ shiftHours,
46035
+ shiftId,
46036
+ onShiftNameChange,
46037
+ canDelete = false,
46038
+ onDelete
45557
46039
  }) => {
45558
- const panelId = `panel-${title.toLowerCase().replace(/\s+/g, "-")}`;
46040
+ const panelId = `panel-${title.toLowerCase().replace(/\s+/g, "-")}-${shiftId ?? 0}`;
45559
46041
  const storageKey = `shift_panel_${panelId}_minimized`;
45560
46042
  const [isMinimized, setIsMinimized] = useState(true);
45561
46043
  useEffect(() => {
@@ -45582,7 +46064,7 @@ var ShiftPanel = memo(({
45582
46064
  "button",
45583
46065
  {
45584
46066
  onClick: toggleMinimize,
45585
- 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",
46067
+ 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",
45586
46068
  "aria-expanded": !isMinimized,
45587
46069
  "aria-controls": panelId,
45588
46070
  children: [
@@ -45599,15 +46081,42 @@ var ShiftPanel = memo(({
45599
46081
  ]
45600
46082
  }
45601
46083
  ),
45602
- /* @__PURE__ */ jsxs("span", { className: "text-xs sm:text-sm font-medium text-gray-600 text-center sm:text-right sm:mr-2", children: [
45603
- "Total Shift Hours: ",
45604
- shiftHours,
45605
- " hours"
46084
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 sm:gap-4", children: [
46085
+ /* @__PURE__ */ jsxs("span", { className: "text-xs sm:text-sm font-medium text-gray-600 text-center sm:text-right", children: [
46086
+ "Total Shift Hours: ",
46087
+ shiftHours,
46088
+ " hours"
46089
+ ] }),
46090
+ canDelete && onDelete && /* @__PURE__ */ jsx(
46091
+ "button",
46092
+ {
46093
+ onClick: (e) => {
46094
+ e.stopPropagation();
46095
+ onDelete();
46096
+ },
46097
+ className: "p-1.5 text-gray-400 hover:text-red-500 hover:bg-red-50 rounded transition-colors",
46098
+ "aria-label": "Delete shift",
46099
+ children: /* @__PURE__ */ jsx(Trash2, { className: "w-4 h-4" })
46100
+ }
46101
+ )
45606
46102
  ] })
45607
46103
  ] })
45608
46104
  }
45609
46105
  ),
45610
46106
  !isMinimized && /* @__PURE__ */ jsxs("div", { id: panelId, className: "p-3 sm:p-4 md:p-6 border-t border-gray-200 w-full bg-white", children: [
46107
+ onShiftNameChange && /* @__PURE__ */ jsxs("div", { className: "mb-4 sm:mb-6", children: [
46108
+ /* @__PURE__ */ jsx("label", { className: "block text-xs sm:text-sm font-medium text-gray-700 mb-1", children: "Shift Name" }),
46109
+ /* @__PURE__ */ jsx(
46110
+ "input",
46111
+ {
46112
+ type: "text",
46113
+ value: title,
46114
+ onChange: (e) => onShiftNameChange(e.target.value),
46115
+ placeholder: "Enter shift name",
46116
+ 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"
46117
+ }
46118
+ )
46119
+ ] }),
45611
46120
  /* @__PURE__ */ 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: [
45612
46121
  /* @__PURE__ */ jsxs("div", { className: "w-full", children: [
45613
46122
  /* @__PURE__ */ jsx("label", { className: "block text-xs sm:text-sm font-medium text-gray-700 mb-1", children: "Shift Start Time" }),
@@ -45701,16 +46210,9 @@ var ShiftsView = ({
45701
46210
  () => lineIds.map((id3) => ({
45702
46211
  id: id3,
45703
46212
  name: lineNames[id3] || `Line ${id3.substring(0, 4)}`,
45704
- dayShift: {
45705
- startTime: "08:00",
45706
- endTime: "16:00",
45707
- breaks: []
45708
- },
45709
- nightShift: {
45710
- startTime: "20:00",
45711
- endTime: "04:00",
45712
- breaks: []
45713
- },
46213
+ timezone: DEFAULT_TIMEZONE,
46214
+ shifts: DEFAULT_SHIFTS.map((s) => ({ ...s })),
46215
+ // Clone default shifts
45714
46216
  isOpen: true,
45715
46217
  isSaving: false,
45716
46218
  saveSuccess: false
@@ -45734,60 +46236,47 @@ var ShiftsView = ({
45734
46236
  try {
45735
46237
  setLoading(true);
45736
46238
  setError(null);
45737
- 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);
45738
- if (dayShiftError) {
45739
- console.error("Error fetching day shift operating hours:", dayShiftError);
45740
- showToast("error", "Error loading day shift data");
45741
- setError("Failed to load day shift data");
45742
- return;
45743
- }
45744
- 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);
45745
- if (nightShiftError) {
45746
- console.error("Error fetching night shift operating hours:", nightShiftError);
45747
- showToast("error", "Error loading night shift data");
45748
- setError("Failed to load night shift data");
46239
+ 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 });
46240
+ if (shiftsError) {
46241
+ console.error("[ShiftsView] Error fetching shift configurations:", shiftsError);
46242
+ showToast("error", "Error loading shift data");
46243
+ setError("Failed to load shift data");
45749
46244
  return;
45750
46245
  }
45751
- const dayShiftHoursMap = (dayShiftOperatingHours || []).reduce((map, item) => {
45752
- map[item.line_id] = {
45753
- startTime: item.start_time,
45754
- endTime: item.end_time,
45755
- breaks: parseBreaksFromDB(item.breaks)
45756
- };
45757
- return map;
45758
- }, {});
45759
- const nightShiftHoursMap = (nightShiftOperatingHours || []).reduce((map, item) => {
45760
- map[item.line_id] = {
45761
- startTime: item.start_time,
45762
- endTime: item.end_time,
45763
- breaks: parseBreaksFromDB(item.breaks)
45764
- };
45765
- return map;
45766
- }, {});
45767
- setLineConfigs((prev) => prev.map((config) => {
45768
- const typedConfig = config;
45769
- const lineId = typedConfig.id;
45770
- const newConfig = { ...typedConfig };
45771
- if (dayShiftHoursMap[lineId]) {
45772
- newConfig.dayShift = {
45773
- ...newConfig.dayShift,
45774
- ...dayShiftHoursMap[lineId]
45775
- };
45776
- }
45777
- if (nightShiftHoursMap[lineId]) {
45778
- newConfig.nightShift = {
45779
- ...newConfig.nightShift,
45780
- ...nightShiftHoursMap[lineId]
45781
- };
45782
- }
45783
- if (newConfig.isOpen === void 0) {
45784
- newConfig.isOpen = getStoredLineState(lineId);
46246
+ console.log("[ShiftsView] Fetched shifts from DB:", allShiftsData);
46247
+ const shiftsByLine = {};
46248
+ const timezoneByLine = {};
46249
+ (allShiftsData || []).forEach((row) => {
46250
+ if (!shiftsByLine[row.line_id]) {
46251
+ shiftsByLine[row.line_id] = [];
46252
+ }
46253
+ shiftsByLine[row.line_id].push({
46254
+ shiftId: row.shift_id,
46255
+ shiftName: row.shift_name || `Shift ${row.shift_id}`,
46256
+ startTime: row.start_time || "08:00",
46257
+ endTime: row.end_time || "16:00",
46258
+ breaks: parseBreaksFromDB(row.breaks),
46259
+ timezone: row.timezone
46260
+ });
46261
+ if (row.timezone && !timezoneByLine[row.line_id]) {
46262
+ timezoneByLine[row.line_id] = row.timezone;
45785
46263
  }
45786
- return newConfig;
46264
+ });
46265
+ setLineConfigs((prev) => prev.map((config) => {
46266
+ const lineId = config.id;
46267
+ const lineShifts = shiftsByLine[lineId];
46268
+ const lineTimezone = timezoneByLine[lineId] || DEFAULT_TIMEZONE;
46269
+ const shifts = lineShifts && lineShifts.length > 0 ? lineShifts.sort((a, b) => a.shiftId - b.shiftId) : DEFAULT_SHIFTS.map((s) => ({ ...s }));
46270
+ return {
46271
+ ...config,
46272
+ timezone: lineTimezone,
46273
+ shifts,
46274
+ isOpen: config.isOpen ?? getStoredLineState(lineId)
46275
+ };
45787
46276
  }));
45788
46277
  setLoading(false);
45789
46278
  } catch (error2) {
45790
- console.error("Error fetching shift configurations:", error2);
46279
+ console.error("[ShiftsView] Error fetching shift configurations:", error2);
45791
46280
  showToast("error", "Failed to load shift configurations");
45792
46281
  setError("Failed to load shift configurations");
45793
46282
  setLoading(false);
@@ -45797,195 +46286,125 @@ var ShiftsView = ({
45797
46286
  }, [lineIds, showToast]);
45798
46287
  useCallback((lineId) => {
45799
46288
  setLineConfigs((prev) => {
45800
- const typedPrev = prev;
45801
- const newIsOpen = !typedPrev.find((config) => config.id === lineId)?.isOpen;
46289
+ const newIsOpen = !prev.find((config) => config.id === lineId)?.isOpen;
45802
46290
  localStorage.setItem(`line_${lineId}_open`, JSON.stringify(newIsOpen));
45803
- return typedPrev.map(
46291
+ return prev.map(
45804
46292
  (config) => config.id === lineId ? { ...config, isOpen: newIsOpen } : config
45805
46293
  );
45806
46294
  });
45807
46295
  }, []);
45808
- const updateDayShiftStartTime = useCallback((lineId, value) => {
45809
- setLineConfigs((prev) => prev.map((config) => {
45810
- const typedConfig = config;
45811
- if (typedConfig.id === lineId) {
45812
- const updatedDayShift = { ...typedConfig.dayShift, startTime: value };
45813
- return {
45814
- ...typedConfig,
45815
- dayShift: updatedDayShift
45816
- };
45817
- }
45818
- return typedConfig;
45819
- }));
45820
- }, []);
45821
- const updateDayShiftEndTime = useCallback((lineId, value) => {
46296
+ const updateShiftTime = useCallback((lineId, shiftId, field, value) => {
45822
46297
  setLineConfigs((prev) => prev.map((config) => {
45823
- const typedConfig = config;
45824
- if (typedConfig.id === lineId) {
45825
- const updatedDayShift = { ...typedConfig.dayShift, endTime: value };
45826
- return {
45827
- ...typedConfig,
45828
- dayShift: updatedDayShift
45829
- };
45830
- }
45831
- return typedConfig;
45832
- }));
45833
- }, []);
45834
- const updateNightShiftStartTime = useCallback((lineId, value) => {
45835
- setLineConfigs((prev) => prev.map((config) => {
45836
- const typedConfig = config;
45837
- if (typedConfig.id === lineId) {
45838
- const updatedNightShift = { ...typedConfig.nightShift, startTime: value };
45839
- return {
45840
- ...typedConfig,
45841
- nightShift: updatedNightShift
45842
- };
46298
+ if (config.id === lineId) {
46299
+ const updatedShifts = config.shifts.map(
46300
+ (shift) => shift.shiftId === shiftId ? { ...shift, [field]: value } : shift
46301
+ );
46302
+ return { ...config, shifts: updatedShifts };
45843
46303
  }
45844
- return typedConfig;
46304
+ return config;
45845
46305
  }));
45846
46306
  }, []);
45847
- const updateNightShiftEndTime = useCallback((lineId, value) => {
46307
+ const updateShiftName = useCallback((lineId, shiftId, value) => {
45848
46308
  setLineConfigs((prev) => prev.map((config) => {
45849
- const typedConfig = config;
45850
- if (typedConfig.id === lineId) {
45851
- const updatedNightShift = { ...typedConfig.nightShift, endTime: value };
45852
- return {
45853
- ...typedConfig,
45854
- nightShift: updatedNightShift
45855
- };
46309
+ if (config.id === lineId) {
46310
+ const updatedShifts = config.shifts.map(
46311
+ (shift) => shift.shiftId === shiftId ? { ...shift, shiftName: value } : shift
46312
+ );
46313
+ return { ...config, shifts: updatedShifts };
45856
46314
  }
45857
- return typedConfig;
46315
+ return config;
45858
46316
  }));
45859
46317
  }, []);
45860
- const addDayShiftBreak = useCallback((lineId) => {
45861
- setLineConfigs((prev) => prev.map((config) => {
45862
- const typedConfig = config;
45863
- if (typedConfig.id === lineId) {
45864
- const dayShift = { ...typedConfig.dayShift };
45865
- const newBreak = {
45866
- startTime: dayShift.startTime,
45867
- endTime: dayShift.startTime,
45868
- duration: 0,
45869
- remarks: ""
45870
- };
45871
- return {
45872
- ...typedConfig,
45873
- dayShift: {
45874
- ...dayShift,
45875
- breaks: [...dayShift.breaks, newBreak]
45876
- }
45877
- };
45878
- }
45879
- return typedConfig;
45880
- }));
46318
+ useCallback((lineId, value) => {
46319
+ setLineConfigs((prev) => prev.map(
46320
+ (config) => config.id === lineId ? { ...config, timezone: value } : config
46321
+ ));
45881
46322
  }, []);
45882
- const addNightShiftBreak = useCallback((lineId) => {
46323
+ const addBreak = useCallback((lineId, shiftId) => {
45883
46324
  setLineConfigs((prev) => prev.map((config) => {
45884
- const typedConfig = config;
45885
- if (typedConfig.id === lineId) {
45886
- const nightShift = { ...typedConfig.nightShift };
45887
- const newBreak = {
45888
- startTime: nightShift.startTime,
45889
- endTime: nightShift.startTime,
45890
- duration: 0
45891
- };
45892
- return {
45893
- ...typedConfig,
45894
- nightShift: {
45895
- ...nightShift,
45896
- breaks: [...nightShift.breaks, newBreak]
46325
+ if (config.id === lineId) {
46326
+ const updatedShifts = config.shifts.map((shift) => {
46327
+ if (shift.shiftId === shiftId) {
46328
+ const newBreak = {
46329
+ startTime: shift.startTime,
46330
+ endTime: shift.startTime,
46331
+ duration: 0,
46332
+ remarks: ""
46333
+ };
46334
+ return { ...shift, breaks: [...shift.breaks, newBreak] };
45897
46335
  }
45898
- };
46336
+ return shift;
46337
+ });
46338
+ return { ...config, shifts: updatedShifts };
45899
46339
  }
45900
- return typedConfig;
46340
+ return config;
45901
46341
  }));
45902
46342
  }, []);
45903
- const updateDayShiftBreak = useCallback((lineId, index, field, value) => {
46343
+ const updateBreak = useCallback((lineId, shiftId, breakIndex, field, value) => {
45904
46344
  setLineConfigs((prev) => prev.map((config) => {
45905
- const typedConfig = config;
45906
- if (typedConfig.id === lineId) {
45907
- const dayShift = { ...typedConfig.dayShift };
45908
- const newBreaks = [...dayShift.breaks];
45909
- newBreaks[index] = { ...newBreaks[index], [field]: value };
45910
- if (field === "startTime" || field === "endTime") {
45911
- const startParts = newBreaks[index].startTime.split(":").map(Number);
45912
- const endParts = newBreaks[index].endTime.split(":").map(Number);
45913
- let startMinutes = startParts[0] * 60 + startParts[1];
45914
- let endMinutes = endParts[0] * 60 + endParts[1];
45915
- if (endMinutes < startMinutes) {
45916
- endMinutes += 24 * 60;
45917
- }
45918
- newBreaks[index].duration = endMinutes - startMinutes;
45919
- }
45920
- return {
45921
- ...typedConfig,
45922
- dayShift: {
45923
- ...dayShift,
45924
- breaks: newBreaks
46345
+ if (config.id === lineId) {
46346
+ const updatedShifts = config.shifts.map((shift) => {
46347
+ if (shift.shiftId === shiftId) {
46348
+ const newBreaks = [...shift.breaks];
46349
+ newBreaks[breakIndex] = { ...newBreaks[breakIndex], [field]: value };
46350
+ if (field === "startTime" || field === "endTime") {
46351
+ newBreaks[breakIndex].duration = calculateBreakDuration(
46352
+ newBreaks[breakIndex].startTime,
46353
+ newBreaks[breakIndex].endTime
46354
+ );
46355
+ }
46356
+ return { ...shift, breaks: newBreaks };
45925
46357
  }
45926
- };
46358
+ return shift;
46359
+ });
46360
+ return { ...config, shifts: updatedShifts };
45927
46361
  }
45928
- return typedConfig;
46362
+ return config;
45929
46363
  }));
45930
46364
  }, []);
45931
- const updateNightShiftBreak = useCallback((lineId, index, field, value) => {
46365
+ const removeBreak = useCallback((lineId, shiftId, breakIndex) => {
45932
46366
  setLineConfigs((prev) => prev.map((config) => {
45933
- const typedConfig = config;
45934
- if (typedConfig.id === lineId) {
45935
- const nightShift = { ...typedConfig.nightShift };
45936
- const newBreaks = [...nightShift.breaks];
45937
- newBreaks[index] = { ...newBreaks[index], [field]: value };
45938
- if (field === "startTime" || field === "endTime") {
45939
- const startParts = newBreaks[index].startTime.split(":").map(Number);
45940
- const endParts = newBreaks[index].endTime.split(":").map(Number);
45941
- let startMinutes = startParts[0] * 60 + startParts[1];
45942
- let endMinutes = endParts[0] * 60 + endParts[1];
45943
- if (endMinutes < startMinutes) {
45944
- endMinutes += 24 * 60;
45945
- }
45946
- newBreaks[index].duration = endMinutes - startMinutes;
45947
- }
45948
- return {
45949
- ...typedConfig,
45950
- nightShift: {
45951
- ...nightShift,
45952
- breaks: newBreaks
46367
+ if (config.id === lineId) {
46368
+ const updatedShifts = config.shifts.map((shift) => {
46369
+ if (shift.shiftId === shiftId) {
46370
+ return { ...shift, breaks: shift.breaks.filter((_, i) => i !== breakIndex) };
45953
46371
  }
45954
- };
46372
+ return shift;
46373
+ });
46374
+ return { ...config, shifts: updatedShifts };
45955
46375
  }
45956
- return typedConfig;
46376
+ return config;
45957
46377
  }));
45958
46378
  }, []);
45959
- const removeDayShiftBreak = useCallback((lineId, index) => {
46379
+ useCallback((lineId) => {
45960
46380
  setLineConfigs((prev) => prev.map((config) => {
45961
46381
  if (config.id === lineId) {
45962
- const dayShift = { ...config.dayShift };
45963
- return {
45964
- ...config,
45965
- dayShift: {
45966
- ...dayShift,
45967
- breaks: dayShift.breaks.filter((_, i) => i !== index)
45968
- }
46382
+ const maxShiftId = Math.max(...config.shifts.map((s) => s.shiftId), -1);
46383
+ const newShiftId = maxShiftId + 1;
46384
+ const newShift = {
46385
+ shiftId: newShiftId,
46386
+ shiftName: `Shift ${newShiftId}`,
46387
+ startTime: "08:00",
46388
+ endTime: "16:00",
46389
+ breaks: []
45969
46390
  };
46391
+ return { ...config, shifts: [...config.shifts, newShift] };
45970
46392
  }
45971
46393
  return config;
45972
46394
  }));
45973
46395
  }, []);
45974
- const removeNightShiftBreak = useCallback((lineId, index) => {
46396
+ const removeShift = useCallback((lineId, shiftId) => {
45975
46397
  setLineConfigs((prev) => prev.map((config) => {
45976
46398
  if (config.id === lineId) {
45977
- const nightShift = { ...config.nightShift };
45978
- return {
45979
- ...config,
45980
- nightShift: {
45981
- ...nightShift,
45982
- breaks: nightShift.breaks.filter((_, i) => i !== index)
45983
- }
45984
- };
46399
+ if (config.shifts.length <= 1) {
46400
+ showToast("error", "Cannot remove the last shift");
46401
+ return config;
46402
+ }
46403
+ return { ...config, shifts: config.shifts.filter((s) => s.shiftId !== shiftId) };
45985
46404
  }
45986
46405
  return config;
45987
46406
  }));
45988
- }, []);
46407
+ }, [showToast]);
45989
46408
  const handleSaveShifts = useCallback(async (lineId) => {
45990
46409
  setLineConfigs((prev) => prev.map(
45991
46410
  (config) => config.id === lineId ? { ...config, isSaving: true, saveSuccess: false } : config
@@ -45995,27 +46414,31 @@ var ShiftsView = ({
45995
46414
  if (!lineConfig) {
45996
46415
  throw new Error("Line configuration not found");
45997
46416
  }
45998
- const dayShiftData = {
45999
- line_id: lineId,
46000
- shift_id: 0,
46001
- start_time: lineConfig.dayShift.startTime,
46002
- end_time: lineConfig.dayShift.endTime,
46003
- breaks: formatBreaks(lineConfig.dayShift.breaks)
46004
- };
46005
- const nightShiftData = {
46006
- line_id: lineId,
46007
- shift_id: 1,
46008
- start_time: lineConfig.nightShift.startTime,
46009
- end_time: lineConfig.nightShift.endTime,
46010
- breaks: formatBreaks(lineConfig.nightShift.breaks)
46011
- };
46012
- const dayResult = await supabase.from("line_operating_hours").upsert(dayShiftData).select();
46013
- if (dayResult.error) {
46014
- throw new Error(`Failed to save day shift: ${dayResult.error.message}`);
46417
+ console.log("[ShiftsView] Saving shifts for line:", lineId, lineConfig.shifts);
46418
+ for (const shift of lineConfig.shifts) {
46419
+ const shiftData = {
46420
+ line_id: lineId,
46421
+ shift_id: shift.shiftId,
46422
+ shift_name: shift.shiftName,
46423
+ start_time: shift.startTime,
46424
+ end_time: shift.endTime,
46425
+ breaks: formatBreaks(shift.breaks),
46426
+ timezone: lineConfig.timezone
46427
+ };
46428
+ const { error: upsertError } = await supabase.from("line_operating_hours").upsert(shiftData).select();
46429
+ if (upsertError) {
46430
+ throw new Error(`Failed to save shift ${shift.shiftId}: ${upsertError.message}`);
46431
+ }
46015
46432
  }
46016
- const nightResult = await supabase.from("line_operating_hours").upsert(nightShiftData).select();
46017
- if (nightResult.error) {
46018
- throw new Error(`Failed to save night shift: ${nightResult.error.message}`);
46433
+ const { data: existingShifts } = await supabase.from("line_operating_hours").select("shift_id").eq("line_id", lineId);
46434
+ const currentShiftIds = lineConfig.shifts.map((s) => s.shiftId);
46435
+ const shiftsToDelete = (existingShifts || []).filter((s) => !currentShiftIds.includes(s.shift_id)).map((s) => s.shift_id);
46436
+ if (shiftsToDelete.length > 0) {
46437
+ console.log("[ShiftsView] Deleting removed shifts:", shiftsToDelete);
46438
+ const { error: deleteError } = await supabase.from("line_operating_hours").delete().eq("line_id", lineId).in("shift_id", shiftsToDelete);
46439
+ if (deleteError) {
46440
+ console.error("[ShiftsView] Error deleting shifts:", deleteError);
46441
+ }
46019
46442
  }
46020
46443
  setLineConfigs((prev) => prev.map(
46021
46444
  (config) => config.id === lineId ? { ...config, isSaving: false, saveSuccess: true } : config
@@ -46027,7 +46450,7 @@ var ShiftsView = ({
46027
46450
  ));
46028
46451
  }, 3e3);
46029
46452
  } catch (error2) {
46030
- console.error("Error saving shift configurations:", error2);
46453
+ console.error("[ShiftsView] Error saving shift configurations:", error2);
46031
46454
  showToast("error", "Failed to save shift configurations");
46032
46455
  setLineConfigs((prev) => prev.map(
46033
46456
  (config) => config.id === lineId ? { ...config, isSaving: false, saveSuccess: false } : config
@@ -46047,7 +46470,7 @@ var ShiftsView = ({
46047
46470
  ) }),
46048
46471
  /* @__PURE__ */ jsxs("div", { className: "flex-1 flex flex-col items-center mt-2 sm:mt-0", children: [
46049
46472
  /* @__PURE__ */ jsx("h1", { className: "text-lg sm:text-xl md:text-2xl lg:text-3xl font-semibold text-gray-900 text-center", children: "Shift Management" }),
46050
- /* @__PURE__ */ 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" })
46473
+ /* @__PURE__ */ 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" })
46051
46474
  ] }),
46052
46475
  /* @__PURE__ */ jsx("div", { className: "hidden sm:block absolute right-0 w-24" })
46053
46476
  ] }) }) }),
@@ -46067,6 +46490,11 @@ var ShiftsView = ({
46067
46490
  /* @__PURE__ */ jsxs("h2", { className: "text-base sm:text-lg font-semibold text-gray-800", children: [
46068
46491
  config.name,
46069
46492
  " Shifts"
46493
+ ] }),
46494
+ /* @__PURE__ */ jsxs("span", { className: "text-xs text-gray-400", children: [
46495
+ "(",
46496
+ config.shifts.length,
46497
+ " shifts)"
46070
46498
  ] })
46071
46499
  ] }),
46072
46500
  /* @__PURE__ */ 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: [
@@ -46094,48 +46522,27 @@ var ShiftsView = ({
46094
46522
  )
46095
46523
  ] })
46096
46524
  ] }) }),
46097
- /* @__PURE__ */ jsxs("div", { id: `shift-panel-${config.id}`, className: "p-3 sm:p-4 md:p-6 border-t border-gray-200 w-full", children: [
46098
- /* @__PURE__ */ jsx(
46099
- ShiftPanel,
46100
- {
46101
- title: "Day Shift",
46102
- icon: /* @__PURE__ */ jsx("svg", { className: "w-5 h-5 text-gray-600", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ 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" }) }),
46103
- startTime: config.dayShift.startTime,
46104
- endTime: config.dayShift.endTime,
46105
- breaks: config.dayShift.breaks,
46106
- onStartTimeChange: (value) => updateDayShiftStartTime(config.id, value),
46107
- onEndTimeChange: (value) => updateDayShiftEndTime(config.id, value),
46108
- onBreakUpdate: (index, field, value) => updateDayShiftBreak(config.id, index, field, value),
46109
- onBreakRemove: (index) => removeDayShiftBreak(config.id, index),
46110
- onBreakAdd: () => addDayShiftBreak(config.id),
46111
- shiftHours: calculateShiftHours(
46112
- config.dayShift.startTime,
46113
- config.dayShift.endTime,
46114
- config.dayShift.breaks
46115
- )
46116
- }
46117
- ),
46118
- /* @__PURE__ */ jsx(
46119
- ShiftPanel,
46120
- {
46121
- title: "Night Shift",
46122
- icon: /* @__PURE__ */ jsx("svg", { className: "w-5 h-5 text-gray-600", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ 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" }) }),
46123
- startTime: config.nightShift.startTime,
46124
- endTime: config.nightShift.endTime,
46125
- breaks: config.nightShift.breaks,
46126
- onStartTimeChange: (value) => updateNightShiftStartTime(config.id, value),
46127
- onEndTimeChange: (value) => updateNightShiftEndTime(config.id, value),
46128
- onBreakUpdate: (index, field, value) => updateNightShiftBreak(config.id, index, field, value),
46129
- onBreakRemove: (index) => removeNightShiftBreak(config.id, index),
46130
- onBreakAdd: () => addNightShiftBreak(config.id),
46131
- shiftHours: calculateShiftHours(
46132
- config.nightShift.startTime,
46133
- config.nightShift.endTime,
46134
- config.nightShift.breaks
46135
- )
46136
- }
46137
- )
46138
- ] })
46525
+ /* @__PURE__ */ 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__ */ jsx(
46526
+ ShiftPanel,
46527
+ {
46528
+ title: shift.shiftName,
46529
+ icon: getShiftIcon(shift.shiftId, shift.shiftName),
46530
+ startTime: shift.startTime,
46531
+ endTime: shift.endTime,
46532
+ breaks: shift.breaks,
46533
+ onStartTimeChange: (value) => updateShiftTime(config.id, shift.shiftId, "startTime", value),
46534
+ onEndTimeChange: (value) => updateShiftTime(config.id, shift.shiftId, "endTime", value),
46535
+ onBreakUpdate: (index, field, value) => updateBreak(config.id, shift.shiftId, index, field, value),
46536
+ onBreakRemove: (index) => removeBreak(config.id, shift.shiftId, index),
46537
+ onBreakAdd: () => addBreak(config.id, shift.shiftId),
46538
+ shiftHours: calculateShiftHours(shift.startTime, shift.endTime, shift.breaks),
46539
+ shiftId: shift.shiftId,
46540
+ onShiftNameChange: (value) => updateShiftName(config.id, shift.shiftId, value),
46541
+ canDelete: config.shifts.length > 1,
46542
+ onDelete: () => removeShift(config.id, shift.shiftId)
46543
+ },
46544
+ `${config.id}-shift-${shift.shiftId}`
46545
+ )) })
46139
46546
  ] }, config.id)) })
46140
46547
  ] })
46141
46548
  ] });
@@ -46962,6 +47369,10 @@ var TargetsViewUI = ({
46962
47369
  savingLines,
46963
47370
  saveSuccess,
46964
47371
  selectedShift,
47372
+ shiftOptions = [
47373
+ { id: 0, name: "Day Shift" },
47374
+ { id: 1, name: "Night Shift" }
47375
+ ],
46965
47376
  isBulkConfigureOpen,
46966
47377
  navItems = [],
46967
47378
  currentPathname = "/targets",
@@ -47014,24 +47425,15 @@ var TargetsViewUI = ({
47014
47425
  ] }) }),
47015
47426
  /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-auto", children: /* @__PURE__ */ jsxs("div", { className: "px-4 sm:px-6 md:px-8 py-4 sm:py-5 md:py-6", children: [
47016
47427
  /* @__PURE__ */ 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__ */ 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." }) }),
47017
- /* @__PURE__ */ jsx("div", { className: "mb-4 sm:mb-6 flex justify-center relative", children: /* @__PURE__ */ jsxs("div", { className: "inline-flex bg-gray-100 p-1 rounded-lg w-full max-w-xs sm:w-auto", children: [
47018
- /* @__PURE__ */ jsx(
47019
- "button",
47020
- {
47021
- onClick: () => onShiftChange(0),
47022
- 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"}`,
47023
- children: "Day Shift"
47024
- }
47025
- ),
47026
- /* @__PURE__ */ jsx(
47027
- "button",
47028
- {
47029
- onClick: () => onShiftChange(1),
47030
- 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"}`,
47031
- children: "Night Shift"
47032
- }
47033
- )
47034
- ] }) }),
47428
+ /* @__PURE__ */ jsx("div", { className: "mb-4 sm:mb-6 flex justify-center relative", children: /* @__PURE__ */ 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__ */ jsx(
47429
+ "button",
47430
+ {
47431
+ onClick: () => onShiftChange(option.id),
47432
+ 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"}`,
47433
+ children: option.name
47434
+ },
47435
+ option.id
47436
+ )) }) }),
47035
47437
  /* @__PURE__ */ jsx("div", { className: "space-y-6", children: Object.entries(lineWorkspaces).map(([lineId, line]) => /* @__PURE__ */ jsxs(
47036
47438
  "div",
47037
47439
  {
@@ -47358,12 +47760,7 @@ var TargetsView = ({
47358
47760
  [lineId]: getStoredLineState2(lineId)
47359
47761
  }), {});
47360
47762
  });
47361
- const [allShiftsData, setAllShiftsData] = useState({
47362
- 0: initialLineWorkspaces,
47363
- // Day shift
47364
- 1: initialLineWorkspaces
47365
- // Night shift (will be populated on first load)
47366
- });
47763
+ const [allShiftsData, setAllShiftsData] = useState({});
47367
47764
  const [actionIds, setActionIds] = useState(null);
47368
47765
  const [savingLines, setSavingLines] = useState(
47369
47766
  () => lineIds.reduce((acc, id3) => ({ ...acc, [id3]: false }), {})
@@ -47375,6 +47772,7 @@ var TargetsView = ({
47375
47772
  const [isBulkConfigureOpen, setIsBulkConfigureOpen] = useState(false);
47376
47773
  const [selectedWorkspaces, setSelectedWorkspaces] = useState([]);
47377
47774
  const [selectedShift, setSelectedShift] = useState(0);
47775
+ const [shiftOptions, setShiftOptions] = useState([]);
47378
47776
  const canSaveTargets = useCanSaveTargets();
47379
47777
  const [dbValues, setDbValues] = useState({ 0: {}, 1: {} });
47380
47778
  const [userEditedFields, setUserEditedFields] = useState(/* @__PURE__ */ new Set());
@@ -47407,12 +47805,28 @@ var TargetsView = ({
47407
47805
  setIsLoading(true);
47408
47806
  try {
47409
47807
  const currentDate = getOperationalDate(timezone);
47808
+ const { data: shiftsData, error: shiftsError } = await supabase.from("line_operating_hours").select("line_id, shift_id, shift_name").in("line_id", lineIds);
47809
+ if (shiftsError) {
47810
+ console.warn("[TargetsView] Error fetching shift definitions, falling back to defaults", shiftsError);
47811
+ }
47812
+ const derivedShiftOptions = (shiftsData || []).reduce((acc, row) => {
47813
+ if (acc.some((s) => s.id === row.shift_id)) return acc;
47814
+ acc.push({ id: row.shift_id, name: row.shift_name || `Shift ${row.shift_id}` });
47815
+ return acc;
47816
+ }, []);
47817
+ const effectiveShiftOptions = derivedShiftOptions.length > 0 ? derivedShiftOptions.sort((a, b) => a.id - b.id) : [
47818
+ { id: 0, name: "Day Shift" },
47819
+ { id: 1, name: "Night Shift" }
47820
+ ];
47821
+ setShiftOptions(effectiveShiftOptions);
47822
+ const defaultShiftId = effectiveShiftOptions[0].id;
47823
+ setSelectedShift(defaultShiftId);
47410
47824
  const bulkResponse = await workspaceService.fetchBulkTargets({
47411
47825
  companyId,
47412
47826
  lineIds,
47413
47827
  date: currentDate,
47414
- shifts: [0, 1],
47415
- // Fetch both shifts at once
47828
+ shifts: effectiveShiftOptions.map((s) => s.id),
47829
+ // Fetch all configured shifts
47416
47830
  includeSkus: skuEnabled,
47417
47831
  includeActions: true
47418
47832
  });
@@ -47430,10 +47844,14 @@ var TargetsView = ({
47430
47844
  packaging: packagingAction.id
47431
47845
  };
47432
47846
  setActionIds(actionIdsData);
47433
- const newAllShiftsData = { 0: {}, 1: {} };
47434
- const newDbValues = { 0: {}, 1: {} };
47847
+ const newAllShiftsData = {};
47848
+ const newDbValues = {};
47849
+ effectiveShiftOptions.forEach((opt) => {
47850
+ newAllShiftsData[opt.id] = {};
47851
+ newDbValues[opt.id] = {};
47852
+ });
47435
47853
  Object.entries(data.lines).forEach(([lineId, lineData]) => {
47436
- [0, 1].forEach((shiftId) => {
47854
+ effectiveShiftOptions.forEach(({ id: shiftId }) => {
47437
47855
  const shiftData = lineData.shifts[shiftId.toString()];
47438
47856
  if (!shiftData) {
47439
47857
  console.warn(`No shift ${shiftId} data for line ${lineId}`);
@@ -47604,7 +48022,7 @@ var TargetsView = ({
47604
48022
  setUserEditedFields(/* @__PURE__ */ new Set());
47605
48023
  if (dbValues[shiftId] && Object.keys(dbValues[shiftId]).length > 0) {
47606
48024
  setAllShiftsData((prev) => {
47607
- const updatedShiftData = { ...prev[shiftId] };
48025
+ const updatedShiftData = { ...prev[shiftId] || {} };
47608
48026
  for (const lineId of Object.keys(updatedShiftData)) {
47609
48027
  if (dbValues[shiftId][lineId]) {
47610
48028
  updatedShiftData[lineId] = {
@@ -47826,6 +48244,7 @@ var TargetsView = ({
47826
48244
  savingLines,
47827
48245
  saveSuccess,
47828
48246
  selectedShift,
48247
+ shiftOptions,
47829
48248
  isBulkConfigureOpen,
47830
48249
  navItems: [],
47831
48250
  currentPathname: "/targets",
@@ -47957,12 +48376,10 @@ var WorkspaceDetailView = ({
47957
48376
  const today = new Date((/* @__PURE__ */ new Date()).toLocaleString("en-US", { timeZone: timezone }));
47958
48377
  const [selectedMonth, setSelectedMonth] = useState(today.getMonth());
47959
48378
  const [selectedYear, setSelectedYear] = useState(today.getFullYear());
47960
- const [selectedShift, setSelectedShift] = useState("day");
48379
+ const [selectedShift, setSelectedShift] = useState(0);
47961
48380
  useEffect(() => {
47962
- if (parsedShiftId === 1) {
47963
- setSelectedShift("night");
47964
- } else if (parsedShiftId === 0) {
47965
- setSelectedShift("day");
48381
+ if (parsedShiftId !== void 0) {
48382
+ setSelectedShift(parsedShiftId);
47966
48383
  }
47967
48384
  }, [parsedShiftId]);
47968
48385
  const isHistoricView = Boolean(date && parsedShiftId !== void 0);
@@ -47974,6 +48391,13 @@ var WorkspaceDetailView = ({
47974
48391
  const dashboardConfig = useDashboardConfig();
47975
48392
  const isClipsEnabled = dashboardConfig?.clipsConfig?.enabled ?? true;
47976
48393
  dashboardConfig?.supervisorConfig?.enabled || false;
48394
+ const effectiveLineId = lineId || selectedLineId;
48395
+ const { shiftConfig, isLoading: isShiftConfigLoading } = useDynamicShiftConfig(effectiveLineId);
48396
+ const calculatedOperationalDate = useMemo(() => {
48397
+ if (isShiftConfigLoading || !shiftConfig) return null;
48398
+ const currentShift = getCurrentShift(timezone, shiftConfig);
48399
+ return currentShift.date;
48400
+ }, [isShiftConfigLoading, shiftConfig, timezone]);
47977
48401
  const {
47978
48402
  workspace: workspaceHealth,
47979
48403
  loading: healthLoading,
@@ -48034,7 +48458,9 @@ var WorkspaceDetailView = ({
48034
48458
  } = useHistoricWorkspaceMetrics(
48035
48459
  workspaceId || "",
48036
48460
  date || "",
48037
- parsedShiftId
48461
+ parsedShiftId,
48462
+ { shiftConfig, enabled: !isShiftConfigLoading }
48463
+ // Pass dynamic shift config and enabled flag
48038
48464
  );
48039
48465
  const {
48040
48466
  metrics: liveMetrics,
@@ -48042,11 +48468,13 @@ var WorkspaceDetailView = ({
48042
48468
  error: liveError
48043
48469
  } = useWorkspaceDetailedMetrics(
48044
48470
  workspaceId || "",
48045
- getOperationalDate(timezone),
48046
- void 0
48471
+ calculatedOperationalDate || getOperationalDate(timezone),
48472
+ void 0,
48473
+ { shiftConfig, enabled: !isShiftConfigLoading }
48474
+ // Pass the dynamic shift config here and enabled flag
48047
48475
  );
48048
48476
  const workspace = isHistoricView ? historicMetrics : liveMetrics;
48049
- const loading = isHistoricView ? historicLoading : liveLoading;
48477
+ const loading = (isHistoricView ? historicLoading : liveLoading) || isShiftConfigLoading;
48050
48478
  const error = isHistoricView ? historicError : liveError;
48051
48479
  const { supervisorName } = useLineSupervisor(workspace?.line_id || lineId);
48052
48480
  useEffect(() => {
@@ -48066,7 +48494,7 @@ var WorkspaceDetailView = ({
48066
48494
  }, [isClipsEnabled, activeTab]);
48067
48495
  useEffect(() => {
48068
48496
  if (liveMetrics && !date && !shift) {
48069
- const currentDate = getOperationalDate(timezone);
48497
+ const currentDate = calculatedOperationalDate || getOperationalDate(timezone);
48070
48498
  if (liveMetrics.date !== currentDate) {
48071
48499
  setUsingFallbackData(true);
48072
48500
  if (activeTab !== "monthly_history") {
@@ -48076,7 +48504,7 @@ var WorkspaceDetailView = ({
48076
48504
  setUsingFallbackData(false);
48077
48505
  }
48078
48506
  }
48079
- }, [liveMetrics, date, shift, activeTab]);
48507
+ }, [liveMetrics, date, shift, activeTab, calculatedOperationalDate]);
48080
48508
  useMemo(() => {
48081
48509
  if (isHistoricView && date) {
48082
48510
  try {
@@ -48084,11 +48512,11 @@ var WorkspaceDetailView = ({
48084
48512
  return date;
48085
48513
  } catch (e) {
48086
48514
  console.error("Error parsing historic date:", e);
48087
- return getOperationalDate(timezone);
48515
+ return calculatedOperationalDate || getOperationalDate(timezone);
48088
48516
  }
48089
48517
  }
48090
- return getOperationalDate(timezone);
48091
- }, [isHistoricView, date]);
48518
+ return calculatedOperationalDate || getOperationalDate(timezone);
48519
+ }, [isHistoricView, date, calculatedOperationalDate, timezone]);
48092
48520
  const handleMonthlyDataLoaded = useCallback((data) => {
48093
48521
  console.log("[handleMonthlyDataLoaded] Received data:", {
48094
48522
  dataLength: data?.length,
@@ -48112,10 +48540,8 @@ var WorkspaceDetailView = ({
48112
48540
  if (!dayEntry) {
48113
48541
  dayEntry = {
48114
48542
  date: dateObj,
48115
- dayShift: null,
48116
- // Start with null instead of zeros
48117
- nightShift: null
48118
- // Start with null instead of zeros
48543
+ shifts: {}
48544
+ // Multi-shift structure: Record<number, CalendarShiftData>
48119
48545
  };
48120
48546
  dayDataMap.set(dateKey, dayEntry);
48121
48547
  }
@@ -48127,19 +48553,14 @@ var WorkspaceDetailView = ({
48127
48553
  pphThreshold: metric.pph_threshold || 0,
48128
48554
  idealOutput: metric.ideal_output || 0,
48129
48555
  rank: metric.workspace_rank || 0,
48130
- idleTime: metric.idle_time || 0
48556
+ idleTime: metric.idle_time || 0,
48557
+ hasData: true
48131
48558
  };
48132
- if (metric.shift_id === 0) {
48133
- dayEntry.dayShift = shiftData;
48134
- } else {
48135
- dayEntry.nightShift = shiftData;
48136
- }
48559
+ dayEntry.shifts[metric.shift_id] = shiftData;
48137
48560
  });
48138
- const processedData = Array.from(dayDataMap.values()).filter((entry) => entry.dayShift !== null || entry.nightShift !== null).map((entry) => ({
48561
+ const processedData = Array.from(dayDataMap.values()).filter((entry) => Object.keys(entry.shifts).length > 0).map((entry) => ({
48139
48562
  date: entry.date,
48140
- // If a shift is null (no data), provide zeros for compatibility
48141
- dayShift: entry.dayShift || { efficiency: 0, output: 0, cycleTime: 0, pph: 0, pphThreshold: 0, idealOutput: 0, rank: 0, idleTime: 0 },
48142
- nightShift: entry.nightShift || { efficiency: 0, output: 0, cycleTime: 0, pph: 0, pphThreshold: 0, idealOutput: 0, rank: 0, idleTime: 0 }
48563
+ shifts: entry.shifts
48143
48564
  }));
48144
48565
  console.log(`[handleMonthlyDataLoaded] Transformed data for calendar:`, {
48145
48566
  count: processedData.length,
@@ -48147,7 +48568,6 @@ var WorkspaceDetailView = ({
48147
48568
  });
48148
48569
  setMonthlyData(processedData);
48149
48570
  }, []);
48150
- const effectiveLineId = lineId || selectedLineId;
48151
48571
  const formattedWorkspaceName = displayName || formatWorkspaceName3(workspace?.workspace_name || "", effectiveLineId);
48152
48572
  const shouldShowCycleTimeChart = showCycleTimeChart ?? formattedWorkspaceName.startsWith("FINAL ASSY");
48153
48573
  const handleBackNavigation = () => {
@@ -48168,7 +48588,7 @@ var WorkspaceDetailView = ({
48168
48588
  if (onNavigate) {
48169
48589
  const params = new URLSearchParams();
48170
48590
  params.set("fromMonthly", "true");
48171
- params.set("shift", selectedShift === "night" ? "1" : "0");
48591
+ params.set("shift", selectedShift.toString());
48172
48592
  if (effectiveLineId) {
48173
48593
  params.set("lineId", effectiveLineId);
48174
48594
  }
@@ -48180,7 +48600,7 @@ var WorkspaceDetailView = ({
48180
48600
  if (onNavigate) {
48181
48601
  const params = new URLSearchParams();
48182
48602
  params.set("fromMonthly", "true");
48183
- params.set("shift", selectedShift === "night" ? "1" : "0");
48603
+ params.set("shift", selectedShift.toString());
48184
48604
  if (effectiveLineId) {
48185
48605
  params.set("lineId", effectiveLineId);
48186
48606
  }
@@ -48193,11 +48613,16 @@ var WorkspaceDetailView = ({
48193
48613
  }
48194
48614
  }
48195
48615
  };
48196
- const getShiftIcon = (shiftType) => {
48197
- if (shiftType === "Day") {
48616
+ const getShiftIcon2 = (shiftType) => {
48617
+ const shiftTypeLower = shiftType?.toLowerCase() || "";
48618
+ if (shiftTypeLower.includes("day") || shiftTypeLower.includes("morning")) {
48198
48619
  return /* @__PURE__ */ jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ 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" }) });
48199
- } else {
48620
+ } else if (shiftTypeLower.includes("afternoon") || shiftTypeLower.includes("noon") || shiftTypeLower.includes("midday")) {
48621
+ return /* @__PURE__ */ jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ 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" }) });
48622
+ } else if (shiftTypeLower.includes("night") || shiftTypeLower.includes("evening")) {
48200
48623
  return /* @__PURE__ */ jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ 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" }) });
48624
+ } else {
48625
+ return /* @__PURE__ */ jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" }) });
48201
48626
  }
48202
48627
  };
48203
48628
  if (loading) {
@@ -48348,7 +48773,7 @@ var WorkspaceDetailView = ({
48348
48773
  /* @__PURE__ */ jsxs("div", { className: "sm:hidden mt-3 flex items-center justify-center gap-2", children: [
48349
48774
  /* @__PURE__ */ jsx("div", { className: "inline-flex items-center px-2.5 py-1 bg-gray-100 rounded-full", children: /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-gray-700", children: formatISTDate2(new Date(workspace.date)) }) }),
48350
48775
  /* @__PURE__ */ jsxs("div", { className: "inline-flex items-center gap-1 px-2.5 py-1 bg-gray-100 rounded-full", children: [
48351
- /* @__PURE__ */ jsx("div", { className: "text-gray-700 scale-90", children: getShiftIcon(workspace.shift_type) }),
48776
+ /* @__PURE__ */ jsx("div", { className: "text-gray-700 scale-90", children: getShiftIcon2(workspace.shift_type) }),
48352
48777
  /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-gray-700", children: workspace.shift_type })
48353
48778
  ] }),
48354
48779
  !date && !shift && !usingFallbackData ? /* @__PURE__ */ jsx("div", { className: "inline-flex items-center px-2.5 py-1 bg-green-100 rounded-full", children: /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-green-700", children: /* @__PURE__ */ jsx(LiveTimer, {}) }) }) : date ? /* @__PURE__ */ jsx("div", { className: "inline-flex items-center px-2.5 py-1 bg-blue-100 rounded-full", children: /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-blue-700", children: getDaysDifference(workspace.date, timezone, dashboardConfig?.shiftConfig?.dayShift?.startTime || "06:00") }) }) : usingFallbackData ? /* @__PURE__ */ jsx("div", { className: "inline-flex items-center px-2.5 py-1 bg-amber-100 rounded-full", children: /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-amber-700", children: getDaysDifference(workspace.date, timezone, dashboardConfig?.shiftConfig?.dayShift?.startTime || "06:00") }) }) : null
@@ -48373,11 +48798,8 @@ var WorkspaceDetailView = ({
48373
48798
  /* @__PURE__ */ jsx("div", { className: "w-px h-4 bg-blue-300" })
48374
48799
  ] }),
48375
48800
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
48376
- /* @__PURE__ */ jsx("div", { className: "text-blue-600", children: getShiftIcon(workspace.shift_type) }),
48377
- /* @__PURE__ */ jsxs("span", { className: "text-sm md:text-base font-medium text-blue-600", children: [
48378
- workspace.shift_type,
48379
- " Shift"
48380
- ] })
48801
+ /* @__PURE__ */ jsx("div", { className: "text-blue-600", children: getShiftIcon2(workspace.shift_type) }),
48802
+ /* @__PURE__ */ jsx("span", { className: "text-sm md:text-base font-medium text-blue-600", children: workspace.shift_type })
48381
48803
  ] })
48382
48804
  ] }) })
48383
48805
  ] }),
@@ -48444,7 +48866,7 @@ var WorkspaceDetailView = ({
48444
48866
  monthlyData,
48445
48867
  selectedMonth,
48446
48868
  selectedYear,
48447
- selectedShift
48869
+ selectedShiftId: selectedShift
48448
48870
  }
48449
48871
  ) })
48450
48872
  ] })
@@ -48713,15 +49135,16 @@ var WorkspaceDetailView = ({
48713
49135
  month: selectedMonth,
48714
49136
  year: selectedYear,
48715
49137
  workspaceId,
48716
- selectedShift,
49138
+ selectedShiftId: selectedShift,
48717
49139
  monthlyDataLoading,
48718
- onDateSelect: (selectedDate, shift2) => {
49140
+ availableShifts: shiftConfig?.shifts?.map((s) => ({ id: s.shiftId, name: s.shiftName })),
49141
+ onDateSelect: (selectedDate, shiftId) => {
48719
49142
  if (onDateSelect) {
48720
- onDateSelect(selectedDate, shift2);
49143
+ onDateSelect(selectedDate, shiftId);
48721
49144
  } else if (onNavigate) {
48722
49145
  const params = new URLSearchParams();
48723
49146
  params.set("date", selectedDate);
48724
- params.set("shift", shift2 === "day" ? "0" : "1");
49147
+ params.set("shift", shiftId.toString());
48725
49148
  params.set("fromMonthly", "true");
48726
49149
  if (effectiveLineId) {
48727
49150
  params.set("lineId", effectiveLineId);
@@ -48744,6 +49167,7 @@ var WorkspaceDetailView = ({
48744
49167
  workspaceId,
48745
49168
  workspaceName: formattedWorkspaceName,
48746
49169
  date,
49170
+ lineId: effectiveLineId,
48747
49171
  shift,
48748
49172
  totalOutput: workspace?.total_actions,
48749
49173
  className: "h-[calc(100vh-10rem)]"
@@ -48900,6 +49324,13 @@ var SKUManagementView = () => {
48900
49324
  var useWorkspaceHealth = (options) => {
48901
49325
  const supabase = useSupabase();
48902
49326
  const databaseConfig = useDatabaseConfig();
49327
+ const entityConfig = useEntityConfig();
49328
+ const configuredLineIds = useMemo(() => getConfiguredLineIds(entityConfig), [entityConfig]);
49329
+ const firstConfiguredLineId = configuredLineIds[0];
49330
+ const isFactoryView = !options.lineId || options.lineId === (entityConfig?.factoryViewId || "factory");
49331
+ const effectiveLineIdForShiftConfig = isFactoryView ? firstConfiguredLineId : options.lineId;
49332
+ const { shiftConfig, isLoading: isShiftConfigLoading } = useDynamicShiftConfig(effectiveLineIdForShiftConfig);
49333
+ const timezone = useAppTimezone() || "UTC";
48903
49334
  const [workspaces, setWorkspaces] = useState([]);
48904
49335
  const [summary, setSummary] = useState({
48905
49336
  totalWorkspaces: 0,
@@ -48946,6 +49377,14 @@ var useWorkspaceHealth = (options) => {
48946
49377
  }, []);
48947
49378
  const fetchWorkspacesHealth = useCallback(async () => {
48948
49379
  if (isFetchingRef.current) return;
49380
+ if (isShiftConfigLoading) {
49381
+ console.log("[useWorkspaceHealth] \u23F3 Waiting for shift config to load");
49382
+ return;
49383
+ }
49384
+ if (!shiftConfig) {
49385
+ console.warn("[useWorkspaceHealth] \u26A0\uFE0F Shift config is null, waiting for it to load");
49386
+ return;
49387
+ }
48949
49388
  if (!options.companyId) {
48950
49389
  setWorkspaces([]);
48951
49390
  setSummary(computeSummary([]));
@@ -48956,9 +49395,16 @@ var useWorkspaceHealth = (options) => {
48956
49395
  isFetchingRef.current = true;
48957
49396
  setLoading(true);
48958
49397
  setError(null);
49398
+ console.log("[useWorkspaceHealth] \u{1F680} Fetching health status with shift config:", {
49399
+ lineId: options.lineId,
49400
+ hasShiftConfig: !!shiftConfig,
49401
+ shiftId: shiftConfig?.shifts?.[0]?.shiftId
49402
+ });
48959
49403
  const workspacesWithStatus = await workspaceHealthService.getWorkspaceHealthStatus({
48960
49404
  lineId: options.lineId,
48961
- companyId: options.companyId
49405
+ companyId: options.companyId,
49406
+ shiftConfig,
49407
+ timezone
48962
49408
  });
48963
49409
  setWorkspaces(workspacesWithStatus);
48964
49410
  setSummary(computeSummary(workspacesWithStatus));
@@ -48970,7 +49416,7 @@ var useWorkspaceHealth = (options) => {
48970
49416
  setLoading(false);
48971
49417
  isFetchingRef.current = false;
48972
49418
  }
48973
- }, [options.companyId, options.lineId, computeSummary]);
49419
+ }, [options.companyId, options.lineId, computeSummary, shiftConfig, isShiftConfigLoading, timezone]);
48974
49420
  useEffect(() => {
48975
49421
  fetchWorkspacesHealth();
48976
49422
  }, [fetchWorkspacesHealth]);
@@ -49010,9 +49456,12 @@ var useWorkspaceHealth = (options) => {
49010
49456
  return {
49011
49457
  workspaces,
49012
49458
  summary,
49013
- loading,
49459
+ loading: loading || isShiftConfigLoading || !shiftConfig,
49014
49460
  error,
49015
- refetch: fetchWorkspacesHealth
49461
+ refetch: fetchWorkspacesHealth,
49462
+ // Expose shift config so consumers can pass it to child components
49463
+ shiftConfig,
49464
+ isShiftConfigLoading
49016
49465
  };
49017
49466
  };
49018
49467
  var STATUS_COLORS = {
@@ -49211,7 +49660,8 @@ var formatTimeRange = (start, end, timezone) => {
49211
49660
  var WorkspaceUptimeDetailModal = ({
49212
49661
  workspace,
49213
49662
  isOpen,
49214
- onClose
49663
+ onClose,
49664
+ shiftConfig: passedShiftConfig
49215
49665
  }) => {
49216
49666
  const timezone = useAppTimezone() || "UTC";
49217
49667
  const logsContainerRef = useRef(null);
@@ -49225,7 +49675,12 @@ var WorkspaceUptimeDetailModal = ({
49225
49675
  workspaceId: workspace?.workspace_id,
49226
49676
  companyId: workspace?.company_id,
49227
49677
  enabled: isOpen && Boolean(workspace?.workspace_id && workspace?.company_id),
49228
- refreshInterval: 6e4
49678
+ refreshInterval: 6e4,
49679
+ lineId: workspace?.line_id,
49680
+ // Pass shift config from parent if available - avoids duplicate DB queries
49681
+ // and ensures consistent shift timing across the view
49682
+ shiftConfig: passedShiftConfig || void 0,
49683
+ timezone
49229
49684
  });
49230
49685
  useEffect(() => {
49231
49686
  if (!isOpen || !workspace) return;
@@ -49412,32 +49867,48 @@ var WorkspaceHealthView = ({
49412
49867
  }) => {
49413
49868
  const router = useRouter();
49414
49869
  const [groupBy, setGroupBy] = useState("line");
49870
+ const entityConfig = useEntityConfig();
49871
+ const configuredLineIds = useMemo(() => getConfiguredLineIds(entityConfig), [entityConfig]);
49872
+ const firstConfiguredLineId = configuredLineIds[0];
49873
+ const factoryViewId = entityConfig?.factoryViewId || "factory";
49874
+ const isFactoryView = !lineId || lineId === factoryViewId;
49875
+ const effectiveLineId = isFactoryView ? firstConfiguredLineId : lineId;
49415
49876
  const timezone = useAppTimezone();
49877
+ const { shiftConfig, isLoading: isShiftConfigLoading } = useDynamicShiftConfig(effectiveLineId);
49416
49878
  const [selectedWorkspace, setSelectedWorkspace] = useState(null);
49417
- const operationalDate = getOperationalDate(timezone || "UTC");
49418
- const currentHour = (/* @__PURE__ */ new Date()).getHours();
49419
- const isNightShift = currentHour >= 18 || currentHour < 6;
49420
- const shiftType = isNightShift ? "Night" : "Day";
49879
+ const effectiveTimezone = timezone || "UTC";
49880
+ const currentShiftDetails = getCurrentShift(effectiveTimezone, shiftConfig);
49881
+ const operationalDate = currentShiftDetails.date;
49882
+ const shiftType = (currentShiftDetails.shiftName || "Day").replace(/ Shift$/i, "");
49421
49883
  const formatDate = (date) => {
49422
49884
  const d = new Date(date);
49423
49885
  return d.toLocaleDateString("en-IN", {
49424
49886
  month: "long",
49425
49887
  day: "numeric",
49426
49888
  year: "numeric",
49427
- timeZone: "Asia/Kolkata"
49889
+ timeZone: effectiveTimezone
49428
49890
  });
49429
49891
  };
49430
- const getShiftIcon = (shift) => {
49431
- return shift === "Night" ? /* @__PURE__ */ jsx(Moon, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx(Sun, { className: "h-4 w-4" });
49892
+ const getShiftIcon2 = () => {
49893
+ const shiftName = (currentShiftDetails.shiftName || "").toLowerCase();
49894
+ if (shiftName.includes("night") || shiftName.includes("evening") || currentShiftDetails.shiftId === 1) {
49895
+ return /* @__PURE__ */ jsx(Moon, { className: "h-4 w-4" });
49896
+ }
49897
+ if (shiftName.includes("afternoon") || shiftName.includes("noon") || shiftName.includes("midday")) {
49898
+ return /* @__PURE__ */ jsx(Sun, { className: "h-4 w-4" });
49899
+ }
49900
+ return /* @__PURE__ */ jsx(Sun, { className: "h-4 w-4" });
49432
49901
  };
49433
49902
  const {
49434
49903
  workspaces,
49435
49904
  summary,
49436
49905
  loading,
49437
49906
  error,
49438
- refetch
49907
+ refetch,
49908
+ shiftConfig: loadedShiftConfig
49909
+ // Get shift config from the hook to pass to modal
49439
49910
  } = useWorkspaceHealth({
49440
- lineId,
49911
+ lineId: effectiveLineId,
49441
49912
  companyId,
49442
49913
  enableRealtime: true,
49443
49914
  refreshInterval: 1e4
@@ -49499,7 +49970,7 @@ var WorkspaceHealthView = ({
49499
49970
  if (percentage >= 90) return "text-yellow-600 dark:text-yellow-400";
49500
49971
  return "text-red-600 dark:text-red-400";
49501
49972
  };
49502
- if (loading && !summary) {
49973
+ if (loading && !summary || isShiftConfigLoading) {
49503
49974
  return /* @__PURE__ */ jsx("div", { className: "min-h-screen bg-gray-50 dark:bg-gray-900 p-4", children: /* @__PURE__ */ jsx(LoadingState, {}) });
49504
49975
  }
49505
49976
  if (error) {
@@ -49609,7 +50080,7 @@ var WorkspaceHealthView = ({
49609
50080
  /* @__PURE__ */ jsx("span", { className: "text-xs sm:text-sm md:text-base font-medium text-blue-600", children: formatDate(operationalDate) }),
49610
50081
  /* @__PURE__ */ jsx("div", { className: "hidden sm:block w-px h-4 bg-blue-300" }),
49611
50082
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 sm:gap-2", children: [
49612
- /* @__PURE__ */ jsx("div", { className: "text-blue-600", children: getShiftIcon(shiftType) }),
50083
+ /* @__PURE__ */ jsx("div", { className: "text-blue-600", children: getShiftIcon2() }),
49613
50084
  /* @__PURE__ */ jsxs("span", { className: "text-xs sm:text-sm md:text-base font-medium text-blue-600", children: [
49614
50085
  shiftType,
49615
50086
  " Shift"
@@ -49697,7 +50168,8 @@ var WorkspaceHealthView = ({
49697
50168
  {
49698
50169
  workspace: selectedWorkspace,
49699
50170
  isOpen: Boolean(selectedWorkspace),
49700
- onClose: handleCloseDetails
50171
+ onClose: handleCloseDetails,
50172
+ shiftConfig: loadedShiftConfig
49701
50173
  }
49702
50174
  )
49703
50175
  ] });
@@ -51734,25 +52206,15 @@ var TeamManagementView_default = TeamManagementView;
51734
52206
  function BottleneckClipsView({
51735
52207
  workspaceId: propWorkspaceId,
51736
52208
  workspaceName: propWorkspaceName,
52209
+ lineId: propLineId,
51737
52210
  date: propDate,
51738
52211
  shift: propShift,
51739
52212
  totalOutput: propTotalOutput
51740
52213
  }) {
51741
52214
  const router = useRouter();
51742
- const dashboardConfig = useDashboardConfig();
51743
- const timezone = useAppTimezone();
51744
52215
  const workspaceId = propWorkspaceId || router.query.workspaceId;
51745
52216
  const workspaceName = propWorkspaceName || router.query.workspaceName || "Workstation";
51746
- const operationalDate = useMemo(() => {
51747
- if (propDate) return propDate;
51748
- return getOperationalDate(timezone || dashboardConfig.dateTimeConfig?.defaultTimezone || "UTC");
51749
- }, [propDate, timezone, dashboardConfig]);
51750
- const currentShift = useMemo(() => {
51751
- if (propShift !== void 0) return propShift;
51752
- const tz = timezone || dashboardConfig.dateTimeConfig?.defaultTimezone || "UTC";
51753
- const shiftResult = getCurrentShift(tz, dashboardConfig?.shiftConfig);
51754
- return shiftResult.shiftId;
51755
- }, [propShift, dashboardConfig, timezone]);
52217
+ const lineId = propLineId || router.query.lineId;
51756
52218
  if (!workspaceId) {
51757
52219
  return /* @__PURE__ */ jsx(LoadingPage_default, { message: "Loading workspace data..." });
51758
52220
  }
@@ -51801,8 +52263,9 @@ function BottleneckClipsView({
51801
52263
  {
51802
52264
  workspaceId,
51803
52265
  workspaceName,
51804
- date: operationalDate,
51805
- shift: currentShift,
52266
+ lineId,
52267
+ date: propDate,
52268
+ shift: propShift,
51806
52269
  totalOutput: propTotalOutput,
51807
52270
  className: "h-full"
51808
52271
  }
@@ -53268,4 +53731,4 @@ function shuffleArray(array) {
53268
53731
  return shuffled;
53269
53732
  }
53270
53733
 
53271
- export { ACTION_NAMES, AIAgentView_default as AIAgentView, AcceptInvite, AcceptInviteView_default as AcceptInviteView, AdvancedFilterDialog, AdvancedFilterPanel, AudioService, AuthCallback, AuthCallbackView_default as AuthCallbackView, AuthProvider, AuthService, AuthenticatedBottleneckClipsView, AuthenticatedFactoryView, AuthenticatedHelpView, AuthenticatedHomeView, AuthenticatedShiftsView, AuthenticatedTargetsView, AuthenticatedTicketsView, AuthenticatedWorkspaceHealthView, AxelNotificationPopup, AxelOrb, BackButton, BackButtonMinimal, BarChart, BaseHistoryCalendar, BottleneckClipsModal, BottleneckClipsView_default as BottleneckClipsView, BottlenecksContent, BreakNotificationPopup, CachePrefetchStatus, Card2 as Card, CardContent2 as CardContent, CardDescription2 as CardDescription, CardFooter2 as CardFooter, CardHeader2 as CardHeader, CardTitle2 as CardTitle, ClipFilterProvider, CompactWorkspaceHealthCard, CongratulationsOverlay, CroppedHlsVideoPlayer, CroppedVideoPlayer, CycleTimeChart, CycleTimeOverTimeChart, DEFAULT_ANALYTICS_CONFIG, DEFAULT_AUTH_CONFIG, DEFAULT_CONFIG, DEFAULT_DATABASE_CONFIG, DEFAULT_DATE_TIME_CONFIG, DEFAULT_ENDPOINTS_CONFIG, DEFAULT_ENTITY_CONFIG, DEFAULT_MAP_VIEW_CONFIG, DEFAULT_SHIFT_CONFIG, DEFAULT_THEME_CONFIG, DEFAULT_VIDEO_CONFIG, DEFAULT_WORKSPACE_CONFIG, DEFAULT_WORKSPACE_POSITIONS, DashboardHeader, DashboardLayout, DashboardOverridesProvider, DashboardProvider, DateDisplay_default as DateDisplay, DateTimeDisplay, DebugAuth, DebugAuthView_default as DebugAuthView, DetailedHealthStatus, DiagnosisVideoModal, EmptyStateMessage, EncouragementOverlay, FactoryView_default as FactoryView, FileManagerFilters, FilterDialogTrigger, FirstTimeLoginDebug, FirstTimeLoginHandler, GaugeChart, GridComponentsPlaceholder, HamburgerButton, Header, HealthStatusGrid, HealthStatusIndicator, HelpView_default as HelpView, HlsVideoPlayer, HomeView_default as HomeView, HourlyOutputChart2 as HourlyOutputChart, ISTTimer_default as ISTTimer, InlineEditableText, InteractiveOnboardingTour, InvitationService, KPICard, KPIDetailView_default as KPIDetailView, KPIGrid, KPIHeader, KPISection, KPIsOverviewView_default as KPIsOverviewView, LINE_1_UUID, LINE_2_UUID, LargeOutputProgressChart, LeaderboardDetailView_default as LeaderboardDetailView, Legend6 as Legend, LineChart, LineHistoryCalendar, LineMonthlyHistory, LineMonthlyPdfGenerator, LinePdfExportButton, LinePdfGenerator, LineWhatsAppShareButton, LinesService, LiveTimer, LoadingInline, LoadingOverlay_default as LoadingOverlay, LoadingPage_default as LoadingPage, LoadingSkeleton, LoadingState, LoginPage, LoginView_default as LoginView, Logo, MainLayout, MapGridView, MetricCard_default as MetricCard, MinimalOnboardingPopup, NewClipsNotification, NoWorkspaceData, OnboardingDemo, OnboardingTour, OptifyeAgentClient, OptifyeLogoLoader_default as OptifyeLogoLoader, OutputProgressChart, PageHeader, PieChart4 as PieChart, PlayPauseIndicator, PrefetchConfigurationError, PrefetchError, PrefetchEvents, PrefetchStatus, PrefetchTimeoutError, ProfileView_default as ProfileView, RegistryProvider, S3ClipsSupabaseService as S3ClipsService, S3Service, SKUManagementView, SOPComplianceChart, SSEChatClient, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, ShiftDisplay_default as ShiftDisplay, ShiftsView_default as ShiftsView, SideNavBar, SignupWithInvitation, SilentErrorBoundary, SimpleOnboardingPopup, SingleVideoStream_default as SingleVideoStream, Skeleton, SubscriptionManager, SubscriptionManagerProvider, SupabaseProvider, SupervisorDropdown_default as SupervisorDropdown, SupervisorManagementView_default as SupervisorManagementView, SupervisorService, TargetWorkspaceGrid, TargetsView_default as TargetsView, TeamManagementView_default as TeamManagementView, ThreadSidebar, TicketHistory_default as TicketHistory, TicketHistoryService, TicketsView_default as TicketsView, TimeDisplay_default as TimeDisplay, TimePickerDropdown, Timer_default as Timer, TimezoneProvider, TimezoneService, UserManagementService, UserService, VideoCard, VideoGridView, VideoPlayer, VideoPreloader, WORKSPACE_POSITIONS, WhatsAppShareButton, WorkspaceCard, WorkspaceDetailView_default as WorkspaceDetailView, WorkspaceDisplayNameExample, WorkspaceGrid, WorkspaceGridItem, WorkspaceHealthCard, WorkspaceHealthView_default as WorkspaceHealthView, WorkspaceHistoryCalendar, WorkspaceMetricCards, WorkspaceMetricCardsImpl, WorkspaceMonthlyDataFetcher, WorkspaceMonthlyHistory, WorkspaceMonthlyPdfGenerator, WorkspacePdfExportButton, WorkspacePdfGenerator, WorkspaceWhatsAppShareButton, actionService, apiUtils, authCoreService, authOTPService, authRateLimitService, checkRateLimit2 as checkRateLimit, clearAllRateLimits2 as clearAllRateLimits, clearRateLimit2 as clearRateLimit, clearS3VideoCache, clearS3VideoFromCache, clearWorkspaceDisplayNamesCache, cn, createInvitationService, createLinesService, createStreamProxyHandler, createSupabaseClient, createSupervisorService, createThrottledReload, createUserManagementService, createUserService, dashboardService, deleteThread, forceRefreshWorkspaceDisplayNames, formatDateInZone, formatDateTimeInZone, formatISTDate, formatIdleTime, formatRelativeTime, formatTimeInZone, fromUrlFriendlyName, getAllLineDisplayNames, getAllThreadMessages, getAllWorkspaceDisplayNamesAsync, getAnonClient, getBrowserName, getCameraNumber, getCompanyMetricsTableName, getConfigurableShortWorkspaceDisplayName, getConfigurableWorkspaceDisplayName, getConfiguredLineIds, getCoreSessionRecordingProperties, getCoreSessionReplayUrl, getCurrentShift, getCurrentTimeInZone, getDashboardHeaderTimeInZone, getDaysDifferenceInZone, getDefaultCameraStreamUrl, getDefaultLineId, getDefaultTabForWorkspace, getLineDisplayName, getManufacturingInsights, getMetricsTablePrefix, getNextUpdateInterval, getOperationalDate, getS3SignedUrl, getS3VideoSrc, getShortWorkspaceDisplayName, getShortWorkspaceDisplayNameAsync, getStoredWorkspaceMappings, getSubscriptionManager, getThreadMessages, getUserThreads, getUserThreadsPaginated, getWorkspaceDisplayName, getWorkspaceDisplayNameAsync, getWorkspaceDisplayNamesMap, getWorkspaceFromUrl, getWorkspaceNavigationParams, identifyCoreUser, initializeCoreMixpanel, isLegacyConfiguration, isPrefetchError, isSafari, isTransitionPeriod, isUrlPermanentlyFailed, isValidFactoryViewConfiguration, isValidLineInfoPayload, isValidPrefetchParams, isValidPrefetchStatus, isValidWorkspaceDetailedMetricsPayload, isValidWorkspaceMetricsPayload, isWorkspaceDisplayNamesLoaded, isWorkspaceDisplayNamesLoading, linesService, mergeWithDefaultConfig, migrateLegacyConfiguration, optifyeAgentClient, parseS3Uri, preInitializeWorkspaceDisplayNames, preloadS3Video, preloadS3VideoUrl, preloadS3VideosUrl, preloadVideoUrl, preloadVideosUrl, qualityService, realtimeService, refreshWorkspaceDisplayNames, resetCoreMixpanel, resetFailedUrl, resetSubscriptionManager, s3VideoPreloader, shuffleArray, simulateApiDelay, skuService, startCoreSessionRecording, stopCoreSessionRecording, storeWorkspaceMapping, streamProxyConfig, throttledReloadDashboard, toUrlFriendlyName, trackCoreEvent, trackCorePageView, updateThreadTitle, useAccessControl, useActiveBreaks, useActiveLineId, useAllWorkspaceMetrics, useAnalyticsConfig, useAppTimezone, useAudioService, useAuth, useAuthConfig, useAxelNotifications, useCanSaveTargets, useClipFilter, useClipTypes, useClipTypesWithCounts, useComponentOverride, useCustomConfig, useDashboardConfig, useDashboardMetrics, useDatabaseConfig, useDateFormatter, useDateTimeConfig, useDynamicShiftConfig, useEndpointsConfig, useEntityConfig, useFactoryOverviewMetrics, useFeatureFlags, useFormatNumber, useHasLineAccess, useHistoricWorkspaceMetrics, useHlsStream, useHlsStreamWithCropping, useHookOverride, useHourEndTimer, useHourlyTargetAchievements, useHourlyTargetMisses, useLeaderboardMetrics, useLineDetailedMetrics, useLineKPIs, useLineMetrics, useLineShiftConfig, useLineSupervisor, useLineWorkspaceMetrics, useMessages, useMetrics, useNavigation, useOverrides, usePageOverride, usePrefetchClipCounts, useRealtimeLineMetrics, useRegistry, useSKUs, useSessionKeepAlive, useShiftConfig, useShifts, useSubscriptionManager, useSubscriptionManagerSafe, useSupabase, useSupabaseClient, useTargets, useTeamManagementPermissions, useTheme, useThemeConfig, useThreads, useTicketHistory, useTimezoneContext, useUserLineAccess, useVideoConfig, useWorkspaceConfig, useWorkspaceDetailedMetrics, useWorkspaceDisplayName, useWorkspaceDisplayNames, useWorkspaceDisplayNamesMap, useWorkspaceHealthById, useWorkspaceHealthStatus, useWorkspaceMetrics, useWorkspaceNavigation, useWorkspaceOperators, useWorkspaceUptimeTimeline, userService, videoPrefetchManager, videoPreloader, whatsappService, withAccessControl, withAuth, withRegistry, withTimezone, workspaceHealthService, workspaceService };
53734
+ export { ACTION_NAMES, AIAgentView_default as AIAgentView, AcceptInvite, AcceptInviteView_default as AcceptInviteView, AdvancedFilterDialog, AdvancedFilterPanel, AudioService, AuthCallback, AuthCallbackView_default as AuthCallbackView, AuthProvider, AuthService, AuthenticatedBottleneckClipsView, AuthenticatedFactoryView, AuthenticatedHelpView, AuthenticatedHomeView, AuthenticatedShiftsView, AuthenticatedTargetsView, AuthenticatedTicketsView, AuthenticatedWorkspaceHealthView, AxelNotificationPopup, AxelOrb, BackButton, BackButtonMinimal, BarChart, BaseHistoryCalendar, BottleneckClipsModal, BottleneckClipsView_default as BottleneckClipsView, BottlenecksContent, BreakNotificationPopup, CachePrefetchStatus, Card2 as Card, CardContent2 as CardContent, CardDescription2 as CardDescription, CardFooter2 as CardFooter, CardHeader2 as CardHeader, CardTitle2 as CardTitle, ClipFilterProvider, CompactWorkspaceHealthCard, CongratulationsOverlay, CroppedHlsVideoPlayer, CroppedVideoPlayer, CycleTimeChart, CycleTimeOverTimeChart, DEFAULT_ANALYTICS_CONFIG, DEFAULT_AUTH_CONFIG, DEFAULT_CONFIG, DEFAULT_DATABASE_CONFIG, DEFAULT_DATE_TIME_CONFIG, DEFAULT_ENDPOINTS_CONFIG, DEFAULT_ENTITY_CONFIG, DEFAULT_MAP_VIEW_CONFIG, DEFAULT_SHIFT_CONFIG, DEFAULT_SHIFT_DATA, DEFAULT_THEME_CONFIG, DEFAULT_VIDEO_CONFIG, DEFAULT_WORKSPACE_CONFIG, DEFAULT_WORKSPACE_POSITIONS, DashboardHeader, DashboardLayout, DashboardOverridesProvider, DashboardProvider, DateDisplay_default as DateDisplay, DateTimeDisplay, DebugAuth, DebugAuthView_default as DebugAuthView, DetailedHealthStatus, DiagnosisVideoModal, EmptyStateMessage, EncouragementOverlay, FactoryView_default as FactoryView, FileManagerFilters, FilterDialogTrigger, FirstTimeLoginDebug, FirstTimeLoginHandler, GaugeChart, GridComponentsPlaceholder, HamburgerButton, Header, HealthStatusGrid, HealthStatusIndicator, HelpView_default as HelpView, HlsVideoPlayer, HomeView_default as HomeView, HourlyOutputChart2 as HourlyOutputChart, ISTTimer_default as ISTTimer, InlineEditableText, InteractiveOnboardingTour, InvitationService, KPICard, KPIDetailView_default as KPIDetailView, KPIGrid, KPIHeader, KPISection, KPIsOverviewView_default as KPIsOverviewView, LINE_1_UUID, LINE_2_UUID, LargeOutputProgressChart, LeaderboardDetailView_default as LeaderboardDetailView, Legend6 as Legend, LineChart, LineHistoryCalendar, LineMonthlyHistory, LineMonthlyPdfGenerator, LinePdfExportButton, LinePdfGenerator, LineWhatsAppShareButton, LinesService, LiveTimer, LoadingInline, LoadingOverlay_default as LoadingOverlay, LoadingPage_default as LoadingPage, LoadingSkeleton, LoadingState, LoginPage, LoginView_default as LoginView, Logo, MainLayout, MapGridView, MetricCard_default as MetricCard, MinimalOnboardingPopup, NewClipsNotification, NoWorkspaceData, OnboardingDemo, OnboardingTour, OptifyeAgentClient, OptifyeLogoLoader_default as OptifyeLogoLoader, OutputProgressChart, PageHeader, PieChart4 as PieChart, PlayPauseIndicator, PrefetchConfigurationError, PrefetchError, PrefetchEvents, PrefetchStatus, PrefetchTimeoutError, ProfileView_default as ProfileView, RegistryProvider, S3ClipsSupabaseService as S3ClipsService, S3Service, SKUManagementView, SOPComplianceChart, SSEChatClient, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, ShiftDisplay_default as ShiftDisplay, ShiftsView_default as ShiftsView, SideNavBar, SignupWithInvitation, SilentErrorBoundary, SimpleOnboardingPopup, SingleVideoStream_default as SingleVideoStream, Skeleton, SubscriptionManager, SubscriptionManagerProvider, SupabaseProvider, SupervisorDropdown_default as SupervisorDropdown, SupervisorManagementView_default as SupervisorManagementView, SupervisorService, TargetWorkspaceGrid, TargetsView_default as TargetsView, TeamManagementView_default as TeamManagementView, ThreadSidebar, TicketHistory_default as TicketHistory, TicketHistoryService, TicketsView_default as TicketsView, TimeDisplay_default as TimeDisplay, TimePickerDropdown, Timer_default as Timer, TimezoneProvider, TimezoneService, UserManagementService, UserService, VideoCard, VideoGridView, VideoPlayer, VideoPreloader, WORKSPACE_POSITIONS, WhatsAppShareButton, WorkspaceCard, WorkspaceDetailView_default as WorkspaceDetailView, WorkspaceDisplayNameExample, WorkspaceGrid, WorkspaceGridItem, WorkspaceHealthCard, WorkspaceHealthView_default as WorkspaceHealthView, WorkspaceHistoryCalendar, WorkspaceMetricCards, WorkspaceMetricCardsImpl, WorkspaceMonthlyDataFetcher, WorkspaceMonthlyHistory, WorkspaceMonthlyPdfGenerator, WorkspacePdfExportButton, WorkspacePdfGenerator, WorkspaceWhatsAppShareButton, actionService, apiUtils, authCoreService, authOTPService, authRateLimitService, checkRateLimit2 as checkRateLimit, clearAllRateLimits2 as clearAllRateLimits, clearRateLimit2 as clearRateLimit, clearS3VideoCache, clearS3VideoFromCache, clearWorkspaceDisplayNamesCache, cn, createInvitationService, createLinesService, createStreamProxyHandler, createSupabaseClient, createSupervisorService, createThrottledReload, createUserManagementService, createUserService, dashboardService, deleteThread, forceRefreshWorkspaceDisplayNames, formatDateInZone, formatDateTimeInZone, formatISTDate, formatIdleTime, formatRelativeTime, formatTimeInZone, fromUrlFriendlyName, getAllLineDisplayNames, getAllThreadMessages, getAllWorkspaceDisplayNamesAsync, getAnonClient, getAvailableShiftIds, getBrowserName, getCameraNumber, getCompanyMetricsTableName, getConfigurableShortWorkspaceDisplayName, getConfigurableWorkspaceDisplayName, getConfiguredLineIds, getCoreSessionRecordingProperties, getCoreSessionReplayUrl, getCurrentShift, getCurrentTimeInZone, getDashboardHeaderTimeInZone, getDaysDifferenceInZone, getDefaultCameraStreamUrl, getDefaultLineId, getDefaultTabForWorkspace, getLineDisplayName, getManufacturingInsights, getMetricsTablePrefix, getNextUpdateInterval, getOperationalDate, getS3SignedUrl, getS3VideoSrc, getShiftData, getShiftNameById, getShortShiftName, getShortWorkspaceDisplayName, getShortWorkspaceDisplayNameAsync, getStoredWorkspaceMappings, getSubscriptionManager, getThreadMessages, getUserThreads, getUserThreadsPaginated, getWorkspaceDisplayName, getWorkspaceDisplayNameAsync, getWorkspaceDisplayNamesMap, getWorkspaceFromUrl, getWorkspaceNavigationParams, hasAnyShiftData, identifyCoreUser, initializeCoreMixpanel, isLegacyConfiguration, isPrefetchError, isSafari, isTransitionPeriod, isUrlPermanentlyFailed, isValidFactoryViewConfiguration, isValidLineInfoPayload, isValidPrefetchParams, isValidPrefetchStatus, isValidWorkspaceDetailedMetricsPayload, isValidWorkspaceMetricsPayload, isWorkspaceDisplayNamesLoaded, isWorkspaceDisplayNamesLoading, linesService, mergeWithDefaultConfig, migrateLegacyConfiguration, optifyeAgentClient, parseS3Uri, preInitializeWorkspaceDisplayNames, preloadS3Video, preloadS3VideoUrl, preloadS3VideosUrl, preloadVideoUrl, preloadVideosUrl, qualityService, realtimeService, refreshWorkspaceDisplayNames, resetCoreMixpanel, resetFailedUrl, resetSubscriptionManager, s3VideoPreloader, shuffleArray, simulateApiDelay, skuService, startCoreSessionRecording, stopCoreSessionRecording, storeWorkspaceMapping, streamProxyConfig, throttledReloadDashboard, toUrlFriendlyName, trackCoreEvent, trackCorePageView, updateThreadTitle, useAccessControl, useActiveBreaks, useActiveLineId, useAllWorkspaceMetrics, useAnalyticsConfig, useAppTimezone, useAudioService, useAuth, useAuthConfig, useAxelNotifications, useCanSaveTargets, useClipFilter, useClipTypes, useClipTypesWithCounts, useComponentOverride, useCustomConfig, useDashboardConfig, useDashboardMetrics, useDatabaseConfig, useDateFormatter, useDateTimeConfig, useDynamicShiftConfig, useEndpointsConfig, useEntityConfig, useFactoryOverviewMetrics, useFeatureFlags, useFormatNumber, useHasLineAccess, useHistoricWorkspaceMetrics, useHlsStream, useHlsStreamWithCropping, useHookOverride, useHourEndTimer, useHourlyTargetAchievements, useHourlyTargetMisses, useLeaderboardMetrics, useLineDetailedMetrics, useLineKPIs, useLineMetrics, useLineShiftConfig, useLineSupervisor, useLineWorkspaceMetrics, useMessages, useMetrics, useNavigation, useOverrides, usePageOverride, usePrefetchClipCounts, useRealtimeLineMetrics, useRegistry, useSKUs, useSessionKeepAlive, useShiftConfig, useShifts, useSubscriptionManager, useSubscriptionManagerSafe, useSupabase, useSupabaseClient, useTargets, useTeamManagementPermissions, useTheme, useThemeConfig, useThreads, useTicketHistory, useTimezoneContext, useUserLineAccess, useVideoConfig, useWorkspaceConfig, useWorkspaceDetailedMetrics, useWorkspaceDisplayName, useWorkspaceDisplayNames, useWorkspaceDisplayNamesMap, useWorkspaceHealthById, useWorkspaceHealthStatus, useWorkspaceMetrics, useWorkspaceNavigation, useWorkspaceOperators, useWorkspaceUptimeTimeline, userService, videoPrefetchManager, videoPreloader, whatsappService, withAccessControl, withAuth, withRegistry, withTimezone, workspaceHealthService, workspaceService };