@optifye/dashboard-core 6.9.13 → 6.9.15
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 +13 -4
- package/dist/index.d.mts +430 -238
- package/dist/index.d.ts +430 -238
- package/dist/index.js +1294 -729
- package/dist/index.mjs +1289 -730
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -125,6 +125,32 @@ function isValidPrefetchStatus(status) {
|
|
|
125
125
|
return typeof status === "string" && Object.values(PrefetchStatus).includes(status);
|
|
126
126
|
}
|
|
127
127
|
|
|
128
|
+
// src/lib/types/calendar.ts
|
|
129
|
+
var DEFAULT_SHIFT_DATA = {
|
|
130
|
+
efficiency: 0,
|
|
131
|
+
output: 0,
|
|
132
|
+
cycleTime: 0,
|
|
133
|
+
pph: 0,
|
|
134
|
+
pphThreshold: 0,
|
|
135
|
+
idealOutput: 0,
|
|
136
|
+
rank: 0,
|
|
137
|
+
idleTime: 0,
|
|
138
|
+
hasData: false
|
|
139
|
+
};
|
|
140
|
+
var getShiftData = (day, shiftId) => {
|
|
141
|
+
const shift = day.shifts[shiftId];
|
|
142
|
+
if (shift) {
|
|
143
|
+
return { ...shift, hasData: true };
|
|
144
|
+
}
|
|
145
|
+
return { ...DEFAULT_SHIFT_DATA };
|
|
146
|
+
};
|
|
147
|
+
var hasAnyShiftData = (day) => {
|
|
148
|
+
return Object.keys(day.shifts).length > 0;
|
|
149
|
+
};
|
|
150
|
+
var getAvailableShiftIds = (day) => {
|
|
151
|
+
return Object.keys(day.shifts).map(Number).sort((a, b) => a - b);
|
|
152
|
+
};
|
|
153
|
+
|
|
128
154
|
// src/components/dashboard/grid/workspace_grid_constants.ts
|
|
129
155
|
var DEFAULT_WORKSPACE_POSITIONS = [
|
|
130
156
|
// Middle top row - 7 tapping workspaces (conveyor style)
|
|
@@ -171,15 +197,21 @@ var DEFAULT_ENTITY_CONFIG = {
|
|
|
171
197
|
}
|
|
172
198
|
};
|
|
173
199
|
var DEFAULT_SHIFT_CONFIG = {
|
|
200
|
+
shifts: [
|
|
201
|
+
{ shiftId: 0, shiftName: "Day Shift", startTime: "06:00", endTime: "18:00", breaks: [], timezone: "UTC" },
|
|
202
|
+
{ shiftId: 1, shiftName: "Night Shift", startTime: "18:00", endTime: "06:00", breaks: [], timezone: "UTC" }
|
|
203
|
+
],
|
|
174
204
|
dayShift: {
|
|
175
205
|
id: 0,
|
|
176
206
|
startTime: "06:00",
|
|
177
|
-
endTime: "18:00"
|
|
207
|
+
endTime: "18:00",
|
|
208
|
+
name: "Day Shift"
|
|
178
209
|
},
|
|
179
210
|
nightShift: {
|
|
180
211
|
id: 1,
|
|
181
212
|
startTime: "18:00",
|
|
182
|
-
endTime: "06:00"
|
|
213
|
+
endTime: "06:00",
|
|
214
|
+
name: "Night Shift"
|
|
183
215
|
},
|
|
184
216
|
transitionPeriodMinutes: 15
|
|
185
217
|
};
|
|
@@ -529,70 +561,128 @@ var parseTimeToMinutes = (timeString) => {
|
|
|
529
561
|
const [hours, minutes] = timeString.split(":").map(Number);
|
|
530
562
|
return hours * 60 + minutes;
|
|
531
563
|
};
|
|
532
|
-
var
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
const
|
|
540
|
-
const
|
|
564
|
+
var normalizeShiftDefinitions = (timezone, shiftConfig) => {
|
|
565
|
+
if (shiftConfig?.shifts && shiftConfig.shifts.length > 0) {
|
|
566
|
+
return {
|
|
567
|
+
shifts: shiftConfig.shifts,
|
|
568
|
+
timezone: shiftConfig.shifts[0].timezone || shiftConfig.timezone || timezone
|
|
569
|
+
};
|
|
570
|
+
}
|
|
571
|
+
const fallbackTimezone = shiftConfig?.timezone || timezone;
|
|
572
|
+
const legacyShifts = [];
|
|
573
|
+
if (shiftConfig?.dayShift) {
|
|
574
|
+
legacyShifts.push({
|
|
575
|
+
shiftId: shiftConfig.dayShift.id ?? 0,
|
|
576
|
+
shiftName: shiftConfig.dayShift.name || "Day Shift",
|
|
577
|
+
startTime: shiftConfig.dayShift.startTime || DEFAULT_DAY_SHIFT_START,
|
|
578
|
+
endTime: shiftConfig.dayShift.endTime || "18:00",
|
|
579
|
+
breaks: [],
|
|
580
|
+
timezone: fallbackTimezone
|
|
581
|
+
});
|
|
582
|
+
}
|
|
583
|
+
if (shiftConfig?.nightShift) {
|
|
584
|
+
legacyShifts.push({
|
|
585
|
+
shiftId: shiftConfig.nightShift.id ?? 1,
|
|
586
|
+
shiftName: shiftConfig.nightShift.name || "Night Shift",
|
|
587
|
+
startTime: shiftConfig.nightShift.startTime || DEFAULT_NIGHT_SHIFT_START,
|
|
588
|
+
endTime: shiftConfig.nightShift.endTime || "06:00",
|
|
589
|
+
breaks: [],
|
|
590
|
+
timezone: fallbackTimezone
|
|
591
|
+
});
|
|
592
|
+
}
|
|
593
|
+
if (legacyShifts.length === 0) {
|
|
594
|
+
legacyShifts.push(
|
|
595
|
+
{
|
|
596
|
+
shiftId: 0,
|
|
597
|
+
shiftName: "Day Shift",
|
|
598
|
+
startTime: DEFAULT_DAY_SHIFT_START,
|
|
599
|
+
endTime: "18:00",
|
|
600
|
+
breaks: [],
|
|
601
|
+
timezone: fallbackTimezone
|
|
602
|
+
},
|
|
603
|
+
{
|
|
604
|
+
shiftId: 1,
|
|
605
|
+
shiftName: "Night Shift",
|
|
606
|
+
startTime: DEFAULT_NIGHT_SHIFT_START,
|
|
607
|
+
endTime: "06:00",
|
|
608
|
+
breaks: [],
|
|
609
|
+
timezone: fallbackTimezone
|
|
610
|
+
}
|
|
611
|
+
);
|
|
612
|
+
}
|
|
613
|
+
return { shifts: legacyShifts, timezone: fallbackTimezone };
|
|
614
|
+
};
|
|
615
|
+
var determineShiftFromDefinitions = (timezone, shifts, now2 = /* @__PURE__ */ new Date()) => {
|
|
541
616
|
const zonedNow = dateFnsTz.toZonedTime(now2, timezone);
|
|
542
|
-
const
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
const
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
617
|
+
const currentMinutes = zonedNow.getHours() * 60 + zonedNow.getMinutes();
|
|
618
|
+
let chosen;
|
|
619
|
+
let operationalDate = getOperationalDate(timezone, zonedNow, shifts[0].startTime);
|
|
620
|
+
for (const shift of shifts) {
|
|
621
|
+
const start = parseTimeToMinutes(shift.startTime);
|
|
622
|
+
const endRaw = parseTimeToMinutes(shift.endTime);
|
|
623
|
+
let end = endRaw;
|
|
624
|
+
const wraps = end <= start;
|
|
625
|
+
if (wraps) end += 1440;
|
|
626
|
+
if (start <= currentMinutes && currentMinutes < end) {
|
|
627
|
+
chosen = shift;
|
|
628
|
+
operationalDate = getOperationalDate(timezone, zonedNow, shift.startTime);
|
|
629
|
+
break;
|
|
552
630
|
}
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
determinedShiftId = nightShiftId;
|
|
631
|
+
if (start <= currentMinutes + 1440 && currentMinutes + 1440 < end) {
|
|
632
|
+
chosen = shift;
|
|
633
|
+
operationalDate = getOperationalDate(timezone, zonedNow, shift.startTime);
|
|
634
|
+
break;
|
|
558
635
|
}
|
|
559
636
|
}
|
|
560
|
-
|
|
637
|
+
if (!chosen) {
|
|
638
|
+
chosen = shifts[0];
|
|
639
|
+
operationalDate = getOperationalDate(timezone, zonedNow, chosen.startTime);
|
|
640
|
+
}
|
|
641
|
+
return {
|
|
642
|
+
shiftId: chosen.shiftId,
|
|
643
|
+
shiftName: chosen.shiftName,
|
|
644
|
+
startTime: chosen.startTime,
|
|
645
|
+
endTime: chosen.endTime,
|
|
646
|
+
timezone,
|
|
647
|
+
date: operationalDate
|
|
648
|
+
};
|
|
649
|
+
};
|
|
650
|
+
var getCurrentShift = (timezone, shiftConfig, now2 = /* @__PURE__ */ new Date()) => {
|
|
651
|
+
const { shifts, timezone: effectiveTz } = normalizeShiftDefinitions(timezone, shiftConfig);
|
|
652
|
+
return determineShiftFromDefinitions(effectiveTz, shifts, now2);
|
|
561
653
|
};
|
|
562
654
|
var isTransitionPeriod = (timezone, shiftConfig, now2 = /* @__PURE__ */ new Date()) => {
|
|
563
|
-
const dayShiftStartStr = shiftConfig?.dayShift?.startTime || DEFAULT_DAY_SHIFT_START;
|
|
564
|
-
const nightShiftStartStr = shiftConfig?.nightShift?.startTime || DEFAULT_NIGHT_SHIFT_START;
|
|
565
655
|
const transitionMinutes = shiftConfig?.transitionPeriodMinutes ?? DEFAULT_TRANSITION_MINUTES;
|
|
566
|
-
const
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
const currentHour = zonedNow.getHours();
|
|
574
|
-
const currentMinutes = zonedNow.getMinutes();
|
|
575
|
-
const currentTotalMinutes = currentHour * 60 + currentMinutes;
|
|
576
|
-
return transitionTimes.some((transitionTime) => {
|
|
656
|
+
const { shifts, timezone: effectiveTz } = normalizeShiftDefinitions(timezone, shiftConfig);
|
|
657
|
+
if (!shifts.length) return false;
|
|
658
|
+
const zonedNow = dateFnsTz.toZonedTime(now2, effectiveTz);
|
|
659
|
+
const currentTotalMinutes = zonedNow.getHours() * 60 + zonedNow.getMinutes();
|
|
660
|
+
return shifts.some((shift) => {
|
|
661
|
+
const transitionTime = parseTimeToMinutes(shift.startTime);
|
|
662
|
+
if (isNaN(transitionTime)) return false;
|
|
577
663
|
const lowerBoundBefore = (transitionTime - transitionMinutes + 1440) % 1440;
|
|
578
664
|
const upperBoundBefore = transitionTime;
|
|
579
|
-
let isBefore = false;
|
|
580
|
-
if (lowerBoundBefore < upperBoundBefore) {
|
|
581
|
-
isBefore = currentTotalMinutes >= lowerBoundBefore && currentTotalMinutes < upperBoundBefore;
|
|
582
|
-
} else {
|
|
583
|
-
isBefore = currentTotalMinutes >= lowerBoundBefore || currentTotalMinutes < upperBoundBefore;
|
|
584
|
-
}
|
|
585
665
|
const lowerBoundAfter = transitionTime;
|
|
586
666
|
const upperBoundAfter = (transitionTime + transitionMinutes) % 1440;
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
} else {
|
|
591
|
-
isAfter = currentTotalMinutes >= lowerBoundAfter || currentTotalMinutes < upperBoundAfter;
|
|
592
|
-
}
|
|
593
|
-
return isBefore || isAfter;
|
|
667
|
+
const inBefore = lowerBoundBefore < upperBoundBefore ? currentTotalMinutes >= lowerBoundBefore && currentTotalMinutes < upperBoundBefore : currentTotalMinutes >= lowerBoundBefore || currentTotalMinutes < upperBoundBefore;
|
|
668
|
+
const inAfter = lowerBoundAfter < upperBoundAfter ? currentTotalMinutes >= lowerBoundAfter && currentTotalMinutes < upperBoundAfter : currentTotalMinutes >= lowerBoundAfter || currentTotalMinutes < upperBoundAfter;
|
|
669
|
+
return inBefore || inAfter;
|
|
594
670
|
});
|
|
595
671
|
};
|
|
672
|
+
var getShiftNameById = (shiftId, timezone, shiftConfig) => {
|
|
673
|
+
const { shifts } = normalizeShiftDefinitions(timezone, shiftConfig);
|
|
674
|
+
const shift = shifts.find((s) => s.shiftId === shiftId);
|
|
675
|
+
if (shift) {
|
|
676
|
+
return shift.shiftName;
|
|
677
|
+
}
|
|
678
|
+
if (shiftId === 0) return "Day Shift";
|
|
679
|
+
if (shiftId === 1) return "Night Shift";
|
|
680
|
+
return `Shift ${shiftId}`;
|
|
681
|
+
};
|
|
682
|
+
var getShortShiftName = (shiftId, timezone, shiftConfig) => {
|
|
683
|
+
const fullName = getShiftNameById(shiftId, timezone, shiftConfig);
|
|
684
|
+
return fullName.replace(/ Shift$/i, "");
|
|
685
|
+
};
|
|
596
686
|
|
|
597
687
|
// src/lib/utils/database.ts
|
|
598
688
|
var getCompanyMetricsTableName = (companyId, prefix = "workspace_performance") => {
|
|
@@ -1185,12 +1275,12 @@ var dashboardService = {
|
|
|
1185
1275
|
throw err;
|
|
1186
1276
|
}
|
|
1187
1277
|
},
|
|
1188
|
-
async getDetailedLineInfo(lineIdInput, dateProp, shiftProp) {
|
|
1278
|
+
async getDetailedLineInfo(lineIdInput, dateProp, shiftProp, providedShiftConfig) {
|
|
1189
1279
|
const supabase = _getSupabaseInstance();
|
|
1190
1280
|
const config = _getDashboardConfigInstance();
|
|
1191
1281
|
const dbConfig = config.databaseConfig ?? DEFAULT_DATABASE_CONFIG;
|
|
1192
1282
|
const entityConfig = config.entityConfig ?? DEFAULT_ENTITY_CONFIG;
|
|
1193
|
-
const shiftConfig = config.shiftConfig ?? DEFAULT_SHIFT_CONFIG;
|
|
1283
|
+
const shiftConfig = providedShiftConfig || (config.shiftConfig ?? DEFAULT_SHIFT_CONFIG);
|
|
1194
1284
|
const dateTimeConfig = config.dateTimeConfig ?? DEFAULT_DATE_TIME_CONFIG;
|
|
1195
1285
|
const workspaceConfig = config.workspaceConfig ?? DEFAULT_WORKSPACE_CONFIG;
|
|
1196
1286
|
const linesTable = getTable(dbConfig, "lines");
|
|
@@ -1277,8 +1367,8 @@ var dashboardService = {
|
|
|
1277
1367
|
underperforming_workspaces: combinedMetricsData.underperforming_workspaces,
|
|
1278
1368
|
line_threshold: combinedMetricsData.line_threshold,
|
|
1279
1369
|
threshold_pph: combinedMetricsData.threshold_pph / numLines,
|
|
1280
|
-
shift_start: metricsData?.[0]?.shift_start || shiftConfig.dayShift?.startTime || "06:00",
|
|
1281
|
-
shift_end: metricsData?.[0]?.shift_end || shiftConfig.dayShift?.endTime || "18:00",
|
|
1370
|
+
shift_start: metricsData?.[0]?.shift_start || (shiftConfig.shifts && shiftConfig.shifts.length > 0 ? shiftConfig.shifts.find((s) => s.shiftId === 0)?.startTime || shiftConfig.shifts[0].startTime : shiftConfig.dayShift?.startTime) || "06:00",
|
|
1371
|
+
shift_end: metricsData?.[0]?.shift_end || (shiftConfig.shifts && shiftConfig.shifts.length > 0 ? shiftConfig.shifts.find((s) => s.shiftId === 0)?.endTime || shiftConfig.shifts[0].endTime : shiftConfig.dayShift?.endTime) || "18:00",
|
|
1282
1372
|
last_updated: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1283
1373
|
output_array: combinedMetricsData.outputArrays.length > 0 ? memoizedOutputArrayAggregation(combinedMetricsData.outputArrays) : [],
|
|
1284
1374
|
underperforming_workspace_names: combinedMetricsData.underperforming_workspace_names,
|
|
@@ -1319,8 +1409,8 @@ var dashboardService = {
|
|
|
1319
1409
|
underperforming_workspaces: metrics2?.underperforming_workspaces ?? 0,
|
|
1320
1410
|
line_threshold: metrics2?.line_threshold || 0,
|
|
1321
1411
|
threshold_pph: metrics2?.threshold_pph || 0,
|
|
1322
|
-
shift_start: metrics2?.shift_start || shiftConfig.dayShift?.startTime || "06:00",
|
|
1323
|
-
shift_end: metrics2?.shift_end || shiftConfig.dayShift?.endTime || "18:00",
|
|
1412
|
+
shift_start: metrics2?.shift_start || (shiftConfig.shifts && shiftConfig.shifts.length > 0 ? shiftConfig.shifts.find((s) => s.shiftId === 0)?.startTime || shiftConfig.shifts[0].startTime : shiftConfig.dayShift?.startTime) || "06:00",
|
|
1413
|
+
shift_end: metrics2?.shift_end || (shiftConfig.shifts && shiftConfig.shifts.length > 0 ? shiftConfig.shifts.find((s) => s.shiftId === 0)?.endTime || shiftConfig.shifts[0].endTime : shiftConfig.dayShift?.endTime) || "18:00",
|
|
1324
1414
|
last_updated: metrics2?.last_updated || (/* @__PURE__ */ new Date()).toISOString(),
|
|
1325
1415
|
output_array: metrics2?.output_array || [],
|
|
1326
1416
|
underperforming_workspace_names: metrics2?.underperforming_workspace_names || [],
|
|
@@ -1431,7 +1521,7 @@ var dashboardService = {
|
|
|
1431
1521
|
throw err;
|
|
1432
1522
|
}
|
|
1433
1523
|
},
|
|
1434
|
-
async getUnderperformingWorkspaces(lineIdInput, monthInput, yearInput) {
|
|
1524
|
+
async getUnderperformingWorkspaces(lineIdInput, monthInput, yearInput, shiftIds) {
|
|
1435
1525
|
_getSupabaseInstance();
|
|
1436
1526
|
const config = _getDashboardConfigInstance();
|
|
1437
1527
|
const entityConfig = config.entityConfig ?? DEFAULT_ENTITY_CONFIG;
|
|
@@ -1451,13 +1541,14 @@ var dashboardService = {
|
|
|
1451
1541
|
const currentDate = /* @__PURE__ */ new Date();
|
|
1452
1542
|
const currentMonth = monthInput !== void 0 ? monthInput : currentDate.getMonth();
|
|
1453
1543
|
const currentYear = yearInput !== void 0 ? yearInput : currentDate.getFullYear();
|
|
1544
|
+
const dynamicShiftIds = shiftIds || shiftConfig.shifts?.map((s) => s.shiftId) || [shiftConfig.dayShift?.id ?? 0, shiftConfig.nightShift?.id ?? 1];
|
|
1454
1545
|
const bodyPayload = {
|
|
1455
1546
|
lineId: lineIdInput === factoryViewId ? configuredLineIds : lineIdInput,
|
|
1456
1547
|
month: currentMonth,
|
|
1457
1548
|
year: currentYear,
|
|
1458
1549
|
companyId,
|
|
1459
1550
|
metricsTable,
|
|
1460
|
-
shifts:
|
|
1551
|
+
shifts: dynamicShiftIds
|
|
1461
1552
|
};
|
|
1462
1553
|
const response = await fetch(fullFunctionUrl, {
|
|
1463
1554
|
method: "POST",
|
|
@@ -2164,16 +2255,13 @@ var WorkspaceHealthService = class _WorkspaceHealthService {
|
|
|
2164
2255
|
this.cache.set(key, { data, timestamp: Date.now() });
|
|
2165
2256
|
}
|
|
2166
2257
|
getShiftTiming(timezone, shiftConfig) {
|
|
2167
|
-
const
|
|
2168
|
-
const
|
|
2169
|
-
const isDayShift = shiftId === dayShiftId;
|
|
2258
|
+
const currentShift = getCurrentShift(timezone, shiftConfig);
|
|
2259
|
+
const { shiftId, date, shiftName, startTime, endTime } = currentShift;
|
|
2170
2260
|
const defaultDayStart = "06:00";
|
|
2171
2261
|
const defaultDayEnd = "18:00";
|
|
2172
|
-
const
|
|
2173
|
-
const
|
|
2174
|
-
const
|
|
2175
|
-
const shiftEndStr = isDayShift ? shiftConfig?.dayShift?.endTime || defaultDayEnd : shiftConfig?.nightShift?.endTime || defaultNightEnd;
|
|
2176
|
-
const shiftLabel = isDayShift ? "Day Shift" : "Night Shift";
|
|
2262
|
+
const shiftStartStr = startTime || defaultDayStart;
|
|
2263
|
+
const shiftEndStr = endTime || defaultDayEnd;
|
|
2264
|
+
const shiftLabel = shiftName || (shiftId === 0 ? "Day Shift" : shiftId === 1 ? "Night Shift" : `Shift ${shiftId}`);
|
|
2177
2265
|
const parseTime = (value) => {
|
|
2178
2266
|
const [hourPart = "0", minutePart = "0"] = value.split(":");
|
|
2179
2267
|
const hour = Number.parseInt(hourPart, 10);
|
|
@@ -2248,6 +2336,13 @@ var WorkspaceHealthService = class _WorkspaceHealthService {
|
|
|
2248
2336
|
async getWorkspaceHealthStatus(options = {}) {
|
|
2249
2337
|
const supabase = _getSupabaseInstance();
|
|
2250
2338
|
if (!supabase) throw new Error("Supabase client not initialized");
|
|
2339
|
+
const dashboardConfig = _getDashboardConfigInstance();
|
|
2340
|
+
if (!options.shiftConfig) {
|
|
2341
|
+
console.warn("[workspaceHealthService.getWorkspaceHealthStatus] \u26A0\uFE0F No shiftConfig passed! Falling back to static config. This may cause incorrect shift_id queries.");
|
|
2342
|
+
}
|
|
2343
|
+
const shiftConfig = options.shiftConfig || dashboardConfig?.shiftConfig;
|
|
2344
|
+
const defaultTimezone = dashboardConfig?.dateTimeConfig?.defaultTimezone || "UTC";
|
|
2345
|
+
const timezone = options.timezone || shiftConfig?.timezone || defaultTimezone;
|
|
2251
2346
|
let query = supabase.from("workspace_health_status").select("*").order("workspace_display_name", { ascending: true });
|
|
2252
2347
|
if (options.lineId) {
|
|
2253
2348
|
query = query.eq("line_id", options.lineId);
|
|
@@ -2265,7 +2360,7 @@ var WorkspaceHealthService = class _WorkspaceHealthService {
|
|
|
2265
2360
|
let uptimeMap = /* @__PURE__ */ new Map();
|
|
2266
2361
|
if (companyId) {
|
|
2267
2362
|
try {
|
|
2268
|
-
uptimeMap = await this.calculateWorkspaceUptime(companyId);
|
|
2363
|
+
uptimeMap = await this.calculateWorkspaceUptime(companyId, shiftConfig, timezone);
|
|
2269
2364
|
} catch (error2) {
|
|
2270
2365
|
console.error("Error calculating uptime:", error2);
|
|
2271
2366
|
}
|
|
@@ -2343,7 +2438,7 @@ var WorkspaceHealthService = class _WorkspaceHealthService {
|
|
|
2343
2438
|
}
|
|
2344
2439
|
return filteredData;
|
|
2345
2440
|
}
|
|
2346
|
-
async getWorkspaceUptimeTimeline(workspaceId, companyId) {
|
|
2441
|
+
async getWorkspaceUptimeTimeline(workspaceId, companyId, passedShiftConfig, passedTimezone) {
|
|
2347
2442
|
if (!workspaceId) {
|
|
2348
2443
|
throw new Error("workspaceId is required to fetch uptime timeline");
|
|
2349
2444
|
}
|
|
@@ -2353,8 +2448,12 @@ var WorkspaceHealthService = class _WorkspaceHealthService {
|
|
|
2353
2448
|
const supabase = _getSupabaseInstance();
|
|
2354
2449
|
if (!supabase) throw new Error("Supabase client not initialized");
|
|
2355
2450
|
const dashboardConfig = _getDashboardConfigInstance();
|
|
2356
|
-
const
|
|
2357
|
-
|
|
2451
|
+
const defaultTimezone = dashboardConfig?.dateTimeConfig?.defaultTimezone || "UTC";
|
|
2452
|
+
if (!passedShiftConfig) {
|
|
2453
|
+
console.warn("[workspaceHealthService.getWorkspaceUptimeTimeline] \u26A0\uFE0F No shiftConfig passed! Falling back to static config. This may cause incorrect shift_id queries.");
|
|
2454
|
+
}
|
|
2455
|
+
const shiftConfig = passedShiftConfig || dashboardConfig?.shiftConfig;
|
|
2456
|
+
const timezone = passedTimezone || shiftConfig?.timezone || defaultTimezone;
|
|
2358
2457
|
const {
|
|
2359
2458
|
shiftId,
|
|
2360
2459
|
shiftLabel,
|
|
@@ -2595,18 +2694,22 @@ var WorkspaceHealthService = class _WorkspaceHealthService {
|
|
|
2595
2694
|
clearCache() {
|
|
2596
2695
|
this.cache.clear();
|
|
2597
2696
|
}
|
|
2598
|
-
async calculateWorkspaceUptime(companyId) {
|
|
2697
|
+
async calculateWorkspaceUptime(companyId, passedShiftConfig, timezone) {
|
|
2599
2698
|
const supabase = _getSupabaseInstance();
|
|
2600
2699
|
if (!supabase) throw new Error("Supabase client not initialized");
|
|
2601
2700
|
const dashboardConfig = _getDashboardConfigInstance();
|
|
2602
|
-
const
|
|
2603
|
-
|
|
2701
|
+
const defaultTimezone = dashboardConfig?.dateTimeConfig?.defaultTimezone || "UTC";
|
|
2702
|
+
if (!passedShiftConfig) {
|
|
2703
|
+
console.warn("[workspaceHealthService.calculateWorkspaceUptime] \u26A0\uFE0F No shiftConfig passed! Falling back to static config. This may cause incorrect shift_id queries.");
|
|
2704
|
+
}
|
|
2705
|
+
const shiftConfig = passedShiftConfig || dashboardConfig?.shiftConfig;
|
|
2706
|
+
const effectiveTimezone = timezone || shiftConfig?.timezone || defaultTimezone;
|
|
2604
2707
|
const {
|
|
2605
2708
|
shiftId,
|
|
2606
2709
|
date,
|
|
2607
2710
|
shiftStartDate,
|
|
2608
2711
|
completedMinutes
|
|
2609
|
-
} = this.getShiftTiming(
|
|
2712
|
+
} = this.getShiftTiming(effectiveTimezone, shiftConfig);
|
|
2610
2713
|
const tableName = `performance_metrics_${companyId.replace(/-/g, "_")}`;
|
|
2611
2714
|
try {
|
|
2612
2715
|
const { data: queryData, error } = await supabase.from(tableName).select("workspace_id, workspace_display_name, output_hourly, output_array").eq("date", date).eq("shift_id", shiftId);
|
|
@@ -2629,7 +2732,7 @@ var WorkspaceHealthService = class _WorkspaceHealthService {
|
|
|
2629
2732
|
minuteDate,
|
|
2630
2733
|
outputHourly,
|
|
2631
2734
|
outputArray,
|
|
2632
|
-
|
|
2735
|
+
effectiveTimezone
|
|
2633
2736
|
);
|
|
2634
2737
|
if (status === "down") {
|
|
2635
2738
|
currentDownRun += 1;
|
|
@@ -4300,7 +4403,7 @@ var useAudioService = () => {
|
|
|
4300
4403
|
// src/lib/utils/dateShiftUtils.ts
|
|
4301
4404
|
function isValidShiftId(shiftId) {
|
|
4302
4405
|
const id3 = typeof shiftId === "string" ? parseInt(shiftId, 10) : shiftId;
|
|
4303
|
-
return id3
|
|
4406
|
+
return Number.isFinite(id3) && id3 >= 0;
|
|
4304
4407
|
}
|
|
4305
4408
|
var getSupabaseClient = () => {
|
|
4306
4409
|
const url = process.env.NEXT_PUBLIC_SUPABASE_URL;
|
|
@@ -6832,11 +6935,12 @@ var useMetrics = (tableName, options) => {
|
|
|
6832
6935
|
};
|
|
6833
6936
|
return { data, isLoading, error, refetch };
|
|
6834
6937
|
};
|
|
6835
|
-
var useWorkspaceDetailedMetrics = (workspaceId, date, shiftId) => {
|
|
6938
|
+
var useWorkspaceDetailedMetrics = (workspaceId, date, shiftId, options) => {
|
|
6836
6939
|
const entityConfig = useEntityConfig();
|
|
6837
6940
|
const databaseConfig = useDatabaseConfig();
|
|
6838
6941
|
const dateTimeConfig = useDateTimeConfig();
|
|
6839
|
-
const
|
|
6942
|
+
const staticShiftConfig = useShiftConfig();
|
|
6943
|
+
const shiftConfig = options?.shiftConfig || staticShiftConfig;
|
|
6840
6944
|
const workspaceConfig = useWorkspaceConfig();
|
|
6841
6945
|
const supabase = useSupabase();
|
|
6842
6946
|
const [metrics2, setMetrics] = React23.useState(null);
|
|
@@ -6849,11 +6953,12 @@ var useWorkspaceDetailedMetrics = (workspaceId, date, shiftId) => {
|
|
|
6849
6953
|
const companyId = entityConfig.companyId || "";
|
|
6850
6954
|
const metricsTablePrefix = getMetricsTablePrefix();
|
|
6851
6955
|
const metricsTable = `${metricsTablePrefix}_${companyId.replace(/-/g, "_")}`;
|
|
6852
|
-
const
|
|
6956
|
+
const appTimezone = useAppTimezone();
|
|
6957
|
+
const defaultTimezone = appTimezone || dateTimeConfig.defaultTimezone || "UTC";
|
|
6853
6958
|
const workspaceMetricsBaseTable = databaseConfig.tables?.workspaces ?? "workspace_metrics";
|
|
6854
6959
|
const workspaceActionsTable = databaseConfig.tables?.actions ?? "workspace_actions";
|
|
6855
6960
|
const fetchMetrics = React23.useCallback(async () => {
|
|
6856
|
-
if (!workspaceId || isFetchingRef.current) return;
|
|
6961
|
+
if (!workspaceId || isFetchingRef.current || options?.enabled === false) return;
|
|
6857
6962
|
try {
|
|
6858
6963
|
isFetchingRef.current = true;
|
|
6859
6964
|
const currentShift = getCurrentShift(defaultTimezone, shiftConfig);
|
|
@@ -6890,6 +6995,16 @@ var useWorkspaceDetailedMetrics = (workspaceId, date, shiftId) => {
|
|
|
6890
6995
|
throw new Error(`Invalid JSON response from backend. Received: ${responseText.substring(0, 100)}...`);
|
|
6891
6996
|
}
|
|
6892
6997
|
const data = backendData.metrics;
|
|
6998
|
+
if (data && options?.shiftConfig) {
|
|
6999
|
+
const dynamicShiftName = getShiftNameById(
|
|
7000
|
+
data.shift_id,
|
|
7001
|
+
appTimezone || "Asia/Kolkata",
|
|
7002
|
+
// Fallback timezone
|
|
7003
|
+
options.shiftConfig
|
|
7004
|
+
);
|
|
7005
|
+
data.shift_type = dynamicShiftName;
|
|
7006
|
+
console.log(`[useWorkspaceDetailedMetrics] Overriding shift name for ID ${data.shift_id}: ${dynamicShiftName}`);
|
|
7007
|
+
}
|
|
6893
7008
|
if (!data && !date && shiftId === void 0) {
|
|
6894
7009
|
console.log("[useWorkspaceDetailedMetrics] No data found for current date/shift, attempting to find most recent data...");
|
|
6895
7010
|
const fallbackResponse = await fetch(
|
|
@@ -7335,7 +7450,7 @@ var useWorkspaceDetailedMetrics = (workspaceId, date, shiftId) => {
|
|
|
7335
7450
|
updateQueueRef.current = false;
|
|
7336
7451
|
setIsLoading(false);
|
|
7337
7452
|
}
|
|
7338
|
-
}, [supabase, workspaceId, date, shiftId, metricsTable, defaultTimezone, shiftConfig, workspaceConfig, companyId]);
|
|
7453
|
+
}, [supabase, workspaceId, date, shiftId, metricsTable, defaultTimezone, shiftConfig, workspaceConfig, companyId, options?.enabled]);
|
|
7339
7454
|
const queueUpdate = React23.useCallback(() => {
|
|
7340
7455
|
if (!workspaceId || updateQueueRef.current) return;
|
|
7341
7456
|
updateQueueRef.current = true;
|
|
@@ -7368,7 +7483,7 @@ var useWorkspaceDetailedMetrics = (workspaceId, date, shiftId) => {
|
|
|
7368
7483
|
return;
|
|
7369
7484
|
}
|
|
7370
7485
|
const channels = [];
|
|
7371
|
-
const operationalDate = date || getOperationalDate(defaultTimezone
|
|
7486
|
+
const operationalDate = date || getOperationalDate(defaultTimezone);
|
|
7372
7487
|
const currentShift = getCurrentShift(defaultTimezone, shiftConfig);
|
|
7373
7488
|
const queryShiftId = shiftId ?? currentShift.shiftId;
|
|
7374
7489
|
const metricsChannel = supabase.channel(`workspace-metrics-${workspaceId}`).on(
|
|
@@ -7467,11 +7582,170 @@ var useWorkspaceDetailedMetrics = (workspaceId, date, shiftId) => {
|
|
|
7467
7582
|
// Force refresh without cache
|
|
7468
7583
|
};
|
|
7469
7584
|
};
|
|
7585
|
+
var useLineShiftConfig = (lineId, fallbackConfig) => {
|
|
7586
|
+
const [shiftConfig, setShiftConfig] = React23.useState(fallbackConfig || null);
|
|
7587
|
+
const [isLoading, setIsLoading] = React23.useState(true);
|
|
7588
|
+
const [error, setError] = React23.useState(null);
|
|
7589
|
+
const supabase = useSupabase();
|
|
7590
|
+
React23.useEffect(() => {
|
|
7591
|
+
if (!lineId || lineId === "factory" || lineId === "all") {
|
|
7592
|
+
setShiftConfig(fallbackConfig || null);
|
|
7593
|
+
setIsLoading(false);
|
|
7594
|
+
return;
|
|
7595
|
+
}
|
|
7596
|
+
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
7597
|
+
if (!uuidRegex.test(lineId)) {
|
|
7598
|
+
console.warn(`[useShiftConfig] Invalid line ID format: ${lineId}, using fallback`);
|
|
7599
|
+
setShiftConfig(fallbackConfig || null);
|
|
7600
|
+
setIsLoading(false);
|
|
7601
|
+
return;
|
|
7602
|
+
}
|
|
7603
|
+
let mounted = true;
|
|
7604
|
+
const calculateBreakDuration2 = (startTime, endTime) => {
|
|
7605
|
+
const [sh, sm] = startTime.split(":").map(Number);
|
|
7606
|
+
const [eh, em] = endTime.split(":").map(Number);
|
|
7607
|
+
let startMinutes = sh * 60 + sm;
|
|
7608
|
+
let endMinutes = eh * 60 + em;
|
|
7609
|
+
if (endMinutes < startMinutes) {
|
|
7610
|
+
endMinutes += 24 * 60;
|
|
7611
|
+
}
|
|
7612
|
+
return endMinutes - startMinutes;
|
|
7613
|
+
};
|
|
7614
|
+
const fetchShiftConfig = async () => {
|
|
7615
|
+
try {
|
|
7616
|
+
setIsLoading(true);
|
|
7617
|
+
setError(null);
|
|
7618
|
+
console.log(`[useLineShiftConfig] \u{1F50D} Fetching shift config for line: ${lineId}`);
|
|
7619
|
+
const { data: shiftsData, error: shiftsError } = await supabase.from("line_operating_hours").select("shift_id, shift_name, start_time, end_time, breaks, timezone").eq("line_id", lineId);
|
|
7620
|
+
if (shiftsError) {
|
|
7621
|
+
console.error(`[useLineShiftConfig] \u274C Error fetching shifts:`, shiftsError);
|
|
7622
|
+
throw new Error(`Failed to fetch shift config: ${shiftsError.message}`);
|
|
7623
|
+
}
|
|
7624
|
+
if (!shiftsData || shiftsData.length === 0) {
|
|
7625
|
+
console.warn(`[useLineShiftConfig] \u26A0\uFE0F No shift config found for line ${lineId}, using fallback`);
|
|
7626
|
+
if (mounted) {
|
|
7627
|
+
setShiftConfig(fallbackConfig || null);
|
|
7628
|
+
setIsLoading(false);
|
|
7629
|
+
}
|
|
7630
|
+
return;
|
|
7631
|
+
}
|
|
7632
|
+
const stripSeconds = (timeStr) => {
|
|
7633
|
+
if (!timeStr) return timeStr;
|
|
7634
|
+
return timeStr.substring(0, 5);
|
|
7635
|
+
};
|
|
7636
|
+
const mapped = shiftsData.map((shift) => ({
|
|
7637
|
+
shiftId: shift.shift_id,
|
|
7638
|
+
shiftName: shift.shift_name || `Shift ${shift.shift_id}`,
|
|
7639
|
+
startTime: stripSeconds(shift.start_time),
|
|
7640
|
+
endTime: stripSeconds(shift.end_time),
|
|
7641
|
+
breaks: Array.isArray(shift.breaks) ? shift.breaks.map((b) => ({
|
|
7642
|
+
startTime: b.start || b.startTime || "00:00",
|
|
7643
|
+
endTime: b.end || b.endTime || "00:00",
|
|
7644
|
+
duration: calculateBreakDuration2(
|
|
7645
|
+
b.start || b.startTime || "00:00",
|
|
7646
|
+
b.end || b.endTime || "00:00"
|
|
7647
|
+
),
|
|
7648
|
+
remarks: b.remarks || b.name || ""
|
|
7649
|
+
})) : [],
|
|
7650
|
+
timezone: shift.timezone
|
|
7651
|
+
}));
|
|
7652
|
+
const day = mapped.find((s) => s.shiftId === 0);
|
|
7653
|
+
const night = mapped.find((s) => s.shiftId === 1);
|
|
7654
|
+
const config = {
|
|
7655
|
+
shifts: mapped,
|
|
7656
|
+
timezone: mapped[0]?.timezone,
|
|
7657
|
+
dayShift: day ? { id: day.shiftId, startTime: day.startTime, endTime: day.endTime, name: day.shiftName } : fallbackConfig?.dayShift,
|
|
7658
|
+
nightShift: night ? { id: night.shiftId, startTime: night.startTime, endTime: night.endTime, name: night.shiftName } : fallbackConfig?.nightShift,
|
|
7659
|
+
transitionPeriodMinutes: fallbackConfig?.transitionPeriodMinutes || 0
|
|
7660
|
+
};
|
|
7661
|
+
console.log(`[useLineShiftConfig] \u2705 Built config from DB:`, config);
|
|
7662
|
+
if (mounted) {
|
|
7663
|
+
setShiftConfig(config);
|
|
7664
|
+
setIsLoading(false);
|
|
7665
|
+
}
|
|
7666
|
+
} catch (err) {
|
|
7667
|
+
console.error("[useShiftConfig] Error fetching shift config:", err);
|
|
7668
|
+
if (mounted) {
|
|
7669
|
+
setError(err instanceof Error ? err.message : "Unknown error occurred");
|
|
7670
|
+
setShiftConfig(fallbackConfig || null);
|
|
7671
|
+
setIsLoading(false);
|
|
7672
|
+
}
|
|
7673
|
+
}
|
|
7674
|
+
};
|
|
7675
|
+
fetchShiftConfig();
|
|
7676
|
+
const subscription = supabase.channel(`shift_config_${lineId}`).on(
|
|
7677
|
+
"postgres_changes",
|
|
7678
|
+
{
|
|
7679
|
+
event: "*",
|
|
7680
|
+
// Listen to all events (INSERT, UPDATE, DELETE)
|
|
7681
|
+
schema: "public",
|
|
7682
|
+
table: "line_operating_hours",
|
|
7683
|
+
filter: `line_id=eq.${lineId}`
|
|
7684
|
+
},
|
|
7685
|
+
(payload) => {
|
|
7686
|
+
console.log("[useShiftConfig] Real-time update received:", payload);
|
|
7687
|
+
fetchShiftConfig();
|
|
7688
|
+
}
|
|
7689
|
+
).subscribe();
|
|
7690
|
+
return () => {
|
|
7691
|
+
mounted = false;
|
|
7692
|
+
subscription.unsubscribe();
|
|
7693
|
+
};
|
|
7694
|
+
}, [lineId, supabase]);
|
|
7695
|
+
return {
|
|
7696
|
+
shiftConfig,
|
|
7697
|
+
isLoading,
|
|
7698
|
+
error
|
|
7699
|
+
};
|
|
7700
|
+
};
|
|
7701
|
+
|
|
7702
|
+
// src/lib/hooks/useDynamicShiftConfig.ts
|
|
7703
|
+
var useDynamicShiftConfig = (lineId) => {
|
|
7704
|
+
const staticShiftConfig = useShiftConfig();
|
|
7705
|
+
const { shiftConfig: dbShiftConfig, isLoading, error } = useLineShiftConfig(lineId, staticShiftConfig);
|
|
7706
|
+
const result = React23.useMemo(() => {
|
|
7707
|
+
console.log(`[useDynamicShiftConfig] \u{1F504} Computing result for lineId: ${lineId}`, {
|
|
7708
|
+
isLoading,
|
|
7709
|
+
hasDbConfig: !!dbShiftConfig,
|
|
7710
|
+
error
|
|
7711
|
+
});
|
|
7712
|
+
if (isLoading) {
|
|
7713
|
+
console.log(`[useDynamicShiftConfig] \u23F3 Still loading, returning null (DO NOT USE until loaded)`);
|
|
7714
|
+
return {
|
|
7715
|
+
shiftConfig: null,
|
|
7716
|
+
isLoading: true,
|
|
7717
|
+
error: null,
|
|
7718
|
+
isFromDatabase: false
|
|
7719
|
+
};
|
|
7720
|
+
}
|
|
7721
|
+
if (dbShiftConfig) {
|
|
7722
|
+
console.log(`[useDynamicShiftConfig] \u2705 Using DB config:`, dbShiftConfig);
|
|
7723
|
+
return {
|
|
7724
|
+
shiftConfig: dbShiftConfig,
|
|
7725
|
+
isLoading: false,
|
|
7726
|
+
error,
|
|
7727
|
+
isFromDatabase: true
|
|
7728
|
+
};
|
|
7729
|
+
}
|
|
7730
|
+
console.log(`[useDynamicShiftConfig] \u26A0\uFE0F No DB config found, falling back to static config`);
|
|
7731
|
+
return {
|
|
7732
|
+
shiftConfig: staticShiftConfig,
|
|
7733
|
+
isLoading: false,
|
|
7734
|
+
error,
|
|
7735
|
+
isFromDatabase: false
|
|
7736
|
+
};
|
|
7737
|
+
}, [dbShiftConfig, staticShiftConfig, isLoading, error, lineId]);
|
|
7738
|
+
return result;
|
|
7739
|
+
};
|
|
7740
|
+
|
|
7741
|
+
// src/lib/hooks/useLineWorkspaceMetrics.ts
|
|
7470
7742
|
var useLineWorkspaceMetrics = (lineId, options) => {
|
|
7471
7743
|
const entityConfig = useEntityConfig();
|
|
7472
7744
|
const databaseConfig = useDatabaseConfig();
|
|
7473
7745
|
const dateTimeConfig = useDateTimeConfig();
|
|
7474
|
-
const
|
|
7746
|
+
const staticShiftConfig = useShiftConfig();
|
|
7747
|
+
const { shiftConfig: dynamicShiftConfig, isLoading: isShiftConfigLoading } = useDynamicShiftConfig(lineId);
|
|
7748
|
+
const shiftConfig = dynamicShiftConfig || staticShiftConfig;
|
|
7475
7749
|
const timezone = useAppTimezone();
|
|
7476
7750
|
const supabase = useSupabase();
|
|
7477
7751
|
const [workspaces, setWorkspaces] = React23.useState([]);
|
|
@@ -7479,12 +7753,10 @@ var useLineWorkspaceMetrics = (lineId, options) => {
|
|
|
7479
7753
|
const [error, setError] = React23.useState(null);
|
|
7480
7754
|
const [initialized, setInitialized] = React23.useState(false);
|
|
7481
7755
|
const queryShiftId = React23.useMemo(() => {
|
|
7482
|
-
const
|
|
7483
|
-
|
|
7484
|
-
shiftConfig
|
|
7485
|
-
);
|
|
7756
|
+
const effectiveTimezone = timezone || dateTimeConfig.defaultTimezone || "Asia/Kolkata";
|
|
7757
|
+
const currentShift = getCurrentShift(effectiveTimezone, shiftConfig);
|
|
7486
7758
|
return options?.initialShiftId !== void 0 ? options.initialShiftId : currentShift.shiftId;
|
|
7487
|
-
}, [options?.initialShiftId, dateTimeConfig.defaultTimezone, shiftConfig]);
|
|
7759
|
+
}, [options?.initialShiftId, timezone, dateTimeConfig.defaultTimezone, shiftConfig]);
|
|
7488
7760
|
const queryDate = React23.useMemo(() => {
|
|
7489
7761
|
return options?.initialDate || getOperationalDate(timezone || dateTimeConfig.defaultTimezone || "UTC");
|
|
7490
7762
|
}, [options?.initialDate, timezone, dateTimeConfig.defaultTimezone]);
|
|
@@ -7496,7 +7768,7 @@ var useLineWorkspaceMetrics = (lineId, options) => {
|
|
|
7496
7768
|
}, [entityConfig.companyId]);
|
|
7497
7769
|
const schema = databaseConfig.schema ?? "public";
|
|
7498
7770
|
const fetchWorkspaceMetrics = React23.useCallback(async () => {
|
|
7499
|
-
if (!lineId) return;
|
|
7771
|
+
if (!lineId || options?.enabled === false || isShiftConfigLoading) return;
|
|
7500
7772
|
if (!initialized) {
|
|
7501
7773
|
setLoading(true);
|
|
7502
7774
|
}
|
|
@@ -7553,7 +7825,7 @@ var useLineWorkspaceMetrics = (lineId, options) => {
|
|
|
7553
7825
|
} finally {
|
|
7554
7826
|
setLoading(false);
|
|
7555
7827
|
}
|
|
7556
|
-
}, [lineId, queryDate, queryShiftId, metricsTable, supabase, entityConfig.companyId]);
|
|
7828
|
+
}, [lineId, queryDate, queryShiftId, metricsTable, supabase, entityConfig.companyId, options?.enabled, isShiftConfigLoading]);
|
|
7557
7829
|
React23.useEffect(() => {
|
|
7558
7830
|
if (!initialized) {
|
|
7559
7831
|
fetchWorkspaceMetrics();
|
|
@@ -7583,25 +7855,26 @@ var useLineWorkspaceMetrics = (lineId, options) => {
|
|
|
7583
7855
|
supabase.removeChannel(channel);
|
|
7584
7856
|
}
|
|
7585
7857
|
};
|
|
7586
|
-
}, [lineId, queryDate, queryShiftId, metricsTable, fetchWorkspaceMetrics, initialized, supabase, schema]);
|
|
7858
|
+
}, [lineId, queryDate, queryShiftId, metricsTable, fetchWorkspaceMetrics, initialized, supabase, schema, isShiftConfigLoading]);
|
|
7587
7859
|
React23.useEffect(() => {
|
|
7588
7860
|
setInitialized(false);
|
|
7589
|
-
}, [lineId, queryDate, queryShiftId]);
|
|
7861
|
+
}, [lineId, queryDate, queryShiftId, isShiftConfigLoading]);
|
|
7590
7862
|
const refreshWorkspaces = fetchWorkspaceMetrics;
|
|
7591
7863
|
return React23.useMemo(
|
|
7592
7864
|
() => ({ workspaces, loading, error, refreshWorkspaces }),
|
|
7593
7865
|
[workspaces, loading, error, refreshWorkspaces]
|
|
7594
7866
|
);
|
|
7595
7867
|
};
|
|
7596
|
-
var useHistoricWorkspaceMetrics = (workspaceId, date, shiftId) => {
|
|
7868
|
+
var useHistoricWorkspaceMetrics = (workspaceId, date, shiftId, options) => {
|
|
7597
7869
|
const supabase = useSupabase();
|
|
7598
7870
|
const entityConfig = useEntityConfig();
|
|
7871
|
+
const timezone = useAppTimezone();
|
|
7599
7872
|
const [metrics2, setMetrics] = React23.useState(null);
|
|
7600
7873
|
const [isLoading, setIsLoading] = React23.useState(true);
|
|
7601
7874
|
const [error, setError] = React23.useState(null);
|
|
7602
7875
|
const isFetchingRef = React23.useRef(false);
|
|
7603
7876
|
const fetchMetrics = React23.useCallback(async () => {
|
|
7604
|
-
if (!supabase || !workspaceId || !date || isFetchingRef.current) return;
|
|
7877
|
+
if (!supabase || !workspaceId || !date || isFetchingRef.current || options?.enabled === false) return;
|
|
7605
7878
|
try {
|
|
7606
7879
|
isFetchingRef.current = true;
|
|
7607
7880
|
setIsLoading(true);
|
|
@@ -7635,7 +7908,18 @@ var useHistoricWorkspaceMetrics = (workspaceId, date, shiftId) => {
|
|
|
7635
7908
|
throw new Error(`Backend API error (${response.status}): ${errorText}`);
|
|
7636
7909
|
}
|
|
7637
7910
|
const data = await response.json();
|
|
7638
|
-
|
|
7911
|
+
const fetchedMetrics = data.metrics;
|
|
7912
|
+
if (fetchedMetrics && options?.shiftConfig) {
|
|
7913
|
+
const dynamicShiftName = getShiftNameById(
|
|
7914
|
+
fetchedMetrics.shift_id,
|
|
7915
|
+
timezone || "Asia/Kolkata",
|
|
7916
|
+
// Fallback timezone
|
|
7917
|
+
options.shiftConfig
|
|
7918
|
+
);
|
|
7919
|
+
fetchedMetrics.shift_type = dynamicShiftName;
|
|
7920
|
+
console.log(`[useHistoricWorkspaceMetrics] Overriding shift name for ID ${fetchedMetrics.shift_id}: ${dynamicShiftName}`);
|
|
7921
|
+
}
|
|
7922
|
+
setMetrics(fetchedMetrics || null);
|
|
7639
7923
|
} catch (err) {
|
|
7640
7924
|
console.error("[useHistoricWorkspaceMetrics] Error fetching historic metrics:", err);
|
|
7641
7925
|
setError({ message: err.message, code: err.code || "FETCH_ERROR" });
|
|
@@ -7644,7 +7928,7 @@ var useHistoricWorkspaceMetrics = (workspaceId, date, shiftId) => {
|
|
|
7644
7928
|
setIsLoading(false);
|
|
7645
7929
|
isFetchingRef.current = false;
|
|
7646
7930
|
}
|
|
7647
|
-
}, [supabase, workspaceId, date, shiftId, entityConfig.companyId]);
|
|
7931
|
+
}, [supabase, workspaceId, date, shiftId, entityConfig.companyId, options?.shiftConfig, timezone, options?.enabled]);
|
|
7648
7932
|
React23.useEffect(() => {
|
|
7649
7933
|
fetchMetrics();
|
|
7650
7934
|
}, [fetchMetrics]);
|
|
@@ -7659,8 +7943,11 @@ var useLineDetailedMetrics = (lineIdFromProp) => {
|
|
|
7659
7943
|
const entityConfig = useEntityConfig();
|
|
7660
7944
|
const databaseConfig = useDatabaseConfig();
|
|
7661
7945
|
const dateTimeConfig = useDateTimeConfig();
|
|
7662
|
-
const
|
|
7946
|
+
const staticShiftConfig = useShiftConfig();
|
|
7663
7947
|
const supabase = useSupabase();
|
|
7948
|
+
const lineIdForShiftConfig = lineIdFromProp === "factory" ? getConfiguredLineIds(entityConfig)[0] : lineIdFromProp;
|
|
7949
|
+
const { shiftConfig: dynamicShiftConfig, isLoading: isShiftConfigLoading } = useDynamicShiftConfig(lineIdForShiftConfig);
|
|
7950
|
+
const shiftConfig = dynamicShiftConfig || staticShiftConfig;
|
|
7664
7951
|
const [lineData, setLineData] = React23.useState(null);
|
|
7665
7952
|
const [loading, setLoading] = React23.useState(true);
|
|
7666
7953
|
const [error, setError] = React23.useState(null);
|
|
@@ -7699,8 +7986,10 @@ var useLineDetailedMetrics = (lineIdFromProp) => {
|
|
|
7699
7986
|
}
|
|
7700
7987
|
}, [dashboardService, lineIdToUse, defaultTimezone, shiftConfig, entityConfig]);
|
|
7701
7988
|
React23.useEffect(() => {
|
|
7702
|
-
if (!supabase || !lineIdToUse || !entityConfig.companyId) {
|
|
7703
|
-
|
|
7989
|
+
if (!supabase || !lineIdToUse || !entityConfig.companyId || isShiftConfigLoading) {
|
|
7990
|
+
if (!isShiftConfigLoading) {
|
|
7991
|
+
setLoading(false);
|
|
7992
|
+
}
|
|
7704
7993
|
if (!entityConfig.companyId && (!error || error.code !== "SERVICE_ERROR")) {
|
|
7705
7994
|
setError({ message: "Company ID not configured for metrics subscription.", code: "CONFIG_ERROR" });
|
|
7706
7995
|
}
|
|
@@ -7765,7 +8054,7 @@ var useLineDetailedMetrics = (lineIdFromProp) => {
|
|
|
7765
8054
|
channelRef.current = null;
|
|
7766
8055
|
}
|
|
7767
8056
|
};
|
|
7768
|
-
}, [supabase, lineIdToUse, fetchData, schema, lineMetricsTable, entityConfig, defaultTimezone, shiftConfig, error]);
|
|
8057
|
+
}, [supabase, lineIdToUse, fetchData, schema, lineMetricsTable, entityConfig, defaultTimezone, shiftConfig, isShiftConfigLoading, error]);
|
|
7769
8058
|
return {
|
|
7770
8059
|
lineData,
|
|
7771
8060
|
// This now contains both metrics and line details via LineInfo type
|
|
@@ -7778,14 +8067,20 @@ var useLeaderboardMetrics = (date, shiftId, limit = 10, filter2 = "all") => {
|
|
|
7778
8067
|
const supabase = useSupabase();
|
|
7779
8068
|
const entityConfig = useEntityConfig();
|
|
7780
8069
|
const dateTimeConfig = useDateTimeConfig();
|
|
7781
|
-
const
|
|
8070
|
+
const staticShiftConfig = useShiftConfig();
|
|
8071
|
+
const firstLineId = React23.useMemo(() => {
|
|
8072
|
+
const lineIds = getConfiguredLineIds(entityConfig);
|
|
8073
|
+
return lineIds[0];
|
|
8074
|
+
}, [entityConfig]);
|
|
8075
|
+
const { shiftConfig: dynamicShiftConfig, isLoading: isShiftConfigLoading } = useDynamicShiftConfig(firstLineId);
|
|
8076
|
+
const shiftConfig = dynamicShiftConfig || staticShiftConfig;
|
|
7782
8077
|
const [leaderboard, setLeaderboard] = React23.useState([]);
|
|
7783
8078
|
const [isLoading, setIsLoading] = React23.useState(true);
|
|
7784
8079
|
const [error, setError] = React23.useState(null);
|
|
7785
8080
|
const isFetchingRef = React23.useRef(false);
|
|
7786
8081
|
const defaultTimezone = dateTimeConfig.defaultTimezone || "UTC";
|
|
7787
8082
|
const fetchLeaderboard = React23.useCallback(async () => {
|
|
7788
|
-
if (!supabase || isFetchingRef.current) return;
|
|
8083
|
+
if (!supabase || isFetchingRef.current || isShiftConfigLoading) return;
|
|
7789
8084
|
try {
|
|
7790
8085
|
isFetchingRef.current = true;
|
|
7791
8086
|
setIsLoading(true);
|
|
@@ -7831,7 +8126,7 @@ var useLeaderboardMetrics = (date, shiftId, limit = 10, filter2 = "all") => {
|
|
|
7831
8126
|
setIsLoading(false);
|
|
7832
8127
|
isFetchingRef.current = false;
|
|
7833
8128
|
}
|
|
7834
|
-
}, [supabase, date, shiftId, limit, filter2, entityConfig.companyId, defaultTimezone, shiftConfig]);
|
|
8129
|
+
}, [supabase, date, shiftId, limit, filter2, entityConfig.companyId, defaultTimezone, shiftConfig, isShiftConfigLoading]);
|
|
7835
8130
|
React23.useEffect(() => {
|
|
7836
8131
|
fetchLeaderboard();
|
|
7837
8132
|
}, [fetchLeaderboard]);
|
|
@@ -7847,8 +8142,22 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId, userAccessibleLineIds
|
|
|
7847
8142
|
const entityConfig = useEntityConfig();
|
|
7848
8143
|
const databaseConfig = useDatabaseConfig();
|
|
7849
8144
|
const dateTimeConfig = useDateTimeConfig();
|
|
7850
|
-
const
|
|
7851
|
-
const
|
|
8145
|
+
const isFactoryView = lineId === (entityConfig.factoryViewId || "factory");
|
|
8146
|
+
const firstLineId = React23.useMemo(() => {
|
|
8147
|
+
const configuredLineIds = getConfiguredLineIds(entityConfig);
|
|
8148
|
+
return configuredLineIds.length > 0 ? configuredLineIds[0] : void 0;
|
|
8149
|
+
}, [entityConfig]);
|
|
8150
|
+
const lineIdForShiftConfig = isFactoryView ? firstLineId : lineId;
|
|
8151
|
+
const { shiftConfig, isLoading: shiftLoading, isFromDatabase } = useDynamicShiftConfig(lineIdForShiftConfig);
|
|
8152
|
+
console.log(`[useDashboardMetrics] \u{1F3AF} Shift config for line ${lineId}:`, {
|
|
8153
|
+
isFactoryView,
|
|
8154
|
+
lineIdForShiftConfig,
|
|
8155
|
+
firstLineId,
|
|
8156
|
+
isFromDatabase,
|
|
8157
|
+
shiftConfig: shiftConfig ? { shifts: shiftConfig.shifts?.length, timezone: shiftConfig.timezone } : null
|
|
8158
|
+
});
|
|
8159
|
+
const appTimezone = useAppTimezone();
|
|
8160
|
+
const defaultTimezone = appTimezone || dateTimeConfig?.defaultTimezone || "UTC";
|
|
7852
8161
|
const configuredLineMetricsTable = databaseConfig?.tables?.lineMetrics ?? "line_metrics";
|
|
7853
8162
|
const schema = databaseConfig?.schema ?? "public";
|
|
7854
8163
|
const supabase = useSupabase();
|
|
@@ -7874,8 +8183,8 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId, userAccessibleLineIds
|
|
|
7874
8183
|
const fetchAllMetrics = React23.useCallback(async () => {
|
|
7875
8184
|
const currentLineIdToUse = lineIdRef.current;
|
|
7876
8185
|
console.log("[useDashboardMetrics] Fetching from backend API. lineId:", currentLineIdToUse);
|
|
7877
|
-
if (!currentLineIdToUse || !supabase || isFetchingRef.current || companySpecificMetricsTable.includes("unknown_company")) {
|
|
7878
|
-
if (!metrics2?.workspaceMetrics?.length && !metrics2?.lineMetrics?.length) setIsLoading(false);
|
|
8186
|
+
if (!currentLineIdToUse || !supabase || isFetchingRef.current || shiftLoading || companySpecificMetricsTable.includes("unknown_company")) {
|
|
8187
|
+
if (!metrics2?.workspaceMetrics?.length && !metrics2?.lineMetrics?.length && !shiftLoading) setIsLoading(false);
|
|
7879
8188
|
if (companySpecificMetricsTable.includes("unknown_company") && !error) {
|
|
7880
8189
|
setError({ message: "Company ID not configured for metrics table.", code: "CONFIG_ERROR" });
|
|
7881
8190
|
}
|
|
@@ -7894,7 +8203,7 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId, userAccessibleLineIds
|
|
|
7894
8203
|
if (targetLineIds.length === 0) {
|
|
7895
8204
|
throw new Error("No target line IDs available for fetching metrics.");
|
|
7896
8205
|
}
|
|
7897
|
-
const
|
|
8206
|
+
const isFactoryView2 = currentLineIdToUse === (entityConfig.factoryViewId || "factory");
|
|
7898
8207
|
const { data: { session } } = await supabase.auth.getSession();
|
|
7899
8208
|
console.log("[useDashboardMetrics] Session check:", {
|
|
7900
8209
|
hasSession: !!session,
|
|
@@ -7908,7 +8217,7 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId, userAccessibleLineIds
|
|
|
7908
8217
|
if (!apiUrl) {
|
|
7909
8218
|
throw new Error("Backend URL is not configured. Please set NEXT_PUBLIC_BACKEND_URL in your environment.");
|
|
7910
8219
|
}
|
|
7911
|
-
const lineIdsParam =
|
|
8220
|
+
const lineIdsParam = isFactoryView2 ? `line_ids=${targetLineIds.join(",")}` : `line_id=${targetLineIds[0]}`;
|
|
7912
8221
|
const url = `${apiUrl}/api/dashboard/metrics?${lineIdsParam}&date=${operationalDate}&shift_id=${currentShiftDetails.shiftId}&company_id=${entityConfig.companyId}`;
|
|
7913
8222
|
console.log("[useDashboardMetrics] Calling backend API:", {
|
|
7914
8223
|
url,
|
|
@@ -7987,8 +8296,10 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId, userAccessibleLineIds
|
|
|
7987
8296
|
metrics2?.lineMetrics?.length || 0,
|
|
7988
8297
|
companySpecificMetricsTable,
|
|
7989
8298
|
entityConfig,
|
|
8299
|
+
appTimezone,
|
|
7990
8300
|
defaultTimezone,
|
|
7991
|
-
shiftConfig
|
|
8301
|
+
shiftConfig,
|
|
8302
|
+
shiftLoading
|
|
7992
8303
|
]);
|
|
7993
8304
|
const fetchAllMetricsRef = React23.useRef(fetchAllMetrics);
|
|
7994
8305
|
React23.useEffect(() => {
|
|
@@ -8002,10 +8313,10 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId, userAccessibleLineIds
|
|
|
8002
8313
|
fetchAllMetricsRef.current();
|
|
8003
8314
|
}, [supabase]);
|
|
8004
8315
|
React23.useEffect(() => {
|
|
8005
|
-
if (lineId && supabase) {
|
|
8316
|
+
if (lineId && supabase && !shiftLoading) {
|
|
8006
8317
|
fetchAllMetrics();
|
|
8007
8318
|
}
|
|
8008
|
-
}, [lineId, supabase, fetchAllMetrics]);
|
|
8319
|
+
}, [lineId, supabase, fetchAllMetrics, shiftLoading]);
|
|
8009
8320
|
React23.useEffect(() => {
|
|
8010
8321
|
const currentLineIdToUse = lineIdRef.current;
|
|
8011
8322
|
if (!currentLineIdToUse || !supabase || companySpecificMetricsTable.includes("unknown_company") || !entityConfig.companyId) {
|
|
@@ -8050,7 +8361,9 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId, userAccessibleLineIds
|
|
|
8050
8361
|
schema,
|
|
8051
8362
|
entityConfig?.companyId,
|
|
8052
8363
|
entityConfig?.factoryViewId,
|
|
8364
|
+
appTimezone,
|
|
8053
8365
|
defaultTimezone,
|
|
8366
|
+
shiftConfig,
|
|
8054
8367
|
lineId,
|
|
8055
8368
|
userAccessibleLineIds
|
|
8056
8369
|
]);
|
|
@@ -8062,145 +8375,7 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId, userAccessibleLineIds
|
|
|
8062
8375
|
refetch: fetchAllMetrics
|
|
8063
8376
|
};
|
|
8064
8377
|
};
|
|
8065
|
-
var
|
|
8066
|
-
const [shiftConfig, setShiftConfig] = React23.useState(fallbackConfig || null);
|
|
8067
|
-
const [isLoading, setIsLoading] = React23.useState(true);
|
|
8068
|
-
const [error, setError] = React23.useState(null);
|
|
8069
|
-
const supabase = useSupabase();
|
|
8070
|
-
React23.useEffect(() => {
|
|
8071
|
-
if (!lineId || lineId === "factory" || lineId === "all") {
|
|
8072
|
-
setShiftConfig(fallbackConfig || null);
|
|
8073
|
-
setIsLoading(false);
|
|
8074
|
-
return;
|
|
8075
|
-
}
|
|
8076
|
-
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
8077
|
-
if (!uuidRegex.test(lineId)) {
|
|
8078
|
-
console.warn(`[useShiftConfig] Invalid line ID format: ${lineId}, using fallback`);
|
|
8079
|
-
setShiftConfig(fallbackConfig || null);
|
|
8080
|
-
setIsLoading(false);
|
|
8081
|
-
return;
|
|
8082
|
-
}
|
|
8083
|
-
let mounted = true;
|
|
8084
|
-
const fetchShiftConfig = async () => {
|
|
8085
|
-
try {
|
|
8086
|
-
setIsLoading(true);
|
|
8087
|
-
setError(null);
|
|
8088
|
-
console.log(`[useLineShiftConfig] \u{1F50D} Fetching shift config for line: ${lineId}`);
|
|
8089
|
-
const { data: dayShift, error: dayError } = await supabase.from("line_operating_hours").select("start_time, end_time, breaks").eq("line_id", lineId).eq("shift_id", 0).maybeSingle();
|
|
8090
|
-
const { data: nightShift, error: nightError } = await supabase.from("line_operating_hours").select("start_time, end_time, breaks").eq("line_id", lineId).eq("shift_id", 1).maybeSingle();
|
|
8091
|
-
console.log(`[useLineShiftConfig] \u{1F4CA} Day shift data:`, dayShift);
|
|
8092
|
-
console.log(`[useLineShiftConfig] \u{1F319} Night shift data:`, nightShift);
|
|
8093
|
-
if (dayError || nightError) {
|
|
8094
|
-
console.error(`[useLineShiftConfig] \u274C Error fetching:`, { dayError, nightError });
|
|
8095
|
-
throw new Error(`Failed to fetch shift config: ${dayError?.message || nightError?.message}`);
|
|
8096
|
-
}
|
|
8097
|
-
if (!dayShift && !nightShift) {
|
|
8098
|
-
console.warn(`[useLineShiftConfig] \u26A0\uFE0F No shift config found for line ${lineId}, using fallback`);
|
|
8099
|
-
if (mounted) {
|
|
8100
|
-
setShiftConfig(fallbackConfig || null);
|
|
8101
|
-
setIsLoading(false);
|
|
8102
|
-
}
|
|
8103
|
-
return;
|
|
8104
|
-
}
|
|
8105
|
-
const stripSeconds = (timeStr) => {
|
|
8106
|
-
if (!timeStr) return timeStr;
|
|
8107
|
-
return timeStr.substring(0, 5);
|
|
8108
|
-
};
|
|
8109
|
-
const config = {
|
|
8110
|
-
dayShift: dayShift ? {
|
|
8111
|
-
id: 0,
|
|
8112
|
-
startTime: stripSeconds(dayShift.start_time),
|
|
8113
|
-
endTime: stripSeconds(dayShift.end_time)
|
|
8114
|
-
} : fallbackConfig?.dayShift || { id: 0, startTime: "06:00", endTime: "18:00" },
|
|
8115
|
-
nightShift: nightShift ? {
|
|
8116
|
-
id: 1,
|
|
8117
|
-
startTime: stripSeconds(nightShift.start_time),
|
|
8118
|
-
endTime: stripSeconds(nightShift.end_time)
|
|
8119
|
-
} : fallbackConfig?.nightShift || { id: 1, startTime: "18:00", endTime: "06:00" },
|
|
8120
|
-
transitionPeriodMinutes: fallbackConfig?.transitionPeriodMinutes || 0
|
|
8121
|
-
};
|
|
8122
|
-
console.log(`[useLineShiftConfig] \u2705 Built config from DB:`, config);
|
|
8123
|
-
if (mounted) {
|
|
8124
|
-
setShiftConfig(config);
|
|
8125
|
-
setIsLoading(false);
|
|
8126
|
-
}
|
|
8127
|
-
} catch (err) {
|
|
8128
|
-
console.error("[useShiftConfig] Error fetching shift config:", err);
|
|
8129
|
-
if (mounted) {
|
|
8130
|
-
setError(err instanceof Error ? err.message : "Unknown error occurred");
|
|
8131
|
-
setShiftConfig(fallbackConfig || null);
|
|
8132
|
-
setIsLoading(false);
|
|
8133
|
-
}
|
|
8134
|
-
}
|
|
8135
|
-
};
|
|
8136
|
-
fetchShiftConfig();
|
|
8137
|
-
const subscription = supabase.channel(`shift_config_${lineId}`).on(
|
|
8138
|
-
"postgres_changes",
|
|
8139
|
-
{
|
|
8140
|
-
event: "*",
|
|
8141
|
-
// Listen to all events (INSERT, UPDATE, DELETE)
|
|
8142
|
-
schema: "public",
|
|
8143
|
-
table: "line_operating_hours",
|
|
8144
|
-
filter: `line_id=eq.${lineId}`
|
|
8145
|
-
},
|
|
8146
|
-
(payload) => {
|
|
8147
|
-
console.log("[useShiftConfig] Real-time update received:", payload);
|
|
8148
|
-
fetchShiftConfig();
|
|
8149
|
-
}
|
|
8150
|
-
).subscribe();
|
|
8151
|
-
return () => {
|
|
8152
|
-
mounted = false;
|
|
8153
|
-
subscription.unsubscribe();
|
|
8154
|
-
};
|
|
8155
|
-
}, [lineId, supabase]);
|
|
8156
|
-
return {
|
|
8157
|
-
shiftConfig,
|
|
8158
|
-
isLoading,
|
|
8159
|
-
error
|
|
8160
|
-
};
|
|
8161
|
-
};
|
|
8162
|
-
|
|
8163
|
-
// src/lib/hooks/useDynamicShiftConfig.ts
|
|
8164
|
-
var useDynamicShiftConfig = (lineId) => {
|
|
8165
|
-
const staticShiftConfig = useShiftConfig();
|
|
8166
|
-
const { shiftConfig: dbShiftConfig, isLoading, error } = useLineShiftConfig(lineId, staticShiftConfig);
|
|
8167
|
-
const result = React23.useMemo(() => {
|
|
8168
|
-
console.log(`[useDynamicShiftConfig] \u{1F504} Computing result for lineId: ${lineId}`, {
|
|
8169
|
-
isLoading,
|
|
8170
|
-
hasDbConfig: !!dbShiftConfig,
|
|
8171
|
-
error
|
|
8172
|
-
});
|
|
8173
|
-
if (isLoading) {
|
|
8174
|
-
console.log(`[useDynamicShiftConfig] \u23F3 Still loading, using static config temporarily`);
|
|
8175
|
-
return {
|
|
8176
|
-
shiftConfig: staticShiftConfig,
|
|
8177
|
-
isLoading: true,
|
|
8178
|
-
error: null,
|
|
8179
|
-
isFromDatabase: false
|
|
8180
|
-
};
|
|
8181
|
-
}
|
|
8182
|
-
if (dbShiftConfig) {
|
|
8183
|
-
console.log(`[useDynamicShiftConfig] \u2705 Using DB config:`, dbShiftConfig);
|
|
8184
|
-
return {
|
|
8185
|
-
shiftConfig: dbShiftConfig,
|
|
8186
|
-
isLoading: false,
|
|
8187
|
-
error,
|
|
8188
|
-
isFromDatabase: true
|
|
8189
|
-
};
|
|
8190
|
-
}
|
|
8191
|
-
console.log(`[useDynamicShiftConfig] \u26A0\uFE0F Falling back to static config`);
|
|
8192
|
-
return {
|
|
8193
|
-
shiftConfig: staticShiftConfig,
|
|
8194
|
-
isLoading: false,
|
|
8195
|
-
error,
|
|
8196
|
-
isFromDatabase: false
|
|
8197
|
-
};
|
|
8198
|
-
}, [dbShiftConfig, staticShiftConfig, isLoading, error, lineId]);
|
|
8199
|
-
return result;
|
|
8200
|
-
};
|
|
8201
|
-
|
|
8202
|
-
// src/lib/hooks/useLineKPIs.ts
|
|
8203
|
-
var useLineKPIs = ({ lineId }) => {
|
|
8378
|
+
var useLineKPIs = ({ lineId, enabled }) => {
|
|
8204
8379
|
useDashboardConfig();
|
|
8205
8380
|
const entityConfig = useEntityConfig();
|
|
8206
8381
|
const isFactoryView = lineId === (entityConfig.factoryViewId || "factory");
|
|
@@ -8212,7 +8387,7 @@ var useLineKPIs = ({ lineId }) => {
|
|
|
8212
8387
|
return configuredLineIds.length > 0 ? configuredLineIds[0] : void 0;
|
|
8213
8388
|
}, [entityConfig]);
|
|
8214
8389
|
const lineIdForShiftConfig = isFactoryView ? firstLineId : lineId;
|
|
8215
|
-
const { shiftConfig: dynamicShiftConfig, isFromDatabase } = useDynamicShiftConfig(lineIdForShiftConfig);
|
|
8390
|
+
const { shiftConfig: dynamicShiftConfig, isFromDatabase, isLoading: isShiftConfigLoading } = useDynamicShiftConfig(lineIdForShiftConfig);
|
|
8216
8391
|
const shiftConfig = dynamicShiftConfig;
|
|
8217
8392
|
console.log(`[useLineKPIs] \u{1F3AF} Shift config for line ${lineId}:`, {
|
|
8218
8393
|
isFactoryView,
|
|
@@ -8233,7 +8408,8 @@ var useLineKPIs = ({ lineId }) => {
|
|
|
8233
8408
|
const updateQueueRef = React23.useRef(false);
|
|
8234
8409
|
const updateTimeoutRef = React23.useRef(null);
|
|
8235
8410
|
const queueUpdateRef = React23.useRef(void 0);
|
|
8236
|
-
const
|
|
8411
|
+
const appTimezone = useAppTimezone();
|
|
8412
|
+
const timezone = appTimezone || dateTimeConfig.defaultTimezone || "UTC";
|
|
8237
8413
|
const schema = databaseConfig.schema ?? "public";
|
|
8238
8414
|
const lineMetricsTable = databaseConfig.tables?.lineMetrics ?? "line_metrics";
|
|
8239
8415
|
const companySpecificMetricsTable = React23.useMemo(
|
|
@@ -8245,14 +8421,14 @@ var useLineKPIs = ({ lineId }) => {
|
|
|
8245
8421
|
}, [lineId]);
|
|
8246
8422
|
const fetchKPIs = React23.useCallback(async () => {
|
|
8247
8423
|
const currentLineId = lineIdRef.current;
|
|
8248
|
-
if (!currentLineId || isFetchingRef.current) {
|
|
8424
|
+
if (!currentLineId || isFetchingRef.current || enabled === false || isShiftConfigLoading) {
|
|
8249
8425
|
return;
|
|
8250
8426
|
}
|
|
8251
8427
|
isFetchingRef.current = true;
|
|
8252
8428
|
setIsLoading(true);
|
|
8253
8429
|
setError(null);
|
|
8254
8430
|
try {
|
|
8255
|
-
const currentShiftDetails = getCurrentShift(
|
|
8431
|
+
const currentShiftDetails = getCurrentShift(timezone, shiftConfig ?? void 0);
|
|
8256
8432
|
const operationalDate = currentShiftDetails.date;
|
|
8257
8433
|
const { data: { session } } = await supabase.auth.getSession();
|
|
8258
8434
|
if (!session?.access_token) {
|
|
@@ -8301,7 +8477,7 @@ var useLineKPIs = ({ lineId }) => {
|
|
|
8301
8477
|
isFetchingRef.current = false;
|
|
8302
8478
|
updateQueueRef.current = false;
|
|
8303
8479
|
}
|
|
8304
|
-
}, [
|
|
8480
|
+
}, [timezone, shiftConfig, entityConfig, supabase, enabled, isShiftConfigLoading]);
|
|
8305
8481
|
const queueUpdate = React23.useCallback(() => {
|
|
8306
8482
|
if (updateTimeoutRef.current) {
|
|
8307
8483
|
clearTimeout(updateTimeoutRef.current);
|
|
@@ -8321,7 +8497,7 @@ var useLineKPIs = ({ lineId }) => {
|
|
|
8321
8497
|
return;
|
|
8322
8498
|
}
|
|
8323
8499
|
fetchKPIs();
|
|
8324
|
-
const currentShiftDetails = getCurrentShift(
|
|
8500
|
+
const currentShiftDetails = getCurrentShift(timezone, shiftConfig ?? void 0);
|
|
8325
8501
|
const operationalDate = currentShiftDetails.date;
|
|
8326
8502
|
const factoryViewIdentifier = entityConfig.factoryViewId || "factory";
|
|
8327
8503
|
const targetLineIds = currentLineId === factoryViewIdentifier ? getConfiguredLineIds(entityConfig) : [currentLineId];
|
|
@@ -8374,7 +8550,7 @@ var useLineKPIs = ({ lineId }) => {
|
|
|
8374
8550
|
clearTimeout(updateTimeoutRef.current);
|
|
8375
8551
|
}
|
|
8376
8552
|
};
|
|
8377
|
-
}, [lineId, supabase, entityConfig, schema, lineMetricsTable, companySpecificMetricsTable,
|
|
8553
|
+
}, [lineId, supabase, entityConfig, schema, lineMetricsTable, companySpecificMetricsTable, timezone, shiftConfig, isShiftConfigLoading]);
|
|
8378
8554
|
return {
|
|
8379
8555
|
kpis,
|
|
8380
8556
|
isLoading,
|
|
@@ -8386,15 +8562,17 @@ var useRealtimeLineMetrics = ({
|
|
|
8386
8562
|
lineId,
|
|
8387
8563
|
date: urlDate,
|
|
8388
8564
|
shiftId: urlShiftId,
|
|
8389
|
-
onMetricsUpdate
|
|
8565
|
+
onMetricsUpdate,
|
|
8566
|
+
enabled
|
|
8390
8567
|
}) => {
|
|
8391
8568
|
const supabase = useSupabase();
|
|
8392
8569
|
const entityConfig = useEntityConfig();
|
|
8393
8570
|
useDatabaseConfig();
|
|
8394
8571
|
const dateTimeConfig = useDateTimeConfig();
|
|
8395
|
-
useShiftConfig();
|
|
8396
|
-
const
|
|
8397
|
-
const shiftConfig =
|
|
8572
|
+
const staticShiftConfig = useShiftConfig();
|
|
8573
|
+
const timezone = useAppTimezone();
|
|
8574
|
+
const { shiftConfig: dynamicShiftConfig, isLoading: isShiftConfigLoading } = useDynamicShiftConfig(lineId);
|
|
8575
|
+
const shiftConfig = dynamicShiftConfig || staticShiftConfig;
|
|
8398
8576
|
const [metrics2, setMetrics] = React23.useState(null);
|
|
8399
8577
|
const [lineDetails, setLineDetails] = React23.useState(null);
|
|
8400
8578
|
const [loading, setLoading] = React23.useState(true);
|
|
@@ -8405,16 +8583,16 @@ var useRealtimeLineMetrics = ({
|
|
|
8405
8583
|
const isFetchingRef = React23.useRef(false);
|
|
8406
8584
|
const channelsRef = React23.useRef([]);
|
|
8407
8585
|
const fetchTimeoutRef = React23.useRef(null);
|
|
8408
|
-
const
|
|
8586
|
+
const effectiveTimezone = timezone || dateTimeConfig.defaultTimezone || "Asia/Kolkata";
|
|
8587
|
+
const currentShift = React23.useMemo(() => getCurrentShift(effectiveTimezone, shiftConfig), [effectiveTimezone, shiftConfig]);
|
|
8409
8588
|
const shiftId = React23.useMemo(
|
|
8410
8589
|
() => urlShiftId !== void 0 ? urlShiftId : currentShift.shiftId,
|
|
8411
8590
|
[urlShiftId, currentShift.shiftId]
|
|
8412
8591
|
);
|
|
8413
|
-
const
|
|
8414
|
-
const date = React23.useMemo(() => urlDate || getOperationalDate(timezone || dateTimeConfig.defaultTimezone || "UTC"), [urlDate, timezone, dateTimeConfig.defaultTimezone]);
|
|
8592
|
+
const date = React23.useMemo(() => urlDate || getOperationalDate(effectiveTimezone), [urlDate, effectiveTimezone]);
|
|
8415
8593
|
const fetchData = React23.useCallback(async () => {
|
|
8416
8594
|
try {
|
|
8417
|
-
if (!lineIdRef.current || isFetchingRef.current) return;
|
|
8595
|
+
if (!lineIdRef.current || isFetchingRef.current || enabled === false) return;
|
|
8418
8596
|
isFetchingRef.current = true;
|
|
8419
8597
|
if (!initialized) {
|
|
8420
8598
|
setLoading(true);
|
|
@@ -8612,7 +8790,7 @@ var useRealtimeLineMetrics = ({
|
|
|
8612
8790
|
updateQueueRef.current = false;
|
|
8613
8791
|
isFetchingRef.current = false;
|
|
8614
8792
|
}
|
|
8615
|
-
}, [supabase, date, shiftId, urlShiftId, onMetricsUpdate, entityConfig, dateTimeConfig.defaultTimezone]);
|
|
8793
|
+
}, [supabase, date, shiftId, urlShiftId, onMetricsUpdate, entityConfig, dateTimeConfig.defaultTimezone, enabled, shiftConfig]);
|
|
8616
8794
|
const queueUpdate = React23.useCallback(() => {
|
|
8617
8795
|
console.log("[useRealtimeLineMetrics] Update queued, debouncing...");
|
|
8618
8796
|
if (fetchTimeoutRef.current) {
|
|
@@ -8694,13 +8872,27 @@ var useRealtimeLineMetrics = ({
|
|
|
8694
8872
|
});
|
|
8695
8873
|
channelsRef.current = [lineMetricsChannel, metricsChannel];
|
|
8696
8874
|
}, [supabase, queueUpdate, urlDate, shiftId, entityConfig, dateTimeConfig.defaultTimezone]);
|
|
8875
|
+
const prevShiftIdRef = React23.useRef(void 0);
|
|
8697
8876
|
React23.useEffect(() => {
|
|
8698
8877
|
if (!lineId) return;
|
|
8699
8878
|
lineIdRef.current = lineId;
|
|
8700
|
-
|
|
8879
|
+
const shouldFetch = !initialized && (!isShiftConfigLoading || enabled === false);
|
|
8880
|
+
const shiftIdChanged = prevShiftIdRef.current !== void 0 && prevShiftIdRef.current !== shiftId && !isShiftConfigLoading;
|
|
8881
|
+
if (shouldFetch || shiftIdChanged) {
|
|
8882
|
+
console.log("[useRealtimeLineMetrics] Fetching data:", {
|
|
8883
|
+
initialized,
|
|
8884
|
+
isShiftConfigLoading,
|
|
8885
|
+
enabled,
|
|
8886
|
+
shiftIdChanged,
|
|
8887
|
+
prevShiftId: prevShiftIdRef.current,
|
|
8888
|
+
currentShiftId: shiftId
|
|
8889
|
+
});
|
|
8701
8890
|
fetchData();
|
|
8702
8891
|
}
|
|
8703
8892
|
setupSubscriptions();
|
|
8893
|
+
if (!isShiftConfigLoading) {
|
|
8894
|
+
prevShiftIdRef.current = shiftId;
|
|
8895
|
+
}
|
|
8704
8896
|
return () => {
|
|
8705
8897
|
if (fetchTimeoutRef.current) {
|
|
8706
8898
|
clearTimeout(fetchTimeoutRef.current);
|
|
@@ -8715,7 +8907,7 @@ var useRealtimeLineMetrics = ({
|
|
|
8715
8907
|
});
|
|
8716
8908
|
}
|
|
8717
8909
|
};
|
|
8718
|
-
}, [lineId, fetchData, setupSubscriptions, initialized, supabase]);
|
|
8910
|
+
}, [lineId, fetchData, setupSubscriptions, initialized, supabase, isShiftConfigLoading, enabled, shiftId]);
|
|
8719
8911
|
React23.useEffect(() => {
|
|
8720
8912
|
setInitialized(false);
|
|
8721
8913
|
}, [lineId, date, shiftId]);
|
|
@@ -9433,14 +9625,20 @@ var useFactoryOverviewMetrics = (date, shiftId) => {
|
|
|
9433
9625
|
const supabase = useSupabase();
|
|
9434
9626
|
const entityConfig = useEntityConfig();
|
|
9435
9627
|
const dateTimeConfig = useDateTimeConfig();
|
|
9436
|
-
const
|
|
9628
|
+
const staticShiftConfig = useShiftConfig();
|
|
9629
|
+
const firstLineId = React23.useMemo(() => {
|
|
9630
|
+
const lineIds = getConfiguredLineIds(entityConfig);
|
|
9631
|
+
return lineIds[0];
|
|
9632
|
+
}, [entityConfig]);
|
|
9633
|
+
const { shiftConfig: dynamicShiftConfig, isLoading: isShiftConfigLoading } = useDynamicShiftConfig(firstLineId);
|
|
9634
|
+
const shiftConfig = dynamicShiftConfig || staticShiftConfig;
|
|
9437
9635
|
const [metrics2, setMetrics] = React23.useState(null);
|
|
9438
9636
|
const [isLoading, setIsLoading] = React23.useState(true);
|
|
9439
9637
|
const [error, setError] = React23.useState(null);
|
|
9440
9638
|
const isFetchingRef = React23.useRef(false);
|
|
9441
9639
|
const defaultTimezone = dateTimeConfig.defaultTimezone || "UTC";
|
|
9442
9640
|
const fetchMetrics = React23.useCallback(async () => {
|
|
9443
|
-
if (!supabase || isFetchingRef.current) return;
|
|
9641
|
+
if (!supabase || isFetchingRef.current || isShiftConfigLoading) return;
|
|
9444
9642
|
try {
|
|
9445
9643
|
isFetchingRef.current = true;
|
|
9446
9644
|
setIsLoading(true);
|
|
@@ -9489,7 +9687,7 @@ var useFactoryOverviewMetrics = (date, shiftId) => {
|
|
|
9489
9687
|
setIsLoading(false);
|
|
9490
9688
|
isFetchingRef.current = false;
|
|
9491
9689
|
}
|
|
9492
|
-
}, [supabase, date, shiftId, entityConfig, defaultTimezone, shiftConfig]);
|
|
9690
|
+
}, [supabase, date, shiftId, entityConfig, defaultTimezone, shiftConfig, isShiftConfigLoading]);
|
|
9493
9691
|
React23.useEffect(() => {
|
|
9494
9692
|
fetchMetrics();
|
|
9495
9693
|
}, [fetchMetrics]);
|
|
@@ -9895,15 +10093,25 @@ var useActiveBreaks = (lineIds) => {
|
|
|
9895
10093
|
}
|
|
9896
10094
|
return { elapsedMinutes, remainingMinutes };
|
|
9897
10095
|
};
|
|
9898
|
-
const
|
|
9899
|
-
const
|
|
9900
|
-
const
|
|
9901
|
-
if (
|
|
9902
|
-
return currentMinutes >=
|
|
10096
|
+
const isTimeInShift = (startTime, endTime, currentMinutes) => {
|
|
10097
|
+
const startMinutes = parseTimeToMinutes2(startTime);
|
|
10098
|
+
const endMinutes = parseTimeToMinutes2(endTime);
|
|
10099
|
+
if (endMinutes < startMinutes) {
|
|
10100
|
+
return currentMinutes >= startMinutes || currentMinutes < endMinutes;
|
|
9903
10101
|
} else {
|
|
9904
|
-
return currentMinutes >=
|
|
10102
|
+
return currentMinutes >= startMinutes && currentMinutes < endMinutes;
|
|
9905
10103
|
}
|
|
9906
10104
|
};
|
|
10105
|
+
const findActiveShift = (shifts, currentMinutes) => {
|
|
10106
|
+
for (const shift of shifts) {
|
|
10107
|
+
const startTime = shift.start_time || "00:00";
|
|
10108
|
+
const endTime = shift.end_time || "00:00";
|
|
10109
|
+
if (isTimeInShift(startTime, endTime, currentMinutes)) {
|
|
10110
|
+
return shift;
|
|
10111
|
+
}
|
|
10112
|
+
}
|
|
10113
|
+
return null;
|
|
10114
|
+
};
|
|
9907
10115
|
const checkActiveBreaks = React23.useCallback(async () => {
|
|
9908
10116
|
try {
|
|
9909
10117
|
setError(null);
|
|
@@ -9917,23 +10125,28 @@ var useActiveBreaks = (lineIds) => {
|
|
|
9917
10125
|
return;
|
|
9918
10126
|
}
|
|
9919
10127
|
const currentMinutes = getCurrentTimeInMinutes();
|
|
9920
|
-
const { data:
|
|
9921
|
-
|
|
9922
|
-
if (dayError || nightError) {
|
|
10128
|
+
const { data: allShifts, error: shiftsError } = await supabase.from("line_operating_hours").select("line_id, shift_id, shift_name, start_time, end_time, breaks").in("line_id", validLineIds).order("shift_id");
|
|
10129
|
+
if (shiftsError) {
|
|
9923
10130
|
throw new Error("Failed to fetch shift configurations");
|
|
9924
10131
|
}
|
|
9925
10132
|
const foundActiveBreaks = [];
|
|
10133
|
+
const shiftsByLine = /* @__PURE__ */ new Map();
|
|
10134
|
+
for (const shift of allShifts || []) {
|
|
10135
|
+
const lineShifts = shiftsByLine.get(shift.line_id) || [];
|
|
10136
|
+
lineShifts.push(shift);
|
|
10137
|
+
shiftsByLine.set(shift.line_id, lineShifts);
|
|
10138
|
+
}
|
|
9926
10139
|
for (const lineId of validLineIds) {
|
|
9927
|
-
const
|
|
9928
|
-
|
|
9929
|
-
|
|
9930
|
-
|
|
9931
|
-
|
|
9932
|
-
|
|
9933
|
-
|
|
9934
|
-
|
|
9935
|
-
|
|
9936
|
-
const shiftName =
|
|
10140
|
+
const lineShifts = shiftsByLine.get(lineId);
|
|
10141
|
+
if (!lineShifts || lineShifts.length === 0) continue;
|
|
10142
|
+
const activeShift = findActiveShift(lineShifts, currentMinutes);
|
|
10143
|
+
if (!activeShift) continue;
|
|
10144
|
+
const getDefaultShiftName = (shiftId) => {
|
|
10145
|
+
if (shiftId === 0) return "Day Shift";
|
|
10146
|
+
if (shiftId === 1) return "Night Shift";
|
|
10147
|
+
return `Shift ${shiftId}`;
|
|
10148
|
+
};
|
|
10149
|
+
const shiftName = activeShift.shift_name || getDefaultShiftName(activeShift.shift_id);
|
|
9937
10150
|
let breaks = [];
|
|
9938
10151
|
if (activeShift.breaks) {
|
|
9939
10152
|
if (Array.isArray(activeShift.breaks)) {
|
|
@@ -10008,8 +10221,12 @@ var useAllWorkspaceMetrics = (options) => {
|
|
|
10008
10221
|
const entityConfig = useEntityConfig();
|
|
10009
10222
|
const databaseConfig = useDatabaseConfig();
|
|
10010
10223
|
const dateTimeConfig = useDateTimeConfig();
|
|
10011
|
-
const
|
|
10224
|
+
const staticShiftConfig = useShiftConfig();
|
|
10012
10225
|
const timezone = useAppTimezone();
|
|
10226
|
+
const configuredLineIds = React23.useMemo(() => getConfiguredLineIds(entityConfig), [entityConfig]);
|
|
10227
|
+
const representativeLineId = options?.allowedLineIds?.[0] || configuredLineIds[0];
|
|
10228
|
+
const { shiftConfig: dynamicShiftConfig, isLoading: isShiftConfigLoading } = useDynamicShiftConfig(representativeLineId);
|
|
10229
|
+
const shiftConfig = dynamicShiftConfig || staticShiftConfig;
|
|
10013
10230
|
const supabase = useSupabase();
|
|
10014
10231
|
const [workspaces, setWorkspaces] = React23.useState([]);
|
|
10015
10232
|
const [loading, setLoading] = React23.useState(true);
|
|
@@ -10018,12 +10235,15 @@ var useAllWorkspaceMetrics = (options) => {
|
|
|
10018
10235
|
const fetchTimeoutRef = React23.useRef(null);
|
|
10019
10236
|
const isFetchingRef = React23.useRef(false);
|
|
10020
10237
|
const queryShiftId = React23.useMemo(() => {
|
|
10238
|
+
if (options?.initialShiftId !== void 0) {
|
|
10239
|
+
return options.initialShiftId;
|
|
10240
|
+
}
|
|
10021
10241
|
const currentShift = getCurrentShift(
|
|
10022
|
-
dateTimeConfig.defaultTimezone || "Asia/Kolkata",
|
|
10242
|
+
timezone || dateTimeConfig.defaultTimezone || "Asia/Kolkata",
|
|
10023
10243
|
shiftConfig
|
|
10024
10244
|
);
|
|
10025
|
-
return
|
|
10026
|
-
}, [options?.initialShiftId, dateTimeConfig.defaultTimezone, shiftConfig]);
|
|
10245
|
+
return currentShift.shiftId;
|
|
10246
|
+
}, [options?.initialShiftId, timezone, dateTimeConfig.defaultTimezone, shiftConfig]);
|
|
10027
10247
|
const queryDate = React23.useMemo(() => {
|
|
10028
10248
|
return options?.initialDate || getOperationalDate(timezone || dateTimeConfig.defaultTimezone || "UTC");
|
|
10029
10249
|
}, [options?.initialDate, timezone, dateTimeConfig.defaultTimezone]);
|
|
@@ -10035,7 +10255,7 @@ var useAllWorkspaceMetrics = (options) => {
|
|
|
10035
10255
|
}, [entityConfig.companyId]);
|
|
10036
10256
|
const schema = databaseConfig.schema ?? "public";
|
|
10037
10257
|
const fetchWorkspaceMetrics = React23.useCallback(async () => {
|
|
10038
|
-
if (isFetchingRef.current) {
|
|
10258
|
+
if (isFetchingRef.current || options?.enabled === false || isShiftConfigLoading) {
|
|
10039
10259
|
return;
|
|
10040
10260
|
}
|
|
10041
10261
|
isFetchingRef.current = true;
|
|
@@ -10045,9 +10265,9 @@ var useAllWorkspaceMetrics = (options) => {
|
|
|
10045
10265
|
setError(null);
|
|
10046
10266
|
try {
|
|
10047
10267
|
const allConfiguredLineIds = getConfiguredLineIds(entityConfig);
|
|
10048
|
-
const
|
|
10268
|
+
const configuredLineIds2 = options?.allowedLineIds ? allConfiguredLineIds.filter((id3) => options.allowedLineIds.includes(id3)) : allConfiguredLineIds;
|
|
10049
10269
|
let enabledWorkspaceIds = [];
|
|
10050
|
-
for (const lineId of
|
|
10270
|
+
for (const lineId of configuredLineIds2) {
|
|
10051
10271
|
const workspaces2 = await workspaceService.getWorkspaces(lineId);
|
|
10052
10272
|
const enabledIds = workspaces2.filter((ws) => ws.enable === true).map((ws) => ws.id);
|
|
10053
10273
|
enabledWorkspaceIds.push(...enabledIds);
|
|
@@ -10108,7 +10328,7 @@ var useAllWorkspaceMetrics = (options) => {
|
|
|
10108
10328
|
setLoading(false);
|
|
10109
10329
|
isFetchingRef.current = false;
|
|
10110
10330
|
}
|
|
10111
|
-
}, [queryDate, queryShiftId, metricsTable, supabase, entityConfig.companyId, entityConfig, options?.allowedLineIds]);
|
|
10331
|
+
}, [queryDate, queryShiftId, metricsTable, supabase, entityConfig.companyId, entityConfig, options?.allowedLineIds, options?.enabled, isShiftConfigLoading]);
|
|
10112
10332
|
React23.useEffect(() => {
|
|
10113
10333
|
if (!initialized) {
|
|
10114
10334
|
fetchWorkspaceMetrics();
|
|
@@ -10587,7 +10807,7 @@ function useClipTypes() {
|
|
|
10587
10807
|
refresh: fetchClipTypes
|
|
10588
10808
|
};
|
|
10589
10809
|
}
|
|
10590
|
-
function useClipTypesWithCounts(workspaceId, date, shiftId, totalOutput) {
|
|
10810
|
+
function useClipTypesWithCounts(workspaceId, date, shiftId, totalOutput, options) {
|
|
10591
10811
|
const { clipTypes, isLoading: typesLoading, error: typesError, refresh } = useClipTypes();
|
|
10592
10812
|
const [counts, setCounts] = React23.useState({});
|
|
10593
10813
|
const [countsLoading, setCountsLoading] = React23.useState(false);
|
|
@@ -10599,8 +10819,13 @@ function useClipTypesWithCounts(workspaceId, date, shiftId, totalOutput) {
|
|
|
10599
10819
|
workspaceId,
|
|
10600
10820
|
date,
|
|
10601
10821
|
shiftId,
|
|
10602
|
-
shiftIdType: typeof shiftId
|
|
10822
|
+
shiftIdType: typeof shiftId,
|
|
10823
|
+
enabled: options?.enabled
|
|
10603
10824
|
});
|
|
10825
|
+
if (!options?.enabled) {
|
|
10826
|
+
console.log("[useClipTypesWithCounts] Skipping counts fetch - disabled");
|
|
10827
|
+
return;
|
|
10828
|
+
}
|
|
10604
10829
|
if (!s3Service || !workspaceId || !date || shiftId === void 0) {
|
|
10605
10830
|
console.log("[useClipTypesWithCounts] Skipping counts fetch - missing dependencies");
|
|
10606
10831
|
return;
|
|
@@ -10624,7 +10849,7 @@ function useClipTypesWithCounts(workspaceId, date, shiftId, totalOutput) {
|
|
|
10624
10849
|
}
|
|
10625
10850
|
};
|
|
10626
10851
|
fetchCounts();
|
|
10627
|
-
}, [s3Service, workspaceId, date, shiftId, totalOutput]);
|
|
10852
|
+
}, [s3Service, workspaceId, date, shiftId, totalOutput, options?.enabled]);
|
|
10628
10853
|
return {
|
|
10629
10854
|
clipTypes: clipTypes.map((type) => ({
|
|
10630
10855
|
...type,
|
|
@@ -11034,15 +11259,48 @@ var useWorkspaceUptimeTimeline = (options) => {
|
|
|
11034
11259
|
workspaceId,
|
|
11035
11260
|
companyId,
|
|
11036
11261
|
enabled = true,
|
|
11037
|
-
refreshInterval
|
|
11262
|
+
refreshInterval,
|
|
11263
|
+
lineId,
|
|
11264
|
+
shiftConfig: passedShiftConfig,
|
|
11265
|
+
timezone: passedTimezone
|
|
11038
11266
|
} = options;
|
|
11267
|
+
const { shiftConfig: dynamicShiftConfig, isLoading: isShiftConfigLoading } = useDynamicShiftConfig(lineId);
|
|
11268
|
+
const appTimezone = useAppTimezone();
|
|
11269
|
+
const shiftConfigPending = !passedShiftConfig && (!lineId || isShiftConfigLoading || !dynamicShiftConfig);
|
|
11270
|
+
const effectiveShiftConfig = passedShiftConfig ?? (shiftConfigPending ? void 0 : dynamicShiftConfig);
|
|
11271
|
+
const effectiveTimezone = passedTimezone || appTimezone || effectiveShiftConfig?.timezone || "UTC";
|
|
11272
|
+
if (process.env.NODE_ENV === "development") {
|
|
11273
|
+
console.log(`[useWorkspaceUptimeTimeline] Shift config state:`, {
|
|
11274
|
+
lineId,
|
|
11275
|
+
hasPassedConfig: !!passedShiftConfig,
|
|
11276
|
+
isShiftConfigLoading,
|
|
11277
|
+
hasDynamicConfig: !!dynamicShiftConfig,
|
|
11278
|
+
shiftConfigPending,
|
|
11279
|
+
hasEffectiveConfig: !!effectiveShiftConfig
|
|
11280
|
+
});
|
|
11281
|
+
}
|
|
11039
11282
|
const [timeline, setTimeline] = React23.useState(null);
|
|
11040
11283
|
const [loading, setLoading] = React23.useState(false);
|
|
11041
11284
|
const [error, setError] = React23.useState(null);
|
|
11042
11285
|
const isFetchingRef = React23.useRef(false);
|
|
11043
11286
|
const intervalRef = React23.useRef(null);
|
|
11287
|
+
React23.useEffect(() => {
|
|
11288
|
+
setTimeline(null);
|
|
11289
|
+
setError(null);
|
|
11290
|
+
setLoading(enabled && Boolean(workspaceId && companyId));
|
|
11291
|
+
}, [workspaceId, companyId, lineId, enabled]);
|
|
11044
11292
|
const fetchTimeline = React23.useCallback(async () => {
|
|
11045
11293
|
if (!enabled) return;
|
|
11294
|
+
if (shiftConfigPending) {
|
|
11295
|
+
console.log("[useWorkspaceUptimeTimeline] \u23F3 Waiting for shift config to load before fetching");
|
|
11296
|
+
setLoading(true);
|
|
11297
|
+
return;
|
|
11298
|
+
}
|
|
11299
|
+
if (!effectiveShiftConfig) {
|
|
11300
|
+
console.warn("[useWorkspaceUptimeTimeline] \u26A0\uFE0F No effective shift config available, cannot fetch");
|
|
11301
|
+
setLoading(false);
|
|
11302
|
+
return;
|
|
11303
|
+
}
|
|
11046
11304
|
if (!workspaceId || !companyId) {
|
|
11047
11305
|
setTimeline(null);
|
|
11048
11306
|
return;
|
|
@@ -11052,9 +11310,16 @@ var useWorkspaceUptimeTimeline = (options) => {
|
|
|
11052
11310
|
isFetchingRef.current = true;
|
|
11053
11311
|
setLoading(true);
|
|
11054
11312
|
setError(null);
|
|
11313
|
+
console.log("[useWorkspaceUptimeTimeline] \u{1F680} Fetching timeline with shift config:", {
|
|
11314
|
+
workspaceId,
|
|
11315
|
+
shiftId: effectiveShiftConfig?.shifts?.[0]?.shiftId,
|
|
11316
|
+
timezone: effectiveTimezone
|
|
11317
|
+
});
|
|
11055
11318
|
const data = await workspaceHealthService.getWorkspaceUptimeTimeline(
|
|
11056
11319
|
workspaceId,
|
|
11057
|
-
companyId
|
|
11320
|
+
companyId,
|
|
11321
|
+
effectiveShiftConfig,
|
|
11322
|
+
effectiveTimezone
|
|
11058
11323
|
);
|
|
11059
11324
|
setTimeline(data);
|
|
11060
11325
|
} catch (err) {
|
|
@@ -11064,7 +11329,7 @@ var useWorkspaceUptimeTimeline = (options) => {
|
|
|
11064
11329
|
setLoading(false);
|
|
11065
11330
|
isFetchingRef.current = false;
|
|
11066
11331
|
}
|
|
11067
|
-
}, [enabled, workspaceId, companyId]);
|
|
11332
|
+
}, [enabled, workspaceId, companyId, effectiveShiftConfig, effectiveTimezone, shiftConfigPending]);
|
|
11068
11333
|
React23.useEffect(() => {
|
|
11069
11334
|
fetchTimeline();
|
|
11070
11335
|
}, [fetchTimeline]);
|
|
@@ -11083,7 +11348,7 @@ var useWorkspaceUptimeTimeline = (options) => {
|
|
|
11083
11348
|
}, [refreshInterval, enabled, fetchTimeline]);
|
|
11084
11349
|
return {
|
|
11085
11350
|
timeline,
|
|
11086
|
-
loading,
|
|
11351
|
+
loading: loading || shiftConfigPending,
|
|
11087
11352
|
error,
|
|
11088
11353
|
refetch: fetchTimeline
|
|
11089
11354
|
};
|
|
@@ -26354,26 +26619,62 @@ var VideoControls = ({
|
|
|
26354
26619
|
const [isHoveringProgressBar, setIsHoveringProgressBar] = React23.useState(false);
|
|
26355
26620
|
const [showSpeedMenu, setShowSpeedMenu] = React23.useState(false);
|
|
26356
26621
|
const speedMenuRef = React23.useRef(null);
|
|
26622
|
+
const progressTrackRef = React23.useRef(null);
|
|
26623
|
+
const activePointerIdRef = React23.useRef(null);
|
|
26357
26624
|
const progressColor = "#4b5563";
|
|
26358
26625
|
const controlsVisible = showControls || controlsPinned;
|
|
26626
|
+
const isDraggingRef = React23.useRef(false);
|
|
26359
26627
|
const getPercentage = (current, total) => {
|
|
26360
26628
|
if (!total || total === 0) return 0;
|
|
26361
26629
|
return Math.min(Math.max(current / total * 100, 0), 100);
|
|
26362
26630
|
};
|
|
26363
26631
|
const handleSeekChange = (e) => {
|
|
26364
|
-
const newTime = parseFloat(e.
|
|
26632
|
+
const newTime = parseFloat(e.currentTarget.value);
|
|
26365
26633
|
setDragTime(newTime);
|
|
26366
26634
|
onSeek(newTime);
|
|
26367
26635
|
};
|
|
26368
26636
|
const handleSeekStart = () => {
|
|
26369
26637
|
setIsDragging(true);
|
|
26638
|
+
isDraggingRef.current = true;
|
|
26370
26639
|
setDragTime(currentTime);
|
|
26371
26640
|
onSeekStart?.();
|
|
26372
26641
|
};
|
|
26373
26642
|
const handleSeekEnd = () => {
|
|
26374
26643
|
setIsDragging(false);
|
|
26644
|
+
isDraggingRef.current = false;
|
|
26375
26645
|
onSeekEnd?.();
|
|
26376
26646
|
};
|
|
26647
|
+
const updateTimeFromClientX = React23.useCallback((clientX) => {
|
|
26648
|
+
if (!progressTrackRef.current) return;
|
|
26649
|
+
const rect = progressTrackRef.current.getBoundingClientRect();
|
|
26650
|
+
if (rect.width === 0 || duration === 0) return;
|
|
26651
|
+
const pct = Math.min(Math.max((clientX - rect.left) / rect.width, 0), 1);
|
|
26652
|
+
const newTime = pct * duration;
|
|
26653
|
+
setDragTime(newTime);
|
|
26654
|
+
onSeek(newTime);
|
|
26655
|
+
}, [duration, onSeek]);
|
|
26656
|
+
const handlePointerDown = React23.useCallback((e) => {
|
|
26657
|
+
if (duration === 0) return;
|
|
26658
|
+
e.preventDefault();
|
|
26659
|
+
activePointerIdRef.current = e.pointerId;
|
|
26660
|
+
handleSeekStart();
|
|
26661
|
+
updateTimeFromClientX(e.clientX);
|
|
26662
|
+
const handleMove = (ev) => {
|
|
26663
|
+
if (ev.pointerId !== activePointerIdRef.current) return;
|
|
26664
|
+
updateTimeFromClientX(ev.clientX);
|
|
26665
|
+
};
|
|
26666
|
+
const handleUp = (ev) => {
|
|
26667
|
+
if (ev.pointerId !== activePointerIdRef.current) return;
|
|
26668
|
+
activePointerIdRef.current = null;
|
|
26669
|
+
window.removeEventListener("pointermove", handleMove);
|
|
26670
|
+
window.removeEventListener("pointerup", handleUp);
|
|
26671
|
+
window.removeEventListener("pointercancel", handleUp);
|
|
26672
|
+
handleSeekEnd();
|
|
26673
|
+
};
|
|
26674
|
+
window.addEventListener("pointermove", handleMove);
|
|
26675
|
+
window.addEventListener("pointerup", handleUp);
|
|
26676
|
+
window.addEventListener("pointercancel", handleUp);
|
|
26677
|
+
}, [duration, handleSeekStart, handleSeekEnd, updateTimeFromClientX]);
|
|
26377
26678
|
React23.useEffect(() => {
|
|
26378
26679
|
const handleClickOutside = (event) => {
|
|
26379
26680
|
if (speedMenuRef.current && !speedMenuRef.current.contains(event.target)) {
|
|
@@ -26385,6 +26686,21 @@ var VideoControls = ({
|
|
|
26385
26686
|
document.removeEventListener("mousedown", handleClickOutside);
|
|
26386
26687
|
};
|
|
26387
26688
|
}, []);
|
|
26689
|
+
React23.useEffect(() => {
|
|
26690
|
+
const cancelDrag = () => {
|
|
26691
|
+
if (isDraggingRef.current) {
|
|
26692
|
+
handleSeekEnd();
|
|
26693
|
+
}
|
|
26694
|
+
};
|
|
26695
|
+
window.addEventListener("mouseup", cancelDrag);
|
|
26696
|
+
window.addEventListener("touchend", cancelDrag);
|
|
26697
|
+
window.addEventListener("touchcancel", cancelDrag);
|
|
26698
|
+
return () => {
|
|
26699
|
+
window.removeEventListener("mouseup", cancelDrag);
|
|
26700
|
+
window.removeEventListener("touchend", cancelDrag);
|
|
26701
|
+
window.removeEventListener("touchcancel", cancelDrag);
|
|
26702
|
+
};
|
|
26703
|
+
}, []);
|
|
26388
26704
|
const displayTime = isDragging ? dragTime : currentTime;
|
|
26389
26705
|
const progressPercent = getPercentage(displayTime, duration);
|
|
26390
26706
|
const bufferedPercent = getPercentage(buffered, duration);
|
|
@@ -26397,11 +26713,13 @@ var VideoControls = ({
|
|
|
26397
26713
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
26398
26714
|
"div",
|
|
26399
26715
|
{
|
|
26716
|
+
ref: progressTrackRef,
|
|
26400
26717
|
className: "relative h-1 mb-4 group cursor-pointer",
|
|
26401
26718
|
onMouseEnter: () => setIsHoveringProgressBar(true),
|
|
26402
26719
|
onMouseLeave: () => setIsHoveringProgressBar(false),
|
|
26720
|
+
onPointerDown: handlePointerDown,
|
|
26403
26721
|
children: [
|
|
26404
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute -top-
|
|
26722
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute -top-4 -bottom-4 left-0 right-0 z-20" }),
|
|
26405
26723
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute top-0 left-0 right-0 bottom-0 bg-white/20 rounded-full overflow-hidden z-0", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
26406
26724
|
"div",
|
|
26407
26725
|
{
|
|
@@ -26432,11 +26750,13 @@ var VideoControls = ({
|
|
|
26432
26750
|
step: "0.1",
|
|
26433
26751
|
value: displayTime,
|
|
26434
26752
|
onChange: handleSeekChange,
|
|
26753
|
+
onInput: handleSeekChange,
|
|
26435
26754
|
onMouseDown: handleSeekStart,
|
|
26436
26755
|
onMouseUp: handleSeekEnd,
|
|
26437
26756
|
onTouchStart: handleSeekStart,
|
|
26438
26757
|
onTouchEnd: handleSeekEnd,
|
|
26439
|
-
|
|
26758
|
+
onPointerDown: handlePointerDown,
|
|
26759
|
+
className: "absolute left-0 right-0 top-[-12px] bottom-[-12px] w-full h-auto opacity-0 cursor-pointer z-30 margin-0 padding-0"
|
|
26440
26760
|
}
|
|
26441
26761
|
)
|
|
26442
26762
|
]
|
|
@@ -26659,6 +26979,7 @@ var HlsVideoPlayer = React23.forwardRef(({
|
|
|
26659
26979
|
const [buffered, setBuffered] = React23.useState(0);
|
|
26660
26980
|
const [playbackRate, setPlaybackRate] = React23.useState(1);
|
|
26661
26981
|
const userSeekingRef = React23.useRef(false);
|
|
26982
|
+
const wasPlayingRef = React23.useRef(false);
|
|
26662
26983
|
const controlsTimeoutRef = React23.useRef(null);
|
|
26663
26984
|
const eventCallbacksRef = React23.useRef({
|
|
26664
26985
|
onReady,
|
|
@@ -26901,10 +27222,6 @@ var HlsVideoPlayer = React23.forwardRef(({
|
|
|
26901
27222
|
eventCallbacksRef.current.onPlay?.(player);
|
|
26902
27223
|
};
|
|
26903
27224
|
const handlePause = () => {
|
|
26904
|
-
if (userSeekingRef.current && videoRef.current) {
|
|
26905
|
-
videoRef.current.play().catch((err) => console.warn("Auto-resume after seek pause failed:", err));
|
|
26906
|
-
return;
|
|
26907
|
-
}
|
|
26908
27225
|
setIsPlaying(false);
|
|
26909
27226
|
eventCallbacksRef.current.onPause?.(player);
|
|
26910
27227
|
};
|
|
@@ -27118,14 +27435,17 @@ var HlsVideoPlayer = React23.forwardRef(({
|
|
|
27118
27435
|
const handleSeek = React23.useCallback((time2) => {
|
|
27119
27436
|
if (videoRef.current) {
|
|
27120
27437
|
videoRef.current.currentTime = time2;
|
|
27121
|
-
videoRef.current.play().catch((err) => console.warn("Resume playback failed during seek:", err));
|
|
27122
27438
|
}
|
|
27123
27439
|
}, []);
|
|
27124
27440
|
const handleSeekStart = React23.useCallback(() => {
|
|
27441
|
+
wasPlayingRef.current = !videoRef.current?.paused;
|
|
27442
|
+
if (videoRef.current && !videoRef.current.paused) {
|
|
27443
|
+
videoRef.current.pause();
|
|
27444
|
+
}
|
|
27125
27445
|
userSeekingRef.current = true;
|
|
27126
27446
|
}, []);
|
|
27127
27447
|
const handleSeekEnd = React23.useCallback(() => {
|
|
27128
|
-
if (videoRef.current) {
|
|
27448
|
+
if (videoRef.current && wasPlayingRef.current) {
|
|
27129
27449
|
videoRef.current.play().catch((err) => console.warn("Resume playback failed after seek:", err));
|
|
27130
27450
|
}
|
|
27131
27451
|
}, []);
|
|
@@ -27267,6 +27587,7 @@ var CroppedHlsVideoPlayer = React23.forwardRef(({
|
|
|
27267
27587
|
const [playbackRate, setPlaybackRate] = React23.useState(1);
|
|
27268
27588
|
const controlsTimeoutRef = React23.useRef(null);
|
|
27269
27589
|
const userSeekingRef = React23.useRef(false);
|
|
27590
|
+
const wasPlayingRef = React23.useRef(false);
|
|
27270
27591
|
const [controlsPinned, setControlsPinned] = React23.useState(false);
|
|
27271
27592
|
const stopCanvasRendering = React23.useCallback(() => {
|
|
27272
27593
|
if (animationFrameRef.current) {
|
|
@@ -27406,7 +27727,7 @@ var CroppedHlsVideoPlayer = React23.forwardRef(({
|
|
|
27406
27727
|
}, [crop, renderFrameToCanvas, onPlayProp]);
|
|
27407
27728
|
const handleVideoPause = React23.useCallback((player) => {
|
|
27408
27729
|
console.log("[CroppedHlsVideoPlayer] Video paused, stopping canvas rendering (keeping last frame)");
|
|
27409
|
-
if (userSeekingRef.current && hiddenVideoRef.current) {
|
|
27730
|
+
if (userSeekingRef.current && wasPlayingRef.current && hiddenVideoRef.current) {
|
|
27410
27731
|
hiddenVideoRef.current.play()?.catch(() => {
|
|
27411
27732
|
});
|
|
27412
27733
|
return;
|
|
@@ -27423,6 +27744,7 @@ var CroppedHlsVideoPlayer = React23.forwardRef(({
|
|
|
27423
27744
|
setIsProcessing(false);
|
|
27424
27745
|
setIsPlaying(false);
|
|
27425
27746
|
userSeekingRef.current = false;
|
|
27747
|
+
wasPlayingRef.current = false;
|
|
27426
27748
|
onEndedProp?.(player);
|
|
27427
27749
|
}, [stopCanvasRendering, onEndedProp]);
|
|
27428
27750
|
const handleSeeking = React23.useCallback((player) => {
|
|
@@ -27438,6 +27760,7 @@ var CroppedHlsVideoPlayer = React23.forwardRef(({
|
|
|
27438
27760
|
hiddenVideoRef.current?.play()?.catch(() => {
|
|
27439
27761
|
});
|
|
27440
27762
|
userSeekingRef.current = false;
|
|
27763
|
+
wasPlayingRef.current = false;
|
|
27441
27764
|
if (crop) {
|
|
27442
27765
|
renderFrameToCanvas();
|
|
27443
27766
|
}
|
|
@@ -27534,20 +27857,34 @@ var CroppedHlsVideoPlayer = React23.forwardRef(({
|
|
|
27534
27857
|
const handleSeek = React23.useCallback((time2) => {
|
|
27535
27858
|
if (hiddenVideoRef.current) {
|
|
27536
27859
|
hiddenVideoRef.current.currentTime(time2);
|
|
27537
|
-
hiddenVideoRef.current.play()?.catch(() => {
|
|
27538
|
-
});
|
|
27539
27860
|
setTimeout(() => renderFrameToCanvas(), 50);
|
|
27861
|
+
userSeekingRef.current = true;
|
|
27540
27862
|
}
|
|
27541
27863
|
}, [renderFrameToCanvas]);
|
|
27542
27864
|
const handleSeekStart = React23.useCallback(() => {
|
|
27865
|
+
const videoPaused = hiddenVideoRef.current?.video?.paused ?? hiddenVideoRef.current?.paused();
|
|
27866
|
+
wasPlayingRef.current = videoPaused === false;
|
|
27867
|
+
if (hiddenVideoRef.current && videoPaused === false) {
|
|
27868
|
+
hiddenVideoRef.current.pause();
|
|
27869
|
+
}
|
|
27543
27870
|
userSeekingRef.current = true;
|
|
27544
27871
|
}, []);
|
|
27545
27872
|
const handleSeekEnd = React23.useCallback(() => {
|
|
27546
|
-
|
|
27547
|
-
|
|
27873
|
+
const shouldResume = wasPlayingRef.current;
|
|
27874
|
+
userSeekingRef.current = shouldResume;
|
|
27875
|
+
if (hiddenVideoRef.current && shouldResume) {
|
|
27876
|
+
hiddenVideoRef.current.play()?.then(() => {
|
|
27877
|
+
if (crop) {
|
|
27878
|
+
setIsProcessing(true);
|
|
27879
|
+
renderFrameToCanvas();
|
|
27880
|
+
}
|
|
27881
|
+
}).catch(() => {
|
|
27548
27882
|
});
|
|
27549
27883
|
}
|
|
27550
|
-
|
|
27884
|
+
if (!shouldResume) {
|
|
27885
|
+
userSeekingRef.current = false;
|
|
27886
|
+
}
|
|
27887
|
+
}, [crop, renderFrameToCanvas]);
|
|
27551
27888
|
const handlePlaybackRateChange = React23.useCallback((rate) => {
|
|
27552
27889
|
if (hiddenVideoRef.current) {
|
|
27553
27890
|
hiddenVideoRef.current.playbackRate(rate);
|
|
@@ -29838,6 +30175,7 @@ var BottlenecksContent = ({
|
|
|
29838
30175
|
workspaceId,
|
|
29839
30176
|
workspaceName,
|
|
29840
30177
|
date,
|
|
30178
|
+
lineId,
|
|
29841
30179
|
shift,
|
|
29842
30180
|
className,
|
|
29843
30181
|
totalOutput,
|
|
@@ -29848,27 +30186,36 @@ var BottlenecksContent = ({
|
|
|
29848
30186
|
console.log("\u{1F3AB} [BottlenecksContent] Rendered with ticketId:", ticketId || "NONE", "workspaceId:", workspaceId, "date:", date, "shift:", shift);
|
|
29849
30187
|
const dashboardConfig = useDashboardConfig();
|
|
29850
30188
|
const timezone = useAppTimezone();
|
|
29851
|
-
const { shiftConfig } = useDynamicShiftConfig(
|
|
29852
|
-
const effectiveShift = React23.useMemo(() => {
|
|
29853
|
-
if (shift !== void 0 && shift !== null) {
|
|
30189
|
+
const { shiftConfig, isLoading: isShiftConfigLoading } = useDynamicShiftConfig(lineId);
|
|
30190
|
+
const { effectiveShift, effectiveDate } = React23.useMemo(() => {
|
|
30191
|
+
if (shift !== void 0 && shift !== null && date) {
|
|
29854
30192
|
const shiftStr = shift.toString();
|
|
29855
|
-
console.log(`[BottlenecksContent] Using
|
|
29856
|
-
return shiftStr;
|
|
30193
|
+
console.log(`[BottlenecksContent] Using explicit date/shift: ${date}, shift ${shiftStr}`);
|
|
30194
|
+
return { effectiveShift: shiftStr, effectiveDate: date };
|
|
29857
30195
|
}
|
|
29858
|
-
if (
|
|
29859
|
-
console.log(
|
|
29860
|
-
return
|
|
29861
|
-
}
|
|
29862
|
-
|
|
29863
|
-
|
|
29864
|
-
|
|
29865
|
-
|
|
29866
|
-
|
|
29867
|
-
);
|
|
29868
|
-
|
|
29869
|
-
|
|
30196
|
+
if ((shift === void 0 || shift === null) && isShiftConfigLoading) {
|
|
30197
|
+
console.log("[BottlenecksContent] Waiting for shift config before determining effective date/shift");
|
|
30198
|
+
return { effectiveShift: null, effectiveDate: null };
|
|
30199
|
+
}
|
|
30200
|
+
const currentShift = getCurrentShift(
|
|
30201
|
+
timezone,
|
|
30202
|
+
shiftConfig
|
|
30203
|
+
);
|
|
30204
|
+
if (shift !== void 0 && shift !== null) {
|
|
30205
|
+
const shiftStr = shift.toString();
|
|
30206
|
+
return {
|
|
30207
|
+
effectiveShift: shiftStr,
|
|
30208
|
+
effectiveDate: date || currentShift.date
|
|
30209
|
+
};
|
|
29870
30210
|
}
|
|
29871
|
-
|
|
30211
|
+
return {
|
|
30212
|
+
effectiveShift: currentShift.shiftId.toString(),
|
|
30213
|
+
effectiveDate: date || currentShift.date
|
|
30214
|
+
};
|
|
30215
|
+
}, [shift, date, timezone, shiftConfig, isShiftConfigLoading]);
|
|
30216
|
+
const isEffectiveShiftReady = Boolean(effectiveShift && effectiveDate);
|
|
30217
|
+
const effectiveDateString = effectiveDate || "";
|
|
30218
|
+
const effectiveShiftId = effectiveShift ?? "";
|
|
29872
30219
|
const { crop: workspaceCrop} = useWorkspaceCrop(workspaceId);
|
|
29873
30220
|
const { metrics: workspaceMetrics } = useWorkspaceDetailedMetrics(
|
|
29874
30221
|
workspaceId,
|
|
@@ -29954,9 +30301,9 @@ var BottlenecksContent = ({
|
|
|
29954
30301
|
clearNotification
|
|
29955
30302
|
} = useClipsRealtimeUpdates({
|
|
29956
30303
|
workspaceId,
|
|
29957
|
-
date:
|
|
29958
|
-
shiftId:
|
|
29959
|
-
enabled:
|
|
30304
|
+
date: effectiveDateString,
|
|
30305
|
+
shiftId: effectiveShiftId,
|
|
30306
|
+
enabled: isEffectiveShiftReady,
|
|
29960
30307
|
// Supabase implementation
|
|
29961
30308
|
onNewClips: (notification) => {
|
|
29962
30309
|
console.log(`[BottlenecksContent] New clips detected:`, notification);
|
|
@@ -29997,10 +30344,11 @@ var BottlenecksContent = ({
|
|
|
29997
30344
|
counts: dynamicCounts
|
|
29998
30345
|
} = useClipTypesWithCounts(
|
|
29999
30346
|
workspaceId,
|
|
30000
|
-
|
|
30001
|
-
|
|
30347
|
+
effectiveDateString,
|
|
30348
|
+
effectiveShiftId,
|
|
30002
30349
|
// Use same shift as video loading for consistency
|
|
30003
|
-
totalOutput
|
|
30350
|
+
totalOutput,
|
|
30351
|
+
{ enabled: isEffectiveShiftReady }
|
|
30004
30352
|
);
|
|
30005
30353
|
console.log("[BottlenecksContent] Clip types data:", {
|
|
30006
30354
|
clipTypes,
|
|
@@ -30009,8 +30357,8 @@ var BottlenecksContent = ({
|
|
|
30009
30357
|
clipTypesError,
|
|
30010
30358
|
dynamicCounts,
|
|
30011
30359
|
workspaceId,
|
|
30012
|
-
date:
|
|
30013
|
-
shift:
|
|
30360
|
+
date: effectiveDateString,
|
|
30361
|
+
shift: effectiveShiftId || "0"
|
|
30014
30362
|
});
|
|
30015
30363
|
React23.useEffect(() => {
|
|
30016
30364
|
if (clipTypes.length > 0) {
|
|
@@ -30051,16 +30399,16 @@ var BottlenecksContent = ({
|
|
|
30051
30399
|
return { ...clipCounts, ...dynamicCounts };
|
|
30052
30400
|
}, [clipCounts, dynamicCounts]);
|
|
30053
30401
|
const fetchClipCounts = React23.useCallback(async () => {
|
|
30054
|
-
if (!workspaceId || !s3ClipsService || !dashboardConfig?.s3Config || !isMountedRef.current) return;
|
|
30055
|
-
const operationKey = `fetchClipCounts:${workspaceId}:${
|
|
30402
|
+
if (!workspaceId || !s3ClipsService || !dashboardConfig?.s3Config || !isMountedRef.current || !isEffectiveShiftReady) return;
|
|
30403
|
+
const operationKey = `fetchClipCounts:${workspaceId}:${effectiveDateString}:${effectiveShiftId}`;
|
|
30056
30404
|
if (fetchInProgressRef.current.has(operationKey)) {
|
|
30057
30405
|
console.log(`[BottlenecksContent] Fetch clip counts already in progress for ${operationKey}`);
|
|
30058
30406
|
return;
|
|
30059
30407
|
}
|
|
30060
30408
|
fetchInProgressRef.current.add(operationKey);
|
|
30061
30409
|
try {
|
|
30062
|
-
const operationalDate =
|
|
30063
|
-
const shiftStr =
|
|
30410
|
+
const operationalDate = effectiveDateString;
|
|
30411
|
+
const shiftStr = effectiveShiftId;
|
|
30064
30412
|
console.log(`[BottlenecksContent] Fetching clip counts directly with params:`, {
|
|
30065
30413
|
workspaceId,
|
|
30066
30414
|
operationalDate,
|
|
@@ -30095,12 +30443,12 @@ var BottlenecksContent = ({
|
|
|
30095
30443
|
} finally {
|
|
30096
30444
|
fetchInProgressRef.current.delete(operationKey);
|
|
30097
30445
|
}
|
|
30098
|
-
}, [workspaceId,
|
|
30446
|
+
}, [workspaceId, effectiveDateString, s3ClipsService, effectiveShiftId, dashboardConfig, updateClipCounts, isEffectiveShiftReady, totalOutput]);
|
|
30099
30447
|
const loadingCategoryRef = React23.useRef(null);
|
|
30100
30448
|
const loadFirstVideoForCategory = React23.useCallback(async (category) => {
|
|
30101
|
-
if (!workspaceId || !s3ClipsService || !isMountedRef.current) return;
|
|
30449
|
+
if (!workspaceId || !s3ClipsService || !isMountedRef.current || !isEffectiveShiftReady) return;
|
|
30102
30450
|
const targetCategory = category || activeFilterRef.current;
|
|
30103
|
-
const operationKey = `loadFirstVideo:${targetCategory}`;
|
|
30451
|
+
const operationKey = `loadFirstVideo:${targetCategory}:${effectiveDateString}:${effectiveShiftId}`;
|
|
30104
30452
|
if (loadingCategoryRef.current === targetCategory || fetchInProgressRef.current.has(operationKey)) {
|
|
30105
30453
|
console.log(`[BottlenecksContent] Load first video already in progress for ${targetCategory}`);
|
|
30106
30454
|
return;
|
|
@@ -30111,8 +30459,8 @@ var BottlenecksContent = ({
|
|
|
30111
30459
|
setError(null);
|
|
30112
30460
|
}
|
|
30113
30461
|
try {
|
|
30114
|
-
const operationalDate =
|
|
30115
|
-
const shiftStr =
|
|
30462
|
+
const operationalDate = effectiveDateString;
|
|
30463
|
+
const shiftStr = effectiveShiftId;
|
|
30116
30464
|
console.log(`[BottlenecksContent] Loading first video for category: ${targetCategory}`);
|
|
30117
30465
|
try {
|
|
30118
30466
|
const firstVideo = await s3ClipsService.getFirstClipForCategory(
|
|
@@ -30185,7 +30533,7 @@ var BottlenecksContent = ({
|
|
|
30185
30533
|
loadingCategoryRef.current = null;
|
|
30186
30534
|
fetchInProgressRef.current.delete(operationKey);
|
|
30187
30535
|
}
|
|
30188
|
-
}, [workspaceId,
|
|
30536
|
+
}, [workspaceId, effectiveDateString, s3ClipsService, mergedCounts, effectiveShiftId, isEffectiveShiftReady]);
|
|
30189
30537
|
const handleRefreshClips = React23.useCallback(async () => {
|
|
30190
30538
|
console.log("[BottlenecksContent] Refreshing clips after new additions");
|
|
30191
30539
|
acknowledgeNewClips();
|
|
@@ -30196,10 +30544,10 @@ var BottlenecksContent = ({
|
|
|
30196
30544
|
}
|
|
30197
30545
|
}, [acknowledgeNewClips, fetchClipCounts, activeFilter, mergedCounts, loadFirstVideoForCategory, invalidateMetadataCache]);
|
|
30198
30546
|
React23.useEffect(() => {
|
|
30199
|
-
if (s3ClipsService) {
|
|
30547
|
+
if (s3ClipsService && isEffectiveShiftReady) {
|
|
30200
30548
|
fetchClipCounts();
|
|
30201
30549
|
}
|
|
30202
|
-
}, [workspaceId,
|
|
30550
|
+
}, [workspaceId, effectiveDateString, effectiveShiftId, s3ClipsService, fetchClipCounts, isEffectiveShiftReady]);
|
|
30203
30551
|
const getAuthToken4 = React23.useCallback(async () => {
|
|
30204
30552
|
try {
|
|
30205
30553
|
const { createClient: createClient5 } = await import('@supabase/supabase-js');
|
|
@@ -30215,7 +30563,7 @@ var BottlenecksContent = ({
|
|
|
30215
30563
|
}
|
|
30216
30564
|
}, []);
|
|
30217
30565
|
React23.useEffect(() => {
|
|
30218
|
-
if (!triageMode || !workspaceId) return;
|
|
30566
|
+
if (!triageMode || !workspaceId || !isEffectiveShiftReady) return;
|
|
30219
30567
|
const fetchTriageClips = async () => {
|
|
30220
30568
|
setIsLoadingTriageClips(true);
|
|
30221
30569
|
try {
|
|
@@ -30234,8 +30582,8 @@ var BottlenecksContent = ({
|
|
|
30234
30582
|
body: JSON.stringify({
|
|
30235
30583
|
action: "metadata",
|
|
30236
30584
|
workspaceId,
|
|
30237
|
-
date:
|
|
30238
|
-
shift:
|
|
30585
|
+
date: effectiveDateString,
|
|
30586
|
+
shift: effectiveShiftId,
|
|
30239
30587
|
category: categoryId,
|
|
30240
30588
|
page: 1,
|
|
30241
30589
|
limit: 100
|
|
@@ -30267,7 +30615,7 @@ var BottlenecksContent = ({
|
|
|
30267
30615
|
}
|
|
30268
30616
|
};
|
|
30269
30617
|
fetchTriageClips();
|
|
30270
|
-
}, [triageMode, workspaceId,
|
|
30618
|
+
}, [triageMode, workspaceId, effectiveDateString, effectiveShiftId, getAuthToken4, isEffectiveShiftReady]);
|
|
30271
30619
|
React23.useEffect(() => {
|
|
30272
30620
|
if (s3ClipsService && (mergedCounts[activeFilter] || 0) > 0) {
|
|
30273
30621
|
const hasVideosForCurrentFilter = allVideos.some((video) => {
|
|
@@ -30368,8 +30716,12 @@ var BottlenecksContent = ({
|
|
|
30368
30716
|
if (!workspaceId) {
|
|
30369
30717
|
return;
|
|
30370
30718
|
}
|
|
30371
|
-
|
|
30372
|
-
|
|
30719
|
+
if (!isEffectiveShiftReady) {
|
|
30720
|
+
console.log("[BottlenecksContent] Skipping metadata load - shift/date not ready");
|
|
30721
|
+
return;
|
|
30722
|
+
}
|
|
30723
|
+
const resolvedDate = effectiveDateString;
|
|
30724
|
+
const cacheKey = `${categoryId}-${resolvedDate}-${effectiveShiftId}`;
|
|
30373
30725
|
const cachedMetadata = !forceRefresh ? metadataCache[cacheKey] : void 0;
|
|
30374
30726
|
try {
|
|
30375
30727
|
if (cachedMetadata) {
|
|
@@ -30423,7 +30775,7 @@ var BottlenecksContent = ({
|
|
|
30423
30775
|
startDate: `${resolvedDate}T00:00:00Z`,
|
|
30424
30776
|
endDate: `${resolvedDate}T23:59:59Z`,
|
|
30425
30777
|
percentile: 10,
|
|
30426
|
-
shiftId:
|
|
30778
|
+
shiftId: effectiveShiftId,
|
|
30427
30779
|
limit: 100
|
|
30428
30780
|
})
|
|
30429
30781
|
});
|
|
@@ -30438,7 +30790,7 @@ var BottlenecksContent = ({
|
|
|
30438
30790
|
action: "clip-metadata",
|
|
30439
30791
|
workspaceId,
|
|
30440
30792
|
date: resolvedDate,
|
|
30441
|
-
shift:
|
|
30793
|
+
shift: effectiveShiftId,
|
|
30442
30794
|
category: categoryId,
|
|
30443
30795
|
page: 1,
|
|
30444
30796
|
limit: 1e3
|
|
@@ -30497,7 +30849,7 @@ var BottlenecksContent = ({
|
|
|
30497
30849
|
} finally {
|
|
30498
30850
|
setIsCategoryLoading(false);
|
|
30499
30851
|
}
|
|
30500
|
-
}, [workspaceId,
|
|
30852
|
+
}, [workspaceId, effectiveDateString, effectiveShiftId, isPercentileCategory, metadataCache, s3ClipsService, clearLoadingState, isEffectiveShiftReady]);
|
|
30501
30853
|
const loadAndPlayClipById = React23.useCallback(async (clipId, categoryId, position) => {
|
|
30502
30854
|
if (!workspaceId || !s3ClipsService || !isMountedRef.current) return;
|
|
30503
30855
|
console.log(`[BottlenecksContent] Loading clip by ID: ${clipId}, category=${categoryId}, position=${position}`);
|
|
@@ -30562,10 +30914,10 @@ var BottlenecksContent = ({
|
|
|
30562
30914
|
}, [workspaceId, s3ClipsService, updateActiveFilter, clearLoadingState, loadCategoryMetadata]);
|
|
30563
30915
|
React23.useCallback(async (categoryId, clipIndex) => {
|
|
30564
30916
|
console.warn("[BottlenecksContent] loadAndPlayClip is deprecated, use loadAndPlayClipById instead");
|
|
30565
|
-
if (!workspaceId || !s3ClipsService || !isMountedRef.current) return;
|
|
30917
|
+
if (!workspaceId || !s3ClipsService || !isMountedRef.current || !isEffectiveShiftReady) return;
|
|
30566
30918
|
try {
|
|
30567
|
-
const operationalDate =
|
|
30568
|
-
const shiftStr =
|
|
30919
|
+
const operationalDate = effectiveDateString;
|
|
30920
|
+
const shiftStr = effectiveShiftId;
|
|
30569
30921
|
const video = await s3ClipsService.getClipByIndex(
|
|
30570
30922
|
workspaceId,
|
|
30571
30923
|
operationalDate,
|
|
@@ -30586,7 +30938,7 @@ var BottlenecksContent = ({
|
|
|
30586
30938
|
});
|
|
30587
30939
|
setIsNavigating(false);
|
|
30588
30940
|
}
|
|
30589
|
-
}, [workspaceId, s3ClipsService,
|
|
30941
|
+
}, [workspaceId, s3ClipsService, effectiveDateString, effectiveShiftId, loadAndPlayClipById, isEffectiveShiftReady]);
|
|
30590
30942
|
const handleNext = React23.useCallback(async () => {
|
|
30591
30943
|
if (!isMountedRef.current) return;
|
|
30592
30944
|
const currentFilter = activeFilterRef.current;
|
|
@@ -31245,8 +31597,8 @@ var BottlenecksContent = ({
|
|
|
31245
31597
|
currentVideoId: currentVideo?.id,
|
|
31246
31598
|
counts: mergedCounts,
|
|
31247
31599
|
workspaceId,
|
|
31248
|
-
date:
|
|
31249
|
-
shift:
|
|
31600
|
+
date: effectiveDateString,
|
|
31601
|
+
shift: effectiveShiftId,
|
|
31250
31602
|
targetCycleTime: workspaceTargetCycleTime,
|
|
31251
31603
|
onFilterChange: (filterId) => {
|
|
31252
31604
|
updateActiveFilter(filterId);
|
|
@@ -31444,6 +31796,7 @@ var BottleneckClipsModal = ({
|
|
|
31444
31796
|
onClose,
|
|
31445
31797
|
workspaceId,
|
|
31446
31798
|
workspaceName,
|
|
31799
|
+
lineId,
|
|
31447
31800
|
date,
|
|
31448
31801
|
shift,
|
|
31449
31802
|
totalOutput,
|
|
@@ -31568,6 +31921,7 @@ var BottleneckClipsModal = ({
|
|
|
31568
31921
|
{
|
|
31569
31922
|
workspaceId,
|
|
31570
31923
|
workspaceName,
|
|
31924
|
+
lineId,
|
|
31571
31925
|
date,
|
|
31572
31926
|
shift,
|
|
31573
31927
|
totalOutput,
|
|
@@ -32514,7 +32868,7 @@ var EncouragementOverlay = ({
|
|
|
32514
32868
|
};
|
|
32515
32869
|
var ShiftDisplay = React23.memo(({ className, variant = "default", lineId }) => {
|
|
32516
32870
|
const { dateTimeConfig } = useDashboardConfig();
|
|
32517
|
-
const { shiftConfig } = useDynamicShiftConfig(lineId);
|
|
32871
|
+
const { shiftConfig, isLoading: isShiftConfigLoading } = useDynamicShiftConfig(lineId);
|
|
32518
32872
|
const getShiftInfo = () => {
|
|
32519
32873
|
const tz = dateTimeConfig?.defaultTimezone;
|
|
32520
32874
|
if (!tz || !shiftConfig || !shiftConfig.dayShift || !shiftConfig.nightShift || !shiftConfig.dayShift.startTime || !shiftConfig.nightShift.startTime) {
|
|
@@ -32542,7 +32896,13 @@ var ShiftDisplay = React23.memo(({ className, variant = "default", lineId }) =>
|
|
|
32542
32896
|
setCurrentShiftText(getShiftInfo());
|
|
32543
32897
|
}, 1e3);
|
|
32544
32898
|
return () => clearInterval(interval);
|
|
32545
|
-
}, [dateTimeConfig?.defaultTimezone, shiftConfig]);
|
|
32899
|
+
}, [dateTimeConfig?.defaultTimezone, shiftConfig, isShiftConfigLoading]);
|
|
32900
|
+
if (isShiftConfigLoading) {
|
|
32901
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `inline-flex items-center gap-2 bg-gray-100 rounded-lg px-3 py-1.5 ${className ?? ""}`, children: [
|
|
32902
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-4 h-4 bg-gray-200 rounded animate-pulse" }),
|
|
32903
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-16 h-4 bg-gray-200 rounded animate-pulse" })
|
|
32904
|
+
] });
|
|
32905
|
+
}
|
|
32546
32906
|
if (!currentShiftText) {
|
|
32547
32907
|
return null;
|
|
32548
32908
|
}
|
|
@@ -33020,13 +33380,26 @@ var LinePdfExportButton = ({
|
|
|
33020
33380
|
}
|
|
33021
33381
|
);
|
|
33022
33382
|
};
|
|
33383
|
+
var DEFAULT_LINE_SHIFT_DATA = {
|
|
33384
|
+
avg_efficiency: 0,
|
|
33385
|
+
underperforming_workspaces: 0,
|
|
33386
|
+
total_workspaces: 0,
|
|
33387
|
+
hasData: false
|
|
33388
|
+
};
|
|
33389
|
+
var getLineShiftData = (day, shiftId) => {
|
|
33390
|
+
const shift = day.shifts[shiftId];
|
|
33391
|
+
if (shift) {
|
|
33392
|
+
return { ...shift, hasData: true };
|
|
33393
|
+
}
|
|
33394
|
+
return { ...DEFAULT_LINE_SHIFT_DATA };
|
|
33395
|
+
};
|
|
33023
33396
|
var WEEKDAYS = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
|
|
33024
33397
|
var LineHistoryCalendar = ({
|
|
33025
33398
|
data,
|
|
33026
33399
|
month,
|
|
33027
33400
|
year,
|
|
33028
33401
|
lineId,
|
|
33029
|
-
|
|
33402
|
+
selectedShiftId,
|
|
33030
33403
|
onDateSelect,
|
|
33031
33404
|
className = ""
|
|
33032
33405
|
}) => {
|
|
@@ -33062,8 +33435,7 @@ var LineHistoryCalendar = ({
|
|
|
33062
33435
|
} else {
|
|
33063
33436
|
calendar.push({
|
|
33064
33437
|
date: currentDate,
|
|
33065
|
-
|
|
33066
|
-
nightShift: { avg_efficiency: 0, underperforming_workspaces: 0, total_workspaces: 0, hasData: false }
|
|
33438
|
+
shifts: {}
|
|
33067
33439
|
});
|
|
33068
33440
|
}
|
|
33069
33441
|
}
|
|
@@ -33114,8 +33486,7 @@ var LineHistoryCalendar = ({
|
|
|
33114
33486
|
};
|
|
33115
33487
|
const renderDayCell = (day) => {
|
|
33116
33488
|
if (!day) return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-full border border-gray-100 dark:border-gray-700 rounded-lg bg-gray-50 dark:bg-gray-800" });
|
|
33117
|
-
const shiftData =
|
|
33118
|
-
if (!shiftData) return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-full border border-gray-100 dark:border-gray-700 rounded-lg bg-gray-50 dark:bg-gray-800" });
|
|
33489
|
+
const shiftData = getLineShiftData(day, selectedShiftId);
|
|
33119
33490
|
const isToday = isCurrentDate(day.date instanceof Date ? day.date : new Date(day.date));
|
|
33120
33491
|
const isFuture = isFutureDate(day.date instanceof Date ? day.date : new Date(day.date));
|
|
33121
33492
|
const hasData = hasRealData(shiftData);
|
|
@@ -33131,21 +33502,20 @@ var LineHistoryCalendar = ({
|
|
|
33131
33502
|
const month2 = String(dateObj2.getMonth() + 1).padStart(2, "0");
|
|
33132
33503
|
const dayOfMonth = String(dateObj2.getDate()).padStart(2, "0");
|
|
33133
33504
|
const date = `${year2}-${month2}-${dayOfMonth}`;
|
|
33134
|
-
const shiftId = selectedShift === "day" ? "0" : "1";
|
|
33135
33505
|
trackCoreEvent("Line Monthly History Day Clicked", {
|
|
33136
33506
|
source: "line_kpi",
|
|
33137
33507
|
line_id: lineId,
|
|
33138
33508
|
date,
|
|
33139
|
-
|
|
33509
|
+
shift_id: selectedShiftId,
|
|
33140
33510
|
efficiency: shiftData.avg_efficiency || 0,
|
|
33141
33511
|
underperforming_workspaces: shiftData.underperforming_workspaces || 0,
|
|
33142
33512
|
total_workspaces: shiftData.total_workspaces || 0
|
|
33143
33513
|
});
|
|
33144
33514
|
const returnTo = `/kpis/${lineId}?tab=monthly_history&month=${month2}&year=${year2}`;
|
|
33145
33515
|
if (onDateSelect) {
|
|
33146
|
-
onDateSelect(date,
|
|
33516
|
+
onDateSelect(date, selectedShiftId);
|
|
33147
33517
|
} else {
|
|
33148
|
-
router.navigate(`/kpis/${lineId}?date=${date}&shift=${
|
|
33518
|
+
router.navigate(`/kpis/${lineId}?date=${date}&shift=${selectedShiftId}&sourceType=lineMonthlyHistory&returnTo=${encodeURIComponent(returnTo)}`);
|
|
33149
33519
|
}
|
|
33150
33520
|
}
|
|
33151
33521
|
},
|
|
@@ -33169,14 +33539,28 @@ var LineHistoryCalendar = ({
|
|
|
33169
33539
|
] });
|
|
33170
33540
|
};
|
|
33171
33541
|
var LineHistoryCalendar_default = LineHistoryCalendar;
|
|
33542
|
+
var DEFAULT_PERFORMANCE_DATA = {
|
|
33543
|
+
avg_efficiency: 0,
|
|
33544
|
+
underperforming_workspaces: 0,
|
|
33545
|
+
total_workspaces: 0,
|
|
33546
|
+
hasData: false
|
|
33547
|
+
};
|
|
33548
|
+
var getShiftData2 = (day, shiftId) => {
|
|
33549
|
+
const shift = day.shifts[shiftId];
|
|
33550
|
+
if (shift) {
|
|
33551
|
+
return { ...shift, hasData: true };
|
|
33552
|
+
}
|
|
33553
|
+
return { ...DEFAULT_PERFORMANCE_DATA };
|
|
33554
|
+
};
|
|
33172
33555
|
var LineMonthlyHistory = ({
|
|
33173
33556
|
month,
|
|
33174
33557
|
year,
|
|
33175
33558
|
monthlyData = [],
|
|
33176
|
-
underperformingWorkspaces = {
|
|
33559
|
+
underperformingWorkspaces = {},
|
|
33177
33560
|
lineId,
|
|
33178
|
-
|
|
33561
|
+
selectedShiftId = 0,
|
|
33179
33562
|
onShiftChange,
|
|
33563
|
+
availableShifts,
|
|
33180
33564
|
onWorkspaceSelect,
|
|
33181
33565
|
onCalendarDateSelect,
|
|
33182
33566
|
onCalendarMonthChange,
|
|
@@ -33185,7 +33569,7 @@ var LineMonthlyHistory = ({
|
|
|
33185
33569
|
const navigation = useNavigation();
|
|
33186
33570
|
const averages = (monthlyData || []).reduce(
|
|
33187
33571
|
(acc, day) => {
|
|
33188
|
-
const shiftData =
|
|
33572
|
+
const shiftData = getShiftData2(day, selectedShiftId);
|
|
33189
33573
|
if (!shiftData || shiftData?.avg_efficiency < 10) {
|
|
33190
33574
|
return acc;
|
|
33191
33575
|
}
|
|
@@ -33259,28 +33643,22 @@ var LineMonthlyHistory = ({
|
|
|
33259
33643
|
line_id: lineId,
|
|
33260
33644
|
workspace_id: workspace.workspace_uuid,
|
|
33261
33645
|
workspace_name: workspace.workspace_name,
|
|
33262
|
-
|
|
33646
|
+
selected_shift_id: selectedShiftId
|
|
33263
33647
|
});
|
|
33264
33648
|
};
|
|
33265
33649
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: clsx("flex flex-col gap-2 min-h-0 overflow-y-auto pb-6", className), children: [
|
|
33266
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-center mb-4", children: /* @__PURE__ */ jsxRuntime.
|
|
33267
|
-
|
|
33268
|
-
|
|
33269
|
-
|
|
33270
|
-
|
|
33271
|
-
|
|
33272
|
-
|
|
33273
|
-
}
|
|
33274
|
-
|
|
33275
|
-
|
|
33276
|
-
|
|
33277
|
-
|
|
33278
|
-
onClick: () => onShiftChange?.("night"),
|
|
33279
|
-
className: `px-4 py-2 text-sm font-medium rounded-md transition-all duration-200 ${selectedShift === "night" ? "bg-white text-blue-600 shadow-sm ring-1 ring-gray-200" : "text-gray-600 hover:text-gray-900 hover:bg-gray-100"}`,
|
|
33280
|
-
children: "Night Shift"
|
|
33281
|
-
}
|
|
33282
|
-
)
|
|
33283
|
-
] }) }),
|
|
33650
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-center mb-4", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex gap-1 border border-gray-200 rounded-lg p-1 bg-gray-50", children: (availableShifts && availableShifts.length > 0 ? availableShifts : [
|
|
33651
|
+
{ id: 0, name: "Day Shift" },
|
|
33652
|
+
{ id: 1, name: "Night Shift" }
|
|
33653
|
+
]).sort((a, b) => a.id - b.id).map((shift) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
33654
|
+
"button",
|
|
33655
|
+
{
|
|
33656
|
+
onClick: () => onShiftChange?.(shift.id),
|
|
33657
|
+
className: `px-4 py-2 text-sm font-medium rounded-md transition-all duration-200 ${selectedShiftId === shift.id ? "bg-white text-blue-600 shadow-sm ring-1 ring-gray-200" : "text-gray-600 hover:text-gray-900 hover:bg-gray-100"}`,
|
|
33658
|
+
children: shift.name
|
|
33659
|
+
},
|
|
33660
|
+
shift.id
|
|
33661
|
+
)) }) }),
|
|
33284
33662
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-1 lg:grid-cols-2 gap-6 mt-6", children: [
|
|
33285
33663
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-white rounded-xl shadow-sm border border-gray-100 p-6", children: [
|
|
33286
33664
|
/* @__PURE__ */ jsxRuntime.jsxs("h2", { className: "text-lg font-semibold text-gray-700 mb-4 text-center", children: [
|
|
@@ -33295,7 +33673,7 @@ var LineMonthlyHistory = ({
|
|
|
33295
33673
|
month,
|
|
33296
33674
|
year,
|
|
33297
33675
|
lineId,
|
|
33298
|
-
|
|
33676
|
+
selectedShiftId,
|
|
33299
33677
|
onDateSelect: onCalendarDateSelect
|
|
33300
33678
|
}
|
|
33301
33679
|
)
|
|
@@ -33332,7 +33710,7 @@ var LineMonthlyHistory = ({
|
|
|
33332
33710
|
new Date(year, month).toLocaleString("default", { month: "long", year: "numeric" })
|
|
33333
33711
|
] }),
|
|
33334
33712
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4", children: [
|
|
33335
|
-
(
|
|
33713
|
+
(underperformingWorkspaces[selectedShiftId] || []).map((workspace) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
33336
33714
|
"button",
|
|
33337
33715
|
{
|
|
33338
33716
|
onClick: () => handleWorkspaceClick(workspace),
|
|
@@ -33354,13 +33732,33 @@ var LineMonthlyHistory = ({
|
|
|
33354
33732
|
},
|
|
33355
33733
|
workspace.workspace_uuid
|
|
33356
33734
|
)),
|
|
33357
|
-
(!underperformingWorkspaces ||
|
|
33735
|
+
(!underperformingWorkspaces || !underperformingWorkspaces[selectedShiftId]?.length) && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-center text-gray-500 py-4", children: "No consistently underperforming workspaces found" })
|
|
33358
33736
|
] })
|
|
33359
33737
|
] })
|
|
33360
33738
|
] })
|
|
33361
33739
|
] })
|
|
33362
33740
|
] });
|
|
33363
33741
|
};
|
|
33742
|
+
var DEFAULT_PERFORMANCE_DATA2 = {
|
|
33743
|
+
avg_efficiency: 0,
|
|
33744
|
+
underperforming_workspaces: 0,
|
|
33745
|
+
total_workspaces: 0,
|
|
33746
|
+
hasData: false
|
|
33747
|
+
};
|
|
33748
|
+
var getLineShiftData2 = (day, shiftId) => {
|
|
33749
|
+
const shift = day.shifts[shiftId];
|
|
33750
|
+
if (shift) {
|
|
33751
|
+
return { ...shift, hasData: true };
|
|
33752
|
+
}
|
|
33753
|
+
return { ...DEFAULT_PERFORMANCE_DATA2 };
|
|
33754
|
+
};
|
|
33755
|
+
var getShiftDisplayName = (shiftId, availableShifts) => {
|
|
33756
|
+
const shift = availableShifts?.find((s) => s.id === shiftId);
|
|
33757
|
+
if (shift) return shift.name;
|
|
33758
|
+
if (shiftId === 0) return "Day Shift";
|
|
33759
|
+
if (shiftId === 1) return "Night Shift";
|
|
33760
|
+
return `Shift ${shiftId}`;
|
|
33761
|
+
};
|
|
33364
33762
|
var LineMonthlyPdfGenerator = ({
|
|
33365
33763
|
lineId,
|
|
33366
33764
|
lineName,
|
|
@@ -33368,7 +33766,8 @@ var LineMonthlyPdfGenerator = ({
|
|
|
33368
33766
|
underperformingWorkspaces,
|
|
33369
33767
|
selectedMonth,
|
|
33370
33768
|
selectedYear,
|
|
33371
|
-
|
|
33769
|
+
selectedShiftId,
|
|
33770
|
+
availableShifts,
|
|
33372
33771
|
className
|
|
33373
33772
|
}) => {
|
|
33374
33773
|
const [isGenerating, setIsGenerating] = React23.useState(false);
|
|
@@ -33380,7 +33779,7 @@ var LineMonthlyPdfGenerator = ({
|
|
|
33380
33779
|
line_name: lineName,
|
|
33381
33780
|
month: selectedMonth,
|
|
33382
33781
|
year: selectedYear,
|
|
33383
|
-
|
|
33782
|
+
shift_id: selectedShiftId
|
|
33384
33783
|
});
|
|
33385
33784
|
const doc = new jsPDF.jsPDF();
|
|
33386
33785
|
doc.setFontSize(14);
|
|
@@ -33410,7 +33809,7 @@ var LineMonthlyPdfGenerator = ({
|
|
|
33410
33809
|
year: "numeric",
|
|
33411
33810
|
timeZone: "Asia/Kolkata"
|
|
33412
33811
|
});
|
|
33413
|
-
const shiftType =
|
|
33812
|
+
const shiftType = getShiftDisplayName(selectedShiftId, availableShifts);
|
|
33414
33813
|
doc.text(`${monthName}`, 20, 55);
|
|
33415
33814
|
doc.text(`${shiftType}`, 20, 63);
|
|
33416
33815
|
const startDate = new Date(selectedYear, selectedMonth, 1);
|
|
@@ -33439,7 +33838,7 @@ var LineMonthlyPdfGenerator = ({
|
|
|
33439
33838
|
return date.getMonth() === selectedMonth && date.getFullYear() === selectedYear;
|
|
33440
33839
|
});
|
|
33441
33840
|
const validShifts = validDays.map(
|
|
33442
|
-
(day) =>
|
|
33841
|
+
(day) => getLineShiftData2(day, selectedShiftId)
|
|
33443
33842
|
).filter((shift) => shift.avg_efficiency > 0);
|
|
33444
33843
|
const monthlyMetrics = validShifts.length > 0 ? {
|
|
33445
33844
|
avgEfficiency: validShifts.reduce((sum, shift) => sum + shift.avg_efficiency, 0) / validShifts.length,
|
|
@@ -33521,8 +33920,8 @@ var LineMonthlyPdfGenerator = ({
|
|
|
33521
33920
|
const recentDays = validDays.slice(-10).reverse();
|
|
33522
33921
|
recentDays.forEach((dayData, index) => {
|
|
33523
33922
|
if (yPos > 245) return;
|
|
33524
|
-
const shift =
|
|
33525
|
-
if (shift.avg_efficiency <= 0) return;
|
|
33923
|
+
const shift = getLineShiftData2(dayData, selectedShiftId);
|
|
33924
|
+
if (shift.avg_efficiency <= 0 || !shift.hasData) return;
|
|
33526
33925
|
if (index % 2 === 0) {
|
|
33527
33926
|
doc.setFillColor(252, 252, 252);
|
|
33528
33927
|
doc.roundedRect(20, yPos - 4, 170, 7, 1, 1, "F");
|
|
@@ -33556,7 +33955,7 @@ var LineMonthlyPdfGenerator = ({
|
|
|
33556
33955
|
doc.text("No daily data available for this month", 25, 200);
|
|
33557
33956
|
doc.setTextColor(0, 0, 0);
|
|
33558
33957
|
}
|
|
33559
|
-
const poorestWorkspaces =
|
|
33958
|
+
const poorestWorkspaces = underperformingWorkspaces[selectedShiftId] || [];
|
|
33560
33959
|
if (poorestWorkspaces && poorestWorkspaces.length > 0) {
|
|
33561
33960
|
doc.addPage();
|
|
33562
33961
|
doc.setFontSize(14);
|
|
@@ -33684,6 +34083,7 @@ Underperforming Workspaces: ${lineInfo.metrics.underperforming_workspaces} / ${l
|
|
|
33684
34083
|
var LinePdfGenerator = ({
|
|
33685
34084
|
lineInfo,
|
|
33686
34085
|
workspaceData,
|
|
34086
|
+
shiftName,
|
|
33687
34087
|
className
|
|
33688
34088
|
}) => {
|
|
33689
34089
|
const [isGenerating, setIsGenerating] = React23.useState(false);
|
|
@@ -33735,7 +34135,8 @@ var LinePdfGenerator = ({
|
|
|
33735
34135
|
doc.text(lineInfo.line_name, 20, 30);
|
|
33736
34136
|
doc.setFontSize(14);
|
|
33737
34137
|
doc.setFont("helvetica", "normal");
|
|
33738
|
-
const
|
|
34138
|
+
const rawShiftType = shiftName || (lineInfo.shift_id === 0 ? "Day" : lineInfo.shift_id === 1 ? "Night" : `Shift ${lineInfo.shift_id}`);
|
|
34139
|
+
const shiftType = rawShiftType.toLowerCase().includes("shift") ? rawShiftType : `${rawShiftType} Shift`;
|
|
33739
34140
|
const date = new Date(lineInfo.date).toLocaleDateString("en-IN", {
|
|
33740
34141
|
weekday: "long",
|
|
33741
34142
|
day: "numeric",
|
|
@@ -34410,9 +34811,10 @@ var WorkspaceHistoryCalendar = ({
|
|
|
34410
34811
|
month,
|
|
34411
34812
|
year,
|
|
34412
34813
|
workspaceId,
|
|
34413
|
-
|
|
34814
|
+
selectedShiftId = 0,
|
|
34414
34815
|
onMonthNavigate,
|
|
34415
34816
|
onShiftChange,
|
|
34817
|
+
availableShifts,
|
|
34416
34818
|
className
|
|
34417
34819
|
}) => {
|
|
34418
34820
|
const { dateTimeConfig } = useDashboardConfig();
|
|
@@ -34477,7 +34879,7 @@ var WorkspaceHistoryCalendar = ({
|
|
|
34477
34879
|
if (compareDate > istNow) {
|
|
34478
34880
|
return [];
|
|
34479
34881
|
}
|
|
34480
|
-
const shiftData =
|
|
34882
|
+
const shiftData = getShiftData(day, selectedShiftId);
|
|
34481
34883
|
if (hasRealData(shiftData)) {
|
|
34482
34884
|
return [shiftData];
|
|
34483
34885
|
}
|
|
@@ -34494,31 +34896,32 @@ var WorkspaceHistoryCalendar = ({
|
|
|
34494
34896
|
badDaysCount: badShiftsCount,
|
|
34495
34897
|
totalDays: validShifts.length
|
|
34496
34898
|
};
|
|
34497
|
-
}, [data, month, year, configuredTimezone,
|
|
34498
|
-
const handleDayClick = React23.useCallback((day,
|
|
34899
|
+
}, [data, month, year, configuredTimezone, selectedShiftId]);
|
|
34900
|
+
const handleDayClick = React23.useCallback((day, shiftId) => {
|
|
34499
34901
|
if (!day || isFutureDate(day.date)) return;
|
|
34500
34902
|
const year2 = day.date.getFullYear();
|
|
34501
34903
|
const month2 = String(day.date.getMonth() + 1).padStart(2, "0");
|
|
34502
34904
|
const dayOfMonth = String(day.date.getDate()).padStart(2, "0");
|
|
34503
34905
|
const formattedDate = `${year2}-${month2}-${dayOfMonth}`;
|
|
34504
|
-
const shiftData =
|
|
34906
|
+
const shiftData = getShiftData(day, shiftId);
|
|
34505
34907
|
trackCoreEvent("Workspace Monthly History Day Clicked", {
|
|
34506
34908
|
source: "workspace_detail",
|
|
34507
34909
|
workspace_id: workspaceId,
|
|
34508
34910
|
date: formattedDate,
|
|
34911
|
+
shift_id: shiftId,
|
|
34509
34912
|
efficiency: shiftData.efficiency,
|
|
34510
34913
|
output: shiftData.output,
|
|
34511
34914
|
cycle_time: shiftData.cycleTime
|
|
34512
34915
|
});
|
|
34513
|
-
onDateSelect(formattedDate);
|
|
34916
|
+
onDateSelect(formattedDate, shiftId);
|
|
34514
34917
|
}, [workspaceId, onDateSelect]);
|
|
34515
|
-
const handleShiftChange = React23.useCallback((
|
|
34918
|
+
const handleShiftChange = React23.useCallback((shiftId) => {
|
|
34516
34919
|
trackCoreEvent("Workspace Calendar Shift Changed", {
|
|
34517
34920
|
workspace_id: workspaceId,
|
|
34518
|
-
|
|
34921
|
+
new_shift_id: shiftId
|
|
34519
34922
|
});
|
|
34520
34923
|
if (onShiftChange) {
|
|
34521
|
-
onShiftChange(
|
|
34924
|
+
onShiftChange(shiftId);
|
|
34522
34925
|
}
|
|
34523
34926
|
}, [workspaceId, onShiftChange]);
|
|
34524
34927
|
const isCurrentDate = React23.useCallback((date) => {
|
|
@@ -34599,13 +35002,13 @@ var WorkspaceHistoryCalendar = ({
|
|
|
34599
35002
|
}
|
|
34600
35003
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: `h-full border border-gray-200 rounded-lg ${bgColor} ${animationComplete ? "transition-all duration-300 ease-in-out" : ""} cursor-not-allowed opacity-60`, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-1 sm:p-2", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: `text-xs sm:text-sm lg:text-base font-medium ${textColor} ${isToday ? "text-blue-500" : ""}`, children: dayNumber }) }) });
|
|
34601
35004
|
}
|
|
34602
|
-
const shiftData =
|
|
35005
|
+
const shiftData = getShiftData(day, selectedShiftId);
|
|
34603
35006
|
const hasData = hasRealData(shiftData);
|
|
34604
35007
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
34605
35008
|
"div",
|
|
34606
35009
|
{
|
|
34607
35010
|
className: `group h-full ${animationComplete ? "transition-all duration-300 ease-in-out" : ""} ${!isFuture && hasData && animationComplete ? "cursor-pointer hover:opacity-90 hover:scale-105" : "cursor-not-allowed"}`,
|
|
34608
|
-
onClick: () => !isFuture && hasData && handleDayClick(day,
|
|
35011
|
+
onClick: () => !isFuture && hasData && handleDayClick(day, selectedShiftId),
|
|
34609
35012
|
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `
|
|
34610
35013
|
${getPerformanceColor(shiftData.efficiency, day.date, hasData)}
|
|
34611
35014
|
rounded-lg h-full p-1 sm:p-2 relative ${animationComplete ? "transition-all duration-300 ease-in-out" : ""} shadow-sm
|
|
@@ -34619,31 +35022,25 @@ var WorkspaceHistoryCalendar = ({
|
|
|
34619
35022
|
] })
|
|
34620
35023
|
}
|
|
34621
35024
|
);
|
|
34622
|
-
}, [
|
|
35025
|
+
}, [selectedShiftId, isCurrentDate, isFutureDate, getPerformanceColor, handleDayClick, year, month, configuredTimezone, animationComplete, hasRealData]);
|
|
34623
35026
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `calendar-wrapper space-y-6 ${className || ""} ${animationComplete ? "animation-complete" : ""}`, children: [
|
|
34624
35027
|
/* @__PURE__ */ jsxRuntime.jsx("style", { dangerouslySetInnerHTML: { __html: styles } }),
|
|
34625
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-center", children: /* @__PURE__ */ jsxRuntime.
|
|
34626
|
-
|
|
34627
|
-
|
|
34628
|
-
|
|
34629
|
-
|
|
34630
|
-
|
|
34631
|
-
|
|
34632
|
-
}
|
|
34633
|
-
|
|
34634
|
-
|
|
34635
|
-
|
|
34636
|
-
|
|
34637
|
-
onClick: () => handleShiftChange("night"),
|
|
34638
|
-
className: `px-4 py-2 text-sm font-medium rounded-md ${animationComplete ? "transition-all duration-200" : ""} ${selectedShift === "night" ? "bg-white text-blue-600 shadow-sm ring-1 ring-gray-200" : `text-gray-600 ${animationComplete ? "hover:text-gray-900 hover:bg-gray-100" : ""}`}`,
|
|
34639
|
-
children: "Night Shift"
|
|
34640
|
-
}
|
|
34641
|
-
)
|
|
34642
|
-
] }) }),
|
|
35028
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-center", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex gap-1 border border-gray-200 rounded-lg p-1 bg-gray-50", children: (availableShifts && availableShifts.length > 0 ? availableShifts : [
|
|
35029
|
+
{ id: 0, name: "Day Shift" },
|
|
35030
|
+
{ id: 1, name: "Night Shift" }
|
|
35031
|
+
]).sort((a, b) => a.id - b.id).map((shift) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
35032
|
+
"button",
|
|
35033
|
+
{
|
|
35034
|
+
onClick: () => handleShiftChange(shift.id),
|
|
35035
|
+
className: `px-4 py-2 text-sm font-medium rounded-md ${animationComplete ? "transition-all duration-200" : ""} ${selectedShiftId === shift.id ? "bg-white text-blue-600 shadow-sm ring-1 ring-gray-200" : `text-gray-600 ${animationComplete ? "hover:text-gray-900 hover:bg-gray-100" : ""}`}`,
|
|
35036
|
+
children: shift.name
|
|
35037
|
+
},
|
|
35038
|
+
shift.id
|
|
35039
|
+
)) }) }),
|
|
34643
35040
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-1 lg:grid-cols-2 gap-4 lg:gap-8", children: [
|
|
34644
35041
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "calendar-container bg-white rounded-xl shadow-sm border border-gray-100 p-3 sm:p-4 lg:p-6 transition-all duration-200 ease-in-out", children: [
|
|
34645
35042
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-3 sm:mb-4 lg:mb-6", children: [
|
|
34646
|
-
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "font-semibold text-gray-900 text-base sm:text-lg", children:
|
|
35043
|
+
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "font-semibold text-gray-900 text-base sm:text-lg", children: (availableShifts?.find((s) => s.id === selectedShiftId)?.name || (selectedShiftId === 0 ? "Day" : selectedShiftId === 1 ? "Night" : `Shift ${selectedShiftId}`)) + "s" }),
|
|
34647
35044
|
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs sm:text-sm text-gray-500 mt-1", children: "Calendar view of daily performance" })
|
|
34648
35045
|
] }),
|
|
34649
35046
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-3 sm:gap-4 lg:gap-6", children: [
|
|
@@ -34659,7 +35056,7 @@ var WorkspaceHistoryCalendar = ({
|
|
|
34659
35056
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-3 sm:mb-4 lg:mb-6", children: [
|
|
34660
35057
|
/* @__PURE__ */ jsxRuntime.jsxs("h3", { className: "font-semibold text-gray-900 text-base sm:text-lg", children: [
|
|
34661
35058
|
"Monthly Summary - ",
|
|
34662
|
-
|
|
35059
|
+
availableShifts?.find((s) => s.id === selectedShiftId)?.name || (selectedShiftId === 0 ? "Day Shift" : selectedShiftId === 1 ? "Night Shift" : `Shift ${selectedShiftId}`)
|
|
34663
35060
|
] }),
|
|
34664
35061
|
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs sm:text-sm text-gray-500 mt-1", children: "Overview of monthly performance metrics" })
|
|
34665
35062
|
] }),
|
|
@@ -34733,10 +35130,11 @@ var WorkspaceMonthlyHistory = ({
|
|
|
34733
35130
|
month,
|
|
34734
35131
|
year,
|
|
34735
35132
|
workspaceId,
|
|
34736
|
-
|
|
35133
|
+
selectedShiftId = 0,
|
|
34737
35134
|
onDateSelect,
|
|
34738
35135
|
onMonthNavigate,
|
|
34739
35136
|
onShiftChange,
|
|
35137
|
+
availableShifts,
|
|
34740
35138
|
monthlyDataLoading = false,
|
|
34741
35139
|
className = ""
|
|
34742
35140
|
}) => {
|
|
@@ -34754,7 +35152,7 @@ var WorkspaceMonthlyHistory = ({
|
|
|
34754
35152
|
const date = new Date(d.date);
|
|
34755
35153
|
return date.getDate() === day;
|
|
34756
35154
|
});
|
|
34757
|
-
const shiftData = dayData ?
|
|
35155
|
+
const shiftData = dayData ? getShiftData(dayData, selectedShiftId) : null;
|
|
34758
35156
|
const idealOutput = shiftData ? shiftData.idealOutput : 0;
|
|
34759
35157
|
if (idealOutput > 0) {
|
|
34760
35158
|
lastSetTarget = idealOutput;
|
|
@@ -34766,7 +35164,7 @@ var WorkspaceMonthlyHistory = ({
|
|
|
34766
35164
|
const date = new Date(d.date);
|
|
34767
35165
|
return date.getDate() === day;
|
|
34768
35166
|
});
|
|
34769
|
-
const shiftData = dayData ?
|
|
35167
|
+
const shiftData = dayData ? getShiftData(dayData, selectedShiftId) : null;
|
|
34770
35168
|
const output = shiftData && hasRealData(shiftData) ? shiftData.output : 0;
|
|
34771
35169
|
const idealOutput = shiftData ? shiftData.idealOutput : 0;
|
|
34772
35170
|
if (output > maxOutput) maxOutput = output;
|
|
@@ -34788,7 +35186,7 @@ var WorkspaceMonthlyHistory = ({
|
|
|
34788
35186
|
const calculatedMax = Math.max(maxOutput, lastSetTarget);
|
|
34789
35187
|
const yAxisMax = calculatedMax > 0 ? calculatedMax * 1.1 : 100;
|
|
34790
35188
|
return { data: dailyData, maxOutput, lastSetTarget, yAxisMax };
|
|
34791
|
-
}, [data, month, year,
|
|
35189
|
+
}, [data, month, year, selectedShiftId]);
|
|
34792
35190
|
const yAxisTicks = React23.useMemo(() => {
|
|
34793
35191
|
const max = chartData.yAxisMax;
|
|
34794
35192
|
const target = chartData.lastSetTarget;
|
|
@@ -34811,7 +35209,7 @@ var WorkspaceMonthlyHistory = ({
|
|
|
34811
35209
|
return Array.from(new Set(ticks)).filter((v) => v >= 0 && v <= max).sort((a, b) => a - b);
|
|
34812
35210
|
}, [chartData.yAxisMax, chartData.lastSetTarget]);
|
|
34813
35211
|
const pieChartData = React23.useMemo(() => {
|
|
34814
|
-
const validShifts = data.map((d) =>
|
|
35212
|
+
const validShifts = data.map((d) => getShiftData(d, selectedShiftId)).filter(hasRealData);
|
|
34815
35213
|
if (validShifts.length === 0) return [];
|
|
34816
35214
|
const totalIdleTime = validShifts.reduce((sum, shift) => sum + shift.idleTime, 0);
|
|
34817
35215
|
const totalShiftTime = validShifts.length * 8 * 3600;
|
|
@@ -34820,9 +35218,9 @@ var WorkspaceMonthlyHistory = ({
|
|
|
34820
35218
|
{ name: "Productive", value: Math.round(activeTime / totalShiftTime * 100) },
|
|
34821
35219
|
{ name: "Idle", value: Math.round(totalIdleTime / totalShiftTime * 100) }
|
|
34822
35220
|
];
|
|
34823
|
-
}, [data,
|
|
35221
|
+
}, [data, selectedShiftId]);
|
|
34824
35222
|
const metrics2 = React23.useMemo(() => {
|
|
34825
|
-
const validShifts = data.map((d) =>
|
|
35223
|
+
const validShifts = data.map((d) => getShiftData(d, selectedShiftId)).filter(hasRealData);
|
|
34826
35224
|
if (validShifts.length === 0) return null;
|
|
34827
35225
|
const totalEfficiency = validShifts.reduce((sum, shift) => sum + shift.efficiency, 0);
|
|
34828
35226
|
const totalCycleTime = validShifts.reduce((sum, shift) => sum + shift.cycleTime, 0);
|
|
@@ -34842,7 +35240,7 @@ var WorkspaceMonthlyHistory = ({
|
|
|
34842
35240
|
totalOutput,
|
|
34843
35241
|
avgIdleTime: Math.round(totalIdleTime / validShifts.length)
|
|
34844
35242
|
};
|
|
34845
|
-
}, [data,
|
|
35243
|
+
}, [data, selectedShiftId]);
|
|
34846
35244
|
const calendarData = React23.useMemo(() => {
|
|
34847
35245
|
const startOfMonth = new Date(year, month, 1);
|
|
34848
35246
|
const endOfMonth = new Date(year, month + 1, 0);
|
|
@@ -34869,17 +35267,17 @@ var WorkspaceMonthlyHistory = ({
|
|
|
34869
35267
|
source: "monthly_history",
|
|
34870
35268
|
workspace_id: workspaceId,
|
|
34871
35269
|
date: formattedDate,
|
|
34872
|
-
|
|
35270
|
+
shift_id: selectedShiftId
|
|
34873
35271
|
});
|
|
34874
|
-
onDateSelect(formattedDate,
|
|
34875
|
-
}, [workspaceId,
|
|
34876
|
-
const handleShiftChange = React23.useCallback((
|
|
35272
|
+
onDateSelect(formattedDate, selectedShiftId);
|
|
35273
|
+
}, [workspaceId, selectedShiftId, onDateSelect]);
|
|
35274
|
+
const handleShiftChange = React23.useCallback((shiftId) => {
|
|
34877
35275
|
trackCoreEvent("Workspace Monthly History Shift Changed", {
|
|
34878
35276
|
workspace_id: workspaceId,
|
|
34879
|
-
|
|
35277
|
+
new_shift_id: shiftId
|
|
34880
35278
|
});
|
|
34881
35279
|
if (onShiftChange) {
|
|
34882
|
-
onShiftChange(
|
|
35280
|
+
onShiftChange(shiftId);
|
|
34883
35281
|
}
|
|
34884
35282
|
}, [workspaceId, onShiftChange]);
|
|
34885
35283
|
if (monthlyDataLoading) {
|
|
@@ -34892,24 +35290,18 @@ var WorkspaceMonthlyHistory = ({
|
|
|
34892
35290
|
) });
|
|
34893
35291
|
}
|
|
34894
35292
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `flex flex-col gap-2 min-h-0 overflow-y-auto pb-6 ${className}`, children: [
|
|
34895
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-center mb-4", children: /* @__PURE__ */ jsxRuntime.
|
|
34896
|
-
|
|
34897
|
-
|
|
34898
|
-
|
|
34899
|
-
|
|
34900
|
-
|
|
34901
|
-
|
|
34902
|
-
}
|
|
34903
|
-
|
|
34904
|
-
|
|
34905
|
-
|
|
34906
|
-
|
|
34907
|
-
onClick: () => handleShiftChange("night"),
|
|
34908
|
-
className: `px-4 py-2 text-sm font-medium rounded-md transition-all duration-200 ${selectedShift === "night" ? "bg-white text-blue-600 shadow-sm ring-1 ring-gray-200" : "text-gray-600 hover:text-gray-900 hover:bg-gray-100"}`,
|
|
34909
|
-
children: "Night Shift"
|
|
34910
|
-
}
|
|
34911
|
-
)
|
|
34912
|
-
] }) }),
|
|
35293
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-center mb-4", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex gap-1 border border-gray-200 rounded-lg p-1 bg-gray-50", children: (availableShifts && availableShifts.length > 0 ? availableShifts : [
|
|
35294
|
+
{ id: 0, name: "Day Shift" },
|
|
35295
|
+
{ id: 1, name: "Night Shift" }
|
|
35296
|
+
]).sort((a, b) => a.id - b.id).map((shift) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
35297
|
+
"button",
|
|
35298
|
+
{
|
|
35299
|
+
onClick: () => handleShiftChange(shift.id),
|
|
35300
|
+
className: `px-4 py-2 text-sm font-medium rounded-md transition-all duration-200 ${selectedShiftId === shift.id ? "bg-white text-blue-600 shadow-sm ring-1 ring-gray-200" : "text-gray-600 hover:text-gray-900 hover:bg-gray-100"}`,
|
|
35301
|
+
children: shift.name
|
|
35302
|
+
},
|
|
35303
|
+
shift.id
|
|
35304
|
+
)) }) }),
|
|
34913
35305
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-1 lg:grid-cols-2 gap-6 mt-6", children: [
|
|
34914
35306
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-white rounded-xl shadow-sm border border-gray-100 p-6", children: [
|
|
34915
35307
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-center items-center mb-6 space-x-4", children: [
|
|
@@ -34973,7 +35365,7 @@ var WorkspaceMonthlyHistory = ({
|
|
|
34973
35365
|
if (!dayNumber || dayNumber > new Date(year, month + 1, 0).getDate()) {
|
|
34974
35366
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "aspect-square relative", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-full border border-gray-100 dark:border-gray-700 rounded-lg bg-gray-50 dark:bg-gray-800" }) }, index);
|
|
34975
35367
|
}
|
|
34976
|
-
const shiftData = day ?
|
|
35368
|
+
const shiftData = day ? getShiftData(day, selectedShiftId) : null;
|
|
34977
35369
|
const hasData = shiftData ? hasRealData(shiftData) : false;
|
|
34978
35370
|
const isToday = (/* @__PURE__ */ new Date()).getDate() === dayNumber && (/* @__PURE__ */ new Date()).getMonth() === month && (/* @__PURE__ */ new Date()).getFullYear() === year;
|
|
34979
35371
|
const isFuture = new Date(year, month, dayNumber) > /* @__PURE__ */ new Date();
|
|
@@ -35300,7 +35692,8 @@ var WorkspacePdfGenerator = ({ workspace, className }) => {
|
|
|
35300
35692
|
month: "long",
|
|
35301
35693
|
timeZone: "Asia/Kolkata"
|
|
35302
35694
|
});
|
|
35303
|
-
const
|
|
35695
|
+
const rawShiftType = workspace.shift_type || (workspace.shift_id === 0 ? "Day" : workspace.shift_id === 1 ? "Night" : `Shift ${workspace.shift_id}`);
|
|
35696
|
+
const shiftType = rawShiftType.toLowerCase().includes("shift") ? rawShiftType : `${rawShiftType} Shift`;
|
|
35304
35697
|
doc.text(`${date}`, 20, 63);
|
|
35305
35698
|
doc.text(`${shiftType}`, 20, 71);
|
|
35306
35699
|
const currentTime = (/* @__PURE__ */ new Date()).toLocaleTimeString("en-IN", {
|
|
@@ -35450,13 +35843,21 @@ var WorkspacePdfGenerator = ({ workspace, className }) => {
|
|
|
35450
35843
|
}
|
|
35451
35844
|
);
|
|
35452
35845
|
};
|
|
35846
|
+
var getShiftDisplayName2 = (shiftId, availableShifts) => {
|
|
35847
|
+
const shift = availableShifts?.find((s) => s.id === shiftId);
|
|
35848
|
+
if (shift) return shift.name;
|
|
35849
|
+
if (shiftId === 0) return "Day Shift";
|
|
35850
|
+
if (shiftId === 1) return "Night Shift";
|
|
35851
|
+
return `Shift ${shiftId}`;
|
|
35852
|
+
};
|
|
35453
35853
|
var WorkspaceMonthlyPdfGenerator = ({
|
|
35454
35854
|
workspaceId,
|
|
35455
35855
|
workspaceName,
|
|
35456
35856
|
monthlyData,
|
|
35457
35857
|
selectedMonth,
|
|
35458
35858
|
selectedYear,
|
|
35459
|
-
|
|
35859
|
+
selectedShiftId,
|
|
35860
|
+
availableShifts,
|
|
35460
35861
|
className
|
|
35461
35862
|
}) => {
|
|
35462
35863
|
const [isGenerating, setIsGenerating] = React23.useState(false);
|
|
@@ -35468,7 +35869,7 @@ var WorkspaceMonthlyPdfGenerator = ({
|
|
|
35468
35869
|
workspace_name: workspaceName,
|
|
35469
35870
|
month: selectedMonth,
|
|
35470
35871
|
year: selectedYear,
|
|
35471
|
-
|
|
35872
|
+
shift_id: selectedShiftId
|
|
35472
35873
|
});
|
|
35473
35874
|
const doc = new jsPDF.jsPDF();
|
|
35474
35875
|
doc.setFontSize(14);
|
|
@@ -35502,7 +35903,7 @@ var WorkspaceMonthlyPdfGenerator = ({
|
|
|
35502
35903
|
year: "numeric",
|
|
35503
35904
|
timeZone: "Asia/Kolkata"
|
|
35504
35905
|
});
|
|
35505
|
-
const shiftType =
|
|
35906
|
+
const shiftType = getShiftDisplayName2(selectedShiftId, availableShifts);
|
|
35506
35907
|
doc.text(`${monthName}`, 20, 65);
|
|
35507
35908
|
doc.text(`${shiftType}`, 20, 73);
|
|
35508
35909
|
const startDate = new Date(selectedYear, selectedMonth, 1);
|
|
@@ -35531,7 +35932,7 @@ var WorkspaceMonthlyPdfGenerator = ({
|
|
|
35531
35932
|
return date.getMonth() === selectedMonth && date.getFullYear() === selectedYear;
|
|
35532
35933
|
});
|
|
35533
35934
|
const validShifts = validDays.map(
|
|
35534
|
-
(day) =>
|
|
35935
|
+
(day) => getShiftData(day, selectedShiftId)
|
|
35535
35936
|
).filter((shift) => shift.efficiency > 0);
|
|
35536
35937
|
const monthlyMetrics = validShifts.length > 0 ? {
|
|
35537
35938
|
avgEfficiency: validShifts.reduce((sum, shift) => sum + shift.efficiency, 0) / validShifts.length,
|
|
@@ -35619,7 +36020,7 @@ var WorkspaceMonthlyPdfGenerator = ({
|
|
|
35619
36020
|
const recentDays = validDays.slice(-10).reverse();
|
|
35620
36021
|
recentDays.forEach((dayData, index) => {
|
|
35621
36022
|
if (yPos > 260) return;
|
|
35622
|
-
const shift =
|
|
36023
|
+
const shift = getShiftData(dayData, selectedShiftId);
|
|
35623
36024
|
if (shift.efficiency <= 0) return;
|
|
35624
36025
|
if (index % 2 === 0) {
|
|
35625
36026
|
doc.setFillColor(252, 252, 252);
|
|
@@ -37006,19 +37407,26 @@ var HealthStatusGrid = ({
|
|
|
37006
37407
|
};
|
|
37007
37408
|
var Timer2 = Timer_default;
|
|
37008
37409
|
var DashboardHeader = React23.memo(({ lineTitle, className = "", headerControls, lineId }) => {
|
|
37009
|
-
const { shiftConfig } = useDynamicShiftConfig(lineId);
|
|
37410
|
+
const { shiftConfig, isLoading: isShiftConfigLoading } = useDynamicShiftConfig(lineId);
|
|
37010
37411
|
const timezone = useAppTimezone();
|
|
37011
37412
|
const getShiftName = () => {
|
|
37012
37413
|
const currentShift = getCurrentShift(timezone, shiftConfig);
|
|
37013
|
-
|
|
37414
|
+
const rawName = currentShift.shiftName || "Day";
|
|
37415
|
+
return rawName.toLowerCase().includes("shift") ? rawName : `${rawName} Shift`;
|
|
37014
37416
|
};
|
|
37015
37417
|
const getShiftIcon = () => {
|
|
37016
|
-
const
|
|
37017
|
-
|
|
37418
|
+
const currentShift = getCurrentShift(timezone, shiftConfig);
|
|
37419
|
+
const shiftName = (currentShift.shiftName || "").toLowerCase();
|
|
37420
|
+
if (shiftName.includes("day") || shiftName.includes("morning") || currentShift.shiftId === 0) {
|
|
37018
37421
|
return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" }) });
|
|
37019
|
-
}
|
|
37422
|
+
}
|
|
37423
|
+
if (shiftName.includes("afternoon") || shiftName.includes("noon") || shiftName.includes("midday")) {
|
|
37424
|
+
return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" }) });
|
|
37425
|
+
}
|
|
37426
|
+
if (shiftName.includes("night") || shiftName.includes("evening") || currentShift.shiftId === 1) {
|
|
37020
37427
|
return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z" }) });
|
|
37021
37428
|
}
|
|
37429
|
+
return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" }) });
|
|
37022
37430
|
};
|
|
37023
37431
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `flex flex-col sm:flex-row items-start sm:items-center justify-between w-full gap-2 sm:gap-4 ${className}`, children: [
|
|
37024
37432
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col", children: [
|
|
@@ -37028,13 +37436,10 @@ var DashboardHeader = React23.memo(({ lineTitle, className = "", headerControls,
|
|
|
37028
37436
|
] }),
|
|
37029
37437
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-0.5 sm:mt-2 inline-flex flex-wrap items-center gap-1.5 sm:gap-3", children: [
|
|
37030
37438
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-[10px] sm:text-xs md:text-sm font-medium text-gray-500 sm:text-gray-600 whitespace-nowrap", children: /* @__PURE__ */ jsxRuntime.jsx(Timer2, {}) }),
|
|
37031
|
-
/* @__PURE__ */ jsxRuntime.
|
|
37439
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "inline-flex items-center gap-0.5 sm:gap-1", children: isShiftConfigLoading ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-4 w-16 sm:w-20 bg-gray-200 rounded animate-pulse" }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
37032
37440
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-gray-500 sm:text-gray-600 scale-90 sm:scale-100", children: getShiftIcon() }),
|
|
37033
|
-
/* @__PURE__ */ jsxRuntime.
|
|
37034
|
-
|
|
37035
|
-
" Shift"
|
|
37036
|
-
] })
|
|
37037
|
-
] })
|
|
37441
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] sm:text-xs md:text-sm font-medium text-gray-500 sm:text-gray-600 whitespace-nowrap", children: getShiftName() })
|
|
37442
|
+
] }) })
|
|
37038
37443
|
] })
|
|
37039
37444
|
] }),
|
|
37040
37445
|
headerControls && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-1.5 sm:gap-3 md:gap-4 w-full sm:w-auto justify-end", children: headerControls })
|
|
@@ -42051,18 +42456,23 @@ var FactoryView = ({
|
|
|
42051
42456
|
fetchHourlyData();
|
|
42052
42457
|
}
|
|
42053
42458
|
}, [supabase, lineDataHooks, effectiveLineIds, lineNames, factoryName, timezone, shiftConfig, productIds]);
|
|
42459
|
+
const getCurrentShiftInfo = () => {
|
|
42460
|
+
return getCurrentShift(timezone, shiftConfig);
|
|
42461
|
+
};
|
|
42054
42462
|
const getShiftName = () => {
|
|
42055
|
-
const
|
|
42056
|
-
|
|
42057
|
-
return currentHour >= 6 && currentHour < 18 ? "Day" : "Night";
|
|
42463
|
+
const currentShift = getCurrentShiftInfo();
|
|
42464
|
+
return (currentShift.shiftName || "Day").replace(/ Shift$/i, "");
|
|
42058
42465
|
};
|
|
42059
42466
|
const getShiftIcon = () => {
|
|
42060
|
-
const
|
|
42061
|
-
|
|
42467
|
+
const currentShift = getCurrentShiftInfo();
|
|
42468
|
+
const shiftNameLower = (currentShift.shiftName || "").toLowerCase();
|
|
42469
|
+
if (shiftNameLower.includes("day") || shiftNameLower.includes("morning") || currentShift.shiftId === 0) {
|
|
42062
42470
|
return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" }) });
|
|
42063
|
-
}
|
|
42471
|
+
}
|
|
42472
|
+
if (shiftNameLower.includes("night") || shiftNameLower.includes("evening") || currentShift.shiftId === 1) {
|
|
42064
42473
|
return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z" }) });
|
|
42065
42474
|
}
|
|
42475
|
+
return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" }) });
|
|
42066
42476
|
};
|
|
42067
42477
|
if (loading || lineDataHooks.some((hookData) => hookData.hook.loading)) {
|
|
42068
42478
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-4", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "animate-pulse space-y-4", children: [
|
|
@@ -43591,8 +44001,8 @@ var KPIDetailView = ({
|
|
|
43591
44001
|
return (/* @__PURE__ */ new Date()).getFullYear();
|
|
43592
44002
|
});
|
|
43593
44003
|
const [monthlyData, setMonthlyData] = React23.useState([]);
|
|
43594
|
-
const [underperformingWorkspaces, setUnderperformingWorkspaces] = React23.useState({
|
|
43595
|
-
const [
|
|
44004
|
+
const [underperformingWorkspaces, setUnderperformingWorkspaces] = React23.useState({});
|
|
44005
|
+
const [selectedShiftId, setSelectedShiftId] = React23.useState(0);
|
|
43596
44006
|
const [showLineDataNotFound, setShowLineDataNotFound] = React23.useState(false);
|
|
43597
44007
|
const navigation = useNavigation(navigate);
|
|
43598
44008
|
const handleNavigate = navigate || navigation.navigate;
|
|
@@ -43622,20 +44032,22 @@ var KPIDetailView = ({
|
|
|
43622
44032
|
setActiveTab("overview");
|
|
43623
44033
|
}
|
|
43624
44034
|
}, [urlDate, urlShift, urlTab]);
|
|
44035
|
+
const { shiftConfig, isLoading: isShiftConfigLoading } = useDynamicShiftConfig(lineId);
|
|
43625
44036
|
const getShiftName = React23.useCallback((shiftId) => {
|
|
43626
|
-
return shiftId
|
|
43627
|
-
}, []);
|
|
44037
|
+
return getShiftNameById(shiftId, configuredTimezone, shiftConfig);
|
|
44038
|
+
}, [configuredTimezone, shiftConfig]);
|
|
43628
44039
|
const getShiftIcon = React23.useCallback((shiftId) => {
|
|
43629
|
-
|
|
43630
|
-
if (shift === "Day") {
|
|
44040
|
+
if (shiftId === 0) {
|
|
43631
44041
|
return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" }) });
|
|
43632
|
-
}
|
|
44042
|
+
}
|
|
44043
|
+
if (shiftId === 1) {
|
|
43633
44044
|
return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z" }) });
|
|
43634
44045
|
}
|
|
43635
|
-
|
|
44046
|
+
return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" }) });
|
|
44047
|
+
}, []);
|
|
43636
44048
|
const getDaysDifference2 = React23.useCallback((date) => {
|
|
43637
44049
|
const compareDate = new Date(date);
|
|
43638
|
-
const shiftStartTime =
|
|
44050
|
+
const shiftStartTime = shiftConfig?.dayShift?.startTime || shiftConfig?.shifts?.[0]?.startTime || "06:00";
|
|
43639
44051
|
const operationalTodayString = getOperationalDate(configuredTimezone, /* @__PURE__ */ new Date(), shiftStartTime);
|
|
43640
44052
|
const operationalTodayDate = new Date(operationalTodayString);
|
|
43641
44053
|
const compareDateInZone = new Date(compareDate.toLocaleString("en-US", { timeZone: configuredTimezone }));
|
|
@@ -43649,7 +44061,7 @@ var KPIDetailView = ({
|
|
|
43649
44061
|
if (diffDays < -1) return `${Math.abs(diffDays)} days ago`;
|
|
43650
44062
|
if (diffDays > 1) return `${diffDays} days ahead`;
|
|
43651
44063
|
return "Today";
|
|
43652
|
-
}, [configuredTimezone,
|
|
44064
|
+
}, [configuredTimezone, shiftConfig]);
|
|
43653
44065
|
const {
|
|
43654
44066
|
metrics: metrics2,
|
|
43655
44067
|
lineDetails,
|
|
@@ -43659,7 +44071,9 @@ var KPIDetailView = ({
|
|
|
43659
44071
|
} = useRealtimeLineMetrics({
|
|
43660
44072
|
lineId,
|
|
43661
44073
|
date: typeof urlDate === "string" ? urlDate : void 0,
|
|
43662
|
-
shiftId: parsedShiftId
|
|
44074
|
+
shiftId: parsedShiftId,
|
|
44075
|
+
enabled: !isShiftConfigLoading
|
|
44076
|
+
// Pass enabled flag to useRealtimeLineMetrics if supported, or we need to add it
|
|
43663
44077
|
});
|
|
43664
44078
|
const {
|
|
43665
44079
|
workspaces,
|
|
@@ -43668,7 +44082,9 @@ var KPIDetailView = ({
|
|
|
43668
44082
|
refreshWorkspaces
|
|
43669
44083
|
} = useLineWorkspaceMetrics(lineId, {
|
|
43670
44084
|
initialDate: typeof urlDate === "string" ? urlDate : void 0,
|
|
43671
|
-
initialShiftId: parsedShiftId
|
|
44085
|
+
initialShiftId: parsedShiftId,
|
|
44086
|
+
enabled: !isShiftConfigLoading
|
|
44087
|
+
// Pass enabled flag to useLineWorkspaceMetrics if supported, or we need to add it
|
|
43672
44088
|
});
|
|
43673
44089
|
React23.useEffect(() => {
|
|
43674
44090
|
if (activeTab === "monthly_history" && lineId) {
|
|
@@ -43681,7 +44097,9 @@ var KPIDetailView = ({
|
|
|
43681
44097
|
dashboardService.getUnderperformingWorkspaces(
|
|
43682
44098
|
lineId,
|
|
43683
44099
|
currentMonth,
|
|
43684
|
-
currentYear
|
|
44100
|
+
currentYear,
|
|
44101
|
+
shiftConfig?.shifts?.map((s) => s.shiftId)
|
|
44102
|
+
// Pass dynamic shift IDs
|
|
43685
44103
|
)
|
|
43686
44104
|
]).then(([monthlyMetrics, underperformingData]) => {
|
|
43687
44105
|
console.log("Fetched monthly metrics data:", monthlyMetrics);
|
|
@@ -43693,18 +44111,8 @@ var KPIDetailView = ({
|
|
|
43693
44111
|
if (!dayData) {
|
|
43694
44112
|
dayData = {
|
|
43695
44113
|
date,
|
|
43696
|
-
|
|
43697
|
-
|
|
43698
|
-
underperforming_workspaces: 0,
|
|
43699
|
-
total_workspaces: 0,
|
|
43700
|
-
compliance_percentage: 0
|
|
43701
|
-
},
|
|
43702
|
-
nightShift: {
|
|
43703
|
-
avg_efficiency: 0,
|
|
43704
|
-
underperforming_workspaces: 0,
|
|
43705
|
-
total_workspaces: 0,
|
|
43706
|
-
compliance_percentage: 0
|
|
43707
|
-
}
|
|
44114
|
+
shifts: {}
|
|
44115
|
+
// Multi-shift structure: Record<number, ShiftData>
|
|
43708
44116
|
};
|
|
43709
44117
|
dayDataMap.set(dateKey, dayData);
|
|
43710
44118
|
}
|
|
@@ -43712,46 +44120,46 @@ var KPIDetailView = ({
|
|
|
43712
44120
|
avg_efficiency: metric.avg_efficiency || 0,
|
|
43713
44121
|
underperforming_workspaces: metric.underperforming_workspaces || 0,
|
|
43714
44122
|
total_workspaces: metric.total_workspaces || 0,
|
|
43715
|
-
compliance_percentage: 95 + Math.random() * 5
|
|
44123
|
+
compliance_percentage: 95 + Math.random() * 5,
|
|
43716
44124
|
// Mock data: random value between 95-100%
|
|
44125
|
+
hasData: true
|
|
43717
44126
|
};
|
|
43718
|
-
|
|
43719
|
-
dayData.dayShift = shiftData;
|
|
43720
|
-
} else {
|
|
43721
|
-
dayData.nightShift = shiftData;
|
|
43722
|
-
}
|
|
44127
|
+
dayData.shifts[metric.shift_id] = shiftData;
|
|
43723
44128
|
});
|
|
43724
44129
|
const transformedMonthlyData = Array.from(dayDataMap.values());
|
|
43725
44130
|
console.log("Transformed monthly data for calendar:", transformedMonthlyData);
|
|
43726
44131
|
setMonthlyData(transformedMonthlyData);
|
|
43727
|
-
const
|
|
43728
|
-
|
|
43729
|
-
|
|
43730
|
-
|
|
43731
|
-
|
|
43732
|
-
|
|
43733
|
-
|
|
43734
|
-
|
|
43735
|
-
performance_score: day.performance_score
|
|
43736
|
-
}))
|
|
43737
|
-
})),
|
|
43738
|
-
nightShift: (underperformingData.nightShift || []).map((ws) => ({
|
|
43739
|
-
workspace_name: ws.workspace_name || "Unknown Workspace",
|
|
43740
|
-
workspace_uuid: ws.workspace_uuid || ws.workspace_name || `unknown-${Math.random()}`,
|
|
43741
|
-
avg_efficiency: ws.avg_efficiency || 0,
|
|
43742
|
-
last_5_days: (ws.last_5_days || []).map((day) => ({
|
|
43743
|
-
date: day.date,
|
|
43744
|
-
efficiency: day.efficiency ?? 0,
|
|
43745
|
-
performance_score: day.performance_score
|
|
43746
|
-
}))
|
|
44132
|
+
const mapWorkspaces = (workspaces2) => (workspaces2 || []).map((ws) => ({
|
|
44133
|
+
workspace_name: ws.workspace_name || "Unknown Workspace",
|
|
44134
|
+
workspace_uuid: ws.workspace_uuid || ws.workspace_name || `unknown-${Math.random()}`,
|
|
44135
|
+
avg_efficiency: ws.avg_efficiency || 0,
|
|
44136
|
+
last_5_days: (ws.last_5_days || []).map((day) => ({
|
|
44137
|
+
date: day.date,
|
|
44138
|
+
efficiency: day.efficiency ?? 0,
|
|
44139
|
+
performance_score: day.performance_score
|
|
43747
44140
|
}))
|
|
43748
|
-
};
|
|
44141
|
+
}));
|
|
44142
|
+
const mappedData = {};
|
|
44143
|
+
if (underperformingData.dayShift) {
|
|
44144
|
+
mappedData[0] = mapWorkspaces(underperformingData.dayShift);
|
|
44145
|
+
}
|
|
44146
|
+
if (underperformingData.nightShift) {
|
|
44147
|
+
mappedData[1] = mapWorkspaces(underperformingData.nightShift);
|
|
44148
|
+
}
|
|
44149
|
+
Object.entries(underperformingData).forEach(([key, value]) => {
|
|
44150
|
+
if (key !== "dayShift" && key !== "nightShift" && Array.isArray(value)) {
|
|
44151
|
+
const shiftId = parseInt(key);
|
|
44152
|
+
if (!isNaN(shiftId)) {
|
|
44153
|
+
mappedData[shiftId] = mapWorkspaces(value);
|
|
44154
|
+
}
|
|
44155
|
+
}
|
|
44156
|
+
});
|
|
43749
44157
|
setUnderperformingWorkspaces(mappedData);
|
|
43750
44158
|
}).catch((error) => {
|
|
43751
44159
|
console.error("Error fetching monthly data:", error);
|
|
43752
44160
|
});
|
|
43753
44161
|
}
|
|
43754
|
-
}, [activeTab, lineId, currentMonth, currentYear, supabase, dashboardConfig]);
|
|
44162
|
+
}, [activeTab, lineId, currentMonth, currentYear, supabase, dashboardConfig, shiftConfig]);
|
|
43755
44163
|
const lineInfo = React23.useMemo(() => {
|
|
43756
44164
|
if (!metrics2 || !lineDetails || !lineDetails.factory) {
|
|
43757
44165
|
return null;
|
|
@@ -43996,7 +44404,7 @@ var KPIDetailView = ({
|
|
|
43996
44404
|
handleNavigate(backUrl);
|
|
43997
44405
|
}
|
|
43998
44406
|
}, [urlDate, urlShift, lineInfo, onBackClick, backLinkUrl, handleNavigate, urlMonth, urlYear, lineId, currentMonth, currentYear]);
|
|
43999
|
-
if ((lineMetricsLoading || workspacesLoading) && !lineInfo && !metrics2) {
|
|
44407
|
+
if ((lineMetricsLoading || workspacesLoading || isShiftConfigLoading) && !lineInfo && !metrics2) {
|
|
44000
44408
|
return /* @__PURE__ */ jsxRuntime.jsx(LoadingPage, { message: "Loading line metrics..." });
|
|
44001
44409
|
}
|
|
44002
44410
|
if (lineMetricsError || workspacesError) {
|
|
@@ -44103,7 +44511,10 @@ var KPIDetailView = ({
|
|
|
44103
44511
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "inline-flex items-center px-2.5 py-1 bg-gray-100 rounded-full", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-gray-700", children: metrics2 && formatLocalDate(new Date(metrics2.date)) }) }),
|
|
44104
44512
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "inline-flex items-center gap-1 px-2.5 py-1 bg-gray-100 rounded-full", children: [
|
|
44105
44513
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-gray-700 scale-90", children: getShiftIcon(metrics2.shift_id ?? 0) }),
|
|
44106
|
-
/* @__PURE__ */ jsxRuntime.
|
|
44514
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs font-medium text-gray-700", children: [
|
|
44515
|
+
getShiftName(metrics2.shift_id ?? 0).replace(/ Shift$/i, ""),
|
|
44516
|
+
" Shift"
|
|
44517
|
+
] })
|
|
44107
44518
|
] }),
|
|
44108
44519
|
!urlDate && !urlShift ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "inline-flex items-center px-2.5 py-1 bg-green-100 rounded-full", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-green-700", children: /* @__PURE__ */ jsxRuntime.jsx(ISTTimer_default, {}) }) }) : urlDate && metrics2.date ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "inline-flex items-center px-2.5 py-1 bg-blue-100 rounded-full", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-blue-700", children: getDaysDifference2(metrics2.date) }) }) : null
|
|
44109
44520
|
] }),
|
|
@@ -44121,7 +44532,7 @@ var KPIDetailView = ({
|
|
|
44121
44532
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
44122
44533
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-blue-600", children: getShiftIcon(metrics2.shift_id ?? 0) }),
|
|
44123
44534
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-sm md:text-base font-medium text-blue-600", children: [
|
|
44124
|
-
getShiftName(metrics2.shift_id ?? 0),
|
|
44535
|
+
getShiftName(metrics2.shift_id ?? 0).replace(/ Shift$/i, ""),
|
|
44125
44536
|
" Shift"
|
|
44126
44537
|
] })
|
|
44127
44538
|
] })
|
|
@@ -44166,7 +44577,7 @@ var KPIDetailView = ({
|
|
|
44166
44577
|
)
|
|
44167
44578
|
] }),
|
|
44168
44579
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center space-x-3 ml-auto", children: [
|
|
44169
|
-
lineInfo && activeTab === "overview" && /* @__PURE__ */ jsxRuntime.jsx(LinePdfGenerator, { lineInfo, workspaceData: workspaces || [] }),
|
|
44580
|
+
lineInfo && activeTab === "overview" && /* @__PURE__ */ jsxRuntime.jsx(LinePdfGenerator, { lineInfo, workspaceData: workspaces || [], shiftName: getShiftName(lineInfo.shift_id) }),
|
|
44170
44581
|
activeTab === "monthly_history" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
44171
44582
|
LineMonthlyPdfGenerator,
|
|
44172
44583
|
{
|
|
@@ -44176,7 +44587,7 @@ var KPIDetailView = ({
|
|
|
44176
44587
|
underperformingWorkspaces,
|
|
44177
44588
|
selectedMonth: currentMonth,
|
|
44178
44589
|
selectedYear: currentYear,
|
|
44179
|
-
|
|
44590
|
+
selectedShiftId
|
|
44180
44591
|
}
|
|
44181
44592
|
)
|
|
44182
44593
|
] })
|
|
@@ -44279,8 +44690,9 @@ var KPIDetailView = ({
|
|
|
44279
44690
|
monthlyData,
|
|
44280
44691
|
month: currentMonth,
|
|
44281
44692
|
year: currentYear,
|
|
44282
|
-
|
|
44283
|
-
onShiftChange:
|
|
44693
|
+
selectedShiftId,
|
|
44694
|
+
onShiftChange: setSelectedShiftId,
|
|
44695
|
+
availableShifts: shiftConfig?.shifts?.map((s) => ({ id: s.shiftId, name: s.shiftName }))
|
|
44284
44696
|
}
|
|
44285
44697
|
)
|
|
44286
44698
|
]
|
|
@@ -44431,7 +44843,8 @@ var KPIsOverviewView = ({
|
|
|
44431
44843
|
const dashboardConfig = useDashboardConfig();
|
|
44432
44844
|
const navigation = useNavigation(navigate);
|
|
44433
44845
|
const dateTimeConfig = useDateTimeConfig();
|
|
44434
|
-
const
|
|
44846
|
+
const representativeLineId = lineIds?.[0] || lines[0]?.id;
|
|
44847
|
+
const { shiftConfig, isLoading: isShiftConfigLoading } = useDynamicShiftConfig(representativeLineId);
|
|
44435
44848
|
const supervisorEnabled = dashboardConfig?.supervisorConfig?.enabled || false;
|
|
44436
44849
|
const dbTimezone = useAppTimezone();
|
|
44437
44850
|
const configuredTimezone = dbTimezone || dateTimeConfig.defaultTimezone || "UTC";
|
|
@@ -44493,15 +44906,21 @@ var KPIsOverviewView = ({
|
|
|
44493
44906
|
return date.toLocaleDateString("en-US", options);
|
|
44494
44907
|
};
|
|
44495
44908
|
const currentShiftDetails = getCurrentShift(configuredTimezone, shiftConfig);
|
|
44496
|
-
const shiftName = currentShiftDetails.
|
|
44909
|
+
const shiftName = (currentShiftDetails.shiftName || "Day").replace(/ Shift$/i, "");
|
|
44497
44910
|
const getShiftIcon = (shiftId) => {
|
|
44498
|
-
|
|
44911
|
+
const shiftNameLower = shiftName.toLowerCase();
|
|
44912
|
+
if (shiftNameLower.includes("day") || shiftNameLower.includes("morning") || shiftId === 0) {
|
|
44499
44913
|
return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" }) });
|
|
44500
|
-
}
|
|
44914
|
+
}
|
|
44915
|
+
if (shiftNameLower.includes("afternoon") || shiftNameLower.includes("noon") || shiftNameLower.includes("midday")) {
|
|
44916
|
+
return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" }) });
|
|
44917
|
+
}
|
|
44918
|
+
if (shiftNameLower.includes("night") || shiftNameLower.includes("evening") || shiftId === 1) {
|
|
44501
44919
|
return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z" }) });
|
|
44502
44920
|
}
|
|
44921
|
+
return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" }) });
|
|
44503
44922
|
};
|
|
44504
|
-
if (loading) {
|
|
44923
|
+
if (loading || isShiftConfigLoading) {
|
|
44505
44924
|
return /* @__PURE__ */ jsxRuntime.jsx(LoadingPage, { message: "Loading production lines..." });
|
|
44506
44925
|
}
|
|
44507
44926
|
if (error) {
|
|
@@ -44670,7 +45089,7 @@ var HeaderRibbon = React23.memo(({
|
|
|
44670
45089
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
44671
45090
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-blue-600", children: shiftIcon }),
|
|
44672
45091
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-sm md:text-base font-medium text-blue-600", children: [
|
|
44673
|
-
shiftName,
|
|
45092
|
+
shiftName.replace(/ Shift$/i, ""),
|
|
44674
45093
|
" Shift"
|
|
44675
45094
|
] })
|
|
44676
45095
|
] })
|
|
@@ -44797,6 +45216,7 @@ var LeaderboardDetailView = React23.memo(({
|
|
|
44797
45216
|
const navigation = useNavigation();
|
|
44798
45217
|
const entityConfig = useEntityConfig();
|
|
44799
45218
|
const [sortAscending, setSortAscending] = React23.useState(false);
|
|
45219
|
+
const timezone = useAppTimezone();
|
|
44800
45220
|
const [isMobile, setIsMobile] = React23.useState(false);
|
|
44801
45221
|
React23__namespace.default.useEffect(() => {
|
|
44802
45222
|
const checkMobile = () => setIsMobile(window.innerWidth < 640);
|
|
@@ -44825,6 +45245,9 @@ var LeaderboardDetailView = React23.memo(({
|
|
|
44825
45245
|
() => typeof shift === "number" ? shift : typeof shift === "string" ? parseInt(shift) : void 0,
|
|
44826
45246
|
[shift]
|
|
44827
45247
|
);
|
|
45248
|
+
const availableLineId = Object.keys(configuredLineNames)[0];
|
|
45249
|
+
const effectiveLineId = lineId || userAccessibleLineIds?.[0] || availableLineId;
|
|
45250
|
+
const { shiftConfig, isLoading: isShiftConfigLoading } = useDynamicShiftConfig(effectiveLineId);
|
|
44828
45251
|
const {
|
|
44829
45252
|
workspaces,
|
|
44830
45253
|
loading: workspacesLoading,
|
|
@@ -44833,20 +45256,31 @@ var LeaderboardDetailView = React23.memo(({
|
|
|
44833
45256
|
} = useAllWorkspaceMetrics({
|
|
44834
45257
|
initialDate: date,
|
|
44835
45258
|
initialShiftId: typeof shift === "number" ? shift : typeof shift === "string" ? parseInt(shift) : void 0,
|
|
44836
|
-
allowedLineIds: userAccessibleLineIds
|
|
45259
|
+
allowedLineIds: userAccessibleLineIds,
|
|
44837
45260
|
// Filter to user's accessible lines only
|
|
45261
|
+
enabled: !isShiftConfigLoading
|
|
45262
|
+
// Pass enabled flag
|
|
44838
45263
|
});
|
|
44839
45264
|
const getShiftName = React23.useCallback((shiftId2) => {
|
|
44840
|
-
if (shiftId2
|
|
44841
|
-
|
|
44842
|
-
|
|
45265
|
+
if (shiftId2 !== void 0) {
|
|
45266
|
+
return getShiftNameById(shiftId2, timezone || "Asia/Kolkata", shiftConfig);
|
|
45267
|
+
}
|
|
45268
|
+
const currentShift = getCurrentShift(timezone || "Asia/Kolkata", shiftConfig);
|
|
45269
|
+
return currentShift.shiftName || getShiftNameById(currentShift.shiftId, timezone || "Asia/Kolkata", shiftConfig);
|
|
45270
|
+
}, [timezone, shiftConfig]);
|
|
44843
45271
|
const getShiftIcon = React23.useCallback((shiftId2) => {
|
|
44844
|
-
const
|
|
44845
|
-
|
|
45272
|
+
const effectiveShiftId = shiftId2 !== void 0 ? shiftId2 : getCurrentShift(timezone || "Asia/Kolkata", shiftConfig).shiftId;
|
|
45273
|
+
const shiftNameLower = getShiftName(effectiveShiftId).toLowerCase();
|
|
45274
|
+
if (shiftNameLower.includes("day") || shiftNameLower.includes("morning")) {
|
|
44846
45275
|
return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" }) });
|
|
44847
|
-
}
|
|
45276
|
+
}
|
|
45277
|
+
if (shiftNameLower.includes("afternoon") || shiftNameLower.includes("noon") || shiftNameLower.includes("midday")) {
|
|
45278
|
+
return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" }) });
|
|
45279
|
+
}
|
|
45280
|
+
if (shiftNameLower.includes("night") || shiftNameLower.includes("evening")) {
|
|
44848
45281
|
return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z" }) });
|
|
44849
45282
|
}
|
|
45283
|
+
return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" }) });
|
|
44850
45284
|
}, [getShiftName]);
|
|
44851
45285
|
const formatDate = React23.useCallback((date2) => {
|
|
44852
45286
|
return new Intl.DateTimeFormat("en-US", {
|
|
@@ -44896,13 +45330,27 @@ var LeaderboardDetailView = React23.memo(({
|
|
|
44896
45330
|
});
|
|
44897
45331
|
const displayName = workspace.displayName || getWorkspaceDisplayName(workspace.workspace_name, workspace.line_id);
|
|
44898
45332
|
const navParams = workspace.workspace_uuid ? getWorkspaceNavigationParams(workspace.workspace_uuid, displayName, workspace.line_id) : "";
|
|
44899
|
-
const
|
|
45333
|
+
const contextParams = new URLSearchParams();
|
|
45334
|
+
if (date) {
|
|
45335
|
+
contextParams.set("date", date);
|
|
45336
|
+
}
|
|
45337
|
+
if (shiftId !== void 0) {
|
|
45338
|
+
contextParams.set("shift", shiftId.toString());
|
|
45339
|
+
}
|
|
45340
|
+
contextParams.set("returnTo", encodeURIComponent("/leaderboard"));
|
|
45341
|
+
const contextParamString = contextParams.toString();
|
|
44900
45342
|
if (onWorkspaceClick) {
|
|
44901
|
-
|
|
45343
|
+
const combinedParams = navParams ? `${navParams}&${contextParamString}` : `?${contextParamString}`;
|
|
45344
|
+
const enhancedWorkspace = {
|
|
45345
|
+
...workspace,
|
|
45346
|
+
navParams: combinedParams
|
|
45347
|
+
};
|
|
45348
|
+
onWorkspaceClick(enhancedWorkspace, rank);
|
|
44902
45349
|
} else {
|
|
44903
|
-
|
|
45350
|
+
const combinedParams = navParams ? `${navParams}&${contextParamString}` : `?${contextParamString}`;
|
|
45351
|
+
navigation.navigate(`/workspace/${workspace.workspace_uuid}${combinedParams}`);
|
|
44904
45352
|
}
|
|
44905
|
-
}, [onWorkspaceClick, navigation,
|
|
45353
|
+
}, [onWorkspaceClick, navigation, workspacesLength, date, shiftId]);
|
|
44906
45354
|
const workspaceDisplayData = React23.useMemo(() => {
|
|
44907
45355
|
if (!workspaces) return [];
|
|
44908
45356
|
return workspaces.map((ws) => ({
|
|
@@ -44918,7 +45366,7 @@ var LeaderboardDetailView = React23.memo(({
|
|
|
44918
45366
|
return sortAscending ? effA - effB : effB - effA;
|
|
44919
45367
|
});
|
|
44920
45368
|
}, [workspaceDisplayData, sortAscending]);
|
|
44921
|
-
const loading = workspacesLoading;
|
|
45369
|
+
const loading = workspacesLoading || isShiftConfigLoading;
|
|
44922
45370
|
const error = workspacesError;
|
|
44923
45371
|
const currentDateFormatted = React23.useMemo(() => {
|
|
44924
45372
|
const dateStr = (/* @__PURE__ */ new Date()).toDateString();
|
|
@@ -45763,14 +46211,28 @@ var ShiftsView = ({
|
|
|
45763
46211
|
try {
|
|
45764
46212
|
setLoading(true);
|
|
45765
46213
|
setError(null);
|
|
45766
|
-
const { data:
|
|
46214
|
+
const { data: enabledLines, error: linesError } = await supabase.from("lines").select("id, enable").in("id", lineIds).eq("enable", true);
|
|
46215
|
+
if (linesError) {
|
|
46216
|
+
console.error("Error fetching enabled lines:", linesError);
|
|
46217
|
+
showToast("error", "Error loading lines");
|
|
46218
|
+
setError("Failed to load lines");
|
|
46219
|
+
setLoading(false);
|
|
46220
|
+
return;
|
|
46221
|
+
}
|
|
46222
|
+
const enabledLineIds = (enabledLines || []).map((line) => line.id);
|
|
46223
|
+
if (enabledLineIds.length === 0) {
|
|
46224
|
+
setLineConfigs([]);
|
|
46225
|
+
setLoading(false);
|
|
46226
|
+
return;
|
|
46227
|
+
}
|
|
46228
|
+
const { data: dayShiftOperatingHours, error: dayShiftError } = await supabase.from("line_operating_hours").select("line_id, start_time, end_time, breaks").eq("shift_id", 0).in("line_id", enabledLineIds);
|
|
45767
46229
|
if (dayShiftError) {
|
|
45768
46230
|
console.error("Error fetching day shift operating hours:", dayShiftError);
|
|
45769
46231
|
showToast("error", "Error loading day shift data");
|
|
45770
46232
|
setError("Failed to load day shift data");
|
|
45771
46233
|
return;
|
|
45772
46234
|
}
|
|
45773
|
-
const { data: nightShiftOperatingHours, error: nightShiftError } = await supabase.from("line_operating_hours").select("line_id, start_time, end_time, breaks").eq("shift_id", 1).in("line_id",
|
|
46235
|
+
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", enabledLineIds);
|
|
45774
46236
|
if (nightShiftError) {
|
|
45775
46237
|
console.error("Error fetching night shift operating hours:", nightShiftError);
|
|
45776
46238
|
showToast("error", "Error loading night shift data");
|
|
@@ -45793,27 +46255,30 @@ var ShiftsView = ({
|
|
|
45793
46255
|
};
|
|
45794
46256
|
return map;
|
|
45795
46257
|
}, {});
|
|
45796
|
-
setLineConfigs((prev) =>
|
|
45797
|
-
const
|
|
45798
|
-
|
|
45799
|
-
|
|
45800
|
-
|
|
45801
|
-
newConfig
|
|
45802
|
-
|
|
45803
|
-
|
|
45804
|
-
|
|
45805
|
-
|
|
45806
|
-
|
|
45807
|
-
|
|
45808
|
-
|
|
45809
|
-
|
|
45810
|
-
|
|
45811
|
-
|
|
45812
|
-
|
|
45813
|
-
|
|
45814
|
-
|
|
45815
|
-
|
|
45816
|
-
|
|
46258
|
+
setLineConfigs((prev) => {
|
|
46259
|
+
const enabledConfigs = prev.filter((config) => enabledLineIds.includes(config.id));
|
|
46260
|
+
return enabledConfigs.map((config) => {
|
|
46261
|
+
const typedConfig = config;
|
|
46262
|
+
const lineId = typedConfig.id;
|
|
46263
|
+
const newConfig = { ...typedConfig };
|
|
46264
|
+
if (dayShiftHoursMap[lineId]) {
|
|
46265
|
+
newConfig.dayShift = {
|
|
46266
|
+
...newConfig.dayShift,
|
|
46267
|
+
...dayShiftHoursMap[lineId]
|
|
46268
|
+
};
|
|
46269
|
+
}
|
|
46270
|
+
if (nightShiftHoursMap[lineId]) {
|
|
46271
|
+
newConfig.nightShift = {
|
|
46272
|
+
...newConfig.nightShift,
|
|
46273
|
+
...nightShiftHoursMap[lineId]
|
|
46274
|
+
};
|
|
46275
|
+
}
|
|
46276
|
+
if (newConfig.isOpen === void 0) {
|
|
46277
|
+
newConfig.isOpen = getStoredLineState(lineId);
|
|
46278
|
+
}
|
|
46279
|
+
return newConfig;
|
|
46280
|
+
});
|
|
46281
|
+
});
|
|
45817
46282
|
setLoading(false);
|
|
45818
46283
|
} catch (error2) {
|
|
45819
46284
|
console.error("Error fetching shift configurations:", error2);
|
|
@@ -46991,6 +47456,10 @@ var TargetsViewUI = ({
|
|
|
46991
47456
|
savingLines,
|
|
46992
47457
|
saveSuccess,
|
|
46993
47458
|
selectedShift,
|
|
47459
|
+
shiftOptions = [
|
|
47460
|
+
{ id: 0, name: "Day Shift" },
|
|
47461
|
+
{ id: 1, name: "Night Shift" }
|
|
47462
|
+
],
|
|
46994
47463
|
isBulkConfigureOpen,
|
|
46995
47464
|
navItems = [],
|
|
46996
47465
|
currentPathname = "/targets",
|
|
@@ -47043,24 +47512,15 @@ var TargetsViewUI = ({
|
|
|
47043
47512
|
] }) }),
|
|
47044
47513
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 overflow-auto", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-4 sm:px-6 md:px-8 py-4 sm:py-5 md:py-6", children: [
|
|
47045
47514
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-4 sm:mb-6 bg-gradient-to-r from-blue-50 to-blue-50/50 p-3 sm:p-4 rounded-xl border border-blue-100", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs sm:text-sm text-blue-700 font-medium text-center sm:text-left", children: "Click on a line to expand and configure individual workspace targets." }) }),
|
|
47046
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-4 sm:mb-6 flex justify-center relative", children: /* @__PURE__ */ jsxRuntime.
|
|
47047
|
-
|
|
47048
|
-
|
|
47049
|
-
|
|
47050
|
-
|
|
47051
|
-
|
|
47052
|
-
|
|
47053
|
-
|
|
47054
|
-
|
|
47055
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
47056
|
-
"button",
|
|
47057
|
-
{
|
|
47058
|
-
onClick: () => onShiftChange(1),
|
|
47059
|
-
className: `flex-1 sm:flex-none px-3 sm:px-4 py-2 text-xs sm:text-sm font-medium rounded-md transition-all ${selectedShift === 1 ? "bg-white text-blue-600 shadow-sm" : "text-gray-600 hover:text-gray-900"}`,
|
|
47060
|
-
children: "Night Shift"
|
|
47061
|
-
}
|
|
47062
|
-
)
|
|
47063
|
-
] }) }),
|
|
47515
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-4 sm:mb-6 flex justify-center relative", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "inline-flex bg-gray-100 p-1 rounded-lg w-full max-w-xl sm:w-auto overflow-x-auto", children: shiftOptions.map((option) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
47516
|
+
"button",
|
|
47517
|
+
{
|
|
47518
|
+
onClick: () => onShiftChange(option.id),
|
|
47519
|
+
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"}`,
|
|
47520
|
+
children: option.name
|
|
47521
|
+
},
|
|
47522
|
+
option.id
|
|
47523
|
+
)) }) }),
|
|
47064
47524
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-6", children: Object.entries(lineWorkspaces).map(([lineId, line]) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
47065
47525
|
"div",
|
|
47066
47526
|
{
|
|
@@ -47365,7 +47825,7 @@ var TargetsView = ({
|
|
|
47365
47825
|
onSaveChanges
|
|
47366
47826
|
}) => {
|
|
47367
47827
|
const timezone = useAppTimezone();
|
|
47368
|
-
|
|
47828
|
+
React23.useMemo(() => {
|
|
47369
47829
|
return lineIds.reduce((acc, lineId) => ({
|
|
47370
47830
|
...acc,
|
|
47371
47831
|
[lineId]: {
|
|
@@ -47387,12 +47847,7 @@ var TargetsView = ({
|
|
|
47387
47847
|
[lineId]: getStoredLineState2(lineId)
|
|
47388
47848
|
}), {});
|
|
47389
47849
|
});
|
|
47390
|
-
const [allShiftsData, setAllShiftsData] = React23.useState({
|
|
47391
|
-
0: initialLineWorkspaces,
|
|
47392
|
-
// Day shift
|
|
47393
|
-
1: initialLineWorkspaces
|
|
47394
|
-
// Night shift (will be populated on first load)
|
|
47395
|
-
});
|
|
47850
|
+
const [allShiftsData, setAllShiftsData] = React23.useState({});
|
|
47396
47851
|
const [actionIds, setActionIds] = React23.useState(null);
|
|
47397
47852
|
const [savingLines, setSavingLines] = React23.useState(
|
|
47398
47853
|
() => lineIds.reduce((acc, id3) => ({ ...acc, [id3]: false }), {})
|
|
@@ -47404,10 +47859,11 @@ var TargetsView = ({
|
|
|
47404
47859
|
const [isBulkConfigureOpen, setIsBulkConfigureOpen] = React23.useState(false);
|
|
47405
47860
|
const [selectedWorkspaces, setSelectedWorkspaces] = React23.useState([]);
|
|
47406
47861
|
const [selectedShift, setSelectedShift] = React23.useState(0);
|
|
47862
|
+
const [shiftOptions, setShiftOptions] = React23.useState([]);
|
|
47407
47863
|
const canSaveTargets = useCanSaveTargets();
|
|
47408
47864
|
const [dbValues, setDbValues] = React23.useState({ 0: {}, 1: {} });
|
|
47409
47865
|
const [userEditedFields, setUserEditedFields] = React23.useState(/* @__PURE__ */ new Set());
|
|
47410
|
-
const lineWorkspaces = allShiftsData[selectedShift] ||
|
|
47866
|
+
const lineWorkspaces = allShiftsData[selectedShift] || {};
|
|
47411
47867
|
const setLineWorkspaces = React23.useCallback((updater) => {
|
|
47412
47868
|
setAllShiftsData((prev) => ({
|
|
47413
47869
|
...prev,
|
|
@@ -47436,12 +47892,28 @@ var TargetsView = ({
|
|
|
47436
47892
|
setIsLoading(true);
|
|
47437
47893
|
try {
|
|
47438
47894
|
const currentDate = getOperationalDate(timezone);
|
|
47895
|
+
const { data: shiftsData, error: shiftsError } = await supabase.from("line_operating_hours").select("line_id, shift_id, shift_name").in("line_id", lineIds);
|
|
47896
|
+
if (shiftsError) {
|
|
47897
|
+
console.warn("[TargetsView] Error fetching shift definitions, falling back to defaults", shiftsError);
|
|
47898
|
+
}
|
|
47899
|
+
const derivedShiftOptions = (shiftsData || []).reduce((acc, row) => {
|
|
47900
|
+
if (acc.some((s) => s.id === row.shift_id)) return acc;
|
|
47901
|
+
acc.push({ id: row.shift_id, name: row.shift_name || `Shift ${row.shift_id}` });
|
|
47902
|
+
return acc;
|
|
47903
|
+
}, []);
|
|
47904
|
+
const effectiveShiftOptions = derivedShiftOptions.length > 0 ? derivedShiftOptions.sort((a, b) => a.id - b.id) : [
|
|
47905
|
+
{ id: 0, name: "Day Shift" },
|
|
47906
|
+
{ id: 1, name: "Night Shift" }
|
|
47907
|
+
];
|
|
47908
|
+
setShiftOptions(effectiveShiftOptions);
|
|
47909
|
+
const defaultShiftId = effectiveShiftOptions[0].id;
|
|
47910
|
+
setSelectedShift(defaultShiftId);
|
|
47439
47911
|
const bulkResponse = await workspaceService.fetchBulkTargets({
|
|
47440
47912
|
companyId,
|
|
47441
47913
|
lineIds,
|
|
47442
47914
|
date: currentDate,
|
|
47443
|
-
shifts:
|
|
47444
|
-
// Fetch
|
|
47915
|
+
shifts: effectiveShiftOptions.map((s) => s.id),
|
|
47916
|
+
// Fetch all configured shifts
|
|
47445
47917
|
includeSkus: skuEnabled,
|
|
47446
47918
|
includeActions: true
|
|
47447
47919
|
});
|
|
@@ -47459,10 +47931,14 @@ var TargetsView = ({
|
|
|
47459
47931
|
packaging: packagingAction.id
|
|
47460
47932
|
};
|
|
47461
47933
|
setActionIds(actionIdsData);
|
|
47462
|
-
const newAllShiftsData = {
|
|
47463
|
-
const newDbValues = {
|
|
47934
|
+
const newAllShiftsData = {};
|
|
47935
|
+
const newDbValues = {};
|
|
47936
|
+
effectiveShiftOptions.forEach((opt) => {
|
|
47937
|
+
newAllShiftsData[opt.id] = {};
|
|
47938
|
+
newDbValues[opt.id] = {};
|
|
47939
|
+
});
|
|
47464
47940
|
Object.entries(data.lines).forEach(([lineId, lineData]) => {
|
|
47465
|
-
|
|
47941
|
+
effectiveShiftOptions.forEach(({ id: shiftId }) => {
|
|
47466
47942
|
const shiftData = lineData.shifts[shiftId.toString()];
|
|
47467
47943
|
if (!shiftData) {
|
|
47468
47944
|
console.warn(`No shift ${shiftId} data for line ${lineId}`);
|
|
@@ -47516,6 +47992,37 @@ var TargetsView = ({
|
|
|
47516
47992
|
newAllShiftsData[shiftId][lineId].workspaces = mappedWorkspaces;
|
|
47517
47993
|
});
|
|
47518
47994
|
});
|
|
47995
|
+
effectiveShiftOptions.forEach(({ id: shiftId }) => {
|
|
47996
|
+
lineIds.forEach((lineId) => {
|
|
47997
|
+
if (!newAllShiftsData[shiftId][lineId]) {
|
|
47998
|
+
const lineData = data.lines[lineId];
|
|
47999
|
+
const shift0Data = newAllShiftsData[0]?.[lineId];
|
|
48000
|
+
const enabledWorkspaces = lineData?.workspaces?.filter((ws) => ws.enable === true) || [];
|
|
48001
|
+
const workspaces = enabledWorkspaces.map((ws) => ({
|
|
48002
|
+
id: ws.id,
|
|
48003
|
+
name: ws.workspace_id,
|
|
48004
|
+
targetPPH: "",
|
|
48005
|
+
targetCycleTime: "",
|
|
48006
|
+
targetDayOutput: "",
|
|
48007
|
+
actionType: "assembly",
|
|
48008
|
+
actionId: actionIdsData.assembly
|
|
48009
|
+
})).sort(
|
|
48010
|
+
(a, b) => a.name.localeCompare(b.name, void 0, { numeric: true })
|
|
48011
|
+
);
|
|
48012
|
+
newAllShiftsData[shiftId][lineId] = {
|
|
48013
|
+
productId: "",
|
|
48014
|
+
shiftStartTime: shift0Data?.shiftStartTime || "08:00",
|
|
48015
|
+
shiftEndTime: shift0Data?.shiftEndTime || "19:00",
|
|
48016
|
+
shiftHours: shift0Data?.shiftHours || 11,
|
|
48017
|
+
breaks: shift0Data?.breaks || [],
|
|
48018
|
+
workspaces,
|
|
48019
|
+
factoryId: shift0Data?.factoryId || lineData?.line_info?.factory_id
|
|
48020
|
+
};
|
|
48021
|
+
newDbValues[shiftId][lineId] = {};
|
|
48022
|
+
console.log(`[TargetsView] Initialized empty data for shift ${shiftId}, line ${lineId}`);
|
|
48023
|
+
}
|
|
48024
|
+
});
|
|
48025
|
+
});
|
|
47519
48026
|
setAllShiftsData(newAllShiftsData);
|
|
47520
48027
|
setDbValues(newDbValues);
|
|
47521
48028
|
console.log("[TargetsView] Successfully loaded all data with bulk endpoint:", {
|
|
@@ -47633,7 +48140,7 @@ var TargetsView = ({
|
|
|
47633
48140
|
setUserEditedFields(/* @__PURE__ */ new Set());
|
|
47634
48141
|
if (dbValues[shiftId] && Object.keys(dbValues[shiftId]).length > 0) {
|
|
47635
48142
|
setAllShiftsData((prev) => {
|
|
47636
|
-
const updatedShiftData = { ...prev[shiftId] };
|
|
48143
|
+
const updatedShiftData = { ...prev[shiftId] || {} };
|
|
47637
48144
|
for (const lineId of Object.keys(updatedShiftData)) {
|
|
47638
48145
|
if (dbValues[shiftId][lineId]) {
|
|
47639
48146
|
updatedShiftData[lineId] = {
|
|
@@ -47662,20 +48169,27 @@ var TargetsView = ({
|
|
|
47662
48169
|
};
|
|
47663
48170
|
const handleActionTypeChange = React23.useCallback((lineId, workspaceId, newActionType) => {
|
|
47664
48171
|
if (!actionIds) return;
|
|
47665
|
-
setLineWorkspaces((prev) =>
|
|
47666
|
-
|
|
47667
|
-
|
|
47668
|
-
|
|
47669
|
-
|
|
47670
|
-
(ws) => ws.id === workspaceId ? {
|
|
47671
|
-
...ws,
|
|
47672
|
-
actionType: newActionType,
|
|
47673
|
-
actionId: actionIds[newActionType]
|
|
47674
|
-
} : ws
|
|
47675
|
-
)
|
|
48172
|
+
setLineWorkspaces((prev) => {
|
|
48173
|
+
const currentLineData = prev?.[lineId];
|
|
48174
|
+
if (!currentLineData?.workspaces) {
|
|
48175
|
+
console.warn(`[handleActionTypeChange] No data for line ${lineId} in current shift`);
|
|
48176
|
+
return prev;
|
|
47676
48177
|
}
|
|
47677
|
-
|
|
47678
|
-
|
|
48178
|
+
return {
|
|
48179
|
+
...prev,
|
|
48180
|
+
[lineId]: {
|
|
48181
|
+
...currentLineData,
|
|
48182
|
+
workspaces: currentLineData.workspaces.map(
|
|
48183
|
+
(ws) => ws.id === workspaceId ? {
|
|
48184
|
+
...ws,
|
|
48185
|
+
actionType: newActionType,
|
|
48186
|
+
actionId: actionIds[newActionType]
|
|
48187
|
+
} : ws
|
|
48188
|
+
)
|
|
48189
|
+
}
|
|
48190
|
+
};
|
|
48191
|
+
});
|
|
48192
|
+
}, [actionIds, setLineWorkspaces]);
|
|
47679
48193
|
const handleSaveLine = React23.useCallback(async (lineId) => {
|
|
47680
48194
|
console.log(`[handleSaveLine] Attempting to save line: ${lineId}`);
|
|
47681
48195
|
if (!canSaveTargets) {
|
|
@@ -47855,6 +48369,7 @@ var TargetsView = ({
|
|
|
47855
48369
|
savingLines,
|
|
47856
48370
|
saveSuccess,
|
|
47857
48371
|
selectedShift,
|
|
48372
|
+
shiftOptions,
|
|
47858
48373
|
isBulkConfigureOpen,
|
|
47859
48374
|
navItems: [],
|
|
47860
48375
|
currentPathname: "/targets",
|
|
@@ -47986,12 +48501,10 @@ var WorkspaceDetailView = ({
|
|
|
47986
48501
|
const today = new Date((/* @__PURE__ */ new Date()).toLocaleString("en-US", { timeZone: timezone }));
|
|
47987
48502
|
const [selectedMonth, setSelectedMonth] = React23.useState(today.getMonth());
|
|
47988
48503
|
const [selectedYear, setSelectedYear] = React23.useState(today.getFullYear());
|
|
47989
|
-
const [selectedShift, setSelectedShift] = React23.useState(
|
|
48504
|
+
const [selectedShift, setSelectedShift] = React23.useState(0);
|
|
47990
48505
|
React23.useEffect(() => {
|
|
47991
|
-
if (parsedShiftId
|
|
47992
|
-
setSelectedShift(
|
|
47993
|
-
} else if (parsedShiftId === 0) {
|
|
47994
|
-
setSelectedShift("day");
|
|
48506
|
+
if (parsedShiftId !== void 0) {
|
|
48507
|
+
setSelectedShift(parsedShiftId);
|
|
47995
48508
|
}
|
|
47996
48509
|
}, [parsedShiftId]);
|
|
47997
48510
|
const isHistoricView = Boolean(date && parsedShiftId !== void 0);
|
|
@@ -48003,6 +48516,13 @@ var WorkspaceDetailView = ({
|
|
|
48003
48516
|
const dashboardConfig = useDashboardConfig();
|
|
48004
48517
|
const isClipsEnabled = dashboardConfig?.clipsConfig?.enabled ?? true;
|
|
48005
48518
|
dashboardConfig?.supervisorConfig?.enabled || false;
|
|
48519
|
+
const effectiveLineId = lineId || selectedLineId;
|
|
48520
|
+
const { shiftConfig, isLoading: isShiftConfigLoading } = useDynamicShiftConfig(effectiveLineId);
|
|
48521
|
+
const calculatedOperationalDate = React23.useMemo(() => {
|
|
48522
|
+
if (isShiftConfigLoading || !shiftConfig) return null;
|
|
48523
|
+
const currentShift = getCurrentShift(timezone, shiftConfig);
|
|
48524
|
+
return currentShift.date;
|
|
48525
|
+
}, [isShiftConfigLoading, shiftConfig, timezone]);
|
|
48006
48526
|
const {
|
|
48007
48527
|
workspace: workspaceHealth,
|
|
48008
48528
|
loading: healthLoading,
|
|
@@ -48063,7 +48583,9 @@ var WorkspaceDetailView = ({
|
|
|
48063
48583
|
} = useHistoricWorkspaceMetrics(
|
|
48064
48584
|
workspaceId || "",
|
|
48065
48585
|
date || "",
|
|
48066
|
-
parsedShiftId
|
|
48586
|
+
parsedShiftId,
|
|
48587
|
+
{ shiftConfig, enabled: !isShiftConfigLoading }
|
|
48588
|
+
// Pass dynamic shift config and enabled flag
|
|
48067
48589
|
);
|
|
48068
48590
|
const {
|
|
48069
48591
|
metrics: liveMetrics,
|
|
@@ -48071,11 +48593,13 @@ var WorkspaceDetailView = ({
|
|
|
48071
48593
|
error: liveError
|
|
48072
48594
|
} = useWorkspaceDetailedMetrics(
|
|
48073
48595
|
workspaceId || "",
|
|
48074
|
-
getOperationalDate(timezone),
|
|
48075
|
-
void 0
|
|
48596
|
+
calculatedOperationalDate || getOperationalDate(timezone),
|
|
48597
|
+
void 0,
|
|
48598
|
+
{ shiftConfig, enabled: !isShiftConfigLoading }
|
|
48599
|
+
// Pass the dynamic shift config here and enabled flag
|
|
48076
48600
|
);
|
|
48077
48601
|
const workspace = isHistoricView ? historicMetrics : liveMetrics;
|
|
48078
|
-
const loading = isHistoricView ? historicLoading : liveLoading;
|
|
48602
|
+
const loading = (isHistoricView ? historicLoading : liveLoading) || isShiftConfigLoading;
|
|
48079
48603
|
const error = isHistoricView ? historicError : liveError;
|
|
48080
48604
|
const { supervisorName } = useLineSupervisor(workspace?.line_id || lineId);
|
|
48081
48605
|
React23.useEffect(() => {
|
|
@@ -48095,7 +48619,7 @@ var WorkspaceDetailView = ({
|
|
|
48095
48619
|
}, [isClipsEnabled, activeTab]);
|
|
48096
48620
|
React23.useEffect(() => {
|
|
48097
48621
|
if (liveMetrics && !date && !shift) {
|
|
48098
|
-
const currentDate = getOperationalDate(timezone);
|
|
48622
|
+
const currentDate = calculatedOperationalDate || getOperationalDate(timezone);
|
|
48099
48623
|
if (liveMetrics.date !== currentDate) {
|
|
48100
48624
|
setUsingFallbackData(true);
|
|
48101
48625
|
if (activeTab !== "monthly_history") {
|
|
@@ -48105,7 +48629,7 @@ var WorkspaceDetailView = ({
|
|
|
48105
48629
|
setUsingFallbackData(false);
|
|
48106
48630
|
}
|
|
48107
48631
|
}
|
|
48108
|
-
}, [liveMetrics, date, shift, activeTab]);
|
|
48632
|
+
}, [liveMetrics, date, shift, activeTab, calculatedOperationalDate]);
|
|
48109
48633
|
React23.useMemo(() => {
|
|
48110
48634
|
if (isHistoricView && date) {
|
|
48111
48635
|
try {
|
|
@@ -48113,11 +48637,11 @@ var WorkspaceDetailView = ({
|
|
|
48113
48637
|
return date;
|
|
48114
48638
|
} catch (e) {
|
|
48115
48639
|
console.error("Error parsing historic date:", e);
|
|
48116
|
-
return getOperationalDate(timezone);
|
|
48640
|
+
return calculatedOperationalDate || getOperationalDate(timezone);
|
|
48117
48641
|
}
|
|
48118
48642
|
}
|
|
48119
|
-
return getOperationalDate(timezone);
|
|
48120
|
-
}, [isHistoricView, date]);
|
|
48643
|
+
return calculatedOperationalDate || getOperationalDate(timezone);
|
|
48644
|
+
}, [isHistoricView, date, calculatedOperationalDate, timezone]);
|
|
48121
48645
|
const handleMonthlyDataLoaded = React23.useCallback((data) => {
|
|
48122
48646
|
console.log("[handleMonthlyDataLoaded] Received data:", {
|
|
48123
48647
|
dataLength: data?.length,
|
|
@@ -48141,10 +48665,8 @@ var WorkspaceDetailView = ({
|
|
|
48141
48665
|
if (!dayEntry) {
|
|
48142
48666
|
dayEntry = {
|
|
48143
48667
|
date: dateObj,
|
|
48144
|
-
|
|
48145
|
-
//
|
|
48146
|
-
nightShift: null
|
|
48147
|
-
// Start with null instead of zeros
|
|
48668
|
+
shifts: {}
|
|
48669
|
+
// Multi-shift structure: Record<number, CalendarShiftData>
|
|
48148
48670
|
};
|
|
48149
48671
|
dayDataMap.set(dateKey, dayEntry);
|
|
48150
48672
|
}
|
|
@@ -48156,19 +48678,14 @@ var WorkspaceDetailView = ({
|
|
|
48156
48678
|
pphThreshold: metric.pph_threshold || 0,
|
|
48157
48679
|
idealOutput: metric.ideal_output || 0,
|
|
48158
48680
|
rank: metric.workspace_rank || 0,
|
|
48159
|
-
idleTime: metric.idle_time || 0
|
|
48681
|
+
idleTime: metric.idle_time || 0,
|
|
48682
|
+
hasData: true
|
|
48160
48683
|
};
|
|
48161
|
-
|
|
48162
|
-
dayEntry.dayShift = shiftData;
|
|
48163
|
-
} else {
|
|
48164
|
-
dayEntry.nightShift = shiftData;
|
|
48165
|
-
}
|
|
48684
|
+
dayEntry.shifts[metric.shift_id] = shiftData;
|
|
48166
48685
|
});
|
|
48167
|
-
const processedData = Array.from(dayDataMap.values()).filter((entry) =>
|
|
48686
|
+
const processedData = Array.from(dayDataMap.values()).filter((entry) => Object.keys(entry.shifts).length > 0).map((entry) => ({
|
|
48168
48687
|
date: entry.date,
|
|
48169
|
-
|
|
48170
|
-
dayShift: entry.dayShift || { efficiency: 0, output: 0, cycleTime: 0, pph: 0, pphThreshold: 0, idealOutput: 0, rank: 0, idleTime: 0 },
|
|
48171
|
-
nightShift: entry.nightShift || { efficiency: 0, output: 0, cycleTime: 0, pph: 0, pphThreshold: 0, idealOutput: 0, rank: 0, idleTime: 0 }
|
|
48688
|
+
shifts: entry.shifts
|
|
48172
48689
|
}));
|
|
48173
48690
|
console.log(`[handleMonthlyDataLoaded] Transformed data for calendar:`, {
|
|
48174
48691
|
count: processedData.length,
|
|
@@ -48176,7 +48693,6 @@ var WorkspaceDetailView = ({
|
|
|
48176
48693
|
});
|
|
48177
48694
|
setMonthlyData(processedData);
|
|
48178
48695
|
}, []);
|
|
48179
|
-
const effectiveLineId = lineId || selectedLineId;
|
|
48180
48696
|
const formattedWorkspaceName = displayName || formatWorkspaceName3(workspace?.workspace_name || "", effectiveLineId);
|
|
48181
48697
|
const shouldShowCycleTimeChart = showCycleTimeChart ?? formattedWorkspaceName.startsWith("FINAL ASSY");
|
|
48182
48698
|
const handleBackNavigation = () => {
|
|
@@ -48197,7 +48713,7 @@ var WorkspaceDetailView = ({
|
|
|
48197
48713
|
if (onNavigate) {
|
|
48198
48714
|
const params = new URLSearchParams();
|
|
48199
48715
|
params.set("fromMonthly", "true");
|
|
48200
|
-
params.set("shift", selectedShift
|
|
48716
|
+
params.set("shift", selectedShift.toString());
|
|
48201
48717
|
if (effectiveLineId) {
|
|
48202
48718
|
params.set("lineId", effectiveLineId);
|
|
48203
48719
|
}
|
|
@@ -48209,7 +48725,7 @@ var WorkspaceDetailView = ({
|
|
|
48209
48725
|
if (onNavigate) {
|
|
48210
48726
|
const params = new URLSearchParams();
|
|
48211
48727
|
params.set("fromMonthly", "true");
|
|
48212
|
-
params.set("shift", selectedShift
|
|
48728
|
+
params.set("shift", selectedShift.toString());
|
|
48213
48729
|
if (effectiveLineId) {
|
|
48214
48730
|
params.set("lineId", effectiveLineId);
|
|
48215
48731
|
}
|
|
@@ -48223,10 +48739,15 @@ var WorkspaceDetailView = ({
|
|
|
48223
48739
|
}
|
|
48224
48740
|
};
|
|
48225
48741
|
const getShiftIcon = (shiftType) => {
|
|
48226
|
-
|
|
48742
|
+
const shiftTypeLower = shiftType?.toLowerCase() || "";
|
|
48743
|
+
if (shiftTypeLower.includes("day") || shiftTypeLower.includes("morning")) {
|
|
48227
48744
|
return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" }) });
|
|
48228
|
-
} else {
|
|
48745
|
+
} else if (shiftTypeLower.includes("afternoon") || shiftTypeLower.includes("noon") || shiftTypeLower.includes("midday")) {
|
|
48746
|
+
return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" }) });
|
|
48747
|
+
} else if (shiftTypeLower.includes("night") || shiftTypeLower.includes("evening")) {
|
|
48229
48748
|
return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z" }) });
|
|
48749
|
+
} else {
|
|
48750
|
+
return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" }) });
|
|
48230
48751
|
}
|
|
48231
48752
|
};
|
|
48232
48753
|
if (loading) {
|
|
@@ -48403,10 +48924,7 @@ var WorkspaceDetailView = ({
|
|
|
48403
48924
|
] }),
|
|
48404
48925
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
48405
48926
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-blue-600", children: getShiftIcon(workspace.shift_type) }),
|
|
48406
|
-
/* @__PURE__ */ jsxRuntime.
|
|
48407
|
-
workspace.shift_type,
|
|
48408
|
-
" Shift"
|
|
48409
|
-
] })
|
|
48927
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm md:text-base font-medium text-blue-600", children: workspace.shift_type })
|
|
48410
48928
|
] })
|
|
48411
48929
|
] }) })
|
|
48412
48930
|
] }),
|
|
@@ -48473,7 +48991,7 @@ var WorkspaceDetailView = ({
|
|
|
48473
48991
|
monthlyData,
|
|
48474
48992
|
selectedMonth,
|
|
48475
48993
|
selectedYear,
|
|
48476
|
-
selectedShift
|
|
48994
|
+
selectedShiftId: selectedShift
|
|
48477
48995
|
}
|
|
48478
48996
|
) })
|
|
48479
48997
|
] })
|
|
@@ -48742,15 +49260,16 @@ var WorkspaceDetailView = ({
|
|
|
48742
49260
|
month: selectedMonth,
|
|
48743
49261
|
year: selectedYear,
|
|
48744
49262
|
workspaceId,
|
|
48745
|
-
selectedShift,
|
|
49263
|
+
selectedShiftId: selectedShift,
|
|
48746
49264
|
monthlyDataLoading,
|
|
48747
|
-
|
|
49265
|
+
availableShifts: shiftConfig?.shifts?.map((s) => ({ id: s.shiftId, name: s.shiftName })),
|
|
49266
|
+
onDateSelect: (selectedDate, shiftId) => {
|
|
48748
49267
|
if (onDateSelect) {
|
|
48749
|
-
onDateSelect(selectedDate,
|
|
49268
|
+
onDateSelect(selectedDate, shiftId);
|
|
48750
49269
|
} else if (onNavigate) {
|
|
48751
49270
|
const params = new URLSearchParams();
|
|
48752
49271
|
params.set("date", selectedDate);
|
|
48753
|
-
params.set("shift",
|
|
49272
|
+
params.set("shift", shiftId.toString());
|
|
48754
49273
|
params.set("fromMonthly", "true");
|
|
48755
49274
|
if (effectiveLineId) {
|
|
48756
49275
|
params.set("lineId", effectiveLineId);
|
|
@@ -48773,6 +49292,7 @@ var WorkspaceDetailView = ({
|
|
|
48773
49292
|
workspaceId,
|
|
48774
49293
|
workspaceName: formattedWorkspaceName,
|
|
48775
49294
|
date,
|
|
49295
|
+
lineId: effectiveLineId,
|
|
48776
49296
|
shift,
|
|
48777
49297
|
totalOutput: workspace?.total_actions,
|
|
48778
49298
|
className: "h-[calc(100vh-10rem)]"
|
|
@@ -48929,6 +49449,13 @@ var SKUManagementView = () => {
|
|
|
48929
49449
|
var useWorkspaceHealth = (options) => {
|
|
48930
49450
|
const supabase = useSupabase();
|
|
48931
49451
|
const databaseConfig = useDatabaseConfig();
|
|
49452
|
+
const entityConfig = useEntityConfig();
|
|
49453
|
+
const configuredLineIds = React23.useMemo(() => getConfiguredLineIds(entityConfig), [entityConfig]);
|
|
49454
|
+
const firstConfiguredLineId = configuredLineIds[0];
|
|
49455
|
+
const isFactoryView = !options.lineId || options.lineId === (entityConfig?.factoryViewId || "factory");
|
|
49456
|
+
const effectiveLineIdForShiftConfig = isFactoryView ? firstConfiguredLineId : options.lineId;
|
|
49457
|
+
const { shiftConfig, isLoading: isShiftConfigLoading } = useDynamicShiftConfig(effectiveLineIdForShiftConfig);
|
|
49458
|
+
const timezone = useAppTimezone() || "UTC";
|
|
48932
49459
|
const [workspaces, setWorkspaces] = React23.useState([]);
|
|
48933
49460
|
const [summary, setSummary] = React23.useState({
|
|
48934
49461
|
totalWorkspaces: 0,
|
|
@@ -48975,6 +49502,14 @@ var useWorkspaceHealth = (options) => {
|
|
|
48975
49502
|
}, []);
|
|
48976
49503
|
const fetchWorkspacesHealth = React23.useCallback(async () => {
|
|
48977
49504
|
if (isFetchingRef.current) return;
|
|
49505
|
+
if (isShiftConfigLoading) {
|
|
49506
|
+
console.log("[useWorkspaceHealth] \u23F3 Waiting for shift config to load");
|
|
49507
|
+
return;
|
|
49508
|
+
}
|
|
49509
|
+
if (!shiftConfig) {
|
|
49510
|
+
console.warn("[useWorkspaceHealth] \u26A0\uFE0F Shift config is null, waiting for it to load");
|
|
49511
|
+
return;
|
|
49512
|
+
}
|
|
48978
49513
|
if (!options.companyId) {
|
|
48979
49514
|
setWorkspaces([]);
|
|
48980
49515
|
setSummary(computeSummary([]));
|
|
@@ -48985,9 +49520,16 @@ var useWorkspaceHealth = (options) => {
|
|
|
48985
49520
|
isFetchingRef.current = true;
|
|
48986
49521
|
setLoading(true);
|
|
48987
49522
|
setError(null);
|
|
49523
|
+
console.log("[useWorkspaceHealth] \u{1F680} Fetching health status with shift config:", {
|
|
49524
|
+
lineId: options.lineId,
|
|
49525
|
+
hasShiftConfig: !!shiftConfig,
|
|
49526
|
+
shiftId: shiftConfig?.shifts?.[0]?.shiftId
|
|
49527
|
+
});
|
|
48988
49528
|
const workspacesWithStatus = await workspaceHealthService.getWorkspaceHealthStatus({
|
|
48989
49529
|
lineId: options.lineId,
|
|
48990
|
-
companyId: options.companyId
|
|
49530
|
+
companyId: options.companyId,
|
|
49531
|
+
shiftConfig,
|
|
49532
|
+
timezone
|
|
48991
49533
|
});
|
|
48992
49534
|
setWorkspaces(workspacesWithStatus);
|
|
48993
49535
|
setSummary(computeSummary(workspacesWithStatus));
|
|
@@ -48999,7 +49541,7 @@ var useWorkspaceHealth = (options) => {
|
|
|
48999
49541
|
setLoading(false);
|
|
49000
49542
|
isFetchingRef.current = false;
|
|
49001
49543
|
}
|
|
49002
|
-
}, [options.companyId, options.lineId, computeSummary]);
|
|
49544
|
+
}, [options.companyId, options.lineId, computeSummary, shiftConfig, isShiftConfigLoading, timezone]);
|
|
49003
49545
|
React23.useEffect(() => {
|
|
49004
49546
|
fetchWorkspacesHealth();
|
|
49005
49547
|
}, [fetchWorkspacesHealth]);
|
|
@@ -49039,9 +49581,12 @@ var useWorkspaceHealth = (options) => {
|
|
|
49039
49581
|
return {
|
|
49040
49582
|
workspaces,
|
|
49041
49583
|
summary,
|
|
49042
|
-
loading,
|
|
49584
|
+
loading: loading || isShiftConfigLoading || !shiftConfig,
|
|
49043
49585
|
error,
|
|
49044
|
-
refetch: fetchWorkspacesHealth
|
|
49586
|
+
refetch: fetchWorkspacesHealth,
|
|
49587
|
+
// Expose shift config so consumers can pass it to child components
|
|
49588
|
+
shiftConfig,
|
|
49589
|
+
isShiftConfigLoading
|
|
49045
49590
|
};
|
|
49046
49591
|
};
|
|
49047
49592
|
var STATUS_COLORS = {
|
|
@@ -49240,7 +49785,8 @@ var formatTimeRange = (start, end, timezone) => {
|
|
|
49240
49785
|
var WorkspaceUptimeDetailModal = ({
|
|
49241
49786
|
workspace,
|
|
49242
49787
|
isOpen,
|
|
49243
|
-
onClose
|
|
49788
|
+
onClose,
|
|
49789
|
+
shiftConfig: passedShiftConfig
|
|
49244
49790
|
}) => {
|
|
49245
49791
|
const timezone = useAppTimezone() || "UTC";
|
|
49246
49792
|
const logsContainerRef = React23.useRef(null);
|
|
@@ -49254,7 +49800,12 @@ var WorkspaceUptimeDetailModal = ({
|
|
|
49254
49800
|
workspaceId: workspace?.workspace_id,
|
|
49255
49801
|
companyId: workspace?.company_id,
|
|
49256
49802
|
enabled: isOpen && Boolean(workspace?.workspace_id && workspace?.company_id),
|
|
49257
|
-
refreshInterval: 6e4
|
|
49803
|
+
refreshInterval: 6e4,
|
|
49804
|
+
lineId: workspace?.line_id,
|
|
49805
|
+
// Pass shift config from parent if available - avoids duplicate DB queries
|
|
49806
|
+
// and ensures consistent shift timing across the view
|
|
49807
|
+
shiftConfig: passedShiftConfig || void 0,
|
|
49808
|
+
timezone
|
|
49258
49809
|
});
|
|
49259
49810
|
React23.useEffect(() => {
|
|
49260
49811
|
if (!isOpen || !workspace) return;
|
|
@@ -49441,32 +49992,48 @@ var WorkspaceHealthView = ({
|
|
|
49441
49992
|
}) => {
|
|
49442
49993
|
const router$1 = router.useRouter();
|
|
49443
49994
|
const [groupBy, setGroupBy] = React23.useState("line");
|
|
49995
|
+
const entityConfig = useEntityConfig();
|
|
49996
|
+
const configuredLineIds = React23.useMemo(() => getConfiguredLineIds(entityConfig), [entityConfig]);
|
|
49997
|
+
const firstConfiguredLineId = configuredLineIds[0];
|
|
49998
|
+
const factoryViewId = entityConfig?.factoryViewId || "factory";
|
|
49999
|
+
const isFactoryView = !lineId || lineId === factoryViewId;
|
|
50000
|
+
const effectiveLineId = isFactoryView ? firstConfiguredLineId : lineId;
|
|
49444
50001
|
const timezone = useAppTimezone();
|
|
50002
|
+
const { shiftConfig, isLoading: isShiftConfigLoading } = useDynamicShiftConfig(effectiveLineId);
|
|
49445
50003
|
const [selectedWorkspace, setSelectedWorkspace] = React23.useState(null);
|
|
49446
|
-
const
|
|
49447
|
-
const
|
|
49448
|
-
const
|
|
49449
|
-
const shiftType =
|
|
50004
|
+
const effectiveTimezone = timezone || "UTC";
|
|
50005
|
+
const currentShiftDetails = getCurrentShift(effectiveTimezone, shiftConfig);
|
|
50006
|
+
const operationalDate = currentShiftDetails.date;
|
|
50007
|
+
const shiftType = (currentShiftDetails.shiftName || "Day").replace(/ Shift$/i, "");
|
|
49450
50008
|
const formatDate = (date) => {
|
|
49451
50009
|
const d = new Date(date);
|
|
49452
50010
|
return d.toLocaleDateString("en-IN", {
|
|
49453
50011
|
month: "long",
|
|
49454
50012
|
day: "numeric",
|
|
49455
50013
|
year: "numeric",
|
|
49456
|
-
timeZone:
|
|
50014
|
+
timeZone: effectiveTimezone
|
|
49457
50015
|
});
|
|
49458
50016
|
};
|
|
49459
|
-
const getShiftIcon = (
|
|
49460
|
-
|
|
50017
|
+
const getShiftIcon = () => {
|
|
50018
|
+
const shiftName = (currentShiftDetails.shiftName || "").toLowerCase();
|
|
50019
|
+
if (shiftName.includes("night") || shiftName.includes("evening") || currentShiftDetails.shiftId === 1) {
|
|
50020
|
+
return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Moon, { className: "h-4 w-4" });
|
|
50021
|
+
}
|
|
50022
|
+
if (shiftName.includes("afternoon") || shiftName.includes("noon") || shiftName.includes("midday")) {
|
|
50023
|
+
return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Sun, { className: "h-4 w-4" });
|
|
50024
|
+
}
|
|
50025
|
+
return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Sun, { className: "h-4 w-4" });
|
|
49461
50026
|
};
|
|
49462
50027
|
const {
|
|
49463
50028
|
workspaces,
|
|
49464
50029
|
summary,
|
|
49465
50030
|
loading,
|
|
49466
50031
|
error,
|
|
49467
|
-
refetch
|
|
50032
|
+
refetch,
|
|
50033
|
+
shiftConfig: loadedShiftConfig
|
|
50034
|
+
// Get shift config from the hook to pass to modal
|
|
49468
50035
|
} = useWorkspaceHealth({
|
|
49469
|
-
lineId,
|
|
50036
|
+
lineId: effectiveLineId,
|
|
49470
50037
|
companyId,
|
|
49471
50038
|
enableRealtime: true,
|
|
49472
50039
|
refreshInterval: 1e4
|
|
@@ -49528,7 +50095,7 @@ var WorkspaceHealthView = ({
|
|
|
49528
50095
|
if (percentage >= 90) return "text-yellow-600 dark:text-yellow-400";
|
|
49529
50096
|
return "text-red-600 dark:text-red-400";
|
|
49530
50097
|
};
|
|
49531
|
-
if (loading && !summary) {
|
|
50098
|
+
if (loading && !summary || isShiftConfigLoading) {
|
|
49532
50099
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-h-screen bg-gray-50 dark:bg-gray-900 p-4", children: /* @__PURE__ */ jsxRuntime.jsx(LoadingState, {}) });
|
|
49533
50100
|
}
|
|
49534
50101
|
if (error) {
|
|
@@ -49638,7 +50205,7 @@ var WorkspaceHealthView = ({
|
|
|
49638
50205
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs sm:text-sm md:text-base font-medium text-blue-600", children: formatDate(operationalDate) }),
|
|
49639
50206
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "hidden sm:block w-px h-4 bg-blue-300" }),
|
|
49640
50207
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1 sm:gap-2", children: [
|
|
49641
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-blue-600", children: getShiftIcon(
|
|
50208
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-blue-600", children: getShiftIcon() }),
|
|
49642
50209
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs sm:text-sm md:text-base font-medium text-blue-600", children: [
|
|
49643
50210
|
shiftType,
|
|
49644
50211
|
" Shift"
|
|
@@ -49726,7 +50293,8 @@ var WorkspaceHealthView = ({
|
|
|
49726
50293
|
{
|
|
49727
50294
|
workspace: selectedWorkspace,
|
|
49728
50295
|
isOpen: Boolean(selectedWorkspace),
|
|
49729
|
-
onClose: handleCloseDetails
|
|
50296
|
+
onClose: handleCloseDetails,
|
|
50297
|
+
shiftConfig: loadedShiftConfig
|
|
49730
50298
|
}
|
|
49731
50299
|
)
|
|
49732
50300
|
] });
|
|
@@ -51763,25 +52331,15 @@ var TeamManagementView_default = TeamManagementView;
|
|
|
51763
52331
|
function BottleneckClipsView({
|
|
51764
52332
|
workspaceId: propWorkspaceId,
|
|
51765
52333
|
workspaceName: propWorkspaceName,
|
|
52334
|
+
lineId: propLineId,
|
|
51766
52335
|
date: propDate,
|
|
51767
52336
|
shift: propShift,
|
|
51768
52337
|
totalOutput: propTotalOutput
|
|
51769
52338
|
}) {
|
|
51770
52339
|
const router$1 = router.useRouter();
|
|
51771
|
-
const dashboardConfig = useDashboardConfig();
|
|
51772
|
-
const timezone = useAppTimezone();
|
|
51773
52340
|
const workspaceId = propWorkspaceId || router$1.query.workspaceId;
|
|
51774
52341
|
const workspaceName = propWorkspaceName || router$1.query.workspaceName || "Workstation";
|
|
51775
|
-
const
|
|
51776
|
-
if (propDate) return propDate;
|
|
51777
|
-
return getOperationalDate(timezone || dashboardConfig.dateTimeConfig?.defaultTimezone || "UTC");
|
|
51778
|
-
}, [propDate, timezone, dashboardConfig]);
|
|
51779
|
-
const currentShift = React23.useMemo(() => {
|
|
51780
|
-
if (propShift !== void 0) return propShift;
|
|
51781
|
-
const tz = timezone || dashboardConfig.dateTimeConfig?.defaultTimezone || "UTC";
|
|
51782
|
-
const shiftResult = getCurrentShift(tz, dashboardConfig?.shiftConfig);
|
|
51783
|
-
return shiftResult.shiftId;
|
|
51784
|
-
}, [propShift, dashboardConfig, timezone]);
|
|
52342
|
+
const lineId = propLineId || router$1.query.lineId;
|
|
51785
52343
|
if (!workspaceId) {
|
|
51786
52344
|
return /* @__PURE__ */ jsxRuntime.jsx(LoadingPage_default, { message: "Loading workspace data..." });
|
|
51787
52345
|
}
|
|
@@ -51830,8 +52388,9 @@ function BottleneckClipsView({
|
|
|
51830
52388
|
{
|
|
51831
52389
|
workspaceId,
|
|
51832
52390
|
workspaceName,
|
|
51833
|
-
|
|
51834
|
-
|
|
52391
|
+
lineId,
|
|
52392
|
+
date: propDate,
|
|
52393
|
+
shift: propShift,
|
|
51835
52394
|
totalOutput: propTotalOutput,
|
|
51836
52395
|
className: "h-full"
|
|
51837
52396
|
}
|
|
@@ -53349,6 +53908,7 @@ exports.DEFAULT_ENDPOINTS_CONFIG = DEFAULT_ENDPOINTS_CONFIG;
|
|
|
53349
53908
|
exports.DEFAULT_ENTITY_CONFIG = DEFAULT_ENTITY_CONFIG;
|
|
53350
53909
|
exports.DEFAULT_MAP_VIEW_CONFIG = DEFAULT_MAP_VIEW_CONFIG;
|
|
53351
53910
|
exports.DEFAULT_SHIFT_CONFIG = DEFAULT_SHIFT_CONFIG;
|
|
53911
|
+
exports.DEFAULT_SHIFT_DATA = DEFAULT_SHIFT_DATA;
|
|
53352
53912
|
exports.DEFAULT_THEME_CONFIG = DEFAULT_THEME_CONFIG;
|
|
53353
53913
|
exports.DEFAULT_VIDEO_CONFIG = DEFAULT_VIDEO_CONFIG;
|
|
53354
53914
|
exports.DEFAULT_WORKSPACE_CONFIG = DEFAULT_WORKSPACE_CONFIG;
|
|
@@ -53532,6 +54092,7 @@ exports.getAllLineDisplayNames = getAllLineDisplayNames;
|
|
|
53532
54092
|
exports.getAllThreadMessages = getAllThreadMessages;
|
|
53533
54093
|
exports.getAllWorkspaceDisplayNamesAsync = getAllWorkspaceDisplayNamesAsync;
|
|
53534
54094
|
exports.getAnonClient = getAnonClient;
|
|
54095
|
+
exports.getAvailableShiftIds = getAvailableShiftIds;
|
|
53535
54096
|
exports.getBrowserName = getBrowserName;
|
|
53536
54097
|
exports.getCameraNumber = getCameraNumber;
|
|
53537
54098
|
exports.getCompanyMetricsTableName = getCompanyMetricsTableName;
|
|
@@ -53554,6 +54115,9 @@ exports.getNextUpdateInterval = getNextUpdateInterval;
|
|
|
53554
54115
|
exports.getOperationalDate = getOperationalDate;
|
|
53555
54116
|
exports.getS3SignedUrl = getS3SignedUrl;
|
|
53556
54117
|
exports.getS3VideoSrc = getS3VideoSrc;
|
|
54118
|
+
exports.getShiftData = getShiftData;
|
|
54119
|
+
exports.getShiftNameById = getShiftNameById;
|
|
54120
|
+
exports.getShortShiftName = getShortShiftName;
|
|
53557
54121
|
exports.getShortWorkspaceDisplayName = getShortWorkspaceDisplayName;
|
|
53558
54122
|
exports.getShortWorkspaceDisplayNameAsync = getShortWorkspaceDisplayNameAsync;
|
|
53559
54123
|
exports.getStoredWorkspaceMappings = getStoredWorkspaceMappings;
|
|
@@ -53566,6 +54130,7 @@ exports.getWorkspaceDisplayNameAsync = getWorkspaceDisplayNameAsync;
|
|
|
53566
54130
|
exports.getWorkspaceDisplayNamesMap = getWorkspaceDisplayNamesMap;
|
|
53567
54131
|
exports.getWorkspaceFromUrl = getWorkspaceFromUrl;
|
|
53568
54132
|
exports.getWorkspaceNavigationParams = getWorkspaceNavigationParams;
|
|
54133
|
+
exports.hasAnyShiftData = hasAnyShiftData;
|
|
53569
54134
|
exports.identifyCoreUser = identifyCoreUser;
|
|
53570
54135
|
exports.initializeCoreMixpanel = initializeCoreMixpanel;
|
|
53571
54136
|
exports.isLegacyConfiguration = isLegacyConfiguration;
|