@optifye/dashboard-core 6.10.9 → 6.10.11
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 +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +181 -81
- package/dist/index.mjs +181 -81
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -4816,6 +4816,7 @@ declare class WorkspaceHealthService {
|
|
|
4816
4816
|
private getFromCache;
|
|
4817
4817
|
private setCache;
|
|
4818
4818
|
private getShiftTiming;
|
|
4819
|
+
private getShiftTimingForDateShift;
|
|
4819
4820
|
private normalizeHourBucket;
|
|
4820
4821
|
private normalizeOutputHourly;
|
|
4821
4822
|
private interpretUptimeValue;
|
package/dist/index.d.ts
CHANGED
|
@@ -4816,6 +4816,7 @@ declare class WorkspaceHealthService {
|
|
|
4816
4816
|
private getFromCache;
|
|
4817
4817
|
private setCache;
|
|
4818
4818
|
private getShiftTiming;
|
|
4819
|
+
private getShiftTimingForDateShift;
|
|
4819
4820
|
private normalizeHourBucket;
|
|
4820
4821
|
private normalizeOutputHourly;
|
|
4821
4822
|
private interpretUptimeValue;
|
package/dist/index.js
CHANGED
|
@@ -536,8 +536,13 @@ var memoizedOutputArrayAggregation = createMemoizedFunction(
|
|
|
536
536
|
var getOperationalDate = (timezone, date = /* @__PURE__ */ new Date(), shiftStartTime = "06:00") => {
|
|
537
537
|
const zonedDate = dateFnsTz.toZonedTime(date, timezone);
|
|
538
538
|
const hours = zonedDate.getHours();
|
|
539
|
-
const
|
|
540
|
-
const
|
|
539
|
+
const minutes = zonedDate.getMinutes();
|
|
540
|
+
const [startHourRaw, startMinuteRaw] = shiftStartTime.split(":").map(Number);
|
|
541
|
+
const startHour = Number.isFinite(startHourRaw) ? startHourRaw : 6;
|
|
542
|
+
const startMinute = Number.isFinite(startMinuteRaw) ? startMinuteRaw : 0;
|
|
543
|
+
const currentTotalMinutes = hours * 60 + minutes;
|
|
544
|
+
const shiftStartTotalMinutes = startHour * 60 + startMinute;
|
|
545
|
+
const operationalDate = currentTotalMinutes < shiftStartTotalMinutes ? dateFns.subDays(zonedDate, 1) : zonedDate;
|
|
541
546
|
return dateFns.format(operationalDate, "yyyy-MM-dd");
|
|
542
547
|
};
|
|
543
548
|
function formatTimeInZone(time2, timezone, formatString = "HH:mm:ss") {
|
|
@@ -2457,6 +2462,39 @@ var WorkspaceHealthService = class _WorkspaceHealthService {
|
|
|
2457
2462
|
pendingMinutes
|
|
2458
2463
|
};
|
|
2459
2464
|
}
|
|
2465
|
+
getShiftTimingForDateShift(shiftConfig, queryDate, queryShiftId) {
|
|
2466
|
+
const targetShiftConfig = shiftConfig?.shifts?.find((s) => s.shiftId === queryShiftId);
|
|
2467
|
+
const startTime = targetShiftConfig?.startTime || "06:00";
|
|
2468
|
+
const endTime = targetShiftConfig?.endTime || "18:00";
|
|
2469
|
+
const [year, month, day] = queryDate.split("-").map(Number);
|
|
2470
|
+
const [startHour = 0, startMin = 0] = startTime.split(":").map(Number);
|
|
2471
|
+
const [endHour = 0, endMin = 0] = endTime.split(":").map(Number);
|
|
2472
|
+
const shiftStartDate = new Date(year, month - 1, day, startHour, startMin, 0);
|
|
2473
|
+
let shiftEndDate;
|
|
2474
|
+
if (endHour < startHour || endHour === startHour && endMin < startMin) {
|
|
2475
|
+
shiftEndDate = new Date(year, month - 1, day + 1, endHour, endMin, 0);
|
|
2476
|
+
} else {
|
|
2477
|
+
shiftEndDate = new Date(year, month - 1, day, endHour, endMin, 0);
|
|
2478
|
+
}
|
|
2479
|
+
const totalMinutes = Math.floor((shiftEndDate.getTime() - shiftStartDate.getTime()) / (1e3 * 60));
|
|
2480
|
+
const now2 = /* @__PURE__ */ new Date();
|
|
2481
|
+
let completedMinutes;
|
|
2482
|
+
if (shiftEndDate < now2) {
|
|
2483
|
+
completedMinutes = totalMinutes;
|
|
2484
|
+
} else if (shiftStartDate > now2) {
|
|
2485
|
+
completedMinutes = 0;
|
|
2486
|
+
} else {
|
|
2487
|
+
completedMinutes = Math.floor((now2.getTime() - shiftStartDate.getTime()) / (1e3 * 60));
|
|
2488
|
+
}
|
|
2489
|
+
const pendingMinutes = totalMinutes - completedMinutes;
|
|
2490
|
+
return {
|
|
2491
|
+
shiftStartDate,
|
|
2492
|
+
shiftEndDate,
|
|
2493
|
+
totalMinutes,
|
|
2494
|
+
completedMinutes,
|
|
2495
|
+
pendingMinutes
|
|
2496
|
+
};
|
|
2497
|
+
}
|
|
2460
2498
|
normalizeHourBucket(bucket) {
|
|
2461
2499
|
if (Array.isArray(bucket)) return bucket;
|
|
2462
2500
|
if (bucket && Array.isArray(bucket.values)) return bucket.values;
|
|
@@ -2926,14 +2964,22 @@ var WorkspaceHealthService = class _WorkspaceHealthService {
|
|
|
2926
2964
|
if (!passedShiftConfig) {
|
|
2927
2965
|
console.warn("[workspaceHealthService.calculateWorkspaceUptime] \u26A0\uFE0F No shiftConfig passed! Falling back to static config. This may cause incorrect shift_id queries.");
|
|
2928
2966
|
}
|
|
2929
|
-
const
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
|
|
2933
|
-
|
|
2934
|
-
|
|
2935
|
-
const
|
|
2936
|
-
|
|
2967
|
+
const currentTiming = this.getShiftTiming(effectiveTimezone, shiftConfig);
|
|
2968
|
+
const queryDate = overrideDate ?? currentTiming.date;
|
|
2969
|
+
const queryShiftId = overrideShiftId ?? currentTiming.shiftId;
|
|
2970
|
+
let shiftStartDate = currentTiming.shiftStartDate;
|
|
2971
|
+
let completedMinutes = currentTiming.completedMinutes;
|
|
2972
|
+
const isHistoricalDate = overrideDate && overrideDate !== currentTiming.date;
|
|
2973
|
+
const isDifferentShift = overrideShiftId !== void 0 && overrideShiftId !== currentTiming.shiftId;
|
|
2974
|
+
if (isHistoricalDate || isDifferentShift) {
|
|
2975
|
+
const overrideTiming = this.getShiftTimingForDateShift(
|
|
2976
|
+
shiftConfig,
|
|
2977
|
+
queryDate,
|
|
2978
|
+
queryShiftId
|
|
2979
|
+
);
|
|
2980
|
+
shiftStartDate = overrideTiming.shiftStartDate;
|
|
2981
|
+
completedMinutes = overrideTiming.completedMinutes;
|
|
2982
|
+
}
|
|
2937
2983
|
const tableName = `performance_metrics_${companyId.replace(/-/g, "_")}`;
|
|
2938
2984
|
try {
|
|
2939
2985
|
const { data: queryData, error } = await supabase.from(tableName).select("workspace_id, workspace_display_name, output_hourly, output_array, line_id").eq("date", queryDate).eq("shift_id", queryShiftId);
|
|
@@ -3008,12 +3054,27 @@ var WorkspaceHealthService = class _WorkspaceHealthService {
|
|
|
3008
3054
|
const queryConfigs = [];
|
|
3009
3055
|
lineShiftConfigs.forEach((config, lineId) => {
|
|
3010
3056
|
const timing = this.getShiftTiming(timezone, config);
|
|
3057
|
+
const queryDate = overrideDate ?? timing.date;
|
|
3058
|
+
const queryShiftId = overrideShiftId ?? timing.shiftId;
|
|
3059
|
+
let shiftStartDate = timing.shiftStartDate;
|
|
3060
|
+
let completedMinutes = timing.completedMinutes;
|
|
3061
|
+
const isHistoricalDate = overrideDate && overrideDate !== timing.date;
|
|
3062
|
+
const isDifferentShift = overrideShiftId !== void 0 && overrideShiftId !== timing.shiftId;
|
|
3063
|
+
if (isHistoricalDate || isDifferentShift) {
|
|
3064
|
+
const overrideTiming = this.getShiftTimingForDateShift(
|
|
3065
|
+
config,
|
|
3066
|
+
queryDate,
|
|
3067
|
+
queryShiftId
|
|
3068
|
+
);
|
|
3069
|
+
shiftStartDate = overrideTiming.shiftStartDate;
|
|
3070
|
+
completedMinutes = overrideTiming.completedMinutes;
|
|
3071
|
+
}
|
|
3011
3072
|
queryConfigs.push({
|
|
3012
3073
|
lineId,
|
|
3013
|
-
date:
|
|
3014
|
-
shiftId:
|
|
3015
|
-
shiftStartDate
|
|
3016
|
-
completedMinutes
|
|
3074
|
+
date: queryDate,
|
|
3075
|
+
shiftId: queryShiftId,
|
|
3076
|
+
shiftStartDate,
|
|
3077
|
+
completedMinutes
|
|
3017
3078
|
});
|
|
3018
3079
|
});
|
|
3019
3080
|
const uniqueQueries = /* @__PURE__ */ new Map();
|
|
@@ -3038,7 +3099,12 @@ var WorkspaceHealthService = class _WorkspaceHealthService {
|
|
|
3038
3099
|
});
|
|
3039
3100
|
const queryPromises = Array.from(uniqueQueries.entries()).map(async ([key, { date, shiftId, lineConfigs }]) => {
|
|
3040
3101
|
try {
|
|
3041
|
-
const
|
|
3102
|
+
const lineIds = Array.from(new Set(lineConfigs.map((lc) => lc.lineId).filter(Boolean)));
|
|
3103
|
+
let query = supabase.from(tableName).select("workspace_id, workspace_display_name, output_hourly, output_array, line_id").eq("date", date).eq("shift_id", shiftId);
|
|
3104
|
+
if (lineIds.length > 0) {
|
|
3105
|
+
query = query.in("line_id", lineIds);
|
|
3106
|
+
}
|
|
3107
|
+
const { data, error } = await query;
|
|
3042
3108
|
if (error) {
|
|
3043
3109
|
console.error(`[calculateWorkspaceUptimeMultiLine] Error fetching metrics for ${key}:`, error);
|
|
3044
3110
|
return { records: [], lineConfigs };
|
|
@@ -3059,11 +3125,16 @@ var WorkspaceHealthService = class _WorkspaceHealthService {
|
|
|
3059
3125
|
recordWorkspaceDisplayName: record.workspace_display_name,
|
|
3060
3126
|
availableLineIds: lineConfigs.map((lc) => lc.lineId),
|
|
3061
3127
|
matchFound: !!lineConfig,
|
|
3062
|
-
matchedLineId: lineConfig?.lineId || "
|
|
3128
|
+
matchedLineId: lineConfig?.lineId || "none"
|
|
3063
3129
|
});
|
|
3064
|
-
|
|
3065
|
-
|
|
3066
|
-
|
|
3130
|
+
if (!lineConfig) {
|
|
3131
|
+
console.warn("[calculateWorkspaceUptimeMultiLine] No line config match for record, skipping", {
|
|
3132
|
+
recordLineId: record.line_id,
|
|
3133
|
+
recordWorkspaceId: record.workspace_id
|
|
3134
|
+
});
|
|
3135
|
+
continue;
|
|
3136
|
+
}
|
|
3137
|
+
const { shiftStartDate, completedMinutes } = lineConfig;
|
|
3067
3138
|
const outputHourly = this.normalizeOutputHourly(record.output_hourly || {});
|
|
3068
3139
|
const outputArray = Array.isArray(record.output_array) ? record.output_array : [];
|
|
3069
3140
|
let uptimeMinutes = 0;
|
|
@@ -37421,50 +37492,61 @@ var LinePdfGenerator = ({
|
|
|
37421
37492
|
doc.setLineWidth(0.8);
|
|
37422
37493
|
doc.line(20, 118, 190, 118);
|
|
37423
37494
|
const hourlyOverviewStartY = 123;
|
|
37495
|
+
const parseTimeToMinutes2 = (timeStr) => {
|
|
37496
|
+
const [hours, minutes] = timeStr.split(":");
|
|
37497
|
+
const hour = parseInt(hours, 10);
|
|
37498
|
+
const minute = parseInt(minutes || "0", 10);
|
|
37499
|
+
if (Number.isNaN(hour) || Number.isNaN(minute)) {
|
|
37500
|
+
return NaN;
|
|
37501
|
+
}
|
|
37502
|
+
return (hour * 60 + minute) % (24 * 60);
|
|
37503
|
+
};
|
|
37504
|
+
const formatMinutesLabel = (totalMinutes) => {
|
|
37505
|
+
const normalized = (totalMinutes % (24 * 60) + 24 * 60) % (24 * 60);
|
|
37506
|
+
const hour = Math.floor(normalized / 60);
|
|
37507
|
+
const minute = normalized % 60;
|
|
37508
|
+
const time2 = /* @__PURE__ */ new Date();
|
|
37509
|
+
time2.setHours(hour);
|
|
37510
|
+
time2.setMinutes(minute);
|
|
37511
|
+
time2.setSeconds(0);
|
|
37512
|
+
time2.setMilliseconds(0);
|
|
37513
|
+
return time2.toLocaleTimeString("en-IN", {
|
|
37514
|
+
hour: "2-digit",
|
|
37515
|
+
minute: "2-digit",
|
|
37516
|
+
hour12: true,
|
|
37517
|
+
timeZone: "Asia/Kolkata"
|
|
37518
|
+
});
|
|
37519
|
+
};
|
|
37520
|
+
const buildRange = (startMinutes, minutes) => {
|
|
37521
|
+
const endMinutes = startMinutes + minutes;
|
|
37522
|
+
return {
|
|
37523
|
+
label: `${formatMinutesLabel(startMinutes)} - ${formatMinutesLabel(endMinutes)}`,
|
|
37524
|
+
minutes
|
|
37525
|
+
};
|
|
37526
|
+
};
|
|
37424
37527
|
const getHourlyTimeRanges = (startTimeStr, endTimeStr) => {
|
|
37425
|
-
const
|
|
37426
|
-
|
|
37427
|
-
|
|
37428
|
-
|
|
37429
|
-
|
|
37430
|
-
|
|
37431
|
-
|
|
37432
|
-
|
|
37433
|
-
|
|
37434
|
-
|
|
37435
|
-
|
|
37436
|
-
|
|
37437
|
-
|
|
37438
|
-
|
|
37439
|
-
|
|
37440
|
-
|
|
37441
|
-
}
|
|
37442
|
-
|
|
37443
|
-
|
|
37444
|
-
const
|
|
37445
|
-
|
|
37446
|
-
|
|
37447
|
-
hourStartTime.setSeconds(0);
|
|
37448
|
-
hourStartTime.setMilliseconds(0);
|
|
37449
|
-
let hourEndTime = /* @__PURE__ */ new Date();
|
|
37450
|
-
if (isLastHour && endTimeStr) {
|
|
37451
|
-
hourEndTime.setHours(endHour % 24);
|
|
37452
|
-
hourEndTime.setMinutes(endMinute);
|
|
37453
|
-
} else {
|
|
37454
|
-
hourEndTime.setHours((startHour + i + 1) % 24);
|
|
37455
|
-
hourEndTime.setMinutes(startMinute);
|
|
37456
|
-
}
|
|
37457
|
-
hourEndTime.setSeconds(0);
|
|
37458
|
-
hourEndTime.setMilliseconds(0);
|
|
37459
|
-
const formatTime5 = (date2) => {
|
|
37460
|
-
return date2.toLocaleTimeString("en-IN", {
|
|
37461
|
-
hour: "2-digit",
|
|
37462
|
-
minute: "2-digit",
|
|
37463
|
-
hour12: true,
|
|
37464
|
-
timeZone: "Asia/Kolkata"
|
|
37465
|
-
});
|
|
37466
|
-
};
|
|
37467
|
-
return `${formatTime5(hourStartTime)} - ${formatTime5(hourEndTime)}`;
|
|
37528
|
+
const startMinutes = parseTimeToMinutes2(startTimeStr);
|
|
37529
|
+
if (Number.isNaN(startMinutes)) {
|
|
37530
|
+
return [];
|
|
37531
|
+
}
|
|
37532
|
+
if (!endTimeStr) {
|
|
37533
|
+
const defaultHours = 11;
|
|
37534
|
+
return Array.from({ length: defaultHours }, (_, i) => buildRange(startMinutes + i * 60, 60));
|
|
37535
|
+
}
|
|
37536
|
+
const endMinutes = parseTimeToMinutes2(endTimeStr);
|
|
37537
|
+
if (Number.isNaN(endMinutes)) {
|
|
37538
|
+
const fallbackHours = 11;
|
|
37539
|
+
return Array.from({ length: fallbackHours }, (_, i) => buildRange(startMinutes + i * 60, 60));
|
|
37540
|
+
}
|
|
37541
|
+
let durationMinutes = endMinutes - startMinutes;
|
|
37542
|
+
if (durationMinutes <= 0) {
|
|
37543
|
+
durationMinutes += 24 * 60;
|
|
37544
|
+
}
|
|
37545
|
+
const rangeCount = Math.max(1, Math.ceil(durationMinutes / 60));
|
|
37546
|
+
return Array.from({ length: rangeCount }, (_, i) => {
|
|
37547
|
+
const remainingMinutes = durationMinutes - i * 60;
|
|
37548
|
+
const rangeMinutes = remainingMinutes >= 60 ? 60 : remainingMinutes;
|
|
37549
|
+
return buildRange(startMinutes + i * 60, rangeMinutes);
|
|
37468
37550
|
});
|
|
37469
37551
|
};
|
|
37470
37552
|
const hourlyTimeRanges = lineInfo.metrics.shift_start ? getHourlyTimeRanges(lineInfo.metrics.shift_start, lineInfo.metrics.shift_end) : [];
|
|
@@ -37476,8 +37558,13 @@ var LinePdfGenerator = ({
|
|
|
37476
37558
|
const startHour = parseInt(startHourStr);
|
|
37477
37559
|
const startMinute = parseInt(startMinuteStr || "0");
|
|
37478
37560
|
const [endHourStr, endMinuteStr] = (lineInfo.metrics.shift_end || "18:00").split(":");
|
|
37561
|
+
const endHour = parseInt(endHourStr);
|
|
37479
37562
|
const endMinute = parseInt(endMinuteStr || "0");
|
|
37480
|
-
|
|
37563
|
+
let durationMinutes = endHour * 60 + endMinute - (startHour * 60 + startMinute);
|
|
37564
|
+
if (durationMinutes <= 0) {
|
|
37565
|
+
durationMinutes += 24 * 60;
|
|
37566
|
+
}
|
|
37567
|
+
const hasPartialLastHour = durationMinutes % 60 !== 0;
|
|
37481
37568
|
const expectedHours = [];
|
|
37482
37569
|
for (let i = 0; i < shiftDuration; i++) {
|
|
37483
37570
|
expectedHours.push((startHour + i) % 24);
|
|
@@ -37668,19 +37755,21 @@ var LinePdfGenerator = ({
|
|
|
37668
37755
|
const hourNumber = (startHour + index) % 24;
|
|
37669
37756
|
const dataCollected = !isTodayForTable || hourNumber < currentHour;
|
|
37670
37757
|
const outputStr = dataCollected ? actualOutput.toString() : "TBD";
|
|
37671
|
-
const targetStr = targetOutputPerHour.toString();
|
|
37672
37758
|
if (index < totalRows - 1) {
|
|
37673
37759
|
const rowBottomY = headerBottomY + (index + 1) * rowSpacing;
|
|
37674
37760
|
doc.setDrawColor(200, 200, 200);
|
|
37675
37761
|
doc.line(20, rowBottomY, 190, rowBottomY);
|
|
37676
37762
|
}
|
|
37677
|
-
|
|
37763
|
+
const rangeMinutes = timeRange.minutes || 60;
|
|
37764
|
+
const targetForRange = targetOutputPerHour * (rangeMinutes / 60);
|
|
37765
|
+
const targetStr = rangeMinutes === 60 ? targetOutputPerHour.toString() : targetForRange.toFixed(1).replace(/\.0$/, "");
|
|
37766
|
+
doc.text(timeRange.label, 25, yPos);
|
|
37678
37767
|
doc.text(outputStr, 75, yPos);
|
|
37679
37768
|
doc.text(targetStr, 105, yPos);
|
|
37680
37769
|
if (!dataCollected) {
|
|
37681
37770
|
doc.setTextColor(100, 100, 100);
|
|
37682
37771
|
doc.text("-", 135, yPos);
|
|
37683
|
-
} else if (actualOutput >=
|
|
37772
|
+
} else if (actualOutput >= targetForRange) {
|
|
37684
37773
|
doc.setTextColor(0, 171, 69);
|
|
37685
37774
|
doc.setFont("ZapfDingbats", "normal");
|
|
37686
37775
|
doc.text("4", 135, yPos);
|
|
@@ -39091,23 +39180,29 @@ var WorkspacePdfGenerator = ({ workspace, className, idleTimeReasons }) => {
|
|
|
39091
39180
|
const colBoundaries = [20, 70, 100, 130, 155, 190];
|
|
39092
39181
|
const totalRows = hourlyData.length;
|
|
39093
39182
|
const gridBottomY = headerBottomY + totalRows * rowHeight;
|
|
39183
|
+
const tableHeight = gridBottomY - gridTopY;
|
|
39184
|
+
doc.setFillColor(255, 255, 255);
|
|
39185
|
+
doc.roundedRect(20, gridTopY, 170, tableHeight, 2, 2, "F");
|
|
39186
|
+
doc.setDrawColor(230, 230, 230);
|
|
39187
|
+
doc.setLineWidth(0.2);
|
|
39188
|
+
doc.roundedRect(20, gridTopY, 170, tableHeight, 2, 2, "S");
|
|
39094
39189
|
doc.setDrawColor(200, 200, 200);
|
|
39095
39190
|
doc.setLineWidth(0.3);
|
|
39096
|
-
doc.line(20, gridTopY, 190, gridTopY);
|
|
39097
39191
|
doc.line(20, headerBottomY, 190, headerBottomY);
|
|
39098
|
-
colBoundaries.forEach((x) => {
|
|
39192
|
+
colBoundaries.slice(1, -1).forEach((x) => {
|
|
39099
39193
|
doc.line(x, gridTopY, x, gridBottomY);
|
|
39100
39194
|
});
|
|
39101
39195
|
doc.setFontSize(headerFontSize);
|
|
39102
39196
|
doc.setFont("helvetica", "bold");
|
|
39103
|
-
|
|
39104
|
-
doc.text("
|
|
39105
|
-
doc.text("
|
|
39106
|
-
doc.text("
|
|
39107
|
-
doc.text("
|
|
39197
|
+
const headerTextY = gridTopY + 5.5;
|
|
39198
|
+
doc.text("Time Range", 25, headerTextY);
|
|
39199
|
+
doc.text("Output", 75, headerTextY);
|
|
39200
|
+
doc.text("Target", 105, headerTextY);
|
|
39201
|
+
doc.text("Status", 135, headerTextY);
|
|
39202
|
+
doc.text("Remarks", 160, headerTextY);
|
|
39108
39203
|
doc.setFontSize(contentFontSize);
|
|
39109
39204
|
doc.setFont("helvetica", "normal");
|
|
39110
|
-
let yPos =
|
|
39205
|
+
let yPos = headerBottomY + 5.5;
|
|
39111
39206
|
const workspaceDate = new Date(workspace.date);
|
|
39112
39207
|
const today = /* @__PURE__ */ new Date();
|
|
39113
39208
|
today.setHours(0, 0, 0, 0);
|
|
@@ -39135,9 +39230,11 @@ var WorkspacePdfGenerator = ({ workspace, className, idleTimeReasons }) => {
|
|
|
39135
39230
|
const dataCollected = !isToday2 || hourNumber < currentHour;
|
|
39136
39231
|
const outputStr = dataCollected ? output.toString() : "TBD";
|
|
39137
39232
|
const targetStr = hourlyTarget.toString();
|
|
39138
|
-
|
|
39139
|
-
|
|
39140
|
-
|
|
39233
|
+
if (index < totalRows - 1) {
|
|
39234
|
+
const rowBottomY = headerBottomY + (index + 1) * rowHeight;
|
|
39235
|
+
doc.setDrawColor(200, 200, 200);
|
|
39236
|
+
doc.line(20, rowBottomY, 190, rowBottomY);
|
|
39237
|
+
}
|
|
39141
39238
|
doc.text(timeRange, 25, yPos);
|
|
39142
39239
|
doc.text(outputStr, 75, yPos);
|
|
39143
39240
|
doc.text(targetStr, 105, yPos);
|
|
@@ -58013,6 +58110,8 @@ var ClipVideoCarousel = ({ clips, clipsService }) => {
|
|
|
58013
58110
|
const [videos, setVideos] = React24.useState([]);
|
|
58014
58111
|
const [loading, setLoading] = React24.useState(false);
|
|
58015
58112
|
const [error, setError] = React24.useState(null);
|
|
58113
|
+
const currentVideo = videos[currentIndex];
|
|
58114
|
+
const { crop: workspaceCrop } = useWorkspaceCrop(currentVideo?.workspace_id || null);
|
|
58016
58115
|
React24.useEffect(() => {
|
|
58017
58116
|
let cancelled = false;
|
|
58018
58117
|
const load = async () => {
|
|
@@ -58032,7 +58131,8 @@ var ClipVideoCarousel = ({ clips, clipsService }) => {
|
|
|
58032
58131
|
const cycleTime = typeof c.cycle_time_seconds === "number" ? c.cycle_time_seconds : typeof c.cycle_sec === "number" ? c.cycle_sec : void 0;
|
|
58033
58132
|
return {
|
|
58034
58133
|
...video,
|
|
58035
|
-
cycle_time_seconds: cycleTime ?? video.cycle_time_seconds
|
|
58134
|
+
cycle_time_seconds: cycleTime ?? video.cycle_time_seconds,
|
|
58135
|
+
workspace_id: c.workspace_id
|
|
58036
58136
|
};
|
|
58037
58137
|
})
|
|
58038
58138
|
);
|
|
@@ -58063,17 +58163,17 @@ var ClipVideoCarousel = ({ clips, clipsService }) => {
|
|
|
58063
58163
|
setCurrentIndex((prev) => (prev - 1 + Math.max(videos.length, 1)) % Math.max(videos.length, 1));
|
|
58064
58164
|
};
|
|
58065
58165
|
if (!clips || clips.length === 0) return null;
|
|
58066
|
-
const currentVideo = videos[currentIndex];
|
|
58067
58166
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative group bg-gray-900 rounded-lg overflow-hidden aspect-video", children: [
|
|
58068
58167
|
loading && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 flex items-center justify-center text-sm text-white/80", children: "Loading clips\u2026" }),
|
|
58069
58168
|
!loading && error && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 flex items-center justify-center text-sm text-white/80", children: error }),
|
|
58070
58169
|
!loading && !error && currentVideo?.src && /* @__PURE__ */ jsxRuntime.jsx(
|
|
58071
|
-
|
|
58170
|
+
CroppedVideoPlayer,
|
|
58072
58171
|
{
|
|
58073
58172
|
src: currentVideo.src,
|
|
58074
58173
|
className: "w-full h-full object-cover opacity-90 group-hover:opacity-100 transition-opacity",
|
|
58075
58174
|
controls: true,
|
|
58076
|
-
playsInline: true
|
|
58175
|
+
playsInline: true,
|
|
58176
|
+
crop: workspaceCrop?.crop || null
|
|
58077
58177
|
},
|
|
58078
58178
|
currentVideo.src
|
|
58079
58179
|
),
|
package/dist/index.mjs
CHANGED
|
@@ -507,8 +507,13 @@ var memoizedOutputArrayAggregation = createMemoizedFunction(
|
|
|
507
507
|
var getOperationalDate = (timezone, date = /* @__PURE__ */ new Date(), shiftStartTime = "06:00") => {
|
|
508
508
|
const zonedDate = toZonedTime(date, timezone);
|
|
509
509
|
const hours = zonedDate.getHours();
|
|
510
|
-
const
|
|
511
|
-
const
|
|
510
|
+
const minutes = zonedDate.getMinutes();
|
|
511
|
+
const [startHourRaw, startMinuteRaw] = shiftStartTime.split(":").map(Number);
|
|
512
|
+
const startHour = Number.isFinite(startHourRaw) ? startHourRaw : 6;
|
|
513
|
+
const startMinute = Number.isFinite(startMinuteRaw) ? startMinuteRaw : 0;
|
|
514
|
+
const currentTotalMinutes = hours * 60 + minutes;
|
|
515
|
+
const shiftStartTotalMinutes = startHour * 60 + startMinute;
|
|
516
|
+
const operationalDate = currentTotalMinutes < shiftStartTotalMinutes ? subDays(zonedDate, 1) : zonedDate;
|
|
512
517
|
return format(operationalDate, "yyyy-MM-dd");
|
|
513
518
|
};
|
|
514
519
|
function formatTimeInZone(time2, timezone, formatString = "HH:mm:ss") {
|
|
@@ -2428,6 +2433,39 @@ var WorkspaceHealthService = class _WorkspaceHealthService {
|
|
|
2428
2433
|
pendingMinutes
|
|
2429
2434
|
};
|
|
2430
2435
|
}
|
|
2436
|
+
getShiftTimingForDateShift(shiftConfig, queryDate, queryShiftId) {
|
|
2437
|
+
const targetShiftConfig = shiftConfig?.shifts?.find((s) => s.shiftId === queryShiftId);
|
|
2438
|
+
const startTime = targetShiftConfig?.startTime || "06:00";
|
|
2439
|
+
const endTime = targetShiftConfig?.endTime || "18:00";
|
|
2440
|
+
const [year, month, day] = queryDate.split("-").map(Number);
|
|
2441
|
+
const [startHour = 0, startMin = 0] = startTime.split(":").map(Number);
|
|
2442
|
+
const [endHour = 0, endMin = 0] = endTime.split(":").map(Number);
|
|
2443
|
+
const shiftStartDate = new Date(year, month - 1, day, startHour, startMin, 0);
|
|
2444
|
+
let shiftEndDate;
|
|
2445
|
+
if (endHour < startHour || endHour === startHour && endMin < startMin) {
|
|
2446
|
+
shiftEndDate = new Date(year, month - 1, day + 1, endHour, endMin, 0);
|
|
2447
|
+
} else {
|
|
2448
|
+
shiftEndDate = new Date(year, month - 1, day, endHour, endMin, 0);
|
|
2449
|
+
}
|
|
2450
|
+
const totalMinutes = Math.floor((shiftEndDate.getTime() - shiftStartDate.getTime()) / (1e3 * 60));
|
|
2451
|
+
const now2 = /* @__PURE__ */ new Date();
|
|
2452
|
+
let completedMinutes;
|
|
2453
|
+
if (shiftEndDate < now2) {
|
|
2454
|
+
completedMinutes = totalMinutes;
|
|
2455
|
+
} else if (shiftStartDate > now2) {
|
|
2456
|
+
completedMinutes = 0;
|
|
2457
|
+
} else {
|
|
2458
|
+
completedMinutes = Math.floor((now2.getTime() - shiftStartDate.getTime()) / (1e3 * 60));
|
|
2459
|
+
}
|
|
2460
|
+
const pendingMinutes = totalMinutes - completedMinutes;
|
|
2461
|
+
return {
|
|
2462
|
+
shiftStartDate,
|
|
2463
|
+
shiftEndDate,
|
|
2464
|
+
totalMinutes,
|
|
2465
|
+
completedMinutes,
|
|
2466
|
+
pendingMinutes
|
|
2467
|
+
};
|
|
2468
|
+
}
|
|
2431
2469
|
normalizeHourBucket(bucket) {
|
|
2432
2470
|
if (Array.isArray(bucket)) return bucket;
|
|
2433
2471
|
if (bucket && Array.isArray(bucket.values)) return bucket.values;
|
|
@@ -2897,14 +2935,22 @@ var WorkspaceHealthService = class _WorkspaceHealthService {
|
|
|
2897
2935
|
if (!passedShiftConfig) {
|
|
2898
2936
|
console.warn("[workspaceHealthService.calculateWorkspaceUptime] \u26A0\uFE0F No shiftConfig passed! Falling back to static config. This may cause incorrect shift_id queries.");
|
|
2899
2937
|
}
|
|
2900
|
-
const
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
const
|
|
2907
|
-
|
|
2938
|
+
const currentTiming = this.getShiftTiming(effectiveTimezone, shiftConfig);
|
|
2939
|
+
const queryDate = overrideDate ?? currentTiming.date;
|
|
2940
|
+
const queryShiftId = overrideShiftId ?? currentTiming.shiftId;
|
|
2941
|
+
let shiftStartDate = currentTiming.shiftStartDate;
|
|
2942
|
+
let completedMinutes = currentTiming.completedMinutes;
|
|
2943
|
+
const isHistoricalDate = overrideDate && overrideDate !== currentTiming.date;
|
|
2944
|
+
const isDifferentShift = overrideShiftId !== void 0 && overrideShiftId !== currentTiming.shiftId;
|
|
2945
|
+
if (isHistoricalDate || isDifferentShift) {
|
|
2946
|
+
const overrideTiming = this.getShiftTimingForDateShift(
|
|
2947
|
+
shiftConfig,
|
|
2948
|
+
queryDate,
|
|
2949
|
+
queryShiftId
|
|
2950
|
+
);
|
|
2951
|
+
shiftStartDate = overrideTiming.shiftStartDate;
|
|
2952
|
+
completedMinutes = overrideTiming.completedMinutes;
|
|
2953
|
+
}
|
|
2908
2954
|
const tableName = `performance_metrics_${companyId.replace(/-/g, "_")}`;
|
|
2909
2955
|
try {
|
|
2910
2956
|
const { data: queryData, error } = await supabase.from(tableName).select("workspace_id, workspace_display_name, output_hourly, output_array, line_id").eq("date", queryDate).eq("shift_id", queryShiftId);
|
|
@@ -2979,12 +3025,27 @@ var WorkspaceHealthService = class _WorkspaceHealthService {
|
|
|
2979
3025
|
const queryConfigs = [];
|
|
2980
3026
|
lineShiftConfigs.forEach((config, lineId) => {
|
|
2981
3027
|
const timing = this.getShiftTiming(timezone, config);
|
|
3028
|
+
const queryDate = overrideDate ?? timing.date;
|
|
3029
|
+
const queryShiftId = overrideShiftId ?? timing.shiftId;
|
|
3030
|
+
let shiftStartDate = timing.shiftStartDate;
|
|
3031
|
+
let completedMinutes = timing.completedMinutes;
|
|
3032
|
+
const isHistoricalDate = overrideDate && overrideDate !== timing.date;
|
|
3033
|
+
const isDifferentShift = overrideShiftId !== void 0 && overrideShiftId !== timing.shiftId;
|
|
3034
|
+
if (isHistoricalDate || isDifferentShift) {
|
|
3035
|
+
const overrideTiming = this.getShiftTimingForDateShift(
|
|
3036
|
+
config,
|
|
3037
|
+
queryDate,
|
|
3038
|
+
queryShiftId
|
|
3039
|
+
);
|
|
3040
|
+
shiftStartDate = overrideTiming.shiftStartDate;
|
|
3041
|
+
completedMinutes = overrideTiming.completedMinutes;
|
|
3042
|
+
}
|
|
2982
3043
|
queryConfigs.push({
|
|
2983
3044
|
lineId,
|
|
2984
|
-
date:
|
|
2985
|
-
shiftId:
|
|
2986
|
-
shiftStartDate
|
|
2987
|
-
completedMinutes
|
|
3045
|
+
date: queryDate,
|
|
3046
|
+
shiftId: queryShiftId,
|
|
3047
|
+
shiftStartDate,
|
|
3048
|
+
completedMinutes
|
|
2988
3049
|
});
|
|
2989
3050
|
});
|
|
2990
3051
|
const uniqueQueries = /* @__PURE__ */ new Map();
|
|
@@ -3009,7 +3070,12 @@ var WorkspaceHealthService = class _WorkspaceHealthService {
|
|
|
3009
3070
|
});
|
|
3010
3071
|
const queryPromises = Array.from(uniqueQueries.entries()).map(async ([key, { date, shiftId, lineConfigs }]) => {
|
|
3011
3072
|
try {
|
|
3012
|
-
const
|
|
3073
|
+
const lineIds = Array.from(new Set(lineConfigs.map((lc) => lc.lineId).filter(Boolean)));
|
|
3074
|
+
let query = supabase.from(tableName).select("workspace_id, workspace_display_name, output_hourly, output_array, line_id").eq("date", date).eq("shift_id", shiftId);
|
|
3075
|
+
if (lineIds.length > 0) {
|
|
3076
|
+
query = query.in("line_id", lineIds);
|
|
3077
|
+
}
|
|
3078
|
+
const { data, error } = await query;
|
|
3013
3079
|
if (error) {
|
|
3014
3080
|
console.error(`[calculateWorkspaceUptimeMultiLine] Error fetching metrics for ${key}:`, error);
|
|
3015
3081
|
return { records: [], lineConfigs };
|
|
@@ -3030,11 +3096,16 @@ var WorkspaceHealthService = class _WorkspaceHealthService {
|
|
|
3030
3096
|
recordWorkspaceDisplayName: record.workspace_display_name,
|
|
3031
3097
|
availableLineIds: lineConfigs.map((lc) => lc.lineId),
|
|
3032
3098
|
matchFound: !!lineConfig,
|
|
3033
|
-
matchedLineId: lineConfig?.lineId || "
|
|
3099
|
+
matchedLineId: lineConfig?.lineId || "none"
|
|
3034
3100
|
});
|
|
3035
|
-
|
|
3036
|
-
|
|
3037
|
-
|
|
3101
|
+
if (!lineConfig) {
|
|
3102
|
+
console.warn("[calculateWorkspaceUptimeMultiLine] No line config match for record, skipping", {
|
|
3103
|
+
recordLineId: record.line_id,
|
|
3104
|
+
recordWorkspaceId: record.workspace_id
|
|
3105
|
+
});
|
|
3106
|
+
continue;
|
|
3107
|
+
}
|
|
3108
|
+
const { shiftStartDate, completedMinutes } = lineConfig;
|
|
3038
3109
|
const outputHourly = this.normalizeOutputHourly(record.output_hourly || {});
|
|
3039
3110
|
const outputArray = Array.isArray(record.output_array) ? record.output_array : [];
|
|
3040
3111
|
let uptimeMinutes = 0;
|
|
@@ -37392,50 +37463,61 @@ var LinePdfGenerator = ({
|
|
|
37392
37463
|
doc.setLineWidth(0.8);
|
|
37393
37464
|
doc.line(20, 118, 190, 118);
|
|
37394
37465
|
const hourlyOverviewStartY = 123;
|
|
37466
|
+
const parseTimeToMinutes2 = (timeStr) => {
|
|
37467
|
+
const [hours, minutes] = timeStr.split(":");
|
|
37468
|
+
const hour = parseInt(hours, 10);
|
|
37469
|
+
const minute = parseInt(minutes || "0", 10);
|
|
37470
|
+
if (Number.isNaN(hour) || Number.isNaN(minute)) {
|
|
37471
|
+
return NaN;
|
|
37472
|
+
}
|
|
37473
|
+
return (hour * 60 + minute) % (24 * 60);
|
|
37474
|
+
};
|
|
37475
|
+
const formatMinutesLabel = (totalMinutes) => {
|
|
37476
|
+
const normalized = (totalMinutes % (24 * 60) + 24 * 60) % (24 * 60);
|
|
37477
|
+
const hour = Math.floor(normalized / 60);
|
|
37478
|
+
const minute = normalized % 60;
|
|
37479
|
+
const time2 = /* @__PURE__ */ new Date();
|
|
37480
|
+
time2.setHours(hour);
|
|
37481
|
+
time2.setMinutes(minute);
|
|
37482
|
+
time2.setSeconds(0);
|
|
37483
|
+
time2.setMilliseconds(0);
|
|
37484
|
+
return time2.toLocaleTimeString("en-IN", {
|
|
37485
|
+
hour: "2-digit",
|
|
37486
|
+
minute: "2-digit",
|
|
37487
|
+
hour12: true,
|
|
37488
|
+
timeZone: "Asia/Kolkata"
|
|
37489
|
+
});
|
|
37490
|
+
};
|
|
37491
|
+
const buildRange = (startMinutes, minutes) => {
|
|
37492
|
+
const endMinutes = startMinutes + minutes;
|
|
37493
|
+
return {
|
|
37494
|
+
label: `${formatMinutesLabel(startMinutes)} - ${formatMinutesLabel(endMinutes)}`,
|
|
37495
|
+
minutes
|
|
37496
|
+
};
|
|
37497
|
+
};
|
|
37395
37498
|
const getHourlyTimeRanges = (startTimeStr, endTimeStr) => {
|
|
37396
|
-
const
|
|
37397
|
-
|
|
37398
|
-
|
|
37399
|
-
|
|
37400
|
-
|
|
37401
|
-
|
|
37402
|
-
|
|
37403
|
-
|
|
37404
|
-
|
|
37405
|
-
|
|
37406
|
-
|
|
37407
|
-
|
|
37408
|
-
|
|
37409
|
-
|
|
37410
|
-
|
|
37411
|
-
|
|
37412
|
-
}
|
|
37413
|
-
|
|
37414
|
-
|
|
37415
|
-
const
|
|
37416
|
-
|
|
37417
|
-
|
|
37418
|
-
hourStartTime.setSeconds(0);
|
|
37419
|
-
hourStartTime.setMilliseconds(0);
|
|
37420
|
-
let hourEndTime = /* @__PURE__ */ new Date();
|
|
37421
|
-
if (isLastHour && endTimeStr) {
|
|
37422
|
-
hourEndTime.setHours(endHour % 24);
|
|
37423
|
-
hourEndTime.setMinutes(endMinute);
|
|
37424
|
-
} else {
|
|
37425
|
-
hourEndTime.setHours((startHour + i + 1) % 24);
|
|
37426
|
-
hourEndTime.setMinutes(startMinute);
|
|
37427
|
-
}
|
|
37428
|
-
hourEndTime.setSeconds(0);
|
|
37429
|
-
hourEndTime.setMilliseconds(0);
|
|
37430
|
-
const formatTime5 = (date2) => {
|
|
37431
|
-
return date2.toLocaleTimeString("en-IN", {
|
|
37432
|
-
hour: "2-digit",
|
|
37433
|
-
minute: "2-digit",
|
|
37434
|
-
hour12: true,
|
|
37435
|
-
timeZone: "Asia/Kolkata"
|
|
37436
|
-
});
|
|
37437
|
-
};
|
|
37438
|
-
return `${formatTime5(hourStartTime)} - ${formatTime5(hourEndTime)}`;
|
|
37499
|
+
const startMinutes = parseTimeToMinutes2(startTimeStr);
|
|
37500
|
+
if (Number.isNaN(startMinutes)) {
|
|
37501
|
+
return [];
|
|
37502
|
+
}
|
|
37503
|
+
if (!endTimeStr) {
|
|
37504
|
+
const defaultHours = 11;
|
|
37505
|
+
return Array.from({ length: defaultHours }, (_, i) => buildRange(startMinutes + i * 60, 60));
|
|
37506
|
+
}
|
|
37507
|
+
const endMinutes = parseTimeToMinutes2(endTimeStr);
|
|
37508
|
+
if (Number.isNaN(endMinutes)) {
|
|
37509
|
+
const fallbackHours = 11;
|
|
37510
|
+
return Array.from({ length: fallbackHours }, (_, i) => buildRange(startMinutes + i * 60, 60));
|
|
37511
|
+
}
|
|
37512
|
+
let durationMinutes = endMinutes - startMinutes;
|
|
37513
|
+
if (durationMinutes <= 0) {
|
|
37514
|
+
durationMinutes += 24 * 60;
|
|
37515
|
+
}
|
|
37516
|
+
const rangeCount = Math.max(1, Math.ceil(durationMinutes / 60));
|
|
37517
|
+
return Array.from({ length: rangeCount }, (_, i) => {
|
|
37518
|
+
const remainingMinutes = durationMinutes - i * 60;
|
|
37519
|
+
const rangeMinutes = remainingMinutes >= 60 ? 60 : remainingMinutes;
|
|
37520
|
+
return buildRange(startMinutes + i * 60, rangeMinutes);
|
|
37439
37521
|
});
|
|
37440
37522
|
};
|
|
37441
37523
|
const hourlyTimeRanges = lineInfo.metrics.shift_start ? getHourlyTimeRanges(lineInfo.metrics.shift_start, lineInfo.metrics.shift_end) : [];
|
|
@@ -37447,8 +37529,13 @@ var LinePdfGenerator = ({
|
|
|
37447
37529
|
const startHour = parseInt(startHourStr);
|
|
37448
37530
|
const startMinute = parseInt(startMinuteStr || "0");
|
|
37449
37531
|
const [endHourStr, endMinuteStr] = (lineInfo.metrics.shift_end || "18:00").split(":");
|
|
37532
|
+
const endHour = parseInt(endHourStr);
|
|
37450
37533
|
const endMinute = parseInt(endMinuteStr || "0");
|
|
37451
|
-
|
|
37534
|
+
let durationMinutes = endHour * 60 + endMinute - (startHour * 60 + startMinute);
|
|
37535
|
+
if (durationMinutes <= 0) {
|
|
37536
|
+
durationMinutes += 24 * 60;
|
|
37537
|
+
}
|
|
37538
|
+
const hasPartialLastHour = durationMinutes % 60 !== 0;
|
|
37452
37539
|
const expectedHours = [];
|
|
37453
37540
|
for (let i = 0; i < shiftDuration; i++) {
|
|
37454
37541
|
expectedHours.push((startHour + i) % 24);
|
|
@@ -37639,19 +37726,21 @@ var LinePdfGenerator = ({
|
|
|
37639
37726
|
const hourNumber = (startHour + index) % 24;
|
|
37640
37727
|
const dataCollected = !isTodayForTable || hourNumber < currentHour;
|
|
37641
37728
|
const outputStr = dataCollected ? actualOutput.toString() : "TBD";
|
|
37642
|
-
const targetStr = targetOutputPerHour.toString();
|
|
37643
37729
|
if (index < totalRows - 1) {
|
|
37644
37730
|
const rowBottomY = headerBottomY + (index + 1) * rowSpacing;
|
|
37645
37731
|
doc.setDrawColor(200, 200, 200);
|
|
37646
37732
|
doc.line(20, rowBottomY, 190, rowBottomY);
|
|
37647
37733
|
}
|
|
37648
|
-
|
|
37734
|
+
const rangeMinutes = timeRange.minutes || 60;
|
|
37735
|
+
const targetForRange = targetOutputPerHour * (rangeMinutes / 60);
|
|
37736
|
+
const targetStr = rangeMinutes === 60 ? targetOutputPerHour.toString() : targetForRange.toFixed(1).replace(/\.0$/, "");
|
|
37737
|
+
doc.text(timeRange.label, 25, yPos);
|
|
37649
37738
|
doc.text(outputStr, 75, yPos);
|
|
37650
37739
|
doc.text(targetStr, 105, yPos);
|
|
37651
37740
|
if (!dataCollected) {
|
|
37652
37741
|
doc.setTextColor(100, 100, 100);
|
|
37653
37742
|
doc.text("-", 135, yPos);
|
|
37654
|
-
} else if (actualOutput >=
|
|
37743
|
+
} else if (actualOutput >= targetForRange) {
|
|
37655
37744
|
doc.setTextColor(0, 171, 69);
|
|
37656
37745
|
doc.setFont("ZapfDingbats", "normal");
|
|
37657
37746
|
doc.text("4", 135, yPos);
|
|
@@ -39062,23 +39151,29 @@ var WorkspacePdfGenerator = ({ workspace, className, idleTimeReasons }) => {
|
|
|
39062
39151
|
const colBoundaries = [20, 70, 100, 130, 155, 190];
|
|
39063
39152
|
const totalRows = hourlyData.length;
|
|
39064
39153
|
const gridBottomY = headerBottomY + totalRows * rowHeight;
|
|
39154
|
+
const tableHeight = gridBottomY - gridTopY;
|
|
39155
|
+
doc.setFillColor(255, 255, 255);
|
|
39156
|
+
doc.roundedRect(20, gridTopY, 170, tableHeight, 2, 2, "F");
|
|
39157
|
+
doc.setDrawColor(230, 230, 230);
|
|
39158
|
+
doc.setLineWidth(0.2);
|
|
39159
|
+
doc.roundedRect(20, gridTopY, 170, tableHeight, 2, 2, "S");
|
|
39065
39160
|
doc.setDrawColor(200, 200, 200);
|
|
39066
39161
|
doc.setLineWidth(0.3);
|
|
39067
|
-
doc.line(20, gridTopY, 190, gridTopY);
|
|
39068
39162
|
doc.line(20, headerBottomY, 190, headerBottomY);
|
|
39069
|
-
colBoundaries.forEach((x) => {
|
|
39163
|
+
colBoundaries.slice(1, -1).forEach((x) => {
|
|
39070
39164
|
doc.line(x, gridTopY, x, gridBottomY);
|
|
39071
39165
|
});
|
|
39072
39166
|
doc.setFontSize(headerFontSize);
|
|
39073
39167
|
doc.setFont("helvetica", "bold");
|
|
39074
|
-
|
|
39075
|
-
doc.text("
|
|
39076
|
-
doc.text("
|
|
39077
|
-
doc.text("
|
|
39078
|
-
doc.text("
|
|
39168
|
+
const headerTextY = gridTopY + 5.5;
|
|
39169
|
+
doc.text("Time Range", 25, headerTextY);
|
|
39170
|
+
doc.text("Output", 75, headerTextY);
|
|
39171
|
+
doc.text("Target", 105, headerTextY);
|
|
39172
|
+
doc.text("Status", 135, headerTextY);
|
|
39173
|
+
doc.text("Remarks", 160, headerTextY);
|
|
39079
39174
|
doc.setFontSize(contentFontSize);
|
|
39080
39175
|
doc.setFont("helvetica", "normal");
|
|
39081
|
-
let yPos =
|
|
39176
|
+
let yPos = headerBottomY + 5.5;
|
|
39082
39177
|
const workspaceDate = new Date(workspace.date);
|
|
39083
39178
|
const today = /* @__PURE__ */ new Date();
|
|
39084
39179
|
today.setHours(0, 0, 0, 0);
|
|
@@ -39106,9 +39201,11 @@ var WorkspacePdfGenerator = ({ workspace, className, idleTimeReasons }) => {
|
|
|
39106
39201
|
const dataCollected = !isToday2 || hourNumber < currentHour;
|
|
39107
39202
|
const outputStr = dataCollected ? output.toString() : "TBD";
|
|
39108
39203
|
const targetStr = hourlyTarget.toString();
|
|
39109
|
-
|
|
39110
|
-
|
|
39111
|
-
|
|
39204
|
+
if (index < totalRows - 1) {
|
|
39205
|
+
const rowBottomY = headerBottomY + (index + 1) * rowHeight;
|
|
39206
|
+
doc.setDrawColor(200, 200, 200);
|
|
39207
|
+
doc.line(20, rowBottomY, 190, rowBottomY);
|
|
39208
|
+
}
|
|
39112
39209
|
doc.text(timeRange, 25, yPos);
|
|
39113
39210
|
doc.text(outputStr, 75, yPos);
|
|
39114
39211
|
doc.text(targetStr, 105, yPos);
|
|
@@ -57984,6 +58081,8 @@ var ClipVideoCarousel = ({ clips, clipsService }) => {
|
|
|
57984
58081
|
const [videos, setVideos] = useState([]);
|
|
57985
58082
|
const [loading, setLoading] = useState(false);
|
|
57986
58083
|
const [error, setError] = useState(null);
|
|
58084
|
+
const currentVideo = videos[currentIndex];
|
|
58085
|
+
const { crop: workspaceCrop } = useWorkspaceCrop(currentVideo?.workspace_id || null);
|
|
57987
58086
|
useEffect(() => {
|
|
57988
58087
|
let cancelled = false;
|
|
57989
58088
|
const load = async () => {
|
|
@@ -58003,7 +58102,8 @@ var ClipVideoCarousel = ({ clips, clipsService }) => {
|
|
|
58003
58102
|
const cycleTime = typeof c.cycle_time_seconds === "number" ? c.cycle_time_seconds : typeof c.cycle_sec === "number" ? c.cycle_sec : void 0;
|
|
58004
58103
|
return {
|
|
58005
58104
|
...video,
|
|
58006
|
-
cycle_time_seconds: cycleTime ?? video.cycle_time_seconds
|
|
58105
|
+
cycle_time_seconds: cycleTime ?? video.cycle_time_seconds,
|
|
58106
|
+
workspace_id: c.workspace_id
|
|
58007
58107
|
};
|
|
58008
58108
|
})
|
|
58009
58109
|
);
|
|
@@ -58034,17 +58134,17 @@ var ClipVideoCarousel = ({ clips, clipsService }) => {
|
|
|
58034
58134
|
setCurrentIndex((prev) => (prev - 1 + Math.max(videos.length, 1)) % Math.max(videos.length, 1));
|
|
58035
58135
|
};
|
|
58036
58136
|
if (!clips || clips.length === 0) return null;
|
|
58037
|
-
const currentVideo = videos[currentIndex];
|
|
58038
58137
|
return /* @__PURE__ */ jsxs("div", { className: "relative group bg-gray-900 rounded-lg overflow-hidden aspect-video", children: [
|
|
58039
58138
|
loading && /* @__PURE__ */ jsx("div", { className: "absolute inset-0 flex items-center justify-center text-sm text-white/80", children: "Loading clips\u2026" }),
|
|
58040
58139
|
!loading && error && /* @__PURE__ */ jsx("div", { className: "absolute inset-0 flex items-center justify-center text-sm text-white/80", children: error }),
|
|
58041
58140
|
!loading && !error && currentVideo?.src && /* @__PURE__ */ jsx(
|
|
58042
|
-
|
|
58141
|
+
CroppedVideoPlayer,
|
|
58043
58142
|
{
|
|
58044
58143
|
src: currentVideo.src,
|
|
58045
58144
|
className: "w-full h-full object-cover opacity-90 group-hover:opacity-100 transition-opacity",
|
|
58046
58145
|
controls: true,
|
|
58047
|
-
playsInline: true
|
|
58146
|
+
playsInline: true,
|
|
58147
|
+
crop: workspaceCrop?.crop || null
|
|
58048
58148
|
},
|
|
58049
58149
|
currentVideo.src
|
|
58050
58150
|
),
|