@optifye/dashboard-core 6.9.13 → 6.9.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.css +16 -4
- package/dist/index.d.mts +432 -239
- package/dist/index.d.ts +432 -239
- package/dist/index.js +1457 -988
- package/dist/index.mjs +1453 -990
- package/package.json +1 -1
package/dist/index.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,14 +10093,24 @@ 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;
|
|
10103
|
+
}
|
|
10104
|
+
};
|
|
10105
|
+
const findActiveShift = (shifts, currentMinutes) => {
|
|
10106
|
+
for (const shift of shifts) {
|
|
10107
|
+
const startTime = shift.start_time || "00:00";
|
|
10108
|
+
const endTime = shift.end_time || "00:00";
|
|
10109
|
+
if (isTimeInShift(startTime, endTime, currentMinutes)) {
|
|
10110
|
+
return shift;
|
|
10111
|
+
}
|
|
9905
10112
|
}
|
|
10113
|
+
return null;
|
|
9906
10114
|
};
|
|
9907
10115
|
const checkActiveBreaks = React23.useCallback(async () => {
|
|
9908
10116
|
try {
|
|
@@ -9917,23 +10125,28 @@ var useActiveBreaks = (lineIds) => {
|
|
|
9917
10125
|
return;
|
|
9918
10126
|
}
|
|
9919
10127
|
const currentMinutes = getCurrentTimeInMinutes();
|
|
9920
|
-
const { data:
|
|
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) {
|
|
@@ -32528,7 +32882,7 @@ var ShiftDisplay = React23.memo(({ className, variant = "default", lineId }) =>
|
|
|
32528
32882
|
return null;
|
|
32529
32883
|
}
|
|
32530
32884
|
};
|
|
32531
|
-
const
|
|
32885
|
+
const getShiftIcon2 = (shift) => {
|
|
32532
32886
|
if (shift === "Day") {
|
|
32533
32887
|
return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ jsxRuntime.jsx("path", { fillRule: "evenodd", d: "M10 2a1 1 0 011 1v1a1 1 0 11-2 0V3a1 1 0 011-1zm4 8a4 4 0 11-8 0 4 4 0 018 0zm-.464 4.95l.707.707a1 1 0 001.414-1.414l-.707-.707a1 1 0 00-1.414 1.414zm2.12-10.607a1 1 0 010 1.414l-.706.707a1 1 0 11-1.414-1.414l.707-.707a1 1 0 011.414 0zM17 11a1 1 0 100-2h-1a1 1 0 100 2h1zm-7 4a1 1 0 011 1v1a1 1 0 11-2 0v-1a1 1 0 011-1zM5.05 6.464A1 1 0 106.465 5.05l-.708-.707a1 1 0 00-1.414 1.414l.707.707zm1.414 8.486l-.707.707a1 1 0 01-1.414-1.414l.707-.707a1 1 0 011.414 1.414zM4 11a1 1 0 100-2H3a1 1 0 000 2h1z", clipRule: "evenodd" }) });
|
|
32534
32888
|
} else {
|
|
@@ -32542,13 +32896,19 @@ var ShiftDisplay = React23.memo(({ className, variant = "default", lineId }) =>
|
|
|
32542
32896
|
setCurrentShiftText(getShiftInfo());
|
|
32543
32897
|
}, 1e3);
|
|
32544
32898
|
return () => clearInterval(interval);
|
|
32545
|
-
}, [dateTimeConfig?.defaultTimezone, shiftConfig]);
|
|
32899
|
+
}, [dateTimeConfig?.defaultTimezone, shiftConfig, isShiftConfigLoading]);
|
|
32900
|
+
if (isShiftConfigLoading) {
|
|
32901
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `inline-flex items-center gap-2 bg-gray-100 rounded-lg px-3 py-1.5 ${className ?? ""}`, children: [
|
|
32902
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-4 h-4 bg-gray-200 rounded animate-pulse" }),
|
|
32903
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-16 h-4 bg-gray-200 rounded animate-pulse" })
|
|
32904
|
+
] });
|
|
32905
|
+
}
|
|
32546
32906
|
if (!currentShiftText) {
|
|
32547
32907
|
return null;
|
|
32548
32908
|
}
|
|
32549
32909
|
if (variant === "enhanced") {
|
|
32550
32910
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `inline-flex items-center gap-2 bg-blue-50 rounded-lg px-3 py-1.5 ${className ?? ""}`, children: [
|
|
32551
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-blue-800", children:
|
|
32911
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-blue-800", children: getShiftIcon2(currentShiftText) }),
|
|
32552
32912
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-base font-medium text-blue-800", children: [
|
|
32553
32913
|
currentShiftText,
|
|
32554
32914
|
" Shift"
|
|
@@ -32556,7 +32916,7 @@ var ShiftDisplay = React23.memo(({ className, variant = "default", lineId }) =>
|
|
|
32556
32916
|
] });
|
|
32557
32917
|
}
|
|
32558
32918
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `inline-flex items-center gap-2 bg-blue-50 rounded-lg px-3 py-1.5 ${className ?? ""}`, children: [
|
|
32559
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-blue-800", children:
|
|
32919
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-blue-800", children: getShiftIcon2(currentShiftText) }),
|
|
32560
32920
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-base font-medium text-blue-800", children: [
|
|
32561
32921
|
currentShiftText,
|
|
32562
32922
|
" Shift"
|
|
@@ -33020,13 +33380,26 @@ var LinePdfExportButton = ({
|
|
|
33020
33380
|
}
|
|
33021
33381
|
);
|
|
33022
33382
|
};
|
|
33383
|
+
var DEFAULT_LINE_SHIFT_DATA = {
|
|
33384
|
+
avg_efficiency: 0,
|
|
33385
|
+
underperforming_workspaces: 0,
|
|
33386
|
+
total_workspaces: 0,
|
|
33387
|
+
hasData: false
|
|
33388
|
+
};
|
|
33389
|
+
var getLineShiftData = (day, shiftId) => {
|
|
33390
|
+
const shift = day.shifts[shiftId];
|
|
33391
|
+
if (shift) {
|
|
33392
|
+
return { ...shift, hasData: true };
|
|
33393
|
+
}
|
|
33394
|
+
return { ...DEFAULT_LINE_SHIFT_DATA };
|
|
33395
|
+
};
|
|
33023
33396
|
var WEEKDAYS = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
|
|
33024
33397
|
var LineHistoryCalendar = ({
|
|
33025
33398
|
data,
|
|
33026
33399
|
month,
|
|
33027
33400
|
year,
|
|
33028
33401
|
lineId,
|
|
33029
|
-
|
|
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
|
-
const
|
|
37016
|
-
const
|
|
37017
|
-
|
|
37417
|
+
const getShiftIcon2 = () => {
|
|
37418
|
+
const currentShift = getCurrentShift(timezone, shiftConfig);
|
|
37419
|
+
const shiftName = (currentShift.shiftName || "").toLowerCase();
|
|
37420
|
+
if (shiftName.includes("day") || shiftName.includes("morning") || currentShift.shiftId === 0) {
|
|
37018
37421
|
return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" }) });
|
|
37019
|
-
}
|
|
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.
|
|
37032
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-gray-500 sm:text-gray-600 scale-90 sm:scale-100", children:
|
|
37033
|
-
/* @__PURE__ */ jsxRuntime.
|
|
37034
|
-
|
|
37035
|
-
" Shift"
|
|
37036
|
-
] })
|
|
37037
|
-
] })
|
|
37439
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "inline-flex items-center gap-0.5 sm:gap-1", children: isShiftConfigLoading ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-4 w-16 sm:w-20 bg-gray-200 rounded animate-pulse" }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
37440
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-gray-500 sm:text-gray-600 scale-90 sm:scale-100", children: getShiftIcon2() }),
|
|
37441
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] sm:text-xs md:text-sm font-medium text-gray-500 sm:text-gray-600 whitespace-nowrap", children: getShiftName() })
|
|
37442
|
+
] }) })
|
|
37038
37443
|
] })
|
|
37039
37444
|
] }),
|
|
37040
37445
|
headerControls && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-1.5 sm:gap-3 md:gap-4 w-full sm:w-auto justify-end", children: headerControls })
|
|
@@ -42051,18 +42456,23 @@ var FactoryView = ({
|
|
|
42051
42456
|
fetchHourlyData();
|
|
42052
42457
|
}
|
|
42053
42458
|
}, [supabase, lineDataHooks, effectiveLineIds, lineNames, factoryName, timezone, shiftConfig, productIds]);
|
|
42459
|
+
const getCurrentShiftInfo = () => {
|
|
42460
|
+
return getCurrentShift(timezone, shiftConfig);
|
|
42461
|
+
};
|
|
42054
42462
|
const getShiftName = () => {
|
|
42055
|
-
const
|
|
42056
|
-
|
|
42057
|
-
return currentHour >= 6 && currentHour < 18 ? "Day" : "Night";
|
|
42463
|
+
const currentShift = getCurrentShiftInfo();
|
|
42464
|
+
return (currentShift.shiftName || "Day").replace(/ Shift$/i, "");
|
|
42058
42465
|
};
|
|
42059
|
-
const
|
|
42060
|
-
const
|
|
42061
|
-
|
|
42466
|
+
const getShiftIcon2 = () => {
|
|
42467
|
+
const currentShift = getCurrentShiftInfo();
|
|
42468
|
+
const shiftNameLower = (currentShift.shiftName || "").toLowerCase();
|
|
42469
|
+
if (shiftNameLower.includes("day") || shiftNameLower.includes("morning") || currentShift.shiftId === 0) {
|
|
42062
42470
|
return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" }) });
|
|
42063
|
-
}
|
|
42471
|
+
}
|
|
42472
|
+
if (shiftNameLower.includes("night") || shiftNameLower.includes("evening") || currentShift.shiftId === 1) {
|
|
42064
42473
|
return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z" }) });
|
|
42065
42474
|
}
|
|
42475
|
+
return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" }) });
|
|
42066
42476
|
};
|
|
42067
42477
|
if (loading || lineDataHooks.some((hookData) => hookData.hook.loading)) {
|
|
42068
42478
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-4", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "animate-pulse space-y-4", children: [
|
|
@@ -42091,7 +42501,7 @@ var FactoryView = ({
|
|
|
42091
42501
|
" IST"
|
|
42092
42502
|
] }),
|
|
42093
42503
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "inline-flex items-center gap-1", children: [
|
|
42094
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-gray-600", children:
|
|
42504
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-gray-600", children: getShiftIcon2() }),
|
|
42095
42505
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-sm font-medium text-gray-600", children: [
|
|
42096
42506
|
getShiftName(),
|
|
42097
42507
|
" Shift"
|
|
@@ -43591,8 +44001,8 @@ var KPIDetailView = ({
|
|
|
43591
44001
|
return (/* @__PURE__ */ new Date()).getFullYear();
|
|
43592
44002
|
});
|
|
43593
44003
|
const [monthlyData, setMonthlyData] = React23.useState([]);
|
|
43594
|
-
const [underperformingWorkspaces, setUnderperformingWorkspaces] = React23.useState({
|
|
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
|
-
}, []);
|
|
43628
|
-
const
|
|
43629
|
-
|
|
43630
|
-
if (shift === "Day") {
|
|
44037
|
+
return getShiftNameById(shiftId, configuredTimezone, shiftConfig);
|
|
44038
|
+
}, [configuredTimezone, shiftConfig]);
|
|
44039
|
+
const getShiftIcon2 = React23.useCallback((shiftId) => {
|
|
44040
|
+
if (shiftId === 0) {
|
|
43631
44041
|
return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" }) });
|
|
43632
|
-
}
|
|
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) {
|
|
@@ -44102,8 +44510,11 @@ var KPIDetailView = ({
|
|
|
44102
44510
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "sm:hidden mt-3 flex items-center justify-center gap-2", children: [
|
|
44103
44511
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "inline-flex items-center px-2.5 py-1 bg-gray-100 rounded-full", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-gray-700", children: metrics2 && formatLocalDate(new Date(metrics2.date)) }) }),
|
|
44104
44512
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "inline-flex items-center gap-1 px-2.5 py-1 bg-gray-100 rounded-full", children: [
|
|
44105
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-gray-700 scale-90", children:
|
|
44106
|
-
/* @__PURE__ */ jsxRuntime.
|
|
44513
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-gray-700 scale-90", children: getShiftIcon2(metrics2.shift_id ?? 0) }),
|
|
44514
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs font-medium text-gray-700", children: [
|
|
44515
|
+
getShiftName(metrics2.shift_id ?? 0).replace(/ Shift$/i, ""),
|
|
44516
|
+
" Shift"
|
|
44517
|
+
] })
|
|
44107
44518
|
] }),
|
|
44108
44519
|
!urlDate && !urlShift ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "inline-flex items-center px-2.5 py-1 bg-green-100 rounded-full", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-green-700", children: /* @__PURE__ */ jsxRuntime.jsx(ISTTimer_default, {}) }) }) : urlDate && metrics2.date ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "inline-flex items-center px-2.5 py-1 bg-blue-100 rounded-full", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-blue-700", children: getDaysDifference2(metrics2.date) }) }) : null
|
|
44109
44520
|
] }),
|
|
@@ -44119,9 +44530,9 @@ var KPIDetailView = ({
|
|
|
44119
44530
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-px h-4 bg-blue-300" })
|
|
44120
44531
|
] }),
|
|
44121
44532
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
44122
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-blue-600", children:
|
|
44533
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-blue-600", children: getShiftIcon2(metrics2.shift_id ?? 0) }),
|
|
44123
44534
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-sm md:text-base font-medium text-blue-600", children: [
|
|
44124
|
-
getShiftName(metrics2.shift_id ?? 0),
|
|
44535
|
+
getShiftName(metrics2.shift_id ?? 0).replace(/ Shift$/i, ""),
|
|
44125
44536
|
" Shift"
|
|
44126
44537
|
] })
|
|
44127
44538
|
] })
|
|
@@ -44166,7 +44577,7 @@ var KPIDetailView = ({
|
|
|
44166
44577
|
)
|
|
44167
44578
|
] }),
|
|
44168
44579
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center space-x-3 ml-auto", children: [
|
|
44169
|
-
lineInfo && activeTab === "overview" && /* @__PURE__ */ jsxRuntime.jsx(LinePdfGenerator, { lineInfo, workspaceData: workspaces || [] }),
|
|
44580
|
+
lineInfo && activeTab === "overview" && /* @__PURE__ */ jsxRuntime.jsx(LinePdfGenerator, { lineInfo, workspaceData: workspaces || [], shiftName: getShiftName(lineInfo.shift_id) }),
|
|
44170
44581
|
activeTab === "monthly_history" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
44171
44582
|
LineMonthlyPdfGenerator,
|
|
44172
44583
|
{
|
|
@@ -44176,7 +44587,7 @@ var KPIDetailView = ({
|
|
|
44176
44587
|
underperformingWorkspaces,
|
|
44177
44588
|
selectedMonth: currentMonth,
|
|
44178
44589
|
selectedYear: currentYear,
|
|
44179
|
-
|
|
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.
|
|
44497
|
-
const
|
|
44498
|
-
|
|
44909
|
+
const shiftName = (currentShiftDetails.shiftName || "Day").replace(/ Shift$/i, "");
|
|
44910
|
+
const getShiftIcon2 = (shiftId) => {
|
|
44911
|
+
const shiftNameLower = shiftName.toLowerCase();
|
|
44912
|
+
if (shiftNameLower.includes("day") || shiftNameLower.includes("morning") || shiftId === 0) {
|
|
44499
44913
|
return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" }) });
|
|
44500
|
-
}
|
|
44914
|
+
}
|
|
44915
|
+
if (shiftNameLower.includes("afternoon") || shiftNameLower.includes("noon") || shiftNameLower.includes("midday")) {
|
|
44916
|
+
return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" }) });
|
|
44917
|
+
}
|
|
44918
|
+
if (shiftNameLower.includes("night") || shiftNameLower.includes("evening") || shiftId === 1) {
|
|
44501
44919
|
return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z" }) });
|
|
44502
44920
|
}
|
|
44921
|
+
return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" }) });
|
|
44503
44922
|
};
|
|
44504
|
-
if (loading) {
|
|
44923
|
+
if (loading || isShiftConfigLoading) {
|
|
44505
44924
|
return /* @__PURE__ */ jsxRuntime.jsx(LoadingPage, { message: "Loading production lines..." });
|
|
44506
44925
|
}
|
|
44507
44926
|
if (error) {
|
|
@@ -44609,7 +45028,7 @@ var KPIsOverviewView = ({
|
|
|
44609
45028
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "sm:hidden mt-3 flex items-center justify-center gap-2", children: [
|
|
44610
45029
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "inline-flex items-center px-2.5 py-1 bg-gray-100 rounded-full", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-gray-700", children: formatLocalDate2(/* @__PURE__ */ new Date()) }) }),
|
|
44611
45030
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "inline-flex items-center gap-1 px-2.5 py-1 bg-gray-100 rounded-full", children: [
|
|
44612
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-gray-700 scale-90", children:
|
|
45031
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-gray-700 scale-90", children: getShiftIcon2(currentShiftDetails.shiftId) }),
|
|
44613
45032
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-gray-700", children: shiftName })
|
|
44614
45033
|
] }),
|
|
44615
45034
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "inline-flex items-center px-2.5 py-1 bg-green-100 rounded-full", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-green-700", children: /* @__PURE__ */ jsxRuntime.jsx(ISTTimer_default, {}) }) })
|
|
@@ -44620,7 +45039,7 @@ var KPIsOverviewView = ({
|
|
|
44620
45039
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm md:text-base font-medium text-blue-600", children: formatLocalDate2(/* @__PURE__ */ new Date()) }),
|
|
44621
45040
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-px h-4 bg-blue-300" }),
|
|
44622
45041
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
44623
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-blue-600", children:
|
|
45042
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-blue-600", children: getShiftIcon2(currentShiftDetails.shiftId) }),
|
|
44624
45043
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-sm md:text-base font-medium text-blue-600", children: [
|
|
44625
45044
|
shiftName,
|
|
44626
45045
|
" Shift"
|
|
@@ -44648,10 +45067,10 @@ var HeaderRibbon = React23.memo(({
|
|
|
44648
45067
|
currentDate,
|
|
44649
45068
|
currentMobileDate,
|
|
44650
45069
|
shiftId,
|
|
44651
|
-
getShiftIcon,
|
|
45070
|
+
getShiftIcon: getShiftIcon2,
|
|
44652
45071
|
getShiftName
|
|
44653
45072
|
}) => {
|
|
44654
|
-
const shiftIcon = React23.useMemo(() =>
|
|
45073
|
+
const shiftIcon = React23.useMemo(() => getShiftIcon2(shiftId), [getShiftIcon2, shiftId]);
|
|
44655
45074
|
const shiftName = React23.useMemo(() => getShiftName(shiftId), [getShiftName, shiftId]);
|
|
44656
45075
|
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
44657
45076
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "sm:hidden mt-3 flex items-center justify-center gap-2", children: [
|
|
@@ -44670,7 +45089,7 @@ var HeaderRibbon = React23.memo(({
|
|
|
44670
45089
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
44671
45090
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-blue-600", children: shiftIcon }),
|
|
44672
45091
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-sm md:text-base font-medium text-blue-600", children: [
|
|
44673
|
-
shiftName,
|
|
45092
|
+
shiftName.replace(/ Shift$/i, ""),
|
|
44674
45093
|
" Shift"
|
|
44675
45094
|
] })
|
|
44676
45095
|
] })
|
|
@@ -44797,6 +45216,7 @@ var LeaderboardDetailView = React23.memo(({
|
|
|
44797
45216
|
const navigation = useNavigation();
|
|
44798
45217
|
const entityConfig = useEntityConfig();
|
|
44799
45218
|
const [sortAscending, setSortAscending] = React23.useState(false);
|
|
45219
|
+
const timezone = useAppTimezone();
|
|
44800
45220
|
const [isMobile, setIsMobile] = React23.useState(false);
|
|
44801
45221
|
React23__namespace.default.useEffect(() => {
|
|
44802
45222
|
const checkMobile = () => setIsMobile(window.innerWidth < 640);
|
|
@@ -44825,6 +45245,9 @@ var LeaderboardDetailView = React23.memo(({
|
|
|
44825
45245
|
() => typeof shift === "number" ? shift : typeof shift === "string" ? parseInt(shift) : void 0,
|
|
44826
45246
|
[shift]
|
|
44827
45247
|
);
|
|
45248
|
+
const availableLineId = Object.keys(configuredLineNames)[0];
|
|
45249
|
+
const effectiveLineId = lineId || userAccessibleLineIds?.[0] || availableLineId;
|
|
45250
|
+
const { shiftConfig, isLoading: isShiftConfigLoading } = useDynamicShiftConfig(effectiveLineId);
|
|
44828
45251
|
const {
|
|
44829
45252
|
workspaces,
|
|
44830
45253
|
loading: workspacesLoading,
|
|
@@ -44833,20 +45256,31 @@ var LeaderboardDetailView = React23.memo(({
|
|
|
44833
45256
|
} = useAllWorkspaceMetrics({
|
|
44834
45257
|
initialDate: date,
|
|
44835
45258
|
initialShiftId: typeof shift === "number" ? shift : typeof shift === "string" ? parseInt(shift) : void 0,
|
|
44836
|
-
allowedLineIds: userAccessibleLineIds
|
|
45259
|
+
allowedLineIds: userAccessibleLineIds,
|
|
44837
45260
|
// Filter to user's accessible lines only
|
|
45261
|
+
enabled: !isShiftConfigLoading
|
|
45262
|
+
// Pass enabled flag
|
|
44838
45263
|
});
|
|
44839
45264
|
const getShiftName = React23.useCallback((shiftId2) => {
|
|
44840
|
-
if (shiftId2
|
|
44841
|
-
|
|
44842
|
-
|
|
44843
|
-
|
|
44844
|
-
|
|
44845
|
-
|
|
45265
|
+
if (shiftId2 !== void 0) {
|
|
45266
|
+
return getShiftNameById(shiftId2, timezone || "Asia/Kolkata", shiftConfig);
|
|
45267
|
+
}
|
|
45268
|
+
const currentShift = getCurrentShift(timezone || "Asia/Kolkata", shiftConfig);
|
|
45269
|
+
return currentShift.shiftName || getShiftNameById(currentShift.shiftId, timezone || "Asia/Kolkata", shiftConfig);
|
|
45270
|
+
}, [timezone, shiftConfig]);
|
|
45271
|
+
const getShiftIcon2 = React23.useCallback((shiftId2) => {
|
|
45272
|
+
const effectiveShiftId = shiftId2 !== void 0 ? shiftId2 : getCurrentShift(timezone || "Asia/Kolkata", shiftConfig).shiftId;
|
|
45273
|
+
const shiftNameLower = getShiftName(effectiveShiftId).toLowerCase();
|
|
45274
|
+
if (shiftNameLower.includes("day") || shiftNameLower.includes("morning")) {
|
|
44846
45275
|
return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" }) });
|
|
44847
|
-
}
|
|
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();
|
|
@@ -45030,7 +45478,7 @@ var LeaderboardDetailView = React23.memo(({
|
|
|
45030
45478
|
currentDate: currentDateFormatted,
|
|
45031
45479
|
currentMobileDate: currentMobileDateFormatted,
|
|
45032
45480
|
shiftId,
|
|
45033
|
-
getShiftIcon,
|
|
45481
|
+
getShiftIcon: getShiftIcon2,
|
|
45034
45482
|
getShiftName
|
|
45035
45483
|
}
|
|
45036
45484
|
)
|
|
@@ -45389,6 +45837,23 @@ var ProfileView = () => {
|
|
|
45389
45837
|
] }) });
|
|
45390
45838
|
};
|
|
45391
45839
|
var ProfileView_default = ProfileView;
|
|
45840
|
+
var DEFAULT_TIMEZONE = "Asia/Kolkata";
|
|
45841
|
+
var DEFAULT_SHIFTS = [
|
|
45842
|
+
{
|
|
45843
|
+
shiftId: 0,
|
|
45844
|
+
shiftName: "Day Shift",
|
|
45845
|
+
startTime: "08:00",
|
|
45846
|
+
endTime: "16:00",
|
|
45847
|
+
breaks: []
|
|
45848
|
+
},
|
|
45849
|
+
{
|
|
45850
|
+
shiftId: 1,
|
|
45851
|
+
shiftName: "Night Shift",
|
|
45852
|
+
startTime: "20:00",
|
|
45853
|
+
endTime: "04:00",
|
|
45854
|
+
breaks: []
|
|
45855
|
+
}
|
|
45856
|
+
];
|
|
45392
45857
|
var calculateShiftHours = (startTime, endTime, breaks = []) => {
|
|
45393
45858
|
if (!startTime || !endTime) return 8;
|
|
45394
45859
|
const [startHour, startMinute] = startTime.split(":").map(Number);
|
|
@@ -45455,6 +45920,19 @@ var formatBreaks = (breaks) => {
|
|
|
45455
45920
|
}))
|
|
45456
45921
|
};
|
|
45457
45922
|
};
|
|
45923
|
+
var getShiftIcon = (shiftId, shiftName) => {
|
|
45924
|
+
const nameLower = shiftName.toLowerCase();
|
|
45925
|
+
if (nameLower.includes("day") || nameLower.includes("morning") || shiftId === 0) {
|
|
45926
|
+
return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-5 h-5 text-gray-600", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" }) });
|
|
45927
|
+
}
|
|
45928
|
+
if (nameLower.includes("afternoon") || nameLower.includes("noon") || nameLower.includes("midday")) {
|
|
45929
|
+
return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-5 h-5 text-gray-600", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" }) });
|
|
45930
|
+
}
|
|
45931
|
+
if (nameLower.includes("night") || nameLower.includes("evening") || shiftId === 1) {
|
|
45932
|
+
return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-5 h-5 text-gray-600", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z" }) });
|
|
45933
|
+
}
|
|
45934
|
+
return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Clock, { className: "w-5 h-5 text-gray-600" });
|
|
45935
|
+
};
|
|
45458
45936
|
var BreakRow = React23.memo(({
|
|
45459
45937
|
break: breakItem,
|
|
45460
45938
|
onUpdate,
|
|
@@ -45582,9 +46060,13 @@ var ShiftPanel = React23.memo(({
|
|
|
45582
46060
|
onBreakUpdate,
|
|
45583
46061
|
onBreakRemove,
|
|
45584
46062
|
onBreakAdd,
|
|
45585
|
-
shiftHours
|
|
46063
|
+
shiftHours,
|
|
46064
|
+
shiftId,
|
|
46065
|
+
onShiftNameChange,
|
|
46066
|
+
canDelete = false,
|
|
46067
|
+
onDelete
|
|
45586
46068
|
}) => {
|
|
45587
|
-
const panelId = `panel-${title.toLowerCase().replace(/\s+/g, "-")}`;
|
|
46069
|
+
const panelId = `panel-${title.toLowerCase().replace(/\s+/g, "-")}-${shiftId ?? 0}`;
|
|
45588
46070
|
const storageKey = `shift_panel_${panelId}_minimized`;
|
|
45589
46071
|
const [isMinimized, setIsMinimized] = React23.useState(true);
|
|
45590
46072
|
React23.useEffect(() => {
|
|
@@ -45611,7 +46093,7 @@ var ShiftPanel = React23.memo(({
|
|
|
45611
46093
|
"button",
|
|
45612
46094
|
{
|
|
45613
46095
|
onClick: toggleMinimize,
|
|
45614
|
-
className: "flex items-center gap-2 sm:gap-3 text-base sm:text-lg font-medium transition-colors duration-200
|
|
46096
|
+
className: "flex items-center gap-2 sm:gap-3 text-base sm:text-lg font-medium transition-colors duration-200\n focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 rounded-lg\n hover:bg-blue-50 px-2 sm:px-3 py-1.5 sm:py-2 group w-full sm:w-auto justify-start",
|
|
45615
46097
|
"aria-expanded": !isMinimized,
|
|
45616
46098
|
"aria-controls": panelId,
|
|
45617
46099
|
children: [
|
|
@@ -45628,15 +46110,42 @@ var ShiftPanel = React23.memo(({
|
|
|
45628
46110
|
]
|
|
45629
46111
|
}
|
|
45630
46112
|
),
|
|
45631
|
-
/* @__PURE__ */ jsxRuntime.jsxs("
|
|
45632
|
-
"
|
|
45633
|
-
|
|
45634
|
-
|
|
46113
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 sm:gap-4", children: [
|
|
46114
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs sm:text-sm font-medium text-gray-600 text-center sm:text-right", children: [
|
|
46115
|
+
"Total Shift Hours: ",
|
|
46116
|
+
shiftHours,
|
|
46117
|
+
" hours"
|
|
46118
|
+
] }),
|
|
46119
|
+
canDelete && onDelete && /* @__PURE__ */ jsxRuntime.jsx(
|
|
46120
|
+
"button",
|
|
46121
|
+
{
|
|
46122
|
+
onClick: (e) => {
|
|
46123
|
+
e.stopPropagation();
|
|
46124
|
+
onDelete();
|
|
46125
|
+
},
|
|
46126
|
+
className: "p-1.5 text-gray-400 hover:text-red-500 hover:bg-red-50 rounded transition-colors",
|
|
46127
|
+
"aria-label": "Delete shift",
|
|
46128
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { className: "w-4 h-4" })
|
|
46129
|
+
}
|
|
46130
|
+
)
|
|
45635
46131
|
] })
|
|
45636
46132
|
] })
|
|
45637
46133
|
}
|
|
45638
46134
|
),
|
|
45639
46135
|
!isMinimized && /* @__PURE__ */ jsxRuntime.jsxs("div", { id: panelId, className: "p-3 sm:p-4 md:p-6 border-t border-gray-200 w-full bg-white", children: [
|
|
46136
|
+
onShiftNameChange && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-4 sm:mb-6", children: [
|
|
46137
|
+
/* @__PURE__ */ jsxRuntime.jsx("label", { className: "block text-xs sm:text-sm font-medium text-gray-700 mb-1", children: "Shift Name" }),
|
|
46138
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
46139
|
+
"input",
|
|
46140
|
+
{
|
|
46141
|
+
type: "text",
|
|
46142
|
+
value: title,
|
|
46143
|
+
onChange: (e) => onShiftNameChange(e.target.value),
|
|
46144
|
+
placeholder: "Enter shift name",
|
|
46145
|
+
className: "w-full sm:w-64 px-3 py-2 border border-gray-300 rounded-md text-sm focus:outline-none focus:ring-2 focus:ring-blue-500"
|
|
46146
|
+
}
|
|
46147
|
+
)
|
|
46148
|
+
] }),
|
|
45640
46149
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-1 sm:grid-cols-2 gap-3 sm:gap-4 md:gap-6 mb-4 sm:mb-6 w-full", children: [
|
|
45641
46150
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-full", children: [
|
|
45642
46151
|
/* @__PURE__ */ jsxRuntime.jsx("label", { className: "block text-xs sm:text-sm font-medium text-gray-700 mb-1", children: "Shift Start Time" }),
|
|
@@ -45730,16 +46239,9 @@ var ShiftsView = ({
|
|
|
45730
46239
|
() => lineIds.map((id3) => ({
|
|
45731
46240
|
id: id3,
|
|
45732
46241
|
name: lineNames[id3] || `Line ${id3.substring(0, 4)}`,
|
|
45733
|
-
|
|
45734
|
-
|
|
45735
|
-
|
|
45736
|
-
breaks: []
|
|
45737
|
-
},
|
|
45738
|
-
nightShift: {
|
|
45739
|
-
startTime: "20:00",
|
|
45740
|
-
endTime: "04:00",
|
|
45741
|
-
breaks: []
|
|
45742
|
-
},
|
|
46242
|
+
timezone: DEFAULT_TIMEZONE,
|
|
46243
|
+
shifts: DEFAULT_SHIFTS.map((s) => ({ ...s })),
|
|
46244
|
+
// Clone default shifts
|
|
45743
46245
|
isOpen: true,
|
|
45744
46246
|
isSaving: false,
|
|
45745
46247
|
saveSuccess: false
|
|
@@ -45763,60 +46265,47 @@ var ShiftsView = ({
|
|
|
45763
46265
|
try {
|
|
45764
46266
|
setLoading(true);
|
|
45765
46267
|
setError(null);
|
|
45766
|
-
const { data:
|
|
45767
|
-
if (
|
|
45768
|
-
console.error("Error fetching
|
|
45769
|
-
showToast("error", "Error loading
|
|
45770
|
-
setError("Failed to load
|
|
45771
|
-
return;
|
|
45772
|
-
}
|
|
45773
|
-
const { data: nightShiftOperatingHours, error: nightShiftError } = await supabase.from("line_operating_hours").select("line_id, start_time, end_time, breaks").eq("shift_id", 1).in("line_id", lineIds);
|
|
45774
|
-
if (nightShiftError) {
|
|
45775
|
-
console.error("Error fetching night shift operating hours:", nightShiftError);
|
|
45776
|
-
showToast("error", "Error loading night shift data");
|
|
45777
|
-
setError("Failed to load night shift data");
|
|
46268
|
+
const { data: allShiftsData, error: shiftsError } = await supabase.from("line_operating_hours").select("line_id, shift_id, shift_name, start_time, end_time, breaks, timezone").in("line_id", lineIds).order("shift_id", { ascending: true });
|
|
46269
|
+
if (shiftsError) {
|
|
46270
|
+
console.error("[ShiftsView] Error fetching shift configurations:", shiftsError);
|
|
46271
|
+
showToast("error", "Error loading shift data");
|
|
46272
|
+
setError("Failed to load shift data");
|
|
45778
46273
|
return;
|
|
45779
46274
|
}
|
|
45780
|
-
|
|
45781
|
-
|
|
45782
|
-
|
|
45783
|
-
|
|
45784
|
-
|
|
45785
|
-
|
|
45786
|
-
|
|
45787
|
-
|
|
45788
|
-
|
|
45789
|
-
|
|
45790
|
-
startTime:
|
|
45791
|
-
endTime:
|
|
45792
|
-
breaks: parseBreaksFromDB(
|
|
45793
|
-
|
|
45794
|
-
|
|
45795
|
-
|
|
45796
|
-
|
|
45797
|
-
const typedConfig = config;
|
|
45798
|
-
const lineId = typedConfig.id;
|
|
45799
|
-
const newConfig = { ...typedConfig };
|
|
45800
|
-
if (dayShiftHoursMap[lineId]) {
|
|
45801
|
-
newConfig.dayShift = {
|
|
45802
|
-
...newConfig.dayShift,
|
|
45803
|
-
...dayShiftHoursMap[lineId]
|
|
45804
|
-
};
|
|
45805
|
-
}
|
|
45806
|
-
if (nightShiftHoursMap[lineId]) {
|
|
45807
|
-
newConfig.nightShift = {
|
|
45808
|
-
...newConfig.nightShift,
|
|
45809
|
-
...nightShiftHoursMap[lineId]
|
|
45810
|
-
};
|
|
45811
|
-
}
|
|
45812
|
-
if (newConfig.isOpen === void 0) {
|
|
45813
|
-
newConfig.isOpen = getStoredLineState(lineId);
|
|
46275
|
+
console.log("[ShiftsView] Fetched shifts from DB:", allShiftsData);
|
|
46276
|
+
const shiftsByLine = {};
|
|
46277
|
+
const timezoneByLine = {};
|
|
46278
|
+
(allShiftsData || []).forEach((row) => {
|
|
46279
|
+
if (!shiftsByLine[row.line_id]) {
|
|
46280
|
+
shiftsByLine[row.line_id] = [];
|
|
46281
|
+
}
|
|
46282
|
+
shiftsByLine[row.line_id].push({
|
|
46283
|
+
shiftId: row.shift_id,
|
|
46284
|
+
shiftName: row.shift_name || `Shift ${row.shift_id}`,
|
|
46285
|
+
startTime: row.start_time || "08:00",
|
|
46286
|
+
endTime: row.end_time || "16:00",
|
|
46287
|
+
breaks: parseBreaksFromDB(row.breaks),
|
|
46288
|
+
timezone: row.timezone
|
|
46289
|
+
});
|
|
46290
|
+
if (row.timezone && !timezoneByLine[row.line_id]) {
|
|
46291
|
+
timezoneByLine[row.line_id] = row.timezone;
|
|
45814
46292
|
}
|
|
45815
|
-
|
|
46293
|
+
});
|
|
46294
|
+
setLineConfigs((prev) => prev.map((config) => {
|
|
46295
|
+
const lineId = config.id;
|
|
46296
|
+
const lineShifts = shiftsByLine[lineId];
|
|
46297
|
+
const lineTimezone = timezoneByLine[lineId] || DEFAULT_TIMEZONE;
|
|
46298
|
+
const shifts = lineShifts && lineShifts.length > 0 ? lineShifts.sort((a, b) => a.shiftId - b.shiftId) : DEFAULT_SHIFTS.map((s) => ({ ...s }));
|
|
46299
|
+
return {
|
|
46300
|
+
...config,
|
|
46301
|
+
timezone: lineTimezone,
|
|
46302
|
+
shifts,
|
|
46303
|
+
isOpen: config.isOpen ?? getStoredLineState(lineId)
|
|
46304
|
+
};
|
|
45816
46305
|
}));
|
|
45817
46306
|
setLoading(false);
|
|
45818
46307
|
} catch (error2) {
|
|
45819
|
-
console.error("Error fetching shift configurations:", error2);
|
|
46308
|
+
console.error("[ShiftsView] Error fetching shift configurations:", error2);
|
|
45820
46309
|
showToast("error", "Failed to load shift configurations");
|
|
45821
46310
|
setError("Failed to load shift configurations");
|
|
45822
46311
|
setLoading(false);
|
|
@@ -45826,195 +46315,125 @@ var ShiftsView = ({
|
|
|
45826
46315
|
}, [lineIds, showToast]);
|
|
45827
46316
|
React23.useCallback((lineId) => {
|
|
45828
46317
|
setLineConfigs((prev) => {
|
|
45829
|
-
const
|
|
45830
|
-
const newIsOpen = !typedPrev.find((config) => config.id === lineId)?.isOpen;
|
|
46318
|
+
const newIsOpen = !prev.find((config) => config.id === lineId)?.isOpen;
|
|
45831
46319
|
localStorage.setItem(`line_${lineId}_open`, JSON.stringify(newIsOpen));
|
|
45832
|
-
return
|
|
46320
|
+
return prev.map(
|
|
45833
46321
|
(config) => config.id === lineId ? { ...config, isOpen: newIsOpen } : config
|
|
45834
46322
|
);
|
|
45835
46323
|
});
|
|
45836
46324
|
}, []);
|
|
45837
|
-
const
|
|
45838
|
-
setLineConfigs((prev) => prev.map((config) => {
|
|
45839
|
-
const typedConfig = config;
|
|
45840
|
-
if (typedConfig.id === lineId) {
|
|
45841
|
-
const updatedDayShift = { ...typedConfig.dayShift, startTime: value };
|
|
45842
|
-
return {
|
|
45843
|
-
...typedConfig,
|
|
45844
|
-
dayShift: updatedDayShift
|
|
45845
|
-
};
|
|
45846
|
-
}
|
|
45847
|
-
return typedConfig;
|
|
45848
|
-
}));
|
|
45849
|
-
}, []);
|
|
45850
|
-
const updateDayShiftEndTime = React23.useCallback((lineId, value) => {
|
|
46325
|
+
const updateShiftTime = React23.useCallback((lineId, shiftId, field, value) => {
|
|
45851
46326
|
setLineConfigs((prev) => prev.map((config) => {
|
|
45852
|
-
|
|
45853
|
-
|
|
45854
|
-
|
|
45855
|
-
|
|
45856
|
-
|
|
45857
|
-
dayShift: updatedDayShift
|
|
45858
|
-
};
|
|
45859
|
-
}
|
|
45860
|
-
return typedConfig;
|
|
45861
|
-
}));
|
|
45862
|
-
}, []);
|
|
45863
|
-
const updateNightShiftStartTime = React23.useCallback((lineId, value) => {
|
|
45864
|
-
setLineConfigs((prev) => prev.map((config) => {
|
|
45865
|
-
const typedConfig = config;
|
|
45866
|
-
if (typedConfig.id === lineId) {
|
|
45867
|
-
const updatedNightShift = { ...typedConfig.nightShift, startTime: value };
|
|
45868
|
-
return {
|
|
45869
|
-
...typedConfig,
|
|
45870
|
-
nightShift: updatedNightShift
|
|
45871
|
-
};
|
|
46327
|
+
if (config.id === lineId) {
|
|
46328
|
+
const updatedShifts = config.shifts.map(
|
|
46329
|
+
(shift) => shift.shiftId === shiftId ? { ...shift, [field]: value } : shift
|
|
46330
|
+
);
|
|
46331
|
+
return { ...config, shifts: updatedShifts };
|
|
45872
46332
|
}
|
|
45873
|
-
return
|
|
46333
|
+
return config;
|
|
45874
46334
|
}));
|
|
45875
46335
|
}, []);
|
|
45876
|
-
const
|
|
46336
|
+
const updateShiftName = React23.useCallback((lineId, shiftId, value) => {
|
|
45877
46337
|
setLineConfigs((prev) => prev.map((config) => {
|
|
45878
|
-
|
|
45879
|
-
|
|
45880
|
-
|
|
45881
|
-
|
|
45882
|
-
|
|
45883
|
-
nightShift: updatedNightShift
|
|
45884
|
-
};
|
|
46338
|
+
if (config.id === lineId) {
|
|
46339
|
+
const updatedShifts = config.shifts.map(
|
|
46340
|
+
(shift) => shift.shiftId === shiftId ? { ...shift, shiftName: value } : shift
|
|
46341
|
+
);
|
|
46342
|
+
return { ...config, shifts: updatedShifts };
|
|
45885
46343
|
}
|
|
45886
|
-
return
|
|
46344
|
+
return config;
|
|
45887
46345
|
}));
|
|
45888
46346
|
}, []);
|
|
45889
|
-
|
|
45890
|
-
setLineConfigs((prev) => prev.map(
|
|
45891
|
-
|
|
45892
|
-
|
|
45893
|
-
const dayShift = { ...typedConfig.dayShift };
|
|
45894
|
-
const newBreak = {
|
|
45895
|
-
startTime: dayShift.startTime,
|
|
45896
|
-
endTime: dayShift.startTime,
|
|
45897
|
-
duration: 0,
|
|
45898
|
-
remarks: ""
|
|
45899
|
-
};
|
|
45900
|
-
return {
|
|
45901
|
-
...typedConfig,
|
|
45902
|
-
dayShift: {
|
|
45903
|
-
...dayShift,
|
|
45904
|
-
breaks: [...dayShift.breaks, newBreak]
|
|
45905
|
-
}
|
|
45906
|
-
};
|
|
45907
|
-
}
|
|
45908
|
-
return typedConfig;
|
|
45909
|
-
}));
|
|
46347
|
+
React23.useCallback((lineId, value) => {
|
|
46348
|
+
setLineConfigs((prev) => prev.map(
|
|
46349
|
+
(config) => config.id === lineId ? { ...config, timezone: value } : config
|
|
46350
|
+
));
|
|
45910
46351
|
}, []);
|
|
45911
|
-
const
|
|
46352
|
+
const addBreak = React23.useCallback((lineId, shiftId) => {
|
|
45912
46353
|
setLineConfigs((prev) => prev.map((config) => {
|
|
45913
|
-
|
|
45914
|
-
|
|
45915
|
-
|
|
45916
|
-
|
|
45917
|
-
|
|
45918
|
-
|
|
45919
|
-
|
|
45920
|
-
|
|
45921
|
-
|
|
45922
|
-
|
|
45923
|
-
nightShift: {
|
|
45924
|
-
...nightShift,
|
|
45925
|
-
breaks: [...nightShift.breaks, newBreak]
|
|
46354
|
+
if (config.id === lineId) {
|
|
46355
|
+
const updatedShifts = config.shifts.map((shift) => {
|
|
46356
|
+
if (shift.shiftId === shiftId) {
|
|
46357
|
+
const newBreak = {
|
|
46358
|
+
startTime: shift.startTime,
|
|
46359
|
+
endTime: shift.startTime,
|
|
46360
|
+
duration: 0,
|
|
46361
|
+
remarks: ""
|
|
46362
|
+
};
|
|
46363
|
+
return { ...shift, breaks: [...shift.breaks, newBreak] };
|
|
45926
46364
|
}
|
|
45927
|
-
|
|
46365
|
+
return shift;
|
|
46366
|
+
});
|
|
46367
|
+
return { ...config, shifts: updatedShifts };
|
|
45928
46368
|
}
|
|
45929
|
-
return
|
|
46369
|
+
return config;
|
|
45930
46370
|
}));
|
|
45931
46371
|
}, []);
|
|
45932
|
-
const
|
|
46372
|
+
const updateBreak = React23.useCallback((lineId, shiftId, breakIndex, field, value) => {
|
|
45933
46373
|
setLineConfigs((prev) => prev.map((config) => {
|
|
45934
|
-
|
|
45935
|
-
|
|
45936
|
-
|
|
45937
|
-
|
|
45938
|
-
|
|
45939
|
-
|
|
45940
|
-
|
|
45941
|
-
|
|
45942
|
-
|
|
45943
|
-
|
|
45944
|
-
|
|
45945
|
-
|
|
45946
|
-
}
|
|
45947
|
-
newBreaks[index].duration = endMinutes - startMinutes;
|
|
45948
|
-
}
|
|
45949
|
-
return {
|
|
45950
|
-
...typedConfig,
|
|
45951
|
-
dayShift: {
|
|
45952
|
-
...dayShift,
|
|
45953
|
-
breaks: newBreaks
|
|
46374
|
+
if (config.id === lineId) {
|
|
46375
|
+
const updatedShifts = config.shifts.map((shift) => {
|
|
46376
|
+
if (shift.shiftId === shiftId) {
|
|
46377
|
+
const newBreaks = [...shift.breaks];
|
|
46378
|
+
newBreaks[breakIndex] = { ...newBreaks[breakIndex], [field]: value };
|
|
46379
|
+
if (field === "startTime" || field === "endTime") {
|
|
46380
|
+
newBreaks[breakIndex].duration = calculateBreakDuration(
|
|
46381
|
+
newBreaks[breakIndex].startTime,
|
|
46382
|
+
newBreaks[breakIndex].endTime
|
|
46383
|
+
);
|
|
46384
|
+
}
|
|
46385
|
+
return { ...shift, breaks: newBreaks };
|
|
45954
46386
|
}
|
|
45955
|
-
|
|
46387
|
+
return shift;
|
|
46388
|
+
});
|
|
46389
|
+
return { ...config, shifts: updatedShifts };
|
|
45956
46390
|
}
|
|
45957
|
-
return
|
|
46391
|
+
return config;
|
|
45958
46392
|
}));
|
|
45959
46393
|
}, []);
|
|
45960
|
-
const
|
|
46394
|
+
const removeBreak = React23.useCallback((lineId, shiftId, breakIndex) => {
|
|
45961
46395
|
setLineConfigs((prev) => prev.map((config) => {
|
|
45962
|
-
|
|
45963
|
-
|
|
45964
|
-
|
|
45965
|
-
|
|
45966
|
-
newBreaks[index] = { ...newBreaks[index], [field]: value };
|
|
45967
|
-
if (field === "startTime" || field === "endTime") {
|
|
45968
|
-
const startParts = newBreaks[index].startTime.split(":").map(Number);
|
|
45969
|
-
const endParts = newBreaks[index].endTime.split(":").map(Number);
|
|
45970
|
-
let startMinutes = startParts[0] * 60 + startParts[1];
|
|
45971
|
-
let endMinutes = endParts[0] * 60 + endParts[1];
|
|
45972
|
-
if (endMinutes < startMinutes) {
|
|
45973
|
-
endMinutes += 24 * 60;
|
|
45974
|
-
}
|
|
45975
|
-
newBreaks[index].duration = endMinutes - startMinutes;
|
|
45976
|
-
}
|
|
45977
|
-
return {
|
|
45978
|
-
...typedConfig,
|
|
45979
|
-
nightShift: {
|
|
45980
|
-
...nightShift,
|
|
45981
|
-
breaks: newBreaks
|
|
46396
|
+
if (config.id === lineId) {
|
|
46397
|
+
const updatedShifts = config.shifts.map((shift) => {
|
|
46398
|
+
if (shift.shiftId === shiftId) {
|
|
46399
|
+
return { ...shift, breaks: shift.breaks.filter((_, i) => i !== breakIndex) };
|
|
45982
46400
|
}
|
|
45983
|
-
|
|
46401
|
+
return shift;
|
|
46402
|
+
});
|
|
46403
|
+
return { ...config, shifts: updatedShifts };
|
|
45984
46404
|
}
|
|
45985
|
-
return
|
|
46405
|
+
return config;
|
|
45986
46406
|
}));
|
|
45987
46407
|
}, []);
|
|
45988
|
-
|
|
46408
|
+
React23.useCallback((lineId) => {
|
|
45989
46409
|
setLineConfigs((prev) => prev.map((config) => {
|
|
45990
46410
|
if (config.id === lineId) {
|
|
45991
|
-
const
|
|
45992
|
-
|
|
45993
|
-
|
|
45994
|
-
|
|
45995
|
-
|
|
45996
|
-
|
|
45997
|
-
|
|
46411
|
+
const maxShiftId = Math.max(...config.shifts.map((s) => s.shiftId), -1);
|
|
46412
|
+
const newShiftId = maxShiftId + 1;
|
|
46413
|
+
const newShift = {
|
|
46414
|
+
shiftId: newShiftId,
|
|
46415
|
+
shiftName: `Shift ${newShiftId}`,
|
|
46416
|
+
startTime: "08:00",
|
|
46417
|
+
endTime: "16:00",
|
|
46418
|
+
breaks: []
|
|
45998
46419
|
};
|
|
46420
|
+
return { ...config, shifts: [...config.shifts, newShift] };
|
|
45999
46421
|
}
|
|
46000
46422
|
return config;
|
|
46001
46423
|
}));
|
|
46002
46424
|
}, []);
|
|
46003
|
-
const
|
|
46425
|
+
const removeShift = React23.useCallback((lineId, shiftId) => {
|
|
46004
46426
|
setLineConfigs((prev) => prev.map((config) => {
|
|
46005
46427
|
if (config.id === lineId) {
|
|
46006
|
-
|
|
46007
|
-
|
|
46008
|
-
|
|
46009
|
-
|
|
46010
|
-
|
|
46011
|
-
breaks: nightShift.breaks.filter((_, i) => i !== index)
|
|
46012
|
-
}
|
|
46013
|
-
};
|
|
46428
|
+
if (config.shifts.length <= 1) {
|
|
46429
|
+
showToast("error", "Cannot remove the last shift");
|
|
46430
|
+
return config;
|
|
46431
|
+
}
|
|
46432
|
+
return { ...config, shifts: config.shifts.filter((s) => s.shiftId !== shiftId) };
|
|
46014
46433
|
}
|
|
46015
46434
|
return config;
|
|
46016
46435
|
}));
|
|
46017
|
-
}, []);
|
|
46436
|
+
}, [showToast]);
|
|
46018
46437
|
const handleSaveShifts = React23.useCallback(async (lineId) => {
|
|
46019
46438
|
setLineConfigs((prev) => prev.map(
|
|
46020
46439
|
(config) => config.id === lineId ? { ...config, isSaving: true, saveSuccess: false } : config
|
|
@@ -46024,27 +46443,31 @@ var ShiftsView = ({
|
|
|
46024
46443
|
if (!lineConfig) {
|
|
46025
46444
|
throw new Error("Line configuration not found");
|
|
46026
46445
|
}
|
|
46027
|
-
|
|
46028
|
-
|
|
46029
|
-
|
|
46030
|
-
|
|
46031
|
-
|
|
46032
|
-
|
|
46033
|
-
|
|
46034
|
-
|
|
46035
|
-
|
|
46036
|
-
|
|
46037
|
-
|
|
46038
|
-
|
|
46039
|
-
|
|
46040
|
-
|
|
46041
|
-
|
|
46042
|
-
if (dayResult.error) {
|
|
46043
|
-
throw new Error(`Failed to save day shift: ${dayResult.error.message}`);
|
|
46446
|
+
console.log("[ShiftsView] Saving shifts for line:", lineId, lineConfig.shifts);
|
|
46447
|
+
for (const shift of lineConfig.shifts) {
|
|
46448
|
+
const shiftData = {
|
|
46449
|
+
line_id: lineId,
|
|
46450
|
+
shift_id: shift.shiftId,
|
|
46451
|
+
shift_name: shift.shiftName,
|
|
46452
|
+
start_time: shift.startTime,
|
|
46453
|
+
end_time: shift.endTime,
|
|
46454
|
+
breaks: formatBreaks(shift.breaks),
|
|
46455
|
+
timezone: lineConfig.timezone
|
|
46456
|
+
};
|
|
46457
|
+
const { error: upsertError } = await supabase.from("line_operating_hours").upsert(shiftData).select();
|
|
46458
|
+
if (upsertError) {
|
|
46459
|
+
throw new Error(`Failed to save shift ${shift.shiftId}: ${upsertError.message}`);
|
|
46460
|
+
}
|
|
46044
46461
|
}
|
|
46045
|
-
const
|
|
46046
|
-
|
|
46047
|
-
|
|
46462
|
+
const { data: existingShifts } = await supabase.from("line_operating_hours").select("shift_id").eq("line_id", lineId);
|
|
46463
|
+
const currentShiftIds = lineConfig.shifts.map((s) => s.shiftId);
|
|
46464
|
+
const shiftsToDelete = (existingShifts || []).filter((s) => !currentShiftIds.includes(s.shift_id)).map((s) => s.shift_id);
|
|
46465
|
+
if (shiftsToDelete.length > 0) {
|
|
46466
|
+
console.log("[ShiftsView] Deleting removed shifts:", shiftsToDelete);
|
|
46467
|
+
const { error: deleteError } = await supabase.from("line_operating_hours").delete().eq("line_id", lineId).in("shift_id", shiftsToDelete);
|
|
46468
|
+
if (deleteError) {
|
|
46469
|
+
console.error("[ShiftsView] Error deleting shifts:", deleteError);
|
|
46470
|
+
}
|
|
46048
46471
|
}
|
|
46049
46472
|
setLineConfigs((prev) => prev.map(
|
|
46050
46473
|
(config) => config.id === lineId ? { ...config, isSaving: false, saveSuccess: true } : config
|
|
@@ -46056,7 +46479,7 @@ var ShiftsView = ({
|
|
|
46056
46479
|
));
|
|
46057
46480
|
}, 3e3);
|
|
46058
46481
|
} catch (error2) {
|
|
46059
|
-
console.error("Error saving shift configurations:", error2);
|
|
46482
|
+
console.error("[ShiftsView] Error saving shift configurations:", error2);
|
|
46060
46483
|
showToast("error", "Failed to save shift configurations");
|
|
46061
46484
|
setLineConfigs((prev) => prev.map(
|
|
46062
46485
|
(config) => config.id === lineId ? { ...config, isSaving: false, saveSuccess: false } : config
|
|
@@ -46076,7 +46499,7 @@ var ShiftsView = ({
|
|
|
46076
46499
|
) }),
|
|
46077
46500
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 flex flex-col items-center mt-2 sm:mt-0", children: [
|
|
46078
46501
|
/* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-lg sm:text-xl md:text-2xl lg:text-3xl font-semibold text-gray-900 text-center", children: "Shift Management" }),
|
|
46079
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs sm:text-sm text-gray-500 mt-0.5 sm:mt-1 text-center px-2 sm:px-0", children: "Configure
|
|
46502
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs sm:text-sm text-gray-500 mt-0.5 sm:mt-1 text-center px-2 sm:px-0", children: "Configure shift timings and breaks for each production line" })
|
|
46080
46503
|
] }),
|
|
46081
46504
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "hidden sm:block absolute right-0 w-24" })
|
|
46082
46505
|
] }) }) }),
|
|
@@ -46096,6 +46519,11 @@ var ShiftsView = ({
|
|
|
46096
46519
|
/* @__PURE__ */ jsxRuntime.jsxs("h2", { className: "text-base sm:text-lg font-semibold text-gray-800", children: [
|
|
46097
46520
|
config.name,
|
|
46098
46521
|
" Shifts"
|
|
46522
|
+
] }),
|
|
46523
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-gray-400", children: [
|
|
46524
|
+
"(",
|
|
46525
|
+
config.shifts.length,
|
|
46526
|
+
" shifts)"
|
|
46099
46527
|
] })
|
|
46100
46528
|
] }),
|
|
46101
46529
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col sm:flex-row items-start sm:items-center gap-2 sm:gap-4 w-full sm:w-auto", children: [
|
|
@@ -46123,48 +46551,27 @@ var ShiftsView = ({
|
|
|
46123
46551
|
)
|
|
46124
46552
|
] })
|
|
46125
46553
|
] }) }),
|
|
46126
|
-
/* @__PURE__ */ jsxRuntime.
|
|
46127
|
-
|
|
46128
|
-
|
|
46129
|
-
|
|
46130
|
-
|
|
46131
|
-
|
|
46132
|
-
|
|
46133
|
-
|
|
46134
|
-
|
|
46135
|
-
|
|
46136
|
-
|
|
46137
|
-
|
|
46138
|
-
|
|
46139
|
-
|
|
46140
|
-
|
|
46141
|
-
|
|
46142
|
-
|
|
46143
|
-
|
|
46144
|
-
|
|
46145
|
-
|
|
46146
|
-
|
|
46147
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
46148
|
-
ShiftPanel,
|
|
46149
|
-
{
|
|
46150
|
-
title: "Night Shift",
|
|
46151
|
-
icon: /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-5 h-5 text-gray-600", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z" }) }),
|
|
46152
|
-
startTime: config.nightShift.startTime,
|
|
46153
|
-
endTime: config.nightShift.endTime,
|
|
46154
|
-
breaks: config.nightShift.breaks,
|
|
46155
|
-
onStartTimeChange: (value) => updateNightShiftStartTime(config.id, value),
|
|
46156
|
-
onEndTimeChange: (value) => updateNightShiftEndTime(config.id, value),
|
|
46157
|
-
onBreakUpdate: (index, field, value) => updateNightShiftBreak(config.id, index, field, value),
|
|
46158
|
-
onBreakRemove: (index) => removeNightShiftBreak(config.id, index),
|
|
46159
|
-
onBreakAdd: () => addNightShiftBreak(config.id),
|
|
46160
|
-
shiftHours: calculateShiftHours(
|
|
46161
|
-
config.nightShift.startTime,
|
|
46162
|
-
config.nightShift.endTime,
|
|
46163
|
-
config.nightShift.breaks
|
|
46164
|
-
)
|
|
46165
|
-
}
|
|
46166
|
-
)
|
|
46167
|
-
] })
|
|
46554
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { id: `shift-panel-${config.id}`, className: "p-3 sm:p-4 md:p-6 border-t border-gray-200 w-full", children: config.shifts.map((shift) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
46555
|
+
ShiftPanel,
|
|
46556
|
+
{
|
|
46557
|
+
title: shift.shiftName,
|
|
46558
|
+
icon: getShiftIcon(shift.shiftId, shift.shiftName),
|
|
46559
|
+
startTime: shift.startTime,
|
|
46560
|
+
endTime: shift.endTime,
|
|
46561
|
+
breaks: shift.breaks,
|
|
46562
|
+
onStartTimeChange: (value) => updateShiftTime(config.id, shift.shiftId, "startTime", value),
|
|
46563
|
+
onEndTimeChange: (value) => updateShiftTime(config.id, shift.shiftId, "endTime", value),
|
|
46564
|
+
onBreakUpdate: (index, field, value) => updateBreak(config.id, shift.shiftId, index, field, value),
|
|
46565
|
+
onBreakRemove: (index) => removeBreak(config.id, shift.shiftId, index),
|
|
46566
|
+
onBreakAdd: () => addBreak(config.id, shift.shiftId),
|
|
46567
|
+
shiftHours: calculateShiftHours(shift.startTime, shift.endTime, shift.breaks),
|
|
46568
|
+
shiftId: shift.shiftId,
|
|
46569
|
+
onShiftNameChange: (value) => updateShiftName(config.id, shift.shiftId, value),
|
|
46570
|
+
canDelete: config.shifts.length > 1,
|
|
46571
|
+
onDelete: () => removeShift(config.id, shift.shiftId)
|
|
46572
|
+
},
|
|
46573
|
+
`${config.id}-shift-${shift.shiftId}`
|
|
46574
|
+
)) })
|
|
46168
46575
|
] }, config.id)) })
|
|
46169
46576
|
] })
|
|
46170
46577
|
] });
|
|
@@ -46991,6 +47398,10 @@ var TargetsViewUI = ({
|
|
|
46991
47398
|
savingLines,
|
|
46992
47399
|
saveSuccess,
|
|
46993
47400
|
selectedShift,
|
|
47401
|
+
shiftOptions = [
|
|
47402
|
+
{ id: 0, name: "Day Shift" },
|
|
47403
|
+
{ id: 1, name: "Night Shift" }
|
|
47404
|
+
],
|
|
46994
47405
|
isBulkConfigureOpen,
|
|
46995
47406
|
navItems = [],
|
|
46996
47407
|
currentPathname = "/targets",
|
|
@@ -47043,24 +47454,15 @@ var TargetsViewUI = ({
|
|
|
47043
47454
|
] }) }),
|
|
47044
47455
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 overflow-auto", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-4 sm:px-6 md:px-8 py-4 sm:py-5 md:py-6", children: [
|
|
47045
47456
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-4 sm:mb-6 bg-gradient-to-r from-blue-50 to-blue-50/50 p-3 sm:p-4 rounded-xl border border-blue-100", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs sm:text-sm text-blue-700 font-medium text-center sm:text-left", children: "Click on a line to expand and configure individual workspace targets." }) }),
|
|
47046
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-4 sm:mb-6 flex justify-center relative", children: /* @__PURE__ */ jsxRuntime.
|
|
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
|
-
] }) }),
|
|
47457
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-4 sm:mb-6 flex justify-center relative", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "inline-flex bg-gray-100 p-1 rounded-lg w-full max-w-xl sm:w-auto overflow-x-auto", children: shiftOptions.map((option) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
47458
|
+
"button",
|
|
47459
|
+
{
|
|
47460
|
+
onClick: () => onShiftChange(option.id),
|
|
47461
|
+
className: `flex-1 sm:flex-none px-3 sm:px-4 py-2 text-xs sm:text-sm font-medium rounded-md transition-all whitespace-nowrap ${selectedShift === option.id ? "bg-white text-blue-600 shadow-sm" : "text-gray-600 hover:text-gray-900"}`,
|
|
47462
|
+
children: option.name
|
|
47463
|
+
},
|
|
47464
|
+
option.id
|
|
47465
|
+
)) }) }),
|
|
47064
47466
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-6", children: Object.entries(lineWorkspaces).map(([lineId, line]) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
47065
47467
|
"div",
|
|
47066
47468
|
{
|
|
@@ -47387,12 +47789,7 @@ var TargetsView = ({
|
|
|
47387
47789
|
[lineId]: getStoredLineState2(lineId)
|
|
47388
47790
|
}), {});
|
|
47389
47791
|
});
|
|
47390
|
-
const [allShiftsData, setAllShiftsData] = React23.useState({
|
|
47391
|
-
0: initialLineWorkspaces,
|
|
47392
|
-
// Day shift
|
|
47393
|
-
1: initialLineWorkspaces
|
|
47394
|
-
// Night shift (will be populated on first load)
|
|
47395
|
-
});
|
|
47792
|
+
const [allShiftsData, setAllShiftsData] = React23.useState({});
|
|
47396
47793
|
const [actionIds, setActionIds] = React23.useState(null);
|
|
47397
47794
|
const [savingLines, setSavingLines] = React23.useState(
|
|
47398
47795
|
() => lineIds.reduce((acc, id3) => ({ ...acc, [id3]: false }), {})
|
|
@@ -47404,6 +47801,7 @@ var TargetsView = ({
|
|
|
47404
47801
|
const [isBulkConfigureOpen, setIsBulkConfigureOpen] = React23.useState(false);
|
|
47405
47802
|
const [selectedWorkspaces, setSelectedWorkspaces] = React23.useState([]);
|
|
47406
47803
|
const [selectedShift, setSelectedShift] = React23.useState(0);
|
|
47804
|
+
const [shiftOptions, setShiftOptions] = React23.useState([]);
|
|
47407
47805
|
const canSaveTargets = useCanSaveTargets();
|
|
47408
47806
|
const [dbValues, setDbValues] = React23.useState({ 0: {}, 1: {} });
|
|
47409
47807
|
const [userEditedFields, setUserEditedFields] = React23.useState(/* @__PURE__ */ new Set());
|
|
@@ -47436,12 +47834,28 @@ var TargetsView = ({
|
|
|
47436
47834
|
setIsLoading(true);
|
|
47437
47835
|
try {
|
|
47438
47836
|
const currentDate = getOperationalDate(timezone);
|
|
47837
|
+
const { data: shiftsData, error: shiftsError } = await supabase.from("line_operating_hours").select("line_id, shift_id, shift_name").in("line_id", lineIds);
|
|
47838
|
+
if (shiftsError) {
|
|
47839
|
+
console.warn("[TargetsView] Error fetching shift definitions, falling back to defaults", shiftsError);
|
|
47840
|
+
}
|
|
47841
|
+
const derivedShiftOptions = (shiftsData || []).reduce((acc, row) => {
|
|
47842
|
+
if (acc.some((s) => s.id === row.shift_id)) return acc;
|
|
47843
|
+
acc.push({ id: row.shift_id, name: row.shift_name || `Shift ${row.shift_id}` });
|
|
47844
|
+
return acc;
|
|
47845
|
+
}, []);
|
|
47846
|
+
const effectiveShiftOptions = derivedShiftOptions.length > 0 ? derivedShiftOptions.sort((a, b) => a.id - b.id) : [
|
|
47847
|
+
{ id: 0, name: "Day Shift" },
|
|
47848
|
+
{ id: 1, name: "Night Shift" }
|
|
47849
|
+
];
|
|
47850
|
+
setShiftOptions(effectiveShiftOptions);
|
|
47851
|
+
const defaultShiftId = effectiveShiftOptions[0].id;
|
|
47852
|
+
setSelectedShift(defaultShiftId);
|
|
47439
47853
|
const bulkResponse = await workspaceService.fetchBulkTargets({
|
|
47440
47854
|
companyId,
|
|
47441
47855
|
lineIds,
|
|
47442
47856
|
date: currentDate,
|
|
47443
|
-
shifts:
|
|
47444
|
-
// Fetch
|
|
47857
|
+
shifts: effectiveShiftOptions.map((s) => s.id),
|
|
47858
|
+
// Fetch all configured shifts
|
|
47445
47859
|
includeSkus: skuEnabled,
|
|
47446
47860
|
includeActions: true
|
|
47447
47861
|
});
|
|
@@ -47459,10 +47873,14 @@ var TargetsView = ({
|
|
|
47459
47873
|
packaging: packagingAction.id
|
|
47460
47874
|
};
|
|
47461
47875
|
setActionIds(actionIdsData);
|
|
47462
|
-
const newAllShiftsData = {
|
|
47463
|
-
const newDbValues = {
|
|
47876
|
+
const newAllShiftsData = {};
|
|
47877
|
+
const newDbValues = {};
|
|
47878
|
+
effectiveShiftOptions.forEach((opt) => {
|
|
47879
|
+
newAllShiftsData[opt.id] = {};
|
|
47880
|
+
newDbValues[opt.id] = {};
|
|
47881
|
+
});
|
|
47464
47882
|
Object.entries(data.lines).forEach(([lineId, lineData]) => {
|
|
47465
|
-
|
|
47883
|
+
effectiveShiftOptions.forEach(({ id: shiftId }) => {
|
|
47466
47884
|
const shiftData = lineData.shifts[shiftId.toString()];
|
|
47467
47885
|
if (!shiftData) {
|
|
47468
47886
|
console.warn(`No shift ${shiftId} data for line ${lineId}`);
|
|
@@ -47633,7 +48051,7 @@ var TargetsView = ({
|
|
|
47633
48051
|
setUserEditedFields(/* @__PURE__ */ new Set());
|
|
47634
48052
|
if (dbValues[shiftId] && Object.keys(dbValues[shiftId]).length > 0) {
|
|
47635
48053
|
setAllShiftsData((prev) => {
|
|
47636
|
-
const updatedShiftData = { ...prev[shiftId] };
|
|
48054
|
+
const updatedShiftData = { ...prev[shiftId] || {} };
|
|
47637
48055
|
for (const lineId of Object.keys(updatedShiftData)) {
|
|
47638
48056
|
if (dbValues[shiftId][lineId]) {
|
|
47639
48057
|
updatedShiftData[lineId] = {
|
|
@@ -47855,6 +48273,7 @@ var TargetsView = ({
|
|
|
47855
48273
|
savingLines,
|
|
47856
48274
|
saveSuccess,
|
|
47857
48275
|
selectedShift,
|
|
48276
|
+
shiftOptions,
|
|
47858
48277
|
isBulkConfigureOpen,
|
|
47859
48278
|
navItems: [],
|
|
47860
48279
|
currentPathname: "/targets",
|
|
@@ -47986,12 +48405,10 @@ var WorkspaceDetailView = ({
|
|
|
47986
48405
|
const today = new Date((/* @__PURE__ */ new Date()).toLocaleString("en-US", { timeZone: timezone }));
|
|
47987
48406
|
const [selectedMonth, setSelectedMonth] = React23.useState(today.getMonth());
|
|
47988
48407
|
const [selectedYear, setSelectedYear] = React23.useState(today.getFullYear());
|
|
47989
|
-
const [selectedShift, setSelectedShift] = React23.useState(
|
|
48408
|
+
const [selectedShift, setSelectedShift] = React23.useState(0);
|
|
47990
48409
|
React23.useEffect(() => {
|
|
47991
|
-
if (parsedShiftId
|
|
47992
|
-
setSelectedShift(
|
|
47993
|
-
} else if (parsedShiftId === 0) {
|
|
47994
|
-
setSelectedShift("day");
|
|
48410
|
+
if (parsedShiftId !== void 0) {
|
|
48411
|
+
setSelectedShift(parsedShiftId);
|
|
47995
48412
|
}
|
|
47996
48413
|
}, [parsedShiftId]);
|
|
47997
48414
|
const isHistoricView = Boolean(date && parsedShiftId !== void 0);
|
|
@@ -48003,6 +48420,13 @@ var WorkspaceDetailView = ({
|
|
|
48003
48420
|
const dashboardConfig = useDashboardConfig();
|
|
48004
48421
|
const isClipsEnabled = dashboardConfig?.clipsConfig?.enabled ?? true;
|
|
48005
48422
|
dashboardConfig?.supervisorConfig?.enabled || false;
|
|
48423
|
+
const effectiveLineId = lineId || selectedLineId;
|
|
48424
|
+
const { shiftConfig, isLoading: isShiftConfigLoading } = useDynamicShiftConfig(effectiveLineId);
|
|
48425
|
+
const calculatedOperationalDate = React23.useMemo(() => {
|
|
48426
|
+
if (isShiftConfigLoading || !shiftConfig) return null;
|
|
48427
|
+
const currentShift = getCurrentShift(timezone, shiftConfig);
|
|
48428
|
+
return currentShift.date;
|
|
48429
|
+
}, [isShiftConfigLoading, shiftConfig, timezone]);
|
|
48006
48430
|
const {
|
|
48007
48431
|
workspace: workspaceHealth,
|
|
48008
48432
|
loading: healthLoading,
|
|
@@ -48063,7 +48487,9 @@ var WorkspaceDetailView = ({
|
|
|
48063
48487
|
} = useHistoricWorkspaceMetrics(
|
|
48064
48488
|
workspaceId || "",
|
|
48065
48489
|
date || "",
|
|
48066
|
-
parsedShiftId
|
|
48490
|
+
parsedShiftId,
|
|
48491
|
+
{ shiftConfig, enabled: !isShiftConfigLoading }
|
|
48492
|
+
// Pass dynamic shift config and enabled flag
|
|
48067
48493
|
);
|
|
48068
48494
|
const {
|
|
48069
48495
|
metrics: liveMetrics,
|
|
@@ -48071,11 +48497,13 @@ var WorkspaceDetailView = ({
|
|
|
48071
48497
|
error: liveError
|
|
48072
48498
|
} = useWorkspaceDetailedMetrics(
|
|
48073
48499
|
workspaceId || "",
|
|
48074
|
-
getOperationalDate(timezone),
|
|
48075
|
-
void 0
|
|
48500
|
+
calculatedOperationalDate || getOperationalDate(timezone),
|
|
48501
|
+
void 0,
|
|
48502
|
+
{ shiftConfig, enabled: !isShiftConfigLoading }
|
|
48503
|
+
// Pass the dynamic shift config here and enabled flag
|
|
48076
48504
|
);
|
|
48077
48505
|
const workspace = isHistoricView ? historicMetrics : liveMetrics;
|
|
48078
|
-
const loading = isHistoricView ? historicLoading : liveLoading;
|
|
48506
|
+
const loading = (isHistoricView ? historicLoading : liveLoading) || isShiftConfigLoading;
|
|
48079
48507
|
const error = isHistoricView ? historicError : liveError;
|
|
48080
48508
|
const { supervisorName } = useLineSupervisor(workspace?.line_id || lineId);
|
|
48081
48509
|
React23.useEffect(() => {
|
|
@@ -48095,7 +48523,7 @@ var WorkspaceDetailView = ({
|
|
|
48095
48523
|
}, [isClipsEnabled, activeTab]);
|
|
48096
48524
|
React23.useEffect(() => {
|
|
48097
48525
|
if (liveMetrics && !date && !shift) {
|
|
48098
|
-
const currentDate = getOperationalDate(timezone);
|
|
48526
|
+
const currentDate = calculatedOperationalDate || getOperationalDate(timezone);
|
|
48099
48527
|
if (liveMetrics.date !== currentDate) {
|
|
48100
48528
|
setUsingFallbackData(true);
|
|
48101
48529
|
if (activeTab !== "monthly_history") {
|
|
@@ -48105,7 +48533,7 @@ var WorkspaceDetailView = ({
|
|
|
48105
48533
|
setUsingFallbackData(false);
|
|
48106
48534
|
}
|
|
48107
48535
|
}
|
|
48108
|
-
}, [liveMetrics, date, shift, activeTab]);
|
|
48536
|
+
}, [liveMetrics, date, shift, activeTab, calculatedOperationalDate]);
|
|
48109
48537
|
React23.useMemo(() => {
|
|
48110
48538
|
if (isHistoricView && date) {
|
|
48111
48539
|
try {
|
|
@@ -48113,11 +48541,11 @@ var WorkspaceDetailView = ({
|
|
|
48113
48541
|
return date;
|
|
48114
48542
|
} catch (e) {
|
|
48115
48543
|
console.error("Error parsing historic date:", e);
|
|
48116
|
-
return getOperationalDate(timezone);
|
|
48544
|
+
return calculatedOperationalDate || getOperationalDate(timezone);
|
|
48117
48545
|
}
|
|
48118
48546
|
}
|
|
48119
|
-
return getOperationalDate(timezone);
|
|
48120
|
-
}, [isHistoricView, date]);
|
|
48547
|
+
return calculatedOperationalDate || getOperationalDate(timezone);
|
|
48548
|
+
}, [isHistoricView, date, calculatedOperationalDate, timezone]);
|
|
48121
48549
|
const handleMonthlyDataLoaded = React23.useCallback((data) => {
|
|
48122
48550
|
console.log("[handleMonthlyDataLoaded] Received data:", {
|
|
48123
48551
|
dataLength: data?.length,
|
|
@@ -48141,10 +48569,8 @@ var WorkspaceDetailView = ({
|
|
|
48141
48569
|
if (!dayEntry) {
|
|
48142
48570
|
dayEntry = {
|
|
48143
48571
|
date: dateObj,
|
|
48144
|
-
|
|
48145
|
-
//
|
|
48146
|
-
nightShift: null
|
|
48147
|
-
// Start with null instead of zeros
|
|
48572
|
+
shifts: {}
|
|
48573
|
+
// Multi-shift structure: Record<number, CalendarShiftData>
|
|
48148
48574
|
};
|
|
48149
48575
|
dayDataMap.set(dateKey, dayEntry);
|
|
48150
48576
|
}
|
|
@@ -48156,19 +48582,14 @@ var WorkspaceDetailView = ({
|
|
|
48156
48582
|
pphThreshold: metric.pph_threshold || 0,
|
|
48157
48583
|
idealOutput: metric.ideal_output || 0,
|
|
48158
48584
|
rank: metric.workspace_rank || 0,
|
|
48159
|
-
idleTime: metric.idle_time || 0
|
|
48585
|
+
idleTime: metric.idle_time || 0,
|
|
48586
|
+
hasData: true
|
|
48160
48587
|
};
|
|
48161
|
-
|
|
48162
|
-
dayEntry.dayShift = shiftData;
|
|
48163
|
-
} else {
|
|
48164
|
-
dayEntry.nightShift = shiftData;
|
|
48165
|
-
}
|
|
48588
|
+
dayEntry.shifts[metric.shift_id] = shiftData;
|
|
48166
48589
|
});
|
|
48167
|
-
const processedData = Array.from(dayDataMap.values()).filter((entry) =>
|
|
48590
|
+
const processedData = Array.from(dayDataMap.values()).filter((entry) => Object.keys(entry.shifts).length > 0).map((entry) => ({
|
|
48168
48591
|
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 }
|
|
48592
|
+
shifts: entry.shifts
|
|
48172
48593
|
}));
|
|
48173
48594
|
console.log(`[handleMonthlyDataLoaded] Transformed data for calendar:`, {
|
|
48174
48595
|
count: processedData.length,
|
|
@@ -48176,7 +48597,6 @@ var WorkspaceDetailView = ({
|
|
|
48176
48597
|
});
|
|
48177
48598
|
setMonthlyData(processedData);
|
|
48178
48599
|
}, []);
|
|
48179
|
-
const effectiveLineId = lineId || selectedLineId;
|
|
48180
48600
|
const formattedWorkspaceName = displayName || formatWorkspaceName3(workspace?.workspace_name || "", effectiveLineId);
|
|
48181
48601
|
const shouldShowCycleTimeChart = showCycleTimeChart ?? formattedWorkspaceName.startsWith("FINAL ASSY");
|
|
48182
48602
|
const handleBackNavigation = () => {
|
|
@@ -48197,7 +48617,7 @@ var WorkspaceDetailView = ({
|
|
|
48197
48617
|
if (onNavigate) {
|
|
48198
48618
|
const params = new URLSearchParams();
|
|
48199
48619
|
params.set("fromMonthly", "true");
|
|
48200
|
-
params.set("shift", selectedShift
|
|
48620
|
+
params.set("shift", selectedShift.toString());
|
|
48201
48621
|
if (effectiveLineId) {
|
|
48202
48622
|
params.set("lineId", effectiveLineId);
|
|
48203
48623
|
}
|
|
@@ -48209,7 +48629,7 @@ var WorkspaceDetailView = ({
|
|
|
48209
48629
|
if (onNavigate) {
|
|
48210
48630
|
const params = new URLSearchParams();
|
|
48211
48631
|
params.set("fromMonthly", "true");
|
|
48212
|
-
params.set("shift", selectedShift
|
|
48632
|
+
params.set("shift", selectedShift.toString());
|
|
48213
48633
|
if (effectiveLineId) {
|
|
48214
48634
|
params.set("lineId", effectiveLineId);
|
|
48215
48635
|
}
|
|
@@ -48222,11 +48642,16 @@ var WorkspaceDetailView = ({
|
|
|
48222
48642
|
}
|
|
48223
48643
|
}
|
|
48224
48644
|
};
|
|
48225
|
-
const
|
|
48226
|
-
|
|
48645
|
+
const getShiftIcon2 = (shiftType) => {
|
|
48646
|
+
const shiftTypeLower = shiftType?.toLowerCase() || "";
|
|
48647
|
+
if (shiftTypeLower.includes("day") || shiftTypeLower.includes("morning")) {
|
|
48227
48648
|
return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" }) });
|
|
48228
|
-
} else {
|
|
48649
|
+
} else if (shiftTypeLower.includes("afternoon") || shiftTypeLower.includes("noon") || shiftTypeLower.includes("midday")) {
|
|
48650
|
+
return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" }) });
|
|
48651
|
+
} else if (shiftTypeLower.includes("night") || shiftTypeLower.includes("evening")) {
|
|
48229
48652
|
return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z" }) });
|
|
48653
|
+
} else {
|
|
48654
|
+
return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" }) });
|
|
48230
48655
|
}
|
|
48231
48656
|
};
|
|
48232
48657
|
if (loading) {
|
|
@@ -48377,7 +48802,7 @@ var WorkspaceDetailView = ({
|
|
|
48377
48802
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "sm:hidden mt-3 flex items-center justify-center gap-2", children: [
|
|
48378
48803
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "inline-flex items-center px-2.5 py-1 bg-gray-100 rounded-full", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-gray-700", children: formatISTDate2(new Date(workspace.date)) }) }),
|
|
48379
48804
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "inline-flex items-center gap-1 px-2.5 py-1 bg-gray-100 rounded-full", children: [
|
|
48380
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-gray-700 scale-90", children:
|
|
48805
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-gray-700 scale-90", children: getShiftIcon2(workspace.shift_type) }),
|
|
48381
48806
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-gray-700", children: workspace.shift_type })
|
|
48382
48807
|
] }),
|
|
48383
48808
|
!date && !shift && !usingFallbackData ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "inline-flex items-center px-2.5 py-1 bg-green-100 rounded-full", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-green-700", children: /* @__PURE__ */ jsxRuntime.jsx(LiveTimer, {}) }) }) : date ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "inline-flex items-center px-2.5 py-1 bg-blue-100 rounded-full", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-blue-700", children: getDaysDifference(workspace.date, timezone, dashboardConfig?.shiftConfig?.dayShift?.startTime || "06:00") }) }) : usingFallbackData ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "inline-flex items-center px-2.5 py-1 bg-amber-100 rounded-full", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-amber-700", children: getDaysDifference(workspace.date, timezone, dashboardConfig?.shiftConfig?.dayShift?.startTime || "06:00") }) }) : null
|
|
@@ -48402,11 +48827,8 @@ var WorkspaceDetailView = ({
|
|
|
48402
48827
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-px h-4 bg-blue-300" })
|
|
48403
48828
|
] }),
|
|
48404
48829
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
48405
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-blue-600", children:
|
|
48406
|
-
/* @__PURE__ */ jsxRuntime.
|
|
48407
|
-
workspace.shift_type,
|
|
48408
|
-
" Shift"
|
|
48409
|
-
] })
|
|
48830
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-blue-600", children: getShiftIcon2(workspace.shift_type) }),
|
|
48831
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm md:text-base font-medium text-blue-600", children: workspace.shift_type })
|
|
48410
48832
|
] })
|
|
48411
48833
|
] }) })
|
|
48412
48834
|
] }),
|
|
@@ -48473,7 +48895,7 @@ var WorkspaceDetailView = ({
|
|
|
48473
48895
|
monthlyData,
|
|
48474
48896
|
selectedMonth,
|
|
48475
48897
|
selectedYear,
|
|
48476
|
-
selectedShift
|
|
48898
|
+
selectedShiftId: selectedShift
|
|
48477
48899
|
}
|
|
48478
48900
|
) })
|
|
48479
48901
|
] })
|
|
@@ -48742,15 +49164,16 @@ var WorkspaceDetailView = ({
|
|
|
48742
49164
|
month: selectedMonth,
|
|
48743
49165
|
year: selectedYear,
|
|
48744
49166
|
workspaceId,
|
|
48745
|
-
selectedShift,
|
|
49167
|
+
selectedShiftId: selectedShift,
|
|
48746
49168
|
monthlyDataLoading,
|
|
48747
|
-
|
|
49169
|
+
availableShifts: shiftConfig?.shifts?.map((s) => ({ id: s.shiftId, name: s.shiftName })),
|
|
49170
|
+
onDateSelect: (selectedDate, shiftId) => {
|
|
48748
49171
|
if (onDateSelect) {
|
|
48749
|
-
onDateSelect(selectedDate,
|
|
49172
|
+
onDateSelect(selectedDate, shiftId);
|
|
48750
49173
|
} else if (onNavigate) {
|
|
48751
49174
|
const params = new URLSearchParams();
|
|
48752
49175
|
params.set("date", selectedDate);
|
|
48753
|
-
params.set("shift",
|
|
49176
|
+
params.set("shift", shiftId.toString());
|
|
48754
49177
|
params.set("fromMonthly", "true");
|
|
48755
49178
|
if (effectiveLineId) {
|
|
48756
49179
|
params.set("lineId", effectiveLineId);
|
|
@@ -48773,6 +49196,7 @@ var WorkspaceDetailView = ({
|
|
|
48773
49196
|
workspaceId,
|
|
48774
49197
|
workspaceName: formattedWorkspaceName,
|
|
48775
49198
|
date,
|
|
49199
|
+
lineId: effectiveLineId,
|
|
48776
49200
|
shift,
|
|
48777
49201
|
totalOutput: workspace?.total_actions,
|
|
48778
49202
|
className: "h-[calc(100vh-10rem)]"
|
|
@@ -48929,6 +49353,13 @@ var SKUManagementView = () => {
|
|
|
48929
49353
|
var useWorkspaceHealth = (options) => {
|
|
48930
49354
|
const supabase = useSupabase();
|
|
48931
49355
|
const databaseConfig = useDatabaseConfig();
|
|
49356
|
+
const entityConfig = useEntityConfig();
|
|
49357
|
+
const configuredLineIds = React23.useMemo(() => getConfiguredLineIds(entityConfig), [entityConfig]);
|
|
49358
|
+
const firstConfiguredLineId = configuredLineIds[0];
|
|
49359
|
+
const isFactoryView = !options.lineId || options.lineId === (entityConfig?.factoryViewId || "factory");
|
|
49360
|
+
const effectiveLineIdForShiftConfig = isFactoryView ? firstConfiguredLineId : options.lineId;
|
|
49361
|
+
const { shiftConfig, isLoading: isShiftConfigLoading } = useDynamicShiftConfig(effectiveLineIdForShiftConfig);
|
|
49362
|
+
const timezone = useAppTimezone() || "UTC";
|
|
48932
49363
|
const [workspaces, setWorkspaces] = React23.useState([]);
|
|
48933
49364
|
const [summary, setSummary] = React23.useState({
|
|
48934
49365
|
totalWorkspaces: 0,
|
|
@@ -48975,6 +49406,14 @@ var useWorkspaceHealth = (options) => {
|
|
|
48975
49406
|
}, []);
|
|
48976
49407
|
const fetchWorkspacesHealth = React23.useCallback(async () => {
|
|
48977
49408
|
if (isFetchingRef.current) return;
|
|
49409
|
+
if (isShiftConfigLoading) {
|
|
49410
|
+
console.log("[useWorkspaceHealth] \u23F3 Waiting for shift config to load");
|
|
49411
|
+
return;
|
|
49412
|
+
}
|
|
49413
|
+
if (!shiftConfig) {
|
|
49414
|
+
console.warn("[useWorkspaceHealth] \u26A0\uFE0F Shift config is null, waiting for it to load");
|
|
49415
|
+
return;
|
|
49416
|
+
}
|
|
48978
49417
|
if (!options.companyId) {
|
|
48979
49418
|
setWorkspaces([]);
|
|
48980
49419
|
setSummary(computeSummary([]));
|
|
@@ -48985,9 +49424,16 @@ var useWorkspaceHealth = (options) => {
|
|
|
48985
49424
|
isFetchingRef.current = true;
|
|
48986
49425
|
setLoading(true);
|
|
48987
49426
|
setError(null);
|
|
49427
|
+
console.log("[useWorkspaceHealth] \u{1F680} Fetching health status with shift config:", {
|
|
49428
|
+
lineId: options.lineId,
|
|
49429
|
+
hasShiftConfig: !!shiftConfig,
|
|
49430
|
+
shiftId: shiftConfig?.shifts?.[0]?.shiftId
|
|
49431
|
+
});
|
|
48988
49432
|
const workspacesWithStatus = await workspaceHealthService.getWorkspaceHealthStatus({
|
|
48989
49433
|
lineId: options.lineId,
|
|
48990
|
-
companyId: options.companyId
|
|
49434
|
+
companyId: options.companyId,
|
|
49435
|
+
shiftConfig,
|
|
49436
|
+
timezone
|
|
48991
49437
|
});
|
|
48992
49438
|
setWorkspaces(workspacesWithStatus);
|
|
48993
49439
|
setSummary(computeSummary(workspacesWithStatus));
|
|
@@ -48999,7 +49445,7 @@ var useWorkspaceHealth = (options) => {
|
|
|
48999
49445
|
setLoading(false);
|
|
49000
49446
|
isFetchingRef.current = false;
|
|
49001
49447
|
}
|
|
49002
|
-
}, [options.companyId, options.lineId, computeSummary]);
|
|
49448
|
+
}, [options.companyId, options.lineId, computeSummary, shiftConfig, isShiftConfigLoading, timezone]);
|
|
49003
49449
|
React23.useEffect(() => {
|
|
49004
49450
|
fetchWorkspacesHealth();
|
|
49005
49451
|
}, [fetchWorkspacesHealth]);
|
|
@@ -49039,9 +49485,12 @@ var useWorkspaceHealth = (options) => {
|
|
|
49039
49485
|
return {
|
|
49040
49486
|
workspaces,
|
|
49041
49487
|
summary,
|
|
49042
|
-
loading,
|
|
49488
|
+
loading: loading || isShiftConfigLoading || !shiftConfig,
|
|
49043
49489
|
error,
|
|
49044
|
-
refetch: fetchWorkspacesHealth
|
|
49490
|
+
refetch: fetchWorkspacesHealth,
|
|
49491
|
+
// Expose shift config so consumers can pass it to child components
|
|
49492
|
+
shiftConfig,
|
|
49493
|
+
isShiftConfigLoading
|
|
49045
49494
|
};
|
|
49046
49495
|
};
|
|
49047
49496
|
var STATUS_COLORS = {
|
|
@@ -49240,7 +49689,8 @@ var formatTimeRange = (start, end, timezone) => {
|
|
|
49240
49689
|
var WorkspaceUptimeDetailModal = ({
|
|
49241
49690
|
workspace,
|
|
49242
49691
|
isOpen,
|
|
49243
|
-
onClose
|
|
49692
|
+
onClose,
|
|
49693
|
+
shiftConfig: passedShiftConfig
|
|
49244
49694
|
}) => {
|
|
49245
49695
|
const timezone = useAppTimezone() || "UTC";
|
|
49246
49696
|
const logsContainerRef = React23.useRef(null);
|
|
@@ -49254,7 +49704,12 @@ var WorkspaceUptimeDetailModal = ({
|
|
|
49254
49704
|
workspaceId: workspace?.workspace_id,
|
|
49255
49705
|
companyId: workspace?.company_id,
|
|
49256
49706
|
enabled: isOpen && Boolean(workspace?.workspace_id && workspace?.company_id),
|
|
49257
|
-
refreshInterval: 6e4
|
|
49707
|
+
refreshInterval: 6e4,
|
|
49708
|
+
lineId: workspace?.line_id,
|
|
49709
|
+
// Pass shift config from parent if available - avoids duplicate DB queries
|
|
49710
|
+
// and ensures consistent shift timing across the view
|
|
49711
|
+
shiftConfig: passedShiftConfig || void 0,
|
|
49712
|
+
timezone
|
|
49258
49713
|
});
|
|
49259
49714
|
React23.useEffect(() => {
|
|
49260
49715
|
if (!isOpen || !workspace) return;
|
|
@@ -49441,32 +49896,48 @@ var WorkspaceHealthView = ({
|
|
|
49441
49896
|
}) => {
|
|
49442
49897
|
const router$1 = router.useRouter();
|
|
49443
49898
|
const [groupBy, setGroupBy] = React23.useState("line");
|
|
49899
|
+
const entityConfig = useEntityConfig();
|
|
49900
|
+
const configuredLineIds = React23.useMemo(() => getConfiguredLineIds(entityConfig), [entityConfig]);
|
|
49901
|
+
const firstConfiguredLineId = configuredLineIds[0];
|
|
49902
|
+
const factoryViewId = entityConfig?.factoryViewId || "factory";
|
|
49903
|
+
const isFactoryView = !lineId || lineId === factoryViewId;
|
|
49904
|
+
const effectiveLineId = isFactoryView ? firstConfiguredLineId : lineId;
|
|
49444
49905
|
const timezone = useAppTimezone();
|
|
49906
|
+
const { shiftConfig, isLoading: isShiftConfigLoading } = useDynamicShiftConfig(effectiveLineId);
|
|
49445
49907
|
const [selectedWorkspace, setSelectedWorkspace] = React23.useState(null);
|
|
49446
|
-
const
|
|
49447
|
-
const
|
|
49448
|
-
const
|
|
49449
|
-
const shiftType =
|
|
49908
|
+
const effectiveTimezone = timezone || "UTC";
|
|
49909
|
+
const currentShiftDetails = getCurrentShift(effectiveTimezone, shiftConfig);
|
|
49910
|
+
const operationalDate = currentShiftDetails.date;
|
|
49911
|
+
const shiftType = (currentShiftDetails.shiftName || "Day").replace(/ Shift$/i, "");
|
|
49450
49912
|
const formatDate = (date) => {
|
|
49451
49913
|
const d = new Date(date);
|
|
49452
49914
|
return d.toLocaleDateString("en-IN", {
|
|
49453
49915
|
month: "long",
|
|
49454
49916
|
day: "numeric",
|
|
49455
49917
|
year: "numeric",
|
|
49456
|
-
timeZone:
|
|
49918
|
+
timeZone: effectiveTimezone
|
|
49457
49919
|
});
|
|
49458
49920
|
};
|
|
49459
|
-
const
|
|
49460
|
-
|
|
49921
|
+
const getShiftIcon2 = () => {
|
|
49922
|
+
const shiftName = (currentShiftDetails.shiftName || "").toLowerCase();
|
|
49923
|
+
if (shiftName.includes("night") || shiftName.includes("evening") || currentShiftDetails.shiftId === 1) {
|
|
49924
|
+
return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Moon, { className: "h-4 w-4" });
|
|
49925
|
+
}
|
|
49926
|
+
if (shiftName.includes("afternoon") || shiftName.includes("noon") || shiftName.includes("midday")) {
|
|
49927
|
+
return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Sun, { className: "h-4 w-4" });
|
|
49928
|
+
}
|
|
49929
|
+
return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Sun, { className: "h-4 w-4" });
|
|
49461
49930
|
};
|
|
49462
49931
|
const {
|
|
49463
49932
|
workspaces,
|
|
49464
49933
|
summary,
|
|
49465
49934
|
loading,
|
|
49466
49935
|
error,
|
|
49467
|
-
refetch
|
|
49936
|
+
refetch,
|
|
49937
|
+
shiftConfig: loadedShiftConfig
|
|
49938
|
+
// Get shift config from the hook to pass to modal
|
|
49468
49939
|
} = useWorkspaceHealth({
|
|
49469
|
-
lineId,
|
|
49940
|
+
lineId: effectiveLineId,
|
|
49470
49941
|
companyId,
|
|
49471
49942
|
enableRealtime: true,
|
|
49472
49943
|
refreshInterval: 1e4
|
|
@@ -49528,7 +49999,7 @@ var WorkspaceHealthView = ({
|
|
|
49528
49999
|
if (percentage >= 90) return "text-yellow-600 dark:text-yellow-400";
|
|
49529
50000
|
return "text-red-600 dark:text-red-400";
|
|
49530
50001
|
};
|
|
49531
|
-
if (loading && !summary) {
|
|
50002
|
+
if (loading && !summary || isShiftConfigLoading) {
|
|
49532
50003
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-h-screen bg-gray-50 dark:bg-gray-900 p-4", children: /* @__PURE__ */ jsxRuntime.jsx(LoadingState, {}) });
|
|
49533
50004
|
}
|
|
49534
50005
|
if (error) {
|
|
@@ -49638,7 +50109,7 @@ var WorkspaceHealthView = ({
|
|
|
49638
50109
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs sm:text-sm md:text-base font-medium text-blue-600", children: formatDate(operationalDate) }),
|
|
49639
50110
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "hidden sm:block w-px h-4 bg-blue-300" }),
|
|
49640
50111
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1 sm:gap-2", children: [
|
|
49641
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-blue-600", children:
|
|
50112
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-blue-600", children: getShiftIcon2() }),
|
|
49642
50113
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs sm:text-sm md:text-base font-medium text-blue-600", children: [
|
|
49643
50114
|
shiftType,
|
|
49644
50115
|
" Shift"
|
|
@@ -49726,7 +50197,8 @@ var WorkspaceHealthView = ({
|
|
|
49726
50197
|
{
|
|
49727
50198
|
workspace: selectedWorkspace,
|
|
49728
50199
|
isOpen: Boolean(selectedWorkspace),
|
|
49729
|
-
onClose: handleCloseDetails
|
|
50200
|
+
onClose: handleCloseDetails,
|
|
50201
|
+
shiftConfig: loadedShiftConfig
|
|
49730
50202
|
}
|
|
49731
50203
|
)
|
|
49732
50204
|
] });
|
|
@@ -51763,25 +52235,15 @@ var TeamManagementView_default = TeamManagementView;
|
|
|
51763
52235
|
function BottleneckClipsView({
|
|
51764
52236
|
workspaceId: propWorkspaceId,
|
|
51765
52237
|
workspaceName: propWorkspaceName,
|
|
52238
|
+
lineId: propLineId,
|
|
51766
52239
|
date: propDate,
|
|
51767
52240
|
shift: propShift,
|
|
51768
52241
|
totalOutput: propTotalOutput
|
|
51769
52242
|
}) {
|
|
51770
52243
|
const router$1 = router.useRouter();
|
|
51771
|
-
const dashboardConfig = useDashboardConfig();
|
|
51772
|
-
const timezone = useAppTimezone();
|
|
51773
52244
|
const workspaceId = propWorkspaceId || router$1.query.workspaceId;
|
|
51774
52245
|
const workspaceName = propWorkspaceName || router$1.query.workspaceName || "Workstation";
|
|
51775
|
-
const
|
|
51776
|
-
if (propDate) return propDate;
|
|
51777
|
-
return getOperationalDate(timezone || dashboardConfig.dateTimeConfig?.defaultTimezone || "UTC");
|
|
51778
|
-
}, [propDate, timezone, dashboardConfig]);
|
|
51779
|
-
const currentShift = React23.useMemo(() => {
|
|
51780
|
-
if (propShift !== void 0) return propShift;
|
|
51781
|
-
const tz = timezone || dashboardConfig.dateTimeConfig?.defaultTimezone || "UTC";
|
|
51782
|
-
const shiftResult = getCurrentShift(tz, dashboardConfig?.shiftConfig);
|
|
51783
|
-
return shiftResult.shiftId;
|
|
51784
|
-
}, [propShift, dashboardConfig, timezone]);
|
|
52246
|
+
const lineId = propLineId || router$1.query.lineId;
|
|
51785
52247
|
if (!workspaceId) {
|
|
51786
52248
|
return /* @__PURE__ */ jsxRuntime.jsx(LoadingPage_default, { message: "Loading workspace data..." });
|
|
51787
52249
|
}
|
|
@@ -51830,8 +52292,9 @@ function BottleneckClipsView({
|
|
|
51830
52292
|
{
|
|
51831
52293
|
workspaceId,
|
|
51832
52294
|
workspaceName,
|
|
51833
|
-
|
|
51834
|
-
|
|
52295
|
+
lineId,
|
|
52296
|
+
date: propDate,
|
|
52297
|
+
shift: propShift,
|
|
51835
52298
|
totalOutput: propTotalOutput,
|
|
51836
52299
|
className: "h-full"
|
|
51837
52300
|
}
|
|
@@ -53349,6 +53812,7 @@ exports.DEFAULT_ENDPOINTS_CONFIG = DEFAULT_ENDPOINTS_CONFIG;
|
|
|
53349
53812
|
exports.DEFAULT_ENTITY_CONFIG = DEFAULT_ENTITY_CONFIG;
|
|
53350
53813
|
exports.DEFAULT_MAP_VIEW_CONFIG = DEFAULT_MAP_VIEW_CONFIG;
|
|
53351
53814
|
exports.DEFAULT_SHIFT_CONFIG = DEFAULT_SHIFT_CONFIG;
|
|
53815
|
+
exports.DEFAULT_SHIFT_DATA = DEFAULT_SHIFT_DATA;
|
|
53352
53816
|
exports.DEFAULT_THEME_CONFIG = DEFAULT_THEME_CONFIG;
|
|
53353
53817
|
exports.DEFAULT_VIDEO_CONFIG = DEFAULT_VIDEO_CONFIG;
|
|
53354
53818
|
exports.DEFAULT_WORKSPACE_CONFIG = DEFAULT_WORKSPACE_CONFIG;
|
|
@@ -53532,6 +53996,7 @@ exports.getAllLineDisplayNames = getAllLineDisplayNames;
|
|
|
53532
53996
|
exports.getAllThreadMessages = getAllThreadMessages;
|
|
53533
53997
|
exports.getAllWorkspaceDisplayNamesAsync = getAllWorkspaceDisplayNamesAsync;
|
|
53534
53998
|
exports.getAnonClient = getAnonClient;
|
|
53999
|
+
exports.getAvailableShiftIds = getAvailableShiftIds;
|
|
53535
54000
|
exports.getBrowserName = getBrowserName;
|
|
53536
54001
|
exports.getCameraNumber = getCameraNumber;
|
|
53537
54002
|
exports.getCompanyMetricsTableName = getCompanyMetricsTableName;
|
|
@@ -53554,6 +54019,9 @@ exports.getNextUpdateInterval = getNextUpdateInterval;
|
|
|
53554
54019
|
exports.getOperationalDate = getOperationalDate;
|
|
53555
54020
|
exports.getS3SignedUrl = getS3SignedUrl;
|
|
53556
54021
|
exports.getS3VideoSrc = getS3VideoSrc;
|
|
54022
|
+
exports.getShiftData = getShiftData;
|
|
54023
|
+
exports.getShiftNameById = getShiftNameById;
|
|
54024
|
+
exports.getShortShiftName = getShortShiftName;
|
|
53557
54025
|
exports.getShortWorkspaceDisplayName = getShortWorkspaceDisplayName;
|
|
53558
54026
|
exports.getShortWorkspaceDisplayNameAsync = getShortWorkspaceDisplayNameAsync;
|
|
53559
54027
|
exports.getStoredWorkspaceMappings = getStoredWorkspaceMappings;
|
|
@@ -53566,6 +54034,7 @@ exports.getWorkspaceDisplayNameAsync = getWorkspaceDisplayNameAsync;
|
|
|
53566
54034
|
exports.getWorkspaceDisplayNamesMap = getWorkspaceDisplayNamesMap;
|
|
53567
54035
|
exports.getWorkspaceFromUrl = getWorkspaceFromUrl;
|
|
53568
54036
|
exports.getWorkspaceNavigationParams = getWorkspaceNavigationParams;
|
|
54037
|
+
exports.hasAnyShiftData = hasAnyShiftData;
|
|
53569
54038
|
exports.identifyCoreUser = identifyCoreUser;
|
|
53570
54039
|
exports.initializeCoreMixpanel = initializeCoreMixpanel;
|
|
53571
54040
|
exports.isLegacyConfiguration = isLegacyConfiguration;
|