@optifye/dashboard-core 6.11.34 → 6.11.36
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.d.mts +15 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.js +541 -227
- package/dist/index.mjs +541 -227
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1667,6 +1667,7 @@ var DEFAULT_SHIFT_DATA = {
|
|
|
1667
1667
|
efficiency: 0,
|
|
1668
1668
|
output: 0,
|
|
1669
1669
|
cycleTime: 0,
|
|
1670
|
+
idealCycleTime: 0,
|
|
1670
1671
|
pph: 0,
|
|
1671
1672
|
pphThreshold: 0,
|
|
1672
1673
|
idealOutput: 0,
|
|
@@ -4513,6 +4514,7 @@ var dashboardService = {
|
|
|
4513
4514
|
avg_efficiency: item.avg_efficiency || 0,
|
|
4514
4515
|
total_output: item.total_output || 0,
|
|
4515
4516
|
avg_cycle_time: item.avg_cycle_time || 0,
|
|
4517
|
+
ideal_cycle_time: item.ideal_cycle_time ?? 0,
|
|
4516
4518
|
ideal_output: item.ideal_output || 0,
|
|
4517
4519
|
total_day_output: item.total_day_output ?? item.ideal_output ?? 0,
|
|
4518
4520
|
avg_pph: item.avg_pph || 0,
|
|
@@ -17309,7 +17311,7 @@ var useActiveBreaks = (lineIds) => {
|
|
|
17309
17311
|
const [isLoading, setIsLoading] = React143.useState(true);
|
|
17310
17312
|
const [error, setError] = React143.useState(null);
|
|
17311
17313
|
const supabase = useSupabase();
|
|
17312
|
-
const
|
|
17314
|
+
const parseTimeToMinutes5 = (timeStr) => {
|
|
17313
17315
|
const [hours, minutes] = timeStr.split(":").map(Number);
|
|
17314
17316
|
return hours * 60 + minutes;
|
|
17315
17317
|
};
|
|
@@ -17318,8 +17320,8 @@ var useActiveBreaks = (lineIds) => {
|
|
|
17318
17320
|
return now4.getHours() * 60 + now4.getMinutes();
|
|
17319
17321
|
};
|
|
17320
17322
|
const isTimeInBreak = (breakStart, breakEnd, currentMinutes) => {
|
|
17321
|
-
const startMinutes =
|
|
17322
|
-
const endMinutes =
|
|
17323
|
+
const startMinutes = parseTimeToMinutes5(breakStart);
|
|
17324
|
+
const endMinutes = parseTimeToMinutes5(breakEnd);
|
|
17323
17325
|
if (endMinutes < startMinutes) {
|
|
17324
17326
|
return currentMinutes >= startMinutes || currentMinutes < endMinutes;
|
|
17325
17327
|
} else {
|
|
@@ -17327,8 +17329,8 @@ var useActiveBreaks = (lineIds) => {
|
|
|
17327
17329
|
}
|
|
17328
17330
|
};
|
|
17329
17331
|
const calculateBreakProgress = (breakStart, breakEnd, currentMinutes) => {
|
|
17330
|
-
const startMinutes =
|
|
17331
|
-
const endMinutes =
|
|
17332
|
+
const startMinutes = parseTimeToMinutes5(breakStart);
|
|
17333
|
+
const endMinutes = parseTimeToMinutes5(breakEnd);
|
|
17332
17334
|
let elapsedMinutes = 0;
|
|
17333
17335
|
let remainingMinutes = 0;
|
|
17334
17336
|
if (endMinutes < startMinutes) {
|
|
@@ -17346,8 +17348,8 @@ var useActiveBreaks = (lineIds) => {
|
|
|
17346
17348
|
return { elapsedMinutes, remainingMinutes };
|
|
17347
17349
|
};
|
|
17348
17350
|
const isTimeInShift = (startTime, endTime, currentMinutes) => {
|
|
17349
|
-
const startMinutes =
|
|
17350
|
-
const endMinutes =
|
|
17351
|
+
const startMinutes = parseTimeToMinutes5(startTime);
|
|
17352
|
+
const endMinutes = parseTimeToMinutes5(endTime);
|
|
17351
17353
|
if (endMinutes < startMinutes) {
|
|
17352
17354
|
return currentMinutes >= startMinutes || currentMinutes < endMinutes;
|
|
17353
17355
|
} else {
|
|
@@ -17407,8 +17409,8 @@ var useActiveBreaks = (lineIds) => {
|
|
|
17407
17409
|
const endTime = breakItem.end || breakItem.endTime || "00:00";
|
|
17408
17410
|
let duration = breakItem.duration || 0;
|
|
17409
17411
|
if (!duration || duration === 0) {
|
|
17410
|
-
const startMinutes =
|
|
17411
|
-
const endMinutes =
|
|
17412
|
+
const startMinutes = parseTimeToMinutes5(startTime);
|
|
17413
|
+
const endMinutes = parseTimeToMinutes5(endTime);
|
|
17412
17414
|
duration = endMinutes < startMinutes ? endMinutes + 24 * 60 - startMinutes : endMinutes - startMinutes;
|
|
17413
17415
|
}
|
|
17414
17416
|
return {
|
|
@@ -17424,8 +17426,8 @@ var useActiveBreaks = (lineIds) => {
|
|
|
17424
17426
|
const endTime = breakItem.end || breakItem.endTime || "00:00";
|
|
17425
17427
|
let duration = breakItem.duration || 0;
|
|
17426
17428
|
if (!duration || duration === 0) {
|
|
17427
|
-
const startMinutes =
|
|
17428
|
-
const endMinutes =
|
|
17429
|
+
const startMinutes = parseTimeToMinutes5(startTime);
|
|
17430
|
+
const endMinutes = parseTimeToMinutes5(endTime);
|
|
17429
17431
|
duration = endMinutes < startMinutes ? endMinutes + 24 * 60 - startMinutes : endMinutes - startMinutes;
|
|
17430
17432
|
}
|
|
17431
17433
|
return {
|
|
@@ -33440,13 +33442,13 @@ var CycleTimeOverTimeChart = ({
|
|
|
33440
33442
|
observer.observe(containerRef.current);
|
|
33441
33443
|
return () => observer.disconnect();
|
|
33442
33444
|
}, []);
|
|
33443
|
-
const
|
|
33445
|
+
const parseTimeToMinutes5 = (value) => {
|
|
33444
33446
|
const [hours, minutes] = value.split(":").map(Number);
|
|
33445
33447
|
if (!Number.isFinite(hours) || !Number.isFinite(minutes)) return 0;
|
|
33446
33448
|
return hours * 60 + minutes;
|
|
33447
33449
|
};
|
|
33448
33450
|
const formatHourLabel = (slotIndex) => {
|
|
33449
|
-
const baseMinutes =
|
|
33451
|
+
const baseMinutes = parseTimeToMinutes5(shiftStart);
|
|
33450
33452
|
const absoluteMinutes = baseMinutes + slotIndex * 60;
|
|
33451
33453
|
const hour24 = Math.floor(absoluteMinutes % (24 * 60) / 60);
|
|
33452
33454
|
const ampm = hour24 >= 12 ? "PM" : "AM";
|
|
@@ -37447,6 +37449,14 @@ var formatTimestampRange = (startTime, endTime, timezone) => {
|
|
|
37447
37449
|
});
|
|
37448
37450
|
return `${startFormatted} - ${endFormatted}`;
|
|
37449
37451
|
};
|
|
37452
|
+
var buildPrefetchedExplorerMetadata = (activeFilter, metadataCategoryId, categoryMetadata) => {
|
|
37453
|
+
if (!activeFilter || !metadataCategoryId || metadataCategoryId !== activeFilter || categoryMetadata.length === 0) {
|
|
37454
|
+
return void 0;
|
|
37455
|
+
}
|
|
37456
|
+
return {
|
|
37457
|
+
[activeFilter]: categoryMetadata
|
|
37458
|
+
};
|
|
37459
|
+
};
|
|
37450
37460
|
var getSecondsBetweenTimestamps = (startTime, endTime) => {
|
|
37451
37461
|
const startDate = parseTimestamp(startTime);
|
|
37452
37462
|
const endDate = parseTimestamp(endTime);
|
|
@@ -42644,6 +42654,7 @@ var BottlenecksContent = ({
|
|
|
42644
42654
|
const [error, setError] = React143.useState(null);
|
|
42645
42655
|
const [clipClassifications, setClipClassifications] = React143.useState({});
|
|
42646
42656
|
const [categoryMetadata, setCategoryMetadata] = React143.useState([]);
|
|
42657
|
+
const [categoryMetadataCategoryId, setCategoryMetadataCategoryId] = React143.useState(null);
|
|
42647
42658
|
const [currentMetadataIndex, setCurrentMetadataIndex] = React143.useState(0);
|
|
42648
42659
|
const [metadataCache, setMetadataCache] = React143.useState({});
|
|
42649
42660
|
const invalidateMetadataCache = React143.useCallback((categories) => {
|
|
@@ -43115,6 +43126,15 @@ var BottlenecksContent = ({
|
|
|
43115
43126
|
const getMetadataCacheKey = React143.useCallback((categoryId) => {
|
|
43116
43127
|
return `${categoryId}-${effectiveDateString}-${effectiveShiftId}-${snapshotDateTime ?? "nosnap"}-${snapshotClipId ?? "nosnap"}`;
|
|
43117
43128
|
}, [effectiveDateString, effectiveShiftId, snapshotDateTime, snapshotClipId]);
|
|
43129
|
+
const setVisibleCategoryMetadata = React143.useCallback((categoryId, clips) => {
|
|
43130
|
+
if (activeFilterRef.current !== categoryId) {
|
|
43131
|
+
return false;
|
|
43132
|
+
}
|
|
43133
|
+
categoryMetadataRef.current = clips;
|
|
43134
|
+
setCategoryMetadata(clips);
|
|
43135
|
+
setCategoryMetadataCategoryId(clips.length > 0 ? categoryId : null);
|
|
43136
|
+
return true;
|
|
43137
|
+
}, []);
|
|
43118
43138
|
const applyMetadataSnapshot = React143.useCallback((categoryId, clips, total) => {
|
|
43119
43139
|
if (!clips || clips.length === 0) {
|
|
43120
43140
|
return;
|
|
@@ -43124,13 +43144,12 @@ var BottlenecksContent = ({
|
|
|
43124
43144
|
...prev,
|
|
43125
43145
|
[cacheKey]: clips
|
|
43126
43146
|
}));
|
|
43127
|
-
|
|
43128
|
-
setCategoryMetadata(clips);
|
|
43147
|
+
setVisibleCategoryMetadata(categoryId, clips);
|
|
43129
43148
|
if (!isPercentileCategory(categoryId) && typeof total === "number") {
|
|
43130
43149
|
currentTotalRef.current = total;
|
|
43131
43150
|
setCurrentTotal(total);
|
|
43132
43151
|
}
|
|
43133
|
-
}, [getMetadataCacheKey, isPercentileCategory]);
|
|
43152
|
+
}, [getMetadataCacheKey, isPercentileCategory, setVisibleCategoryMetadata]);
|
|
43134
43153
|
const getClipTypesForPercentileCategory = React143.useCallback((categoryId) => {
|
|
43135
43154
|
switch (categoryId) {
|
|
43136
43155
|
case "fast-cycles":
|
|
@@ -43155,6 +43174,7 @@ var BottlenecksContent = ({
|
|
|
43155
43174
|
return;
|
|
43156
43175
|
}
|
|
43157
43176
|
setCategoryMetadata([]);
|
|
43177
|
+
setCategoryMetadataCategoryId(null);
|
|
43158
43178
|
categoryMetadataRef.current = [];
|
|
43159
43179
|
updateActiveFilter(fallbackFilter);
|
|
43160
43180
|
}, [isFastSlowClipFiltersEnabled, activeFilter, dynamicCounts, clipTypes, updateActiveFilter]);
|
|
@@ -43201,6 +43221,7 @@ var BottlenecksContent = ({
|
|
|
43201
43221
|
}
|
|
43202
43222
|
if (!isFastSlowClipFiltersEnabled && (categoryId === "fast-cycles" || categoryId === "slow-cycles")) {
|
|
43203
43223
|
setCategoryMetadata([]);
|
|
43224
|
+
setCategoryMetadataCategoryId(null);
|
|
43204
43225
|
categoryMetadataRef.current = [];
|
|
43205
43226
|
return;
|
|
43206
43227
|
}
|
|
@@ -43214,8 +43235,7 @@ var BottlenecksContent = ({
|
|
|
43214
43235
|
try {
|
|
43215
43236
|
if (cachedMetadata) {
|
|
43216
43237
|
console.log(`[BottlenecksContent] Using cached metadata for ${categoryId}`);
|
|
43217
|
-
|
|
43218
|
-
categoryMetadataRef.current = cachedMetadata;
|
|
43238
|
+
setVisibleCategoryMetadata(categoryId, cachedMetadata);
|
|
43219
43239
|
if (autoLoadFirstVideo && cachedMetadata.length > 0 && s3ClipsService) {
|
|
43220
43240
|
const firstClipMeta = cachedMetadata[0];
|
|
43221
43241
|
try {
|
|
@@ -43329,8 +43349,7 @@ var BottlenecksContent = ({
|
|
|
43329
43349
|
...prev,
|
|
43330
43350
|
[cacheKey]: metadataClips
|
|
43331
43351
|
}));
|
|
43332
|
-
|
|
43333
|
-
categoryMetadataRef.current = metadataClips;
|
|
43352
|
+
setVisibleCategoryMetadata(categoryId, metadataClips);
|
|
43334
43353
|
console.log(`[BottlenecksContent] Loaded metadata for ${categoryId}: ${metadataClips.length} clips`);
|
|
43335
43354
|
if (autoLoadFirstVideo && metadataClips.length > 0 && s3ClipsService) {
|
|
43336
43355
|
const firstClipMeta = metadataClips[0];
|
|
@@ -43349,15 +43368,18 @@ var BottlenecksContent = ({
|
|
|
43349
43368
|
}
|
|
43350
43369
|
}
|
|
43351
43370
|
} else {
|
|
43352
|
-
|
|
43353
|
-
|
|
43371
|
+
if (activeFilterRef.current === categoryId) {
|
|
43372
|
+
setCategoryMetadata([]);
|
|
43373
|
+
setCategoryMetadataCategoryId(null);
|
|
43374
|
+
categoryMetadataRef.current = [];
|
|
43375
|
+
}
|
|
43354
43376
|
}
|
|
43355
43377
|
} catch (error2) {
|
|
43356
43378
|
console.error(`[BottlenecksContent] Error loading category metadata:`, error2);
|
|
43357
43379
|
} finally {
|
|
43358
43380
|
setIsCategoryLoading(false);
|
|
43359
43381
|
}
|
|
43360
|
-
}, [workspaceId, effectiveDateString, effectiveShiftId, getMetadataCacheKey, isPercentileCategory, isFastSlowClipFiltersEnabled, metadataCache, s3ClipsService, clearLoadingState, isEffectiveShiftReady, snapshotDateTime, snapshotClipId, supabase]);
|
|
43382
|
+
}, [workspaceId, effectiveDateString, effectiveShiftId, getMetadataCacheKey, isPercentileCategory, isFastSlowClipFiltersEnabled, metadataCache, s3ClipsService, clearLoadingState, isEffectiveShiftReady, snapshotDateTime, snapshotClipId, supabase, setVisibleCategoryMetadata]);
|
|
43361
43383
|
React143.useEffect(() => {
|
|
43362
43384
|
if (previousFilterRef.current !== activeFilter) {
|
|
43363
43385
|
console.log(`Filter changed from ${previousFilterRef.current} to ${activeFilter} - resetting to first video`);
|
|
@@ -43367,6 +43389,7 @@ var BottlenecksContent = ({
|
|
|
43367
43389
|
setIsNavigating(false);
|
|
43368
43390
|
loadingCategoryRef.current = null;
|
|
43369
43391
|
setCategoryMetadata([]);
|
|
43392
|
+
setCategoryMetadataCategoryId(null);
|
|
43370
43393
|
setCurrentMetadataIndex(0);
|
|
43371
43394
|
categoryMetadataRef.current = [];
|
|
43372
43395
|
currentMetadataIndexRef.current = 0;
|
|
@@ -43925,14 +43948,11 @@ var BottlenecksContent = ({
|
|
|
43925
43948
|
}
|
|
43926
43949
|
return currentPosition;
|
|
43927
43950
|
}, [activeFilter, categoryMetadata.length, currentMetadataIndex, currentPosition, isPercentileCategory]);
|
|
43928
|
-
const prefetchedExplorerMetadata = React143.useMemo(() =>
|
|
43929
|
-
|
|
43930
|
-
|
|
43931
|
-
|
|
43932
|
-
|
|
43933
|
-
[activeFilter]: categoryMetadata
|
|
43934
|
-
};
|
|
43935
|
-
}, [activeFilter, categoryMetadata]);
|
|
43951
|
+
const prefetchedExplorerMetadata = React143.useMemo(() => buildPrefetchedExplorerMetadata(
|
|
43952
|
+
activeFilter,
|
|
43953
|
+
categoryMetadataCategoryId,
|
|
43954
|
+
categoryMetadata
|
|
43955
|
+
), [activeFilter, categoryMetadata, categoryMetadataCategoryId]);
|
|
43936
43956
|
const classificationClipIds = React143.useMemo(() => {
|
|
43937
43957
|
if (!idleTimeVlmEnabled) {
|
|
43938
43958
|
return [];
|
|
@@ -47885,6 +47905,7 @@ var LineMonthlyPdfGenerator = ({
|
|
|
47885
47905
|
rangeEnd,
|
|
47886
47906
|
selectedShiftId,
|
|
47887
47907
|
availableShifts,
|
|
47908
|
+
lineAssembly = false,
|
|
47888
47909
|
compact = false,
|
|
47889
47910
|
className
|
|
47890
47911
|
}) => {
|
|
@@ -48168,8 +48189,8 @@ var LineMonthlyPdfGenerator = ({
|
|
|
48168
48189
|
timeZone: "Asia/Kolkata"
|
|
48169
48190
|
});
|
|
48170
48191
|
doc.text(dateStr, 25, yPos);
|
|
48171
|
-
doc.text(`${shift.
|
|
48172
|
-
doc.text(`${shift.
|
|
48192
|
+
doc.text(`${Math.round(shift.output || 0)}`, 60, yPos);
|
|
48193
|
+
doc.text(`${Math.round(shift.idealOutput || 0)}`, 95, yPos);
|
|
48173
48194
|
doc.text(`${shift.avg_efficiency.toFixed(1)}%`, 135, yPos);
|
|
48174
48195
|
const statusColor = getEfficiencyColor(shift.avg_efficiency, effectiveLegend);
|
|
48175
48196
|
if (statusColor === "green") {
|
|
@@ -48199,6 +48220,8 @@ var LineMonthlyPdfGenerator = ({
|
|
|
48199
48220
|
doc.setTextColor(0, 0, 0);
|
|
48200
48221
|
}
|
|
48201
48222
|
const poorestWorkspaces = underperformingWorkspaces[selectedShiftId] || [];
|
|
48223
|
+
const isCycleTimeWorkspace = (workspace) => workspace.metric_mode === "cycle_time" || lineAssembly && (workspace.avg_cycle_time !== void 0 || workspace.ideal_cycle_time !== void 0 || workspace.cycle_ratio !== void 0);
|
|
48224
|
+
const showCycleTimePoorestPerformers = !isUptimeMode && poorestWorkspaces.some(isCycleTimeWorkspace);
|
|
48202
48225
|
if (poorestWorkspaces && poorestWorkspaces.length > 0) {
|
|
48203
48226
|
doc.addPage();
|
|
48204
48227
|
doc.setFontSize(14);
|
|
@@ -48224,7 +48247,11 @@ var LineMonthlyPdfGenerator = ({
|
|
|
48224
48247
|
doc.setFillColor(245, 245, 245);
|
|
48225
48248
|
doc.roundedRect(20, 45, 170, 8, 1, 1, "F");
|
|
48226
48249
|
doc.text("Workspace", 25, 50);
|
|
48227
|
-
doc.text(
|
|
48250
|
+
doc.text(
|
|
48251
|
+
isUptimeMode ? "Avg Utilization" : showCycleTimePoorestPerformers ? "Cycle Time" : "Avg Efficiency",
|
|
48252
|
+
120,
|
|
48253
|
+
50
|
|
48254
|
+
);
|
|
48228
48255
|
doc.text("Last 5 Days", 160, 50);
|
|
48229
48256
|
doc.setLineWidth(0.2);
|
|
48230
48257
|
doc.setDrawColor(220, 220, 220);
|
|
@@ -48243,7 +48270,16 @@ var LineMonthlyPdfGenerator = ({
|
|
|
48243
48270
|
);
|
|
48244
48271
|
const workspaceName = rawWorkspaceName.length > 30 ? `${rawWorkspaceName.substring(0, 27)}...` : rawWorkspaceName;
|
|
48245
48272
|
doc.text(workspaceName, 25, yPos2);
|
|
48246
|
-
|
|
48273
|
+
if (isUptimeMode) {
|
|
48274
|
+
doc.text(`${(workspace.avg_efficiency || 0).toFixed(1)}%`, 120, yPos2);
|
|
48275
|
+
} else if (isCycleTimeWorkspace(workspace)) {
|
|
48276
|
+
const actualCycleTime = Number.isFinite(workspace.avg_cycle_time) ? Number(workspace.avg_cycle_time) : null;
|
|
48277
|
+
const targetCycleTime = Number.isFinite(workspace.ideal_cycle_time) ? Number(workspace.ideal_cycle_time) : null;
|
|
48278
|
+
const cycleTimeText = actualCycleTime !== null ? `${actualCycleTime.toFixed(1)}s${targetCycleTime !== null ? ` / ${targetCycleTime.toFixed(1)}s` : ""}` : "-";
|
|
48279
|
+
doc.text(cycleTimeText, 120, yPos2);
|
|
48280
|
+
} else {
|
|
48281
|
+
doc.text(`${(workspace.avg_efficiency || 0).toFixed(1)}%`, 120, yPos2);
|
|
48282
|
+
}
|
|
48247
48283
|
const squareSize = 3;
|
|
48248
48284
|
const squareSpacing = 1;
|
|
48249
48285
|
let squareX = 160;
|
|
@@ -48338,12 +48374,279 @@ Underperforming Workspaces: ${lineInfo.metrics.underperforming_workspaces} / ${l
|
|
|
48338
48374
|
}
|
|
48339
48375
|
);
|
|
48340
48376
|
};
|
|
48377
|
+
|
|
48378
|
+
// src/lib/utils/hourlyTargets.ts
|
|
48379
|
+
var stripSeconds2 = (timeStr) => timeStr ? timeStr.slice(0, 5) : timeStr;
|
|
48380
|
+
var MINUTES_PER_DAY = 24 * 60;
|
|
48381
|
+
var parseTimeToMinutes2 = (timeString) => {
|
|
48382
|
+
const normalized = stripSeconds2(timeString || "");
|
|
48383
|
+
if (!normalized || !/^[0-2]\d:[0-5]\d$/.test(normalized)) return Number.NaN;
|
|
48384
|
+
const [hours, minutes] = normalized.split(":").map(Number);
|
|
48385
|
+
return hours * 60 + minutes;
|
|
48386
|
+
};
|
|
48387
|
+
var normalizeBreaksOnShiftTimeline = (shiftStart, breaks) => {
|
|
48388
|
+
const shiftStartMinutes = parseTimeToMinutes2(shiftStart);
|
|
48389
|
+
if (!Number.isFinite(shiftStartMinutes)) return [];
|
|
48390
|
+
const normalizedBreaks = [];
|
|
48391
|
+
for (const entry of breaks) {
|
|
48392
|
+
const startRaw = parseTimeToMinutes2(entry.startTime);
|
|
48393
|
+
const endRaw = parseTimeToMinutes2(entry.endTime);
|
|
48394
|
+
if (!Number.isFinite(startRaw) || !Number.isFinite(endRaw)) continue;
|
|
48395
|
+
let start = startRaw;
|
|
48396
|
+
let end = endRaw;
|
|
48397
|
+
if (end <= start) {
|
|
48398
|
+
end += 24 * 60;
|
|
48399
|
+
}
|
|
48400
|
+
if (start < shiftStartMinutes) {
|
|
48401
|
+
start += 24 * 60;
|
|
48402
|
+
end += 24 * 60;
|
|
48403
|
+
}
|
|
48404
|
+
const label = entry.remarks?.trim() || "Break";
|
|
48405
|
+
normalizedBreaks.push({ start, end, label });
|
|
48406
|
+
}
|
|
48407
|
+
return normalizedBreaks;
|
|
48408
|
+
};
|
|
48409
|
+
var roundTarget = (value, mode) => {
|
|
48410
|
+
if (!Number.isFinite(value)) return 0;
|
|
48411
|
+
switch (mode) {
|
|
48412
|
+
case "floor":
|
|
48413
|
+
return Math.floor(value);
|
|
48414
|
+
case "ceil":
|
|
48415
|
+
return Math.ceil(value);
|
|
48416
|
+
case "round":
|
|
48417
|
+
default:
|
|
48418
|
+
return Math.round(value);
|
|
48419
|
+
}
|
|
48420
|
+
};
|
|
48421
|
+
var formatDateKey = (date) => {
|
|
48422
|
+
const year = date.getUTCFullYear();
|
|
48423
|
+
const month = `${date.getUTCMonth() + 1}`.padStart(2, "0");
|
|
48424
|
+
const day = `${date.getUTCDate()}`.padStart(2, "0");
|
|
48425
|
+
return `${year}-${month}-${day}`;
|
|
48426
|
+
};
|
|
48427
|
+
var shiftDateKey = (dateKey, deltaDays) => {
|
|
48428
|
+
const [yearPart, monthPart, dayPart] = dateKey.split("-").map(Number);
|
|
48429
|
+
const year = Number.isFinite(yearPart) ? yearPart : 1970;
|
|
48430
|
+
const month = Number.isFinite(monthPart) ? monthPart : 1;
|
|
48431
|
+
const day = Number.isFinite(dayPart) ? dayPart : 1;
|
|
48432
|
+
const date = new Date(Date.UTC(year, month - 1, day));
|
|
48433
|
+
date.setUTCDate(date.getUTCDate() + deltaDays);
|
|
48434
|
+
return formatDateKey(date);
|
|
48435
|
+
};
|
|
48436
|
+
var getZonedNowSnapshot = (timeZone, now4) => {
|
|
48437
|
+
const formatter = new Intl.DateTimeFormat("en-US", {
|
|
48438
|
+
timeZone,
|
|
48439
|
+
year: "numeric",
|
|
48440
|
+
month: "2-digit",
|
|
48441
|
+
day: "2-digit",
|
|
48442
|
+
hour: "2-digit",
|
|
48443
|
+
minute: "2-digit",
|
|
48444
|
+
hourCycle: "h23"
|
|
48445
|
+
});
|
|
48446
|
+
const parts = formatter.formatToParts(now4).reduce((acc, part) => {
|
|
48447
|
+
if (part.type !== "literal") {
|
|
48448
|
+
acc[part.type] = part.value;
|
|
48449
|
+
}
|
|
48450
|
+
return acc;
|
|
48451
|
+
}, {});
|
|
48452
|
+
const year = Number(parts.year);
|
|
48453
|
+
const month = Number(parts.month);
|
|
48454
|
+
const day = Number(parts.day);
|
|
48455
|
+
const hour = Number(parts.hour);
|
|
48456
|
+
const minute = Number(parts.minute);
|
|
48457
|
+
return {
|
|
48458
|
+
dateKey: `${String(year).padStart(4, "0")}-${String(month).padStart(2, "0")}-${String(day).padStart(2, "0")}`,
|
|
48459
|
+
minutesOfDay: (Number.isFinite(hour) ? hour : 0) * 60 + (Number.isFinite(minute) ? minute : 0)
|
|
48460
|
+
};
|
|
48461
|
+
};
|
|
48462
|
+
var getDateKeyInTimeZone = (timeZone, now4 = /* @__PURE__ */ new Date()) => getZonedNowSnapshot(timeZone, now4).dateKey;
|
|
48463
|
+
var buildHourlyIntervals = ({
|
|
48464
|
+
shiftStart,
|
|
48465
|
+
shiftEnd,
|
|
48466
|
+
bucketMinutes = 60,
|
|
48467
|
+
fallbackHours = 11
|
|
48468
|
+
}) => {
|
|
48469
|
+
const startMinutes = parseTimeToMinutes2(shiftStart);
|
|
48470
|
+
if (!Number.isFinite(startMinutes)) return [];
|
|
48471
|
+
const bucket = Number.isFinite(bucketMinutes) && bucketMinutes > 0 ? Math.floor(bucketMinutes) : 60;
|
|
48472
|
+
let totalMinutes;
|
|
48473
|
+
const endRaw = shiftEnd ? parseTimeToMinutes2(shiftEnd) : Number.NaN;
|
|
48474
|
+
if (!Number.isFinite(endRaw)) {
|
|
48475
|
+
totalMinutes = Math.max(0, Math.round(fallbackHours * 60));
|
|
48476
|
+
} else {
|
|
48477
|
+
let endMinutes = endRaw;
|
|
48478
|
+
if (endMinutes <= startMinutes) {
|
|
48479
|
+
endMinutes += 24 * 60;
|
|
48480
|
+
}
|
|
48481
|
+
totalMinutes = endMinutes - startMinutes;
|
|
48482
|
+
}
|
|
48483
|
+
if (!Number.isFinite(totalMinutes) || totalMinutes <= 0) return [];
|
|
48484
|
+
const count = Math.ceil(totalMinutes / bucket);
|
|
48485
|
+
const shiftEndMinutes = startMinutes + totalMinutes;
|
|
48486
|
+
const intervals = [];
|
|
48487
|
+
for (let i = 0; i < count; i += 1) {
|
|
48488
|
+
const start = startMinutes + i * bucket;
|
|
48489
|
+
const end = Math.min(start + bucket, shiftEndMinutes);
|
|
48490
|
+
const minutes = Math.max(0, end - start);
|
|
48491
|
+
if (minutes <= 0) continue;
|
|
48492
|
+
intervals.push({ start, end, minutes });
|
|
48493
|
+
}
|
|
48494
|
+
return intervals;
|
|
48495
|
+
};
|
|
48496
|
+
var computeBreakMinutesByInterval = ({
|
|
48497
|
+
intervals,
|
|
48498
|
+
shiftStart,
|
|
48499
|
+
breaks
|
|
48500
|
+
}) => {
|
|
48501
|
+
if (!intervals.length || !breaks.length) return intervals.map(() => 0);
|
|
48502
|
+
const normalizedBreaks = normalizeBreaksOnShiftTimeline(shiftStart, breaks);
|
|
48503
|
+
return intervals.map((interval) => {
|
|
48504
|
+
if (!normalizedBreaks.length) return 0;
|
|
48505
|
+
let total = 0;
|
|
48506
|
+
for (const brk of normalizedBreaks) {
|
|
48507
|
+
const overlap = Math.max(0, Math.min(interval.end, brk.end) - Math.max(interval.start, brk.start));
|
|
48508
|
+
total += overlap;
|
|
48509
|
+
if (total >= interval.minutes) return interval.minutes;
|
|
48510
|
+
}
|
|
48511
|
+
return Math.min(interval.minutes, total);
|
|
48512
|
+
});
|
|
48513
|
+
};
|
|
48514
|
+
var computeBreakRemarksByInterval = ({
|
|
48515
|
+
intervals,
|
|
48516
|
+
shiftStart,
|
|
48517
|
+
breaks
|
|
48518
|
+
}) => {
|
|
48519
|
+
if (!intervals.length || !breaks.length) return intervals.map(() => "");
|
|
48520
|
+
const normalizedBreaks = normalizeBreaksOnShiftTimeline(shiftStart, breaks);
|
|
48521
|
+
return intervals.map((interval) => {
|
|
48522
|
+
const labels = normalizedBreaks.filter((brk) => Math.max(0, Math.min(interval.end, brk.end) - Math.max(interval.start, brk.start)) > 0).map((brk) => brk.label).filter((label, index, values) => label && values.indexOf(label) === index);
|
|
48523
|
+
return labels.join(", ");
|
|
48524
|
+
});
|
|
48525
|
+
};
|
|
48526
|
+
var computeEffectiveTargets = ({
|
|
48527
|
+
intervals,
|
|
48528
|
+
breakMinutes,
|
|
48529
|
+
pphThreshold,
|
|
48530
|
+
rounding = "round"
|
|
48531
|
+
}) => {
|
|
48532
|
+
return intervals.map((interval, idx) => {
|
|
48533
|
+
const intervalMinutes = Number(interval?.minutes) || 0;
|
|
48534
|
+
const breakMins = Number(breakMinutes?.[idx]) || 0;
|
|
48535
|
+
const plannedWorkMinutes = Math.max(0, intervalMinutes - breakMins);
|
|
48536
|
+
if (!Number.isFinite(pphThreshold) || pphThreshold <= 0) return 0;
|
|
48537
|
+
if (plannedWorkMinutes <= 0) return 0;
|
|
48538
|
+
return roundTarget(pphThreshold * plannedWorkMinutes / 60, rounding);
|
|
48539
|
+
});
|
|
48540
|
+
};
|
|
48541
|
+
var buildHourlyTargetPlan = ({
|
|
48542
|
+
shiftStart,
|
|
48543
|
+
shiftEnd,
|
|
48544
|
+
breaks = [],
|
|
48545
|
+
pphThreshold,
|
|
48546
|
+
bucketMinutes = 60,
|
|
48547
|
+
fallbackHours = 11,
|
|
48548
|
+
rounding = "round"
|
|
48549
|
+
}) => {
|
|
48550
|
+
const intervals = buildHourlyIntervals({
|
|
48551
|
+
shiftStart,
|
|
48552
|
+
shiftEnd,
|
|
48553
|
+
bucketMinutes,
|
|
48554
|
+
fallbackHours
|
|
48555
|
+
});
|
|
48556
|
+
const breakMinutes = computeBreakMinutesByInterval({
|
|
48557
|
+
intervals,
|
|
48558
|
+
shiftStart,
|
|
48559
|
+
breaks
|
|
48560
|
+
});
|
|
48561
|
+
const breakRemarks = computeBreakRemarksByInterval({
|
|
48562
|
+
intervals,
|
|
48563
|
+
shiftStart,
|
|
48564
|
+
breaks
|
|
48565
|
+
});
|
|
48566
|
+
const productiveMinutes = intervals.map((interval, idx) => Math.max(0, (Number(interval?.minutes) || 0) - (Number(breakMinutes[idx]) || 0)));
|
|
48567
|
+
const targets = computeEffectiveTargets({
|
|
48568
|
+
intervals,
|
|
48569
|
+
breakMinutes,
|
|
48570
|
+
pphThreshold,
|
|
48571
|
+
rounding
|
|
48572
|
+
});
|
|
48573
|
+
return {
|
|
48574
|
+
intervals,
|
|
48575
|
+
breakMinutes,
|
|
48576
|
+
breakRemarks,
|
|
48577
|
+
productiveMinutes,
|
|
48578
|
+
targets
|
|
48579
|
+
};
|
|
48580
|
+
};
|
|
48581
|
+
var isHourlyIntervalComplete = ({
|
|
48582
|
+
reportDate,
|
|
48583
|
+
shiftStart,
|
|
48584
|
+
shiftEnd,
|
|
48585
|
+
interval,
|
|
48586
|
+
timeZone = "Asia/Kolkata",
|
|
48587
|
+
now: now4 = /* @__PURE__ */ new Date()
|
|
48588
|
+
}) => {
|
|
48589
|
+
if (!reportDate) return true;
|
|
48590
|
+
const snapshot = getZonedNowSnapshot(timeZone, now4);
|
|
48591
|
+
const shiftStartMinutes = parseTimeToMinutes2(shiftStart);
|
|
48592
|
+
const shiftEndMinutes = shiftEnd ? parseTimeToMinutes2(shiftEnd) : Number.NaN;
|
|
48593
|
+
const wrapsMidnight = Number.isFinite(shiftStartMinutes) && Number.isFinite(shiftEndMinutes) && shiftEndMinutes <= shiftStartMinutes;
|
|
48594
|
+
if (reportDate === snapshot.dateKey) {
|
|
48595
|
+
return interval.end <= snapshot.minutesOfDay;
|
|
48596
|
+
}
|
|
48597
|
+
if (wrapsMidnight && reportDate === shiftDateKey(snapshot.dateKey, -1)) {
|
|
48598
|
+
return interval.end <= snapshot.minutesOfDay + MINUTES_PER_DAY;
|
|
48599
|
+
}
|
|
48600
|
+
return reportDate < snapshot.dateKey;
|
|
48601
|
+
};
|
|
48602
|
+
var isShiftInProgressForReportDate = ({
|
|
48603
|
+
reportDate,
|
|
48604
|
+
shiftStart,
|
|
48605
|
+
shiftEnd,
|
|
48606
|
+
timeZone = "Asia/Kolkata",
|
|
48607
|
+
now: now4 = /* @__PURE__ */ new Date()
|
|
48608
|
+
}) => {
|
|
48609
|
+
if (!reportDate || !shiftStart || !shiftEnd) return false;
|
|
48610
|
+
const shiftStartMinutes = parseTimeToMinutes2(shiftStart);
|
|
48611
|
+
const shiftEndMinutesRaw = parseTimeToMinutes2(shiftEnd);
|
|
48612
|
+
if (!Number.isFinite(shiftStartMinutes) || !Number.isFinite(shiftEndMinutesRaw)) {
|
|
48613
|
+
return false;
|
|
48614
|
+
}
|
|
48615
|
+
let shiftEndMinutes = shiftEndMinutesRaw;
|
|
48616
|
+
const wrapsMidnight = shiftEndMinutes <= shiftStartMinutes;
|
|
48617
|
+
if (wrapsMidnight) {
|
|
48618
|
+
shiftEndMinutes += MINUTES_PER_DAY;
|
|
48619
|
+
}
|
|
48620
|
+
const snapshot = getZonedNowSnapshot(timeZone, now4);
|
|
48621
|
+
let currentMinutes = null;
|
|
48622
|
+
if (reportDate === snapshot.dateKey) {
|
|
48623
|
+
currentMinutes = snapshot.minutesOfDay;
|
|
48624
|
+
} else if (wrapsMidnight && reportDate === shiftDateKey(snapshot.dateKey, -1)) {
|
|
48625
|
+
currentMinutes = snapshot.minutesOfDay + MINUTES_PER_DAY;
|
|
48626
|
+
}
|
|
48627
|
+
if (currentMinutes === null) {
|
|
48628
|
+
return false;
|
|
48629
|
+
}
|
|
48630
|
+
return shiftStartMinutes <= currentMinutes && currentMinutes < shiftEndMinutes;
|
|
48631
|
+
};
|
|
48632
|
+
var formatOperationalDateKey = (dateKey, options) => {
|
|
48633
|
+
const [yearPart, monthPart, dayPart] = dateKey.split("-").map(Number);
|
|
48634
|
+
const year = Number.isFinite(yearPart) ? yearPart : 1970;
|
|
48635
|
+
const month = Number.isFinite(monthPart) ? monthPart : 1;
|
|
48636
|
+
const day = Number.isFinite(dayPart) ? dayPart : 1;
|
|
48637
|
+
return new Date(Date.UTC(year, month - 1, day, 12)).toLocaleDateString("en-IN", {
|
|
48638
|
+
...options,
|
|
48639
|
+
timeZone: "UTC"
|
|
48640
|
+
});
|
|
48641
|
+
};
|
|
48341
48642
|
var LinePdfGenerator = ({
|
|
48342
48643
|
lineInfo,
|
|
48343
48644
|
workspaceData,
|
|
48344
48645
|
issueResolutionSummary,
|
|
48345
48646
|
shiftName,
|
|
48346
|
-
className
|
|
48647
|
+
className,
|
|
48648
|
+
shiftBreaks = [],
|
|
48649
|
+
reportTimezone = "Asia/Kolkata"
|
|
48347
48650
|
}) => {
|
|
48348
48651
|
const [isGenerating, setIsGenerating] = React143.useState(false);
|
|
48349
48652
|
const formatResolutionDuration2 = (seconds) => {
|
|
@@ -48370,7 +48673,7 @@ var LinePdfGenerator = ({
|
|
|
48370
48673
|
doc.setFontSize(9);
|
|
48371
48674
|
doc.setFont("helvetica", "normal");
|
|
48372
48675
|
doc.setTextColor(100, 100, 100);
|
|
48373
|
-
const generatedText = `Generated on ${(/* @__PURE__ */ new Date()).toLocaleString("en-IN", { timeZone:
|
|
48676
|
+
const generatedText = `Generated on ${(/* @__PURE__ */ new Date()).toLocaleString("en-IN", { timeZone: reportTimezone })}`;
|
|
48374
48677
|
const generatedTextWidth = doc.getStringUnitWidth(generatedText) * 9 / doc.internal.scaleFactor;
|
|
48375
48678
|
doc.text(generatedText, doc.internal.pageSize.width - 20 - generatedTextWidth, 15);
|
|
48376
48679
|
doc.setDrawColor(200, 200, 200);
|
|
@@ -48388,11 +48691,10 @@ var LinePdfGenerator = ({
|
|
|
48388
48691
|
const isUptimeMode = lineInfo.monitoring_mode === "uptime";
|
|
48389
48692
|
const rawShiftType = shiftName || (lineInfo.shift_id === 0 ? "Day" : lineInfo.shift_id === 1 ? "Night" : `Shift ${lineInfo.shift_id}`);
|
|
48390
48693
|
const shiftType = rawShiftType.toLowerCase().includes("shift") ? rawShiftType : `${rawShiftType} Shift`;
|
|
48391
|
-
const date =
|
|
48694
|
+
const date = formatOperationalDateKey(lineInfo.date, {
|
|
48392
48695
|
weekday: "long",
|
|
48393
48696
|
day: "numeric",
|
|
48394
|
-
month: "long"
|
|
48395
|
-
timeZone: "Asia/Kolkata"
|
|
48697
|
+
month: "long"
|
|
48396
48698
|
});
|
|
48397
48699
|
const shiftStartTime = lineInfo.metrics.shift_start ? (/* @__PURE__ */ new Date(`2000-01-01 ${lineInfo.metrics.shift_start}`)).toLocaleTimeString("en-IN", {
|
|
48398
48700
|
hour: "2-digit",
|
|
@@ -48400,24 +48702,25 @@ var LinePdfGenerator = ({
|
|
|
48400
48702
|
hour12: true,
|
|
48401
48703
|
timeZone: "Asia/Kolkata"
|
|
48402
48704
|
}) : "N/A";
|
|
48403
|
-
const
|
|
48404
|
-
|
|
48405
|
-
|
|
48406
|
-
|
|
48407
|
-
|
|
48408
|
-
|
|
48409
|
-
|
|
48410
|
-
|
|
48411
|
-
|
|
48412
|
-
|
|
48413
|
-
|
|
48414
|
-
|
|
48415
|
-
|
|
48416
|
-
|
|
48417
|
-
|
|
48418
|
-
}
|
|
48705
|
+
const currentTime = (/* @__PURE__ */ new Date()).toLocaleTimeString("en-IN", {
|
|
48706
|
+
hour: "2-digit",
|
|
48707
|
+
minute: "2-digit",
|
|
48708
|
+
timeZone: reportTimezone
|
|
48709
|
+
});
|
|
48710
|
+
const reportEndTime = isShiftInProgressForReportDate({
|
|
48711
|
+
reportDate: lineInfo.date,
|
|
48712
|
+
shiftStart: lineInfo.metrics.shift_start || "",
|
|
48713
|
+
shiftEnd: lineInfo.metrics.shift_end,
|
|
48714
|
+
timeZone: reportTimezone
|
|
48715
|
+
}) ? currentTime : lineInfo.metrics.shift_end ? (/* @__PURE__ */ new Date(`2000-01-01 ${lineInfo.metrics.shift_end}`)).toLocaleTimeString("en-IN", {
|
|
48716
|
+
hour: "2-digit",
|
|
48717
|
+
minute: "2-digit",
|
|
48718
|
+
hour12: true,
|
|
48719
|
+
timeZone: "Asia/Kolkata"
|
|
48720
|
+
}) : "N/A";
|
|
48419
48721
|
if (isUptimeMode) {
|
|
48420
48722
|
const configuredTimezone = "Asia/Kolkata";
|
|
48723
|
+
const effectiveUptimeTimezone = reportTimezone || configuredTimezone;
|
|
48421
48724
|
const lineShiftStart = lineInfo.metrics.shift_start || "06:00";
|
|
48422
48725
|
const lineShiftEnd = lineInfo.metrics.shift_end || "14:00";
|
|
48423
48726
|
const shiftMinutes = getShiftDurationMinutes(lineShiftStart, lineShiftEnd) || 0;
|
|
@@ -48431,7 +48734,7 @@ var LinePdfGenerator = ({
|
|
|
48431
48734
|
shiftStart,
|
|
48432
48735
|
shiftEnd,
|
|
48433
48736
|
shiftDate,
|
|
48434
|
-
timezone:
|
|
48737
|
+
timezone: effectiveUptimeTimezone
|
|
48435
48738
|
});
|
|
48436
48739
|
let activeMinutes = uptimeSeries.activeMinutes;
|
|
48437
48740
|
let idleMinutes = uptimeSeries.idleMinutes;
|
|
@@ -48512,7 +48815,7 @@ var LinePdfGenerator = ({
|
|
|
48512
48815
|
shiftStart: lineShiftStart,
|
|
48513
48816
|
shiftEnd: lineShiftEnd,
|
|
48514
48817
|
shiftDate: lineInfo.date,
|
|
48515
|
-
timezone:
|
|
48818
|
+
timezone: effectiveUptimeTimezone
|
|
48516
48819
|
});
|
|
48517
48820
|
hourlyData = buildHourlyFromSeries(lineUptimeSeries);
|
|
48518
48821
|
}
|
|
@@ -48620,13 +48923,13 @@ var LinePdfGenerator = ({
|
|
|
48620
48923
|
doc.setFontSize(contentFontSize);
|
|
48621
48924
|
doc.setFont("helvetica", "normal");
|
|
48622
48925
|
let yPos2 = headerBottomY2 + 5.5;
|
|
48623
|
-
const
|
|
48624
|
-
const
|
|
48625
|
-
const [
|
|
48626
|
-
const [
|
|
48627
|
-
const
|
|
48926
|
+
const now4 = /* @__PURE__ */ new Date();
|
|
48927
|
+
const currentTimeIST = new Date(now4.toLocaleString("en-US", { timeZone: configuredTimezone }));
|
|
48928
|
+
const [sYear, sMonth, sDay] = lineInfo.date.split("-").map(Number);
|
|
48929
|
+
const [sStartH, sStartM] = (lineShiftStart || "06:00").split(":").map(Number);
|
|
48930
|
+
const shiftStartBase = new Date(sYear, sMonth - 1, sDay, sStartH, sStartM || 0);
|
|
48628
48931
|
hourlyData.forEach((entry, index) => {
|
|
48629
|
-
const bucketStartTime = new Date(
|
|
48932
|
+
const bucketStartTime = new Date(shiftStartBase);
|
|
48630
48933
|
bucketStartTime.setHours(bucketStartTime.getHours() + index);
|
|
48631
48934
|
const bucketEndTime = new Date(bucketStartTime);
|
|
48632
48935
|
bucketEndTime.setHours(bucketEndTime.getHours() + 1);
|
|
@@ -48637,7 +48940,7 @@ var LinePdfGenerator = ({
|
|
|
48637
48940
|
hour: "numeric",
|
|
48638
48941
|
hour12: true
|
|
48639
48942
|
})}`;
|
|
48640
|
-
const dataCollected = bucketEndTime.getTime() <=
|
|
48943
|
+
const dataCollected = bucketEndTime.getTime() <= currentTimeIST.getTime();
|
|
48641
48944
|
if (index < totalRows2 - 1) {
|
|
48642
48945
|
const rowBottomY = headerBottomY2 + (index + 1) * rowHeight;
|
|
48643
48946
|
doc.setDrawColor(200, 200, 200);
|
|
@@ -48648,11 +48951,10 @@ var LinePdfGenerator = ({
|
|
|
48648
48951
|
doc.text(utilizationStr, 147, yPos2);
|
|
48649
48952
|
yPos2 += rowHeight;
|
|
48650
48953
|
});
|
|
48651
|
-
const fileDate2 =
|
|
48954
|
+
const fileDate2 = formatOperationalDateKey(lineInfo.date, {
|
|
48652
48955
|
day: "2-digit",
|
|
48653
48956
|
month: "short",
|
|
48654
|
-
year: "numeric"
|
|
48655
|
-
timeZone: "Asia/Kolkata"
|
|
48957
|
+
year: "numeric"
|
|
48656
48958
|
}).replace(/ /g, "_");
|
|
48657
48959
|
const fileShift2 = shiftType.replace(/ /g, "_");
|
|
48658
48960
|
const fileName2 = `${lineInfo.line_name}_${fileDate2}_${fileShift2}.pdf`;
|
|
@@ -48705,66 +49007,32 @@ var LinePdfGenerator = ({
|
|
|
48705
49007
|
doc.setLineWidth(0.8);
|
|
48706
49008
|
doc.line(20, 123, 190, 123);
|
|
48707
49009
|
const hourlyOverviewStartY = 128;
|
|
48708
|
-
const parseTimeToMinutes4 = (timeStr) => {
|
|
48709
|
-
const [hours, minutes] = timeStr.split(":");
|
|
48710
|
-
const hour = parseInt(hours, 10);
|
|
48711
|
-
const minute = parseInt(minutes || "0", 10);
|
|
48712
|
-
if (Number.isNaN(hour) || Number.isNaN(minute)) {
|
|
48713
|
-
return NaN;
|
|
48714
|
-
}
|
|
48715
|
-
return (hour * 60 + minute) % (24 * 60);
|
|
48716
|
-
};
|
|
48717
49010
|
const formatMinutesLabel = (totalMinutes) => {
|
|
48718
49011
|
const normalized = (totalMinutes % (24 * 60) + 24 * 60) % (24 * 60);
|
|
48719
49012
|
const hour = Math.floor(normalized / 60);
|
|
48720
49013
|
const minute = normalized % 60;
|
|
48721
|
-
const time2 =
|
|
48722
|
-
time2.setHours(hour);
|
|
48723
|
-
time2.setMinutes(minute);
|
|
48724
|
-
time2.setSeconds(0);
|
|
48725
|
-
time2.setMilliseconds(0);
|
|
49014
|
+
const time2 = new Date(Date.UTC(2e3, 0, 1, hour, minute));
|
|
48726
49015
|
return time2.toLocaleTimeString("en-IN", {
|
|
48727
49016
|
hour: "2-digit",
|
|
48728
49017
|
minute: "2-digit",
|
|
48729
49018
|
hour12: true,
|
|
48730
|
-
timeZone: "
|
|
49019
|
+
timeZone: "UTC"
|
|
48731
49020
|
});
|
|
48732
49021
|
};
|
|
48733
|
-
const
|
|
48734
|
-
|
|
48735
|
-
|
|
48736
|
-
|
|
48737
|
-
|
|
48738
|
-
|
|
48739
|
-
|
|
48740
|
-
|
|
48741
|
-
|
|
48742
|
-
|
|
48743
|
-
|
|
48744
|
-
|
|
48745
|
-
|
|
48746
|
-
const defaultHours = 11;
|
|
48747
|
-
return Array.from({ length: defaultHours }, (_, i) => buildRange(startMinutes + i * 60, 60));
|
|
48748
|
-
}
|
|
48749
|
-
const endMinutes = parseTimeToMinutes4(endTimeStr);
|
|
48750
|
-
if (Number.isNaN(endMinutes)) {
|
|
48751
|
-
const fallbackHours = 11;
|
|
48752
|
-
return Array.from({ length: fallbackHours }, (_, i) => buildRange(startMinutes + i * 60, 60));
|
|
48753
|
-
}
|
|
48754
|
-
let durationMinutes = endMinutes - startMinutes;
|
|
48755
|
-
if (durationMinutes <= 0) {
|
|
48756
|
-
durationMinutes += 24 * 60;
|
|
48757
|
-
}
|
|
48758
|
-
const rangeCount = Math.max(1, Math.ceil(durationMinutes / 60));
|
|
48759
|
-
return Array.from({ length: rangeCount }, (_, i) => {
|
|
48760
|
-
const remainingMinutes = durationMinutes - i * 60;
|
|
48761
|
-
const rangeMinutes = remainingMinutes >= 60 ? 60 : remainingMinutes;
|
|
48762
|
-
return buildRange(startMinutes + i * 60, rangeMinutes);
|
|
48763
|
-
});
|
|
48764
|
-
};
|
|
48765
|
-
const hourlyTimeRanges = lineInfo.metrics.shift_start ? getHourlyTimeRanges(lineInfo.metrics.shift_start, lineInfo.metrics.shift_end) : [];
|
|
49022
|
+
const hourlyTimeRanges = buildHourlyIntervals({
|
|
49023
|
+
shiftStart: lineInfo.metrics.shift_start || "06:00",
|
|
49024
|
+
shiftEnd: lineInfo.metrics.shift_end,
|
|
49025
|
+
fallbackHours: 11
|
|
49026
|
+
});
|
|
49027
|
+
const targetPlan = buildHourlyTargetPlan({
|
|
49028
|
+
shiftStart: lineInfo.metrics.shift_start || "06:00",
|
|
49029
|
+
shiftEnd: lineInfo.metrics.shift_end,
|
|
49030
|
+
breaks: shiftBreaks,
|
|
49031
|
+
pphThreshold: Number(lineInfo.metrics.threshold_pph ?? 0),
|
|
49032
|
+
fallbackHours: Math.max(hourlyTimeRanges.length, 1),
|
|
49033
|
+
rounding: "floor"
|
|
49034
|
+
});
|
|
48766
49035
|
const shiftDuration = hourlyTimeRanges.length || 11;
|
|
48767
|
-
const targetOutputPerHour = Math.round(lineInfo.metrics.threshold_pph ?? 0);
|
|
48768
49036
|
let hourlyActualOutput = [];
|
|
48769
49037
|
if (lineInfo.metrics.output_hourly && Object.keys(lineInfo.metrics.output_hourly).length > 0) {
|
|
48770
49038
|
const [startHourStr, startMinuteStr] = (lineInfo.metrics.shift_start || "6:00").split(":");
|
|
@@ -48950,29 +49218,29 @@ var LinePdfGenerator = ({
|
|
|
48950
49218
|
doc.text("Remarks", 160, tableHeaderY);
|
|
48951
49219
|
doc.setFont("helvetica", "normal");
|
|
48952
49220
|
let yPos = tableStartY;
|
|
48953
|
-
const now4 = /* @__PURE__ */ new Date();
|
|
48954
|
-
const currentTimeIST = new Date(now4.toLocaleString("en-US", { timeZone: "Asia/Kolkata" }));
|
|
48955
|
-
const [sYear, sMonth, sDay] = lineInfo.date.split("-").map(Number);
|
|
48956
|
-
const [sStartH, sStartM] = (lineInfo.metrics.shift_start || "06:00").split(":").map(Number);
|
|
48957
|
-
const shiftStartBase = new Date(sYear, sMonth - 1, sDay, sStartH, sStartM || 0);
|
|
48958
49221
|
hourlyTimeRanges.forEach((timeRange, index) => {
|
|
48959
49222
|
const actualOutput = hourlyActualOutput[index] || 0;
|
|
48960
|
-
const
|
|
48961
|
-
|
|
48962
|
-
|
|
48963
|
-
|
|
49223
|
+
const dataCollected = isHourlyIntervalComplete({
|
|
49224
|
+
reportDate: lineInfo.date,
|
|
49225
|
+
shiftStart: lineInfo.metrics.shift_start || "06:00",
|
|
49226
|
+
shiftEnd: lineInfo.metrics.shift_end,
|
|
49227
|
+
interval: timeRange,
|
|
49228
|
+
timeZone: reportTimezone
|
|
49229
|
+
});
|
|
48964
49230
|
const outputStr = dataCollected ? actualOutput.toString() : "TBD";
|
|
48965
49231
|
if (index < totalRows - 1) {
|
|
48966
49232
|
const rowBottomY = headerBottomY + (index + 1) * rowSpacing;
|
|
48967
49233
|
doc.setDrawColor(200, 200, 200);
|
|
48968
49234
|
doc.line(20, rowBottomY, 190, rowBottomY);
|
|
48969
49235
|
}
|
|
48970
|
-
const
|
|
48971
|
-
const
|
|
48972
|
-
const
|
|
48973
|
-
doc.text(timeRange.
|
|
49236
|
+
const targetForRange = targetPlan.targets[index] ?? 0;
|
|
49237
|
+
const targetStr = targetForRange.toString();
|
|
49238
|
+
const remarkText = targetPlan.breakRemarks[index] || "";
|
|
49239
|
+
doc.text(`${formatMinutesLabel(timeRange.start)} - ${formatMinutesLabel(timeRange.end)}`, 25, yPos);
|
|
48974
49240
|
doc.text(outputStr, 75, yPos);
|
|
48975
49241
|
doc.text(targetStr, 105, yPos);
|
|
49242
|
+
const remarkDisplay = remarkText ? doc.splitTextToSize(remarkText, 26)[0] : "";
|
|
49243
|
+
doc.text(remarkDisplay, 160, yPos);
|
|
48976
49244
|
if (!dataCollected) {
|
|
48977
49245
|
doc.setTextColor(100, 100, 100);
|
|
48978
49246
|
doc.text("-", 135, yPos);
|
|
@@ -48988,11 +49256,10 @@ var LinePdfGenerator = ({
|
|
|
48988
49256
|
doc.setTextColor(0, 0, 0);
|
|
48989
49257
|
yPos += rowSpacing;
|
|
48990
49258
|
});
|
|
48991
|
-
const fileDate =
|
|
49259
|
+
const fileDate = formatOperationalDateKey(lineInfo.date, {
|
|
48992
49260
|
day: "2-digit",
|
|
48993
49261
|
month: "short",
|
|
48994
|
-
year: "numeric"
|
|
48995
|
-
timeZone: "Asia/Kolkata"
|
|
49262
|
+
year: "numeric"
|
|
48996
49263
|
}).replace(/ /g, "_");
|
|
48997
49264
|
const fileShift = shiftType.replace(/ /g, "_");
|
|
48998
49265
|
const fileName = `${lineInfo.line_name}_${fileDate}_${fileShift}.pdf`;
|
|
@@ -49920,6 +50187,13 @@ var WorkspaceMonthlyHistory = ({
|
|
|
49920
50187
|
}, [analysisMonthlyData, selectedShiftId, isUptimeMode, shiftWorkSeconds]);
|
|
49921
50188
|
const efficiencyDelta = trendSummary?.avg_efficiency?.delta_pp ?? 0;
|
|
49922
50189
|
const efficiencyImproved = efficiencyDelta >= 0;
|
|
50190
|
+
const assemblyRangeCycleTime = React143.useMemo(() => {
|
|
50191
|
+
const trendCycleTime = Number(trendSummary?.avg_cycle_time?.current);
|
|
50192
|
+
if (Number.isFinite(trendCycleTime) && trendCycleTime > 0) {
|
|
50193
|
+
return Math.round(trendCycleTime);
|
|
50194
|
+
}
|
|
50195
|
+
return metrics2?.avgCycleTime ?? 0;
|
|
50196
|
+
}, [trendSummary?.avg_cycle_time?.current, metrics2?.avgCycleTime]);
|
|
49923
50197
|
const cycleDeltaRaw = trendSummary?.avg_cycle_time?.delta_seconds ?? 0;
|
|
49924
50198
|
const cyclePrev = trendSummary?.avg_cycle_time?.previous ?? 0;
|
|
49925
50199
|
const cycleDelta = cyclePrev ? cycleDeltaRaw / cyclePrev * 100 : 0;
|
|
@@ -50105,7 +50379,7 @@ var WorkspaceMonthlyHistory = ({
|
|
|
50105
50379
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm font-semibold text-gray-600 mb-1", children: "Avg Cycle Time" }),
|
|
50106
50380
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 flex-nowrap", children: [
|
|
50107
50381
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-2xl font-bold text-gray-900", children: [
|
|
50108
|
-
|
|
50382
|
+
assemblyRangeCycleTime,
|
|
50109
50383
|
"s"
|
|
50110
50384
|
] }),
|
|
50111
50385
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: `flex items-center gap-1 ${cycleWorsened ? "bg-red-50 text-red-600" : "bg-emerald-50 text-emerald-600"} px-2 py-0.5 rounded-full text-[10px] font-medium whitespace-nowrap flex-shrink-0`, children: [
|
|
@@ -50441,7 +50715,25 @@ var WorkspaceWhatsAppShareButton = ({
|
|
|
50441
50715
|
}
|
|
50442
50716
|
);
|
|
50443
50717
|
};
|
|
50444
|
-
var
|
|
50718
|
+
var formatOperationalDateKey2 = (dateKey, options) => {
|
|
50719
|
+
const [yearPart, monthPart, dayPart] = dateKey.split("-").map(Number);
|
|
50720
|
+
const year = Number.isFinite(yearPart) ? yearPart : 1970;
|
|
50721
|
+
const month = Number.isFinite(monthPart) ? monthPart : 1;
|
|
50722
|
+
const day = Number.isFinite(dayPart) ? dayPart : 1;
|
|
50723
|
+
return new Date(Date.UTC(year, month - 1, day, 12)).toLocaleDateString("en-IN", {
|
|
50724
|
+
...options,
|
|
50725
|
+
timeZone: "UTC"
|
|
50726
|
+
});
|
|
50727
|
+
};
|
|
50728
|
+
var WorkspacePdfGenerator = ({
|
|
50729
|
+
workspace,
|
|
50730
|
+
className,
|
|
50731
|
+
idleTimeReasons,
|
|
50732
|
+
efficiencyLegend,
|
|
50733
|
+
hourlyCycleTimes,
|
|
50734
|
+
shiftBreaks = [],
|
|
50735
|
+
reportTimezone = "Asia/Kolkata"
|
|
50736
|
+
}) => {
|
|
50445
50737
|
const [isGenerating, setIsGenerating] = React143.useState(false);
|
|
50446
50738
|
const entityConfig = useEntityConfig();
|
|
50447
50739
|
const effectiveLegend = efficiencyLegend || DEFAULT_EFFICIENCY_LEGEND;
|
|
@@ -50471,7 +50763,7 @@ var WorkspacePdfGenerator = ({ workspace, className, idleTimeReasons, efficiency
|
|
|
50471
50763
|
doc.setFontSize(9);
|
|
50472
50764
|
doc.setFont("helvetica", "normal");
|
|
50473
50765
|
doc.setTextColor(100, 100, 100);
|
|
50474
|
-
const generatedText = `Generated on ${(/* @__PURE__ */ new Date()).toLocaleString("en-IN", { timeZone:
|
|
50766
|
+
const generatedText = `Generated on ${(/* @__PURE__ */ new Date()).toLocaleString("en-IN", { timeZone: reportTimezone })}`;
|
|
50475
50767
|
const generatedTextWidth = doc.getStringUnitWidth(generatedText) * 9 / doc.internal.scaleFactor;
|
|
50476
50768
|
doc.text(generatedText, doc.internal.pageSize.width - 20 - generatedTextWidth, 15);
|
|
50477
50769
|
doc.setDrawColor(200, 200, 200);
|
|
@@ -50490,11 +50782,10 @@ var WorkspacePdfGenerator = ({ workspace, className, idleTimeReasons, efficiency
|
|
|
50490
50782
|
doc.setFontSize(13);
|
|
50491
50783
|
doc.setFont("helvetica", "normal");
|
|
50492
50784
|
doc.setTextColor(60, 60, 60);
|
|
50493
|
-
const date =
|
|
50785
|
+
const date = formatOperationalDateKey2(workspace.date, {
|
|
50494
50786
|
weekday: "long",
|
|
50495
50787
|
day: "numeric",
|
|
50496
|
-
month: "long"
|
|
50497
|
-
timeZone: "Asia/Kolkata"
|
|
50788
|
+
month: "long"
|
|
50498
50789
|
});
|
|
50499
50790
|
const rawShiftType = workspace.shift_type || (workspace.shift_id === 0 ? "Day" : workspace.shift_id === 1 ? "Night" : `Shift ${workspace.shift_id}`);
|
|
50500
50791
|
const shiftType = rawShiftType.toLowerCase().includes("shift") ? rawShiftType : `${rawShiftType} Shift`;
|
|
@@ -50503,7 +50794,7 @@ var WorkspacePdfGenerator = ({ workspace, className, idleTimeReasons, efficiency
|
|
|
50503
50794
|
const currentTime = (/* @__PURE__ */ new Date()).toLocaleTimeString("en-IN", {
|
|
50504
50795
|
hour: "2-digit",
|
|
50505
50796
|
minute: "2-digit",
|
|
50506
|
-
timeZone:
|
|
50797
|
+
timeZone: reportTimezone
|
|
50507
50798
|
});
|
|
50508
50799
|
const shiftStartTime = (/* @__PURE__ */ new Date(`2000-01-01 ${workspace.shift_start}`)).toLocaleTimeString("en-IN", {
|
|
50509
50800
|
hour: "2-digit",
|
|
@@ -50515,29 +50806,12 @@ var WorkspacePdfGenerator = ({ workspace, className, idleTimeReasons, efficiency
|
|
|
50515
50806
|
minute: "2-digit",
|
|
50516
50807
|
hour12: true
|
|
50517
50808
|
});
|
|
50518
|
-
const
|
|
50519
|
-
|
|
50520
|
-
|
|
50521
|
-
|
|
50522
|
-
|
|
50523
|
-
};
|
|
50524
|
-
const toShiftUtcMs = (dateKey, timeValue) => {
|
|
50525
|
-
const [yearPart, monthPart, dayPart] = dateKey.split("-").map(Number);
|
|
50526
|
-
const year = Number.isFinite(yearPart) ? yearPart : 1970;
|
|
50527
|
-
const month = Number.isFinite(monthPart) ? monthPart : 1;
|
|
50528
|
-
const day = Number.isFinite(dayPart) ? dayPart : 1;
|
|
50529
|
-
const [hourPart, minutePart] = timeValue.split(":").map(Number);
|
|
50530
|
-
const hour = Number.isFinite(hourPart) ? hourPart : 0;
|
|
50531
|
-
const minute = Number.isFinite(minutePart) ? minutePart : 0;
|
|
50532
|
-
const IST_OFFSET_MINUTES = 330;
|
|
50533
|
-
return Date.UTC(year, month - 1, day, hour, minute) - IST_OFFSET_MINUTES * 60 * 1e3;
|
|
50534
|
-
};
|
|
50535
|
-
const shiftStartMinutes = parseTimeToMinutes4(workspace.shift_start);
|
|
50536
|
-
const shiftEndMinutes = parseTimeToMinutes4(workspace.shift_end);
|
|
50537
|
-
const wrapsMidnight = shiftEndMinutes <= shiftStartMinutes;
|
|
50538
|
-
const shiftStartUtcMs = toShiftUtcMs(workspace.date, workspace.shift_start);
|
|
50539
|
-
const shiftEndUtcMs = toShiftUtcMs(workspace.date, workspace.shift_end) + (wrapsMidnight ? 24 * 60 * 60 * 1e3 : 0);
|
|
50540
|
-
const isShiftInProgress = Date.now() >= shiftStartUtcMs && Date.now() < shiftEndUtcMs;
|
|
50809
|
+
const isShiftInProgress = isShiftInProgressForReportDate({
|
|
50810
|
+
reportDate: workspace.date,
|
|
50811
|
+
shiftStart: workspace.shift_start,
|
|
50812
|
+
shiftEnd: workspace.shift_end,
|
|
50813
|
+
timeZone: reportTimezone
|
|
50814
|
+
});
|
|
50541
50815
|
const reportPeriodEndTime = isShiftInProgress ? currentTime : shiftEndTime;
|
|
50542
50816
|
doc.setFontSize(12);
|
|
50543
50817
|
doc.setTextColor(80, 80, 80);
|
|
@@ -50643,7 +50917,7 @@ var WorkspacePdfGenerator = ({ workspace, className, idleTimeReasons, efficiency
|
|
|
50643
50917
|
shiftStart: workspace.shift_start,
|
|
50644
50918
|
shiftEnd: workspace.shift_end,
|
|
50645
50919
|
shiftDate: workspace.date,
|
|
50646
|
-
timezone:
|
|
50920
|
+
timezone: reportTimezone
|
|
50647
50921
|
}) : null;
|
|
50648
50922
|
const hourlyUptime = uptimeSeries?.points?.length ? Array.from({ length: Math.ceil(uptimeSeries.shiftMinutes / 60) }, (_, index) => {
|
|
50649
50923
|
const start = index * 60;
|
|
@@ -50658,6 +50932,31 @@ var WorkspacePdfGenerator = ({ workspace, className, idleTimeReasons, efficiency
|
|
|
50658
50932
|
const hourlyData = isUptimeMode ? hourlyUptime : isAssemblyCycleMode ? hourlyCycleTimes && hourlyCycleTimes.length > 0 ? hourlyCycleTimes : workspace.hourly_action_counts || [] : workspace.hourly_action_counts || [];
|
|
50659
50933
|
const hourlyTarget = workspace.pph_threshold;
|
|
50660
50934
|
const cycleTarget = workspace.ideal_cycle_time || 0;
|
|
50935
|
+
const hourlyIntervals = buildHourlyIntervals({
|
|
50936
|
+
shiftStart: workspace.shift_start,
|
|
50937
|
+
shiftEnd: workspace.shift_end,
|
|
50938
|
+
fallbackHours: Math.max(hourlyData.length, 1)
|
|
50939
|
+
});
|
|
50940
|
+
const outputTargetPlan = !isUptimeMode && !isAssemblyCycleMode ? buildHourlyTargetPlan({
|
|
50941
|
+
shiftStart: workspace.shift_start,
|
|
50942
|
+
shiftEnd: workspace.shift_end,
|
|
50943
|
+
breaks: shiftBreaks,
|
|
50944
|
+
pphThreshold: workspace.pph_threshold,
|
|
50945
|
+
fallbackHours: Math.max(hourlyData.length, 1),
|
|
50946
|
+
rounding: "floor"
|
|
50947
|
+
}) : null;
|
|
50948
|
+
const formatIntervalLabel = (totalMinutes) => {
|
|
50949
|
+
const normalized = (totalMinutes % (24 * 60) + 24 * 60) % (24 * 60);
|
|
50950
|
+
const hour = Math.floor(normalized / 60);
|
|
50951
|
+
const minute = normalized % 60;
|
|
50952
|
+
const time2 = new Date(Date.UTC(2e3, 0, 1, hour, minute));
|
|
50953
|
+
return time2.toLocaleTimeString("en-IN", {
|
|
50954
|
+
hour: "numeric",
|
|
50955
|
+
...minute > 0 ? { minute: "2-digit" } : {},
|
|
50956
|
+
hour12: true,
|
|
50957
|
+
timeZone: "UTC"
|
|
50958
|
+
});
|
|
50959
|
+
};
|
|
50661
50960
|
const pageHeight = doc.internal.pageSize.height;
|
|
50662
50961
|
const maxContentY = pageHeight - 15;
|
|
50663
50962
|
const baseTableStartY = hourlyPerfStartY + 31;
|
|
@@ -50725,36 +51024,30 @@ var WorkspacePdfGenerator = ({ workspace, className, idleTimeReasons, efficiency
|
|
|
50725
51024
|
doc.setFontSize(contentFontSize);
|
|
50726
51025
|
doc.setFont("helvetica", "normal");
|
|
50727
51026
|
let yPos = headerBottomY + 5.5;
|
|
50728
|
-
const
|
|
50729
|
-
const today = /* @__PURE__ */ new Date();
|
|
50730
|
-
today.setHours(0, 0, 0, 0);
|
|
50731
|
-
workspaceDate.setHours(0, 0, 0, 0);
|
|
50732
|
-
const isToday2 = workspaceDate.getTime() === today.getTime();
|
|
51027
|
+
const isToday2 = getDateKeyInTimeZone(reportTimezone) === workspace.date;
|
|
50733
51028
|
let currentHour = 24;
|
|
50734
51029
|
if (isToday2) {
|
|
50735
51030
|
const now4 = /* @__PURE__ */ new Date();
|
|
50736
|
-
const
|
|
50737
|
-
currentHour =
|
|
51031
|
+
const currentTimeInReportTimezone = new Date(now4.toLocaleString("en-US", { timeZone: reportTimezone }));
|
|
51032
|
+
currentHour = currentTimeInReportTimezone.getHours();
|
|
50738
51033
|
}
|
|
50739
51034
|
hourlyData.forEach((entry, index) => {
|
|
50740
|
-
const
|
|
50741
|
-
|
|
50742
|
-
const
|
|
50743
|
-
|
|
50744
|
-
|
|
50745
|
-
|
|
50746
|
-
|
|
50747
|
-
|
|
50748
|
-
|
|
50749
|
-
hour12: true
|
|
50750
|
-
})}`;
|
|
50751
|
-
const hourNumber = startTime.getHours();
|
|
50752
|
-
const dataCollected = !isToday2 || hourNumber < currentHour;
|
|
51035
|
+
const interval = hourlyIntervals[index];
|
|
51036
|
+
const timeRange = interval ? `${formatIntervalLabel(interval.start)} - ${formatIntervalLabel(interval.end)}` : `${index + 1}`;
|
|
51037
|
+
const dataCollected = interval ? isHourlyIntervalComplete({
|
|
51038
|
+
reportDate: workspace.date,
|
|
51039
|
+
shiftStart: workspace.shift_start,
|
|
51040
|
+
shiftEnd: workspace.shift_end,
|
|
51041
|
+
interval,
|
|
51042
|
+
timeZone: reportTimezone
|
|
51043
|
+
}) : !isToday2 || currentHour >= 24;
|
|
50753
51044
|
const outputValue = isUptimeMode ? entry.activeMinutes ?? 0 : entry;
|
|
50754
51045
|
const idleValue = isUptimeMode ? entry.idleMinutes ?? 0 : 0;
|
|
50755
51046
|
const uptimePercent = isUptimeMode ? entry.uptimePercent ?? 0 : 0;
|
|
50756
51047
|
const outputStr = dataCollected ? outputValue.toString() : "TBD";
|
|
50757
|
-
const
|
|
51048
|
+
const effectiveTarget = outputTargetPlan?.targets[index] ?? hourlyTarget;
|
|
51049
|
+
const remarkText = outputTargetPlan?.breakRemarks[index] || "";
|
|
51050
|
+
const targetStr = isUptimeMode ? dataCollected ? idleValue.toString() : "TBD" : effectiveTarget.toString();
|
|
50758
51051
|
if (index < totalRows - 1) {
|
|
50759
51052
|
const rowBottomY = headerBottomY + (index + 1) * rowHeight;
|
|
50760
51053
|
doc.setDrawColor(200, 200, 200);
|
|
@@ -50786,10 +51079,12 @@ var WorkspacePdfGenerator = ({ workspace, className, idleTimeReasons, efficiency
|
|
|
50786
51079
|
} else {
|
|
50787
51080
|
doc.text(outputStr, 75, yPos);
|
|
50788
51081
|
doc.text(targetStr, 105, yPos);
|
|
51082
|
+
const remarkDisplay = remarkText ? doc.splitTextToSize(remarkText, 26)[0] : "";
|
|
51083
|
+
doc.text(remarkDisplay, 160, yPos);
|
|
50789
51084
|
if (!dataCollected) {
|
|
50790
51085
|
doc.setTextColor(100, 100, 100);
|
|
50791
51086
|
doc.text("-", 135, yPos);
|
|
50792
|
-
} else if (outputValue >=
|
|
51087
|
+
} else if (outputValue >= effectiveTarget) {
|
|
50793
51088
|
doc.setTextColor(0, 171, 69);
|
|
50794
51089
|
doc.setFont("ZapfDingbats", "normal");
|
|
50795
51090
|
doc.text("4", 135, yPos);
|
|
@@ -50803,11 +51098,10 @@ var WorkspacePdfGenerator = ({ workspace, className, idleTimeReasons, efficiency
|
|
|
50803
51098
|
yPos += rowHeight;
|
|
50804
51099
|
});
|
|
50805
51100
|
const workspaceDisplayName = getWorkspaceDisplayName(workspace.workspace_name, workspace.line_id);
|
|
50806
|
-
const fileDate =
|
|
51101
|
+
const fileDate = formatOperationalDateKey2(workspace.date, {
|
|
50807
51102
|
day: "2-digit",
|
|
50808
51103
|
month: "short",
|
|
50809
|
-
year: "numeric"
|
|
50810
|
-
timeZone: "Asia/Kolkata"
|
|
51104
|
+
year: "numeric"
|
|
50811
51105
|
}).replace(/ /g, "_");
|
|
50812
51106
|
const fileShift = shiftType.replace(/ /g, "_");
|
|
50813
51107
|
const fileName = `${workspaceDisplayName}_${fileDate}_${fileShift}.pdf`;
|
|
@@ -50853,12 +51147,25 @@ var WorkspaceMonthlyPdfGenerator = ({
|
|
|
50853
51147
|
availableShifts,
|
|
50854
51148
|
shiftConfig,
|
|
50855
51149
|
efficiencyLegend,
|
|
51150
|
+
trendSummary,
|
|
50856
51151
|
className,
|
|
50857
51152
|
compact = false,
|
|
50858
51153
|
isAssemblyWorkspace = false
|
|
50859
51154
|
}) => {
|
|
50860
51155
|
const [isGenerating, setIsGenerating] = React143.useState(false);
|
|
50861
51156
|
const effectiveLegend = efficiencyLegend || DEFAULT_EFFICIENCY_LEGEND;
|
|
51157
|
+
const drawStatusMark = (doc, x, y, met) => {
|
|
51158
|
+
doc.setLineWidth(0.8);
|
|
51159
|
+
if (met) {
|
|
51160
|
+
doc.setDrawColor(0, 171, 69);
|
|
51161
|
+
doc.line(x - 1.8, y - 0.2, x - 0.5, y + 1.2);
|
|
51162
|
+
doc.line(x - 0.5, y + 1.2, x + 2.1, y - 1.6);
|
|
51163
|
+
return;
|
|
51164
|
+
}
|
|
51165
|
+
doc.setDrawColor(227, 67, 41);
|
|
51166
|
+
doc.line(x - 1.8, y - 1.6, x + 1.8, y + 1.6);
|
|
51167
|
+
doc.line(x - 1.8, y + 1.6, x + 1.8, y - 1.6);
|
|
51168
|
+
};
|
|
50862
51169
|
const generatePDF = async () => {
|
|
50863
51170
|
setIsGenerating(true);
|
|
50864
51171
|
try {
|
|
@@ -51053,12 +51360,13 @@ var WorkspaceMonthlyPdfGenerator = ({
|
|
|
51053
51360
|
doc.setFont("helvetica", "bold");
|
|
51054
51361
|
doc.text(`${outputMetrics.underperformingDays} of ${outputMetrics.totalDays}`, 120, kpiStartY + kpiSpacing * 3);
|
|
51055
51362
|
} else {
|
|
51363
|
+
const medianCycleTime = Number.isFinite(trendSummary?.avg_cycle_time?.current) ? Number(trendSummary?.avg_cycle_time?.current) : outputMetrics.avgCycleTime;
|
|
51056
51364
|
createKPIBox(kpiStartY);
|
|
51057
51365
|
doc.setFontSize(11);
|
|
51058
51366
|
doc.setFont("helvetica", "normal");
|
|
51059
51367
|
doc.text("Average Cycle Time:", 25, kpiStartY);
|
|
51060
51368
|
doc.setFont("helvetica", "bold");
|
|
51061
|
-
doc.text(`${
|
|
51369
|
+
doc.text(`${medianCycleTime.toFixed(1)}s`, 120, kpiStartY);
|
|
51062
51370
|
createKPIBox(kpiStartY + kpiSpacing);
|
|
51063
51371
|
doc.setFont("helvetica", "normal");
|
|
51064
51372
|
doc.text("Average Idle Time:", 25, kpiStartY + kpiSpacing);
|
|
@@ -51093,8 +51401,8 @@ var WorkspaceMonthlyPdfGenerator = ({
|
|
|
51093
51401
|
doc.roundedRect(20, tableHeaderY, 170, 7, 1, 1, "F");
|
|
51094
51402
|
const textY = tableHeaderY + 5;
|
|
51095
51403
|
doc.text("Date", 25, textY);
|
|
51096
|
-
doc.text(isUptimeMode ? "Productive" : isAssemblyWorkspace ? "Cycle Time" : "Actual", 60, textY);
|
|
51097
|
-
doc.text(isUptimeMode ? "Idle" : isAssemblyWorkspace ? "
|
|
51404
|
+
doc.text(isUptimeMode ? "Productive" : isAssemblyWorkspace ? "Actual Cycle Time" : "Actual", 60, textY);
|
|
51405
|
+
doc.text(isUptimeMode ? "Idle" : isAssemblyWorkspace ? "Standard Cycle Time" : "Standard", 95, textY);
|
|
51098
51406
|
doc.text(isUptimeMode ? "Utilization" : "Efficiency", 135, textY);
|
|
51099
51407
|
doc.text("Status", 170, textY);
|
|
51100
51408
|
doc.setLineWidth(0.2);
|
|
@@ -51126,31 +51434,18 @@ var WorkspaceMonthlyPdfGenerator = ({
|
|
|
51126
51434
|
doc.text(formatIdleTime(productiveSeconds), 60, yPos);
|
|
51127
51435
|
doc.text(formatIdleTime(clampedIdleSeconds), 95, yPos);
|
|
51128
51436
|
doc.text(`${utilization}%`, 135, yPos);
|
|
51129
|
-
|
|
51130
|
-
doc.setTextColor(0, 171, 69);
|
|
51131
|
-
doc.text("\u2713", 170, yPos);
|
|
51132
|
-
} else {
|
|
51133
|
-
doc.setTextColor(227, 67, 41);
|
|
51134
|
-
doc.text("\xD7", 170, yPos);
|
|
51135
|
-
}
|
|
51136
|
-
doc.setTextColor(0, 0, 0);
|
|
51437
|
+
drawStatusMark(doc, 171, yPos - 0.3, utilization >= effectiveLegend.green_min);
|
|
51137
51438
|
} else {
|
|
51138
51439
|
if (isAssemblyWorkspace) {
|
|
51440
|
+
const targetCycleTime = Number.isFinite(shift.idealCycleTime) && Number(shift.idealCycleTime) > 0 ? Number(shift.idealCycleTime) : shift.pphThreshold > 0 ? 3600 / shift.pphThreshold : null;
|
|
51139
51441
|
doc.text(`${shift.cycleTime.toFixed(1)}`, 60, yPos);
|
|
51140
|
-
doc.text(
|
|
51442
|
+
doc.text(targetCycleTime !== null ? `${targetCycleTime.toFixed(1)}` : "-", 95, yPos);
|
|
51141
51443
|
} else {
|
|
51142
51444
|
doc.text(`${shift.output}`, 60, yPos);
|
|
51143
51445
|
doc.text(`${shift.targetOutput}`, 95, yPos);
|
|
51144
51446
|
}
|
|
51145
51447
|
doc.text(`${shift.efficiency.toFixed(1)}%`, 135, yPos);
|
|
51146
|
-
|
|
51147
|
-
doc.setTextColor(0, 171, 69);
|
|
51148
|
-
doc.text("\u2713", 170, yPos);
|
|
51149
|
-
} else {
|
|
51150
|
-
doc.setTextColor(227, 67, 41);
|
|
51151
|
-
doc.text("\xD7", 170, yPos);
|
|
51152
|
-
}
|
|
51153
|
-
doc.setTextColor(0, 0, 0);
|
|
51448
|
+
drawStatusMark(doc, 171, yPos - 0.3, shift.efficiency >= effectiveLegend.green_min);
|
|
51154
51449
|
}
|
|
51155
51450
|
yPos += 8;
|
|
51156
51451
|
});
|
|
@@ -64316,7 +64611,17 @@ var KPIDetailView = ({
|
|
|
64316
64611
|
)
|
|
64317
64612
|
] }),
|
|
64318
64613
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 ml-auto", children: [
|
|
64319
|
-
resolvedLineInfo && activeTab === "overview" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
64614
|
+
resolvedLineInfo && activeTab === "overview" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
64615
|
+
LinePdfGenerator,
|
|
64616
|
+
{
|
|
64617
|
+
lineInfo: resolvedLineInfo,
|
|
64618
|
+
workspaceData: resolvedWorkspaces || [],
|
|
64619
|
+
issueResolutionSummary,
|
|
64620
|
+
shiftName: getShiftName(resolvedLineInfo.shift_id),
|
|
64621
|
+
shiftBreaks: shiftConfig?.shifts?.find((shift) => shift.shiftId === resolvedLineInfo.shift_id)?.breaks || [],
|
|
64622
|
+
reportTimezone: shiftConfig?.timezone || configuredTimezone
|
|
64623
|
+
}
|
|
64624
|
+
),
|
|
64320
64625
|
activeTab === "monthly_history" && !urlDate && !urlShift && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
64321
64626
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
64322
64627
|
MonthlyRangeFilter_default,
|
|
@@ -64345,6 +64650,8 @@ var KPIDetailView = ({
|
|
|
64345
64650
|
rangeStart,
|
|
64346
64651
|
rangeEnd,
|
|
64347
64652
|
selectedShiftId,
|
|
64653
|
+
availableShifts: shiftConfig?.shifts?.map((shift) => ({ id: shift.shiftId, name: shift.shiftName })),
|
|
64654
|
+
lineAssembly: resolvedLineInfo?.assembly === true,
|
|
64348
64655
|
compact: true
|
|
64349
64656
|
}
|
|
64350
64657
|
)
|
|
@@ -64523,7 +64830,7 @@ var KPIDetailViewWithDisplayNames = withSelectedLineDisplayNames(KPIDetailView);
|
|
|
64523
64830
|
var KPIDetailView_default = KPIDetailViewWithDisplayNames;
|
|
64524
64831
|
var isNonEmptyString = (value) => typeof value === "string" && value.trim().length > 0;
|
|
64525
64832
|
var resolveCompanyId = (...candidates) => candidates.find(isNonEmptyString);
|
|
64526
|
-
var
|
|
64833
|
+
var parseTimeToMinutes3 = (value) => {
|
|
64527
64834
|
if (!value) return null;
|
|
64528
64835
|
const [hourStr, minuteStr] = value.split(":");
|
|
64529
64836
|
const hour = Number.parseInt(hourStr ?? "", 10);
|
|
@@ -64535,8 +64842,8 @@ var getShiftEndDate = (shift, timezone) => {
|
|
|
64535
64842
|
if (!shift?.date) return null;
|
|
64536
64843
|
const startTime = shift.startTime || "06:00";
|
|
64537
64844
|
const endTime = shift.endTime || "18:00";
|
|
64538
|
-
const startMinutes =
|
|
64539
|
-
const endMinutes =
|
|
64845
|
+
const startMinutes = parseTimeToMinutes3(startTime);
|
|
64846
|
+
const endMinutes = parseTimeToMinutes3(endTime);
|
|
64540
64847
|
if (startMinutes === null || endMinutes === null) return null;
|
|
64541
64848
|
const shiftStartDate = dateFnsTz.fromZonedTime(`${shift.date}T${startTime}:00`, timezone);
|
|
64542
64849
|
let durationMinutes = endMinutes - startMinutes;
|
|
@@ -64574,7 +64881,7 @@ var createKpisOverviewUrl = ({
|
|
|
64574
64881
|
return queryString ? `/kpis?${queryString}` : "/kpis";
|
|
64575
64882
|
};
|
|
64576
64883
|
var getZonedDateAtMidday = (dateKey, timezone) => dateFnsTz.fromZonedTime(`${dateKey}T12:00:00`, timezone);
|
|
64577
|
-
var
|
|
64884
|
+
var formatDateKey2 = (dateKey, timezone, options) => {
|
|
64578
64885
|
try {
|
|
64579
64886
|
return new Intl.DateTimeFormat("en-US", {
|
|
64580
64887
|
...options,
|
|
@@ -65642,7 +65949,7 @@ var KPIsOverviewView = ({
|
|
|
65642
65949
|
setActiveTab(newTab);
|
|
65643
65950
|
}, [activeTab, leaderboardLines.length, lines.length]);
|
|
65644
65951
|
const formatLocalDate2 = React143.useCallback((dateKey) => {
|
|
65645
|
-
return
|
|
65952
|
+
return formatDateKey2(dateKey, configuredTimezone, {
|
|
65646
65953
|
year: "numeric",
|
|
65647
65954
|
month: "long",
|
|
65648
65955
|
day: "numeric"
|
|
@@ -65656,8 +65963,8 @@ var KPIsOverviewView = ({
|
|
|
65656
65963
|
zonedNow.getMonth(),
|
|
65657
65964
|
new Date(zonedNow.getFullYear(), zonedNow.getMonth() + 1, 0).getDate()
|
|
65658
65965
|
);
|
|
65659
|
-
const startLabel =
|
|
65660
|
-
const endLabel =
|
|
65966
|
+
const startLabel = formatDateKey2(startOfMonthKey, configuredTimezone, { month: "short", day: "numeric" });
|
|
65967
|
+
const endLabel = formatDateKey2(endOfMonthKey, configuredTimezone, { month: "short", day: "numeric" });
|
|
65661
65968
|
return `${startLabel} - ${endLabel}, ${zonedNow.getFullYear()}`;
|
|
65662
65969
|
};
|
|
65663
65970
|
const isMonthlyMode = activeTab === "leaderboard" && timeRange === "monthly";
|
|
@@ -71292,6 +71599,7 @@ var WorkspaceDetailView = ({
|
|
|
71292
71599
|
efficiency: monitoringMode === "uptime" ? Number.isFinite(metric.avg_efficiency) ? Number(metric.avg_efficiency) : computedUptimeEfficiency : Number.isFinite(metric.avg_efficiency) ? Number(metric.avg_efficiency) : 0,
|
|
71293
71600
|
output: metric.total_output || 0,
|
|
71294
71601
|
cycleTime: metric.avg_cycle_time || 0,
|
|
71602
|
+
idealCycleTime: Number(metric.ideal_cycle_time || 0),
|
|
71295
71603
|
pph: metric.avg_pph || 0,
|
|
71296
71604
|
pphThreshold: metric.pph_threshold || 0,
|
|
71297
71605
|
idealOutput: Number(metric.ideal_output || 0),
|
|
@@ -71847,7 +72155,9 @@ var WorkspaceDetailView = ({
|
|
|
71847
72155
|
workspace,
|
|
71848
72156
|
idleTimeReasons: idleTimeChartData,
|
|
71849
72157
|
efficiencyLegend,
|
|
71850
|
-
hourlyCycleTimes: cycleTimeChartData
|
|
72158
|
+
hourlyCycleTimes: cycleTimeChartData,
|
|
72159
|
+
shiftBreaks: shiftConfig?.shifts?.find((shift2) => shift2.shiftId === workspace.shift_id)?.breaks || [],
|
|
72160
|
+
reportTimezone: shiftConfig?.timezone || timezone
|
|
71851
72161
|
}
|
|
71852
72162
|
) }),
|
|
71853
72163
|
activeTab === "monthly_history" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
@@ -71882,6 +72192,7 @@ var WorkspaceDetailView = ({
|
|
|
71882
72192
|
workspaceId,
|
|
71883
72193
|
workspaceName: formattedWorkspaceName,
|
|
71884
72194
|
monthlyData,
|
|
72195
|
+
analysisData: analysisMonthlyData,
|
|
71885
72196
|
selectedMonth,
|
|
71886
72197
|
selectedYear,
|
|
71887
72198
|
monitoringMode: workspace?.monitoring_mode,
|
|
@@ -71890,7 +72201,10 @@ var WorkspaceDetailView = ({
|
|
|
71890
72201
|
selectedShiftId: selectedShift,
|
|
71891
72202
|
availableShifts: shiftConfig?.shifts?.map((s) => ({ id: s.shiftId, name: s.shiftName })),
|
|
71892
72203
|
shiftConfig,
|
|
71893
|
-
|
|
72204
|
+
efficiencyLegend,
|
|
72205
|
+
trendSummary: workspaceMonthlyTrend,
|
|
72206
|
+
compact: true,
|
|
72207
|
+
isAssemblyWorkspace
|
|
71894
72208
|
}
|
|
71895
72209
|
)
|
|
71896
72210
|
] })
|
|
@@ -80105,7 +80419,7 @@ var useOperationsOverviewRefresh = ({
|
|
|
80105
80419
|
};
|
|
80106
80420
|
}, [companyId, enabled, getIsPageActive, isLiveScope, lineIds.length, refreshFromResume, startPolling, stopPolling, supabase]);
|
|
80107
80421
|
};
|
|
80108
|
-
var
|
|
80422
|
+
var parseTimeToMinutes4 = (value) => {
|
|
80109
80423
|
if (!value) return null;
|
|
80110
80424
|
const parts = value.split(":");
|
|
80111
80425
|
if (parts.length < 2) return null;
|
|
@@ -80140,8 +80454,8 @@ var classifyShiftBucket = ({
|
|
|
80140
80454
|
return "day";
|
|
80141
80455
|
}
|
|
80142
80456
|
}
|
|
80143
|
-
const startMinutes =
|
|
80144
|
-
const endMinutes =
|
|
80457
|
+
const startMinutes = parseTimeToMinutes4(startTime);
|
|
80458
|
+
const endMinutes = parseTimeToMinutes4(endTime);
|
|
80145
80459
|
if (startMinutes !== null) {
|
|
80146
80460
|
if (startMinutes >= 4 * 60 && startMinutes < 18 * 60) return "day";
|
|
80147
80461
|
return "night";
|
|
@@ -80200,8 +80514,8 @@ var getShiftWindowsForConfig = (shiftConfig, timezone) => {
|
|
|
80200
80514
|
];
|
|
80201
80515
|
};
|
|
80202
80516
|
var normalizeShiftWindowMinutes = (startTime, endTime) => {
|
|
80203
|
-
const startMinutes =
|
|
80204
|
-
const endMinutesRaw =
|
|
80517
|
+
const startMinutes = parseTimeToMinutes4(startTime);
|
|
80518
|
+
const endMinutesRaw = parseTimeToMinutes4(endTime);
|
|
80205
80519
|
if (startMinutes === null || endMinutesRaw === null) {
|
|
80206
80520
|
return null;
|
|
80207
80521
|
}
|
|
@@ -80367,7 +80681,7 @@ var PlantHeadView = () => {
|
|
|
80367
80681
|
startTime: shift.startTime,
|
|
80368
80682
|
endTime: shift.endTime
|
|
80369
80683
|
});
|
|
80370
|
-
const startMinutes =
|
|
80684
|
+
const startMinutes = parseTimeToMinutes4(shift.startTime);
|
|
80371
80685
|
if (bucket === "day" && startMinutes !== null) {
|
|
80372
80686
|
candidateStarts.push(startMinutes);
|
|
80373
80687
|
}
|
|
@@ -80377,7 +80691,7 @@ var PlantHeadView = () => {
|
|
|
80377
80691
|
scopedLineIds.forEach((lineId) => {
|
|
80378
80692
|
const shiftConfig = shiftConfigMap.get(lineId) || staticShiftConfig;
|
|
80379
80693
|
getShiftWindowsForConfig(shiftConfig).forEach((shift) => {
|
|
80380
|
-
const startMinutes =
|
|
80694
|
+
const startMinutes = parseTimeToMinutes4(shift.startTime);
|
|
80381
80695
|
if (startMinutes !== null) {
|
|
80382
80696
|
candidateStarts.push(startMinutes);
|
|
80383
80697
|
}
|
|
@@ -80468,7 +80782,7 @@ var PlantHeadView = () => {
|
|
|
80468
80782
|
startTime: shift.startTime,
|
|
80469
80783
|
endTime: shift.endTime
|
|
80470
80784
|
});
|
|
80471
|
-
return bucket === "day" ?
|
|
80785
|
+
return bucket === "day" ? parseTimeToMinutes4(shift.startTime) : null;
|
|
80472
80786
|
}).filter((value) => value !== null);
|
|
80473
80787
|
}) : [];
|
|
80474
80788
|
if (dayStartCandidates.length > 0) {
|