@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.css +16 -4
- package/dist/index.d.mts +432 -239
- package/dist/index.d.ts +432 -239
- package/dist/index.js +1457 -988
- package/dist/index.mjs +1453 -990
- package/package.json +1 -1
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,
|
|
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
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
const
|
|
511
|
-
const
|
|
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
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
const
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
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
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
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
|
-
|
|
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
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
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
|
-
|
|
559
|
-
|
|
560
|
-
|
|
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:
|
|
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
|
|
2139
|
-
const
|
|
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
|
|
2144
|
-
const
|
|
2145
|
-
const
|
|
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
|
|
2328
|
-
|
|
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
|
|
2574
|
-
|
|
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(
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
7454
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
7822
|
-
const
|
|
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
|
|
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 =
|
|
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
|
|
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
|
|
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(
|
|
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
|
-
}, [
|
|
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(
|
|
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,
|
|
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
|
|
8368
|
-
const shiftConfig =
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
9870
|
-
const
|
|
9871
|
-
const
|
|
9872
|
-
if (
|
|
9873
|
-
return currentMinutes >=
|
|
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 >=
|
|
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:
|
|
9892
|
-
|
|
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
|
|
9899
|
-
|
|
9900
|
-
|
|
9901
|
-
|
|
9902
|
-
|
|
9903
|
-
|
|
9904
|
-
|
|
9905
|
-
|
|
9906
|
-
|
|
9907
|
-
const shiftName =
|
|
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
|
|
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
|
|
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
|
|
10239
|
+
const configuredLineIds2 = options?.allowedLineIds ? allConfiguredLineIds.filter((id3) => options.allowedLineIds.includes(id3)) : allConfiguredLineIds;
|
|
10020
10240
|
let enabledWorkspaceIds = [];
|
|
10021
|
-
for (const lineId of
|
|
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.
|
|
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-
|
|
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
|
-
|
|
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
|
-
|
|
27518
|
-
|
|
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(
|
|
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
|
|
29827
|
-
return shiftStr;
|
|
30164
|
+
console.log(`[BottlenecksContent] Using explicit date/shift: ${date}, shift ${shiftStr}`);
|
|
30165
|
+
return { effectiveShift: shiftStr, effectiveDate: date };
|
|
29828
30166
|
}
|
|
29829
|
-
if (
|
|
29830
|
-
console.log(
|
|
29831
|
-
return
|
|
29832
|
-
}
|
|
29833
|
-
|
|
29834
|
-
|
|
29835
|
-
|
|
29836
|
-
|
|
29837
|
-
|
|
29838
|
-
);
|
|
29839
|
-
|
|
29840
|
-
|
|
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
|
-
|
|
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:
|
|
29929
|
-
shiftId:
|
|
29930
|
-
enabled:
|
|
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
|
-
|
|
29972
|
-
|
|
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:
|
|
29984
|
-
shift:
|
|
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}:${
|
|
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 =
|
|
30034
|
-
const shiftStr =
|
|
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,
|
|
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 =
|
|
30086
|
-
const shiftStr =
|
|
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,
|
|
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,
|
|
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:
|
|
30209
|
-
shift:
|
|
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,
|
|
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
|
-
|
|
30343
|
-
|
|
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:
|
|
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:
|
|
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,
|
|
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 =
|
|
30539
|
-
const shiftStr =
|
|
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,
|
|
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:
|
|
31220
|
-
shift:
|
|
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
|
|
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:
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
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,
|
|
33487
|
+
onDateSelect(date, selectedShiftId);
|
|
33118
33488
|
} else {
|
|
33119
|
-
router.navigate(`/kpis/${lineId}?date=${date}&shift=${
|
|
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 = {
|
|
33530
|
+
underperformingWorkspaces = {},
|
|
33148
33531
|
lineId,
|
|
33149
|
-
|
|
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 =
|
|
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
|
-
|
|
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__ */
|
|
33238
|
-
|
|
33239
|
-
|
|
33240
|
-
|
|
33241
|
-
|
|
33242
|
-
|
|
33243
|
-
|
|
33244
|
-
}
|
|
33245
|
-
|
|
33246
|
-
|
|
33247
|
-
|
|
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
|
-
|
|
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
|
-
(
|
|
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 ||
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
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) =>
|
|
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 =
|
|
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 =
|
|
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
|
|
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
|
-
|
|
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 =
|
|
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,
|
|
34469
|
-
const handleDayClick = useCallback((day,
|
|
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 =
|
|
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((
|
|
34889
|
+
const handleShiftChange = useCallback((shiftId) => {
|
|
34487
34890
|
trackCoreEvent("Workspace Calendar Shift Changed", {
|
|
34488
34891
|
workspace_id: workspaceId,
|
|
34489
|
-
|
|
34892
|
+
new_shift_id: shiftId
|
|
34490
34893
|
});
|
|
34491
34894
|
if (onShiftChange) {
|
|
34492
|
-
onShiftChange(
|
|
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 =
|
|
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,
|
|
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
|
-
}, [
|
|
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__ */
|
|
34597
|
-
|
|
34598
|
-
|
|
34599
|
-
|
|
34600
|
-
|
|
34601
|
-
|
|
34602
|
-
|
|
34603
|
-
}
|
|
34604
|
-
|
|
34605
|
-
|
|
34606
|
-
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
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 ?
|
|
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 ?
|
|
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,
|
|
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) =>
|
|
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,
|
|
35192
|
+
}, [data, selectedShiftId]);
|
|
34795
35193
|
const metrics2 = useMemo(() => {
|
|
34796
|
-
const validShifts = data.map((d) =>
|
|
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,
|
|
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
|
-
|
|
35241
|
+
shift_id: selectedShiftId
|
|
34844
35242
|
});
|
|
34845
|
-
onDateSelect(formattedDate,
|
|
34846
|
-
}, [workspaceId,
|
|
34847
|
-
const handleShiftChange = useCallback((
|
|
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
|
-
|
|
35248
|
+
new_shift_id: shiftId
|
|
34851
35249
|
});
|
|
34852
35250
|
if (onShiftChange) {
|
|
34853
|
-
onShiftChange(
|
|
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__ */
|
|
34867
|
-
|
|
34868
|
-
|
|
34869
|
-
|
|
34870
|
-
|
|
34871
|
-
|
|
34872
|
-
|
|
34873
|
-
}
|
|
34874
|
-
|
|
34875
|
-
|
|
34876
|
-
|
|
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 ?
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
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) =>
|
|
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 =
|
|
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
|
-
|
|
37385
|
+
const rawName = currentShift.shiftName || "Day";
|
|
37386
|
+
return rawName.toLowerCase().includes("shift") ? rawName : `${rawName} Shift`;
|
|
36985
37387
|
};
|
|
36986
|
-
const
|
|
36987
|
-
const
|
|
36988
|
-
|
|
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
|
-
}
|
|
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__ */
|
|
37003
|
-
/* @__PURE__ */ jsx("div", { className: "text-gray-500 sm:text-gray-600 scale-90 sm:scale-100", children:
|
|
37004
|
-
/* @__PURE__ */
|
|
37005
|
-
|
|
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
|
|
42027
|
-
|
|
42028
|
-
return currentHour >= 6 && currentHour < 18 ? "Day" : "Night";
|
|
42434
|
+
const currentShift = getCurrentShiftInfo();
|
|
42435
|
+
return (currentShift.shiftName || "Day").replace(/ Shift$/i, "");
|
|
42029
42436
|
};
|
|
42030
|
-
const
|
|
42031
|
-
const
|
|
42032
|
-
|
|
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
|
-
}
|
|
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:
|
|
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({
|
|
43566
|
-
const [
|
|
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
|
|
43598
|
-
}, []);
|
|
43599
|
-
const
|
|
43600
|
-
|
|
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
|
-
}
|
|
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
|
-
|
|
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 =
|
|
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,
|
|
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
|
-
|
|
43668
|
-
|
|
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
|
-
|
|
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
|
|
43699
|
-
|
|
43700
|
-
|
|
43701
|
-
|
|
43702
|
-
|
|
43703
|
-
|
|
43704
|
-
|
|
43705
|
-
|
|
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:
|
|
44077
|
-
/* @__PURE__ */
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
44254
|
-
onShiftChange:
|
|
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
|
|
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.
|
|
44468
|
-
const
|
|
44469
|
-
|
|
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
|
-
}
|
|
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:
|
|
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:
|
|
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(() =>
|
|
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
|
|
44812
|
-
|
|
44813
|
-
|
|
44814
|
-
|
|
44815
|
-
|
|
44816
|
-
|
|
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
|
-
}
|
|
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
|
|
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
|
-
|
|
45314
|
+
const combinedParams = navParams ? `${navParams}&${contextParamString}` : `?${contextParamString}`;
|
|
45315
|
+
const enhancedWorkspace = {
|
|
45316
|
+
...workspace,
|
|
45317
|
+
navParams: combinedParams
|
|
45318
|
+
};
|
|
45319
|
+
onWorkspaceClick(enhancedWorkspace, rank);
|
|
44873
45320
|
} else {
|
|
44874
|
-
|
|
45321
|
+
const combinedParams = navParams ? `${navParams}&${contextParamString}` : `?${contextParamString}`;
|
|
45322
|
+
navigation.navigate(`/workspace/${workspace.workspace_uuid}${combinedParams}`);
|
|
44875
45323
|
}
|
|
44876
|
-
}, [onWorkspaceClick, navigation,
|
|
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
|
|
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("
|
|
45603
|
-
"
|
|
45604
|
-
|
|
45605
|
-
|
|
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
|
-
|
|
45705
|
-
|
|
45706
|
-
|
|
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:
|
|
45738
|
-
if (
|
|
45739
|
-
console.error("Error fetching
|
|
45740
|
-
showToast("error", "Error loading
|
|
45741
|
-
setError("Failed to load
|
|
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
|
-
|
|
45752
|
-
|
|
45753
|
-
|
|
45754
|
-
|
|
45755
|
-
|
|
45756
|
-
|
|
45757
|
-
|
|
45758
|
-
|
|
45759
|
-
|
|
45760
|
-
|
|
45761
|
-
startTime:
|
|
45762
|
-
endTime:
|
|
45763
|
-
breaks: parseBreaksFromDB(
|
|
45764
|
-
|
|
45765
|
-
|
|
45766
|
-
|
|
45767
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
46291
|
+
return prev.map(
|
|
45804
46292
|
(config) => config.id === lineId ? { ...config, isOpen: newIsOpen } : config
|
|
45805
46293
|
);
|
|
45806
46294
|
});
|
|
45807
46295
|
}, []);
|
|
45808
|
-
const
|
|
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
|
-
|
|
45824
|
-
|
|
45825
|
-
|
|
45826
|
-
|
|
45827
|
-
|
|
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
|
|
46304
|
+
return config;
|
|
45845
46305
|
}));
|
|
45846
46306
|
}, []);
|
|
45847
|
-
const
|
|
46307
|
+
const updateShiftName = useCallback((lineId, shiftId, value) => {
|
|
45848
46308
|
setLineConfigs((prev) => prev.map((config) => {
|
|
45849
|
-
|
|
45850
|
-
|
|
45851
|
-
|
|
45852
|
-
|
|
45853
|
-
|
|
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
|
|
46315
|
+
return config;
|
|
45858
46316
|
}));
|
|
45859
46317
|
}, []);
|
|
45860
|
-
|
|
45861
|
-
setLineConfigs((prev) => prev.map(
|
|
45862
|
-
|
|
45863
|
-
|
|
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
|
|
46323
|
+
const addBreak = useCallback((lineId, shiftId) => {
|
|
45883
46324
|
setLineConfigs((prev) => prev.map((config) => {
|
|
45884
|
-
|
|
45885
|
-
|
|
45886
|
-
|
|
45887
|
-
|
|
45888
|
-
|
|
45889
|
-
|
|
45890
|
-
|
|
45891
|
-
|
|
45892
|
-
|
|
45893
|
-
|
|
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
|
|
46340
|
+
return config;
|
|
45901
46341
|
}));
|
|
45902
46342
|
}, []);
|
|
45903
|
-
const
|
|
46343
|
+
const updateBreak = useCallback((lineId, shiftId, breakIndex, field, value) => {
|
|
45904
46344
|
setLineConfigs((prev) => prev.map((config) => {
|
|
45905
|
-
|
|
45906
|
-
|
|
45907
|
-
|
|
45908
|
-
|
|
45909
|
-
|
|
45910
|
-
|
|
45911
|
-
|
|
45912
|
-
|
|
45913
|
-
|
|
45914
|
-
|
|
45915
|
-
|
|
45916
|
-
|
|
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
|
|
46362
|
+
return config;
|
|
45929
46363
|
}));
|
|
45930
46364
|
}, []);
|
|
45931
|
-
const
|
|
46365
|
+
const removeBreak = useCallback((lineId, shiftId, breakIndex) => {
|
|
45932
46366
|
setLineConfigs((prev) => prev.map((config) => {
|
|
45933
|
-
|
|
45934
|
-
|
|
45935
|
-
|
|
45936
|
-
|
|
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
|
|
46376
|
+
return config;
|
|
45957
46377
|
}));
|
|
45958
46378
|
}, []);
|
|
45959
|
-
|
|
46379
|
+
useCallback((lineId) => {
|
|
45960
46380
|
setLineConfigs((prev) => prev.map((config) => {
|
|
45961
46381
|
if (config.id === lineId) {
|
|
45962
|
-
const
|
|
45963
|
-
|
|
45964
|
-
|
|
45965
|
-
|
|
45966
|
-
|
|
45967
|
-
|
|
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
|
|
46396
|
+
const removeShift = useCallback((lineId, shiftId) => {
|
|
45975
46397
|
setLineConfigs((prev) => prev.map((config) => {
|
|
45976
46398
|
if (config.id === lineId) {
|
|
45977
|
-
|
|
45978
|
-
|
|
45979
|
-
|
|
45980
|
-
|
|
45981
|
-
|
|
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
|
-
|
|
45999
|
-
|
|
46000
|
-
|
|
46001
|
-
|
|
46002
|
-
|
|
46003
|
-
|
|
46004
|
-
|
|
46005
|
-
|
|
46006
|
-
|
|
46007
|
-
|
|
46008
|
-
|
|
46009
|
-
|
|
46010
|
-
|
|
46011
|
-
|
|
46012
|
-
|
|
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
|
|
46017
|
-
|
|
46018
|
-
|
|
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
|
|
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__ */
|
|
46098
|
-
|
|
46099
|
-
|
|
46100
|
-
|
|
46101
|
-
|
|
46102
|
-
|
|
46103
|
-
|
|
46104
|
-
|
|
46105
|
-
|
|
46106
|
-
|
|
46107
|
-
|
|
46108
|
-
|
|
46109
|
-
|
|
46110
|
-
|
|
46111
|
-
|
|
46112
|
-
|
|
46113
|
-
|
|
46114
|
-
|
|
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__ */
|
|
47018
|
-
|
|
47019
|
-
|
|
47020
|
-
|
|
47021
|
-
|
|
47022
|
-
|
|
47023
|
-
|
|
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:
|
|
47415
|
-
// Fetch
|
|
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 = {
|
|
47434
|
-
const newDbValues = {
|
|
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
|
-
|
|
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(
|
|
48379
|
+
const [selectedShift, setSelectedShift] = useState(0);
|
|
47961
48380
|
useEffect(() => {
|
|
47962
|
-
if (parsedShiftId
|
|
47963
|
-
setSelectedShift(
|
|
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
|
-
|
|
48116
|
-
//
|
|
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
|
-
|
|
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) =>
|
|
48561
|
+
const processedData = Array.from(dayDataMap.values()).filter((entry) => Object.keys(entry.shifts).length > 0).map((entry) => ({
|
|
48139
48562
|
date: entry.date,
|
|
48140
|
-
|
|
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
|
|
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
|
|
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
|
|
48197
|
-
|
|
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:
|
|
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:
|
|
48377
|
-
/* @__PURE__ */
|
|
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
|
-
|
|
49140
|
+
availableShifts: shiftConfig?.shifts?.map((s) => ({ id: s.shiftId, name: s.shiftName })),
|
|
49141
|
+
onDateSelect: (selectedDate, shiftId) => {
|
|
48719
49142
|
if (onDateSelect) {
|
|
48720
|
-
onDateSelect(selectedDate,
|
|
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",
|
|
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
|
|
49418
|
-
const
|
|
49419
|
-
const
|
|
49420
|
-
const shiftType =
|
|
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:
|
|
49889
|
+
timeZone: effectiveTimezone
|
|
49428
49890
|
});
|
|
49429
49891
|
};
|
|
49430
|
-
const
|
|
49431
|
-
|
|
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:
|
|
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
|
|
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
|
-
|
|
51805
|
-
|
|
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 };
|