@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.mjs
CHANGED
|
@@ -1638,6 +1638,7 @@ var DEFAULT_SHIFT_DATA = {
|
|
|
1638
1638
|
efficiency: 0,
|
|
1639
1639
|
output: 0,
|
|
1640
1640
|
cycleTime: 0,
|
|
1641
|
+
idealCycleTime: 0,
|
|
1641
1642
|
pph: 0,
|
|
1642
1643
|
pphThreshold: 0,
|
|
1643
1644
|
idealOutput: 0,
|
|
@@ -4484,6 +4485,7 @@ var dashboardService = {
|
|
|
4484
4485
|
avg_efficiency: item.avg_efficiency || 0,
|
|
4485
4486
|
total_output: item.total_output || 0,
|
|
4486
4487
|
avg_cycle_time: item.avg_cycle_time || 0,
|
|
4488
|
+
ideal_cycle_time: item.ideal_cycle_time ?? 0,
|
|
4487
4489
|
ideal_output: item.ideal_output || 0,
|
|
4488
4490
|
total_day_output: item.total_day_output ?? item.ideal_output ?? 0,
|
|
4489
4491
|
avg_pph: item.avg_pph || 0,
|
|
@@ -17280,7 +17282,7 @@ var useActiveBreaks = (lineIds) => {
|
|
|
17280
17282
|
const [isLoading, setIsLoading] = useState(true);
|
|
17281
17283
|
const [error, setError] = useState(null);
|
|
17282
17284
|
const supabase = useSupabase();
|
|
17283
|
-
const
|
|
17285
|
+
const parseTimeToMinutes5 = (timeStr) => {
|
|
17284
17286
|
const [hours, minutes] = timeStr.split(":").map(Number);
|
|
17285
17287
|
return hours * 60 + minutes;
|
|
17286
17288
|
};
|
|
@@ -17289,8 +17291,8 @@ var useActiveBreaks = (lineIds) => {
|
|
|
17289
17291
|
return now4.getHours() * 60 + now4.getMinutes();
|
|
17290
17292
|
};
|
|
17291
17293
|
const isTimeInBreak = (breakStart, breakEnd, currentMinutes) => {
|
|
17292
|
-
const startMinutes =
|
|
17293
|
-
const endMinutes =
|
|
17294
|
+
const startMinutes = parseTimeToMinutes5(breakStart);
|
|
17295
|
+
const endMinutes = parseTimeToMinutes5(breakEnd);
|
|
17294
17296
|
if (endMinutes < startMinutes) {
|
|
17295
17297
|
return currentMinutes >= startMinutes || currentMinutes < endMinutes;
|
|
17296
17298
|
} else {
|
|
@@ -17298,8 +17300,8 @@ var useActiveBreaks = (lineIds) => {
|
|
|
17298
17300
|
}
|
|
17299
17301
|
};
|
|
17300
17302
|
const calculateBreakProgress = (breakStart, breakEnd, currentMinutes) => {
|
|
17301
|
-
const startMinutes =
|
|
17302
|
-
const endMinutes =
|
|
17303
|
+
const startMinutes = parseTimeToMinutes5(breakStart);
|
|
17304
|
+
const endMinutes = parseTimeToMinutes5(breakEnd);
|
|
17303
17305
|
let elapsedMinutes = 0;
|
|
17304
17306
|
let remainingMinutes = 0;
|
|
17305
17307
|
if (endMinutes < startMinutes) {
|
|
@@ -17317,8 +17319,8 @@ var useActiveBreaks = (lineIds) => {
|
|
|
17317
17319
|
return { elapsedMinutes, remainingMinutes };
|
|
17318
17320
|
};
|
|
17319
17321
|
const isTimeInShift = (startTime, endTime, currentMinutes) => {
|
|
17320
|
-
const startMinutes =
|
|
17321
|
-
const endMinutes =
|
|
17322
|
+
const startMinutes = parseTimeToMinutes5(startTime);
|
|
17323
|
+
const endMinutes = parseTimeToMinutes5(endTime);
|
|
17322
17324
|
if (endMinutes < startMinutes) {
|
|
17323
17325
|
return currentMinutes >= startMinutes || currentMinutes < endMinutes;
|
|
17324
17326
|
} else {
|
|
@@ -17378,8 +17380,8 @@ var useActiveBreaks = (lineIds) => {
|
|
|
17378
17380
|
const endTime = breakItem.end || breakItem.endTime || "00:00";
|
|
17379
17381
|
let duration = breakItem.duration || 0;
|
|
17380
17382
|
if (!duration || duration === 0) {
|
|
17381
|
-
const startMinutes =
|
|
17382
|
-
const endMinutes =
|
|
17383
|
+
const startMinutes = parseTimeToMinutes5(startTime);
|
|
17384
|
+
const endMinutes = parseTimeToMinutes5(endTime);
|
|
17383
17385
|
duration = endMinutes < startMinutes ? endMinutes + 24 * 60 - startMinutes : endMinutes - startMinutes;
|
|
17384
17386
|
}
|
|
17385
17387
|
return {
|
|
@@ -17395,8 +17397,8 @@ var useActiveBreaks = (lineIds) => {
|
|
|
17395
17397
|
const endTime = breakItem.end || breakItem.endTime || "00:00";
|
|
17396
17398
|
let duration = breakItem.duration || 0;
|
|
17397
17399
|
if (!duration || duration === 0) {
|
|
17398
|
-
const startMinutes =
|
|
17399
|
-
const endMinutes =
|
|
17400
|
+
const startMinutes = parseTimeToMinutes5(startTime);
|
|
17401
|
+
const endMinutes = parseTimeToMinutes5(endTime);
|
|
17400
17402
|
duration = endMinutes < startMinutes ? endMinutes + 24 * 60 - startMinutes : endMinutes - startMinutes;
|
|
17401
17403
|
}
|
|
17402
17404
|
return {
|
|
@@ -33411,13 +33413,13 @@ var CycleTimeOverTimeChart = ({
|
|
|
33411
33413
|
observer.observe(containerRef.current);
|
|
33412
33414
|
return () => observer.disconnect();
|
|
33413
33415
|
}, []);
|
|
33414
|
-
const
|
|
33416
|
+
const parseTimeToMinutes5 = (value) => {
|
|
33415
33417
|
const [hours, minutes] = value.split(":").map(Number);
|
|
33416
33418
|
if (!Number.isFinite(hours) || !Number.isFinite(minutes)) return 0;
|
|
33417
33419
|
return hours * 60 + minutes;
|
|
33418
33420
|
};
|
|
33419
33421
|
const formatHourLabel = (slotIndex) => {
|
|
33420
|
-
const baseMinutes =
|
|
33422
|
+
const baseMinutes = parseTimeToMinutes5(shiftStart);
|
|
33421
33423
|
const absoluteMinutes = baseMinutes + slotIndex * 60;
|
|
33422
33424
|
const hour24 = Math.floor(absoluteMinutes % (24 * 60) / 60);
|
|
33423
33425
|
const ampm = hour24 >= 12 ? "PM" : "AM";
|
|
@@ -37418,6 +37420,14 @@ var formatTimestampRange = (startTime, endTime, timezone) => {
|
|
|
37418
37420
|
});
|
|
37419
37421
|
return `${startFormatted} - ${endFormatted}`;
|
|
37420
37422
|
};
|
|
37423
|
+
var buildPrefetchedExplorerMetadata = (activeFilter, metadataCategoryId, categoryMetadata) => {
|
|
37424
|
+
if (!activeFilter || !metadataCategoryId || metadataCategoryId !== activeFilter || categoryMetadata.length === 0) {
|
|
37425
|
+
return void 0;
|
|
37426
|
+
}
|
|
37427
|
+
return {
|
|
37428
|
+
[activeFilter]: categoryMetadata
|
|
37429
|
+
};
|
|
37430
|
+
};
|
|
37421
37431
|
var getSecondsBetweenTimestamps = (startTime, endTime) => {
|
|
37422
37432
|
const startDate = parseTimestamp(startTime);
|
|
37423
37433
|
const endDate = parseTimestamp(endTime);
|
|
@@ -42615,6 +42625,7 @@ var BottlenecksContent = ({
|
|
|
42615
42625
|
const [error, setError] = useState(null);
|
|
42616
42626
|
const [clipClassifications, setClipClassifications] = useState({});
|
|
42617
42627
|
const [categoryMetadata, setCategoryMetadata] = useState([]);
|
|
42628
|
+
const [categoryMetadataCategoryId, setCategoryMetadataCategoryId] = useState(null);
|
|
42618
42629
|
const [currentMetadataIndex, setCurrentMetadataIndex] = useState(0);
|
|
42619
42630
|
const [metadataCache, setMetadataCache] = useState({});
|
|
42620
42631
|
const invalidateMetadataCache = useCallback((categories) => {
|
|
@@ -43086,6 +43097,15 @@ var BottlenecksContent = ({
|
|
|
43086
43097
|
const getMetadataCacheKey = useCallback((categoryId) => {
|
|
43087
43098
|
return `${categoryId}-${effectiveDateString}-${effectiveShiftId}-${snapshotDateTime ?? "nosnap"}-${snapshotClipId ?? "nosnap"}`;
|
|
43088
43099
|
}, [effectiveDateString, effectiveShiftId, snapshotDateTime, snapshotClipId]);
|
|
43100
|
+
const setVisibleCategoryMetadata = useCallback((categoryId, clips) => {
|
|
43101
|
+
if (activeFilterRef.current !== categoryId) {
|
|
43102
|
+
return false;
|
|
43103
|
+
}
|
|
43104
|
+
categoryMetadataRef.current = clips;
|
|
43105
|
+
setCategoryMetadata(clips);
|
|
43106
|
+
setCategoryMetadataCategoryId(clips.length > 0 ? categoryId : null);
|
|
43107
|
+
return true;
|
|
43108
|
+
}, []);
|
|
43089
43109
|
const applyMetadataSnapshot = useCallback((categoryId, clips, total) => {
|
|
43090
43110
|
if (!clips || clips.length === 0) {
|
|
43091
43111
|
return;
|
|
@@ -43095,13 +43115,12 @@ var BottlenecksContent = ({
|
|
|
43095
43115
|
...prev,
|
|
43096
43116
|
[cacheKey]: clips
|
|
43097
43117
|
}));
|
|
43098
|
-
|
|
43099
|
-
setCategoryMetadata(clips);
|
|
43118
|
+
setVisibleCategoryMetadata(categoryId, clips);
|
|
43100
43119
|
if (!isPercentileCategory(categoryId) && typeof total === "number") {
|
|
43101
43120
|
currentTotalRef.current = total;
|
|
43102
43121
|
setCurrentTotal(total);
|
|
43103
43122
|
}
|
|
43104
|
-
}, [getMetadataCacheKey, isPercentileCategory]);
|
|
43123
|
+
}, [getMetadataCacheKey, isPercentileCategory, setVisibleCategoryMetadata]);
|
|
43105
43124
|
const getClipTypesForPercentileCategory = useCallback((categoryId) => {
|
|
43106
43125
|
switch (categoryId) {
|
|
43107
43126
|
case "fast-cycles":
|
|
@@ -43126,6 +43145,7 @@ var BottlenecksContent = ({
|
|
|
43126
43145
|
return;
|
|
43127
43146
|
}
|
|
43128
43147
|
setCategoryMetadata([]);
|
|
43148
|
+
setCategoryMetadataCategoryId(null);
|
|
43129
43149
|
categoryMetadataRef.current = [];
|
|
43130
43150
|
updateActiveFilter(fallbackFilter);
|
|
43131
43151
|
}, [isFastSlowClipFiltersEnabled, activeFilter, dynamicCounts, clipTypes, updateActiveFilter]);
|
|
@@ -43172,6 +43192,7 @@ var BottlenecksContent = ({
|
|
|
43172
43192
|
}
|
|
43173
43193
|
if (!isFastSlowClipFiltersEnabled && (categoryId === "fast-cycles" || categoryId === "slow-cycles")) {
|
|
43174
43194
|
setCategoryMetadata([]);
|
|
43195
|
+
setCategoryMetadataCategoryId(null);
|
|
43175
43196
|
categoryMetadataRef.current = [];
|
|
43176
43197
|
return;
|
|
43177
43198
|
}
|
|
@@ -43185,8 +43206,7 @@ var BottlenecksContent = ({
|
|
|
43185
43206
|
try {
|
|
43186
43207
|
if (cachedMetadata) {
|
|
43187
43208
|
console.log(`[BottlenecksContent] Using cached metadata for ${categoryId}`);
|
|
43188
|
-
|
|
43189
|
-
categoryMetadataRef.current = cachedMetadata;
|
|
43209
|
+
setVisibleCategoryMetadata(categoryId, cachedMetadata);
|
|
43190
43210
|
if (autoLoadFirstVideo && cachedMetadata.length > 0 && s3ClipsService) {
|
|
43191
43211
|
const firstClipMeta = cachedMetadata[0];
|
|
43192
43212
|
try {
|
|
@@ -43300,8 +43320,7 @@ var BottlenecksContent = ({
|
|
|
43300
43320
|
...prev,
|
|
43301
43321
|
[cacheKey]: metadataClips
|
|
43302
43322
|
}));
|
|
43303
|
-
|
|
43304
|
-
categoryMetadataRef.current = metadataClips;
|
|
43323
|
+
setVisibleCategoryMetadata(categoryId, metadataClips);
|
|
43305
43324
|
console.log(`[BottlenecksContent] Loaded metadata for ${categoryId}: ${metadataClips.length} clips`);
|
|
43306
43325
|
if (autoLoadFirstVideo && metadataClips.length > 0 && s3ClipsService) {
|
|
43307
43326
|
const firstClipMeta = metadataClips[0];
|
|
@@ -43320,15 +43339,18 @@ var BottlenecksContent = ({
|
|
|
43320
43339
|
}
|
|
43321
43340
|
}
|
|
43322
43341
|
} else {
|
|
43323
|
-
|
|
43324
|
-
|
|
43342
|
+
if (activeFilterRef.current === categoryId) {
|
|
43343
|
+
setCategoryMetadata([]);
|
|
43344
|
+
setCategoryMetadataCategoryId(null);
|
|
43345
|
+
categoryMetadataRef.current = [];
|
|
43346
|
+
}
|
|
43325
43347
|
}
|
|
43326
43348
|
} catch (error2) {
|
|
43327
43349
|
console.error(`[BottlenecksContent] Error loading category metadata:`, error2);
|
|
43328
43350
|
} finally {
|
|
43329
43351
|
setIsCategoryLoading(false);
|
|
43330
43352
|
}
|
|
43331
|
-
}, [workspaceId, effectiveDateString, effectiveShiftId, getMetadataCacheKey, isPercentileCategory, isFastSlowClipFiltersEnabled, metadataCache, s3ClipsService, clearLoadingState, isEffectiveShiftReady, snapshotDateTime, snapshotClipId, supabase]);
|
|
43353
|
+
}, [workspaceId, effectiveDateString, effectiveShiftId, getMetadataCacheKey, isPercentileCategory, isFastSlowClipFiltersEnabled, metadataCache, s3ClipsService, clearLoadingState, isEffectiveShiftReady, snapshotDateTime, snapshotClipId, supabase, setVisibleCategoryMetadata]);
|
|
43332
43354
|
useEffect(() => {
|
|
43333
43355
|
if (previousFilterRef.current !== activeFilter) {
|
|
43334
43356
|
console.log(`Filter changed from ${previousFilterRef.current} to ${activeFilter} - resetting to first video`);
|
|
@@ -43338,6 +43360,7 @@ var BottlenecksContent = ({
|
|
|
43338
43360
|
setIsNavigating(false);
|
|
43339
43361
|
loadingCategoryRef.current = null;
|
|
43340
43362
|
setCategoryMetadata([]);
|
|
43363
|
+
setCategoryMetadataCategoryId(null);
|
|
43341
43364
|
setCurrentMetadataIndex(0);
|
|
43342
43365
|
categoryMetadataRef.current = [];
|
|
43343
43366
|
currentMetadataIndexRef.current = 0;
|
|
@@ -43896,14 +43919,11 @@ var BottlenecksContent = ({
|
|
|
43896
43919
|
}
|
|
43897
43920
|
return currentPosition;
|
|
43898
43921
|
}, [activeFilter, categoryMetadata.length, currentMetadataIndex, currentPosition, isPercentileCategory]);
|
|
43899
|
-
const prefetchedExplorerMetadata = useMemo(() =>
|
|
43900
|
-
|
|
43901
|
-
|
|
43902
|
-
|
|
43903
|
-
|
|
43904
|
-
[activeFilter]: categoryMetadata
|
|
43905
|
-
};
|
|
43906
|
-
}, [activeFilter, categoryMetadata]);
|
|
43922
|
+
const prefetchedExplorerMetadata = useMemo(() => buildPrefetchedExplorerMetadata(
|
|
43923
|
+
activeFilter,
|
|
43924
|
+
categoryMetadataCategoryId,
|
|
43925
|
+
categoryMetadata
|
|
43926
|
+
), [activeFilter, categoryMetadata, categoryMetadataCategoryId]);
|
|
43907
43927
|
const classificationClipIds = useMemo(() => {
|
|
43908
43928
|
if (!idleTimeVlmEnabled) {
|
|
43909
43929
|
return [];
|
|
@@ -47856,6 +47876,7 @@ var LineMonthlyPdfGenerator = ({
|
|
|
47856
47876
|
rangeEnd,
|
|
47857
47877
|
selectedShiftId,
|
|
47858
47878
|
availableShifts,
|
|
47879
|
+
lineAssembly = false,
|
|
47859
47880
|
compact = false,
|
|
47860
47881
|
className
|
|
47861
47882
|
}) => {
|
|
@@ -48139,8 +48160,8 @@ var LineMonthlyPdfGenerator = ({
|
|
|
48139
48160
|
timeZone: "Asia/Kolkata"
|
|
48140
48161
|
});
|
|
48141
48162
|
doc.text(dateStr, 25, yPos);
|
|
48142
|
-
doc.text(`${shift.
|
|
48143
|
-
doc.text(`${shift.
|
|
48163
|
+
doc.text(`${Math.round(shift.output || 0)}`, 60, yPos);
|
|
48164
|
+
doc.text(`${Math.round(shift.idealOutput || 0)}`, 95, yPos);
|
|
48144
48165
|
doc.text(`${shift.avg_efficiency.toFixed(1)}%`, 135, yPos);
|
|
48145
48166
|
const statusColor = getEfficiencyColor(shift.avg_efficiency, effectiveLegend);
|
|
48146
48167
|
if (statusColor === "green") {
|
|
@@ -48170,6 +48191,8 @@ var LineMonthlyPdfGenerator = ({
|
|
|
48170
48191
|
doc.setTextColor(0, 0, 0);
|
|
48171
48192
|
}
|
|
48172
48193
|
const poorestWorkspaces = underperformingWorkspaces[selectedShiftId] || [];
|
|
48194
|
+
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);
|
|
48195
|
+
const showCycleTimePoorestPerformers = !isUptimeMode && poorestWorkspaces.some(isCycleTimeWorkspace);
|
|
48173
48196
|
if (poorestWorkspaces && poorestWorkspaces.length > 0) {
|
|
48174
48197
|
doc.addPage();
|
|
48175
48198
|
doc.setFontSize(14);
|
|
@@ -48195,7 +48218,11 @@ var LineMonthlyPdfGenerator = ({
|
|
|
48195
48218
|
doc.setFillColor(245, 245, 245);
|
|
48196
48219
|
doc.roundedRect(20, 45, 170, 8, 1, 1, "F");
|
|
48197
48220
|
doc.text("Workspace", 25, 50);
|
|
48198
|
-
doc.text(
|
|
48221
|
+
doc.text(
|
|
48222
|
+
isUptimeMode ? "Avg Utilization" : showCycleTimePoorestPerformers ? "Cycle Time" : "Avg Efficiency",
|
|
48223
|
+
120,
|
|
48224
|
+
50
|
|
48225
|
+
);
|
|
48199
48226
|
doc.text("Last 5 Days", 160, 50);
|
|
48200
48227
|
doc.setLineWidth(0.2);
|
|
48201
48228
|
doc.setDrawColor(220, 220, 220);
|
|
@@ -48214,7 +48241,16 @@ var LineMonthlyPdfGenerator = ({
|
|
|
48214
48241
|
);
|
|
48215
48242
|
const workspaceName = rawWorkspaceName.length > 30 ? `${rawWorkspaceName.substring(0, 27)}...` : rawWorkspaceName;
|
|
48216
48243
|
doc.text(workspaceName, 25, yPos2);
|
|
48217
|
-
|
|
48244
|
+
if (isUptimeMode) {
|
|
48245
|
+
doc.text(`${(workspace.avg_efficiency || 0).toFixed(1)}%`, 120, yPos2);
|
|
48246
|
+
} else if (isCycleTimeWorkspace(workspace)) {
|
|
48247
|
+
const actualCycleTime = Number.isFinite(workspace.avg_cycle_time) ? Number(workspace.avg_cycle_time) : null;
|
|
48248
|
+
const targetCycleTime = Number.isFinite(workspace.ideal_cycle_time) ? Number(workspace.ideal_cycle_time) : null;
|
|
48249
|
+
const cycleTimeText = actualCycleTime !== null ? `${actualCycleTime.toFixed(1)}s${targetCycleTime !== null ? ` / ${targetCycleTime.toFixed(1)}s` : ""}` : "-";
|
|
48250
|
+
doc.text(cycleTimeText, 120, yPos2);
|
|
48251
|
+
} else {
|
|
48252
|
+
doc.text(`${(workspace.avg_efficiency || 0).toFixed(1)}%`, 120, yPos2);
|
|
48253
|
+
}
|
|
48218
48254
|
const squareSize = 3;
|
|
48219
48255
|
const squareSpacing = 1;
|
|
48220
48256
|
let squareX = 160;
|
|
@@ -48309,12 +48345,279 @@ Underperforming Workspaces: ${lineInfo.metrics.underperforming_workspaces} / ${l
|
|
|
48309
48345
|
}
|
|
48310
48346
|
);
|
|
48311
48347
|
};
|
|
48348
|
+
|
|
48349
|
+
// src/lib/utils/hourlyTargets.ts
|
|
48350
|
+
var stripSeconds2 = (timeStr) => timeStr ? timeStr.slice(0, 5) : timeStr;
|
|
48351
|
+
var MINUTES_PER_DAY = 24 * 60;
|
|
48352
|
+
var parseTimeToMinutes2 = (timeString) => {
|
|
48353
|
+
const normalized = stripSeconds2(timeString || "");
|
|
48354
|
+
if (!normalized || !/^[0-2]\d:[0-5]\d$/.test(normalized)) return Number.NaN;
|
|
48355
|
+
const [hours, minutes] = normalized.split(":").map(Number);
|
|
48356
|
+
return hours * 60 + minutes;
|
|
48357
|
+
};
|
|
48358
|
+
var normalizeBreaksOnShiftTimeline = (shiftStart, breaks) => {
|
|
48359
|
+
const shiftStartMinutes = parseTimeToMinutes2(shiftStart);
|
|
48360
|
+
if (!Number.isFinite(shiftStartMinutes)) return [];
|
|
48361
|
+
const normalizedBreaks = [];
|
|
48362
|
+
for (const entry of breaks) {
|
|
48363
|
+
const startRaw = parseTimeToMinutes2(entry.startTime);
|
|
48364
|
+
const endRaw = parseTimeToMinutes2(entry.endTime);
|
|
48365
|
+
if (!Number.isFinite(startRaw) || !Number.isFinite(endRaw)) continue;
|
|
48366
|
+
let start = startRaw;
|
|
48367
|
+
let end = endRaw;
|
|
48368
|
+
if (end <= start) {
|
|
48369
|
+
end += 24 * 60;
|
|
48370
|
+
}
|
|
48371
|
+
if (start < shiftStartMinutes) {
|
|
48372
|
+
start += 24 * 60;
|
|
48373
|
+
end += 24 * 60;
|
|
48374
|
+
}
|
|
48375
|
+
const label = entry.remarks?.trim() || "Break";
|
|
48376
|
+
normalizedBreaks.push({ start, end, label });
|
|
48377
|
+
}
|
|
48378
|
+
return normalizedBreaks;
|
|
48379
|
+
};
|
|
48380
|
+
var roundTarget = (value, mode) => {
|
|
48381
|
+
if (!Number.isFinite(value)) return 0;
|
|
48382
|
+
switch (mode) {
|
|
48383
|
+
case "floor":
|
|
48384
|
+
return Math.floor(value);
|
|
48385
|
+
case "ceil":
|
|
48386
|
+
return Math.ceil(value);
|
|
48387
|
+
case "round":
|
|
48388
|
+
default:
|
|
48389
|
+
return Math.round(value);
|
|
48390
|
+
}
|
|
48391
|
+
};
|
|
48392
|
+
var formatDateKey = (date) => {
|
|
48393
|
+
const year = date.getUTCFullYear();
|
|
48394
|
+
const month = `${date.getUTCMonth() + 1}`.padStart(2, "0");
|
|
48395
|
+
const day = `${date.getUTCDate()}`.padStart(2, "0");
|
|
48396
|
+
return `${year}-${month}-${day}`;
|
|
48397
|
+
};
|
|
48398
|
+
var shiftDateKey = (dateKey, deltaDays) => {
|
|
48399
|
+
const [yearPart, monthPart, dayPart] = dateKey.split("-").map(Number);
|
|
48400
|
+
const year = Number.isFinite(yearPart) ? yearPart : 1970;
|
|
48401
|
+
const month = Number.isFinite(monthPart) ? monthPart : 1;
|
|
48402
|
+
const day = Number.isFinite(dayPart) ? dayPart : 1;
|
|
48403
|
+
const date = new Date(Date.UTC(year, month - 1, day));
|
|
48404
|
+
date.setUTCDate(date.getUTCDate() + deltaDays);
|
|
48405
|
+
return formatDateKey(date);
|
|
48406
|
+
};
|
|
48407
|
+
var getZonedNowSnapshot = (timeZone, now4) => {
|
|
48408
|
+
const formatter = new Intl.DateTimeFormat("en-US", {
|
|
48409
|
+
timeZone,
|
|
48410
|
+
year: "numeric",
|
|
48411
|
+
month: "2-digit",
|
|
48412
|
+
day: "2-digit",
|
|
48413
|
+
hour: "2-digit",
|
|
48414
|
+
minute: "2-digit",
|
|
48415
|
+
hourCycle: "h23"
|
|
48416
|
+
});
|
|
48417
|
+
const parts = formatter.formatToParts(now4).reduce((acc, part) => {
|
|
48418
|
+
if (part.type !== "literal") {
|
|
48419
|
+
acc[part.type] = part.value;
|
|
48420
|
+
}
|
|
48421
|
+
return acc;
|
|
48422
|
+
}, {});
|
|
48423
|
+
const year = Number(parts.year);
|
|
48424
|
+
const month = Number(parts.month);
|
|
48425
|
+
const day = Number(parts.day);
|
|
48426
|
+
const hour = Number(parts.hour);
|
|
48427
|
+
const minute = Number(parts.minute);
|
|
48428
|
+
return {
|
|
48429
|
+
dateKey: `${String(year).padStart(4, "0")}-${String(month).padStart(2, "0")}-${String(day).padStart(2, "0")}`,
|
|
48430
|
+
minutesOfDay: (Number.isFinite(hour) ? hour : 0) * 60 + (Number.isFinite(minute) ? minute : 0)
|
|
48431
|
+
};
|
|
48432
|
+
};
|
|
48433
|
+
var getDateKeyInTimeZone = (timeZone, now4 = /* @__PURE__ */ new Date()) => getZonedNowSnapshot(timeZone, now4).dateKey;
|
|
48434
|
+
var buildHourlyIntervals = ({
|
|
48435
|
+
shiftStart,
|
|
48436
|
+
shiftEnd,
|
|
48437
|
+
bucketMinutes = 60,
|
|
48438
|
+
fallbackHours = 11
|
|
48439
|
+
}) => {
|
|
48440
|
+
const startMinutes = parseTimeToMinutes2(shiftStart);
|
|
48441
|
+
if (!Number.isFinite(startMinutes)) return [];
|
|
48442
|
+
const bucket = Number.isFinite(bucketMinutes) && bucketMinutes > 0 ? Math.floor(bucketMinutes) : 60;
|
|
48443
|
+
let totalMinutes;
|
|
48444
|
+
const endRaw = shiftEnd ? parseTimeToMinutes2(shiftEnd) : Number.NaN;
|
|
48445
|
+
if (!Number.isFinite(endRaw)) {
|
|
48446
|
+
totalMinutes = Math.max(0, Math.round(fallbackHours * 60));
|
|
48447
|
+
} else {
|
|
48448
|
+
let endMinutes = endRaw;
|
|
48449
|
+
if (endMinutes <= startMinutes) {
|
|
48450
|
+
endMinutes += 24 * 60;
|
|
48451
|
+
}
|
|
48452
|
+
totalMinutes = endMinutes - startMinutes;
|
|
48453
|
+
}
|
|
48454
|
+
if (!Number.isFinite(totalMinutes) || totalMinutes <= 0) return [];
|
|
48455
|
+
const count = Math.ceil(totalMinutes / bucket);
|
|
48456
|
+
const shiftEndMinutes = startMinutes + totalMinutes;
|
|
48457
|
+
const intervals = [];
|
|
48458
|
+
for (let i = 0; i < count; i += 1) {
|
|
48459
|
+
const start = startMinutes + i * bucket;
|
|
48460
|
+
const end = Math.min(start + bucket, shiftEndMinutes);
|
|
48461
|
+
const minutes = Math.max(0, end - start);
|
|
48462
|
+
if (minutes <= 0) continue;
|
|
48463
|
+
intervals.push({ start, end, minutes });
|
|
48464
|
+
}
|
|
48465
|
+
return intervals;
|
|
48466
|
+
};
|
|
48467
|
+
var computeBreakMinutesByInterval = ({
|
|
48468
|
+
intervals,
|
|
48469
|
+
shiftStart,
|
|
48470
|
+
breaks
|
|
48471
|
+
}) => {
|
|
48472
|
+
if (!intervals.length || !breaks.length) return intervals.map(() => 0);
|
|
48473
|
+
const normalizedBreaks = normalizeBreaksOnShiftTimeline(shiftStart, breaks);
|
|
48474
|
+
return intervals.map((interval) => {
|
|
48475
|
+
if (!normalizedBreaks.length) return 0;
|
|
48476
|
+
let total = 0;
|
|
48477
|
+
for (const brk of normalizedBreaks) {
|
|
48478
|
+
const overlap = Math.max(0, Math.min(interval.end, brk.end) - Math.max(interval.start, brk.start));
|
|
48479
|
+
total += overlap;
|
|
48480
|
+
if (total >= interval.minutes) return interval.minutes;
|
|
48481
|
+
}
|
|
48482
|
+
return Math.min(interval.minutes, total);
|
|
48483
|
+
});
|
|
48484
|
+
};
|
|
48485
|
+
var computeBreakRemarksByInterval = ({
|
|
48486
|
+
intervals,
|
|
48487
|
+
shiftStart,
|
|
48488
|
+
breaks
|
|
48489
|
+
}) => {
|
|
48490
|
+
if (!intervals.length || !breaks.length) return intervals.map(() => "");
|
|
48491
|
+
const normalizedBreaks = normalizeBreaksOnShiftTimeline(shiftStart, breaks);
|
|
48492
|
+
return intervals.map((interval) => {
|
|
48493
|
+
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);
|
|
48494
|
+
return labels.join(", ");
|
|
48495
|
+
});
|
|
48496
|
+
};
|
|
48497
|
+
var computeEffectiveTargets = ({
|
|
48498
|
+
intervals,
|
|
48499
|
+
breakMinutes,
|
|
48500
|
+
pphThreshold,
|
|
48501
|
+
rounding = "round"
|
|
48502
|
+
}) => {
|
|
48503
|
+
return intervals.map((interval, idx) => {
|
|
48504
|
+
const intervalMinutes = Number(interval?.minutes) || 0;
|
|
48505
|
+
const breakMins = Number(breakMinutes?.[idx]) || 0;
|
|
48506
|
+
const plannedWorkMinutes = Math.max(0, intervalMinutes - breakMins);
|
|
48507
|
+
if (!Number.isFinite(pphThreshold) || pphThreshold <= 0) return 0;
|
|
48508
|
+
if (plannedWorkMinutes <= 0) return 0;
|
|
48509
|
+
return roundTarget(pphThreshold * plannedWorkMinutes / 60, rounding);
|
|
48510
|
+
});
|
|
48511
|
+
};
|
|
48512
|
+
var buildHourlyTargetPlan = ({
|
|
48513
|
+
shiftStart,
|
|
48514
|
+
shiftEnd,
|
|
48515
|
+
breaks = [],
|
|
48516
|
+
pphThreshold,
|
|
48517
|
+
bucketMinutes = 60,
|
|
48518
|
+
fallbackHours = 11,
|
|
48519
|
+
rounding = "round"
|
|
48520
|
+
}) => {
|
|
48521
|
+
const intervals = buildHourlyIntervals({
|
|
48522
|
+
shiftStart,
|
|
48523
|
+
shiftEnd,
|
|
48524
|
+
bucketMinutes,
|
|
48525
|
+
fallbackHours
|
|
48526
|
+
});
|
|
48527
|
+
const breakMinutes = computeBreakMinutesByInterval({
|
|
48528
|
+
intervals,
|
|
48529
|
+
shiftStart,
|
|
48530
|
+
breaks
|
|
48531
|
+
});
|
|
48532
|
+
const breakRemarks = computeBreakRemarksByInterval({
|
|
48533
|
+
intervals,
|
|
48534
|
+
shiftStart,
|
|
48535
|
+
breaks
|
|
48536
|
+
});
|
|
48537
|
+
const productiveMinutes = intervals.map((interval, idx) => Math.max(0, (Number(interval?.minutes) || 0) - (Number(breakMinutes[idx]) || 0)));
|
|
48538
|
+
const targets = computeEffectiveTargets({
|
|
48539
|
+
intervals,
|
|
48540
|
+
breakMinutes,
|
|
48541
|
+
pphThreshold,
|
|
48542
|
+
rounding
|
|
48543
|
+
});
|
|
48544
|
+
return {
|
|
48545
|
+
intervals,
|
|
48546
|
+
breakMinutes,
|
|
48547
|
+
breakRemarks,
|
|
48548
|
+
productiveMinutes,
|
|
48549
|
+
targets
|
|
48550
|
+
};
|
|
48551
|
+
};
|
|
48552
|
+
var isHourlyIntervalComplete = ({
|
|
48553
|
+
reportDate,
|
|
48554
|
+
shiftStart,
|
|
48555
|
+
shiftEnd,
|
|
48556
|
+
interval,
|
|
48557
|
+
timeZone = "Asia/Kolkata",
|
|
48558
|
+
now: now4 = /* @__PURE__ */ new Date()
|
|
48559
|
+
}) => {
|
|
48560
|
+
if (!reportDate) return true;
|
|
48561
|
+
const snapshot = getZonedNowSnapshot(timeZone, now4);
|
|
48562
|
+
const shiftStartMinutes = parseTimeToMinutes2(shiftStart);
|
|
48563
|
+
const shiftEndMinutes = shiftEnd ? parseTimeToMinutes2(shiftEnd) : Number.NaN;
|
|
48564
|
+
const wrapsMidnight = Number.isFinite(shiftStartMinutes) && Number.isFinite(shiftEndMinutes) && shiftEndMinutes <= shiftStartMinutes;
|
|
48565
|
+
if (reportDate === snapshot.dateKey) {
|
|
48566
|
+
return interval.end <= snapshot.minutesOfDay;
|
|
48567
|
+
}
|
|
48568
|
+
if (wrapsMidnight && reportDate === shiftDateKey(snapshot.dateKey, -1)) {
|
|
48569
|
+
return interval.end <= snapshot.minutesOfDay + MINUTES_PER_DAY;
|
|
48570
|
+
}
|
|
48571
|
+
return reportDate < snapshot.dateKey;
|
|
48572
|
+
};
|
|
48573
|
+
var isShiftInProgressForReportDate = ({
|
|
48574
|
+
reportDate,
|
|
48575
|
+
shiftStart,
|
|
48576
|
+
shiftEnd,
|
|
48577
|
+
timeZone = "Asia/Kolkata",
|
|
48578
|
+
now: now4 = /* @__PURE__ */ new Date()
|
|
48579
|
+
}) => {
|
|
48580
|
+
if (!reportDate || !shiftStart || !shiftEnd) return false;
|
|
48581
|
+
const shiftStartMinutes = parseTimeToMinutes2(shiftStart);
|
|
48582
|
+
const shiftEndMinutesRaw = parseTimeToMinutes2(shiftEnd);
|
|
48583
|
+
if (!Number.isFinite(shiftStartMinutes) || !Number.isFinite(shiftEndMinutesRaw)) {
|
|
48584
|
+
return false;
|
|
48585
|
+
}
|
|
48586
|
+
let shiftEndMinutes = shiftEndMinutesRaw;
|
|
48587
|
+
const wrapsMidnight = shiftEndMinutes <= shiftStartMinutes;
|
|
48588
|
+
if (wrapsMidnight) {
|
|
48589
|
+
shiftEndMinutes += MINUTES_PER_DAY;
|
|
48590
|
+
}
|
|
48591
|
+
const snapshot = getZonedNowSnapshot(timeZone, now4);
|
|
48592
|
+
let currentMinutes = null;
|
|
48593
|
+
if (reportDate === snapshot.dateKey) {
|
|
48594
|
+
currentMinutes = snapshot.minutesOfDay;
|
|
48595
|
+
} else if (wrapsMidnight && reportDate === shiftDateKey(snapshot.dateKey, -1)) {
|
|
48596
|
+
currentMinutes = snapshot.minutesOfDay + MINUTES_PER_DAY;
|
|
48597
|
+
}
|
|
48598
|
+
if (currentMinutes === null) {
|
|
48599
|
+
return false;
|
|
48600
|
+
}
|
|
48601
|
+
return shiftStartMinutes <= currentMinutes && currentMinutes < shiftEndMinutes;
|
|
48602
|
+
};
|
|
48603
|
+
var formatOperationalDateKey = (dateKey, options) => {
|
|
48604
|
+
const [yearPart, monthPart, dayPart] = dateKey.split("-").map(Number);
|
|
48605
|
+
const year = Number.isFinite(yearPart) ? yearPart : 1970;
|
|
48606
|
+
const month = Number.isFinite(monthPart) ? monthPart : 1;
|
|
48607
|
+
const day = Number.isFinite(dayPart) ? dayPart : 1;
|
|
48608
|
+
return new Date(Date.UTC(year, month - 1, day, 12)).toLocaleDateString("en-IN", {
|
|
48609
|
+
...options,
|
|
48610
|
+
timeZone: "UTC"
|
|
48611
|
+
});
|
|
48612
|
+
};
|
|
48312
48613
|
var LinePdfGenerator = ({
|
|
48313
48614
|
lineInfo,
|
|
48314
48615
|
workspaceData,
|
|
48315
48616
|
issueResolutionSummary,
|
|
48316
48617
|
shiftName,
|
|
48317
|
-
className
|
|
48618
|
+
className,
|
|
48619
|
+
shiftBreaks = [],
|
|
48620
|
+
reportTimezone = "Asia/Kolkata"
|
|
48318
48621
|
}) => {
|
|
48319
48622
|
const [isGenerating, setIsGenerating] = useState(false);
|
|
48320
48623
|
const formatResolutionDuration2 = (seconds) => {
|
|
@@ -48341,7 +48644,7 @@ var LinePdfGenerator = ({
|
|
|
48341
48644
|
doc.setFontSize(9);
|
|
48342
48645
|
doc.setFont("helvetica", "normal");
|
|
48343
48646
|
doc.setTextColor(100, 100, 100);
|
|
48344
|
-
const generatedText = `Generated on ${(/* @__PURE__ */ new Date()).toLocaleString("en-IN", { timeZone:
|
|
48647
|
+
const generatedText = `Generated on ${(/* @__PURE__ */ new Date()).toLocaleString("en-IN", { timeZone: reportTimezone })}`;
|
|
48345
48648
|
const generatedTextWidth = doc.getStringUnitWidth(generatedText) * 9 / doc.internal.scaleFactor;
|
|
48346
48649
|
doc.text(generatedText, doc.internal.pageSize.width - 20 - generatedTextWidth, 15);
|
|
48347
48650
|
doc.setDrawColor(200, 200, 200);
|
|
@@ -48359,11 +48662,10 @@ var LinePdfGenerator = ({
|
|
|
48359
48662
|
const isUptimeMode = lineInfo.monitoring_mode === "uptime";
|
|
48360
48663
|
const rawShiftType = shiftName || (lineInfo.shift_id === 0 ? "Day" : lineInfo.shift_id === 1 ? "Night" : `Shift ${lineInfo.shift_id}`);
|
|
48361
48664
|
const shiftType = rawShiftType.toLowerCase().includes("shift") ? rawShiftType : `${rawShiftType} Shift`;
|
|
48362
|
-
const date =
|
|
48665
|
+
const date = formatOperationalDateKey(lineInfo.date, {
|
|
48363
48666
|
weekday: "long",
|
|
48364
48667
|
day: "numeric",
|
|
48365
|
-
month: "long"
|
|
48366
|
-
timeZone: "Asia/Kolkata"
|
|
48668
|
+
month: "long"
|
|
48367
48669
|
});
|
|
48368
48670
|
const shiftStartTime = lineInfo.metrics.shift_start ? (/* @__PURE__ */ new Date(`2000-01-01 ${lineInfo.metrics.shift_start}`)).toLocaleTimeString("en-IN", {
|
|
48369
48671
|
hour: "2-digit",
|
|
@@ -48371,24 +48673,25 @@ var LinePdfGenerator = ({
|
|
|
48371
48673
|
hour12: true,
|
|
48372
48674
|
timeZone: "Asia/Kolkata"
|
|
48373
48675
|
}) : "N/A";
|
|
48374
|
-
const
|
|
48375
|
-
|
|
48376
|
-
|
|
48377
|
-
|
|
48378
|
-
|
|
48379
|
-
|
|
48380
|
-
|
|
48381
|
-
|
|
48382
|
-
|
|
48383
|
-
|
|
48384
|
-
|
|
48385
|
-
|
|
48386
|
-
|
|
48387
|
-
|
|
48388
|
-
|
|
48389
|
-
}
|
|
48676
|
+
const currentTime = (/* @__PURE__ */ new Date()).toLocaleTimeString("en-IN", {
|
|
48677
|
+
hour: "2-digit",
|
|
48678
|
+
minute: "2-digit",
|
|
48679
|
+
timeZone: reportTimezone
|
|
48680
|
+
});
|
|
48681
|
+
const reportEndTime = isShiftInProgressForReportDate({
|
|
48682
|
+
reportDate: lineInfo.date,
|
|
48683
|
+
shiftStart: lineInfo.metrics.shift_start || "",
|
|
48684
|
+
shiftEnd: lineInfo.metrics.shift_end,
|
|
48685
|
+
timeZone: reportTimezone
|
|
48686
|
+
}) ? currentTime : lineInfo.metrics.shift_end ? (/* @__PURE__ */ new Date(`2000-01-01 ${lineInfo.metrics.shift_end}`)).toLocaleTimeString("en-IN", {
|
|
48687
|
+
hour: "2-digit",
|
|
48688
|
+
minute: "2-digit",
|
|
48689
|
+
hour12: true,
|
|
48690
|
+
timeZone: "Asia/Kolkata"
|
|
48691
|
+
}) : "N/A";
|
|
48390
48692
|
if (isUptimeMode) {
|
|
48391
48693
|
const configuredTimezone = "Asia/Kolkata";
|
|
48694
|
+
const effectiveUptimeTimezone = reportTimezone || configuredTimezone;
|
|
48392
48695
|
const lineShiftStart = lineInfo.metrics.shift_start || "06:00";
|
|
48393
48696
|
const lineShiftEnd = lineInfo.metrics.shift_end || "14:00";
|
|
48394
48697
|
const shiftMinutes = getShiftDurationMinutes(lineShiftStart, lineShiftEnd) || 0;
|
|
@@ -48402,7 +48705,7 @@ var LinePdfGenerator = ({
|
|
|
48402
48705
|
shiftStart,
|
|
48403
48706
|
shiftEnd,
|
|
48404
48707
|
shiftDate,
|
|
48405
|
-
timezone:
|
|
48708
|
+
timezone: effectiveUptimeTimezone
|
|
48406
48709
|
});
|
|
48407
48710
|
let activeMinutes = uptimeSeries.activeMinutes;
|
|
48408
48711
|
let idleMinutes = uptimeSeries.idleMinutes;
|
|
@@ -48483,7 +48786,7 @@ var LinePdfGenerator = ({
|
|
|
48483
48786
|
shiftStart: lineShiftStart,
|
|
48484
48787
|
shiftEnd: lineShiftEnd,
|
|
48485
48788
|
shiftDate: lineInfo.date,
|
|
48486
|
-
timezone:
|
|
48789
|
+
timezone: effectiveUptimeTimezone
|
|
48487
48790
|
});
|
|
48488
48791
|
hourlyData = buildHourlyFromSeries(lineUptimeSeries);
|
|
48489
48792
|
}
|
|
@@ -48591,13 +48894,13 @@ var LinePdfGenerator = ({
|
|
|
48591
48894
|
doc.setFontSize(contentFontSize);
|
|
48592
48895
|
doc.setFont("helvetica", "normal");
|
|
48593
48896
|
let yPos2 = headerBottomY2 + 5.5;
|
|
48594
|
-
const
|
|
48595
|
-
const
|
|
48596
|
-
const [
|
|
48597
|
-
const [
|
|
48598
|
-
const
|
|
48897
|
+
const now4 = /* @__PURE__ */ new Date();
|
|
48898
|
+
const currentTimeIST = new Date(now4.toLocaleString("en-US", { timeZone: configuredTimezone }));
|
|
48899
|
+
const [sYear, sMonth, sDay] = lineInfo.date.split("-").map(Number);
|
|
48900
|
+
const [sStartH, sStartM] = (lineShiftStart || "06:00").split(":").map(Number);
|
|
48901
|
+
const shiftStartBase = new Date(sYear, sMonth - 1, sDay, sStartH, sStartM || 0);
|
|
48599
48902
|
hourlyData.forEach((entry, index) => {
|
|
48600
|
-
const bucketStartTime = new Date(
|
|
48903
|
+
const bucketStartTime = new Date(shiftStartBase);
|
|
48601
48904
|
bucketStartTime.setHours(bucketStartTime.getHours() + index);
|
|
48602
48905
|
const bucketEndTime = new Date(bucketStartTime);
|
|
48603
48906
|
bucketEndTime.setHours(bucketEndTime.getHours() + 1);
|
|
@@ -48608,7 +48911,7 @@ var LinePdfGenerator = ({
|
|
|
48608
48911
|
hour: "numeric",
|
|
48609
48912
|
hour12: true
|
|
48610
48913
|
})}`;
|
|
48611
|
-
const dataCollected = bucketEndTime.getTime() <=
|
|
48914
|
+
const dataCollected = bucketEndTime.getTime() <= currentTimeIST.getTime();
|
|
48612
48915
|
if (index < totalRows2 - 1) {
|
|
48613
48916
|
const rowBottomY = headerBottomY2 + (index + 1) * rowHeight;
|
|
48614
48917
|
doc.setDrawColor(200, 200, 200);
|
|
@@ -48619,11 +48922,10 @@ var LinePdfGenerator = ({
|
|
|
48619
48922
|
doc.text(utilizationStr, 147, yPos2);
|
|
48620
48923
|
yPos2 += rowHeight;
|
|
48621
48924
|
});
|
|
48622
|
-
const fileDate2 =
|
|
48925
|
+
const fileDate2 = formatOperationalDateKey(lineInfo.date, {
|
|
48623
48926
|
day: "2-digit",
|
|
48624
48927
|
month: "short",
|
|
48625
|
-
year: "numeric"
|
|
48626
|
-
timeZone: "Asia/Kolkata"
|
|
48928
|
+
year: "numeric"
|
|
48627
48929
|
}).replace(/ /g, "_");
|
|
48628
48930
|
const fileShift2 = shiftType.replace(/ /g, "_");
|
|
48629
48931
|
const fileName2 = `${lineInfo.line_name}_${fileDate2}_${fileShift2}.pdf`;
|
|
@@ -48676,66 +48978,32 @@ var LinePdfGenerator = ({
|
|
|
48676
48978
|
doc.setLineWidth(0.8);
|
|
48677
48979
|
doc.line(20, 123, 190, 123);
|
|
48678
48980
|
const hourlyOverviewStartY = 128;
|
|
48679
|
-
const parseTimeToMinutes4 = (timeStr) => {
|
|
48680
|
-
const [hours, minutes] = timeStr.split(":");
|
|
48681
|
-
const hour = parseInt(hours, 10);
|
|
48682
|
-
const minute = parseInt(minutes || "0", 10);
|
|
48683
|
-
if (Number.isNaN(hour) || Number.isNaN(minute)) {
|
|
48684
|
-
return NaN;
|
|
48685
|
-
}
|
|
48686
|
-
return (hour * 60 + minute) % (24 * 60);
|
|
48687
|
-
};
|
|
48688
48981
|
const formatMinutesLabel = (totalMinutes) => {
|
|
48689
48982
|
const normalized = (totalMinutes % (24 * 60) + 24 * 60) % (24 * 60);
|
|
48690
48983
|
const hour = Math.floor(normalized / 60);
|
|
48691
48984
|
const minute = normalized % 60;
|
|
48692
|
-
const time2 =
|
|
48693
|
-
time2.setHours(hour);
|
|
48694
|
-
time2.setMinutes(minute);
|
|
48695
|
-
time2.setSeconds(0);
|
|
48696
|
-
time2.setMilliseconds(0);
|
|
48985
|
+
const time2 = new Date(Date.UTC(2e3, 0, 1, hour, minute));
|
|
48697
48986
|
return time2.toLocaleTimeString("en-IN", {
|
|
48698
48987
|
hour: "2-digit",
|
|
48699
48988
|
minute: "2-digit",
|
|
48700
48989
|
hour12: true,
|
|
48701
|
-
timeZone: "
|
|
48990
|
+
timeZone: "UTC"
|
|
48702
48991
|
});
|
|
48703
48992
|
};
|
|
48704
|
-
const
|
|
48705
|
-
|
|
48706
|
-
|
|
48707
|
-
|
|
48708
|
-
|
|
48709
|
-
|
|
48710
|
-
|
|
48711
|
-
|
|
48712
|
-
|
|
48713
|
-
|
|
48714
|
-
|
|
48715
|
-
|
|
48716
|
-
|
|
48717
|
-
const defaultHours = 11;
|
|
48718
|
-
return Array.from({ length: defaultHours }, (_, i) => buildRange(startMinutes + i * 60, 60));
|
|
48719
|
-
}
|
|
48720
|
-
const endMinutes = parseTimeToMinutes4(endTimeStr);
|
|
48721
|
-
if (Number.isNaN(endMinutes)) {
|
|
48722
|
-
const fallbackHours = 11;
|
|
48723
|
-
return Array.from({ length: fallbackHours }, (_, i) => buildRange(startMinutes + i * 60, 60));
|
|
48724
|
-
}
|
|
48725
|
-
let durationMinutes = endMinutes - startMinutes;
|
|
48726
|
-
if (durationMinutes <= 0) {
|
|
48727
|
-
durationMinutes += 24 * 60;
|
|
48728
|
-
}
|
|
48729
|
-
const rangeCount = Math.max(1, Math.ceil(durationMinutes / 60));
|
|
48730
|
-
return Array.from({ length: rangeCount }, (_, i) => {
|
|
48731
|
-
const remainingMinutes = durationMinutes - i * 60;
|
|
48732
|
-
const rangeMinutes = remainingMinutes >= 60 ? 60 : remainingMinutes;
|
|
48733
|
-
return buildRange(startMinutes + i * 60, rangeMinutes);
|
|
48734
|
-
});
|
|
48735
|
-
};
|
|
48736
|
-
const hourlyTimeRanges = lineInfo.metrics.shift_start ? getHourlyTimeRanges(lineInfo.metrics.shift_start, lineInfo.metrics.shift_end) : [];
|
|
48993
|
+
const hourlyTimeRanges = buildHourlyIntervals({
|
|
48994
|
+
shiftStart: lineInfo.metrics.shift_start || "06:00",
|
|
48995
|
+
shiftEnd: lineInfo.metrics.shift_end,
|
|
48996
|
+
fallbackHours: 11
|
|
48997
|
+
});
|
|
48998
|
+
const targetPlan = buildHourlyTargetPlan({
|
|
48999
|
+
shiftStart: lineInfo.metrics.shift_start || "06:00",
|
|
49000
|
+
shiftEnd: lineInfo.metrics.shift_end,
|
|
49001
|
+
breaks: shiftBreaks,
|
|
49002
|
+
pphThreshold: Number(lineInfo.metrics.threshold_pph ?? 0),
|
|
49003
|
+
fallbackHours: Math.max(hourlyTimeRanges.length, 1),
|
|
49004
|
+
rounding: "floor"
|
|
49005
|
+
});
|
|
48737
49006
|
const shiftDuration = hourlyTimeRanges.length || 11;
|
|
48738
|
-
const targetOutputPerHour = Math.round(lineInfo.metrics.threshold_pph ?? 0);
|
|
48739
49007
|
let hourlyActualOutput = [];
|
|
48740
49008
|
if (lineInfo.metrics.output_hourly && Object.keys(lineInfo.metrics.output_hourly).length > 0) {
|
|
48741
49009
|
const [startHourStr, startMinuteStr] = (lineInfo.metrics.shift_start || "6:00").split(":");
|
|
@@ -48921,29 +49189,29 @@ var LinePdfGenerator = ({
|
|
|
48921
49189
|
doc.text("Remarks", 160, tableHeaderY);
|
|
48922
49190
|
doc.setFont("helvetica", "normal");
|
|
48923
49191
|
let yPos = tableStartY;
|
|
48924
|
-
const now4 = /* @__PURE__ */ new Date();
|
|
48925
|
-
const currentTimeIST = new Date(now4.toLocaleString("en-US", { timeZone: "Asia/Kolkata" }));
|
|
48926
|
-
const [sYear, sMonth, sDay] = lineInfo.date.split("-").map(Number);
|
|
48927
|
-
const [sStartH, sStartM] = (lineInfo.metrics.shift_start || "06:00").split(":").map(Number);
|
|
48928
|
-
const shiftStartBase = new Date(sYear, sMonth - 1, sDay, sStartH, sStartM || 0);
|
|
48929
49192
|
hourlyTimeRanges.forEach((timeRange, index) => {
|
|
48930
49193
|
const actualOutput = hourlyActualOutput[index] || 0;
|
|
48931
|
-
const
|
|
48932
|
-
|
|
48933
|
-
|
|
48934
|
-
|
|
49194
|
+
const dataCollected = isHourlyIntervalComplete({
|
|
49195
|
+
reportDate: lineInfo.date,
|
|
49196
|
+
shiftStart: lineInfo.metrics.shift_start || "06:00",
|
|
49197
|
+
shiftEnd: lineInfo.metrics.shift_end,
|
|
49198
|
+
interval: timeRange,
|
|
49199
|
+
timeZone: reportTimezone
|
|
49200
|
+
});
|
|
48935
49201
|
const outputStr = dataCollected ? actualOutput.toString() : "TBD";
|
|
48936
49202
|
if (index < totalRows - 1) {
|
|
48937
49203
|
const rowBottomY = headerBottomY + (index + 1) * rowSpacing;
|
|
48938
49204
|
doc.setDrawColor(200, 200, 200);
|
|
48939
49205
|
doc.line(20, rowBottomY, 190, rowBottomY);
|
|
48940
49206
|
}
|
|
48941
|
-
const
|
|
48942
|
-
const
|
|
48943
|
-
const
|
|
48944
|
-
doc.text(timeRange.
|
|
49207
|
+
const targetForRange = targetPlan.targets[index] ?? 0;
|
|
49208
|
+
const targetStr = targetForRange.toString();
|
|
49209
|
+
const remarkText = targetPlan.breakRemarks[index] || "";
|
|
49210
|
+
doc.text(`${formatMinutesLabel(timeRange.start)} - ${formatMinutesLabel(timeRange.end)}`, 25, yPos);
|
|
48945
49211
|
doc.text(outputStr, 75, yPos);
|
|
48946
49212
|
doc.text(targetStr, 105, yPos);
|
|
49213
|
+
const remarkDisplay = remarkText ? doc.splitTextToSize(remarkText, 26)[0] : "";
|
|
49214
|
+
doc.text(remarkDisplay, 160, yPos);
|
|
48947
49215
|
if (!dataCollected) {
|
|
48948
49216
|
doc.setTextColor(100, 100, 100);
|
|
48949
49217
|
doc.text("-", 135, yPos);
|
|
@@ -48959,11 +49227,10 @@ var LinePdfGenerator = ({
|
|
|
48959
49227
|
doc.setTextColor(0, 0, 0);
|
|
48960
49228
|
yPos += rowSpacing;
|
|
48961
49229
|
});
|
|
48962
|
-
const fileDate =
|
|
49230
|
+
const fileDate = formatOperationalDateKey(lineInfo.date, {
|
|
48963
49231
|
day: "2-digit",
|
|
48964
49232
|
month: "short",
|
|
48965
|
-
year: "numeric"
|
|
48966
|
-
timeZone: "Asia/Kolkata"
|
|
49233
|
+
year: "numeric"
|
|
48967
49234
|
}).replace(/ /g, "_");
|
|
48968
49235
|
const fileShift = shiftType.replace(/ /g, "_");
|
|
48969
49236
|
const fileName = `${lineInfo.line_name}_${fileDate}_${fileShift}.pdf`;
|
|
@@ -49891,6 +50158,13 @@ var WorkspaceMonthlyHistory = ({
|
|
|
49891
50158
|
}, [analysisMonthlyData, selectedShiftId, isUptimeMode, shiftWorkSeconds]);
|
|
49892
50159
|
const efficiencyDelta = trendSummary?.avg_efficiency?.delta_pp ?? 0;
|
|
49893
50160
|
const efficiencyImproved = efficiencyDelta >= 0;
|
|
50161
|
+
const assemblyRangeCycleTime = useMemo(() => {
|
|
50162
|
+
const trendCycleTime = Number(trendSummary?.avg_cycle_time?.current);
|
|
50163
|
+
if (Number.isFinite(trendCycleTime) && trendCycleTime > 0) {
|
|
50164
|
+
return Math.round(trendCycleTime);
|
|
50165
|
+
}
|
|
50166
|
+
return metrics2?.avgCycleTime ?? 0;
|
|
50167
|
+
}, [trendSummary?.avg_cycle_time?.current, metrics2?.avgCycleTime]);
|
|
49894
50168
|
const cycleDeltaRaw = trendSummary?.avg_cycle_time?.delta_seconds ?? 0;
|
|
49895
50169
|
const cyclePrev = trendSummary?.avg_cycle_time?.previous ?? 0;
|
|
49896
50170
|
const cycleDelta = cyclePrev ? cycleDeltaRaw / cyclePrev * 100 : 0;
|
|
@@ -50076,7 +50350,7 @@ var WorkspaceMonthlyHistory = ({
|
|
|
50076
50350
|
/* @__PURE__ */ jsx("div", { className: "text-sm font-semibold text-gray-600 mb-1", children: "Avg Cycle Time" }),
|
|
50077
50351
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 flex-nowrap", children: [
|
|
50078
50352
|
/* @__PURE__ */ jsxs("div", { className: "text-2xl font-bold text-gray-900", children: [
|
|
50079
|
-
|
|
50353
|
+
assemblyRangeCycleTime,
|
|
50080
50354
|
"s"
|
|
50081
50355
|
] }),
|
|
50082
50356
|
/* @__PURE__ */ 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: [
|
|
@@ -50412,7 +50686,25 @@ var WorkspaceWhatsAppShareButton = ({
|
|
|
50412
50686
|
}
|
|
50413
50687
|
);
|
|
50414
50688
|
};
|
|
50415
|
-
var
|
|
50689
|
+
var formatOperationalDateKey2 = (dateKey, options) => {
|
|
50690
|
+
const [yearPart, monthPart, dayPart] = dateKey.split("-").map(Number);
|
|
50691
|
+
const year = Number.isFinite(yearPart) ? yearPart : 1970;
|
|
50692
|
+
const month = Number.isFinite(monthPart) ? monthPart : 1;
|
|
50693
|
+
const day = Number.isFinite(dayPart) ? dayPart : 1;
|
|
50694
|
+
return new Date(Date.UTC(year, month - 1, day, 12)).toLocaleDateString("en-IN", {
|
|
50695
|
+
...options,
|
|
50696
|
+
timeZone: "UTC"
|
|
50697
|
+
});
|
|
50698
|
+
};
|
|
50699
|
+
var WorkspacePdfGenerator = ({
|
|
50700
|
+
workspace,
|
|
50701
|
+
className,
|
|
50702
|
+
idleTimeReasons,
|
|
50703
|
+
efficiencyLegend,
|
|
50704
|
+
hourlyCycleTimes,
|
|
50705
|
+
shiftBreaks = [],
|
|
50706
|
+
reportTimezone = "Asia/Kolkata"
|
|
50707
|
+
}) => {
|
|
50416
50708
|
const [isGenerating, setIsGenerating] = useState(false);
|
|
50417
50709
|
const entityConfig = useEntityConfig();
|
|
50418
50710
|
const effectiveLegend = efficiencyLegend || DEFAULT_EFFICIENCY_LEGEND;
|
|
@@ -50442,7 +50734,7 @@ var WorkspacePdfGenerator = ({ workspace, className, idleTimeReasons, efficiency
|
|
|
50442
50734
|
doc.setFontSize(9);
|
|
50443
50735
|
doc.setFont("helvetica", "normal");
|
|
50444
50736
|
doc.setTextColor(100, 100, 100);
|
|
50445
|
-
const generatedText = `Generated on ${(/* @__PURE__ */ new Date()).toLocaleString("en-IN", { timeZone:
|
|
50737
|
+
const generatedText = `Generated on ${(/* @__PURE__ */ new Date()).toLocaleString("en-IN", { timeZone: reportTimezone })}`;
|
|
50446
50738
|
const generatedTextWidth = doc.getStringUnitWidth(generatedText) * 9 / doc.internal.scaleFactor;
|
|
50447
50739
|
doc.text(generatedText, doc.internal.pageSize.width - 20 - generatedTextWidth, 15);
|
|
50448
50740
|
doc.setDrawColor(200, 200, 200);
|
|
@@ -50461,11 +50753,10 @@ var WorkspacePdfGenerator = ({ workspace, className, idleTimeReasons, efficiency
|
|
|
50461
50753
|
doc.setFontSize(13);
|
|
50462
50754
|
doc.setFont("helvetica", "normal");
|
|
50463
50755
|
doc.setTextColor(60, 60, 60);
|
|
50464
|
-
const date =
|
|
50756
|
+
const date = formatOperationalDateKey2(workspace.date, {
|
|
50465
50757
|
weekday: "long",
|
|
50466
50758
|
day: "numeric",
|
|
50467
|
-
month: "long"
|
|
50468
|
-
timeZone: "Asia/Kolkata"
|
|
50759
|
+
month: "long"
|
|
50469
50760
|
});
|
|
50470
50761
|
const rawShiftType = workspace.shift_type || (workspace.shift_id === 0 ? "Day" : workspace.shift_id === 1 ? "Night" : `Shift ${workspace.shift_id}`);
|
|
50471
50762
|
const shiftType = rawShiftType.toLowerCase().includes("shift") ? rawShiftType : `${rawShiftType} Shift`;
|
|
@@ -50474,7 +50765,7 @@ var WorkspacePdfGenerator = ({ workspace, className, idleTimeReasons, efficiency
|
|
|
50474
50765
|
const currentTime = (/* @__PURE__ */ new Date()).toLocaleTimeString("en-IN", {
|
|
50475
50766
|
hour: "2-digit",
|
|
50476
50767
|
minute: "2-digit",
|
|
50477
|
-
timeZone:
|
|
50768
|
+
timeZone: reportTimezone
|
|
50478
50769
|
});
|
|
50479
50770
|
const shiftStartTime = (/* @__PURE__ */ new Date(`2000-01-01 ${workspace.shift_start}`)).toLocaleTimeString("en-IN", {
|
|
50480
50771
|
hour: "2-digit",
|
|
@@ -50486,29 +50777,12 @@ var WorkspacePdfGenerator = ({ workspace, className, idleTimeReasons, efficiency
|
|
|
50486
50777
|
minute: "2-digit",
|
|
50487
50778
|
hour12: true
|
|
50488
50779
|
});
|
|
50489
|
-
const
|
|
50490
|
-
|
|
50491
|
-
|
|
50492
|
-
|
|
50493
|
-
|
|
50494
|
-
};
|
|
50495
|
-
const toShiftUtcMs = (dateKey, timeValue) => {
|
|
50496
|
-
const [yearPart, monthPart, dayPart] = dateKey.split("-").map(Number);
|
|
50497
|
-
const year = Number.isFinite(yearPart) ? yearPart : 1970;
|
|
50498
|
-
const month = Number.isFinite(monthPart) ? monthPart : 1;
|
|
50499
|
-
const day = Number.isFinite(dayPart) ? dayPart : 1;
|
|
50500
|
-
const [hourPart, minutePart] = timeValue.split(":").map(Number);
|
|
50501
|
-
const hour = Number.isFinite(hourPart) ? hourPart : 0;
|
|
50502
|
-
const minute = Number.isFinite(minutePart) ? minutePart : 0;
|
|
50503
|
-
const IST_OFFSET_MINUTES = 330;
|
|
50504
|
-
return Date.UTC(year, month - 1, day, hour, minute) - IST_OFFSET_MINUTES * 60 * 1e3;
|
|
50505
|
-
};
|
|
50506
|
-
const shiftStartMinutes = parseTimeToMinutes4(workspace.shift_start);
|
|
50507
|
-
const shiftEndMinutes = parseTimeToMinutes4(workspace.shift_end);
|
|
50508
|
-
const wrapsMidnight = shiftEndMinutes <= shiftStartMinutes;
|
|
50509
|
-
const shiftStartUtcMs = toShiftUtcMs(workspace.date, workspace.shift_start);
|
|
50510
|
-
const shiftEndUtcMs = toShiftUtcMs(workspace.date, workspace.shift_end) + (wrapsMidnight ? 24 * 60 * 60 * 1e3 : 0);
|
|
50511
|
-
const isShiftInProgress = Date.now() >= shiftStartUtcMs && Date.now() < shiftEndUtcMs;
|
|
50780
|
+
const isShiftInProgress = isShiftInProgressForReportDate({
|
|
50781
|
+
reportDate: workspace.date,
|
|
50782
|
+
shiftStart: workspace.shift_start,
|
|
50783
|
+
shiftEnd: workspace.shift_end,
|
|
50784
|
+
timeZone: reportTimezone
|
|
50785
|
+
});
|
|
50512
50786
|
const reportPeriodEndTime = isShiftInProgress ? currentTime : shiftEndTime;
|
|
50513
50787
|
doc.setFontSize(12);
|
|
50514
50788
|
doc.setTextColor(80, 80, 80);
|
|
@@ -50614,7 +50888,7 @@ var WorkspacePdfGenerator = ({ workspace, className, idleTimeReasons, efficiency
|
|
|
50614
50888
|
shiftStart: workspace.shift_start,
|
|
50615
50889
|
shiftEnd: workspace.shift_end,
|
|
50616
50890
|
shiftDate: workspace.date,
|
|
50617
|
-
timezone:
|
|
50891
|
+
timezone: reportTimezone
|
|
50618
50892
|
}) : null;
|
|
50619
50893
|
const hourlyUptime = uptimeSeries?.points?.length ? Array.from({ length: Math.ceil(uptimeSeries.shiftMinutes / 60) }, (_, index) => {
|
|
50620
50894
|
const start = index * 60;
|
|
@@ -50629,6 +50903,31 @@ var WorkspacePdfGenerator = ({ workspace, className, idleTimeReasons, efficiency
|
|
|
50629
50903
|
const hourlyData = isUptimeMode ? hourlyUptime : isAssemblyCycleMode ? hourlyCycleTimes && hourlyCycleTimes.length > 0 ? hourlyCycleTimes : workspace.hourly_action_counts || [] : workspace.hourly_action_counts || [];
|
|
50630
50904
|
const hourlyTarget = workspace.pph_threshold;
|
|
50631
50905
|
const cycleTarget = workspace.ideal_cycle_time || 0;
|
|
50906
|
+
const hourlyIntervals = buildHourlyIntervals({
|
|
50907
|
+
shiftStart: workspace.shift_start,
|
|
50908
|
+
shiftEnd: workspace.shift_end,
|
|
50909
|
+
fallbackHours: Math.max(hourlyData.length, 1)
|
|
50910
|
+
});
|
|
50911
|
+
const outputTargetPlan = !isUptimeMode && !isAssemblyCycleMode ? buildHourlyTargetPlan({
|
|
50912
|
+
shiftStart: workspace.shift_start,
|
|
50913
|
+
shiftEnd: workspace.shift_end,
|
|
50914
|
+
breaks: shiftBreaks,
|
|
50915
|
+
pphThreshold: workspace.pph_threshold,
|
|
50916
|
+
fallbackHours: Math.max(hourlyData.length, 1),
|
|
50917
|
+
rounding: "floor"
|
|
50918
|
+
}) : null;
|
|
50919
|
+
const formatIntervalLabel = (totalMinutes) => {
|
|
50920
|
+
const normalized = (totalMinutes % (24 * 60) + 24 * 60) % (24 * 60);
|
|
50921
|
+
const hour = Math.floor(normalized / 60);
|
|
50922
|
+
const minute = normalized % 60;
|
|
50923
|
+
const time2 = new Date(Date.UTC(2e3, 0, 1, hour, minute));
|
|
50924
|
+
return time2.toLocaleTimeString("en-IN", {
|
|
50925
|
+
hour: "numeric",
|
|
50926
|
+
...minute > 0 ? { minute: "2-digit" } : {},
|
|
50927
|
+
hour12: true,
|
|
50928
|
+
timeZone: "UTC"
|
|
50929
|
+
});
|
|
50930
|
+
};
|
|
50632
50931
|
const pageHeight = doc.internal.pageSize.height;
|
|
50633
50932
|
const maxContentY = pageHeight - 15;
|
|
50634
50933
|
const baseTableStartY = hourlyPerfStartY + 31;
|
|
@@ -50696,36 +50995,30 @@ var WorkspacePdfGenerator = ({ workspace, className, idleTimeReasons, efficiency
|
|
|
50696
50995
|
doc.setFontSize(contentFontSize);
|
|
50697
50996
|
doc.setFont("helvetica", "normal");
|
|
50698
50997
|
let yPos = headerBottomY + 5.5;
|
|
50699
|
-
const
|
|
50700
|
-
const today = /* @__PURE__ */ new Date();
|
|
50701
|
-
today.setHours(0, 0, 0, 0);
|
|
50702
|
-
workspaceDate.setHours(0, 0, 0, 0);
|
|
50703
|
-
const isToday2 = workspaceDate.getTime() === today.getTime();
|
|
50998
|
+
const isToday2 = getDateKeyInTimeZone(reportTimezone) === workspace.date;
|
|
50704
50999
|
let currentHour = 24;
|
|
50705
51000
|
if (isToday2) {
|
|
50706
51001
|
const now4 = /* @__PURE__ */ new Date();
|
|
50707
|
-
const
|
|
50708
|
-
currentHour =
|
|
51002
|
+
const currentTimeInReportTimezone = new Date(now4.toLocaleString("en-US", { timeZone: reportTimezone }));
|
|
51003
|
+
currentHour = currentTimeInReportTimezone.getHours();
|
|
50709
51004
|
}
|
|
50710
51005
|
hourlyData.forEach((entry, index) => {
|
|
50711
|
-
const
|
|
50712
|
-
|
|
50713
|
-
const
|
|
50714
|
-
|
|
50715
|
-
|
|
50716
|
-
|
|
50717
|
-
|
|
50718
|
-
|
|
50719
|
-
|
|
50720
|
-
hour12: true
|
|
50721
|
-
})}`;
|
|
50722
|
-
const hourNumber = startTime.getHours();
|
|
50723
|
-
const dataCollected = !isToday2 || hourNumber < currentHour;
|
|
51006
|
+
const interval = hourlyIntervals[index];
|
|
51007
|
+
const timeRange = interval ? `${formatIntervalLabel(interval.start)} - ${formatIntervalLabel(interval.end)}` : `${index + 1}`;
|
|
51008
|
+
const dataCollected = interval ? isHourlyIntervalComplete({
|
|
51009
|
+
reportDate: workspace.date,
|
|
51010
|
+
shiftStart: workspace.shift_start,
|
|
51011
|
+
shiftEnd: workspace.shift_end,
|
|
51012
|
+
interval,
|
|
51013
|
+
timeZone: reportTimezone
|
|
51014
|
+
}) : !isToday2 || currentHour >= 24;
|
|
50724
51015
|
const outputValue = isUptimeMode ? entry.activeMinutes ?? 0 : entry;
|
|
50725
51016
|
const idleValue = isUptimeMode ? entry.idleMinutes ?? 0 : 0;
|
|
50726
51017
|
const uptimePercent = isUptimeMode ? entry.uptimePercent ?? 0 : 0;
|
|
50727
51018
|
const outputStr = dataCollected ? outputValue.toString() : "TBD";
|
|
50728
|
-
const
|
|
51019
|
+
const effectiveTarget = outputTargetPlan?.targets[index] ?? hourlyTarget;
|
|
51020
|
+
const remarkText = outputTargetPlan?.breakRemarks[index] || "";
|
|
51021
|
+
const targetStr = isUptimeMode ? dataCollected ? idleValue.toString() : "TBD" : effectiveTarget.toString();
|
|
50729
51022
|
if (index < totalRows - 1) {
|
|
50730
51023
|
const rowBottomY = headerBottomY + (index + 1) * rowHeight;
|
|
50731
51024
|
doc.setDrawColor(200, 200, 200);
|
|
@@ -50757,10 +51050,12 @@ var WorkspacePdfGenerator = ({ workspace, className, idleTimeReasons, efficiency
|
|
|
50757
51050
|
} else {
|
|
50758
51051
|
doc.text(outputStr, 75, yPos);
|
|
50759
51052
|
doc.text(targetStr, 105, yPos);
|
|
51053
|
+
const remarkDisplay = remarkText ? doc.splitTextToSize(remarkText, 26)[0] : "";
|
|
51054
|
+
doc.text(remarkDisplay, 160, yPos);
|
|
50760
51055
|
if (!dataCollected) {
|
|
50761
51056
|
doc.setTextColor(100, 100, 100);
|
|
50762
51057
|
doc.text("-", 135, yPos);
|
|
50763
|
-
} else if (outputValue >=
|
|
51058
|
+
} else if (outputValue >= effectiveTarget) {
|
|
50764
51059
|
doc.setTextColor(0, 171, 69);
|
|
50765
51060
|
doc.setFont("ZapfDingbats", "normal");
|
|
50766
51061
|
doc.text("4", 135, yPos);
|
|
@@ -50774,11 +51069,10 @@ var WorkspacePdfGenerator = ({ workspace, className, idleTimeReasons, efficiency
|
|
|
50774
51069
|
yPos += rowHeight;
|
|
50775
51070
|
});
|
|
50776
51071
|
const workspaceDisplayName = getWorkspaceDisplayName(workspace.workspace_name, workspace.line_id);
|
|
50777
|
-
const fileDate =
|
|
51072
|
+
const fileDate = formatOperationalDateKey2(workspace.date, {
|
|
50778
51073
|
day: "2-digit",
|
|
50779
51074
|
month: "short",
|
|
50780
|
-
year: "numeric"
|
|
50781
|
-
timeZone: "Asia/Kolkata"
|
|
51075
|
+
year: "numeric"
|
|
50782
51076
|
}).replace(/ /g, "_");
|
|
50783
51077
|
const fileShift = shiftType.replace(/ /g, "_");
|
|
50784
51078
|
const fileName = `${workspaceDisplayName}_${fileDate}_${fileShift}.pdf`;
|
|
@@ -50824,12 +51118,25 @@ var WorkspaceMonthlyPdfGenerator = ({
|
|
|
50824
51118
|
availableShifts,
|
|
50825
51119
|
shiftConfig,
|
|
50826
51120
|
efficiencyLegend,
|
|
51121
|
+
trendSummary,
|
|
50827
51122
|
className,
|
|
50828
51123
|
compact = false,
|
|
50829
51124
|
isAssemblyWorkspace = false
|
|
50830
51125
|
}) => {
|
|
50831
51126
|
const [isGenerating, setIsGenerating] = useState(false);
|
|
50832
51127
|
const effectiveLegend = efficiencyLegend || DEFAULT_EFFICIENCY_LEGEND;
|
|
51128
|
+
const drawStatusMark = (doc, x, y, met) => {
|
|
51129
|
+
doc.setLineWidth(0.8);
|
|
51130
|
+
if (met) {
|
|
51131
|
+
doc.setDrawColor(0, 171, 69);
|
|
51132
|
+
doc.line(x - 1.8, y - 0.2, x - 0.5, y + 1.2);
|
|
51133
|
+
doc.line(x - 0.5, y + 1.2, x + 2.1, y - 1.6);
|
|
51134
|
+
return;
|
|
51135
|
+
}
|
|
51136
|
+
doc.setDrawColor(227, 67, 41);
|
|
51137
|
+
doc.line(x - 1.8, y - 1.6, x + 1.8, y + 1.6);
|
|
51138
|
+
doc.line(x - 1.8, y + 1.6, x + 1.8, y - 1.6);
|
|
51139
|
+
};
|
|
50833
51140
|
const generatePDF = async () => {
|
|
50834
51141
|
setIsGenerating(true);
|
|
50835
51142
|
try {
|
|
@@ -51024,12 +51331,13 @@ var WorkspaceMonthlyPdfGenerator = ({
|
|
|
51024
51331
|
doc.setFont("helvetica", "bold");
|
|
51025
51332
|
doc.text(`${outputMetrics.underperformingDays} of ${outputMetrics.totalDays}`, 120, kpiStartY + kpiSpacing * 3);
|
|
51026
51333
|
} else {
|
|
51334
|
+
const medianCycleTime = Number.isFinite(trendSummary?.avg_cycle_time?.current) ? Number(trendSummary?.avg_cycle_time?.current) : outputMetrics.avgCycleTime;
|
|
51027
51335
|
createKPIBox(kpiStartY);
|
|
51028
51336
|
doc.setFontSize(11);
|
|
51029
51337
|
doc.setFont("helvetica", "normal");
|
|
51030
51338
|
doc.text("Average Cycle Time:", 25, kpiStartY);
|
|
51031
51339
|
doc.setFont("helvetica", "bold");
|
|
51032
|
-
doc.text(`${
|
|
51340
|
+
doc.text(`${medianCycleTime.toFixed(1)}s`, 120, kpiStartY);
|
|
51033
51341
|
createKPIBox(kpiStartY + kpiSpacing);
|
|
51034
51342
|
doc.setFont("helvetica", "normal");
|
|
51035
51343
|
doc.text("Average Idle Time:", 25, kpiStartY + kpiSpacing);
|
|
@@ -51064,8 +51372,8 @@ var WorkspaceMonthlyPdfGenerator = ({
|
|
|
51064
51372
|
doc.roundedRect(20, tableHeaderY, 170, 7, 1, 1, "F");
|
|
51065
51373
|
const textY = tableHeaderY + 5;
|
|
51066
51374
|
doc.text("Date", 25, textY);
|
|
51067
|
-
doc.text(isUptimeMode ? "Productive" : isAssemblyWorkspace ? "Cycle Time" : "Actual", 60, textY);
|
|
51068
|
-
doc.text(isUptimeMode ? "Idle" : isAssemblyWorkspace ? "
|
|
51375
|
+
doc.text(isUptimeMode ? "Productive" : isAssemblyWorkspace ? "Actual Cycle Time" : "Actual", 60, textY);
|
|
51376
|
+
doc.text(isUptimeMode ? "Idle" : isAssemblyWorkspace ? "Standard Cycle Time" : "Standard", 95, textY);
|
|
51069
51377
|
doc.text(isUptimeMode ? "Utilization" : "Efficiency", 135, textY);
|
|
51070
51378
|
doc.text("Status", 170, textY);
|
|
51071
51379
|
doc.setLineWidth(0.2);
|
|
@@ -51097,31 +51405,18 @@ var WorkspaceMonthlyPdfGenerator = ({
|
|
|
51097
51405
|
doc.text(formatIdleTime(productiveSeconds), 60, yPos);
|
|
51098
51406
|
doc.text(formatIdleTime(clampedIdleSeconds), 95, yPos);
|
|
51099
51407
|
doc.text(`${utilization}%`, 135, yPos);
|
|
51100
|
-
|
|
51101
|
-
doc.setTextColor(0, 171, 69);
|
|
51102
|
-
doc.text("\u2713", 170, yPos);
|
|
51103
|
-
} else {
|
|
51104
|
-
doc.setTextColor(227, 67, 41);
|
|
51105
|
-
doc.text("\xD7", 170, yPos);
|
|
51106
|
-
}
|
|
51107
|
-
doc.setTextColor(0, 0, 0);
|
|
51408
|
+
drawStatusMark(doc, 171, yPos - 0.3, utilization >= effectiveLegend.green_min);
|
|
51108
51409
|
} else {
|
|
51109
51410
|
if (isAssemblyWorkspace) {
|
|
51411
|
+
const targetCycleTime = Number.isFinite(shift.idealCycleTime) && Number(shift.idealCycleTime) > 0 ? Number(shift.idealCycleTime) : shift.pphThreshold > 0 ? 3600 / shift.pphThreshold : null;
|
|
51110
51412
|
doc.text(`${shift.cycleTime.toFixed(1)}`, 60, yPos);
|
|
51111
|
-
doc.text(
|
|
51413
|
+
doc.text(targetCycleTime !== null ? `${targetCycleTime.toFixed(1)}` : "-", 95, yPos);
|
|
51112
51414
|
} else {
|
|
51113
51415
|
doc.text(`${shift.output}`, 60, yPos);
|
|
51114
51416
|
doc.text(`${shift.targetOutput}`, 95, yPos);
|
|
51115
51417
|
}
|
|
51116
51418
|
doc.text(`${shift.efficiency.toFixed(1)}%`, 135, yPos);
|
|
51117
|
-
|
|
51118
|
-
doc.setTextColor(0, 171, 69);
|
|
51119
|
-
doc.text("\u2713", 170, yPos);
|
|
51120
|
-
} else {
|
|
51121
|
-
doc.setTextColor(227, 67, 41);
|
|
51122
|
-
doc.text("\xD7", 170, yPos);
|
|
51123
|
-
}
|
|
51124
|
-
doc.setTextColor(0, 0, 0);
|
|
51419
|
+
drawStatusMark(doc, 171, yPos - 0.3, shift.efficiency >= effectiveLegend.green_min);
|
|
51125
51420
|
}
|
|
51126
51421
|
yPos += 8;
|
|
51127
51422
|
});
|
|
@@ -64287,7 +64582,17 @@ var KPIDetailView = ({
|
|
|
64287
64582
|
)
|
|
64288
64583
|
] }),
|
|
64289
64584
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 ml-auto", children: [
|
|
64290
|
-
resolvedLineInfo && activeTab === "overview" && /* @__PURE__ */ jsx(
|
|
64585
|
+
resolvedLineInfo && activeTab === "overview" && /* @__PURE__ */ jsx(
|
|
64586
|
+
LinePdfGenerator,
|
|
64587
|
+
{
|
|
64588
|
+
lineInfo: resolvedLineInfo,
|
|
64589
|
+
workspaceData: resolvedWorkspaces || [],
|
|
64590
|
+
issueResolutionSummary,
|
|
64591
|
+
shiftName: getShiftName(resolvedLineInfo.shift_id),
|
|
64592
|
+
shiftBreaks: shiftConfig?.shifts?.find((shift) => shift.shiftId === resolvedLineInfo.shift_id)?.breaks || [],
|
|
64593
|
+
reportTimezone: shiftConfig?.timezone || configuredTimezone
|
|
64594
|
+
}
|
|
64595
|
+
),
|
|
64291
64596
|
activeTab === "monthly_history" && !urlDate && !urlShift && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
64292
64597
|
/* @__PURE__ */ jsx(
|
|
64293
64598
|
MonthlyRangeFilter_default,
|
|
@@ -64316,6 +64621,8 @@ var KPIDetailView = ({
|
|
|
64316
64621
|
rangeStart,
|
|
64317
64622
|
rangeEnd,
|
|
64318
64623
|
selectedShiftId,
|
|
64624
|
+
availableShifts: shiftConfig?.shifts?.map((shift) => ({ id: shift.shiftId, name: shift.shiftName })),
|
|
64625
|
+
lineAssembly: resolvedLineInfo?.assembly === true,
|
|
64319
64626
|
compact: true
|
|
64320
64627
|
}
|
|
64321
64628
|
)
|
|
@@ -64494,7 +64801,7 @@ var KPIDetailViewWithDisplayNames = withSelectedLineDisplayNames(KPIDetailView);
|
|
|
64494
64801
|
var KPIDetailView_default = KPIDetailViewWithDisplayNames;
|
|
64495
64802
|
var isNonEmptyString = (value) => typeof value === "string" && value.trim().length > 0;
|
|
64496
64803
|
var resolveCompanyId = (...candidates) => candidates.find(isNonEmptyString);
|
|
64497
|
-
var
|
|
64804
|
+
var parseTimeToMinutes3 = (value) => {
|
|
64498
64805
|
if (!value) return null;
|
|
64499
64806
|
const [hourStr, minuteStr] = value.split(":");
|
|
64500
64807
|
const hour = Number.parseInt(hourStr ?? "", 10);
|
|
@@ -64506,8 +64813,8 @@ var getShiftEndDate = (shift, timezone) => {
|
|
|
64506
64813
|
if (!shift?.date) return null;
|
|
64507
64814
|
const startTime = shift.startTime || "06:00";
|
|
64508
64815
|
const endTime = shift.endTime || "18:00";
|
|
64509
|
-
const startMinutes =
|
|
64510
|
-
const endMinutes =
|
|
64816
|
+
const startMinutes = parseTimeToMinutes3(startTime);
|
|
64817
|
+
const endMinutes = parseTimeToMinutes3(endTime);
|
|
64511
64818
|
if (startMinutes === null || endMinutes === null) return null;
|
|
64512
64819
|
const shiftStartDate = fromZonedTime(`${shift.date}T${startTime}:00`, timezone);
|
|
64513
64820
|
let durationMinutes = endMinutes - startMinutes;
|
|
@@ -64545,7 +64852,7 @@ var createKpisOverviewUrl = ({
|
|
|
64545
64852
|
return queryString ? `/kpis?${queryString}` : "/kpis";
|
|
64546
64853
|
};
|
|
64547
64854
|
var getZonedDateAtMidday = (dateKey, timezone) => fromZonedTime(`${dateKey}T12:00:00`, timezone);
|
|
64548
|
-
var
|
|
64855
|
+
var formatDateKey2 = (dateKey, timezone, options) => {
|
|
64549
64856
|
try {
|
|
64550
64857
|
return new Intl.DateTimeFormat("en-US", {
|
|
64551
64858
|
...options,
|
|
@@ -65613,7 +65920,7 @@ var KPIsOverviewView = ({
|
|
|
65613
65920
|
setActiveTab(newTab);
|
|
65614
65921
|
}, [activeTab, leaderboardLines.length, lines.length]);
|
|
65615
65922
|
const formatLocalDate2 = useCallback((dateKey) => {
|
|
65616
|
-
return
|
|
65923
|
+
return formatDateKey2(dateKey, configuredTimezone, {
|
|
65617
65924
|
year: "numeric",
|
|
65618
65925
|
month: "long",
|
|
65619
65926
|
day: "numeric"
|
|
@@ -65627,8 +65934,8 @@ var KPIsOverviewView = ({
|
|
|
65627
65934
|
zonedNow.getMonth(),
|
|
65628
65935
|
new Date(zonedNow.getFullYear(), zonedNow.getMonth() + 1, 0).getDate()
|
|
65629
65936
|
);
|
|
65630
|
-
const startLabel =
|
|
65631
|
-
const endLabel =
|
|
65937
|
+
const startLabel = formatDateKey2(startOfMonthKey, configuredTimezone, { month: "short", day: "numeric" });
|
|
65938
|
+
const endLabel = formatDateKey2(endOfMonthKey, configuredTimezone, { month: "short", day: "numeric" });
|
|
65632
65939
|
return `${startLabel} - ${endLabel}, ${zonedNow.getFullYear()}`;
|
|
65633
65940
|
};
|
|
65634
65941
|
const isMonthlyMode = activeTab === "leaderboard" && timeRange === "monthly";
|
|
@@ -71263,6 +71570,7 @@ var WorkspaceDetailView = ({
|
|
|
71263
71570
|
efficiency: monitoringMode === "uptime" ? Number.isFinite(metric.avg_efficiency) ? Number(metric.avg_efficiency) : computedUptimeEfficiency : Number.isFinite(metric.avg_efficiency) ? Number(metric.avg_efficiency) : 0,
|
|
71264
71571
|
output: metric.total_output || 0,
|
|
71265
71572
|
cycleTime: metric.avg_cycle_time || 0,
|
|
71573
|
+
idealCycleTime: Number(metric.ideal_cycle_time || 0),
|
|
71266
71574
|
pph: metric.avg_pph || 0,
|
|
71267
71575
|
pphThreshold: metric.pph_threshold || 0,
|
|
71268
71576
|
idealOutput: Number(metric.ideal_output || 0),
|
|
@@ -71818,7 +72126,9 @@ var WorkspaceDetailView = ({
|
|
|
71818
72126
|
workspace,
|
|
71819
72127
|
idleTimeReasons: idleTimeChartData,
|
|
71820
72128
|
efficiencyLegend,
|
|
71821
|
-
hourlyCycleTimes: cycleTimeChartData
|
|
72129
|
+
hourlyCycleTimes: cycleTimeChartData,
|
|
72130
|
+
shiftBreaks: shiftConfig?.shifts?.find((shift2) => shift2.shiftId === workspace.shift_id)?.breaks || [],
|
|
72131
|
+
reportTimezone: shiftConfig?.timezone || timezone
|
|
71822
72132
|
}
|
|
71823
72133
|
) }),
|
|
71824
72134
|
activeTab === "monthly_history" && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
@@ -71853,6 +72163,7 @@ var WorkspaceDetailView = ({
|
|
|
71853
72163
|
workspaceId,
|
|
71854
72164
|
workspaceName: formattedWorkspaceName,
|
|
71855
72165
|
monthlyData,
|
|
72166
|
+
analysisData: analysisMonthlyData,
|
|
71856
72167
|
selectedMonth,
|
|
71857
72168
|
selectedYear,
|
|
71858
72169
|
monitoringMode: workspace?.monitoring_mode,
|
|
@@ -71861,7 +72172,10 @@ var WorkspaceDetailView = ({
|
|
|
71861
72172
|
selectedShiftId: selectedShift,
|
|
71862
72173
|
availableShifts: shiftConfig?.shifts?.map((s) => ({ id: s.shiftId, name: s.shiftName })),
|
|
71863
72174
|
shiftConfig,
|
|
71864
|
-
|
|
72175
|
+
efficiencyLegend,
|
|
72176
|
+
trendSummary: workspaceMonthlyTrend,
|
|
72177
|
+
compact: true,
|
|
72178
|
+
isAssemblyWorkspace
|
|
71865
72179
|
}
|
|
71866
72180
|
)
|
|
71867
72181
|
] })
|
|
@@ -80076,7 +80390,7 @@ var useOperationsOverviewRefresh = ({
|
|
|
80076
80390
|
};
|
|
80077
80391
|
}, [companyId, enabled, getIsPageActive, isLiveScope, lineIds.length, refreshFromResume, startPolling, stopPolling, supabase]);
|
|
80078
80392
|
};
|
|
80079
|
-
var
|
|
80393
|
+
var parseTimeToMinutes4 = (value) => {
|
|
80080
80394
|
if (!value) return null;
|
|
80081
80395
|
const parts = value.split(":");
|
|
80082
80396
|
if (parts.length < 2) return null;
|
|
@@ -80111,8 +80425,8 @@ var classifyShiftBucket = ({
|
|
|
80111
80425
|
return "day";
|
|
80112
80426
|
}
|
|
80113
80427
|
}
|
|
80114
|
-
const startMinutes =
|
|
80115
|
-
const endMinutes =
|
|
80428
|
+
const startMinutes = parseTimeToMinutes4(startTime);
|
|
80429
|
+
const endMinutes = parseTimeToMinutes4(endTime);
|
|
80116
80430
|
if (startMinutes !== null) {
|
|
80117
80431
|
if (startMinutes >= 4 * 60 && startMinutes < 18 * 60) return "day";
|
|
80118
80432
|
return "night";
|
|
@@ -80171,8 +80485,8 @@ var getShiftWindowsForConfig = (shiftConfig, timezone) => {
|
|
|
80171
80485
|
];
|
|
80172
80486
|
};
|
|
80173
80487
|
var normalizeShiftWindowMinutes = (startTime, endTime) => {
|
|
80174
|
-
const startMinutes =
|
|
80175
|
-
const endMinutesRaw =
|
|
80488
|
+
const startMinutes = parseTimeToMinutes4(startTime);
|
|
80489
|
+
const endMinutesRaw = parseTimeToMinutes4(endTime);
|
|
80176
80490
|
if (startMinutes === null || endMinutesRaw === null) {
|
|
80177
80491
|
return null;
|
|
80178
80492
|
}
|
|
@@ -80338,7 +80652,7 @@ var PlantHeadView = () => {
|
|
|
80338
80652
|
startTime: shift.startTime,
|
|
80339
80653
|
endTime: shift.endTime
|
|
80340
80654
|
});
|
|
80341
|
-
const startMinutes =
|
|
80655
|
+
const startMinutes = parseTimeToMinutes4(shift.startTime);
|
|
80342
80656
|
if (bucket === "day" && startMinutes !== null) {
|
|
80343
80657
|
candidateStarts.push(startMinutes);
|
|
80344
80658
|
}
|
|
@@ -80348,7 +80662,7 @@ var PlantHeadView = () => {
|
|
|
80348
80662
|
scopedLineIds.forEach((lineId) => {
|
|
80349
80663
|
const shiftConfig = shiftConfigMap.get(lineId) || staticShiftConfig;
|
|
80350
80664
|
getShiftWindowsForConfig(shiftConfig).forEach((shift) => {
|
|
80351
|
-
const startMinutes =
|
|
80665
|
+
const startMinutes = parseTimeToMinutes4(shift.startTime);
|
|
80352
80666
|
if (startMinutes !== null) {
|
|
80353
80667
|
candidateStarts.push(startMinutes);
|
|
80354
80668
|
}
|
|
@@ -80439,7 +80753,7 @@ var PlantHeadView = () => {
|
|
|
80439
80753
|
startTime: shift.startTime,
|
|
80440
80754
|
endTime: shift.endTime
|
|
80441
80755
|
});
|
|
80442
|
-
return bucket === "day" ?
|
|
80756
|
+
return bucket === "day" ? parseTimeToMinutes4(shift.startTime) : null;
|
|
80443
80757
|
}).filter((value) => value !== null);
|
|
80444
80758
|
}) : [];
|
|
80445
80759
|
if (dayStartCandidates.length > 0) {
|