@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.mjs
CHANGED
|
@@ -2896,8 +2896,8 @@ var AuthService = class {
|
|
|
2896
2896
|
"Authorization": `Bearer ${accessToken}`,
|
|
2897
2897
|
"Content-Type": "application/json"
|
|
2898
2898
|
},
|
|
2899
|
-
timeout:
|
|
2900
|
-
//
|
|
2899
|
+
timeout: 1e4,
|
|
2900
|
+
// 10 seconds
|
|
2901
2901
|
retries: 1,
|
|
2902
2902
|
silentErrors: false
|
|
2903
2903
|
// We want to know about auth errors
|
|
@@ -2934,8 +2934,8 @@ var AuthService = class {
|
|
|
2934
2934
|
"Authorization": `Bearer ${accessToken}`,
|
|
2935
2935
|
"Content-Type": "application/json"
|
|
2936
2936
|
},
|
|
2937
|
-
timeout:
|
|
2938
|
-
//
|
|
2937
|
+
timeout: 1e4,
|
|
2938
|
+
// 10 seconds
|
|
2939
2939
|
retries: 2,
|
|
2940
2940
|
// More retries for validation
|
|
2941
2941
|
silentErrors: true,
|
|
@@ -2967,8 +2967,8 @@ var AuthService = class {
|
|
|
2967
2967
|
"Authorization": `Bearer ${accessToken}`,
|
|
2968
2968
|
"Content-Type": "application/json"
|
|
2969
2969
|
},
|
|
2970
|
-
timeout:
|
|
2971
|
-
//
|
|
2970
|
+
timeout: 1e4,
|
|
2971
|
+
// 10 seconds
|
|
2972
2972
|
retries: 1,
|
|
2973
2973
|
silentErrors: false
|
|
2974
2974
|
}
|
|
@@ -10883,7 +10883,7 @@ function useDateFormatter() {
|
|
|
10883
10883
|
},
|
|
10884
10884
|
[defaultTimezone, defaultLocale, dateFormatOptions]
|
|
10885
10885
|
);
|
|
10886
|
-
const
|
|
10886
|
+
const formatTime4 = useCallback(
|
|
10887
10887
|
(date, formatString) => {
|
|
10888
10888
|
const dateObj = typeof date === "string" ? parseISO(date) : date;
|
|
10889
10889
|
if (!isValid(dateObj)) return "Invalid Time";
|
|
@@ -10914,7 +10914,7 @@ function useDateFormatter() {
|
|
|
10914
10914
|
}, []);
|
|
10915
10915
|
return {
|
|
10916
10916
|
formatDate,
|
|
10917
|
-
formatTime:
|
|
10917
|
+
formatTime: formatTime4,
|
|
10918
10918
|
formatDateTime,
|
|
10919
10919
|
getNow,
|
|
10920
10920
|
timezone: defaultTimezone || "UTC",
|
|
@@ -23070,7 +23070,7 @@ var OutputProgressChartComponent = ({
|
|
|
23070
23070
|
];
|
|
23071
23071
|
const COLORS = ["#00AB45", "#f3f4f6"];
|
|
23072
23072
|
const percentage = (currentOutput / targetOutput * 100).toFixed(1);
|
|
23073
|
-
return /* @__PURE__ */ jsx("div", { className: `w-full h-full flex items-center justify-center ${className}`, children: /* @__PURE__ */ jsxs("div", { className: "relative w-full aspect-square max-h-full", style: { maxWidth: "min(100%, 280px)" }, children: [
|
|
23073
|
+
return /* @__PURE__ */ jsx("div", { className: `w-full h-full flex items-center justify-center ${className}`, children: /* @__PURE__ */ jsxs("div", { className: "relative w-full aspect-square max-h-full", style: { maxWidth: "min(100%, 280px)", containerType: "inline-size" }, children: [
|
|
23074
23074
|
/* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsx(PieChart, { children: /* @__PURE__ */ jsx(
|
|
23075
23075
|
Pie,
|
|
23076
23076
|
{
|
|
@@ -23094,16 +23094,33 @@ var OutputProgressChartComponent = ({
|
|
|
23094
23094
|
))
|
|
23095
23095
|
}
|
|
23096
23096
|
) }) }),
|
|
23097
|
-
/* @__PURE__ */ jsx("div", { className: "absolute inset-0 flex flex-col items-center justify-center", children: /* @__PURE__ */ jsxs("div", { className: "text-center", children: [
|
|
23098
|
-
/* @__PURE__ */ jsxs(
|
|
23099
|
-
|
|
23100
|
-
|
|
23101
|
-
|
|
23102
|
-
|
|
23103
|
-
|
|
23104
|
-
|
|
23105
|
-
|
|
23106
|
-
|
|
23097
|
+
/* @__PURE__ */ jsx("div", { className: "absolute inset-0 flex flex-col items-center justify-center", children: /* @__PURE__ */ jsxs("div", { className: "text-center", style: { width: "100%", padding: "0 10%" }, children: [
|
|
23098
|
+
/* @__PURE__ */ jsxs(
|
|
23099
|
+
"div",
|
|
23100
|
+
{
|
|
23101
|
+
className: "font-bold text-gray-800",
|
|
23102
|
+
style: { fontSize: "clamp(1.25rem, 8cqw, 2.5rem)" },
|
|
23103
|
+
children: [
|
|
23104
|
+
percentage,
|
|
23105
|
+
"%"
|
|
23106
|
+
]
|
|
23107
|
+
}
|
|
23108
|
+
),
|
|
23109
|
+
/* @__PURE__ */ jsxs(
|
|
23110
|
+
"div",
|
|
23111
|
+
{
|
|
23112
|
+
className: "text-gray-500",
|
|
23113
|
+
style: {
|
|
23114
|
+
fontSize: "clamp(0.7rem, 3.5cqw, 1rem)",
|
|
23115
|
+
marginTop: "clamp(0.125rem, 1cqw, 0.5rem)"
|
|
23116
|
+
},
|
|
23117
|
+
children: [
|
|
23118
|
+
currentOutput,
|
|
23119
|
+
" / ",
|
|
23120
|
+
Math.round(targetOutput)
|
|
23121
|
+
]
|
|
23122
|
+
}
|
|
23123
|
+
)
|
|
23107
23124
|
] }) })
|
|
23108
23125
|
] }) });
|
|
23109
23126
|
};
|
|
@@ -23121,7 +23138,7 @@ var LargeOutputProgressChart = ({
|
|
|
23121
23138
|
];
|
|
23122
23139
|
const COLORS = ["#00AB45", "#f3f4f6"];
|
|
23123
23140
|
const percentage = (currentOutput / targetOutput * 100).toFixed(1);
|
|
23124
|
-
return /* @__PURE__ */ jsx("div", { className: `w-full h-full flex items-center justify-center ${className}`, children: /* @__PURE__ */ jsxs("div", { className: "relative w-full h-full", style: { minHeight: "100px", minWidth: "100px" }, children: [
|
|
23141
|
+
return /* @__PURE__ */ jsx("div", { className: `w-full h-full flex items-center justify-center ${className}`, children: /* @__PURE__ */ jsxs("div", { className: "relative w-full h-full", style: { minHeight: "100px", minWidth: "100px", containerType: "inline-size" }, children: [
|
|
23125
23142
|
/* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsx(PieChart, { children: /* @__PURE__ */ jsx(
|
|
23126
23143
|
Pie,
|
|
23127
23144
|
{
|
|
@@ -23145,16 +23162,40 @@ var LargeOutputProgressChart = ({
|
|
|
23145
23162
|
))
|
|
23146
23163
|
}
|
|
23147
23164
|
) }) }),
|
|
23148
|
-
/* @__PURE__ */ jsx("div", { className: "absolute inset-0 flex flex-col items-center justify-center", children: /* @__PURE__ */ jsxs("div", { className: "text-center", children: [
|
|
23149
|
-
/* @__PURE__ */ jsx(
|
|
23150
|
-
|
|
23151
|
-
|
|
23152
|
-
|
|
23153
|
-
|
|
23154
|
-
|
|
23155
|
-
|
|
23156
|
-
|
|
23157
|
-
|
|
23165
|
+
/* @__PURE__ */ jsx("div", { className: "absolute inset-0 flex flex-col items-center justify-center", children: /* @__PURE__ */ jsxs("div", { className: "text-center", style: { width: "100%", padding: "0 10%" }, children: [
|
|
23166
|
+
/* @__PURE__ */ jsx(
|
|
23167
|
+
"div",
|
|
23168
|
+
{
|
|
23169
|
+
className: "font-bold text-gray-900",
|
|
23170
|
+
style: { fontSize: "clamp(1.5rem, 10cqw, 3rem)" },
|
|
23171
|
+
children: currentOutput
|
|
23172
|
+
}
|
|
23173
|
+
),
|
|
23174
|
+
/* @__PURE__ */ jsxs(
|
|
23175
|
+
"div",
|
|
23176
|
+
{
|
|
23177
|
+
className: "text-gray-500",
|
|
23178
|
+
style: { fontSize: "clamp(0.75rem, 3.5cqw, 1rem)" },
|
|
23179
|
+
children: [
|
|
23180
|
+
"of ",
|
|
23181
|
+
targetOutput
|
|
23182
|
+
]
|
|
23183
|
+
}
|
|
23184
|
+
),
|
|
23185
|
+
/* @__PURE__ */ jsxs(
|
|
23186
|
+
"div",
|
|
23187
|
+
{
|
|
23188
|
+
className: "font-medium text-gray-600",
|
|
23189
|
+
style: {
|
|
23190
|
+
fontSize: "clamp(0.875rem, 4.5cqw, 1.25rem)",
|
|
23191
|
+
marginTop: "clamp(0.125rem, 1cqw, 0.5rem)"
|
|
23192
|
+
},
|
|
23193
|
+
children: [
|
|
23194
|
+
percentage,
|
|
23195
|
+
"%"
|
|
23196
|
+
]
|
|
23197
|
+
}
|
|
23198
|
+
)
|
|
23158
23199
|
] }) })
|
|
23159
23200
|
] }) });
|
|
23160
23201
|
};
|
|
@@ -23859,7 +23900,7 @@ var HourlyOutputChartComponent = ({
|
|
|
23859
23900
|
endHour = Math.floor(endDecimalHour) % 24;
|
|
23860
23901
|
endMinute = Math.round(endDecimalHour % 1 * 60);
|
|
23861
23902
|
}
|
|
23862
|
-
const
|
|
23903
|
+
const formatTime4 = (h, m) => {
|
|
23863
23904
|
const period = h >= 12 ? "PM" : "AM";
|
|
23864
23905
|
const hour12 = h === 0 ? 12 : h > 12 ? h - 12 : h;
|
|
23865
23906
|
if (m === 0) {
|
|
@@ -23867,7 +23908,7 @@ var HourlyOutputChartComponent = ({
|
|
|
23867
23908
|
}
|
|
23868
23909
|
return `${hour12}:${m.toString().padStart(2, "0")}${period}`;
|
|
23869
23910
|
};
|
|
23870
|
-
return `${
|
|
23911
|
+
return `${formatTime4(startHour, startMinute)}-${formatTime4(endHour, endMinute)}`;
|
|
23871
23912
|
}, [shiftStartTime.decimalHour, SHIFT_DURATION, shiftEndTime]);
|
|
23872
23913
|
const formatTimeRange = React23__default.useCallback((hourIndex) => {
|
|
23873
23914
|
const isLastHour = hourIndex === SHIFT_DURATION - 1;
|
|
@@ -23883,12 +23924,12 @@ var HourlyOutputChartComponent = ({
|
|
|
23883
23924
|
endHour = Math.floor(endDecimalHour) % 24;
|
|
23884
23925
|
endMinute = Math.round(endDecimalHour % 1 * 60);
|
|
23885
23926
|
}
|
|
23886
|
-
const
|
|
23927
|
+
const formatTime4 = (h, m) => {
|
|
23887
23928
|
const period = h >= 12 ? "PM" : "AM";
|
|
23888
23929
|
const hour12 = h === 0 ? 12 : h > 12 ? h - 12 : h;
|
|
23889
23930
|
return `${hour12}:${m.toString().padStart(2, "0")} ${period}`;
|
|
23890
23931
|
};
|
|
23891
|
-
return `${
|
|
23932
|
+
return `${formatTime4(startHour, startMinute)} - ${formatTime4(endHour, endMinute)}`;
|
|
23892
23933
|
}, [shiftStartTime.decimalHour, SHIFT_DURATION, shiftEndTime]);
|
|
23893
23934
|
const chartData = React23__default.useMemo(() => {
|
|
23894
23935
|
return Array.from({ length: SHIFT_DURATION }, (_, i) => {
|
|
@@ -25059,7 +25100,7 @@ var SOPComplianceChart = ({
|
|
|
25059
25100
|
}
|
|
25060
25101
|
};
|
|
25061
25102
|
}, [data, animateToNewData, mockData]);
|
|
25062
|
-
const
|
|
25103
|
+
const formatTime4 = (minuteIndex) => {
|
|
25063
25104
|
const totalMinutes = shiftStartHour * 60 + minuteIndex;
|
|
25064
25105
|
const hours = Math.floor(totalMinutes / 60) % 24;
|
|
25065
25106
|
const minutes = totalMinutes % 60;
|
|
@@ -25071,7 +25112,7 @@ var SOPComplianceChart = ({
|
|
|
25071
25112
|
const hasDataForMinute = index < animatedData.length - 10;
|
|
25072
25113
|
return {
|
|
25073
25114
|
minute: index,
|
|
25074
|
-
time:
|
|
25115
|
+
time: formatTime4(index),
|
|
25075
25116
|
compliance: hasDataForMinute ? animatedData[index] : null
|
|
25076
25117
|
};
|
|
25077
25118
|
});
|
|
@@ -25248,7 +25289,7 @@ var GaugeChart = ({
|
|
|
25248
25289
|
};
|
|
25249
25290
|
const gaugeColor = getColor();
|
|
25250
25291
|
const targetAngle = target !== void 0 ? 180 - (target - min) / (max - min) * 180 : null;
|
|
25251
|
-
return /* @__PURE__ */ jsx("div", { className: `relative w-full h-full flex flex-col items-center justify-center ${className}`, children: /* @__PURE__ */ jsxs("div", { className: "relative w-full max-w-[280px] aspect-square", style: { minHeight: "100px", minWidth: "100px" }, children: [
|
|
25292
|
+
return /* @__PURE__ */ jsx("div", { className: `relative w-full h-full flex flex-col items-center justify-center ${className}`, children: /* @__PURE__ */ jsxs("div", { className: "relative w-full max-w-[280px] aspect-square", style: { minHeight: "100px", minWidth: "100px", containerType: "inline-size" }, children: [
|
|
25252
25293
|
/* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsx(PieChart, { children: /* @__PURE__ */ jsxs(
|
|
25253
25294
|
Pie,
|
|
25254
25295
|
{
|
|
@@ -25281,17 +25322,44 @@ var GaugeChart = ({
|
|
|
25281
25322
|
children: /* @__PURE__ */ jsx("div", { className: "absolute -top-1 -left-1.5 w-3 h-3 bg-gray-800 rounded-full" })
|
|
25282
25323
|
}
|
|
25283
25324
|
),
|
|
25284
|
-
/* @__PURE__ */ jsx("div", { className: "absolute inset-0 flex flex-col items-center justify-center", children: /* @__PURE__ */ jsxs("div", { className: "text-center", children: [
|
|
25285
|
-
/* @__PURE__ */ jsxs(
|
|
25286
|
-
|
|
25287
|
-
|
|
25288
|
-
|
|
25289
|
-
|
|
25290
|
-
|
|
25291
|
-
|
|
25292
|
-
|
|
25293
|
-
|
|
25294
|
-
|
|
25325
|
+
/* @__PURE__ */ jsx("div", { className: "absolute inset-0 flex flex-col items-center justify-center", children: /* @__PURE__ */ jsxs("div", { className: "text-center", style: { width: "100%", padding: "0 10%" }, children: [
|
|
25326
|
+
/* @__PURE__ */ jsxs(
|
|
25327
|
+
"div",
|
|
25328
|
+
{
|
|
25329
|
+
className: "font-bold text-gray-800",
|
|
25330
|
+
style: { fontSize: "clamp(1.25rem, 8cqw, 2rem)" },
|
|
25331
|
+
children: [
|
|
25332
|
+
value.toFixed(unit === "%" ? 1 : 0),
|
|
25333
|
+
unit
|
|
25334
|
+
]
|
|
25335
|
+
}
|
|
25336
|
+
),
|
|
25337
|
+
/* @__PURE__ */ jsx(
|
|
25338
|
+
"div",
|
|
25339
|
+
{
|
|
25340
|
+
className: "text-gray-600 font-medium",
|
|
25341
|
+
style: {
|
|
25342
|
+
fontSize: "clamp(0.75rem, 3.5cqw, 1rem)",
|
|
25343
|
+
marginTop: "clamp(0.125rem, 1cqw, 0.25rem)"
|
|
25344
|
+
},
|
|
25345
|
+
children: label
|
|
25346
|
+
}
|
|
25347
|
+
),
|
|
25348
|
+
target !== void 0 && /* @__PURE__ */ jsxs(
|
|
25349
|
+
"div",
|
|
25350
|
+
{
|
|
25351
|
+
className: "text-gray-500",
|
|
25352
|
+
style: {
|
|
25353
|
+
fontSize: "clamp(0.7rem, 3cqw, 0.875rem)",
|
|
25354
|
+
marginTop: "clamp(0.125rem, 1cqw, 0.25rem)"
|
|
25355
|
+
},
|
|
25356
|
+
children: [
|
|
25357
|
+
"Target: ",
|
|
25358
|
+
target,
|
|
25359
|
+
unit
|
|
25360
|
+
]
|
|
25361
|
+
}
|
|
25362
|
+
)
|
|
25295
25363
|
] }) }),
|
|
25296
25364
|
/* @__PURE__ */ jsxs("div", { className: "absolute bottom-[15%] left-[15%] text-xs text-gray-500", children: [
|
|
25297
25365
|
min,
|
|
@@ -25478,7 +25546,7 @@ var DateTimeDisplay = ({
|
|
|
25478
25546
|
const {
|
|
25479
25547
|
defaultTimezone
|
|
25480
25548
|
} = useDateTimeConfig();
|
|
25481
|
-
const { formatDate, formatTime:
|
|
25549
|
+
const { formatDate, formatTime: formatTime4 } = useDateFormatter();
|
|
25482
25550
|
const [now2, setNow] = useState(() => getCurrentTimeInZone(defaultTimezone || "UTC"));
|
|
25483
25551
|
useEffect(() => {
|
|
25484
25552
|
const timerId = setInterval(() => {
|
|
@@ -25490,7 +25558,7 @@ var DateTimeDisplay = ({
|
|
|
25490
25558
|
return null;
|
|
25491
25559
|
}
|
|
25492
25560
|
const formattedDate = showDate ? formatDate(now2) : "";
|
|
25493
|
-
const formattedTime = showTime ?
|
|
25561
|
+
const formattedTime = showTime ? formatTime4(now2) : "";
|
|
25494
25562
|
return /* @__PURE__ */ jsxs("div", { className: clsx_default("flex items-center space-x-2 text-sm text-gray-700 dark:text-gray-300", className), children: [
|
|
25495
25563
|
showDate && /* @__PURE__ */ jsx("span", { className: "date-display", "aria-label": `Current date: ${formattedDate}`, children: formattedDate }),
|
|
25496
25564
|
showDate && showTime && formattedDate && formattedTime && /* @__PURE__ */ jsx("span", { className: "separator", "aria-hidden": "true", children: "|" }),
|
|
@@ -25654,7 +25722,7 @@ var BreakNotificationPopup = ({
|
|
|
25654
25722
|
const handlePrevious = () => {
|
|
25655
25723
|
setCurrentIndex((prev) => (prev - 1 + visibleBreaks.length) % visibleBreaks.length);
|
|
25656
25724
|
};
|
|
25657
|
-
const
|
|
25725
|
+
const formatTime4 = (minutes) => {
|
|
25658
25726
|
const hours = Math.floor(minutes / 60);
|
|
25659
25727
|
const mins = minutes % 60;
|
|
25660
25728
|
if (hours > 0) {
|
|
@@ -25728,9 +25796,9 @@ var BreakNotificationPopup = ({
|
|
|
25728
25796
|
formatTo12Hour(currentBreak.endTime)
|
|
25729
25797
|
] }),
|
|
25730
25798
|
/* @__PURE__ */ jsxs("p", { className: "text-xs text-gray-500 mb-2", children: [
|
|
25731
|
-
|
|
25799
|
+
formatTime4(currentBreak.elapsedMinutes),
|
|
25732
25800
|
" elapsed of ",
|
|
25733
|
-
|
|
25801
|
+
formatTime4(currentBreak.duration),
|
|
25734
25802
|
" total"
|
|
25735
25803
|
] }),
|
|
25736
25804
|
/* @__PURE__ */ jsx("div", { className: "w-full bg-gray-200 rounded-full h-1.5", children: /* @__PURE__ */ jsx(
|
|
@@ -26034,64 +26102,208 @@ var getSeverityColor = (severity) => {
|
|
|
26034
26102
|
return "bg-gray-500";
|
|
26035
26103
|
}
|
|
26036
26104
|
};
|
|
26037
|
-
var
|
|
26038
|
-
|
|
26105
|
+
var formatTime2 = (seconds) => {
|
|
26106
|
+
if (!seconds || isNaN(seconds)) return "0:00";
|
|
26107
|
+
const h = Math.floor(seconds / 3600);
|
|
26108
|
+
const m = Math.floor(seconds % 3600 / 60);
|
|
26109
|
+
const s = Math.floor(seconds % 60);
|
|
26110
|
+
if (h > 0) {
|
|
26111
|
+
return `${h}:${m.toString().padStart(2, "0")}:${s.toString().padStart(2, "0")}`;
|
|
26112
|
+
}
|
|
26113
|
+
return `${m}:${s.toString().padStart(2, "0")}`;
|
|
26114
|
+
};
|
|
26115
|
+
var VideoControls = ({
|
|
26039
26116
|
isPlaying,
|
|
26040
|
-
|
|
26117
|
+
currentTime,
|
|
26118
|
+
duration,
|
|
26119
|
+
buffered,
|
|
26120
|
+
showControls,
|
|
26121
|
+
controlsPinned = false,
|
|
26122
|
+
onTogglePinControls,
|
|
26123
|
+
playbackRate = 1,
|
|
26124
|
+
onPlayPause,
|
|
26125
|
+
onSeek,
|
|
26126
|
+
onSeekStart,
|
|
26127
|
+
onSeekEnd,
|
|
26128
|
+
onToggleFullscreen,
|
|
26129
|
+
onPlaybackRateChange,
|
|
26130
|
+
className = ""
|
|
26041
26131
|
}) => {
|
|
26042
|
-
const [
|
|
26043
|
-
const [
|
|
26132
|
+
const [isDragging, setIsDragging] = useState(false);
|
|
26133
|
+
const [dragTime, setDragTime] = useState(0);
|
|
26134
|
+
const [isHoveringProgressBar, setIsHoveringProgressBar] = useState(false);
|
|
26135
|
+
const [showSpeedMenu, setShowSpeedMenu] = useState(false);
|
|
26136
|
+
const speedMenuRef = useRef(null);
|
|
26137
|
+
const progressColor = "#4b5563";
|
|
26138
|
+
const controlsVisible = showControls || controlsPinned;
|
|
26139
|
+
const getPercentage = (current, total) => {
|
|
26140
|
+
if (!total || total === 0) return 0;
|
|
26141
|
+
return Math.min(Math.max(current / total * 100, 0), 100);
|
|
26142
|
+
};
|
|
26143
|
+
const handleSeekChange = (e) => {
|
|
26144
|
+
const newTime = parseFloat(e.target.value);
|
|
26145
|
+
setDragTime(newTime);
|
|
26146
|
+
onSeek(newTime);
|
|
26147
|
+
};
|
|
26148
|
+
const handleSeekStart = () => {
|
|
26149
|
+
setIsDragging(true);
|
|
26150
|
+
setDragTime(currentTime);
|
|
26151
|
+
onSeekStart?.();
|
|
26152
|
+
};
|
|
26153
|
+
const handleSeekEnd = () => {
|
|
26154
|
+
setIsDragging(false);
|
|
26155
|
+
onSeekEnd?.();
|
|
26156
|
+
};
|
|
26044
26157
|
useEffect(() => {
|
|
26045
|
-
|
|
26046
|
-
|
|
26047
|
-
|
|
26048
|
-
|
|
26049
|
-
|
|
26050
|
-
|
|
26051
|
-
|
|
26052
|
-
|
|
26053
|
-
|
|
26054
|
-
|
|
26055
|
-
|
|
26056
|
-
|
|
26057
|
-
|
|
26058
|
-
|
|
26059
|
-
}
|
|
26060
|
-
}, [show, duration]);
|
|
26061
|
-
if (!isVisible) return null;
|
|
26062
|
-
return /* @__PURE__ */ jsx(
|
|
26158
|
+
const handleClickOutside = (event) => {
|
|
26159
|
+
if (speedMenuRef.current && !speedMenuRef.current.contains(event.target)) {
|
|
26160
|
+
setShowSpeedMenu(false);
|
|
26161
|
+
}
|
|
26162
|
+
};
|
|
26163
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
26164
|
+
return () => {
|
|
26165
|
+
document.removeEventListener("mousedown", handleClickOutside);
|
|
26166
|
+
};
|
|
26167
|
+
}, []);
|
|
26168
|
+
const displayTime = isDragging ? dragTime : currentTime;
|
|
26169
|
+
const progressPercent = getPercentage(displayTime, duration);
|
|
26170
|
+
const bufferedPercent = getPercentage(buffered, duration);
|
|
26171
|
+
return /* @__PURE__ */ jsxs(
|
|
26063
26172
|
"div",
|
|
26064
26173
|
{
|
|
26065
|
-
className:
|
|
26066
|
-
style: {
|
|
26067
|
-
|
|
26068
|
-
|
|
26069
|
-
|
|
26070
|
-
children: /* @__PURE__ */ jsx("div", { className: "bg-black/70 rounded-full p-6", children: isPlaying ? (
|
|
26071
|
-
// Play icon (triangle)
|
|
26072
|
-
/* @__PURE__ */ jsx(
|
|
26073
|
-
"svg",
|
|
26074
|
-
{
|
|
26075
|
-
xmlns: "http://www.w3.org/2000/svg",
|
|
26076
|
-
viewBox: "0 0 24 24",
|
|
26077
|
-
fill: "white",
|
|
26078
|
-
className: "w-16 h-16",
|
|
26079
|
-
children: /* @__PURE__ */ jsx("path", { d: "M8 5v14l11-7z" })
|
|
26080
|
-
}
|
|
26081
|
-
)
|
|
26082
|
-
) : (
|
|
26083
|
-
// Pause icon (two bars)
|
|
26084
|
-
/* @__PURE__ */ jsx(
|
|
26085
|
-
"svg",
|
|
26174
|
+
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}`,
|
|
26175
|
+
style: { touchAction: "none" },
|
|
26176
|
+
children: [
|
|
26177
|
+
/* @__PURE__ */ jsxs(
|
|
26178
|
+
"div",
|
|
26086
26179
|
{
|
|
26087
|
-
|
|
26088
|
-
|
|
26089
|
-
|
|
26090
|
-
|
|
26091
|
-
|
|
26180
|
+
className: "relative h-1 mb-4 group cursor-pointer",
|
|
26181
|
+
onMouseEnter: () => setIsHoveringProgressBar(true),
|
|
26182
|
+
onMouseLeave: () => setIsHoveringProgressBar(false),
|
|
26183
|
+
children: [
|
|
26184
|
+
/* @__PURE__ */ jsx("div", { className: "absolute -top-2 -bottom-2 left-0 right-0 z-20" }),
|
|
26185
|
+
/* @__PURE__ */ jsx("div", { className: "absolute top-0 left-0 right-0 bottom-0 bg-white/20 rounded-full overflow-hidden z-0", children: /* @__PURE__ */ jsx(
|
|
26186
|
+
"div",
|
|
26187
|
+
{
|
|
26188
|
+
className: "absolute top-0 left-0 bottom-0 bg-white/40 transition-all duration-200",
|
|
26189
|
+
style: { width: `${bufferedPercent}%` }
|
|
26190
|
+
}
|
|
26191
|
+
) }),
|
|
26192
|
+
/* @__PURE__ */ jsx(
|
|
26193
|
+
"div",
|
|
26194
|
+
{
|
|
26195
|
+
className: "absolute top-0 left-0 bottom-0 bg-[#007bff] transition-all duration-75 z-10",
|
|
26196
|
+
style: { width: `${progressPercent}%`, backgroundColor: progressColor },
|
|
26197
|
+
children: /* @__PURE__ */ jsx(
|
|
26198
|
+
"div",
|
|
26199
|
+
{
|
|
26200
|
+
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"}`,
|
|
26201
|
+
style: { backgroundColor: progressColor }
|
|
26202
|
+
}
|
|
26203
|
+
)
|
|
26204
|
+
}
|
|
26205
|
+
),
|
|
26206
|
+
/* @__PURE__ */ jsx(
|
|
26207
|
+
"input",
|
|
26208
|
+
{
|
|
26209
|
+
type: "range",
|
|
26210
|
+
min: "0",
|
|
26211
|
+
max: duration || 100,
|
|
26212
|
+
step: "0.1",
|
|
26213
|
+
value: displayTime,
|
|
26214
|
+
onChange: handleSeekChange,
|
|
26215
|
+
onMouseDown: handleSeekStart,
|
|
26216
|
+
onMouseUp: handleSeekEnd,
|
|
26217
|
+
onTouchStart: handleSeekStart,
|
|
26218
|
+
onTouchEnd: handleSeekEnd,
|
|
26219
|
+
className: "absolute inset-0 w-full h-full opacity-0 cursor-pointer z-30 margin-0 padding-0"
|
|
26220
|
+
}
|
|
26221
|
+
)
|
|
26222
|
+
]
|
|
26092
26223
|
}
|
|
26093
|
-
)
|
|
26094
|
-
|
|
26224
|
+
),
|
|
26225
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between text-white", children: [
|
|
26226
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-4", children: [
|
|
26227
|
+
/* @__PURE__ */ jsx(
|
|
26228
|
+
"button",
|
|
26229
|
+
{
|
|
26230
|
+
onClick: (e) => {
|
|
26231
|
+
e.stopPropagation();
|
|
26232
|
+
onPlayPause();
|
|
26233
|
+
},
|
|
26234
|
+
className: "hover:text-[#007bff] transition-colors focus:outline-none",
|
|
26235
|
+
"aria-label": isPlaying ? "Pause" : "Play",
|
|
26236
|
+
children: isPlaying ? /* @__PURE__ */ jsx("svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ jsx("path", { d: "M6 4h4v16H6V4zm8 0h4v16h-4V4z" }) }) : /* @__PURE__ */ jsx("svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ jsx("path", { d: "M8 5v14l11-7z" }) })
|
|
26237
|
+
}
|
|
26238
|
+
),
|
|
26239
|
+
/* @__PURE__ */ jsxs("div", { className: "text-xs font-medium font-sans", children: [
|
|
26240
|
+
/* @__PURE__ */ jsx("span", { children: formatTime2(displayTime) }),
|
|
26241
|
+
/* @__PURE__ */ jsx("span", { className: "mx-1 text-white/70", children: "/" }),
|
|
26242
|
+
/* @__PURE__ */ jsx("span", { className: "text-white/70", children: formatTime2(duration) })
|
|
26243
|
+
] })
|
|
26244
|
+
] }),
|
|
26245
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-4", children: [
|
|
26246
|
+
onTogglePinControls && /* @__PURE__ */ jsx(
|
|
26247
|
+
"button",
|
|
26248
|
+
{
|
|
26249
|
+
onClick: (e) => {
|
|
26250
|
+
e.stopPropagation();
|
|
26251
|
+
onTogglePinControls();
|
|
26252
|
+
},
|
|
26253
|
+
className: `transition-colors focus:outline-none ${controlsPinned ? "text-[#007bff]" : "hover:text-[#007bff]"}`,
|
|
26254
|
+
"aria-label": controlsPinned ? "Unpin controls" : "Pin controls",
|
|
26255
|
+
title: controlsPinned ? "Unpin controls" : "Pin controls",
|
|
26256
|
+
children: /* @__PURE__ */ jsx("svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24", fill: "currentColor", children: controlsPinned ? /* @__PURE__ */ jsx("path", { d: "M9 3h6l-1 7h3v2h-4.5l-.5 4.5-2 1L10 12H6v-2h3z" }) : /* @__PURE__ */ jsx("path", { d: "M9 3h6l-1 7h3v2h-4v5l-2 1-1-6H6v-2h3z" }) })
|
|
26257
|
+
}
|
|
26258
|
+
),
|
|
26259
|
+
onPlaybackRateChange && /* @__PURE__ */ jsxs("div", { className: "relative", ref: speedMenuRef, children: [
|
|
26260
|
+
/* @__PURE__ */ jsxs(
|
|
26261
|
+
"button",
|
|
26262
|
+
{
|
|
26263
|
+
onClick: (e) => {
|
|
26264
|
+
e.stopPropagation();
|
|
26265
|
+
setShowSpeedMenu(!showSpeedMenu);
|
|
26266
|
+
},
|
|
26267
|
+
className: "text-xs font-medium hover:text-[#007bff] transition-colors focus:outline-none min-w-[32px]",
|
|
26268
|
+
"aria-label": "Playback Speed",
|
|
26269
|
+
children: [
|
|
26270
|
+
playbackRate,
|
|
26271
|
+
"x"
|
|
26272
|
+
]
|
|
26273
|
+
}
|
|
26274
|
+
),
|
|
26275
|
+
showSpeedMenu && /* @__PURE__ */ 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__ */ jsxs(
|
|
26276
|
+
"button",
|
|
26277
|
+
{
|
|
26278
|
+
onClick: (e) => {
|
|
26279
|
+
e.stopPropagation();
|
|
26280
|
+
onPlaybackRateChange(rate);
|
|
26281
|
+
setShowSpeedMenu(false);
|
|
26282
|
+
},
|
|
26283
|
+
className: `block w-full text-left px-4 py-2 text-xs hover:bg-white/20 transition-colors ${playbackRate === rate ? "text-[#007bff] font-bold" : ""}`,
|
|
26284
|
+
children: [
|
|
26285
|
+
rate,
|
|
26286
|
+
"x"
|
|
26287
|
+
]
|
|
26288
|
+
},
|
|
26289
|
+
rate
|
|
26290
|
+
)) })
|
|
26291
|
+
] }),
|
|
26292
|
+
onToggleFullscreen && /* @__PURE__ */ jsx(
|
|
26293
|
+
"button",
|
|
26294
|
+
{
|
|
26295
|
+
onClick: (e) => {
|
|
26296
|
+
e.stopPropagation();
|
|
26297
|
+
onToggleFullscreen();
|
|
26298
|
+
},
|
|
26299
|
+
className: "hover:text-[#007bff] transition-colors focus:outline-none",
|
|
26300
|
+
"aria-label": "Toggle Fullscreen",
|
|
26301
|
+
children: /* @__PURE__ */ jsx("svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ jsx("path", { d: "M7 14H5v5h5v-2H7v-3zm-2-4h2V7h3V5H5v5zm12 7h-3v2h5v-5h-2v3zM14 5v2h3v3h2V5h-5z" }) })
|
|
26302
|
+
}
|
|
26303
|
+
)
|
|
26304
|
+
] })
|
|
26305
|
+
] })
|
|
26306
|
+
]
|
|
26095
26307
|
}
|
|
26096
26308
|
);
|
|
26097
26309
|
};
|
|
@@ -26219,9 +26431,15 @@ var HlsVideoPlayer = forwardRef(({
|
|
|
26219
26431
|
const blobUrlRef = useRef(null);
|
|
26220
26432
|
const [isReady, setIsReady] = useState(false);
|
|
26221
26433
|
const [isLoading, setIsLoading] = useState(true);
|
|
26222
|
-
const [
|
|
26223
|
-
const [
|
|
26224
|
-
const
|
|
26434
|
+
const [showControls, setShowControls] = useState(true);
|
|
26435
|
+
const [controlsPinned, setControlsPinned] = useState(false);
|
|
26436
|
+
const [isPlaying, setIsPlaying] = useState(false);
|
|
26437
|
+
const [currentTime, setCurrentTime] = useState(0);
|
|
26438
|
+
const [duration, setDuration] = useState(0);
|
|
26439
|
+
const [buffered, setBuffered] = useState(0);
|
|
26440
|
+
const [playbackRate, setPlaybackRate] = useState(1);
|
|
26441
|
+
const userSeekingRef = useRef(false);
|
|
26442
|
+
const controlsTimeoutRef = useRef(null);
|
|
26225
26443
|
const eventCallbacksRef = useRef({
|
|
26226
26444
|
onReady,
|
|
26227
26445
|
onPlay,
|
|
@@ -26400,8 +26618,6 @@ var HlsVideoPlayer = forwardRef(({
|
|
|
26400
26618
|
}
|
|
26401
26619
|
});
|
|
26402
26620
|
hls.on(Events.FRAG_LOADING, () => {
|
|
26403
|
-
setIsLoading(true);
|
|
26404
|
-
eventCallbacksRef.current.onLoadingChange?.(true);
|
|
26405
26621
|
});
|
|
26406
26622
|
hls.on(Events.FRAG_LOADED, () => {
|
|
26407
26623
|
setIsLoading(false);
|
|
@@ -26455,25 +26671,52 @@ var HlsVideoPlayer = forwardRef(({
|
|
|
26455
26671
|
const handleCanPlay = () => {
|
|
26456
26672
|
if (!hlsRef.current) {
|
|
26457
26673
|
setIsReady(true);
|
|
26458
|
-
onReady?.(player);
|
|
26459
26674
|
}
|
|
26675
|
+
setIsLoading(false);
|
|
26676
|
+
eventCallbacksRef.current.onLoadingChange?.(false);
|
|
26677
|
+
onReady?.(player);
|
|
26678
|
+
};
|
|
26679
|
+
const handlePlay = () => {
|
|
26680
|
+
setIsPlaying(true);
|
|
26681
|
+
eventCallbacksRef.current.onPlay?.(player);
|
|
26682
|
+
};
|
|
26683
|
+
const handlePause = () => {
|
|
26684
|
+
if (userSeekingRef.current && videoRef.current) {
|
|
26685
|
+
videoRef.current.play().catch((err) => console.warn("Auto-resume after seek pause failed:", err));
|
|
26686
|
+
return;
|
|
26687
|
+
}
|
|
26688
|
+
setIsPlaying(false);
|
|
26689
|
+
eventCallbacksRef.current.onPause?.(player);
|
|
26460
26690
|
};
|
|
26461
|
-
const handlePlay = () => eventCallbacksRef.current.onPlay?.(player);
|
|
26462
|
-
const handlePause = () => eventCallbacksRef.current.onPause?.(player);
|
|
26463
26691
|
const handlePlaying = () => {
|
|
26464
26692
|
setIsLoading(false);
|
|
26693
|
+
setIsPlaying(true);
|
|
26465
26694
|
eventCallbacksRef.current.onLoadingChange?.(false);
|
|
26466
26695
|
eventCallbacksRef.current.onPlaying?.(player);
|
|
26467
26696
|
};
|
|
26468
26697
|
const handleTimeUpdate = () => {
|
|
26469
26698
|
const currentTime2 = video.currentTime || 0;
|
|
26699
|
+
setCurrentTime(currentTime2);
|
|
26700
|
+
if (video.buffered.length > 0) {
|
|
26701
|
+
for (let i = 0; i < video.buffered.length; i++) {
|
|
26702
|
+
if (video.buffered.start(i) <= currentTime2 && video.buffered.end(i) >= currentTime2) {
|
|
26703
|
+
setBuffered(video.buffered.end(i));
|
|
26704
|
+
break;
|
|
26705
|
+
}
|
|
26706
|
+
}
|
|
26707
|
+
}
|
|
26470
26708
|
eventCallbacksRef.current.onTimeUpdate?.(player, currentTime2);
|
|
26471
26709
|
};
|
|
26472
26710
|
const handleDurationChange = () => {
|
|
26473
26711
|
const duration2 = video.duration || 0;
|
|
26712
|
+
setDuration(duration2);
|
|
26474
26713
|
eventCallbacksRef.current.onDurationChange?.(player, duration2);
|
|
26475
26714
|
};
|
|
26476
|
-
const handleEnded = () =>
|
|
26715
|
+
const handleEnded = () => {
|
|
26716
|
+
setIsPlaying(false);
|
|
26717
|
+
userSeekingRef.current = false;
|
|
26718
|
+
eventCallbacksRef.current.onEnded?.(player);
|
|
26719
|
+
};
|
|
26477
26720
|
const handleLoadStart = () => {
|
|
26478
26721
|
setIsLoading(true);
|
|
26479
26722
|
eventCallbacksRef.current.onLoadingChange?.(true);
|
|
@@ -26489,8 +26732,19 @@ var HlsVideoPlayer = forwardRef(({
|
|
|
26489
26732
|
setIsLoading(true);
|
|
26490
26733
|
eventCallbacksRef.current.onLoadingChange?.(true);
|
|
26491
26734
|
};
|
|
26492
|
-
const handleSeeking = () =>
|
|
26493
|
-
|
|
26735
|
+
const handleSeeking = () => {
|
|
26736
|
+
userSeekingRef.current = true;
|
|
26737
|
+
eventCallbacksRef.current.onSeeking?.(player);
|
|
26738
|
+
};
|
|
26739
|
+
const handleSeeked = () => {
|
|
26740
|
+
setIsLoading(false);
|
|
26741
|
+
eventCallbacksRef.current.onLoadingChange?.(false);
|
|
26742
|
+
if (videoRef.current) {
|
|
26743
|
+
videoRef.current.play().catch((err) => console.warn("Resume playback after seek failed:", err));
|
|
26744
|
+
}
|
|
26745
|
+
userSeekingRef.current = false;
|
|
26746
|
+
eventCallbacksRef.current.onSeeked?.(player);
|
|
26747
|
+
};
|
|
26494
26748
|
const handleError = () => {
|
|
26495
26749
|
const error = video.error;
|
|
26496
26750
|
if (error) {
|
|
@@ -26503,6 +26757,10 @@ var HlsVideoPlayer = forwardRef(({
|
|
|
26503
26757
|
eventCallbacksRef.current.onError?.(player, errorInfo);
|
|
26504
26758
|
}
|
|
26505
26759
|
};
|
|
26760
|
+
const handlePlaybackRateChange2 = (e) => {
|
|
26761
|
+
const target = e.target;
|
|
26762
|
+
setPlaybackRate(target.playbackRate);
|
|
26763
|
+
};
|
|
26506
26764
|
video.addEventListener("canplay", handleCanPlay);
|
|
26507
26765
|
video.addEventListener("play", handlePlay);
|
|
26508
26766
|
video.addEventListener("pause", handlePause);
|
|
@@ -26517,6 +26775,7 @@ var HlsVideoPlayer = forwardRef(({
|
|
|
26517
26775
|
video.addEventListener("seeking", handleSeeking);
|
|
26518
26776
|
video.addEventListener("seeked", handleSeeked);
|
|
26519
26777
|
video.addEventListener("error", handleError);
|
|
26778
|
+
video.addEventListener("ratechange", handlePlaybackRateChange2);
|
|
26520
26779
|
return () => {
|
|
26521
26780
|
video.removeEventListener("canplay", handleCanPlay);
|
|
26522
26781
|
video.removeEventListener("play", handlePlay);
|
|
@@ -26532,6 +26791,7 @@ var HlsVideoPlayer = forwardRef(({
|
|
|
26532
26791
|
video.removeEventListener("seeking", handleSeeking);
|
|
26533
26792
|
video.removeEventListener("seeked", handleSeeked);
|
|
26534
26793
|
video.removeEventListener("error", handleError);
|
|
26794
|
+
video.removeEventListener("ratechange", handlePlaybackRateChange2);
|
|
26535
26795
|
};
|
|
26536
26796
|
}, [
|
|
26537
26797
|
src,
|
|
@@ -26560,20 +26820,46 @@ var HlsVideoPlayer = forwardRef(({
|
|
|
26560
26820
|
}
|
|
26561
26821
|
}
|
|
26562
26822
|
}, [autoplay]);
|
|
26823
|
+
const resetControlsTimeout = useCallback(() => {
|
|
26824
|
+
if (controlsPinned) {
|
|
26825
|
+
setShowControls(true);
|
|
26826
|
+
return;
|
|
26827
|
+
}
|
|
26828
|
+
setShowControls(true);
|
|
26829
|
+
if (controlsTimeoutRef.current) {
|
|
26830
|
+
clearTimeout(controlsTimeoutRef.current);
|
|
26831
|
+
}
|
|
26832
|
+
if (isPlaying) {
|
|
26833
|
+
controlsTimeoutRef.current = setTimeout(() => {
|
|
26834
|
+
setShowControls(false);
|
|
26835
|
+
}, 3e3);
|
|
26836
|
+
}
|
|
26837
|
+
}, [isPlaying, controlsPinned]);
|
|
26838
|
+
const handleMouseMove = useCallback(() => {
|
|
26839
|
+
resetControlsTimeout();
|
|
26840
|
+
}, [resetControlsTimeout]);
|
|
26841
|
+
useEffect(() => {
|
|
26842
|
+
resetControlsTimeout();
|
|
26843
|
+
return () => {
|
|
26844
|
+
if (controlsTimeoutRef.current) {
|
|
26845
|
+
clearTimeout(controlsTimeoutRef.current);
|
|
26846
|
+
}
|
|
26847
|
+
};
|
|
26848
|
+
}, [isPlaying, resetControlsTimeout]);
|
|
26563
26849
|
const play = useCallback(() => {
|
|
26564
26850
|
return videoRef.current?.play();
|
|
26565
26851
|
}, []);
|
|
26566
26852
|
const pause = useCallback(() => {
|
|
26567
26853
|
videoRef.current?.pause();
|
|
26568
26854
|
}, []);
|
|
26569
|
-
const
|
|
26855
|
+
const currentTimeProp = useCallback((time2) => {
|
|
26570
26856
|
if (time2 !== void 0 && videoRef.current) {
|
|
26571
26857
|
videoRef.current.currentTime = time2;
|
|
26572
26858
|
return time2;
|
|
26573
26859
|
}
|
|
26574
26860
|
return videoRef.current?.currentTime || 0;
|
|
26575
26861
|
}, []);
|
|
26576
|
-
const
|
|
26862
|
+
const durationProp = useCallback(() => {
|
|
26577
26863
|
return videoRef.current?.duration || 0;
|
|
26578
26864
|
}, []);
|
|
26579
26865
|
const paused = useCallback(() => {
|
|
@@ -26586,95 +26872,144 @@ var HlsVideoPlayer = forwardRef(({
|
|
|
26586
26872
|
}
|
|
26587
26873
|
return videoRef.current?.muted ?? false;
|
|
26588
26874
|
}, []);
|
|
26589
|
-
const
|
|
26875
|
+
const volumeProp = useCallback((level) => {
|
|
26590
26876
|
if (level !== void 0 && videoRef.current) {
|
|
26591
26877
|
videoRef.current.volume = level;
|
|
26592
26878
|
return level;
|
|
26593
26879
|
}
|
|
26594
26880
|
return videoRef.current?.volume ?? 1;
|
|
26595
26881
|
}, []);
|
|
26596
|
-
const
|
|
26882
|
+
const playbackRateProp = useCallback((rate) => {
|
|
26597
26883
|
if (rate !== void 0 && videoRef.current) {
|
|
26598
26884
|
videoRef.current.playbackRate = rate;
|
|
26599
26885
|
return rate;
|
|
26600
26886
|
}
|
|
26601
26887
|
return videoRef.current?.playbackRate ?? 1;
|
|
26602
26888
|
}, []);
|
|
26889
|
+
const handleTogglePlay = useCallback(() => {
|
|
26890
|
+
if (videoRef.current) {
|
|
26891
|
+
if (videoRef.current.paused) {
|
|
26892
|
+
videoRef.current.play();
|
|
26893
|
+
} else {
|
|
26894
|
+
videoRef.current.pause();
|
|
26895
|
+
}
|
|
26896
|
+
}
|
|
26897
|
+
}, []);
|
|
26898
|
+
const handleSeek = useCallback((time2) => {
|
|
26899
|
+
if (videoRef.current) {
|
|
26900
|
+
videoRef.current.currentTime = time2;
|
|
26901
|
+
videoRef.current.play().catch((err) => console.warn("Resume playback failed during seek:", err));
|
|
26902
|
+
}
|
|
26903
|
+
}, []);
|
|
26904
|
+
const handleSeekStart = useCallback(() => {
|
|
26905
|
+
userSeekingRef.current = true;
|
|
26906
|
+
}, []);
|
|
26907
|
+
const handleSeekEnd = useCallback(() => {
|
|
26908
|
+
if (videoRef.current) {
|
|
26909
|
+
videoRef.current.play().catch((err) => console.warn("Resume playback failed after seek:", err));
|
|
26910
|
+
}
|
|
26911
|
+
}, []);
|
|
26912
|
+
const handlePlaybackRateChange = useCallback((rate) => {
|
|
26913
|
+
if (videoRef.current) {
|
|
26914
|
+
videoRef.current.playbackRate = rate;
|
|
26915
|
+
}
|
|
26916
|
+
}, []);
|
|
26917
|
+
const handleToggleFullscreen = useCallback(() => {
|
|
26918
|
+
if (videoContainerRef.current) {
|
|
26919
|
+
if (!document.fullscreenElement) {
|
|
26920
|
+
videoContainerRef.current.requestFullscreen();
|
|
26921
|
+
} else {
|
|
26922
|
+
document.exitFullscreen();
|
|
26923
|
+
}
|
|
26924
|
+
}
|
|
26925
|
+
}, []);
|
|
26603
26926
|
useImperativeHandle(ref, () => ({
|
|
26604
26927
|
hls: hlsRef.current,
|
|
26605
26928
|
video: videoRef.current,
|
|
26606
26929
|
play,
|
|
26607
26930
|
pause,
|
|
26608
|
-
currentTime,
|
|
26609
|
-
duration,
|
|
26931
|
+
currentTime: currentTimeProp,
|
|
26932
|
+
duration: durationProp,
|
|
26610
26933
|
paused,
|
|
26611
26934
|
mute,
|
|
26612
|
-
volume,
|
|
26613
|
-
playbackRate,
|
|
26935
|
+
volume: volumeProp,
|
|
26936
|
+
playbackRate: playbackRateProp,
|
|
26614
26937
|
dispose,
|
|
26615
26938
|
isReady,
|
|
26616
26939
|
// For backward compatibility with Video.js API
|
|
26617
26940
|
player: playerLikeObject()
|
|
26618
|
-
}), [play, pause,
|
|
26619
|
-
const
|
|
26620
|
-
if (!onClick
|
|
26621
|
-
|
|
26622
|
-
|
|
26623
|
-
|
|
26624
|
-
|
|
26625
|
-
|
|
26626
|
-
|
|
26627
|
-
|
|
26628
|
-
|
|
26629
|
-
|
|
26630
|
-
|
|
26631
|
-
|
|
26632
|
-
|
|
26633
|
-
|
|
26634
|
-
|
|
26635
|
-
|
|
26636
|
-
|
|
26637
|
-
"video",
|
|
26941
|
+
}), [play, pause, currentTimeProp, durationProp, paused, mute, volumeProp, playbackRateProp, dispose, isReady, playerLikeObject]);
|
|
26942
|
+
const handleContainerClick = useCallback(() => {
|
|
26943
|
+
if (!onClick && !controls) {
|
|
26944
|
+
handleTogglePlay();
|
|
26945
|
+
}
|
|
26946
|
+
if (onClick) {
|
|
26947
|
+
onClick();
|
|
26948
|
+
}
|
|
26949
|
+
}, [onClick, controls, handleTogglePlay]);
|
|
26950
|
+
return /* @__PURE__ */ jsxs(
|
|
26951
|
+
"div",
|
|
26952
|
+
{
|
|
26953
|
+
className: `hls-video-player-wrapper ${className} group`,
|
|
26954
|
+
style: { position: "relative", width: "100%", height: "100%" },
|
|
26955
|
+
onMouseMove: handleMouseMove,
|
|
26956
|
+
onMouseLeave: () => isPlaying && !controlsPinned && setShowControls(false),
|
|
26957
|
+
children: [
|
|
26958
|
+
/* @__PURE__ */ jsxs(
|
|
26959
|
+
"div",
|
|
26638
26960
|
{
|
|
26639
|
-
|
|
26640
|
-
|
|
26641
|
-
|
|
26642
|
-
|
|
26643
|
-
|
|
26644
|
-
|
|
26645
|
-
|
|
26646
|
-
|
|
26647
|
-
|
|
26961
|
+
className: "hls-video-player-container",
|
|
26962
|
+
ref: videoContainerRef,
|
|
26963
|
+
onClick: handleContainerClick,
|
|
26964
|
+
children: [
|
|
26965
|
+
/* @__PURE__ */ jsx(
|
|
26966
|
+
"video",
|
|
26967
|
+
{
|
|
26968
|
+
ref: videoRef,
|
|
26969
|
+
className: "hls-video-element",
|
|
26970
|
+
poster,
|
|
26971
|
+
controls: false,
|
|
26972
|
+
loop,
|
|
26973
|
+
muted,
|
|
26974
|
+
playsInline,
|
|
26975
|
+
autoPlay: autoplay,
|
|
26976
|
+
preload: "metadata"
|
|
26977
|
+
}
|
|
26978
|
+
),
|
|
26979
|
+
controls && /* @__PURE__ */ jsx(
|
|
26980
|
+
VideoControls,
|
|
26981
|
+
{
|
|
26982
|
+
isPlaying,
|
|
26983
|
+
currentTime,
|
|
26984
|
+
duration,
|
|
26985
|
+
buffered,
|
|
26986
|
+
showControls: controlsPinned || showControls || !isPlaying,
|
|
26987
|
+
controlsPinned,
|
|
26988
|
+
playbackRate,
|
|
26989
|
+
onPlayPause: handleTogglePlay,
|
|
26990
|
+
onSeek: handleSeek,
|
|
26991
|
+
onSeekStart: handleSeekStart,
|
|
26992
|
+
onSeekEnd: handleSeekEnd,
|
|
26993
|
+
onPlaybackRateChange: handlePlaybackRateChange,
|
|
26994
|
+
onTogglePinControls: () => setControlsPinned((prev) => {
|
|
26995
|
+
const next = !prev;
|
|
26996
|
+
if (next) {
|
|
26997
|
+
setShowControls(true);
|
|
26998
|
+
} else {
|
|
26999
|
+
resetControlsTimeout();
|
|
27000
|
+
}
|
|
27001
|
+
return next;
|
|
27002
|
+
}),
|
|
27003
|
+
onToggleFullscreen: handleToggleFullscreen
|
|
27004
|
+
}
|
|
27005
|
+
)
|
|
27006
|
+
]
|
|
26648
27007
|
}
|
|
26649
|
-
)
|
|
26650
|
-
|
|
26651
|
-
|
|
26652
|
-
|
|
26653
|
-
|
|
26654
|
-
"div",
|
|
26655
|
-
{
|
|
26656
|
-
onClick: handleClickWithIndicator,
|
|
26657
|
-
style: {
|
|
26658
|
-
position: "absolute",
|
|
26659
|
-
top: 0,
|
|
26660
|
-
left: 0,
|
|
26661
|
-
right: 0,
|
|
26662
|
-
bottom: 0,
|
|
26663
|
-
zIndex: 1,
|
|
26664
|
-
cursor: "pointer"
|
|
26665
|
-
},
|
|
26666
|
-
"aria-label": "Click to play/pause"
|
|
26667
|
-
}
|
|
26668
|
-
),
|
|
26669
|
-
onClick && !controls && /* @__PURE__ */ jsx(
|
|
26670
|
-
PlayPauseIndicator,
|
|
26671
|
-
{
|
|
26672
|
-
show: showIndicator,
|
|
26673
|
-
isPlaying: indicatorIsPlaying
|
|
26674
|
-
},
|
|
26675
|
-
indicatorKeyRef.current
|
|
26676
|
-
)
|
|
26677
|
-
] });
|
|
27008
|
+
),
|
|
27009
|
+
isLoading && !externalLoadingControl && /* @__PURE__ */ jsx("div", { className: "hls-video-player-loading", children: /* @__PURE__ */ jsx(OptifyeLogoLoader_default, { size: "md", message: "Loading video..." }) })
|
|
27010
|
+
]
|
|
27011
|
+
}
|
|
27012
|
+
);
|
|
26678
27013
|
});
|
|
26679
27014
|
HlsVideoPlayer.displayName = "HlsVideoPlayer";
|
|
26680
27015
|
var VideoPlayer = HlsVideoPlayer;
|
|
@@ -26682,6 +27017,7 @@ var CroppedHlsVideoPlayer = forwardRef(({
|
|
|
26682
27017
|
crop,
|
|
26683
27018
|
debug = false,
|
|
26684
27019
|
onClick,
|
|
27020
|
+
controls = true,
|
|
26685
27021
|
...videoProps
|
|
26686
27022
|
}, ref) => {
|
|
26687
27023
|
const {
|
|
@@ -26703,9 +27039,15 @@ var CroppedHlsVideoPlayer = forwardRef(({
|
|
|
26703
27039
|
const [isVideoReady, setIsVideoReady] = useState(false);
|
|
26704
27040
|
const [canvasDimensions, setCanvasDimensions] = useState({ width: 0, height: 0 });
|
|
26705
27041
|
const [isProcessing, setIsProcessing] = useState(false);
|
|
26706
|
-
const [
|
|
26707
|
-
const [
|
|
26708
|
-
const
|
|
27042
|
+
const [showControls, setShowControls] = useState(true);
|
|
27043
|
+
const [isPlaying, setIsPlaying] = useState(false);
|
|
27044
|
+
const [currentTime, setCurrentTime] = useState(0);
|
|
27045
|
+
const [duration, setDuration] = useState(0);
|
|
27046
|
+
const [buffered, setBuffered] = useState(0);
|
|
27047
|
+
const [playbackRate, setPlaybackRate] = useState(1);
|
|
27048
|
+
const controlsTimeoutRef = useRef(null);
|
|
27049
|
+
const userSeekingRef = useRef(false);
|
|
27050
|
+
const [controlsPinned, setControlsPinned] = useState(false);
|
|
26709
27051
|
const stopCanvasRendering = useCallback(() => {
|
|
26710
27052
|
if (animationFrameRef.current) {
|
|
26711
27053
|
cancelAnimationFrame(animationFrameRef.current);
|
|
@@ -26790,7 +27132,7 @@ var CroppedHlsVideoPlayer = forwardRef(({
|
|
|
26790
27132
|
const canvas = canvasRef.current;
|
|
26791
27133
|
const video = videoElementRef.current;
|
|
26792
27134
|
const ctx = canvas.getContext("2d");
|
|
26793
|
-
if (!ctx || video.
|
|
27135
|
+
if (!ctx || video.readyState < 2) {
|
|
26794
27136
|
return;
|
|
26795
27137
|
}
|
|
26796
27138
|
const videoWidth = video.videoWidth;
|
|
@@ -26817,7 +27159,9 @@ var CroppedHlsVideoPlayer = forwardRef(({
|
|
|
26817
27159
|
canvas.height
|
|
26818
27160
|
// Destination (full canvas)
|
|
26819
27161
|
);
|
|
26820
|
-
|
|
27162
|
+
if (!video.paused && !video.ended) {
|
|
27163
|
+
animationFrameRef.current = requestAnimationFrame(renderFrameToCanvas);
|
|
27164
|
+
}
|
|
26821
27165
|
}, [crop]);
|
|
26822
27166
|
const handleVideoReady = useCallback((player) => {
|
|
26823
27167
|
console.log("[CroppedHlsVideoPlayer] Video player ready");
|
|
@@ -26825,11 +27169,15 @@ var CroppedHlsVideoPlayer = forwardRef(({
|
|
|
26825
27169
|
if (videoEl) {
|
|
26826
27170
|
videoElementRef.current = videoEl;
|
|
26827
27171
|
setIsVideoReady(true);
|
|
27172
|
+
if (videoEl.readyState >= 2) {
|
|
27173
|
+
renderFrameToCanvas();
|
|
27174
|
+
}
|
|
26828
27175
|
}
|
|
26829
27176
|
onReadyProp?.(player);
|
|
26830
|
-
}, [onReadyProp]);
|
|
27177
|
+
}, [onReadyProp, renderFrameToCanvas]);
|
|
26831
27178
|
const handleVideoPlay = useCallback((player) => {
|
|
26832
27179
|
console.log("[CroppedHlsVideoPlayer] Video playing, starting canvas rendering");
|
|
27180
|
+
setIsPlaying(true);
|
|
26833
27181
|
if (crop && canvasRef.current) {
|
|
26834
27182
|
setIsProcessing(true);
|
|
26835
27183
|
renderFrameToCanvas();
|
|
@@ -26837,43 +27185,40 @@ var CroppedHlsVideoPlayer = forwardRef(({
|
|
|
26837
27185
|
onPlayProp?.(player);
|
|
26838
27186
|
}, [crop, renderFrameToCanvas, onPlayProp]);
|
|
26839
27187
|
const handleVideoPause = useCallback((player) => {
|
|
26840
|
-
console.log("[CroppedHlsVideoPlayer] Video paused, stopping canvas rendering
|
|
27188
|
+
console.log("[CroppedHlsVideoPlayer] Video paused, stopping canvas rendering (keeping last frame)");
|
|
27189
|
+
if (userSeekingRef.current && hiddenVideoRef.current) {
|
|
27190
|
+
hiddenVideoRef.current.play()?.catch(() => {
|
|
27191
|
+
});
|
|
27192
|
+
return;
|
|
27193
|
+
}
|
|
26841
27194
|
stopCanvasRendering();
|
|
26842
27195
|
setIsProcessing(false);
|
|
26843
|
-
|
|
26844
|
-
|
|
26845
|
-
if (ctx) {
|
|
26846
|
-
ctx.clearRect(0, 0, canvasRef.current.width, canvasRef.current.height);
|
|
26847
|
-
ctx.fillStyle = "black";
|
|
26848
|
-
ctx.fillRect(0, 0, canvasRef.current.width, canvasRef.current.height);
|
|
26849
|
-
}
|
|
26850
|
-
}
|
|
27196
|
+
setIsPlaying(false);
|
|
27197
|
+
renderFrameToCanvas();
|
|
26851
27198
|
onPauseProp?.(player);
|
|
26852
|
-
}, [stopCanvasRendering, onPauseProp]);
|
|
27199
|
+
}, [stopCanvasRendering, onPauseProp, renderFrameToCanvas]);
|
|
26853
27200
|
const handleVideoEnded = useCallback((player) => {
|
|
26854
|
-
console.log("[CroppedHlsVideoPlayer] Video ended,
|
|
27201
|
+
console.log("[CroppedHlsVideoPlayer] Video ended, stopping canvas rendering (keeping last frame)");
|
|
26855
27202
|
stopCanvasRendering();
|
|
26856
27203
|
setIsProcessing(false);
|
|
26857
|
-
|
|
26858
|
-
|
|
26859
|
-
if (ctx) {
|
|
26860
|
-
ctx.clearRect(0, 0, canvasRef.current.width, canvasRef.current.height);
|
|
26861
|
-
ctx.fillStyle = "black";
|
|
26862
|
-
ctx.fillRect(0, 0, canvasRef.current.width, canvasRef.current.height);
|
|
26863
|
-
}
|
|
26864
|
-
}
|
|
27204
|
+
setIsPlaying(false);
|
|
27205
|
+
userSeekingRef.current = false;
|
|
26865
27206
|
onEndedProp?.(player);
|
|
26866
27207
|
}, [stopCanvasRendering, onEndedProp]);
|
|
26867
27208
|
const handleSeeking = useCallback((player) => {
|
|
26868
27209
|
console.log("[CroppedHlsVideoPlayer] Video seeking");
|
|
26869
|
-
|
|
27210
|
+
userSeekingRef.current = true;
|
|
27211
|
+
if (crop) {
|
|
26870
27212
|
renderFrameToCanvas();
|
|
26871
27213
|
}
|
|
26872
27214
|
onSeekingProp?.(player);
|
|
26873
27215
|
}, [crop, renderFrameToCanvas, onSeekingProp]);
|
|
26874
27216
|
const handleSeeked = useCallback((player) => {
|
|
26875
27217
|
console.log("[CroppedHlsVideoPlayer] Video seeked");
|
|
26876
|
-
|
|
27218
|
+
hiddenVideoRef.current?.play()?.catch(() => {
|
|
27219
|
+
});
|
|
27220
|
+
userSeekingRef.current = false;
|
|
27221
|
+
if (crop) {
|
|
26877
27222
|
renderFrameToCanvas();
|
|
26878
27223
|
}
|
|
26879
27224
|
onSeekedProp?.(player);
|
|
@@ -26881,8 +27226,29 @@ var CroppedHlsVideoPlayer = forwardRef(({
|
|
|
26881
27226
|
const handleLoadedMetadata = useCallback((player) => {
|
|
26882
27227
|
console.log("[CroppedHlsVideoPlayer] Video metadata loaded");
|
|
26883
27228
|
calculateCanvasDimensions();
|
|
27229
|
+
if (hiddenVideoRef.current?.video) {
|
|
27230
|
+
setDuration(hiddenVideoRef.current.video.duration || 0);
|
|
27231
|
+
}
|
|
27232
|
+
requestAnimationFrame(() => renderFrameToCanvas());
|
|
26884
27233
|
onLoadedMetadataProp?.(player);
|
|
26885
|
-
}, [calculateCanvasDimensions, onLoadedMetadataProp]);
|
|
27234
|
+
}, [calculateCanvasDimensions, onLoadedMetadataProp, renderFrameToCanvas]);
|
|
27235
|
+
const handleTimeUpdate = useCallback((player, time2) => {
|
|
27236
|
+
setCurrentTime(time2);
|
|
27237
|
+
if (hiddenVideoRef.current?.video && hiddenVideoRef.current.video.buffered.length > 0) {
|
|
27238
|
+
const video = hiddenVideoRef.current.video;
|
|
27239
|
+
for (let i = 0; i < video.buffered.length; i++) {
|
|
27240
|
+
if (video.buffered.start(i) <= time2 && video.buffered.end(i) >= time2) {
|
|
27241
|
+
setBuffered(video.buffered.end(i));
|
|
27242
|
+
break;
|
|
27243
|
+
}
|
|
27244
|
+
}
|
|
27245
|
+
}
|
|
27246
|
+
videoProps.onTimeUpdate?.(player, time2);
|
|
27247
|
+
}, [videoProps.onTimeUpdate]);
|
|
27248
|
+
const handleDurationChange = useCallback((player, dur) => {
|
|
27249
|
+
setDuration(dur);
|
|
27250
|
+
videoProps.onDurationChange?.(player, dur);
|
|
27251
|
+
}, [videoProps.onDurationChange]);
|
|
26886
27252
|
useEffect(() => {
|
|
26887
27253
|
calculateCanvasDimensions();
|
|
26888
27254
|
const handleResize = () => {
|
|
@@ -26910,33 +27276,97 @@ var CroppedHlsVideoPlayer = forwardRef(({
|
|
|
26910
27276
|
stopCanvasRendering();
|
|
26911
27277
|
};
|
|
26912
27278
|
}, [stopCanvasRendering]);
|
|
27279
|
+
const resetControlsTimeout = useCallback(() => {
|
|
27280
|
+
if (controlsPinned) {
|
|
27281
|
+
setShowControls(true);
|
|
27282
|
+
return;
|
|
27283
|
+
}
|
|
27284
|
+
setShowControls(true);
|
|
27285
|
+
if (controlsTimeoutRef.current) {
|
|
27286
|
+
clearTimeout(controlsTimeoutRef.current);
|
|
27287
|
+
}
|
|
27288
|
+
if (isPlaying) {
|
|
27289
|
+
controlsTimeoutRef.current = setTimeout(() => {
|
|
27290
|
+
setShowControls(false);
|
|
27291
|
+
}, 3e3);
|
|
27292
|
+
}
|
|
27293
|
+
}, [isPlaying, controlsPinned]);
|
|
27294
|
+
const handleMouseMove = useCallback(() => {
|
|
27295
|
+
resetControlsTimeout();
|
|
27296
|
+
}, [resetControlsTimeout]);
|
|
27297
|
+
useEffect(() => {
|
|
27298
|
+
resetControlsTimeout();
|
|
27299
|
+
return () => {
|
|
27300
|
+
if (controlsTimeoutRef.current) {
|
|
27301
|
+
clearTimeout(controlsTimeoutRef.current);
|
|
27302
|
+
}
|
|
27303
|
+
};
|
|
27304
|
+
}, [isPlaying, resetControlsTimeout]);
|
|
27305
|
+
const handleTogglePlay = useCallback(() => {
|
|
27306
|
+
if (hiddenVideoRef.current?.video) {
|
|
27307
|
+
if (hiddenVideoRef.current.video.paused) {
|
|
27308
|
+
hiddenVideoRef.current.play();
|
|
27309
|
+
} else {
|
|
27310
|
+
hiddenVideoRef.current.pause();
|
|
27311
|
+
}
|
|
27312
|
+
}
|
|
27313
|
+
}, []);
|
|
27314
|
+
const handleSeek = useCallback((time2) => {
|
|
27315
|
+
if (hiddenVideoRef.current) {
|
|
27316
|
+
hiddenVideoRef.current.currentTime(time2);
|
|
27317
|
+
hiddenVideoRef.current.play()?.catch(() => {
|
|
27318
|
+
});
|
|
27319
|
+
setTimeout(() => renderFrameToCanvas(), 50);
|
|
27320
|
+
}
|
|
27321
|
+
}, [renderFrameToCanvas]);
|
|
27322
|
+
const handleSeekStart = useCallback(() => {
|
|
27323
|
+
userSeekingRef.current = true;
|
|
27324
|
+
}, []);
|
|
27325
|
+
const handleSeekEnd = useCallback(() => {
|
|
27326
|
+
if (hiddenVideoRef.current) {
|
|
27327
|
+
hiddenVideoRef.current.play()?.catch(() => {
|
|
27328
|
+
});
|
|
27329
|
+
}
|
|
27330
|
+
}, []);
|
|
27331
|
+
const handlePlaybackRateChange = useCallback((rate) => {
|
|
27332
|
+
if (hiddenVideoRef.current) {
|
|
27333
|
+
hiddenVideoRef.current.playbackRate(rate);
|
|
27334
|
+
setPlaybackRate(rate);
|
|
27335
|
+
}
|
|
27336
|
+
}, []);
|
|
27337
|
+
const handleToggleFullscreen = useCallback(() => {
|
|
27338
|
+
if (videoContainerRef.current) {
|
|
27339
|
+
if (!document.fullscreenElement) {
|
|
27340
|
+
videoContainerRef.current.requestFullscreen();
|
|
27341
|
+
} else {
|
|
27342
|
+
document.exitFullscreen();
|
|
27343
|
+
}
|
|
27344
|
+
}
|
|
27345
|
+
}, []);
|
|
26913
27346
|
if (!crop) {
|
|
26914
|
-
return /* @__PURE__ */ jsx(HlsVideoPlayer, { ref, ...videoProps, onClick });
|
|
26915
|
-
}
|
|
26916
|
-
const
|
|
26917
|
-
if (!onClick
|
|
26918
|
-
|
|
26919
|
-
|
|
26920
|
-
|
|
26921
|
-
setShowIndicator(false);
|
|
26922
|
-
setTimeout(() => {
|
|
26923
|
-
indicatorKeyRef.current += 1;
|
|
26924
|
-
setShowIndicator(true);
|
|
26925
|
-
}, 0);
|
|
26926
|
-
onClick();
|
|
27347
|
+
return /* @__PURE__ */ jsx(HlsVideoPlayer, { ref, ...videoProps, onClick, controls });
|
|
27348
|
+
}
|
|
27349
|
+
const handleClick = () => {
|
|
27350
|
+
if (!onClick && !controls) {
|
|
27351
|
+
handleTogglePlay();
|
|
27352
|
+
}
|
|
27353
|
+
if (onClick) onClick();
|
|
26927
27354
|
};
|
|
26928
27355
|
return /* @__PURE__ */ jsxs(
|
|
26929
27356
|
"div",
|
|
26930
27357
|
{
|
|
26931
27358
|
ref: videoContainerRef,
|
|
26932
|
-
className: `relative w-full h-full flex items-center justify-center bg-black ${onClick ? "cursor-pointer" : ""}
|
|
26933
|
-
onClick:
|
|
27359
|
+
className: `relative w-full h-full flex items-center justify-center bg-black group ${inheritedClassName} ${onClick || controls ? "cursor-pointer" : ""}`,
|
|
27360
|
+
onClick: handleClick,
|
|
27361
|
+
onMouseMove: handleMouseMove,
|
|
27362
|
+
onMouseLeave: () => isPlaying && !controlsPinned && setShowControls(false),
|
|
26934
27363
|
children: [
|
|
26935
27364
|
/* @__PURE__ */ jsx("div", { className: "hidden", children: /* @__PURE__ */ jsx(
|
|
26936
27365
|
HlsVideoPlayer,
|
|
26937
27366
|
{
|
|
26938
27367
|
ref: hiddenVideoRef,
|
|
26939
27368
|
...videoProps,
|
|
27369
|
+
controls: false,
|
|
26940
27370
|
onReady: handleVideoReady,
|
|
26941
27371
|
onPlay: handleVideoPlay,
|
|
26942
27372
|
onPause: handleVideoPause,
|
|
@@ -26946,7 +27376,9 @@ var CroppedHlsVideoPlayer = forwardRef(({
|
|
|
26946
27376
|
onLoadedMetadata: handleLoadedMetadata,
|
|
26947
27377
|
onLoadedData: videoProps.onLoadedData,
|
|
26948
27378
|
onPlaying: videoProps.onPlaying,
|
|
26949
|
-
onLoadingChange: videoProps.onLoadingChange
|
|
27379
|
+
onLoadingChange: videoProps.onLoadingChange,
|
|
27380
|
+
onTimeUpdate: handleTimeUpdate,
|
|
27381
|
+
onDurationChange: handleDurationChange
|
|
26950
27382
|
}
|
|
26951
27383
|
) }),
|
|
26952
27384
|
/* @__PURE__ */ jsx(
|
|
@@ -26963,8 +27395,8 @@ var CroppedHlsVideoPlayer = forwardRef(({
|
|
|
26963
27395
|
}
|
|
26964
27396
|
}
|
|
26965
27397
|
),
|
|
26966
|
-
!isVideoReady && /* @__PURE__ */ jsx("div", { className: "absolute inset-0 flex items-center justify-center", children: /* @__PURE__ */ jsx(OptifyeLogoLoader_default, { size: "md", message: "Loading video..." }) }),
|
|
26967
|
-
debug && isVideoReady && /* @__PURE__ */ jsxs("div", { className: "absolute top-2 left-2 bg-black/80 text-white text-xs p-2 rounded font-mono", children: [
|
|
27398
|
+
!isVideoReady && /* @__PURE__ */ jsx("div", { className: "absolute inset-0 flex items-center justify-center pointer-events-none", children: /* @__PURE__ */ jsx(OptifyeLogoLoader_default, { size: "md", message: "Loading video..." }) }),
|
|
27399
|
+
debug && isVideoReady && /* @__PURE__ */ 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: [
|
|
26968
27400
|
/* @__PURE__ */ jsxs("div", { children: [
|
|
26969
27401
|
"Crop: ",
|
|
26970
27402
|
crop.x,
|
|
@@ -26988,13 +27420,32 @@ var CroppedHlsVideoPlayer = forwardRef(({
|
|
|
26988
27420
|
isProcessing ? "Yes" : "No"
|
|
26989
27421
|
] })
|
|
26990
27422
|
] }),
|
|
26991
|
-
|
|
26992
|
-
|
|
27423
|
+
controls && isVideoReady && /* @__PURE__ */ jsx(
|
|
27424
|
+
VideoControls,
|
|
26993
27425
|
{
|
|
26994
|
-
|
|
26995
|
-
|
|
26996
|
-
|
|
26997
|
-
|
|
27426
|
+
isPlaying,
|
|
27427
|
+
currentTime,
|
|
27428
|
+
duration,
|
|
27429
|
+
buffered,
|
|
27430
|
+
showControls: controlsPinned || showControls || !isPlaying,
|
|
27431
|
+
controlsPinned,
|
|
27432
|
+
playbackRate,
|
|
27433
|
+
onPlayPause: handleTogglePlay,
|
|
27434
|
+
onSeek: handleSeek,
|
|
27435
|
+
onSeekStart: handleSeekStart,
|
|
27436
|
+
onSeekEnd: handleSeekEnd,
|
|
27437
|
+
onPlaybackRateChange: handlePlaybackRateChange,
|
|
27438
|
+
onTogglePinControls: () => setControlsPinned((prev) => {
|
|
27439
|
+
const next = !prev;
|
|
27440
|
+
if (next) {
|
|
27441
|
+
setShowControls(true);
|
|
27442
|
+
} else {
|
|
27443
|
+
resetControlsTimeout();
|
|
27444
|
+
}
|
|
27445
|
+
return next;
|
|
27446
|
+
}),
|
|
27447
|
+
onToggleFullscreen: handleToggleFullscreen
|
|
27448
|
+
}
|
|
26998
27449
|
)
|
|
26999
27450
|
]
|
|
27000
27451
|
}
|
|
@@ -27533,6 +27984,67 @@ var SilentErrorBoundary = class extends React23__default.Component {
|
|
|
27533
27984
|
] }) });
|
|
27534
27985
|
}
|
|
27535
27986
|
};
|
|
27987
|
+
var PlayPauseIndicator = ({
|
|
27988
|
+
show,
|
|
27989
|
+
isPlaying,
|
|
27990
|
+
duration = 600
|
|
27991
|
+
}) => {
|
|
27992
|
+
const [isVisible, setIsVisible] = useState(false);
|
|
27993
|
+
const [isFading, setIsFading] = useState(false);
|
|
27994
|
+
useEffect(() => {
|
|
27995
|
+
if (show) {
|
|
27996
|
+
setIsVisible(true);
|
|
27997
|
+
setIsFading(false);
|
|
27998
|
+
const fadeTimer = setTimeout(() => {
|
|
27999
|
+
setIsFading(true);
|
|
28000
|
+
}, 100);
|
|
28001
|
+
const hideTimer = setTimeout(() => {
|
|
28002
|
+
setIsVisible(false);
|
|
28003
|
+
setIsFading(false);
|
|
28004
|
+
}, duration);
|
|
28005
|
+
return () => {
|
|
28006
|
+
clearTimeout(fadeTimer);
|
|
28007
|
+
clearTimeout(hideTimer);
|
|
28008
|
+
};
|
|
28009
|
+
}
|
|
28010
|
+
}, [show, duration]);
|
|
28011
|
+
if (!isVisible) return null;
|
|
28012
|
+
return /* @__PURE__ */ jsx(
|
|
28013
|
+
"div",
|
|
28014
|
+
{
|
|
28015
|
+
className: "absolute inset-0 flex items-center justify-center pointer-events-none z-10",
|
|
28016
|
+
style: {
|
|
28017
|
+
opacity: isFading ? 0 : 1,
|
|
28018
|
+
transition: `opacity ${duration - 100}ms ease-out`
|
|
28019
|
+
},
|
|
28020
|
+
children: /* @__PURE__ */ jsx("div", { className: "bg-black/70 rounded-full p-6", children: isPlaying ? (
|
|
28021
|
+
// Play icon (triangle)
|
|
28022
|
+
/* @__PURE__ */ jsx(
|
|
28023
|
+
"svg",
|
|
28024
|
+
{
|
|
28025
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
28026
|
+
viewBox: "0 0 24 24",
|
|
28027
|
+
fill: "white",
|
|
28028
|
+
className: "w-16 h-16",
|
|
28029
|
+
children: /* @__PURE__ */ jsx("path", { d: "M8 5v14l11-7z" })
|
|
28030
|
+
}
|
|
28031
|
+
)
|
|
28032
|
+
) : (
|
|
28033
|
+
// Pause icon (two bars)
|
|
28034
|
+
/* @__PURE__ */ jsx(
|
|
28035
|
+
"svg",
|
|
28036
|
+
{
|
|
28037
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
28038
|
+
viewBox: "0 0 24 24",
|
|
28039
|
+
fill: "white",
|
|
28040
|
+
className: "w-16 h-16",
|
|
28041
|
+
children: /* @__PURE__ */ jsx("path", { d: "M6 4h4v16H6V4zm8 0h4v16h-4V4z" })
|
|
28042
|
+
}
|
|
28043
|
+
)
|
|
28044
|
+
) })
|
|
28045
|
+
}
|
|
28046
|
+
);
|
|
28047
|
+
};
|
|
27536
28048
|
var BackButton = ({
|
|
27537
28049
|
onClick,
|
|
27538
28050
|
text = "Back",
|
|
@@ -29185,6 +29697,31 @@ var BottlenecksContent = ({
|
|
|
29185
29697
|
const [categoryMetadata, setCategoryMetadata] = useState([]);
|
|
29186
29698
|
const [currentMetadataIndex, setCurrentMetadataIndex] = useState(0);
|
|
29187
29699
|
const [metadataCache, setMetadataCache] = useState({});
|
|
29700
|
+
const invalidateMetadataCache = useCallback((categories) => {
|
|
29701
|
+
setMetadataCache((prevCache) => {
|
|
29702
|
+
if (!prevCache || Object.keys(prevCache).length === 0) {
|
|
29703
|
+
return prevCache;
|
|
29704
|
+
}
|
|
29705
|
+
const targetCategories = categories ? (Array.isArray(categories) ? categories : [categories]).filter(Boolean) : null;
|
|
29706
|
+
let updatedCache = null;
|
|
29707
|
+
const shouldInvalidate = (key) => {
|
|
29708
|
+
if (!targetCategories || targetCategories.length === 0) {
|
|
29709
|
+
return true;
|
|
29710
|
+
}
|
|
29711
|
+
const [categoryId] = key.split("-");
|
|
29712
|
+
return targetCategories.includes(categoryId);
|
|
29713
|
+
};
|
|
29714
|
+
Object.keys(prevCache).forEach((cacheKey) => {
|
|
29715
|
+
if (shouldInvalidate(cacheKey)) {
|
|
29716
|
+
if (!updatedCache) {
|
|
29717
|
+
updatedCache = { ...prevCache };
|
|
29718
|
+
}
|
|
29719
|
+
delete updatedCache[cacheKey];
|
|
29720
|
+
}
|
|
29721
|
+
});
|
|
29722
|
+
return updatedCache || prevCache;
|
|
29723
|
+
});
|
|
29724
|
+
}, []);
|
|
29188
29725
|
const [triageClips, setTriageClips] = useState([]);
|
|
29189
29726
|
const [isLoadingTriageClips, setIsLoadingTriageClips] = useState(false);
|
|
29190
29727
|
const [isFullscreen, setIsFullscreen] = useState(false);
|
|
@@ -29204,6 +29741,12 @@ var BottlenecksContent = ({
|
|
|
29204
29741
|
onNewClips: (notification) => {
|
|
29205
29742
|
console.log(`[BottlenecksContent] New clips detected:`, notification);
|
|
29206
29743
|
if (notification.clips.length > 0) {
|
|
29744
|
+
const categoryIds = notification.clips.map((clip) => clip.clip_type).filter(Boolean).map((value) => String(value));
|
|
29745
|
+
if (categoryIds.length > 0) {
|
|
29746
|
+
invalidateMetadataCache(categoryIds);
|
|
29747
|
+
} else {
|
|
29748
|
+
invalidateMetadataCache();
|
|
29749
|
+
}
|
|
29207
29750
|
fetchClipCounts();
|
|
29208
29751
|
}
|
|
29209
29752
|
}
|
|
@@ -29250,24 +29793,37 @@ var BottlenecksContent = ({
|
|
|
29250
29793
|
shift: shift || "0"
|
|
29251
29794
|
});
|
|
29252
29795
|
useEffect(() => {
|
|
29253
|
-
if (clipTypes.length > 0
|
|
29254
|
-
const
|
|
29255
|
-
|
|
29256
|
-
|
|
29257
|
-
|
|
29258
|
-
|
|
29259
|
-
|
|
29260
|
-
|
|
29796
|
+
if (clipTypes.length > 0) {
|
|
29797
|
+
const currentFilterCount = initialFilter ? dynamicCounts[initialFilter] || 0 : 0;
|
|
29798
|
+
const hasAnyCounts = Object.values(dynamicCounts).some((c) => c > 0);
|
|
29799
|
+
const userHasNotNavigated = !initialFilter || activeFilterRef.current === initialFilter;
|
|
29800
|
+
const shouldRunSelection = !initialFilter || userHasNotNavigated && currentFilterCount === 0 && hasAnyCounts;
|
|
29801
|
+
if (shouldRunSelection) {
|
|
29802
|
+
let selectedType = null;
|
|
29803
|
+
if (clipTypes.length === 1) {
|
|
29804
|
+
selectedType = clipTypes[0];
|
|
29805
|
+
} else {
|
|
29806
|
+
const priorityOrder = ["cycle_completion", "fast-cycles", "slow-cycles", "idle_time"];
|
|
29807
|
+
for (const priorityType of priorityOrder) {
|
|
29808
|
+
const type = clipTypes.find((t) => t.type === priorityType && (dynamicCounts[t.type] || 0) > 0);
|
|
29809
|
+
if (type) {
|
|
29810
|
+
selectedType = type;
|
|
29811
|
+
break;
|
|
29812
|
+
}
|
|
29813
|
+
}
|
|
29814
|
+
if (!selectedType) {
|
|
29815
|
+
selectedType = clipTypes.find((type) => (dynamicCounts[type.type] || 0) > 0);
|
|
29816
|
+
}
|
|
29817
|
+
if (!selectedType) {
|
|
29818
|
+
selectedType = clipTypes[0];
|
|
29819
|
+
}
|
|
29820
|
+
}
|
|
29821
|
+
if (selectedType && selectedType.type !== initialFilter) {
|
|
29822
|
+
console.log(`[BottlenecksContent] Auto-selecting filter: ${selectedType.type} (count: ${dynamicCounts[selectedType.type] || 0})`);
|
|
29823
|
+
setInitialFilter(selectedType.type);
|
|
29824
|
+
setActiveFilter(selectedType.type);
|
|
29825
|
+
activeFilterRef.current = selectedType.type;
|
|
29261
29826
|
}
|
|
29262
|
-
}
|
|
29263
|
-
if (!selectedType) {
|
|
29264
|
-
selectedType = clipTypes.find((type) => (dynamicCounts[type.type] || 0) > 0);
|
|
29265
|
-
}
|
|
29266
|
-
const firstType = selectedType || clipTypes[0];
|
|
29267
|
-
if (firstType) {
|
|
29268
|
-
setInitialFilter(firstType.type);
|
|
29269
|
-
setActiveFilter(firstType.type);
|
|
29270
|
-
activeFilterRef.current = firstType.type;
|
|
29271
29827
|
}
|
|
29272
29828
|
}
|
|
29273
29829
|
}, [clipTypes, dynamicCounts, initialFilter]);
|
|
@@ -29319,7 +29875,7 @@ var BottlenecksContent = ({
|
|
|
29319
29875
|
} finally {
|
|
29320
29876
|
fetchInProgressRef.current.delete(operationKey);
|
|
29321
29877
|
}
|
|
29322
|
-
}, [workspaceId, date, s3ClipsService, effectiveShift, dashboardConfig, updateClipCounts]);
|
|
29878
|
+
}, [workspaceId, date, s3ClipsService, effectiveShift, dashboardConfig, updateClipCounts, timezone, totalOutput]);
|
|
29323
29879
|
const loadingCategoryRef = useRef(null);
|
|
29324
29880
|
const loadFirstVideoForCategory = useCallback(async (category) => {
|
|
29325
29881
|
if (!workspaceId || !s3ClipsService || !isMountedRef.current) return;
|
|
@@ -29409,15 +29965,16 @@ var BottlenecksContent = ({
|
|
|
29409
29965
|
loadingCategoryRef.current = null;
|
|
29410
29966
|
fetchInProgressRef.current.delete(operationKey);
|
|
29411
29967
|
}
|
|
29412
|
-
}, [workspaceId, date, s3ClipsService, mergedCounts, effectiveShift]);
|
|
29968
|
+
}, [workspaceId, date, s3ClipsService, mergedCounts, effectiveShift, timezone]);
|
|
29413
29969
|
const handleRefreshClips = useCallback(async () => {
|
|
29414
29970
|
console.log("[BottlenecksContent] Refreshing clips after new additions");
|
|
29415
29971
|
acknowledgeNewClips();
|
|
29972
|
+
invalidateMetadataCache();
|
|
29416
29973
|
await fetchClipCounts();
|
|
29417
29974
|
if (activeFilter && mergedCounts[activeFilter] > 0) {
|
|
29418
29975
|
await loadFirstVideoForCategory(activeFilter);
|
|
29419
29976
|
}
|
|
29420
|
-
}, [acknowledgeNewClips, fetchClipCounts, activeFilter, mergedCounts, loadFirstVideoForCategory]);
|
|
29977
|
+
}, [acknowledgeNewClips, fetchClipCounts, activeFilter, mergedCounts, loadFirstVideoForCategory, invalidateMetadataCache]);
|
|
29421
29978
|
useEffect(() => {
|
|
29422
29979
|
if (s3ClipsService) {
|
|
29423
29980
|
fetchClipCounts();
|
|
@@ -29587,38 +30144,38 @@ var BottlenecksContent = ({
|
|
|
29587
30144
|
loadingTimeoutRef.current = null;
|
|
29588
30145
|
}
|
|
29589
30146
|
}, []);
|
|
29590
|
-
const loadCategoryMetadata = useCallback(async (categoryId, autoLoadFirstVideo = false) => {
|
|
30147
|
+
const loadCategoryMetadata = useCallback(async (categoryId, autoLoadFirstVideo = false, forceRefresh = false) => {
|
|
29591
30148
|
if (!workspaceId) {
|
|
29592
30149
|
return;
|
|
29593
30150
|
}
|
|
29594
|
-
const
|
|
29595
|
-
|
|
29596
|
-
|
|
29597
|
-
|
|
29598
|
-
|
|
29599
|
-
|
|
29600
|
-
|
|
29601
|
-
|
|
29602
|
-
|
|
29603
|
-
|
|
29604
|
-
|
|
29605
|
-
|
|
29606
|
-
|
|
29607
|
-
|
|
29608
|
-
|
|
29609
|
-
|
|
29610
|
-
|
|
30151
|
+
const resolvedDate = date || getOperationalDate(timezone);
|
|
30152
|
+
const cacheKey = `${categoryId}-${resolvedDate}-${effectiveShift}`;
|
|
30153
|
+
const cachedMetadata = !forceRefresh ? metadataCache[cacheKey] : void 0;
|
|
30154
|
+
try {
|
|
30155
|
+
if (cachedMetadata) {
|
|
30156
|
+
console.log(`[BottlenecksContent] Using cached metadata for ${categoryId}`);
|
|
30157
|
+
setCategoryMetadata(cachedMetadata);
|
|
30158
|
+
categoryMetadataRef.current = cachedMetadata;
|
|
30159
|
+
if (autoLoadFirstVideo && cachedMetadata.length > 0 && s3ClipsService) {
|
|
30160
|
+
const firstClipMeta = cachedMetadata[0];
|
|
30161
|
+
try {
|
|
30162
|
+
const video = await s3ClipsService.getClipById(firstClipMeta.clipId);
|
|
30163
|
+
if (video && isMountedRef.current) {
|
|
30164
|
+
setCurrentClipId(firstClipMeta.clipId);
|
|
30165
|
+
setAllVideos([video]);
|
|
30166
|
+
setCurrentIndex(0);
|
|
30167
|
+
setCurrentMetadataIndex(0);
|
|
30168
|
+
currentMetadataIndexRef.current = 0;
|
|
30169
|
+
console.log(`[BottlenecksContent] Auto-loaded first video from cache: ${video.id} (1/${cachedMetadata.length})`);
|
|
30170
|
+
}
|
|
30171
|
+
} catch (error2) {
|
|
30172
|
+
console.error(`[BottlenecksContent] Error loading first video from cache:`, error2);
|
|
30173
|
+
clearLoadingState();
|
|
29611
30174
|
}
|
|
29612
|
-
} catch (error2) {
|
|
29613
|
-
console.error(`[BottlenecksContent] Error loading first video from cache:`, error2);
|
|
29614
|
-
setIsCategoryLoading(false);
|
|
29615
|
-
clearLoadingState();
|
|
29616
30175
|
}
|
|
30176
|
+
return;
|
|
29617
30177
|
}
|
|
29618
|
-
|
|
29619
|
-
}
|
|
29620
|
-
try {
|
|
29621
|
-
console.log(`[BottlenecksContent] Loading metadata for category: ${categoryId}`);
|
|
30178
|
+
console.log(`[BottlenecksContent] Loading metadata for category: ${categoryId}${forceRefresh ? " (force refresh)" : ""}`);
|
|
29622
30179
|
const { createClient: createClient5 } = await import('@supabase/supabase-js');
|
|
29623
30180
|
const supabase = createClient5(
|
|
29624
30181
|
process.env.NEXT_PUBLIC_SUPABASE_URL || "",
|
|
@@ -29643,8 +30200,8 @@ var BottlenecksContent = ({
|
|
|
29643
30200
|
action: "percentile-clips",
|
|
29644
30201
|
percentileAction: percentileType,
|
|
29645
30202
|
workspaceId,
|
|
29646
|
-
startDate: `${
|
|
29647
|
-
endDate: `${
|
|
30203
|
+
startDate: `${resolvedDate}T00:00:00Z`,
|
|
30204
|
+
endDate: `${resolvedDate}T23:59:59Z`,
|
|
29648
30205
|
percentile: 10,
|
|
29649
30206
|
shiftId: effectiveShift,
|
|
29650
30207
|
limit: 100
|
|
@@ -29660,7 +30217,7 @@ var BottlenecksContent = ({
|
|
|
29660
30217
|
body: JSON.stringify({
|
|
29661
30218
|
action: "clip-metadata",
|
|
29662
30219
|
workspaceId,
|
|
29663
|
-
date:
|
|
30220
|
+
date: resolvedDate,
|
|
29664
30221
|
shift: effectiveShift,
|
|
29665
30222
|
category: categoryId,
|
|
29666
30223
|
page: 1,
|
|
@@ -29705,19 +30262,22 @@ var BottlenecksContent = ({
|
|
|
29705
30262
|
setCurrentIndex(0);
|
|
29706
30263
|
setCurrentMetadataIndex(0);
|
|
29707
30264
|
currentMetadataIndexRef.current = 0;
|
|
29708
|
-
setIsCategoryLoading(false);
|
|
29709
30265
|
console.log(`[BottlenecksContent] Auto-loaded first video: ${video.id} (1/${metadataClips.length})`);
|
|
29710
30266
|
}
|
|
29711
30267
|
} catch (error2) {
|
|
29712
30268
|
console.error(`[BottlenecksContent] Error loading first video:`, error2);
|
|
29713
|
-
setIsCategoryLoading(false);
|
|
29714
30269
|
}
|
|
29715
30270
|
}
|
|
30271
|
+
} else {
|
|
30272
|
+
setCategoryMetadata([]);
|
|
30273
|
+
categoryMetadataRef.current = [];
|
|
29716
30274
|
}
|
|
29717
30275
|
} catch (error2) {
|
|
29718
30276
|
console.error(`[BottlenecksContent] Error loading category metadata:`, error2);
|
|
30277
|
+
} finally {
|
|
30278
|
+
setIsCategoryLoading(false);
|
|
29719
30279
|
}
|
|
29720
|
-
}, [workspaceId, date, effectiveShift, isPercentileCategory, metadataCache, s3ClipsService]);
|
|
30280
|
+
}, [workspaceId, date, effectiveShift, isPercentileCategory, metadataCache, s3ClipsService, timezone, clearLoadingState]);
|
|
29721
30281
|
const loadAndPlayClipById = useCallback(async (clipId, categoryId, position) => {
|
|
29722
30282
|
if (!workspaceId || !s3ClipsService || !isMountedRef.current) return;
|
|
29723
30283
|
console.log(`[BottlenecksContent] Loading clip by ID: ${clipId}, category=${categoryId}, position=${position}`);
|
|
@@ -29741,21 +30301,31 @@ var BottlenecksContent = ({
|
|
|
29741
30301
|
}
|
|
29742
30302
|
try {
|
|
29743
30303
|
await loadCategoryMetadata(categoryId, false);
|
|
29744
|
-
|
|
29745
|
-
|
|
29746
|
-
|
|
29747
|
-
|
|
29748
|
-
|
|
29749
|
-
|
|
29750
|
-
|
|
29751
|
-
|
|
29752
|
-
|
|
29753
|
-
|
|
29754
|
-
|
|
29755
|
-
|
|
29756
|
-
|
|
29757
|
-
|
|
29758
|
-
|
|
30304
|
+
let metadataArray = categoryMetadataRef.current;
|
|
30305
|
+
const clipExistsInMetadata = metadataArray.some((clip) => clip.clipId === clipId);
|
|
30306
|
+
if (metadataArray.length === 0 || !clipExistsInMetadata) {
|
|
30307
|
+
console.warn(`[BottlenecksContent] Clip ${clipId} not found in metadata for ${categoryId} (cache hit: ${metadataArray.length > 0}) - forcing refresh`);
|
|
30308
|
+
await loadCategoryMetadata(categoryId, false, true);
|
|
30309
|
+
metadataArray = categoryMetadataRef.current;
|
|
30310
|
+
}
|
|
30311
|
+
if (metadataArray.length === 0) {
|
|
30312
|
+
throw new Error(`No metadata available for category ${categoryId}`);
|
|
30313
|
+
}
|
|
30314
|
+
const clickedClipIndex = metadataArray.findIndex((clip) => clip.clipId === clipId);
|
|
30315
|
+
if (clickedClipIndex === -1) {
|
|
30316
|
+
throw new Error(`Clip ${clipId} not found after metadata refresh`);
|
|
30317
|
+
}
|
|
30318
|
+
setCurrentMetadataIndex(clickedClipIndex);
|
|
30319
|
+
currentMetadataIndexRef.current = clickedClipIndex;
|
|
30320
|
+
const video = await s3ClipsService.getClipById(clipId);
|
|
30321
|
+
if (video) {
|
|
30322
|
+
setPendingVideo(video);
|
|
30323
|
+
setCurrentClipId(clipId);
|
|
30324
|
+
setAllVideos([video]);
|
|
30325
|
+
setCurrentIndex(0);
|
|
30326
|
+
console.log(`[BottlenecksContent] Loaded clip ${clipId} (${clickedClipIndex + 1}/${metadataArray.length})`);
|
|
30327
|
+
} else {
|
|
30328
|
+
throw new Error(`Failed to load video data for clip ${clipId}`);
|
|
29759
30329
|
}
|
|
29760
30330
|
} catch (error2) {
|
|
29761
30331
|
console.error(`[BottlenecksContent] Error loading clip by ID (${clipId}):`, error2);
|
|
@@ -29769,7 +30339,7 @@ var BottlenecksContent = ({
|
|
|
29769
30339
|
clearLoadingState();
|
|
29770
30340
|
}
|
|
29771
30341
|
}
|
|
29772
|
-
}, [workspaceId, s3ClipsService,
|
|
30342
|
+
}, [workspaceId, s3ClipsService, updateActiveFilter, clearLoadingState, loadCategoryMetadata]);
|
|
29773
30343
|
useCallback(async (categoryId, clipIndex) => {
|
|
29774
30344
|
console.warn("[BottlenecksContent] loadAndPlayClip is deprecated, use loadAndPlayClipById instead");
|
|
29775
30345
|
if (!workspaceId || !s3ClipsService || !isMountedRef.current) return;
|
|
@@ -29796,7 +30366,7 @@ var BottlenecksContent = ({
|
|
|
29796
30366
|
});
|
|
29797
30367
|
setIsNavigating(false);
|
|
29798
30368
|
}
|
|
29799
|
-
}, [workspaceId, s3ClipsService, date, effectiveShift, loadAndPlayClipById]);
|
|
30369
|
+
}, [workspaceId, s3ClipsService, date, effectiveShift, loadAndPlayClipById, timezone]);
|
|
29800
30370
|
const handleNext = useCallback(async () => {
|
|
29801
30371
|
if (!isMountedRef.current) return;
|
|
29802
30372
|
const currentFilter = activeFilterRef.current;
|
|
@@ -29813,8 +30383,18 @@ var BottlenecksContent = ({
|
|
|
29813
30383
|
}
|
|
29814
30384
|
try {
|
|
29815
30385
|
const currentMetaIndex = currentMetadataIndexRef.current;
|
|
29816
|
-
|
|
30386
|
+
let metadataArray = categoryMetadataRef.current;
|
|
30387
|
+
if (metadataArray.length === 0) {
|
|
30388
|
+
console.log(`[handleNext] Metadata empty for ${currentFilter}, loading before navigation`);
|
|
30389
|
+
await loadCategoryMetadata(currentFilter, false);
|
|
30390
|
+
metadataArray = categoryMetadataRef.current;
|
|
30391
|
+
}
|
|
29817
30392
|
console.log(`[handleNext] Unified navigation: ${currentFilter}, metadata index: ${currentMetaIndex}/${metadataArray.length}`);
|
|
30393
|
+
if (metadataArray.length === 0) {
|
|
30394
|
+
console.warn("[handleNext] No metadata available after refresh - stopping navigation");
|
|
30395
|
+
clearLoadingState();
|
|
30396
|
+
return;
|
|
30397
|
+
}
|
|
29818
30398
|
if (currentMetaIndex < metadataArray.length - 1) {
|
|
29819
30399
|
const nextMetadataIndex = currentMetaIndex + 1;
|
|
29820
30400
|
const nextClipMeta = metadataArray[nextMetadataIndex];
|
|
@@ -29849,7 +30429,7 @@ var BottlenecksContent = ({
|
|
|
29849
30429
|
});
|
|
29850
30430
|
clearLoadingState();
|
|
29851
30431
|
}
|
|
29852
|
-
}, [clearLoadingState, s3ClipsService]);
|
|
30432
|
+
}, [clearLoadingState, s3ClipsService, loadCategoryMetadata]);
|
|
29853
30433
|
const handlePrevious = useCallback(async () => {
|
|
29854
30434
|
if (!isMountedRef.current) return;
|
|
29855
30435
|
const currentFilter = activeFilterRef.current;
|
|
@@ -29866,8 +30446,18 @@ var BottlenecksContent = ({
|
|
|
29866
30446
|
}
|
|
29867
30447
|
try {
|
|
29868
30448
|
const currentMetaIndex = currentMetadataIndexRef.current;
|
|
29869
|
-
|
|
30449
|
+
let metadataArray = categoryMetadataRef.current;
|
|
30450
|
+
if (metadataArray.length === 0) {
|
|
30451
|
+
console.log(`[handlePrevious] Metadata empty for ${currentFilter}, loading before navigation`);
|
|
30452
|
+
await loadCategoryMetadata(currentFilter, false);
|
|
30453
|
+
metadataArray = categoryMetadataRef.current;
|
|
30454
|
+
}
|
|
29870
30455
|
console.log(`[handlePrevious] Unified navigation: ${currentFilter}, metadata index: ${currentMetaIndex}/${metadataArray.length}`);
|
|
30456
|
+
if (metadataArray.length === 0) {
|
|
30457
|
+
console.warn("[handlePrevious] No metadata available after refresh - stopping navigation");
|
|
30458
|
+
clearLoadingState();
|
|
30459
|
+
return;
|
|
30460
|
+
}
|
|
29871
30461
|
if (currentMetaIndex > 0) {
|
|
29872
30462
|
const prevMetadataIndex = currentMetaIndex - 1;
|
|
29873
30463
|
const prevClipMeta = metadataArray[prevMetadataIndex];
|
|
@@ -29898,7 +30488,7 @@ var BottlenecksContent = ({
|
|
|
29898
30488
|
});
|
|
29899
30489
|
clearLoadingState();
|
|
29900
30490
|
}
|
|
29901
|
-
}, [clearLoadingState, s3ClipsService]);
|
|
30491
|
+
}, [clearLoadingState, s3ClipsService, loadCategoryMetadata]);
|
|
29902
30492
|
const currentVideo = useMemo(() => {
|
|
29903
30493
|
if (!filteredVideos || filteredVideos.length === 0 || currentIndex >= filteredVideos.length) {
|
|
29904
30494
|
return null;
|
|
@@ -30874,7 +31464,7 @@ function DiagnosisVideoModal({
|
|
|
30874
31464
|
}
|
|
30875
31465
|
loadClip();
|
|
30876
31466
|
}, [clipId, supabase, transformPlaylistUrls]);
|
|
30877
|
-
const
|
|
31467
|
+
const formatTime4 = (seconds) => {
|
|
30878
31468
|
const mins = Math.floor(seconds / 60);
|
|
30879
31469
|
const secs = Math.floor(seconds % 60);
|
|
30880
31470
|
return `${mins}:${secs.toString().padStart(2, "0")}`;
|
|
@@ -31066,9 +31656,9 @@ function DiagnosisVideoModal({
|
|
|
31066
31656
|
}
|
|
31067
31657
|
),
|
|
31068
31658
|
/* @__PURE__ */ jsxs("span", { className: "text-sm font-medium", children: [
|
|
31069
|
-
|
|
31659
|
+
formatTime4(currentTime),
|
|
31070
31660
|
" / ",
|
|
31071
|
-
|
|
31661
|
+
formatTime4(duration)
|
|
31072
31662
|
] }),
|
|
31073
31663
|
/* @__PURE__ */ jsx(
|
|
31074
31664
|
"input",
|
|
@@ -33039,7 +33629,7 @@ var LinePdfGenerator = ({
|
|
|
33039
33629
|
}
|
|
33040
33630
|
hourEndTime.setSeconds(0);
|
|
33041
33631
|
hourEndTime.setMilliseconds(0);
|
|
33042
|
-
const
|
|
33632
|
+
const formatTime4 = (date2) => {
|
|
33043
33633
|
return date2.toLocaleTimeString("en-IN", {
|
|
33044
33634
|
hour: "2-digit",
|
|
33045
33635
|
minute: "2-digit",
|
|
@@ -33047,7 +33637,7 @@ var LinePdfGenerator = ({
|
|
|
33047
33637
|
timeZone: "Asia/Kolkata"
|
|
33048
33638
|
});
|
|
33049
33639
|
};
|
|
33050
|
-
return `${
|
|
33640
|
+
return `${formatTime4(hourStartTime)} - ${formatTime4(hourEndTime)}`;
|
|
33051
33641
|
});
|
|
33052
33642
|
};
|
|
33053
33643
|
const hourlyTimeRanges = lineInfo.metrics.shift_start ? getHourlyTimeRanges(lineInfo.metrics.shift_start, lineInfo.metrics.shift_end) : [];
|
|
@@ -39633,7 +40223,7 @@ var AIAgentView = () => {
|
|
|
39633
40223
|
}
|
|
39634
40224
|
return formattedLines.join("");
|
|
39635
40225
|
};
|
|
39636
|
-
const
|
|
40226
|
+
const formatTime4 = (timestamp) => {
|
|
39637
40227
|
const date = new Date(timestamp);
|
|
39638
40228
|
return date.toLocaleTimeString([], {
|
|
39639
40229
|
hour: "2-digit",
|
|
@@ -40897,7 +41487,7 @@ var AIAgentView = () => {
|
|
|
40897
41487
|
}
|
|
40898
41488
|
),
|
|
40899
41489
|
/* @__PURE__ */ 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: [
|
|
40900
|
-
/* @__PURE__ */ jsx("span", { children:
|
|
41490
|
+
/* @__PURE__ */ jsx("span", { children: formatTime4(message.created_at) }),
|
|
40901
41491
|
message.role === "assistant" && message.id !== -1 && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
|
|
40902
41492
|
/* @__PURE__ */ jsx("div", { className: "w-1 h-1 bg-gray-300 rounded-full" }),
|
|
40903
41493
|
/* @__PURE__ */ jsx("span", { children: "Axel" })
|