@optifye/dashboard-core 6.9.9 → 6.9.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.css +59 -4
- package/dist/index.js +903 -313
- package/dist/index.mjs +903 -313
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2925,8 +2925,8 @@ var AuthService = class {
|
|
|
2925
2925
|
"Authorization": `Bearer ${accessToken}`,
|
|
2926
2926
|
"Content-Type": "application/json"
|
|
2927
2927
|
},
|
|
2928
|
-
timeout:
|
|
2929
|
-
//
|
|
2928
|
+
timeout: 1e4,
|
|
2929
|
+
// 10 seconds
|
|
2930
2930
|
retries: 1,
|
|
2931
2931
|
silentErrors: false
|
|
2932
2932
|
// We want to know about auth errors
|
|
@@ -2963,8 +2963,8 @@ var AuthService = class {
|
|
|
2963
2963
|
"Authorization": `Bearer ${accessToken}`,
|
|
2964
2964
|
"Content-Type": "application/json"
|
|
2965
2965
|
},
|
|
2966
|
-
timeout:
|
|
2967
|
-
//
|
|
2966
|
+
timeout: 1e4,
|
|
2967
|
+
// 10 seconds
|
|
2968
2968
|
retries: 2,
|
|
2969
2969
|
// More retries for validation
|
|
2970
2970
|
silentErrors: true,
|
|
@@ -2996,8 +2996,8 @@ var AuthService = class {
|
|
|
2996
2996
|
"Authorization": `Bearer ${accessToken}`,
|
|
2997
2997
|
"Content-Type": "application/json"
|
|
2998
2998
|
},
|
|
2999
|
-
timeout:
|
|
3000
|
-
//
|
|
2999
|
+
timeout: 1e4,
|
|
3000
|
+
// 10 seconds
|
|
3001
3001
|
retries: 1,
|
|
3002
3002
|
silentErrors: false
|
|
3003
3003
|
}
|
|
@@ -10912,7 +10912,7 @@ function useDateFormatter() {
|
|
|
10912
10912
|
},
|
|
10913
10913
|
[defaultTimezone, defaultLocale, dateFormatOptions]
|
|
10914
10914
|
);
|
|
10915
|
-
const
|
|
10915
|
+
const formatTime4 = React23.useCallback(
|
|
10916
10916
|
(date, formatString) => {
|
|
10917
10917
|
const dateObj = typeof date === "string" ? dateFns.parseISO(date) : date;
|
|
10918
10918
|
if (!dateFns.isValid(dateObj)) return "Invalid Time";
|
|
@@ -10943,7 +10943,7 @@ function useDateFormatter() {
|
|
|
10943
10943
|
}, []);
|
|
10944
10944
|
return {
|
|
10945
10945
|
formatDate,
|
|
10946
|
-
formatTime:
|
|
10946
|
+
formatTime: formatTime4,
|
|
10947
10947
|
formatDateTime,
|
|
10948
10948
|
getNow,
|
|
10949
10949
|
timezone: defaultTimezone || "UTC",
|
|
@@ -23099,7 +23099,7 @@ var OutputProgressChartComponent = ({
|
|
|
23099
23099
|
];
|
|
23100
23100
|
const COLORS = ["#00AB45", "#f3f4f6"];
|
|
23101
23101
|
const percentage = (currentOutput / targetOutput * 100).toFixed(1);
|
|
23102
|
-
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: `w-full h-full flex items-center justify-center ${className}`, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative w-full aspect-square max-h-full", style: { maxWidth: "min(100%, 280px)" }, children: [
|
|
23102
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: `w-full h-full flex items-center justify-center ${className}`, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative w-full aspect-square max-h-full", style: { maxWidth: "min(100%, 280px)", containerType: "inline-size" }, children: [
|
|
23103
23103
|
/* @__PURE__ */ jsxRuntime.jsx(recharts.ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxRuntime.jsx(recharts.PieChart, { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
23104
23104
|
recharts.Pie,
|
|
23105
23105
|
{
|
|
@@ -23123,16 +23123,33 @@ var OutputProgressChartComponent = ({
|
|
|
23123
23123
|
))
|
|
23124
23124
|
}
|
|
23125
23125
|
) }) }),
|
|
23126
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 flex flex-col items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center", children: [
|
|
23127
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
23128
|
-
|
|
23129
|
-
|
|
23130
|
-
|
|
23131
|
-
|
|
23132
|
-
|
|
23133
|
-
|
|
23134
|
-
|
|
23135
|
-
|
|
23126
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 flex flex-col items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center", style: { width: "100%", padding: "0 10%" }, children: [
|
|
23127
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
23128
|
+
"div",
|
|
23129
|
+
{
|
|
23130
|
+
className: "font-bold text-gray-800",
|
|
23131
|
+
style: { fontSize: "clamp(1.25rem, 8cqw, 2.5rem)" },
|
|
23132
|
+
children: [
|
|
23133
|
+
percentage,
|
|
23134
|
+
"%"
|
|
23135
|
+
]
|
|
23136
|
+
}
|
|
23137
|
+
),
|
|
23138
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
23139
|
+
"div",
|
|
23140
|
+
{
|
|
23141
|
+
className: "text-gray-500",
|
|
23142
|
+
style: {
|
|
23143
|
+
fontSize: "clamp(0.7rem, 3.5cqw, 1rem)",
|
|
23144
|
+
marginTop: "clamp(0.125rem, 1cqw, 0.5rem)"
|
|
23145
|
+
},
|
|
23146
|
+
children: [
|
|
23147
|
+
currentOutput,
|
|
23148
|
+
" / ",
|
|
23149
|
+
Math.round(targetOutput)
|
|
23150
|
+
]
|
|
23151
|
+
}
|
|
23152
|
+
)
|
|
23136
23153
|
] }) })
|
|
23137
23154
|
] }) });
|
|
23138
23155
|
};
|
|
@@ -23150,7 +23167,7 @@ var LargeOutputProgressChart = ({
|
|
|
23150
23167
|
];
|
|
23151
23168
|
const COLORS = ["#00AB45", "#f3f4f6"];
|
|
23152
23169
|
const percentage = (currentOutput / targetOutput * 100).toFixed(1);
|
|
23153
|
-
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: `w-full h-full flex items-center justify-center ${className}`, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative w-full h-full", style: { minHeight: "100px", minWidth: "100px" }, children: [
|
|
23170
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: `w-full h-full flex items-center justify-center ${className}`, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative w-full h-full", style: { minHeight: "100px", minWidth: "100px", containerType: "inline-size" }, children: [
|
|
23154
23171
|
/* @__PURE__ */ jsxRuntime.jsx(recharts.ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxRuntime.jsx(recharts.PieChart, { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
23155
23172
|
recharts.Pie,
|
|
23156
23173
|
{
|
|
@@ -23174,16 +23191,40 @@ var LargeOutputProgressChart = ({
|
|
|
23174
23191
|
))
|
|
23175
23192
|
}
|
|
23176
23193
|
) }) }),
|
|
23177
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 flex flex-col items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center", children: [
|
|
23178
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
23179
|
-
|
|
23180
|
-
|
|
23181
|
-
|
|
23182
|
-
|
|
23183
|
-
|
|
23184
|
-
|
|
23185
|
-
|
|
23186
|
-
|
|
23194
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 flex flex-col items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center", style: { width: "100%", padding: "0 10%" }, children: [
|
|
23195
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
23196
|
+
"div",
|
|
23197
|
+
{
|
|
23198
|
+
className: "font-bold text-gray-900",
|
|
23199
|
+
style: { fontSize: "clamp(1.5rem, 10cqw, 3rem)" },
|
|
23200
|
+
children: currentOutput
|
|
23201
|
+
}
|
|
23202
|
+
),
|
|
23203
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
23204
|
+
"div",
|
|
23205
|
+
{
|
|
23206
|
+
className: "text-gray-500",
|
|
23207
|
+
style: { fontSize: "clamp(0.75rem, 3.5cqw, 1rem)" },
|
|
23208
|
+
children: [
|
|
23209
|
+
"of ",
|
|
23210
|
+
targetOutput
|
|
23211
|
+
]
|
|
23212
|
+
}
|
|
23213
|
+
),
|
|
23214
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
23215
|
+
"div",
|
|
23216
|
+
{
|
|
23217
|
+
className: "font-medium text-gray-600",
|
|
23218
|
+
style: {
|
|
23219
|
+
fontSize: "clamp(0.875rem, 4.5cqw, 1.25rem)",
|
|
23220
|
+
marginTop: "clamp(0.125rem, 1cqw, 0.5rem)"
|
|
23221
|
+
},
|
|
23222
|
+
children: [
|
|
23223
|
+
percentage,
|
|
23224
|
+
"%"
|
|
23225
|
+
]
|
|
23226
|
+
}
|
|
23227
|
+
)
|
|
23187
23228
|
] }) })
|
|
23188
23229
|
] }) });
|
|
23189
23230
|
};
|
|
@@ -23888,7 +23929,7 @@ var HourlyOutputChartComponent = ({
|
|
|
23888
23929
|
endHour = Math.floor(endDecimalHour) % 24;
|
|
23889
23930
|
endMinute = Math.round(endDecimalHour % 1 * 60);
|
|
23890
23931
|
}
|
|
23891
|
-
const
|
|
23932
|
+
const formatTime4 = (h, m) => {
|
|
23892
23933
|
const period = h >= 12 ? "PM" : "AM";
|
|
23893
23934
|
const hour12 = h === 0 ? 12 : h > 12 ? h - 12 : h;
|
|
23894
23935
|
if (m === 0) {
|
|
@@ -23896,7 +23937,7 @@ var HourlyOutputChartComponent = ({
|
|
|
23896
23937
|
}
|
|
23897
23938
|
return `${hour12}:${m.toString().padStart(2, "0")}${period}`;
|
|
23898
23939
|
};
|
|
23899
|
-
return `${
|
|
23940
|
+
return `${formatTime4(startHour, startMinute)}-${formatTime4(endHour, endMinute)}`;
|
|
23900
23941
|
}, [shiftStartTime.decimalHour, SHIFT_DURATION, shiftEndTime]);
|
|
23901
23942
|
const formatTimeRange = React23__namespace.default.useCallback((hourIndex) => {
|
|
23902
23943
|
const isLastHour = hourIndex === SHIFT_DURATION - 1;
|
|
@@ -23912,12 +23953,12 @@ var HourlyOutputChartComponent = ({
|
|
|
23912
23953
|
endHour = Math.floor(endDecimalHour) % 24;
|
|
23913
23954
|
endMinute = Math.round(endDecimalHour % 1 * 60);
|
|
23914
23955
|
}
|
|
23915
|
-
const
|
|
23956
|
+
const formatTime4 = (h, m) => {
|
|
23916
23957
|
const period = h >= 12 ? "PM" : "AM";
|
|
23917
23958
|
const hour12 = h === 0 ? 12 : h > 12 ? h - 12 : h;
|
|
23918
23959
|
return `${hour12}:${m.toString().padStart(2, "0")} ${period}`;
|
|
23919
23960
|
};
|
|
23920
|
-
return `${
|
|
23961
|
+
return `${formatTime4(startHour, startMinute)} - ${formatTime4(endHour, endMinute)}`;
|
|
23921
23962
|
}, [shiftStartTime.decimalHour, SHIFT_DURATION, shiftEndTime]);
|
|
23922
23963
|
const chartData = React23__namespace.default.useMemo(() => {
|
|
23923
23964
|
return Array.from({ length: SHIFT_DURATION }, (_, i) => {
|
|
@@ -25088,7 +25129,7 @@ var SOPComplianceChart = ({
|
|
|
25088
25129
|
}
|
|
25089
25130
|
};
|
|
25090
25131
|
}, [data, animateToNewData, mockData]);
|
|
25091
|
-
const
|
|
25132
|
+
const formatTime4 = (minuteIndex) => {
|
|
25092
25133
|
const totalMinutes = shiftStartHour * 60 + minuteIndex;
|
|
25093
25134
|
const hours = Math.floor(totalMinutes / 60) % 24;
|
|
25094
25135
|
const minutes = totalMinutes % 60;
|
|
@@ -25100,7 +25141,7 @@ var SOPComplianceChart = ({
|
|
|
25100
25141
|
const hasDataForMinute = index < animatedData.length - 10;
|
|
25101
25142
|
return {
|
|
25102
25143
|
minute: index,
|
|
25103
|
-
time:
|
|
25144
|
+
time: formatTime4(index),
|
|
25104
25145
|
compliance: hasDataForMinute ? animatedData[index] : null
|
|
25105
25146
|
};
|
|
25106
25147
|
});
|
|
@@ -25277,7 +25318,7 @@ var GaugeChart = ({
|
|
|
25277
25318
|
};
|
|
25278
25319
|
const gaugeColor = getColor();
|
|
25279
25320
|
const targetAngle = target !== void 0 ? 180 - (target - min) / (max - min) * 180 : null;
|
|
25280
|
-
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: `relative w-full h-full flex flex-col items-center justify-center ${className}`, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative w-full max-w-[280px] aspect-square", style: { minHeight: "100px", minWidth: "100px" }, children: [
|
|
25321
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: `relative w-full h-full flex flex-col items-center justify-center ${className}`, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative w-full max-w-[280px] aspect-square", style: { minHeight: "100px", minWidth: "100px", containerType: "inline-size" }, children: [
|
|
25281
25322
|
/* @__PURE__ */ jsxRuntime.jsx(recharts.ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxRuntime.jsx(recharts.PieChart, { children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
25282
25323
|
recharts.Pie,
|
|
25283
25324
|
{
|
|
@@ -25310,17 +25351,44 @@ var GaugeChart = ({
|
|
|
25310
25351
|
children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute -top-1 -left-1.5 w-3 h-3 bg-gray-800 rounded-full" })
|
|
25311
25352
|
}
|
|
25312
25353
|
),
|
|
25313
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 flex flex-col items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center", children: [
|
|
25314
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
25315
|
-
|
|
25316
|
-
|
|
25317
|
-
|
|
25318
|
-
|
|
25319
|
-
|
|
25320
|
-
|
|
25321
|
-
|
|
25322
|
-
|
|
25323
|
-
|
|
25354
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 flex flex-col items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center", style: { width: "100%", padding: "0 10%" }, children: [
|
|
25355
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
25356
|
+
"div",
|
|
25357
|
+
{
|
|
25358
|
+
className: "font-bold text-gray-800",
|
|
25359
|
+
style: { fontSize: "clamp(1.25rem, 8cqw, 2rem)" },
|
|
25360
|
+
children: [
|
|
25361
|
+
value.toFixed(unit === "%" ? 1 : 0),
|
|
25362
|
+
unit
|
|
25363
|
+
]
|
|
25364
|
+
}
|
|
25365
|
+
),
|
|
25366
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
25367
|
+
"div",
|
|
25368
|
+
{
|
|
25369
|
+
className: "text-gray-600 font-medium",
|
|
25370
|
+
style: {
|
|
25371
|
+
fontSize: "clamp(0.75rem, 3.5cqw, 1rem)",
|
|
25372
|
+
marginTop: "clamp(0.125rem, 1cqw, 0.25rem)"
|
|
25373
|
+
},
|
|
25374
|
+
children: label
|
|
25375
|
+
}
|
|
25376
|
+
),
|
|
25377
|
+
target !== void 0 && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
25378
|
+
"div",
|
|
25379
|
+
{
|
|
25380
|
+
className: "text-gray-500",
|
|
25381
|
+
style: {
|
|
25382
|
+
fontSize: "clamp(0.7rem, 3cqw, 0.875rem)",
|
|
25383
|
+
marginTop: "clamp(0.125rem, 1cqw, 0.25rem)"
|
|
25384
|
+
},
|
|
25385
|
+
children: [
|
|
25386
|
+
"Target: ",
|
|
25387
|
+
target,
|
|
25388
|
+
unit
|
|
25389
|
+
]
|
|
25390
|
+
}
|
|
25391
|
+
)
|
|
25324
25392
|
] }) }),
|
|
25325
25393
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute bottom-[15%] left-[15%] text-xs text-gray-500", children: [
|
|
25326
25394
|
min,
|
|
@@ -25507,7 +25575,7 @@ var DateTimeDisplay = ({
|
|
|
25507
25575
|
const {
|
|
25508
25576
|
defaultTimezone
|
|
25509
25577
|
} = useDateTimeConfig();
|
|
25510
|
-
const { formatDate, formatTime:
|
|
25578
|
+
const { formatDate, formatTime: formatTime4 } = useDateFormatter();
|
|
25511
25579
|
const [now2, setNow] = React23.useState(() => getCurrentTimeInZone(defaultTimezone || "UTC"));
|
|
25512
25580
|
React23.useEffect(() => {
|
|
25513
25581
|
const timerId = setInterval(() => {
|
|
@@ -25519,7 +25587,7 @@ var DateTimeDisplay = ({
|
|
|
25519
25587
|
return null;
|
|
25520
25588
|
}
|
|
25521
25589
|
const formattedDate = showDate ? formatDate(now2) : "";
|
|
25522
|
-
const formattedTime = showTime ?
|
|
25590
|
+
const formattedTime = showTime ? formatTime4(now2) : "";
|
|
25523
25591
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: clsx_default("flex items-center space-x-2 text-sm text-gray-700 dark:text-gray-300", className), children: [
|
|
25524
25592
|
showDate && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "date-display", "aria-label": `Current date: ${formattedDate}`, children: formattedDate }),
|
|
25525
25593
|
showDate && showTime && formattedDate && formattedTime && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "separator", "aria-hidden": "true", children: "|" }),
|
|
@@ -25683,7 +25751,7 @@ var BreakNotificationPopup = ({
|
|
|
25683
25751
|
const handlePrevious = () => {
|
|
25684
25752
|
setCurrentIndex((prev) => (prev - 1 + visibleBreaks.length) % visibleBreaks.length);
|
|
25685
25753
|
};
|
|
25686
|
-
const
|
|
25754
|
+
const formatTime4 = (minutes) => {
|
|
25687
25755
|
const hours = Math.floor(minutes / 60);
|
|
25688
25756
|
const mins = minutes % 60;
|
|
25689
25757
|
if (hours > 0) {
|
|
@@ -25757,9 +25825,9 @@ var BreakNotificationPopup = ({
|
|
|
25757
25825
|
formatTo12Hour(currentBreak.endTime)
|
|
25758
25826
|
] }),
|
|
25759
25827
|
/* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-xs text-gray-500 mb-2", children: [
|
|
25760
|
-
|
|
25828
|
+
formatTime4(currentBreak.elapsedMinutes),
|
|
25761
25829
|
" elapsed of ",
|
|
25762
|
-
|
|
25830
|
+
formatTime4(currentBreak.duration),
|
|
25763
25831
|
" total"
|
|
25764
25832
|
] }),
|
|
25765
25833
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full bg-gray-200 rounded-full h-1.5", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -26063,64 +26131,208 @@ var getSeverityColor = (severity) => {
|
|
|
26063
26131
|
return "bg-gray-500";
|
|
26064
26132
|
}
|
|
26065
26133
|
};
|
|
26066
|
-
var
|
|
26067
|
-
|
|
26134
|
+
var formatTime2 = (seconds) => {
|
|
26135
|
+
if (!seconds || isNaN(seconds)) return "0:00";
|
|
26136
|
+
const h = Math.floor(seconds / 3600);
|
|
26137
|
+
const m = Math.floor(seconds % 3600 / 60);
|
|
26138
|
+
const s = Math.floor(seconds % 60);
|
|
26139
|
+
if (h > 0) {
|
|
26140
|
+
return `${h}:${m.toString().padStart(2, "0")}:${s.toString().padStart(2, "0")}`;
|
|
26141
|
+
}
|
|
26142
|
+
return `${m}:${s.toString().padStart(2, "0")}`;
|
|
26143
|
+
};
|
|
26144
|
+
var VideoControls = ({
|
|
26068
26145
|
isPlaying,
|
|
26069
|
-
|
|
26146
|
+
currentTime,
|
|
26147
|
+
duration,
|
|
26148
|
+
buffered,
|
|
26149
|
+
showControls,
|
|
26150
|
+
controlsPinned = false,
|
|
26151
|
+
onTogglePinControls,
|
|
26152
|
+
playbackRate = 1,
|
|
26153
|
+
onPlayPause,
|
|
26154
|
+
onSeek,
|
|
26155
|
+
onSeekStart,
|
|
26156
|
+
onSeekEnd,
|
|
26157
|
+
onToggleFullscreen,
|
|
26158
|
+
onPlaybackRateChange,
|
|
26159
|
+
className = ""
|
|
26070
26160
|
}) => {
|
|
26071
|
-
const [
|
|
26072
|
-
const [
|
|
26161
|
+
const [isDragging, setIsDragging] = React23.useState(false);
|
|
26162
|
+
const [dragTime, setDragTime] = React23.useState(0);
|
|
26163
|
+
const [isHoveringProgressBar, setIsHoveringProgressBar] = React23.useState(false);
|
|
26164
|
+
const [showSpeedMenu, setShowSpeedMenu] = React23.useState(false);
|
|
26165
|
+
const speedMenuRef = React23.useRef(null);
|
|
26166
|
+
const progressColor = "#4b5563";
|
|
26167
|
+
const controlsVisible = showControls || controlsPinned;
|
|
26168
|
+
const getPercentage = (current, total) => {
|
|
26169
|
+
if (!total || total === 0) return 0;
|
|
26170
|
+
return Math.min(Math.max(current / total * 100, 0), 100);
|
|
26171
|
+
};
|
|
26172
|
+
const handleSeekChange = (e) => {
|
|
26173
|
+
const newTime = parseFloat(e.target.value);
|
|
26174
|
+
setDragTime(newTime);
|
|
26175
|
+
onSeek(newTime);
|
|
26176
|
+
};
|
|
26177
|
+
const handleSeekStart = () => {
|
|
26178
|
+
setIsDragging(true);
|
|
26179
|
+
setDragTime(currentTime);
|
|
26180
|
+
onSeekStart?.();
|
|
26181
|
+
};
|
|
26182
|
+
const handleSeekEnd = () => {
|
|
26183
|
+
setIsDragging(false);
|
|
26184
|
+
onSeekEnd?.();
|
|
26185
|
+
};
|
|
26073
26186
|
React23.useEffect(() => {
|
|
26074
|
-
|
|
26075
|
-
|
|
26076
|
-
|
|
26077
|
-
|
|
26078
|
-
|
|
26079
|
-
|
|
26080
|
-
|
|
26081
|
-
|
|
26082
|
-
|
|
26083
|
-
|
|
26084
|
-
|
|
26085
|
-
|
|
26086
|
-
|
|
26087
|
-
|
|
26088
|
-
}
|
|
26089
|
-
}, [show, duration]);
|
|
26090
|
-
if (!isVisible) return null;
|
|
26091
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
26187
|
+
const handleClickOutside = (event) => {
|
|
26188
|
+
if (speedMenuRef.current && !speedMenuRef.current.contains(event.target)) {
|
|
26189
|
+
setShowSpeedMenu(false);
|
|
26190
|
+
}
|
|
26191
|
+
};
|
|
26192
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
26193
|
+
return () => {
|
|
26194
|
+
document.removeEventListener("mousedown", handleClickOutside);
|
|
26195
|
+
};
|
|
26196
|
+
}, []);
|
|
26197
|
+
const displayTime = isDragging ? dragTime : currentTime;
|
|
26198
|
+
const progressPercent = getPercentage(displayTime, duration);
|
|
26199
|
+
const bufferedPercent = getPercentage(buffered, duration);
|
|
26200
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
26092
26201
|
"div",
|
|
26093
26202
|
{
|
|
26094
|
-
className:
|
|
26095
|
-
style: {
|
|
26096
|
-
|
|
26097
|
-
|
|
26098
|
-
|
|
26099
|
-
children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "bg-black/70 rounded-full p-6", children: isPlaying ? (
|
|
26100
|
-
// Play icon (triangle)
|
|
26101
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
26102
|
-
"svg",
|
|
26103
|
-
{
|
|
26104
|
-
xmlns: "http://www.w3.org/2000/svg",
|
|
26105
|
-
viewBox: "0 0 24 24",
|
|
26106
|
-
fill: "white",
|
|
26107
|
-
className: "w-16 h-16",
|
|
26108
|
-
children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M8 5v14l11-7z" })
|
|
26109
|
-
}
|
|
26110
|
-
)
|
|
26111
|
-
) : (
|
|
26112
|
-
// Pause icon (two bars)
|
|
26113
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
26114
|
-
"svg",
|
|
26203
|
+
className: `absolute bottom-0 left-0 right-0 px-3 pb-3 pt-12 bg-gradient-to-t from-black/80 via-black/40 to-transparent transition-opacity duration-300 ${controlsVisible ? "opacity-100" : "opacity-0 pointer-events-none"} ${className}`,
|
|
26204
|
+
style: { touchAction: "none" },
|
|
26205
|
+
children: [
|
|
26206
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
26207
|
+
"div",
|
|
26115
26208
|
{
|
|
26116
|
-
|
|
26117
|
-
|
|
26118
|
-
|
|
26119
|
-
|
|
26120
|
-
|
|
26209
|
+
className: "relative h-1 mb-4 group cursor-pointer",
|
|
26210
|
+
onMouseEnter: () => setIsHoveringProgressBar(true),
|
|
26211
|
+
onMouseLeave: () => setIsHoveringProgressBar(false),
|
|
26212
|
+
children: [
|
|
26213
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute -top-2 -bottom-2 left-0 right-0 z-20" }),
|
|
26214
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute top-0 left-0 right-0 bottom-0 bg-white/20 rounded-full overflow-hidden z-0", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
26215
|
+
"div",
|
|
26216
|
+
{
|
|
26217
|
+
className: "absolute top-0 left-0 bottom-0 bg-white/40 transition-all duration-200",
|
|
26218
|
+
style: { width: `${bufferedPercent}%` }
|
|
26219
|
+
}
|
|
26220
|
+
) }),
|
|
26221
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
26222
|
+
"div",
|
|
26223
|
+
{
|
|
26224
|
+
className: "absolute top-0 left-0 bottom-0 bg-[#007bff] transition-all duration-75 z-10",
|
|
26225
|
+
style: { width: `${progressPercent}%`, backgroundColor: progressColor },
|
|
26226
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
26227
|
+
"div",
|
|
26228
|
+
{
|
|
26229
|
+
className: `absolute right-0 top-1/2 -translate-y-1/2 translate-x-1/2 w-3 h-3 rounded-full shadow transform transition-transform duration-200 ${isHoveringProgressBar || isDragging ? "scale-100" : "scale-0"}`,
|
|
26230
|
+
style: { backgroundColor: progressColor }
|
|
26231
|
+
}
|
|
26232
|
+
)
|
|
26233
|
+
}
|
|
26234
|
+
),
|
|
26235
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
26236
|
+
"input",
|
|
26237
|
+
{
|
|
26238
|
+
type: "range",
|
|
26239
|
+
min: "0",
|
|
26240
|
+
max: duration || 100,
|
|
26241
|
+
step: "0.1",
|
|
26242
|
+
value: displayTime,
|
|
26243
|
+
onChange: handleSeekChange,
|
|
26244
|
+
onMouseDown: handleSeekStart,
|
|
26245
|
+
onMouseUp: handleSeekEnd,
|
|
26246
|
+
onTouchStart: handleSeekStart,
|
|
26247
|
+
onTouchEnd: handleSeekEnd,
|
|
26248
|
+
className: "absolute inset-0 w-full h-full opacity-0 cursor-pointer z-30 margin-0 padding-0"
|
|
26249
|
+
}
|
|
26250
|
+
)
|
|
26251
|
+
]
|
|
26121
26252
|
}
|
|
26122
|
-
)
|
|
26123
|
-
|
|
26253
|
+
),
|
|
26254
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between text-white", children: [
|
|
26255
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-4", children: [
|
|
26256
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
26257
|
+
"button",
|
|
26258
|
+
{
|
|
26259
|
+
onClick: (e) => {
|
|
26260
|
+
e.stopPropagation();
|
|
26261
|
+
onPlayPause();
|
|
26262
|
+
},
|
|
26263
|
+
className: "hover:text-[#007bff] transition-colors focus:outline-none",
|
|
26264
|
+
"aria-label": isPlaying ? "Pause" : "Play",
|
|
26265
|
+
children: isPlaying ? /* @__PURE__ */ jsxRuntime.jsx("svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M6 4h4v16H6V4zm8 0h4v16h-4V4z" }) }) : /* @__PURE__ */ jsxRuntime.jsx("svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M8 5v14l11-7z" }) })
|
|
26266
|
+
}
|
|
26267
|
+
),
|
|
26268
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-xs font-medium font-sans", children: [
|
|
26269
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: formatTime2(displayTime) }),
|
|
26270
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "mx-1 text-white/70", children: "/" }),
|
|
26271
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-white/70", children: formatTime2(duration) })
|
|
26272
|
+
] })
|
|
26273
|
+
] }),
|
|
26274
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-4", children: [
|
|
26275
|
+
onTogglePinControls && /* @__PURE__ */ jsxRuntime.jsx(
|
|
26276
|
+
"button",
|
|
26277
|
+
{
|
|
26278
|
+
onClick: (e) => {
|
|
26279
|
+
e.stopPropagation();
|
|
26280
|
+
onTogglePinControls();
|
|
26281
|
+
},
|
|
26282
|
+
className: `transition-colors focus:outline-none ${controlsPinned ? "text-[#007bff]" : "hover:text-[#007bff]"}`,
|
|
26283
|
+
"aria-label": controlsPinned ? "Unpin controls" : "Pin controls",
|
|
26284
|
+
title: controlsPinned ? "Unpin controls" : "Pin controls",
|
|
26285
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24", fill: "currentColor", children: controlsPinned ? /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M9 3h6l-1 7h3v2h-4.5l-.5 4.5-2 1L10 12H6v-2h3z" }) : /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M9 3h6l-1 7h3v2h-4v5l-2 1-1-6H6v-2h3z" }) })
|
|
26286
|
+
}
|
|
26287
|
+
),
|
|
26288
|
+
onPlaybackRateChange && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", ref: speedMenuRef, children: [
|
|
26289
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
26290
|
+
"button",
|
|
26291
|
+
{
|
|
26292
|
+
onClick: (e) => {
|
|
26293
|
+
e.stopPropagation();
|
|
26294
|
+
setShowSpeedMenu(!showSpeedMenu);
|
|
26295
|
+
},
|
|
26296
|
+
className: "text-xs font-medium hover:text-[#007bff] transition-colors focus:outline-none min-w-[32px]",
|
|
26297
|
+
"aria-label": "Playback Speed",
|
|
26298
|
+
children: [
|
|
26299
|
+
playbackRate,
|
|
26300
|
+
"x"
|
|
26301
|
+
]
|
|
26302
|
+
}
|
|
26303
|
+
),
|
|
26304
|
+
showSpeedMenu && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute bottom-full right-0 mb-2 bg-black/90 text-white rounded shadow-lg overflow-hidden z-50 min-w-[80px]", children: [0.5, 1, 1.5, 2, 2.5, 3, 4, 5].map((rate) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
26305
|
+
"button",
|
|
26306
|
+
{
|
|
26307
|
+
onClick: (e) => {
|
|
26308
|
+
e.stopPropagation();
|
|
26309
|
+
onPlaybackRateChange(rate);
|
|
26310
|
+
setShowSpeedMenu(false);
|
|
26311
|
+
},
|
|
26312
|
+
className: `block w-full text-left px-4 py-2 text-xs hover:bg-white/20 transition-colors ${playbackRate === rate ? "text-[#007bff] font-bold" : ""}`,
|
|
26313
|
+
children: [
|
|
26314
|
+
rate,
|
|
26315
|
+
"x"
|
|
26316
|
+
]
|
|
26317
|
+
},
|
|
26318
|
+
rate
|
|
26319
|
+
)) })
|
|
26320
|
+
] }),
|
|
26321
|
+
onToggleFullscreen && /* @__PURE__ */ jsxRuntime.jsx(
|
|
26322
|
+
"button",
|
|
26323
|
+
{
|
|
26324
|
+
onClick: (e) => {
|
|
26325
|
+
e.stopPropagation();
|
|
26326
|
+
onToggleFullscreen();
|
|
26327
|
+
},
|
|
26328
|
+
className: "hover:text-[#007bff] transition-colors focus:outline-none",
|
|
26329
|
+
"aria-label": "Toggle Fullscreen",
|
|
26330
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M7 14H5v5h5v-2H7v-3zm-2-4h2V7h3V5H5v5zm12 7h-3v2h5v-5h-2v3zM14 5v2h3v3h2V5h-5z" }) })
|
|
26331
|
+
}
|
|
26332
|
+
)
|
|
26333
|
+
] })
|
|
26334
|
+
] })
|
|
26335
|
+
]
|
|
26124
26336
|
}
|
|
26125
26337
|
);
|
|
26126
26338
|
};
|
|
@@ -26248,9 +26460,15 @@ var HlsVideoPlayer = React23.forwardRef(({
|
|
|
26248
26460
|
const blobUrlRef = React23.useRef(null);
|
|
26249
26461
|
const [isReady, setIsReady] = React23.useState(false);
|
|
26250
26462
|
const [isLoading, setIsLoading] = React23.useState(true);
|
|
26251
|
-
const [
|
|
26252
|
-
const [
|
|
26253
|
-
const
|
|
26463
|
+
const [showControls, setShowControls] = React23.useState(true);
|
|
26464
|
+
const [controlsPinned, setControlsPinned] = React23.useState(false);
|
|
26465
|
+
const [isPlaying, setIsPlaying] = React23.useState(false);
|
|
26466
|
+
const [currentTime, setCurrentTime] = React23.useState(0);
|
|
26467
|
+
const [duration, setDuration] = React23.useState(0);
|
|
26468
|
+
const [buffered, setBuffered] = React23.useState(0);
|
|
26469
|
+
const [playbackRate, setPlaybackRate] = React23.useState(1);
|
|
26470
|
+
const userSeekingRef = React23.useRef(false);
|
|
26471
|
+
const controlsTimeoutRef = React23.useRef(null);
|
|
26254
26472
|
const eventCallbacksRef = React23.useRef({
|
|
26255
26473
|
onReady,
|
|
26256
26474
|
onPlay,
|
|
@@ -26429,8 +26647,6 @@ var HlsVideoPlayer = React23.forwardRef(({
|
|
|
26429
26647
|
}
|
|
26430
26648
|
});
|
|
26431
26649
|
hls.on(Hls3.Events.FRAG_LOADING, () => {
|
|
26432
|
-
setIsLoading(true);
|
|
26433
|
-
eventCallbacksRef.current.onLoadingChange?.(true);
|
|
26434
26650
|
});
|
|
26435
26651
|
hls.on(Hls3.Events.FRAG_LOADED, () => {
|
|
26436
26652
|
setIsLoading(false);
|
|
@@ -26484,25 +26700,52 @@ var HlsVideoPlayer = React23.forwardRef(({
|
|
|
26484
26700
|
const handleCanPlay = () => {
|
|
26485
26701
|
if (!hlsRef.current) {
|
|
26486
26702
|
setIsReady(true);
|
|
26487
|
-
onReady?.(player);
|
|
26488
26703
|
}
|
|
26704
|
+
setIsLoading(false);
|
|
26705
|
+
eventCallbacksRef.current.onLoadingChange?.(false);
|
|
26706
|
+
onReady?.(player);
|
|
26707
|
+
};
|
|
26708
|
+
const handlePlay = () => {
|
|
26709
|
+
setIsPlaying(true);
|
|
26710
|
+
eventCallbacksRef.current.onPlay?.(player);
|
|
26711
|
+
};
|
|
26712
|
+
const handlePause = () => {
|
|
26713
|
+
if (userSeekingRef.current && videoRef.current) {
|
|
26714
|
+
videoRef.current.play().catch((err) => console.warn("Auto-resume after seek pause failed:", err));
|
|
26715
|
+
return;
|
|
26716
|
+
}
|
|
26717
|
+
setIsPlaying(false);
|
|
26718
|
+
eventCallbacksRef.current.onPause?.(player);
|
|
26489
26719
|
};
|
|
26490
|
-
const handlePlay = () => eventCallbacksRef.current.onPlay?.(player);
|
|
26491
|
-
const handlePause = () => eventCallbacksRef.current.onPause?.(player);
|
|
26492
26720
|
const handlePlaying = () => {
|
|
26493
26721
|
setIsLoading(false);
|
|
26722
|
+
setIsPlaying(true);
|
|
26494
26723
|
eventCallbacksRef.current.onLoadingChange?.(false);
|
|
26495
26724
|
eventCallbacksRef.current.onPlaying?.(player);
|
|
26496
26725
|
};
|
|
26497
26726
|
const handleTimeUpdate = () => {
|
|
26498
26727
|
const currentTime2 = video.currentTime || 0;
|
|
26728
|
+
setCurrentTime(currentTime2);
|
|
26729
|
+
if (video.buffered.length > 0) {
|
|
26730
|
+
for (let i = 0; i < video.buffered.length; i++) {
|
|
26731
|
+
if (video.buffered.start(i) <= currentTime2 && video.buffered.end(i) >= currentTime2) {
|
|
26732
|
+
setBuffered(video.buffered.end(i));
|
|
26733
|
+
break;
|
|
26734
|
+
}
|
|
26735
|
+
}
|
|
26736
|
+
}
|
|
26499
26737
|
eventCallbacksRef.current.onTimeUpdate?.(player, currentTime2);
|
|
26500
26738
|
};
|
|
26501
26739
|
const handleDurationChange = () => {
|
|
26502
26740
|
const duration2 = video.duration || 0;
|
|
26741
|
+
setDuration(duration2);
|
|
26503
26742
|
eventCallbacksRef.current.onDurationChange?.(player, duration2);
|
|
26504
26743
|
};
|
|
26505
|
-
const handleEnded = () =>
|
|
26744
|
+
const handleEnded = () => {
|
|
26745
|
+
setIsPlaying(false);
|
|
26746
|
+
userSeekingRef.current = false;
|
|
26747
|
+
eventCallbacksRef.current.onEnded?.(player);
|
|
26748
|
+
};
|
|
26506
26749
|
const handleLoadStart = () => {
|
|
26507
26750
|
setIsLoading(true);
|
|
26508
26751
|
eventCallbacksRef.current.onLoadingChange?.(true);
|
|
@@ -26518,8 +26761,19 @@ var HlsVideoPlayer = React23.forwardRef(({
|
|
|
26518
26761
|
setIsLoading(true);
|
|
26519
26762
|
eventCallbacksRef.current.onLoadingChange?.(true);
|
|
26520
26763
|
};
|
|
26521
|
-
const handleSeeking = () =>
|
|
26522
|
-
|
|
26764
|
+
const handleSeeking = () => {
|
|
26765
|
+
userSeekingRef.current = true;
|
|
26766
|
+
eventCallbacksRef.current.onSeeking?.(player);
|
|
26767
|
+
};
|
|
26768
|
+
const handleSeeked = () => {
|
|
26769
|
+
setIsLoading(false);
|
|
26770
|
+
eventCallbacksRef.current.onLoadingChange?.(false);
|
|
26771
|
+
if (videoRef.current) {
|
|
26772
|
+
videoRef.current.play().catch((err) => console.warn("Resume playback after seek failed:", err));
|
|
26773
|
+
}
|
|
26774
|
+
userSeekingRef.current = false;
|
|
26775
|
+
eventCallbacksRef.current.onSeeked?.(player);
|
|
26776
|
+
};
|
|
26523
26777
|
const handleError = () => {
|
|
26524
26778
|
const error = video.error;
|
|
26525
26779
|
if (error) {
|
|
@@ -26532,6 +26786,10 @@ var HlsVideoPlayer = React23.forwardRef(({
|
|
|
26532
26786
|
eventCallbacksRef.current.onError?.(player, errorInfo);
|
|
26533
26787
|
}
|
|
26534
26788
|
};
|
|
26789
|
+
const handlePlaybackRateChange2 = (e) => {
|
|
26790
|
+
const target = e.target;
|
|
26791
|
+
setPlaybackRate(target.playbackRate);
|
|
26792
|
+
};
|
|
26535
26793
|
video.addEventListener("canplay", handleCanPlay);
|
|
26536
26794
|
video.addEventListener("play", handlePlay);
|
|
26537
26795
|
video.addEventListener("pause", handlePause);
|
|
@@ -26546,6 +26804,7 @@ var HlsVideoPlayer = React23.forwardRef(({
|
|
|
26546
26804
|
video.addEventListener("seeking", handleSeeking);
|
|
26547
26805
|
video.addEventListener("seeked", handleSeeked);
|
|
26548
26806
|
video.addEventListener("error", handleError);
|
|
26807
|
+
video.addEventListener("ratechange", handlePlaybackRateChange2);
|
|
26549
26808
|
return () => {
|
|
26550
26809
|
video.removeEventListener("canplay", handleCanPlay);
|
|
26551
26810
|
video.removeEventListener("play", handlePlay);
|
|
@@ -26561,6 +26820,7 @@ var HlsVideoPlayer = React23.forwardRef(({
|
|
|
26561
26820
|
video.removeEventListener("seeking", handleSeeking);
|
|
26562
26821
|
video.removeEventListener("seeked", handleSeeked);
|
|
26563
26822
|
video.removeEventListener("error", handleError);
|
|
26823
|
+
video.removeEventListener("ratechange", handlePlaybackRateChange2);
|
|
26564
26824
|
};
|
|
26565
26825
|
}, [
|
|
26566
26826
|
src,
|
|
@@ -26589,20 +26849,46 @@ var HlsVideoPlayer = React23.forwardRef(({
|
|
|
26589
26849
|
}
|
|
26590
26850
|
}
|
|
26591
26851
|
}, [autoplay]);
|
|
26852
|
+
const resetControlsTimeout = React23.useCallback(() => {
|
|
26853
|
+
if (controlsPinned) {
|
|
26854
|
+
setShowControls(true);
|
|
26855
|
+
return;
|
|
26856
|
+
}
|
|
26857
|
+
setShowControls(true);
|
|
26858
|
+
if (controlsTimeoutRef.current) {
|
|
26859
|
+
clearTimeout(controlsTimeoutRef.current);
|
|
26860
|
+
}
|
|
26861
|
+
if (isPlaying) {
|
|
26862
|
+
controlsTimeoutRef.current = setTimeout(() => {
|
|
26863
|
+
setShowControls(false);
|
|
26864
|
+
}, 3e3);
|
|
26865
|
+
}
|
|
26866
|
+
}, [isPlaying, controlsPinned]);
|
|
26867
|
+
const handleMouseMove = React23.useCallback(() => {
|
|
26868
|
+
resetControlsTimeout();
|
|
26869
|
+
}, [resetControlsTimeout]);
|
|
26870
|
+
React23.useEffect(() => {
|
|
26871
|
+
resetControlsTimeout();
|
|
26872
|
+
return () => {
|
|
26873
|
+
if (controlsTimeoutRef.current) {
|
|
26874
|
+
clearTimeout(controlsTimeoutRef.current);
|
|
26875
|
+
}
|
|
26876
|
+
};
|
|
26877
|
+
}, [isPlaying, resetControlsTimeout]);
|
|
26592
26878
|
const play = React23.useCallback(() => {
|
|
26593
26879
|
return videoRef.current?.play();
|
|
26594
26880
|
}, []);
|
|
26595
26881
|
const pause = React23.useCallback(() => {
|
|
26596
26882
|
videoRef.current?.pause();
|
|
26597
26883
|
}, []);
|
|
26598
|
-
const
|
|
26884
|
+
const currentTimeProp = React23.useCallback((time2) => {
|
|
26599
26885
|
if (time2 !== void 0 && videoRef.current) {
|
|
26600
26886
|
videoRef.current.currentTime = time2;
|
|
26601
26887
|
return time2;
|
|
26602
26888
|
}
|
|
26603
26889
|
return videoRef.current?.currentTime || 0;
|
|
26604
26890
|
}, []);
|
|
26605
|
-
const
|
|
26891
|
+
const durationProp = React23.useCallback(() => {
|
|
26606
26892
|
return videoRef.current?.duration || 0;
|
|
26607
26893
|
}, []);
|
|
26608
26894
|
const paused = React23.useCallback(() => {
|
|
@@ -26615,95 +26901,144 @@ var HlsVideoPlayer = React23.forwardRef(({
|
|
|
26615
26901
|
}
|
|
26616
26902
|
return videoRef.current?.muted ?? false;
|
|
26617
26903
|
}, []);
|
|
26618
|
-
const
|
|
26904
|
+
const volumeProp = React23.useCallback((level) => {
|
|
26619
26905
|
if (level !== void 0 && videoRef.current) {
|
|
26620
26906
|
videoRef.current.volume = level;
|
|
26621
26907
|
return level;
|
|
26622
26908
|
}
|
|
26623
26909
|
return videoRef.current?.volume ?? 1;
|
|
26624
26910
|
}, []);
|
|
26625
|
-
const
|
|
26911
|
+
const playbackRateProp = React23.useCallback((rate) => {
|
|
26626
26912
|
if (rate !== void 0 && videoRef.current) {
|
|
26627
26913
|
videoRef.current.playbackRate = rate;
|
|
26628
26914
|
return rate;
|
|
26629
26915
|
}
|
|
26630
26916
|
return videoRef.current?.playbackRate ?? 1;
|
|
26631
26917
|
}, []);
|
|
26918
|
+
const handleTogglePlay = React23.useCallback(() => {
|
|
26919
|
+
if (videoRef.current) {
|
|
26920
|
+
if (videoRef.current.paused) {
|
|
26921
|
+
videoRef.current.play();
|
|
26922
|
+
} else {
|
|
26923
|
+
videoRef.current.pause();
|
|
26924
|
+
}
|
|
26925
|
+
}
|
|
26926
|
+
}, []);
|
|
26927
|
+
const handleSeek = React23.useCallback((time2) => {
|
|
26928
|
+
if (videoRef.current) {
|
|
26929
|
+
videoRef.current.currentTime = time2;
|
|
26930
|
+
videoRef.current.play().catch((err) => console.warn("Resume playback failed during seek:", err));
|
|
26931
|
+
}
|
|
26932
|
+
}, []);
|
|
26933
|
+
const handleSeekStart = React23.useCallback(() => {
|
|
26934
|
+
userSeekingRef.current = true;
|
|
26935
|
+
}, []);
|
|
26936
|
+
const handleSeekEnd = React23.useCallback(() => {
|
|
26937
|
+
if (videoRef.current) {
|
|
26938
|
+
videoRef.current.play().catch((err) => console.warn("Resume playback failed after seek:", err));
|
|
26939
|
+
}
|
|
26940
|
+
}, []);
|
|
26941
|
+
const handlePlaybackRateChange = React23.useCallback((rate) => {
|
|
26942
|
+
if (videoRef.current) {
|
|
26943
|
+
videoRef.current.playbackRate = rate;
|
|
26944
|
+
}
|
|
26945
|
+
}, []);
|
|
26946
|
+
const handleToggleFullscreen = React23.useCallback(() => {
|
|
26947
|
+
if (videoContainerRef.current) {
|
|
26948
|
+
if (!document.fullscreenElement) {
|
|
26949
|
+
videoContainerRef.current.requestFullscreen();
|
|
26950
|
+
} else {
|
|
26951
|
+
document.exitFullscreen();
|
|
26952
|
+
}
|
|
26953
|
+
}
|
|
26954
|
+
}, []);
|
|
26632
26955
|
React23.useImperativeHandle(ref, () => ({
|
|
26633
26956
|
hls: hlsRef.current,
|
|
26634
26957
|
video: videoRef.current,
|
|
26635
26958
|
play,
|
|
26636
26959
|
pause,
|
|
26637
|
-
currentTime,
|
|
26638
|
-
duration,
|
|
26960
|
+
currentTime: currentTimeProp,
|
|
26961
|
+
duration: durationProp,
|
|
26639
26962
|
paused,
|
|
26640
26963
|
mute,
|
|
26641
|
-
volume,
|
|
26642
|
-
playbackRate,
|
|
26964
|
+
volume: volumeProp,
|
|
26965
|
+
playbackRate: playbackRateProp,
|
|
26643
26966
|
dispose,
|
|
26644
26967
|
isReady,
|
|
26645
26968
|
// For backward compatibility with Video.js API
|
|
26646
26969
|
player: playerLikeObject()
|
|
26647
|
-
}), [play, pause,
|
|
26648
|
-
const
|
|
26649
|
-
if (!onClick
|
|
26650
|
-
|
|
26651
|
-
|
|
26652
|
-
|
|
26653
|
-
|
|
26654
|
-
|
|
26655
|
-
|
|
26656
|
-
|
|
26657
|
-
|
|
26658
|
-
|
|
26659
|
-
|
|
26660
|
-
|
|
26661
|
-
|
|
26662
|
-
|
|
26663
|
-
|
|
26664
|
-
|
|
26665
|
-
|
|
26666
|
-
"video",
|
|
26970
|
+
}), [play, pause, currentTimeProp, durationProp, paused, mute, volumeProp, playbackRateProp, dispose, isReady, playerLikeObject]);
|
|
26971
|
+
const handleContainerClick = React23.useCallback(() => {
|
|
26972
|
+
if (!onClick && !controls) {
|
|
26973
|
+
handleTogglePlay();
|
|
26974
|
+
}
|
|
26975
|
+
if (onClick) {
|
|
26976
|
+
onClick();
|
|
26977
|
+
}
|
|
26978
|
+
}, [onClick, controls, handleTogglePlay]);
|
|
26979
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
26980
|
+
"div",
|
|
26981
|
+
{
|
|
26982
|
+
className: `hls-video-player-wrapper ${className} group`,
|
|
26983
|
+
style: { position: "relative", width: "100%", height: "100%" },
|
|
26984
|
+
onMouseMove: handleMouseMove,
|
|
26985
|
+
onMouseLeave: () => isPlaying && !controlsPinned && setShowControls(false),
|
|
26986
|
+
children: [
|
|
26987
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
26988
|
+
"div",
|
|
26667
26989
|
{
|
|
26668
|
-
|
|
26669
|
-
|
|
26670
|
-
|
|
26671
|
-
|
|
26672
|
-
|
|
26673
|
-
|
|
26674
|
-
|
|
26675
|
-
|
|
26676
|
-
|
|
26990
|
+
className: "hls-video-player-container",
|
|
26991
|
+
ref: videoContainerRef,
|
|
26992
|
+
onClick: handleContainerClick,
|
|
26993
|
+
children: [
|
|
26994
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
26995
|
+
"video",
|
|
26996
|
+
{
|
|
26997
|
+
ref: videoRef,
|
|
26998
|
+
className: "hls-video-element",
|
|
26999
|
+
poster,
|
|
27000
|
+
controls: false,
|
|
27001
|
+
loop,
|
|
27002
|
+
muted,
|
|
27003
|
+
playsInline,
|
|
27004
|
+
autoPlay: autoplay,
|
|
27005
|
+
preload: "metadata"
|
|
27006
|
+
}
|
|
27007
|
+
),
|
|
27008
|
+
controls && /* @__PURE__ */ jsxRuntime.jsx(
|
|
27009
|
+
VideoControls,
|
|
27010
|
+
{
|
|
27011
|
+
isPlaying,
|
|
27012
|
+
currentTime,
|
|
27013
|
+
duration,
|
|
27014
|
+
buffered,
|
|
27015
|
+
showControls: controlsPinned || showControls || !isPlaying,
|
|
27016
|
+
controlsPinned,
|
|
27017
|
+
playbackRate,
|
|
27018
|
+
onPlayPause: handleTogglePlay,
|
|
27019
|
+
onSeek: handleSeek,
|
|
27020
|
+
onSeekStart: handleSeekStart,
|
|
27021
|
+
onSeekEnd: handleSeekEnd,
|
|
27022
|
+
onPlaybackRateChange: handlePlaybackRateChange,
|
|
27023
|
+
onTogglePinControls: () => setControlsPinned((prev) => {
|
|
27024
|
+
const next = !prev;
|
|
27025
|
+
if (next) {
|
|
27026
|
+
setShowControls(true);
|
|
27027
|
+
} else {
|
|
27028
|
+
resetControlsTimeout();
|
|
27029
|
+
}
|
|
27030
|
+
return next;
|
|
27031
|
+
}),
|
|
27032
|
+
onToggleFullscreen: handleToggleFullscreen
|
|
27033
|
+
}
|
|
27034
|
+
)
|
|
27035
|
+
]
|
|
26677
27036
|
}
|
|
26678
|
-
)
|
|
26679
|
-
|
|
26680
|
-
|
|
26681
|
-
|
|
26682
|
-
|
|
26683
|
-
"div",
|
|
26684
|
-
{
|
|
26685
|
-
onClick: handleClickWithIndicator,
|
|
26686
|
-
style: {
|
|
26687
|
-
position: "absolute",
|
|
26688
|
-
top: 0,
|
|
26689
|
-
left: 0,
|
|
26690
|
-
right: 0,
|
|
26691
|
-
bottom: 0,
|
|
26692
|
-
zIndex: 1,
|
|
26693
|
-
cursor: "pointer"
|
|
26694
|
-
},
|
|
26695
|
-
"aria-label": "Click to play/pause"
|
|
26696
|
-
}
|
|
26697
|
-
),
|
|
26698
|
-
onClick && !controls && /* @__PURE__ */ jsxRuntime.jsx(
|
|
26699
|
-
PlayPauseIndicator,
|
|
26700
|
-
{
|
|
26701
|
-
show: showIndicator,
|
|
26702
|
-
isPlaying: indicatorIsPlaying
|
|
26703
|
-
},
|
|
26704
|
-
indicatorKeyRef.current
|
|
26705
|
-
)
|
|
26706
|
-
] });
|
|
27037
|
+
),
|
|
27038
|
+
isLoading && !externalLoadingControl && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "hls-video-player-loading", children: /* @__PURE__ */ jsxRuntime.jsx(OptifyeLogoLoader_default, { size: "md", message: "Loading video..." }) })
|
|
27039
|
+
]
|
|
27040
|
+
}
|
|
27041
|
+
);
|
|
26707
27042
|
});
|
|
26708
27043
|
HlsVideoPlayer.displayName = "HlsVideoPlayer";
|
|
26709
27044
|
var VideoPlayer = HlsVideoPlayer;
|
|
@@ -26711,6 +27046,7 @@ var CroppedHlsVideoPlayer = React23.forwardRef(({
|
|
|
26711
27046
|
crop,
|
|
26712
27047
|
debug = false,
|
|
26713
27048
|
onClick,
|
|
27049
|
+
controls = true,
|
|
26714
27050
|
...videoProps
|
|
26715
27051
|
}, ref) => {
|
|
26716
27052
|
const {
|
|
@@ -26732,9 +27068,15 @@ var CroppedHlsVideoPlayer = React23.forwardRef(({
|
|
|
26732
27068
|
const [isVideoReady, setIsVideoReady] = React23.useState(false);
|
|
26733
27069
|
const [canvasDimensions, setCanvasDimensions] = React23.useState({ width: 0, height: 0 });
|
|
26734
27070
|
const [isProcessing, setIsProcessing] = React23.useState(false);
|
|
26735
|
-
const [
|
|
26736
|
-
const [
|
|
26737
|
-
const
|
|
27071
|
+
const [showControls, setShowControls] = React23.useState(true);
|
|
27072
|
+
const [isPlaying, setIsPlaying] = React23.useState(false);
|
|
27073
|
+
const [currentTime, setCurrentTime] = React23.useState(0);
|
|
27074
|
+
const [duration, setDuration] = React23.useState(0);
|
|
27075
|
+
const [buffered, setBuffered] = React23.useState(0);
|
|
27076
|
+
const [playbackRate, setPlaybackRate] = React23.useState(1);
|
|
27077
|
+
const controlsTimeoutRef = React23.useRef(null);
|
|
27078
|
+
const userSeekingRef = React23.useRef(false);
|
|
27079
|
+
const [controlsPinned, setControlsPinned] = React23.useState(false);
|
|
26738
27080
|
const stopCanvasRendering = React23.useCallback(() => {
|
|
26739
27081
|
if (animationFrameRef.current) {
|
|
26740
27082
|
cancelAnimationFrame(animationFrameRef.current);
|
|
@@ -26819,7 +27161,7 @@ var CroppedHlsVideoPlayer = React23.forwardRef(({
|
|
|
26819
27161
|
const canvas = canvasRef.current;
|
|
26820
27162
|
const video = videoElementRef.current;
|
|
26821
27163
|
const ctx = canvas.getContext("2d");
|
|
26822
|
-
if (!ctx || video.
|
|
27164
|
+
if (!ctx || video.readyState < 2) {
|
|
26823
27165
|
return;
|
|
26824
27166
|
}
|
|
26825
27167
|
const videoWidth = video.videoWidth;
|
|
@@ -26846,7 +27188,9 @@ var CroppedHlsVideoPlayer = React23.forwardRef(({
|
|
|
26846
27188
|
canvas.height
|
|
26847
27189
|
// Destination (full canvas)
|
|
26848
27190
|
);
|
|
26849
|
-
|
|
27191
|
+
if (!video.paused && !video.ended) {
|
|
27192
|
+
animationFrameRef.current = requestAnimationFrame(renderFrameToCanvas);
|
|
27193
|
+
}
|
|
26850
27194
|
}, [crop]);
|
|
26851
27195
|
const handleVideoReady = React23.useCallback((player) => {
|
|
26852
27196
|
console.log("[CroppedHlsVideoPlayer] Video player ready");
|
|
@@ -26854,11 +27198,15 @@ var CroppedHlsVideoPlayer = React23.forwardRef(({
|
|
|
26854
27198
|
if (videoEl) {
|
|
26855
27199
|
videoElementRef.current = videoEl;
|
|
26856
27200
|
setIsVideoReady(true);
|
|
27201
|
+
if (videoEl.readyState >= 2) {
|
|
27202
|
+
renderFrameToCanvas();
|
|
27203
|
+
}
|
|
26857
27204
|
}
|
|
26858
27205
|
onReadyProp?.(player);
|
|
26859
|
-
}, [onReadyProp]);
|
|
27206
|
+
}, [onReadyProp, renderFrameToCanvas]);
|
|
26860
27207
|
const handleVideoPlay = React23.useCallback((player) => {
|
|
26861
27208
|
console.log("[CroppedHlsVideoPlayer] Video playing, starting canvas rendering");
|
|
27209
|
+
setIsPlaying(true);
|
|
26862
27210
|
if (crop && canvasRef.current) {
|
|
26863
27211
|
setIsProcessing(true);
|
|
26864
27212
|
renderFrameToCanvas();
|
|
@@ -26866,43 +27214,40 @@ var CroppedHlsVideoPlayer = React23.forwardRef(({
|
|
|
26866
27214
|
onPlayProp?.(player);
|
|
26867
27215
|
}, [crop, renderFrameToCanvas, onPlayProp]);
|
|
26868
27216
|
const handleVideoPause = React23.useCallback((player) => {
|
|
26869
|
-
console.log("[CroppedHlsVideoPlayer] Video paused, stopping canvas rendering
|
|
27217
|
+
console.log("[CroppedHlsVideoPlayer] Video paused, stopping canvas rendering (keeping last frame)");
|
|
27218
|
+
if (userSeekingRef.current && hiddenVideoRef.current) {
|
|
27219
|
+
hiddenVideoRef.current.play()?.catch(() => {
|
|
27220
|
+
});
|
|
27221
|
+
return;
|
|
27222
|
+
}
|
|
26870
27223
|
stopCanvasRendering();
|
|
26871
27224
|
setIsProcessing(false);
|
|
26872
|
-
|
|
26873
|
-
|
|
26874
|
-
if (ctx) {
|
|
26875
|
-
ctx.clearRect(0, 0, canvasRef.current.width, canvasRef.current.height);
|
|
26876
|
-
ctx.fillStyle = "black";
|
|
26877
|
-
ctx.fillRect(0, 0, canvasRef.current.width, canvasRef.current.height);
|
|
26878
|
-
}
|
|
26879
|
-
}
|
|
27225
|
+
setIsPlaying(false);
|
|
27226
|
+
renderFrameToCanvas();
|
|
26880
27227
|
onPauseProp?.(player);
|
|
26881
|
-
}, [stopCanvasRendering, onPauseProp]);
|
|
27228
|
+
}, [stopCanvasRendering, onPauseProp, renderFrameToCanvas]);
|
|
26882
27229
|
const handleVideoEnded = React23.useCallback((player) => {
|
|
26883
|
-
console.log("[CroppedHlsVideoPlayer] Video ended,
|
|
27230
|
+
console.log("[CroppedHlsVideoPlayer] Video ended, stopping canvas rendering (keeping last frame)");
|
|
26884
27231
|
stopCanvasRendering();
|
|
26885
27232
|
setIsProcessing(false);
|
|
26886
|
-
|
|
26887
|
-
|
|
26888
|
-
if (ctx) {
|
|
26889
|
-
ctx.clearRect(0, 0, canvasRef.current.width, canvasRef.current.height);
|
|
26890
|
-
ctx.fillStyle = "black";
|
|
26891
|
-
ctx.fillRect(0, 0, canvasRef.current.width, canvasRef.current.height);
|
|
26892
|
-
}
|
|
26893
|
-
}
|
|
27233
|
+
setIsPlaying(false);
|
|
27234
|
+
userSeekingRef.current = false;
|
|
26894
27235
|
onEndedProp?.(player);
|
|
26895
27236
|
}, [stopCanvasRendering, onEndedProp]);
|
|
26896
27237
|
const handleSeeking = React23.useCallback((player) => {
|
|
26897
27238
|
console.log("[CroppedHlsVideoPlayer] Video seeking");
|
|
26898
|
-
|
|
27239
|
+
userSeekingRef.current = true;
|
|
27240
|
+
if (crop) {
|
|
26899
27241
|
renderFrameToCanvas();
|
|
26900
27242
|
}
|
|
26901
27243
|
onSeekingProp?.(player);
|
|
26902
27244
|
}, [crop, renderFrameToCanvas, onSeekingProp]);
|
|
26903
27245
|
const handleSeeked = React23.useCallback((player) => {
|
|
26904
27246
|
console.log("[CroppedHlsVideoPlayer] Video seeked");
|
|
26905
|
-
|
|
27247
|
+
hiddenVideoRef.current?.play()?.catch(() => {
|
|
27248
|
+
});
|
|
27249
|
+
userSeekingRef.current = false;
|
|
27250
|
+
if (crop) {
|
|
26906
27251
|
renderFrameToCanvas();
|
|
26907
27252
|
}
|
|
26908
27253
|
onSeekedProp?.(player);
|
|
@@ -26910,8 +27255,29 @@ var CroppedHlsVideoPlayer = React23.forwardRef(({
|
|
|
26910
27255
|
const handleLoadedMetadata = React23.useCallback((player) => {
|
|
26911
27256
|
console.log("[CroppedHlsVideoPlayer] Video metadata loaded");
|
|
26912
27257
|
calculateCanvasDimensions();
|
|
27258
|
+
if (hiddenVideoRef.current?.video) {
|
|
27259
|
+
setDuration(hiddenVideoRef.current.video.duration || 0);
|
|
27260
|
+
}
|
|
27261
|
+
requestAnimationFrame(() => renderFrameToCanvas());
|
|
26913
27262
|
onLoadedMetadataProp?.(player);
|
|
26914
|
-
}, [calculateCanvasDimensions, onLoadedMetadataProp]);
|
|
27263
|
+
}, [calculateCanvasDimensions, onLoadedMetadataProp, renderFrameToCanvas]);
|
|
27264
|
+
const handleTimeUpdate = React23.useCallback((player, time2) => {
|
|
27265
|
+
setCurrentTime(time2);
|
|
27266
|
+
if (hiddenVideoRef.current?.video && hiddenVideoRef.current.video.buffered.length > 0) {
|
|
27267
|
+
const video = hiddenVideoRef.current.video;
|
|
27268
|
+
for (let i = 0; i < video.buffered.length; i++) {
|
|
27269
|
+
if (video.buffered.start(i) <= time2 && video.buffered.end(i) >= time2) {
|
|
27270
|
+
setBuffered(video.buffered.end(i));
|
|
27271
|
+
break;
|
|
27272
|
+
}
|
|
27273
|
+
}
|
|
27274
|
+
}
|
|
27275
|
+
videoProps.onTimeUpdate?.(player, time2);
|
|
27276
|
+
}, [videoProps.onTimeUpdate]);
|
|
27277
|
+
const handleDurationChange = React23.useCallback((player, dur) => {
|
|
27278
|
+
setDuration(dur);
|
|
27279
|
+
videoProps.onDurationChange?.(player, dur);
|
|
27280
|
+
}, [videoProps.onDurationChange]);
|
|
26915
27281
|
React23.useEffect(() => {
|
|
26916
27282
|
calculateCanvasDimensions();
|
|
26917
27283
|
const handleResize = () => {
|
|
@@ -26939,33 +27305,97 @@ var CroppedHlsVideoPlayer = React23.forwardRef(({
|
|
|
26939
27305
|
stopCanvasRendering();
|
|
26940
27306
|
};
|
|
26941
27307
|
}, [stopCanvasRendering]);
|
|
27308
|
+
const resetControlsTimeout = React23.useCallback(() => {
|
|
27309
|
+
if (controlsPinned) {
|
|
27310
|
+
setShowControls(true);
|
|
27311
|
+
return;
|
|
27312
|
+
}
|
|
27313
|
+
setShowControls(true);
|
|
27314
|
+
if (controlsTimeoutRef.current) {
|
|
27315
|
+
clearTimeout(controlsTimeoutRef.current);
|
|
27316
|
+
}
|
|
27317
|
+
if (isPlaying) {
|
|
27318
|
+
controlsTimeoutRef.current = setTimeout(() => {
|
|
27319
|
+
setShowControls(false);
|
|
27320
|
+
}, 3e3);
|
|
27321
|
+
}
|
|
27322
|
+
}, [isPlaying, controlsPinned]);
|
|
27323
|
+
const handleMouseMove = React23.useCallback(() => {
|
|
27324
|
+
resetControlsTimeout();
|
|
27325
|
+
}, [resetControlsTimeout]);
|
|
27326
|
+
React23.useEffect(() => {
|
|
27327
|
+
resetControlsTimeout();
|
|
27328
|
+
return () => {
|
|
27329
|
+
if (controlsTimeoutRef.current) {
|
|
27330
|
+
clearTimeout(controlsTimeoutRef.current);
|
|
27331
|
+
}
|
|
27332
|
+
};
|
|
27333
|
+
}, [isPlaying, resetControlsTimeout]);
|
|
27334
|
+
const handleTogglePlay = React23.useCallback(() => {
|
|
27335
|
+
if (hiddenVideoRef.current?.video) {
|
|
27336
|
+
if (hiddenVideoRef.current.video.paused) {
|
|
27337
|
+
hiddenVideoRef.current.play();
|
|
27338
|
+
} else {
|
|
27339
|
+
hiddenVideoRef.current.pause();
|
|
27340
|
+
}
|
|
27341
|
+
}
|
|
27342
|
+
}, []);
|
|
27343
|
+
const handleSeek = React23.useCallback((time2) => {
|
|
27344
|
+
if (hiddenVideoRef.current) {
|
|
27345
|
+
hiddenVideoRef.current.currentTime(time2);
|
|
27346
|
+
hiddenVideoRef.current.play()?.catch(() => {
|
|
27347
|
+
});
|
|
27348
|
+
setTimeout(() => renderFrameToCanvas(), 50);
|
|
27349
|
+
}
|
|
27350
|
+
}, [renderFrameToCanvas]);
|
|
27351
|
+
const handleSeekStart = React23.useCallback(() => {
|
|
27352
|
+
userSeekingRef.current = true;
|
|
27353
|
+
}, []);
|
|
27354
|
+
const handleSeekEnd = React23.useCallback(() => {
|
|
27355
|
+
if (hiddenVideoRef.current) {
|
|
27356
|
+
hiddenVideoRef.current.play()?.catch(() => {
|
|
27357
|
+
});
|
|
27358
|
+
}
|
|
27359
|
+
}, []);
|
|
27360
|
+
const handlePlaybackRateChange = React23.useCallback((rate) => {
|
|
27361
|
+
if (hiddenVideoRef.current) {
|
|
27362
|
+
hiddenVideoRef.current.playbackRate(rate);
|
|
27363
|
+
setPlaybackRate(rate);
|
|
27364
|
+
}
|
|
27365
|
+
}, []);
|
|
27366
|
+
const handleToggleFullscreen = React23.useCallback(() => {
|
|
27367
|
+
if (videoContainerRef.current) {
|
|
27368
|
+
if (!document.fullscreenElement) {
|
|
27369
|
+
videoContainerRef.current.requestFullscreen();
|
|
27370
|
+
} else {
|
|
27371
|
+
document.exitFullscreen();
|
|
27372
|
+
}
|
|
27373
|
+
}
|
|
27374
|
+
}, []);
|
|
26942
27375
|
if (!crop) {
|
|
26943
|
-
return /* @__PURE__ */ jsxRuntime.jsx(HlsVideoPlayer, { ref, ...videoProps, onClick });
|
|
26944
|
-
}
|
|
26945
|
-
const
|
|
26946
|
-
if (!onClick
|
|
26947
|
-
|
|
26948
|
-
|
|
26949
|
-
|
|
26950
|
-
setShowIndicator(false);
|
|
26951
|
-
setTimeout(() => {
|
|
26952
|
-
indicatorKeyRef.current += 1;
|
|
26953
|
-
setShowIndicator(true);
|
|
26954
|
-
}, 0);
|
|
26955
|
-
onClick();
|
|
27376
|
+
return /* @__PURE__ */ jsxRuntime.jsx(HlsVideoPlayer, { ref, ...videoProps, onClick, controls });
|
|
27377
|
+
}
|
|
27378
|
+
const handleClick = () => {
|
|
27379
|
+
if (!onClick && !controls) {
|
|
27380
|
+
handleTogglePlay();
|
|
27381
|
+
}
|
|
27382
|
+
if (onClick) onClick();
|
|
26956
27383
|
};
|
|
26957
27384
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
26958
27385
|
"div",
|
|
26959
27386
|
{
|
|
26960
27387
|
ref: videoContainerRef,
|
|
26961
|
-
className: `relative w-full h-full flex items-center justify-center bg-black ${onClick ? "cursor-pointer" : ""}
|
|
26962
|
-
onClick:
|
|
27388
|
+
className: `relative w-full h-full flex items-center justify-center bg-black group ${inheritedClassName} ${onClick || controls ? "cursor-pointer" : ""}`,
|
|
27389
|
+
onClick: handleClick,
|
|
27390
|
+
onMouseMove: handleMouseMove,
|
|
27391
|
+
onMouseLeave: () => isPlaying && !controlsPinned && setShowControls(false),
|
|
26963
27392
|
children: [
|
|
26964
27393
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "hidden", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
26965
27394
|
HlsVideoPlayer,
|
|
26966
27395
|
{
|
|
26967
27396
|
ref: hiddenVideoRef,
|
|
26968
27397
|
...videoProps,
|
|
27398
|
+
controls: false,
|
|
26969
27399
|
onReady: handleVideoReady,
|
|
26970
27400
|
onPlay: handleVideoPlay,
|
|
26971
27401
|
onPause: handleVideoPause,
|
|
@@ -26975,7 +27405,9 @@ var CroppedHlsVideoPlayer = React23.forwardRef(({
|
|
|
26975
27405
|
onLoadedMetadata: handleLoadedMetadata,
|
|
26976
27406
|
onLoadedData: videoProps.onLoadedData,
|
|
26977
27407
|
onPlaying: videoProps.onPlaying,
|
|
26978
|
-
onLoadingChange: videoProps.onLoadingChange
|
|
27408
|
+
onLoadingChange: videoProps.onLoadingChange,
|
|
27409
|
+
onTimeUpdate: handleTimeUpdate,
|
|
27410
|
+
onDurationChange: handleDurationChange
|
|
26979
27411
|
}
|
|
26980
27412
|
) }),
|
|
26981
27413
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -26992,8 +27424,8 @@ var CroppedHlsVideoPlayer = React23.forwardRef(({
|
|
|
26992
27424
|
}
|
|
26993
27425
|
}
|
|
26994
27426
|
),
|
|
26995
|
-
!isVideoReady && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 flex items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(OptifyeLogoLoader_default, { size: "md", message: "Loading video..." }) }),
|
|
26996
|
-
debug && isVideoReady && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute top-2 left-2 bg-black/80 text-white text-xs p-2 rounded font-mono", children: [
|
|
27427
|
+
!isVideoReady && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 flex items-center justify-center pointer-events-none", children: /* @__PURE__ */ jsxRuntime.jsx(OptifyeLogoLoader_default, { size: "md", message: "Loading video..." }) }),
|
|
27428
|
+
debug && isVideoReady && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute top-2 left-2 bg-black/80 text-white text-xs p-2 rounded font-mono pointer-events-none z-20", children: [
|
|
26997
27429
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
26998
27430
|
"Crop: ",
|
|
26999
27431
|
crop.x,
|
|
@@ -27017,13 +27449,32 @@ var CroppedHlsVideoPlayer = React23.forwardRef(({
|
|
|
27017
27449
|
isProcessing ? "Yes" : "No"
|
|
27018
27450
|
] })
|
|
27019
27451
|
] }),
|
|
27020
|
-
|
|
27021
|
-
|
|
27452
|
+
controls && isVideoReady && /* @__PURE__ */ jsxRuntime.jsx(
|
|
27453
|
+
VideoControls,
|
|
27022
27454
|
{
|
|
27023
|
-
|
|
27024
|
-
|
|
27025
|
-
|
|
27026
|
-
|
|
27455
|
+
isPlaying,
|
|
27456
|
+
currentTime,
|
|
27457
|
+
duration,
|
|
27458
|
+
buffered,
|
|
27459
|
+
showControls: controlsPinned || showControls || !isPlaying,
|
|
27460
|
+
controlsPinned,
|
|
27461
|
+
playbackRate,
|
|
27462
|
+
onPlayPause: handleTogglePlay,
|
|
27463
|
+
onSeek: handleSeek,
|
|
27464
|
+
onSeekStart: handleSeekStart,
|
|
27465
|
+
onSeekEnd: handleSeekEnd,
|
|
27466
|
+
onPlaybackRateChange: handlePlaybackRateChange,
|
|
27467
|
+
onTogglePinControls: () => setControlsPinned((prev) => {
|
|
27468
|
+
const next = !prev;
|
|
27469
|
+
if (next) {
|
|
27470
|
+
setShowControls(true);
|
|
27471
|
+
} else {
|
|
27472
|
+
resetControlsTimeout();
|
|
27473
|
+
}
|
|
27474
|
+
return next;
|
|
27475
|
+
}),
|
|
27476
|
+
onToggleFullscreen: handleToggleFullscreen
|
|
27477
|
+
}
|
|
27027
27478
|
)
|
|
27028
27479
|
]
|
|
27029
27480
|
}
|
|
@@ -27562,6 +28013,67 @@ var SilentErrorBoundary = class extends React23__namespace.default.Component {
|
|
|
27562
28013
|
] }) });
|
|
27563
28014
|
}
|
|
27564
28015
|
};
|
|
28016
|
+
var PlayPauseIndicator = ({
|
|
28017
|
+
show,
|
|
28018
|
+
isPlaying,
|
|
28019
|
+
duration = 600
|
|
28020
|
+
}) => {
|
|
28021
|
+
const [isVisible, setIsVisible] = React23.useState(false);
|
|
28022
|
+
const [isFading, setIsFading] = React23.useState(false);
|
|
28023
|
+
React23.useEffect(() => {
|
|
28024
|
+
if (show) {
|
|
28025
|
+
setIsVisible(true);
|
|
28026
|
+
setIsFading(false);
|
|
28027
|
+
const fadeTimer = setTimeout(() => {
|
|
28028
|
+
setIsFading(true);
|
|
28029
|
+
}, 100);
|
|
28030
|
+
const hideTimer = setTimeout(() => {
|
|
28031
|
+
setIsVisible(false);
|
|
28032
|
+
setIsFading(false);
|
|
28033
|
+
}, duration);
|
|
28034
|
+
return () => {
|
|
28035
|
+
clearTimeout(fadeTimer);
|
|
28036
|
+
clearTimeout(hideTimer);
|
|
28037
|
+
};
|
|
28038
|
+
}
|
|
28039
|
+
}, [show, duration]);
|
|
28040
|
+
if (!isVisible) return null;
|
|
28041
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
28042
|
+
"div",
|
|
28043
|
+
{
|
|
28044
|
+
className: "absolute inset-0 flex items-center justify-center pointer-events-none z-10",
|
|
28045
|
+
style: {
|
|
28046
|
+
opacity: isFading ? 0 : 1,
|
|
28047
|
+
transition: `opacity ${duration - 100}ms ease-out`
|
|
28048
|
+
},
|
|
28049
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "bg-black/70 rounded-full p-6", children: isPlaying ? (
|
|
28050
|
+
// Play icon (triangle)
|
|
28051
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
28052
|
+
"svg",
|
|
28053
|
+
{
|
|
28054
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
28055
|
+
viewBox: "0 0 24 24",
|
|
28056
|
+
fill: "white",
|
|
28057
|
+
className: "w-16 h-16",
|
|
28058
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M8 5v14l11-7z" })
|
|
28059
|
+
}
|
|
28060
|
+
)
|
|
28061
|
+
) : (
|
|
28062
|
+
// Pause icon (two bars)
|
|
28063
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
28064
|
+
"svg",
|
|
28065
|
+
{
|
|
28066
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
28067
|
+
viewBox: "0 0 24 24",
|
|
28068
|
+
fill: "white",
|
|
28069
|
+
className: "w-16 h-16",
|
|
28070
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M6 4h4v16H6V4zm8 0h4v16h-4V4z" })
|
|
28071
|
+
}
|
|
28072
|
+
)
|
|
28073
|
+
) })
|
|
28074
|
+
}
|
|
28075
|
+
);
|
|
28076
|
+
};
|
|
27565
28077
|
var BackButton = ({
|
|
27566
28078
|
onClick,
|
|
27567
28079
|
text = "Back",
|
|
@@ -29214,6 +29726,31 @@ var BottlenecksContent = ({
|
|
|
29214
29726
|
const [categoryMetadata, setCategoryMetadata] = React23.useState([]);
|
|
29215
29727
|
const [currentMetadataIndex, setCurrentMetadataIndex] = React23.useState(0);
|
|
29216
29728
|
const [metadataCache, setMetadataCache] = React23.useState({});
|
|
29729
|
+
const invalidateMetadataCache = React23.useCallback((categories) => {
|
|
29730
|
+
setMetadataCache((prevCache) => {
|
|
29731
|
+
if (!prevCache || Object.keys(prevCache).length === 0) {
|
|
29732
|
+
return prevCache;
|
|
29733
|
+
}
|
|
29734
|
+
const targetCategories = categories ? (Array.isArray(categories) ? categories : [categories]).filter(Boolean) : null;
|
|
29735
|
+
let updatedCache = null;
|
|
29736
|
+
const shouldInvalidate = (key) => {
|
|
29737
|
+
if (!targetCategories || targetCategories.length === 0) {
|
|
29738
|
+
return true;
|
|
29739
|
+
}
|
|
29740
|
+
const [categoryId] = key.split("-");
|
|
29741
|
+
return targetCategories.includes(categoryId);
|
|
29742
|
+
};
|
|
29743
|
+
Object.keys(prevCache).forEach((cacheKey) => {
|
|
29744
|
+
if (shouldInvalidate(cacheKey)) {
|
|
29745
|
+
if (!updatedCache) {
|
|
29746
|
+
updatedCache = { ...prevCache };
|
|
29747
|
+
}
|
|
29748
|
+
delete updatedCache[cacheKey];
|
|
29749
|
+
}
|
|
29750
|
+
});
|
|
29751
|
+
return updatedCache || prevCache;
|
|
29752
|
+
});
|
|
29753
|
+
}, []);
|
|
29217
29754
|
const [triageClips, setTriageClips] = React23.useState([]);
|
|
29218
29755
|
const [isLoadingTriageClips, setIsLoadingTriageClips] = React23.useState(false);
|
|
29219
29756
|
const [isFullscreen, setIsFullscreen] = React23.useState(false);
|
|
@@ -29233,6 +29770,12 @@ var BottlenecksContent = ({
|
|
|
29233
29770
|
onNewClips: (notification) => {
|
|
29234
29771
|
console.log(`[BottlenecksContent] New clips detected:`, notification);
|
|
29235
29772
|
if (notification.clips.length > 0) {
|
|
29773
|
+
const categoryIds = notification.clips.map((clip) => clip.clip_type).filter(Boolean).map((value) => String(value));
|
|
29774
|
+
if (categoryIds.length > 0) {
|
|
29775
|
+
invalidateMetadataCache(categoryIds);
|
|
29776
|
+
} else {
|
|
29777
|
+
invalidateMetadataCache();
|
|
29778
|
+
}
|
|
29236
29779
|
fetchClipCounts();
|
|
29237
29780
|
}
|
|
29238
29781
|
}
|
|
@@ -29279,24 +29822,37 @@ var BottlenecksContent = ({
|
|
|
29279
29822
|
shift: shift || "0"
|
|
29280
29823
|
});
|
|
29281
29824
|
React23.useEffect(() => {
|
|
29282
|
-
if (clipTypes.length > 0
|
|
29283
|
-
const
|
|
29284
|
-
|
|
29285
|
-
|
|
29286
|
-
|
|
29287
|
-
|
|
29288
|
-
|
|
29289
|
-
|
|
29825
|
+
if (clipTypes.length > 0) {
|
|
29826
|
+
const currentFilterCount = initialFilter ? dynamicCounts[initialFilter] || 0 : 0;
|
|
29827
|
+
const hasAnyCounts = Object.values(dynamicCounts).some((c) => c > 0);
|
|
29828
|
+
const userHasNotNavigated = !initialFilter || activeFilterRef.current === initialFilter;
|
|
29829
|
+
const shouldRunSelection = !initialFilter || userHasNotNavigated && currentFilterCount === 0 && hasAnyCounts;
|
|
29830
|
+
if (shouldRunSelection) {
|
|
29831
|
+
let selectedType = null;
|
|
29832
|
+
if (clipTypes.length === 1) {
|
|
29833
|
+
selectedType = clipTypes[0];
|
|
29834
|
+
} else {
|
|
29835
|
+
const priorityOrder = ["cycle_completion", "fast-cycles", "slow-cycles", "idle_time"];
|
|
29836
|
+
for (const priorityType of priorityOrder) {
|
|
29837
|
+
const type = clipTypes.find((t) => t.type === priorityType && (dynamicCounts[t.type] || 0) > 0);
|
|
29838
|
+
if (type) {
|
|
29839
|
+
selectedType = type;
|
|
29840
|
+
break;
|
|
29841
|
+
}
|
|
29842
|
+
}
|
|
29843
|
+
if (!selectedType) {
|
|
29844
|
+
selectedType = clipTypes.find((type) => (dynamicCounts[type.type] || 0) > 0);
|
|
29845
|
+
}
|
|
29846
|
+
if (!selectedType) {
|
|
29847
|
+
selectedType = clipTypes[0];
|
|
29848
|
+
}
|
|
29849
|
+
}
|
|
29850
|
+
if (selectedType && selectedType.type !== initialFilter) {
|
|
29851
|
+
console.log(`[BottlenecksContent] Auto-selecting filter: ${selectedType.type} (count: ${dynamicCounts[selectedType.type] || 0})`);
|
|
29852
|
+
setInitialFilter(selectedType.type);
|
|
29853
|
+
setActiveFilter(selectedType.type);
|
|
29854
|
+
activeFilterRef.current = selectedType.type;
|
|
29290
29855
|
}
|
|
29291
|
-
}
|
|
29292
|
-
if (!selectedType) {
|
|
29293
|
-
selectedType = clipTypes.find((type) => (dynamicCounts[type.type] || 0) > 0);
|
|
29294
|
-
}
|
|
29295
|
-
const firstType = selectedType || clipTypes[0];
|
|
29296
|
-
if (firstType) {
|
|
29297
|
-
setInitialFilter(firstType.type);
|
|
29298
|
-
setActiveFilter(firstType.type);
|
|
29299
|
-
activeFilterRef.current = firstType.type;
|
|
29300
29856
|
}
|
|
29301
29857
|
}
|
|
29302
29858
|
}, [clipTypes, dynamicCounts, initialFilter]);
|
|
@@ -29348,7 +29904,7 @@ var BottlenecksContent = ({
|
|
|
29348
29904
|
} finally {
|
|
29349
29905
|
fetchInProgressRef.current.delete(operationKey);
|
|
29350
29906
|
}
|
|
29351
|
-
}, [workspaceId, date, s3ClipsService, effectiveShift, dashboardConfig, updateClipCounts]);
|
|
29907
|
+
}, [workspaceId, date, s3ClipsService, effectiveShift, dashboardConfig, updateClipCounts, timezone, totalOutput]);
|
|
29352
29908
|
const loadingCategoryRef = React23.useRef(null);
|
|
29353
29909
|
const loadFirstVideoForCategory = React23.useCallback(async (category) => {
|
|
29354
29910
|
if (!workspaceId || !s3ClipsService || !isMountedRef.current) return;
|
|
@@ -29438,15 +29994,16 @@ var BottlenecksContent = ({
|
|
|
29438
29994
|
loadingCategoryRef.current = null;
|
|
29439
29995
|
fetchInProgressRef.current.delete(operationKey);
|
|
29440
29996
|
}
|
|
29441
|
-
}, [workspaceId, date, s3ClipsService, mergedCounts, effectiveShift]);
|
|
29997
|
+
}, [workspaceId, date, s3ClipsService, mergedCounts, effectiveShift, timezone]);
|
|
29442
29998
|
const handleRefreshClips = React23.useCallback(async () => {
|
|
29443
29999
|
console.log("[BottlenecksContent] Refreshing clips after new additions");
|
|
29444
30000
|
acknowledgeNewClips();
|
|
30001
|
+
invalidateMetadataCache();
|
|
29445
30002
|
await fetchClipCounts();
|
|
29446
30003
|
if (activeFilter && mergedCounts[activeFilter] > 0) {
|
|
29447
30004
|
await loadFirstVideoForCategory(activeFilter);
|
|
29448
30005
|
}
|
|
29449
|
-
}, [acknowledgeNewClips, fetchClipCounts, activeFilter, mergedCounts, loadFirstVideoForCategory]);
|
|
30006
|
+
}, [acknowledgeNewClips, fetchClipCounts, activeFilter, mergedCounts, loadFirstVideoForCategory, invalidateMetadataCache]);
|
|
29450
30007
|
React23.useEffect(() => {
|
|
29451
30008
|
if (s3ClipsService) {
|
|
29452
30009
|
fetchClipCounts();
|
|
@@ -29616,38 +30173,38 @@ var BottlenecksContent = ({
|
|
|
29616
30173
|
loadingTimeoutRef.current = null;
|
|
29617
30174
|
}
|
|
29618
30175
|
}, []);
|
|
29619
|
-
const loadCategoryMetadata = React23.useCallback(async (categoryId, autoLoadFirstVideo = false) => {
|
|
30176
|
+
const loadCategoryMetadata = React23.useCallback(async (categoryId, autoLoadFirstVideo = false, forceRefresh = false) => {
|
|
29620
30177
|
if (!workspaceId) {
|
|
29621
30178
|
return;
|
|
29622
30179
|
}
|
|
29623
|
-
const
|
|
29624
|
-
|
|
29625
|
-
|
|
29626
|
-
|
|
29627
|
-
|
|
29628
|
-
|
|
29629
|
-
|
|
29630
|
-
|
|
29631
|
-
|
|
29632
|
-
|
|
29633
|
-
|
|
29634
|
-
|
|
29635
|
-
|
|
29636
|
-
|
|
29637
|
-
|
|
29638
|
-
|
|
29639
|
-
|
|
30180
|
+
const resolvedDate = date || getOperationalDate(timezone);
|
|
30181
|
+
const cacheKey = `${categoryId}-${resolvedDate}-${effectiveShift}`;
|
|
30182
|
+
const cachedMetadata = !forceRefresh ? metadataCache[cacheKey] : void 0;
|
|
30183
|
+
try {
|
|
30184
|
+
if (cachedMetadata) {
|
|
30185
|
+
console.log(`[BottlenecksContent] Using cached metadata for ${categoryId}`);
|
|
30186
|
+
setCategoryMetadata(cachedMetadata);
|
|
30187
|
+
categoryMetadataRef.current = cachedMetadata;
|
|
30188
|
+
if (autoLoadFirstVideo && cachedMetadata.length > 0 && s3ClipsService) {
|
|
30189
|
+
const firstClipMeta = cachedMetadata[0];
|
|
30190
|
+
try {
|
|
30191
|
+
const video = await s3ClipsService.getClipById(firstClipMeta.clipId);
|
|
30192
|
+
if (video && isMountedRef.current) {
|
|
30193
|
+
setCurrentClipId(firstClipMeta.clipId);
|
|
30194
|
+
setAllVideos([video]);
|
|
30195
|
+
setCurrentIndex(0);
|
|
30196
|
+
setCurrentMetadataIndex(0);
|
|
30197
|
+
currentMetadataIndexRef.current = 0;
|
|
30198
|
+
console.log(`[BottlenecksContent] Auto-loaded first video from cache: ${video.id} (1/${cachedMetadata.length})`);
|
|
30199
|
+
}
|
|
30200
|
+
} catch (error2) {
|
|
30201
|
+
console.error(`[BottlenecksContent] Error loading first video from cache:`, error2);
|
|
30202
|
+
clearLoadingState();
|
|
29640
30203
|
}
|
|
29641
|
-
} catch (error2) {
|
|
29642
|
-
console.error(`[BottlenecksContent] Error loading first video from cache:`, error2);
|
|
29643
|
-
setIsCategoryLoading(false);
|
|
29644
|
-
clearLoadingState();
|
|
29645
30204
|
}
|
|
30205
|
+
return;
|
|
29646
30206
|
}
|
|
29647
|
-
|
|
29648
|
-
}
|
|
29649
|
-
try {
|
|
29650
|
-
console.log(`[BottlenecksContent] Loading metadata for category: ${categoryId}`);
|
|
30207
|
+
console.log(`[BottlenecksContent] Loading metadata for category: ${categoryId}${forceRefresh ? " (force refresh)" : ""}`);
|
|
29651
30208
|
const { createClient: createClient5 } = await import('@supabase/supabase-js');
|
|
29652
30209
|
const supabase = createClient5(
|
|
29653
30210
|
process.env.NEXT_PUBLIC_SUPABASE_URL || "",
|
|
@@ -29672,8 +30229,8 @@ var BottlenecksContent = ({
|
|
|
29672
30229
|
action: "percentile-clips",
|
|
29673
30230
|
percentileAction: percentileType,
|
|
29674
30231
|
workspaceId,
|
|
29675
|
-
startDate: `${
|
|
29676
|
-
endDate: `${
|
|
30232
|
+
startDate: `${resolvedDate}T00:00:00Z`,
|
|
30233
|
+
endDate: `${resolvedDate}T23:59:59Z`,
|
|
29677
30234
|
percentile: 10,
|
|
29678
30235
|
shiftId: effectiveShift,
|
|
29679
30236
|
limit: 100
|
|
@@ -29689,7 +30246,7 @@ var BottlenecksContent = ({
|
|
|
29689
30246
|
body: JSON.stringify({
|
|
29690
30247
|
action: "clip-metadata",
|
|
29691
30248
|
workspaceId,
|
|
29692
|
-
date:
|
|
30249
|
+
date: resolvedDate,
|
|
29693
30250
|
shift: effectiveShift,
|
|
29694
30251
|
category: categoryId,
|
|
29695
30252
|
page: 1,
|
|
@@ -29734,19 +30291,22 @@ var BottlenecksContent = ({
|
|
|
29734
30291
|
setCurrentIndex(0);
|
|
29735
30292
|
setCurrentMetadataIndex(0);
|
|
29736
30293
|
currentMetadataIndexRef.current = 0;
|
|
29737
|
-
setIsCategoryLoading(false);
|
|
29738
30294
|
console.log(`[BottlenecksContent] Auto-loaded first video: ${video.id} (1/${metadataClips.length})`);
|
|
29739
30295
|
}
|
|
29740
30296
|
} catch (error2) {
|
|
29741
30297
|
console.error(`[BottlenecksContent] Error loading first video:`, error2);
|
|
29742
|
-
setIsCategoryLoading(false);
|
|
29743
30298
|
}
|
|
29744
30299
|
}
|
|
30300
|
+
} else {
|
|
30301
|
+
setCategoryMetadata([]);
|
|
30302
|
+
categoryMetadataRef.current = [];
|
|
29745
30303
|
}
|
|
29746
30304
|
} catch (error2) {
|
|
29747
30305
|
console.error(`[BottlenecksContent] Error loading category metadata:`, error2);
|
|
30306
|
+
} finally {
|
|
30307
|
+
setIsCategoryLoading(false);
|
|
29748
30308
|
}
|
|
29749
|
-
}, [workspaceId, date, effectiveShift, isPercentileCategory, metadataCache, s3ClipsService]);
|
|
30309
|
+
}, [workspaceId, date, effectiveShift, isPercentileCategory, metadataCache, s3ClipsService, timezone, clearLoadingState]);
|
|
29750
30310
|
const loadAndPlayClipById = React23.useCallback(async (clipId, categoryId, position) => {
|
|
29751
30311
|
if (!workspaceId || !s3ClipsService || !isMountedRef.current) return;
|
|
29752
30312
|
console.log(`[BottlenecksContent] Loading clip by ID: ${clipId}, category=${categoryId}, position=${position}`);
|
|
@@ -29770,21 +30330,31 @@ var BottlenecksContent = ({
|
|
|
29770
30330
|
}
|
|
29771
30331
|
try {
|
|
29772
30332
|
await loadCategoryMetadata(categoryId, false);
|
|
29773
|
-
|
|
29774
|
-
|
|
29775
|
-
|
|
29776
|
-
|
|
29777
|
-
|
|
29778
|
-
|
|
29779
|
-
|
|
29780
|
-
|
|
29781
|
-
|
|
29782
|
-
|
|
29783
|
-
|
|
29784
|
-
|
|
29785
|
-
|
|
29786
|
-
|
|
29787
|
-
|
|
30333
|
+
let metadataArray = categoryMetadataRef.current;
|
|
30334
|
+
const clipExistsInMetadata = metadataArray.some((clip) => clip.clipId === clipId);
|
|
30335
|
+
if (metadataArray.length === 0 || !clipExistsInMetadata) {
|
|
30336
|
+
console.warn(`[BottlenecksContent] Clip ${clipId} not found in metadata for ${categoryId} (cache hit: ${metadataArray.length > 0}) - forcing refresh`);
|
|
30337
|
+
await loadCategoryMetadata(categoryId, false, true);
|
|
30338
|
+
metadataArray = categoryMetadataRef.current;
|
|
30339
|
+
}
|
|
30340
|
+
if (metadataArray.length === 0) {
|
|
30341
|
+
throw new Error(`No metadata available for category ${categoryId}`);
|
|
30342
|
+
}
|
|
30343
|
+
const clickedClipIndex = metadataArray.findIndex((clip) => clip.clipId === clipId);
|
|
30344
|
+
if (clickedClipIndex === -1) {
|
|
30345
|
+
throw new Error(`Clip ${clipId} not found after metadata refresh`);
|
|
30346
|
+
}
|
|
30347
|
+
setCurrentMetadataIndex(clickedClipIndex);
|
|
30348
|
+
currentMetadataIndexRef.current = clickedClipIndex;
|
|
30349
|
+
const video = await s3ClipsService.getClipById(clipId);
|
|
30350
|
+
if (video) {
|
|
30351
|
+
setPendingVideo(video);
|
|
30352
|
+
setCurrentClipId(clipId);
|
|
30353
|
+
setAllVideos([video]);
|
|
30354
|
+
setCurrentIndex(0);
|
|
30355
|
+
console.log(`[BottlenecksContent] Loaded clip ${clipId} (${clickedClipIndex + 1}/${metadataArray.length})`);
|
|
30356
|
+
} else {
|
|
30357
|
+
throw new Error(`Failed to load video data for clip ${clipId}`);
|
|
29788
30358
|
}
|
|
29789
30359
|
} catch (error2) {
|
|
29790
30360
|
console.error(`[BottlenecksContent] Error loading clip by ID (${clipId}):`, error2);
|
|
@@ -29798,7 +30368,7 @@ var BottlenecksContent = ({
|
|
|
29798
30368
|
clearLoadingState();
|
|
29799
30369
|
}
|
|
29800
30370
|
}
|
|
29801
|
-
}, [workspaceId, s3ClipsService,
|
|
30371
|
+
}, [workspaceId, s3ClipsService, updateActiveFilter, clearLoadingState, loadCategoryMetadata]);
|
|
29802
30372
|
React23.useCallback(async (categoryId, clipIndex) => {
|
|
29803
30373
|
console.warn("[BottlenecksContent] loadAndPlayClip is deprecated, use loadAndPlayClipById instead");
|
|
29804
30374
|
if (!workspaceId || !s3ClipsService || !isMountedRef.current) return;
|
|
@@ -29825,7 +30395,7 @@ var BottlenecksContent = ({
|
|
|
29825
30395
|
});
|
|
29826
30396
|
setIsNavigating(false);
|
|
29827
30397
|
}
|
|
29828
|
-
}, [workspaceId, s3ClipsService, date, effectiveShift, loadAndPlayClipById]);
|
|
30398
|
+
}, [workspaceId, s3ClipsService, date, effectiveShift, loadAndPlayClipById, timezone]);
|
|
29829
30399
|
const handleNext = React23.useCallback(async () => {
|
|
29830
30400
|
if (!isMountedRef.current) return;
|
|
29831
30401
|
const currentFilter = activeFilterRef.current;
|
|
@@ -29842,8 +30412,18 @@ var BottlenecksContent = ({
|
|
|
29842
30412
|
}
|
|
29843
30413
|
try {
|
|
29844
30414
|
const currentMetaIndex = currentMetadataIndexRef.current;
|
|
29845
|
-
|
|
30415
|
+
let metadataArray = categoryMetadataRef.current;
|
|
30416
|
+
if (metadataArray.length === 0) {
|
|
30417
|
+
console.log(`[handleNext] Metadata empty for ${currentFilter}, loading before navigation`);
|
|
30418
|
+
await loadCategoryMetadata(currentFilter, false);
|
|
30419
|
+
metadataArray = categoryMetadataRef.current;
|
|
30420
|
+
}
|
|
29846
30421
|
console.log(`[handleNext] Unified navigation: ${currentFilter}, metadata index: ${currentMetaIndex}/${metadataArray.length}`);
|
|
30422
|
+
if (metadataArray.length === 0) {
|
|
30423
|
+
console.warn("[handleNext] No metadata available after refresh - stopping navigation");
|
|
30424
|
+
clearLoadingState();
|
|
30425
|
+
return;
|
|
30426
|
+
}
|
|
29847
30427
|
if (currentMetaIndex < metadataArray.length - 1) {
|
|
29848
30428
|
const nextMetadataIndex = currentMetaIndex + 1;
|
|
29849
30429
|
const nextClipMeta = metadataArray[nextMetadataIndex];
|
|
@@ -29878,7 +30458,7 @@ var BottlenecksContent = ({
|
|
|
29878
30458
|
});
|
|
29879
30459
|
clearLoadingState();
|
|
29880
30460
|
}
|
|
29881
|
-
}, [clearLoadingState, s3ClipsService]);
|
|
30461
|
+
}, [clearLoadingState, s3ClipsService, loadCategoryMetadata]);
|
|
29882
30462
|
const handlePrevious = React23.useCallback(async () => {
|
|
29883
30463
|
if (!isMountedRef.current) return;
|
|
29884
30464
|
const currentFilter = activeFilterRef.current;
|
|
@@ -29895,8 +30475,18 @@ var BottlenecksContent = ({
|
|
|
29895
30475
|
}
|
|
29896
30476
|
try {
|
|
29897
30477
|
const currentMetaIndex = currentMetadataIndexRef.current;
|
|
29898
|
-
|
|
30478
|
+
let metadataArray = categoryMetadataRef.current;
|
|
30479
|
+
if (metadataArray.length === 0) {
|
|
30480
|
+
console.log(`[handlePrevious] Metadata empty for ${currentFilter}, loading before navigation`);
|
|
30481
|
+
await loadCategoryMetadata(currentFilter, false);
|
|
30482
|
+
metadataArray = categoryMetadataRef.current;
|
|
30483
|
+
}
|
|
29899
30484
|
console.log(`[handlePrevious] Unified navigation: ${currentFilter}, metadata index: ${currentMetaIndex}/${metadataArray.length}`);
|
|
30485
|
+
if (metadataArray.length === 0) {
|
|
30486
|
+
console.warn("[handlePrevious] No metadata available after refresh - stopping navigation");
|
|
30487
|
+
clearLoadingState();
|
|
30488
|
+
return;
|
|
30489
|
+
}
|
|
29900
30490
|
if (currentMetaIndex > 0) {
|
|
29901
30491
|
const prevMetadataIndex = currentMetaIndex - 1;
|
|
29902
30492
|
const prevClipMeta = metadataArray[prevMetadataIndex];
|
|
@@ -29927,7 +30517,7 @@ var BottlenecksContent = ({
|
|
|
29927
30517
|
});
|
|
29928
30518
|
clearLoadingState();
|
|
29929
30519
|
}
|
|
29930
|
-
}, [clearLoadingState, s3ClipsService]);
|
|
30520
|
+
}, [clearLoadingState, s3ClipsService, loadCategoryMetadata]);
|
|
29931
30521
|
const currentVideo = React23.useMemo(() => {
|
|
29932
30522
|
if (!filteredVideos || filteredVideos.length === 0 || currentIndex >= filteredVideos.length) {
|
|
29933
30523
|
return null;
|
|
@@ -30903,7 +31493,7 @@ function DiagnosisVideoModal({
|
|
|
30903
31493
|
}
|
|
30904
31494
|
loadClip();
|
|
30905
31495
|
}, [clipId, supabase, transformPlaylistUrls]);
|
|
30906
|
-
const
|
|
31496
|
+
const formatTime4 = (seconds) => {
|
|
30907
31497
|
const mins = Math.floor(seconds / 60);
|
|
30908
31498
|
const secs = Math.floor(seconds % 60);
|
|
30909
31499
|
return `${mins}:${secs.toString().padStart(2, "0")}`;
|
|
@@ -31095,9 +31685,9 @@ function DiagnosisVideoModal({
|
|
|
31095
31685
|
}
|
|
31096
31686
|
),
|
|
31097
31687
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-sm font-medium", children: [
|
|
31098
|
-
|
|
31688
|
+
formatTime4(currentTime),
|
|
31099
31689
|
" / ",
|
|
31100
|
-
|
|
31690
|
+
formatTime4(duration)
|
|
31101
31691
|
] }),
|
|
31102
31692
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
31103
31693
|
"input",
|
|
@@ -33068,7 +33658,7 @@ var LinePdfGenerator = ({
|
|
|
33068
33658
|
}
|
|
33069
33659
|
hourEndTime.setSeconds(0);
|
|
33070
33660
|
hourEndTime.setMilliseconds(0);
|
|
33071
|
-
const
|
|
33661
|
+
const formatTime4 = (date2) => {
|
|
33072
33662
|
return date2.toLocaleTimeString("en-IN", {
|
|
33073
33663
|
hour: "2-digit",
|
|
33074
33664
|
minute: "2-digit",
|
|
@@ -33076,7 +33666,7 @@ var LinePdfGenerator = ({
|
|
|
33076
33666
|
timeZone: "Asia/Kolkata"
|
|
33077
33667
|
});
|
|
33078
33668
|
};
|
|
33079
|
-
return `${
|
|
33669
|
+
return `${formatTime4(hourStartTime)} - ${formatTime4(hourEndTime)}`;
|
|
33080
33670
|
});
|
|
33081
33671
|
};
|
|
33082
33672
|
const hourlyTimeRanges = lineInfo.metrics.shift_start ? getHourlyTimeRanges(lineInfo.metrics.shift_start, lineInfo.metrics.shift_end) : [];
|
|
@@ -39662,7 +40252,7 @@ var AIAgentView = () => {
|
|
|
39662
40252
|
}
|
|
39663
40253
|
return formattedLines.join("");
|
|
39664
40254
|
};
|
|
39665
|
-
const
|
|
40255
|
+
const formatTime4 = (timestamp) => {
|
|
39666
40256
|
const date = new Date(timestamp);
|
|
39667
40257
|
return date.toLocaleTimeString([], {
|
|
39668
40258
|
hour: "2-digit",
|
|
@@ -40926,7 +41516,7 @@ var AIAgentView = () => {
|
|
|
40926
41516
|
}
|
|
40927
41517
|
),
|
|
40928
41518
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: `mt-1.5 sm:mt-2 flex items-center gap-2 text-xs text-gray-400 ${message.role === "user" ? "justify-end" : "justify-start"}`, children: [
|
|
40929
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { children:
|
|
41519
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: formatTime4(message.created_at) }),
|
|
40930
41520
|
message.role === "assistant" && message.id !== -1 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1", children: [
|
|
40931
41521
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-1 h-1 bg-gray-300 rounded-full" }),
|
|
40932
41522
|
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "Axel" })
|