@optifye/dashboard-core 6.9.8 → 6.9.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.css +4 -36
- package/dist/index.d.mts +58 -37
- package/dist/index.d.ts +58 -37
- package/dist/index.js +1596 -1375
- package/dist/index.mjs +1595 -1375
- package/package.json +1 -3
package/dist/index.mjs
CHANGED
|
@@ -7,17 +7,15 @@ import { subDays, format, parseISO, isValid, formatDistanceToNow, isFuture, isTo
|
|
|
7
7
|
import mixpanel from 'mixpanel-browser';
|
|
8
8
|
import { EventEmitter } from 'events';
|
|
9
9
|
import { createClient, REALTIME_SUBSCRIBE_STATES } from '@supabase/supabase-js';
|
|
10
|
-
import
|
|
10
|
+
import Hls3, { Events, ErrorTypes } from 'hls.js';
|
|
11
11
|
import useSWR from 'swr';
|
|
12
12
|
import { noop, warning, invariant, progress, secondsToMilliseconds, millisecondsToSeconds, memo as memo$1 } from 'motion-utils';
|
|
13
13
|
import { getValueTransition, hover, press, isPrimaryPointer, GroupPlaybackControls, setDragLock, supportsLinearEasing, attachTimeline, isGenerator, calcGeneratorDuration, isWaapiSupportedEasing, mapEasingToNativeEasing, maxGeneratorDuration, generateLinearEasing, isBezierDefinition } from 'motion-dom';
|
|
14
|
-
import { Camera, ChevronDown, ChevronUp, Check, Map as Map$1, Video, ShieldCheck, Star, Award, ArrowLeft, X, Coffee, Plus, Clock, Calendar, Save, AlertCircle, Loader2, Minus, ArrowDown, ArrowUp, ChevronLeft, ChevronRight, Pause, Play, XCircle,
|
|
14
|
+
import { Camera, ChevronDown, ChevronUp, Check, Map as Map$1, Video, ShieldCheck, Star, Award, ArrowLeft, X, Coffee, Plus, Clock, Calendar, Save, AlertCircle, Loader2, Minus, ArrowDown, ArrowUp, ChevronLeft, ChevronRight, Pause, Play, XCircle, Sparkles, TrendingUp, Settings2, CheckCircle2, RefreshCw, TrendingDown, FolderOpen, Folder, HelpCircle, Sliders, Activity, Layers, Filter, Search, Edit2, AlertTriangle, CheckCircle, Building2, Mail, Users, User, Lock, ArrowRight, Info, Share2, Trophy, Target, Download, Sun, Moon, MousePointer, MessageSquare, Trash2, Menu, Send, Copy, UserCheck, LogOut, Package, UserPlus, Settings, LifeBuoy, EyeOff, Eye, MoreVertical, UserCog, Zap, Shield, UserCircle } from 'lucide-react';
|
|
15
15
|
import { toast } from 'sonner';
|
|
16
16
|
import { BarChart as BarChart$1, CartesianGrid, XAxis, YAxis, Tooltip, Legend, Bar, LabelList, ResponsiveContainer, LineChart as LineChart$1, Line, PieChart, Pie, Cell, ReferenceLine, ComposedChart, Area, ScatterChart, Scatter } from 'recharts';
|
|
17
17
|
import { Slot } from '@radix-ui/react-slot';
|
|
18
18
|
import * as SelectPrimitive from '@radix-ui/react-select';
|
|
19
|
-
import videojs from 'video.js';
|
|
20
|
-
import 'video.js/dist/video-js.css';
|
|
21
19
|
import { DayPicker, useNavigation as useNavigation$1 } from 'react-day-picker';
|
|
22
20
|
import { XMarkIcon, ArrowRightIcon, HomeIcon, TrophyIcon, ChartBarIcon, AdjustmentsHorizontalIcon, ClockIcon, UsersIcon, TicketIcon, CubeIcon, SparklesIcon, QuestionMarkCircleIcon, HeartIcon, UserCircleIcon, ExclamationCircleIcon, EnvelopeIcon, DocumentTextIcon, ChevronUpIcon, ChevronDownIcon, ChevronLeftIcon, ChevronRightIcon, Bars3Icon, CheckCircleIcon, ChatBubbleLeftRightIcon, ArrowLeftIcon, XCircleIcon, InformationCircleIcon } from '@heroicons/react/24/outline';
|
|
23
21
|
import { CheckIcon } from '@heroicons/react/24/solid';
|
|
@@ -8989,12 +8987,12 @@ function useHlsStream(videoRef, { src, shouldPlay, onFatalError }) {
|
|
|
8989
8987
|
const video = videoRef.current;
|
|
8990
8988
|
if (!video) return;
|
|
8991
8989
|
isNativeHlsRef.current = video.canPlayType("application/vnd.apple.mpegurl") === "probably";
|
|
8992
|
-
if (
|
|
8993
|
-
const hls = new
|
|
8990
|
+
if (Hls3.isSupported() && !isNativeHlsRef.current) {
|
|
8991
|
+
const hls = new Hls3(HLS_CONFIG);
|
|
8994
8992
|
hlsRef.current = hls;
|
|
8995
8993
|
hls.attachMedia(video);
|
|
8996
8994
|
hls.loadSource(src);
|
|
8997
|
-
hls.on(
|
|
8995
|
+
hls.on(Hls3.Events.ERROR, (_, data) => {
|
|
8998
8996
|
if (!data.fatal) return;
|
|
8999
8997
|
console.error("[HLS] Fatal error:", data.type, data.details);
|
|
9000
8998
|
if (data.response?.code === 404) {
|
|
@@ -9002,8 +9000,8 @@ function useHlsStream(videoRef, { src, shouldPlay, onFatalError }) {
|
|
|
9002
9000
|
return;
|
|
9003
9001
|
}
|
|
9004
9002
|
switch (data.type) {
|
|
9005
|
-
case
|
|
9006
|
-
case
|
|
9003
|
+
case Hls3.ErrorTypes.NETWORK_ERROR:
|
|
9004
|
+
case Hls3.ErrorTypes.MEDIA_ERROR:
|
|
9007
9005
|
softRestart(`${data.type}: ${data.details}`);
|
|
9008
9006
|
break;
|
|
9009
9007
|
default:
|
|
@@ -9011,7 +9009,7 @@ function useHlsStream(videoRef, { src, shouldPlay, onFatalError }) {
|
|
|
9011
9009
|
break;
|
|
9012
9010
|
}
|
|
9013
9011
|
});
|
|
9014
|
-
hls.on(
|
|
9012
|
+
hls.on(Hls3.Events.MANIFEST_PARSED, () => {
|
|
9015
9013
|
if (failedUrls.has(src)) {
|
|
9016
9014
|
console.log(`[HLS] Stream loaded successfully, resetting failure count for: ${src}`);
|
|
9017
9015
|
failedUrls.delete(src);
|
|
@@ -14054,9 +14052,9 @@ var S3VideoPreloader = class {
|
|
|
14054
14052
|
this.processQueue();
|
|
14055
14053
|
};
|
|
14056
14054
|
if (url.endsWith(".m3u8")) {
|
|
14057
|
-
import('hls.js').then(({ default:
|
|
14058
|
-
if (
|
|
14059
|
-
const hls = new
|
|
14055
|
+
import('hls.js').then(({ default: Hls4 }) => {
|
|
14056
|
+
if (Hls4.isSupported()) {
|
|
14057
|
+
const hls = new Hls4({
|
|
14060
14058
|
maxBufferLength: 10,
|
|
14061
14059
|
startFragPrefetch: true,
|
|
14062
14060
|
lowLatencyMode: false,
|
|
@@ -14068,7 +14066,7 @@ var S3VideoPreloader = class {
|
|
|
14068
14066
|
hls.destroy();
|
|
14069
14067
|
cleanup();
|
|
14070
14068
|
}, 4e3);
|
|
14071
|
-
hls.on(
|
|
14069
|
+
hls.on(Hls4.Events.BUFFER_APPENDED, () => {
|
|
14072
14070
|
window.clearTimeout(timeout);
|
|
14073
14071
|
hls.destroy();
|
|
14074
14072
|
cleanup();
|
|
@@ -23072,7 +23070,7 @@ var OutputProgressChartComponent = ({
|
|
|
23072
23070
|
];
|
|
23073
23071
|
const COLORS = ["#00AB45", "#f3f4f6"];
|
|
23074
23072
|
const percentage = (currentOutput / targetOutput * 100).toFixed(1);
|
|
23075
|
-
return /* @__PURE__ */ jsx("div", { className: `w-full h-full flex items-center justify-center ${className}`, children: /* @__PURE__ */ jsxs("div", { className: "relative w-full
|
|
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: [
|
|
23076
23074
|
/* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsx(PieChart, { children: /* @__PURE__ */ jsx(
|
|
23077
23075
|
Pie,
|
|
23078
23076
|
{
|
|
@@ -23096,16 +23094,33 @@ var OutputProgressChartComponent = ({
|
|
|
23096
23094
|
))
|
|
23097
23095
|
}
|
|
23098
23096
|
) }) }),
|
|
23099
|
-
/* @__PURE__ */ jsx("div", { className: "absolute inset-0 flex flex-col items-center justify-center", children: /* @__PURE__ */ jsxs("div", { className: "text-center", children: [
|
|
23100
|
-
/* @__PURE__ */ jsxs(
|
|
23101
|
-
|
|
23102
|
-
|
|
23103
|
-
|
|
23104
|
-
|
|
23105
|
-
|
|
23106
|
-
|
|
23107
|
-
|
|
23108
|
-
|
|
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
|
+
)
|
|
23109
23124
|
] }) })
|
|
23110
23125
|
] }) });
|
|
23111
23126
|
};
|
|
@@ -23123,7 +23138,7 @@ var LargeOutputProgressChart = ({
|
|
|
23123
23138
|
];
|
|
23124
23139
|
const COLORS = ["#00AB45", "#f3f4f6"];
|
|
23125
23140
|
const percentage = (currentOutput / targetOutput * 100).toFixed(1);
|
|
23126
|
-
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: [
|
|
23127
23142
|
/* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsx(PieChart, { children: /* @__PURE__ */ jsx(
|
|
23128
23143
|
Pie,
|
|
23129
23144
|
{
|
|
@@ -23147,16 +23162,40 @@ var LargeOutputProgressChart = ({
|
|
|
23147
23162
|
))
|
|
23148
23163
|
}
|
|
23149
23164
|
) }) }),
|
|
23150
|
-
/* @__PURE__ */ jsx("div", { className: "absolute inset-0 flex flex-col items-center justify-center", children: /* @__PURE__ */ jsxs("div", { className: "text-center", children: [
|
|
23151
|
-
/* @__PURE__ */ jsx(
|
|
23152
|
-
|
|
23153
|
-
|
|
23154
|
-
|
|
23155
|
-
|
|
23156
|
-
|
|
23157
|
-
|
|
23158
|
-
|
|
23159
|
-
|
|
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
|
+
)
|
|
23160
23199
|
] }) })
|
|
23161
23200
|
] }) });
|
|
23162
23201
|
};
|
|
@@ -25250,7 +25289,7 @@ var GaugeChart = ({
|
|
|
25250
25289
|
};
|
|
25251
25290
|
const gaugeColor = getColor();
|
|
25252
25291
|
const targetAngle = target !== void 0 ? 180 - (target - min) / (max - min) * 180 : null;
|
|
25253
|
-
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: [
|
|
25254
25293
|
/* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsx(PieChart, { children: /* @__PURE__ */ jsxs(
|
|
25255
25294
|
Pie,
|
|
25256
25295
|
{
|
|
@@ -25283,17 +25322,44 @@ var GaugeChart = ({
|
|
|
25283
25322
|
children: /* @__PURE__ */ jsx("div", { className: "absolute -top-1 -left-1.5 w-3 h-3 bg-gray-800 rounded-full" })
|
|
25284
25323
|
}
|
|
25285
25324
|
),
|
|
25286
|
-
/* @__PURE__ */ jsx("div", { className: "absolute inset-0 flex flex-col items-center justify-center", children: /* @__PURE__ */ jsxs("div", { className: "text-center", children: [
|
|
25287
|
-
/* @__PURE__ */ jsxs(
|
|
25288
|
-
|
|
25289
|
-
|
|
25290
|
-
|
|
25291
|
-
|
|
25292
|
-
|
|
25293
|
-
|
|
25294
|
-
|
|
25295
|
-
|
|
25296
|
-
|
|
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
|
+
)
|
|
25297
25363
|
] }) }),
|
|
25298
25364
|
/* @__PURE__ */ jsxs("div", { className: "absolute bottom-[15%] left-[15%] text-xs text-gray-500", children: [
|
|
25299
25365
|
min,
|
|
@@ -26024,12 +26090,6 @@ var AxelNotificationPopup = ({
|
|
|
26024
26090
|
};
|
|
26025
26091
|
|
|
26026
26092
|
// src/views/components/workspace/BottlenecksContent.utils.ts
|
|
26027
|
-
var formatTime2 = (seconds) => {
|
|
26028
|
-
if (isNaN(seconds)) return "0:00";
|
|
26029
|
-
const minutes = Math.floor(seconds / 60);
|
|
26030
|
-
const remainingSeconds = Math.floor(seconds % 60);
|
|
26031
|
-
return `${minutes}:${remainingSeconds < 10 ? "0" : ""}${remainingSeconds}`;
|
|
26032
|
-
};
|
|
26033
26093
|
var getSeverityColor = (severity) => {
|
|
26034
26094
|
switch (severity) {
|
|
26035
26095
|
case "low":
|
|
@@ -26042,957 +26102,575 @@ var getSeverityColor = (severity) => {
|
|
|
26042
26102
|
return "bg-gray-500";
|
|
26043
26103
|
}
|
|
26044
26104
|
};
|
|
26045
|
-
|
|
26046
|
-
|
|
26047
|
-
|
|
26048
|
-
|
|
26049
|
-
var SelectGroup = SelectPrimitive.Group;
|
|
26050
|
-
var SelectValue = SelectPrimitive.Value;
|
|
26051
|
-
var SelectTrigger = React23.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(
|
|
26052
|
-
SelectPrimitive.Trigger,
|
|
26053
|
-
{
|
|
26054
|
-
ref,
|
|
26055
|
-
className: cn(
|
|
26056
|
-
"flex h-11 sm:h-9 w-full items-center justify-between whitespace-nowrap rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm ring-offset-background data-[placeholder]:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-ring disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1 touch-manipulation",
|
|
26057
|
-
className
|
|
26058
|
-
),
|
|
26059
|
-
...props,
|
|
26060
|
-
children: [
|
|
26061
|
-
children,
|
|
26062
|
-
/* @__PURE__ */ jsx(SelectPrimitive.Icon, { asChild: true, children: /* @__PURE__ */ jsx(ChevronDown, { className: "h-4 w-4 opacity-50" }) })
|
|
26063
|
-
]
|
|
26064
|
-
}
|
|
26065
|
-
));
|
|
26066
|
-
SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
|
|
26067
|
-
var SelectScrollUpButton = React23.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
26068
|
-
SelectPrimitive.ScrollUpButton,
|
|
26069
|
-
{
|
|
26070
|
-
ref,
|
|
26071
|
-
className: cn("flex cursor-default items-center justify-center py-1", className),
|
|
26072
|
-
...props,
|
|
26073
|
-
children: /* @__PURE__ */ jsx(ChevronUp, { className: "h-4 w-4" })
|
|
26074
|
-
}
|
|
26075
|
-
));
|
|
26076
|
-
SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName;
|
|
26077
|
-
var SelectScrollDownButton = React23.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
26078
|
-
SelectPrimitive.ScrollDownButton,
|
|
26079
|
-
{
|
|
26080
|
-
ref,
|
|
26081
|
-
className: cn("flex cursor-default items-center justify-center py-1", className),
|
|
26082
|
-
...props,
|
|
26083
|
-
children: /* @__PURE__ */ jsx(ChevronDown, { className: "h-4 w-4" })
|
|
26084
|
-
}
|
|
26085
|
-
));
|
|
26086
|
-
SelectScrollDownButton.displayName = SelectPrimitive.ScrollDownButton.displayName;
|
|
26087
|
-
var SelectContent = React23.forwardRef(({ className, children, position = "popper", ...props }, ref) => /* @__PURE__ */ jsx(SelectPrimitive.Portal, { children: /* @__PURE__ */ jsxs(
|
|
26088
|
-
SelectPrimitive.Content,
|
|
26089
|
-
{
|
|
26090
|
-
ref,
|
|
26091
|
-
className: cn(
|
|
26092
|
-
"relative z-50 max-h-[--radix-select-content-available-height] min-w-[8rem] overflow-y-auto overflow-x-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-select-content-transform-origin]",
|
|
26093
|
-
position === "popper" && "data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
|
|
26094
|
-
className
|
|
26095
|
-
),
|
|
26096
|
-
position,
|
|
26097
|
-
...props,
|
|
26098
|
-
children: [
|
|
26099
|
-
/* @__PURE__ */ jsx(SelectScrollUpButton, {}),
|
|
26100
|
-
/* @__PURE__ */ jsx(
|
|
26101
|
-
SelectPrimitive.Viewport,
|
|
26102
|
-
{
|
|
26103
|
-
className: cn(
|
|
26104
|
-
"p-1",
|
|
26105
|
-
position === "popper" && "h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]"
|
|
26106
|
-
),
|
|
26107
|
-
children
|
|
26108
|
-
}
|
|
26109
|
-
),
|
|
26110
|
-
/* @__PURE__ */ jsx(SelectScrollDownButton, {})
|
|
26111
|
-
]
|
|
26112
|
-
}
|
|
26113
|
-
) }));
|
|
26114
|
-
SelectContent.displayName = SelectPrimitive.Content.displayName;
|
|
26115
|
-
var SelectLabel = React23.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
26116
|
-
SelectPrimitive.Label,
|
|
26117
|
-
{
|
|
26118
|
-
ref,
|
|
26119
|
-
className: cn("px-2 py-1.5 text-sm font-semibold", className),
|
|
26120
|
-
...props
|
|
26121
|
-
}
|
|
26122
|
-
));
|
|
26123
|
-
SelectLabel.displayName = SelectPrimitive.Label.displayName;
|
|
26124
|
-
var SelectItem = React23.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(
|
|
26125
|
-
SelectPrimitive.Item,
|
|
26126
|
-
{
|
|
26127
|
-
ref,
|
|
26128
|
-
className: cn(
|
|
26129
|
-
"relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-2 pr-8 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
|
26130
|
-
className
|
|
26131
|
-
),
|
|
26132
|
-
...props,
|
|
26133
|
-
children: [
|
|
26134
|
-
/* @__PURE__ */ jsx("span", { className: "absolute right-2 flex h-3.5 w-3.5 items-center justify-center", children: /* @__PURE__ */ jsx(SelectPrimitive.ItemIndicator, { children: /* @__PURE__ */ jsx(Check, { className: "h-4 w-4" }) }) }),
|
|
26135
|
-
/* @__PURE__ */ jsx(SelectPrimitive.ItemText, { children })
|
|
26136
|
-
]
|
|
26137
|
-
}
|
|
26138
|
-
));
|
|
26139
|
-
SelectItem.displayName = SelectPrimitive.Item.displayName;
|
|
26140
|
-
var SelectSeparator = React23.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
26141
|
-
SelectPrimitive.Separator,
|
|
26142
|
-
{
|
|
26143
|
-
ref,
|
|
26144
|
-
className: cn("-mx-1 my-1 h-px bg-muted", className),
|
|
26145
|
-
...props
|
|
26146
|
-
}
|
|
26147
|
-
));
|
|
26148
|
-
SelectSeparator.displayName = SelectPrimitive.Separator.displayName;
|
|
26149
|
-
var LoadingOverlay = ({
|
|
26150
|
-
isVisible,
|
|
26151
|
-
message = "Loading...",
|
|
26152
|
-
className
|
|
26105
|
+
var PlayPauseIndicator = ({
|
|
26106
|
+
show,
|
|
26107
|
+
isPlaying,
|
|
26108
|
+
duration = 600
|
|
26153
26109
|
}) => {
|
|
26110
|
+
const [isVisible, setIsVisible] = useState(false);
|
|
26111
|
+
const [isFading, setIsFading] = useState(false);
|
|
26112
|
+
useEffect(() => {
|
|
26113
|
+
if (show) {
|
|
26114
|
+
setIsVisible(true);
|
|
26115
|
+
setIsFading(false);
|
|
26116
|
+
const fadeTimer = setTimeout(() => {
|
|
26117
|
+
setIsFading(true);
|
|
26118
|
+
}, 100);
|
|
26119
|
+
const hideTimer = setTimeout(() => {
|
|
26120
|
+
setIsVisible(false);
|
|
26121
|
+
setIsFading(false);
|
|
26122
|
+
}, duration);
|
|
26123
|
+
return () => {
|
|
26124
|
+
clearTimeout(fadeTimer);
|
|
26125
|
+
clearTimeout(hideTimer);
|
|
26126
|
+
};
|
|
26127
|
+
}
|
|
26128
|
+
}, [show, duration]);
|
|
26154
26129
|
if (!isVisible) return null;
|
|
26155
26130
|
return /* @__PURE__ */ jsx(
|
|
26156
|
-
|
|
26131
|
+
"div",
|
|
26157
26132
|
{
|
|
26158
|
-
|
|
26159
|
-
|
|
26160
|
-
|
|
26161
|
-
|
|
26162
|
-
|
|
26163
|
-
"
|
|
26164
|
-
|
|
26165
|
-
|
|
26133
|
+
className: "absolute inset-0 flex items-center justify-center pointer-events-none z-10",
|
|
26134
|
+
style: {
|
|
26135
|
+
opacity: isFading ? 0 : 1,
|
|
26136
|
+
transition: `opacity ${duration - 100}ms ease-out`
|
|
26137
|
+
},
|
|
26138
|
+
children: /* @__PURE__ */ jsx("div", { className: "bg-black/70 rounded-full p-6", children: isPlaying ? (
|
|
26139
|
+
// Play icon (triangle)
|
|
26140
|
+
/* @__PURE__ */ jsx(
|
|
26141
|
+
"svg",
|
|
26142
|
+
{
|
|
26143
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
26144
|
+
viewBox: "0 0 24 24",
|
|
26145
|
+
fill: "white",
|
|
26146
|
+
className: "w-16 h-16",
|
|
26147
|
+
children: /* @__PURE__ */ jsx("path", { d: "M8 5v14l11-7z" })
|
|
26148
|
+
}
|
|
26149
|
+
)
|
|
26150
|
+
) : (
|
|
26151
|
+
// Pause icon (two bars)
|
|
26152
|
+
/* @__PURE__ */ jsx(
|
|
26153
|
+
"svg",
|
|
26154
|
+
{
|
|
26155
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
26156
|
+
viewBox: "0 0 24 24",
|
|
26157
|
+
fill: "white",
|
|
26158
|
+
className: "w-16 h-16",
|
|
26159
|
+
children: /* @__PURE__ */ jsx("path", { d: "M6 4h4v16H6V4zm8 0h4v16h-4V4z" })
|
|
26160
|
+
}
|
|
26161
|
+
)
|
|
26162
|
+
) })
|
|
26166
26163
|
}
|
|
26167
26164
|
);
|
|
26168
26165
|
};
|
|
26169
|
-
var
|
|
26170
|
-
|
|
26171
|
-
|
|
26172
|
-
|
|
26173
|
-
|
|
26174
|
-
|
|
26175
|
-
|
|
26176
|
-
|
|
26177
|
-
|
|
26178
|
-
|
|
26179
|
-
|
|
26180
|
-
|
|
26181
|
-
|
|
26182
|
-
|
|
26183
|
-
|
|
26184
|
-
|
|
26185
|
-
|
|
26186
|
-
|
|
26187
|
-
|
|
26188
|
-
|
|
26189
|
-
|
|
26190
|
-
|
|
26191
|
-
|
|
26192
|
-
|
|
26193
|
-
setTime("Error");
|
|
26194
|
-
}
|
|
26195
|
-
};
|
|
26196
|
-
updateTime();
|
|
26197
|
-
const interval = setInterval(updateTime, 1e3);
|
|
26198
|
-
return () => clearInterval(interval);
|
|
26199
|
-
}, [timezoneToDisplay, dateTimeConfig?.timeFormatOptions, localeToUse]);
|
|
26200
|
-
if (!time2) return null;
|
|
26201
|
-
if (variant === "minimal") {
|
|
26202
|
-
return /* @__PURE__ */ jsxs("span", { className: className || "", children: [
|
|
26203
|
-
time2,
|
|
26204
|
-
" ",
|
|
26205
|
-
timeSuffix
|
|
26206
|
-
] });
|
|
26166
|
+
var ERROR_MAPPING = {
|
|
26167
|
+
"networkError": {
|
|
26168
|
+
code: 2,
|
|
26169
|
+
type: "recoverable",
|
|
26170
|
+
message: "Network error - please check your internet connection",
|
|
26171
|
+
canRetry: true
|
|
26172
|
+
},
|
|
26173
|
+
"mediaError": {
|
|
26174
|
+
code: 3,
|
|
26175
|
+
type: "non_recoverable",
|
|
26176
|
+
message: "Stream corrupted due to internet connection",
|
|
26177
|
+
canRetry: false
|
|
26178
|
+
},
|
|
26179
|
+
"muxError": {
|
|
26180
|
+
code: 3,
|
|
26181
|
+
type: "non_recoverable",
|
|
26182
|
+
message: "Error processing media stream",
|
|
26183
|
+
canRetry: false
|
|
26184
|
+
},
|
|
26185
|
+
"otherError": {
|
|
26186
|
+
code: 4,
|
|
26187
|
+
type: "non_recoverable",
|
|
26188
|
+
message: "Video format not supported by your browser. Please use Google Chrome.",
|
|
26189
|
+
canRetry: false
|
|
26207
26190
|
}
|
|
26208
|
-
return /* @__PURE__ */ jsxs(
|
|
26209
|
-
motion.div,
|
|
26210
|
-
{
|
|
26211
|
-
initial: { opacity: 0, y: -5 },
|
|
26212
|
-
animate: { opacity: 1, y: 0 },
|
|
26213
|
-
transition: { duration: 0.3 },
|
|
26214
|
-
className: `flex items-center space-x-1.5 bg-white/60 backdrop-blur-sm px-2 py-0.5 rounded-md shadow-xs ${className || ""}`,
|
|
26215
|
-
children: [
|
|
26216
|
-
/* @__PURE__ */ jsx("svg", { xmlns: "http://www.w3.org/2000/svg", className: "h-3 w-3 text-[var(--primary-DEFAULT)]", viewBox: "0 0 20 20", fill: "currentColor", children: /* @__PURE__ */ jsx("path", { fillRule: "evenodd", d: "M10 18a8 8 0 100-16 8 8 0 000 16zm1-12a1 1 0 10-2 0v4a1 1 0 00.293.707l2.828 2.829a1 1 0 101.415-1.415L11 9.586V6z", clipRule: "evenodd" }) }),
|
|
26217
|
-
/* @__PURE__ */ jsxs("span", { className: "text-xs sm:text-[11px] font-medium text-gray-800 tabular-nums tracking-tight", children: [
|
|
26218
|
-
time2,
|
|
26219
|
-
" ",
|
|
26220
|
-
timeSuffix
|
|
26221
|
-
] })
|
|
26222
|
-
]
|
|
26223
|
-
}
|
|
26224
|
-
);
|
|
26225
26191
|
};
|
|
26226
|
-
var
|
|
26227
|
-
|
|
26228
|
-
|
|
26229
|
-
|
|
26230
|
-
|
|
26231
|
-
|
|
26192
|
+
var hlsVideoPlayerStyles = `
|
|
26193
|
+
.hls-video-player-container {
|
|
26194
|
+
width: 100%;
|
|
26195
|
+
height: 100%;
|
|
26196
|
+
background-color: #000;
|
|
26197
|
+
display: flex;
|
|
26198
|
+
align-items: center;
|
|
26199
|
+
justify-content: center;
|
|
26200
|
+
}
|
|
26201
|
+
|
|
26202
|
+
/* Center the video and maintain aspect ratio */
|
|
26203
|
+
.hls-video-element {
|
|
26204
|
+
width: 100%;
|
|
26205
|
+
height: 100%;
|
|
26206
|
+
max-width: 100%;
|
|
26207
|
+
max-height: 100%;
|
|
26208
|
+
object-fit: contain;
|
|
26209
|
+
}
|
|
26210
|
+
|
|
26211
|
+
/* Custom loading indicator styles */
|
|
26212
|
+
.hls-video-player-loading {
|
|
26213
|
+
position: absolute;
|
|
26214
|
+
top: 50%;
|
|
26215
|
+
left: 50%;
|
|
26216
|
+
transform: translate(-50%, -50%);
|
|
26217
|
+
z-index: 10;
|
|
26218
|
+
}
|
|
26219
|
+
`;
|
|
26220
|
+
if (typeof document !== "undefined") {
|
|
26221
|
+
const styleId = "hls-video-player-custom-styles";
|
|
26222
|
+
if (!document.getElementById(styleId)) {
|
|
26223
|
+
const style = document.createElement("style");
|
|
26224
|
+
style.id = styleId;
|
|
26225
|
+
style.textContent = hlsVideoPlayerStyles;
|
|
26226
|
+
document.head.appendChild(style);
|
|
26227
|
+
}
|
|
26228
|
+
}
|
|
26229
|
+
var BASE_HLS_CONFIG = {
|
|
26230
|
+
maxBufferLength: 3,
|
|
26231
|
+
maxMaxBufferLength: 8,
|
|
26232
|
+
maxBufferSize: 50 * 1e3 * 1e3,
|
|
26233
|
+
maxBufferHole: 0.25,
|
|
26234
|
+
manifestLoadingTimeOut: 15e3,
|
|
26235
|
+
manifestLoadingMaxRetry: 3,
|
|
26236
|
+
manifestLoadingRetryDelay: 500,
|
|
26237
|
+
levelLoadingTimeOut: 6e4,
|
|
26238
|
+
levelLoadingMaxRetry: 5,
|
|
26239
|
+
levelLoadingRetryDelay: 500,
|
|
26240
|
+
fragLoadingTimeOut: 6e4,
|
|
26241
|
+
fragLoadingMaxRetry: 5,
|
|
26242
|
+
fragLoadingRetryDelay: 500,
|
|
26243
|
+
startPosition: -1,
|
|
26244
|
+
debug: false,
|
|
26245
|
+
enableWorker: true,
|
|
26246
|
+
lowLatencyMode: false,
|
|
26247
|
+
progressive: true,
|
|
26248
|
+
abrEwmaSlowLive: 9,
|
|
26249
|
+
abrEwmaFastLive: 3,
|
|
26250
|
+
abrBandWidthFactor: 0.95,
|
|
26251
|
+
abrBandWidthUpFactor: 0.7,
|
|
26252
|
+
abrMaxWithRealBitrate: false,
|
|
26253
|
+
abrEwmaDefaultEstimate: 5e7
|
|
26254
|
+
};
|
|
26255
|
+
var HlsVideoPlayer = forwardRef(({
|
|
26256
|
+
src,
|
|
26257
|
+
poster,
|
|
26258
|
+
autoplay = false,
|
|
26259
|
+
controls = true,
|
|
26260
|
+
loop = false,
|
|
26261
|
+
muted = false,
|
|
26262
|
+
playsInline = true,
|
|
26263
|
+
className = "",
|
|
26264
|
+
hlsConfig = {},
|
|
26265
|
+
options = {},
|
|
26266
|
+
// Backward compatibility with Video.js
|
|
26267
|
+
externalLoadingControl = false,
|
|
26268
|
+
onLoadingChange,
|
|
26269
|
+
onReady,
|
|
26270
|
+
onPlay,
|
|
26271
|
+
onPause,
|
|
26272
|
+
onPlaying,
|
|
26273
|
+
onTimeUpdate,
|
|
26274
|
+
onDurationChange,
|
|
26275
|
+
onEnded,
|
|
26276
|
+
onError,
|
|
26277
|
+
onLoadStart,
|
|
26278
|
+
onLoadedMetadata,
|
|
26279
|
+
onLoadedData,
|
|
26280
|
+
onSeeking,
|
|
26281
|
+
onSeeked,
|
|
26282
|
+
onClick
|
|
26283
|
+
}, ref) => {
|
|
26284
|
+
const videoContainerRef = useRef(null);
|
|
26285
|
+
const videoRef = useRef(null);
|
|
26286
|
+
const hlsRef = useRef(null);
|
|
26287
|
+
const blobUrlRef = useRef(null);
|
|
26288
|
+
const [isReady, setIsReady] = useState(false);
|
|
26289
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
26290
|
+
const [showIndicator, setShowIndicator] = useState(false);
|
|
26291
|
+
const [indicatorIsPlaying, setIndicatorIsPlaying] = useState(false);
|
|
26292
|
+
const indicatorKeyRef = useRef(0);
|
|
26293
|
+
const eventCallbacksRef = useRef({
|
|
26294
|
+
onReady,
|
|
26295
|
+
onPlay,
|
|
26296
|
+
onPause,
|
|
26297
|
+
onPlaying,
|
|
26298
|
+
onTimeUpdate,
|
|
26299
|
+
onDurationChange,
|
|
26300
|
+
onEnded,
|
|
26301
|
+
onError,
|
|
26302
|
+
onLoadStart,
|
|
26303
|
+
onLoadedMetadata,
|
|
26304
|
+
onLoadedData,
|
|
26305
|
+
onSeeking,
|
|
26306
|
+
onSeeked,
|
|
26307
|
+
onLoadingChange
|
|
26308
|
+
});
|
|
26232
26309
|
useEffect(() => {
|
|
26233
|
-
|
|
26234
|
-
|
|
26235
|
-
|
|
26236
|
-
|
|
26237
|
-
|
|
26238
|
-
|
|
26239
|
-
|
|
26240
|
-
|
|
26241
|
-
|
|
26242
|
-
|
|
26243
|
-
|
|
26244
|
-
|
|
26245
|
-
|
|
26246
|
-
|
|
26247
|
-
|
|
26248
|
-
}
|
|
26310
|
+
eventCallbacksRef.current = {
|
|
26311
|
+
onReady,
|
|
26312
|
+
onPlay,
|
|
26313
|
+
onPause,
|
|
26314
|
+
onPlaying,
|
|
26315
|
+
onTimeUpdate,
|
|
26316
|
+
onDurationChange,
|
|
26317
|
+
onEnded,
|
|
26318
|
+
onError,
|
|
26319
|
+
onLoadStart,
|
|
26320
|
+
onLoadedMetadata,
|
|
26321
|
+
onLoadedData,
|
|
26322
|
+
onSeeking,
|
|
26323
|
+
onSeeked,
|
|
26324
|
+
onLoadingChange
|
|
26249
26325
|
};
|
|
26250
|
-
|
|
26251
|
-
|
|
26326
|
+
}, [
|
|
26327
|
+
onReady,
|
|
26328
|
+
onPlay,
|
|
26329
|
+
onPause,
|
|
26330
|
+
onPlaying,
|
|
26331
|
+
onTimeUpdate,
|
|
26332
|
+
onDurationChange,
|
|
26333
|
+
onEnded,
|
|
26334
|
+
onError,
|
|
26335
|
+
onLoadStart,
|
|
26336
|
+
onLoadedMetadata,
|
|
26337
|
+
onLoadedData,
|
|
26338
|
+
onSeeking,
|
|
26339
|
+
onSeeked,
|
|
26340
|
+
onLoadingChange
|
|
26341
|
+
]);
|
|
26342
|
+
const stableHlsConfigRef = useRef(hlsConfig);
|
|
26343
|
+
const stableOptionsRef = useRef(options);
|
|
26344
|
+
const configSignatureRef = useRef("");
|
|
26345
|
+
const [configVersion, setConfigVersion] = useState(0);
|
|
26346
|
+
useEffect(() => {
|
|
26347
|
+
const serialized = JSON.stringify({
|
|
26348
|
+
hlsConfig: hlsConfig || null,
|
|
26349
|
+
options: options || null
|
|
26350
|
+
});
|
|
26351
|
+
if (!configSignatureRef.current) {
|
|
26352
|
+
configSignatureRef.current = serialized;
|
|
26353
|
+
stableHlsConfigRef.current = hlsConfig;
|
|
26354
|
+
stableOptionsRef.current = options;
|
|
26355
|
+
return;
|
|
26356
|
+
}
|
|
26357
|
+
if (configSignatureRef.current !== serialized) {
|
|
26358
|
+
configSignatureRef.current = serialized;
|
|
26359
|
+
stableHlsConfigRef.current = hlsConfig;
|
|
26360
|
+
stableOptionsRef.current = options;
|
|
26361
|
+
setConfigVersion((prev) => prev + 1);
|
|
26362
|
+
}
|
|
26363
|
+
}, [hlsConfig, options]);
|
|
26364
|
+
const cleanupBlobUrl = useCallback(() => {
|
|
26365
|
+
if (blobUrlRef.current) {
|
|
26366
|
+
URL.revokeObjectURL(blobUrlRef.current);
|
|
26367
|
+
blobUrlRef.current = null;
|
|
26368
|
+
}
|
|
26369
|
+
}, []);
|
|
26370
|
+
const dispose = useCallback(() => {
|
|
26371
|
+
if (hlsRef.current) {
|
|
26372
|
+
hlsRef.current.destroy();
|
|
26373
|
+
hlsRef.current = null;
|
|
26374
|
+
}
|
|
26375
|
+
cleanupBlobUrl();
|
|
26376
|
+
setIsReady(false);
|
|
26377
|
+
}, [cleanupBlobUrl]);
|
|
26378
|
+
const playerLikeObject = useCallback(() => {
|
|
26379
|
+
return {
|
|
26380
|
+
el: () => videoRef.current,
|
|
26381
|
+
currentTime: () => videoRef.current?.currentTime || 0,
|
|
26382
|
+
duration: () => videoRef.current?.duration || 0,
|
|
26383
|
+
paused: () => videoRef.current?.paused ?? true,
|
|
26384
|
+
play: () => videoRef.current?.play(),
|
|
26385
|
+
pause: () => videoRef.current?.pause(),
|
|
26386
|
+
muted: (val) => {
|
|
26387
|
+
if (videoRef.current) {
|
|
26388
|
+
if (val !== void 0) videoRef.current.muted = val;
|
|
26389
|
+
return videoRef.current.muted;
|
|
26390
|
+
}
|
|
26391
|
+
return false;
|
|
26392
|
+
},
|
|
26393
|
+
volume: (val) => {
|
|
26394
|
+
if (videoRef.current) {
|
|
26395
|
+
if (val !== void 0) videoRef.current.volume = val;
|
|
26396
|
+
return videoRef.current.volume;
|
|
26397
|
+
}
|
|
26398
|
+
return 1;
|
|
26399
|
+
},
|
|
26400
|
+
error: () => null,
|
|
26401
|
+
dispose: () => dispose()
|
|
26252
26402
|
};
|
|
26253
|
-
|
|
26254
|
-
|
|
26255
|
-
|
|
26256
|
-
|
|
26257
|
-
|
|
26403
|
+
}, [dispose]);
|
|
26404
|
+
const initializePlayer = useCallback(() => {
|
|
26405
|
+
if (!videoRef.current || !src) return;
|
|
26406
|
+
const video = videoRef.current;
|
|
26407
|
+
const player = playerLikeObject();
|
|
26408
|
+
const mergedHlsConfig = {
|
|
26409
|
+
...BASE_HLS_CONFIG,
|
|
26410
|
+
...stableHlsConfigRef.current || {},
|
|
26411
|
+
...stableOptionsRef.current || {}
|
|
26412
|
+
};
|
|
26413
|
+
cleanupBlobUrl();
|
|
26414
|
+
const isHLS = src.endsWith(".m3u8") || src.startsWith("#EXTM3U");
|
|
26415
|
+
if (isHLS) {
|
|
26416
|
+
if (src.startsWith("#EXTM3U")) {
|
|
26417
|
+
const safariMode = isSafari();
|
|
26418
|
+
const browserName = getBrowserName();
|
|
26419
|
+
if (safariMode) {
|
|
26420
|
+
const clipIdMatch = src.match(/# Clip ID: ([a-f0-9-]+)/i);
|
|
26421
|
+
if (clipIdMatch) {
|
|
26422
|
+
const proxyUrl = `/api/clips/playlist/${clipIdMatch[1]}`;
|
|
26423
|
+
console.log(`[HlsVideoPlayer] Safari detected (${browserName}) - using playlist proxy URL:`, proxyUrl);
|
|
26424
|
+
video.src = proxyUrl;
|
|
26425
|
+
} else {
|
|
26426
|
+
console.warn("[HlsVideoPlayer] Safari detected but no clip ID found in playlist, trying blob URL fallback");
|
|
26427
|
+
const blob = new Blob([src], { type: "application/vnd.apple.mpegurl" });
|
|
26428
|
+
const blobUrl = URL.createObjectURL(blob);
|
|
26429
|
+
blobUrlRef.current = blobUrl;
|
|
26430
|
+
video.src = blobUrl;
|
|
26431
|
+
}
|
|
26432
|
+
} else if (Hls3.isSupported()) {
|
|
26433
|
+
const blob = new Blob([src], { type: "application/vnd.apple.mpegurl" });
|
|
26434
|
+
const blobUrl = URL.createObjectURL(blob);
|
|
26435
|
+
blobUrlRef.current = blobUrl;
|
|
26436
|
+
console.log(`[HlsVideoPlayer] Non-Safari browser (${browserName}) - using HLS.js with blob URL`);
|
|
26437
|
+
const hls = new Hls3(mergedHlsConfig);
|
|
26438
|
+
hlsRef.current = hls;
|
|
26439
|
+
hls.on(Events.MANIFEST_PARSED, () => {
|
|
26440
|
+
console.log("[HlsVideoPlayer] Manifest parsed, ready to play");
|
|
26441
|
+
setIsReady(true);
|
|
26442
|
+
eventCallbacksRef.current.onReady?.(player);
|
|
26443
|
+
});
|
|
26444
|
+
hls.on(Events.ERROR, (event, data) => {
|
|
26445
|
+
console.error("[HlsVideoPlayer] HLS.js error:", data);
|
|
26446
|
+
if (data.fatal) {
|
|
26447
|
+
let errorInfo;
|
|
26448
|
+
switch (data.type) {
|
|
26449
|
+
case ErrorTypes.NETWORK_ERROR:
|
|
26450
|
+
errorInfo = ERROR_MAPPING.networkError;
|
|
26451
|
+
console.log("[HlsVideoPlayer] Attempting to recover from network error");
|
|
26452
|
+
hls.startLoad();
|
|
26453
|
+
break;
|
|
26454
|
+
case ErrorTypes.MEDIA_ERROR:
|
|
26455
|
+
errorInfo = ERROR_MAPPING.mediaError;
|
|
26456
|
+
console.log("[HlsVideoPlayer] Attempting to recover from media error");
|
|
26457
|
+
hls.recoverMediaError();
|
|
26458
|
+
break;
|
|
26459
|
+
case ErrorTypes.MUX_ERROR:
|
|
26460
|
+
errorInfo = ERROR_MAPPING.muxError;
|
|
26461
|
+
break;
|
|
26462
|
+
default:
|
|
26463
|
+
errorInfo = ERROR_MAPPING.otherError;
|
|
26464
|
+
break;
|
|
26465
|
+
}
|
|
26466
|
+
errorInfo.details = data.details;
|
|
26467
|
+
eventCallbacksRef.current.onError?.(player, errorInfo);
|
|
26468
|
+
}
|
|
26469
|
+
});
|
|
26470
|
+
hls.on(Events.FRAG_LOADING, () => {
|
|
26471
|
+
setIsLoading(true);
|
|
26472
|
+
eventCallbacksRef.current.onLoadingChange?.(true);
|
|
26473
|
+
});
|
|
26474
|
+
hls.on(Events.FRAG_LOADED, () => {
|
|
26475
|
+
setIsLoading(false);
|
|
26476
|
+
eventCallbacksRef.current.onLoadingChange?.(false);
|
|
26477
|
+
});
|
|
26478
|
+
hls.loadSource(blobUrl);
|
|
26479
|
+
hls.attachMedia(video);
|
|
26480
|
+
} else {
|
|
26481
|
+
console.error("[HlsVideoPlayer] HLS.js not supported and not Safari - cannot play HLS content");
|
|
26482
|
+
const errorInfo = ERROR_MAPPING.otherError;
|
|
26483
|
+
onError?.(player, errorInfo);
|
|
26484
|
+
}
|
|
26485
|
+
} else {
|
|
26486
|
+
if (Hls3.isSupported() && !isSafari()) {
|
|
26487
|
+
const hls = new Hls3(mergedHlsConfig);
|
|
26488
|
+
hlsRef.current = hls;
|
|
26489
|
+
hls.on(Events.MANIFEST_PARSED, () => {
|
|
26490
|
+
setIsReady(true);
|
|
26491
|
+
eventCallbacksRef.current.onReady?.(player);
|
|
26492
|
+
});
|
|
26493
|
+
hls.on(Events.ERROR, (event, data) => {
|
|
26494
|
+
console.error("[HlsVideoPlayer] HLS.js error:", data);
|
|
26495
|
+
if (data.fatal) {
|
|
26496
|
+
let errorInfo;
|
|
26497
|
+
switch (data.type) {
|
|
26498
|
+
case ErrorTypes.NETWORK_ERROR:
|
|
26499
|
+
errorInfo = ERROR_MAPPING.networkError;
|
|
26500
|
+
hls.startLoad();
|
|
26501
|
+
break;
|
|
26502
|
+
case ErrorTypes.MEDIA_ERROR:
|
|
26503
|
+
errorInfo = ERROR_MAPPING.mediaError;
|
|
26504
|
+
hls.recoverMediaError();
|
|
26505
|
+
break;
|
|
26506
|
+
default:
|
|
26507
|
+
errorInfo = ERROR_MAPPING.otherError;
|
|
26508
|
+
break;
|
|
26509
|
+
}
|
|
26510
|
+
errorInfo.details = data.details;
|
|
26511
|
+
eventCallbacksRef.current.onError?.(player, errorInfo);
|
|
26512
|
+
}
|
|
26513
|
+
});
|
|
26514
|
+
hls.loadSource(src);
|
|
26515
|
+
hls.attachMedia(video);
|
|
26516
|
+
} else {
|
|
26517
|
+
video.src = src;
|
|
26518
|
+
}
|
|
26258
26519
|
}
|
|
26259
|
-
}
|
|
26260
|
-
|
|
26261
|
-
}, [date, timezoneToDisplay, dateTimeConfig?.dateFormatOptions, localeToUse]);
|
|
26262
|
-
if (!date) return null;
|
|
26263
|
-
if (variant === "minimal") {
|
|
26264
|
-
return /* @__PURE__ */ jsx("span", { className: className || "", children: date });
|
|
26265
|
-
}
|
|
26266
|
-
return /* @__PURE__ */ jsxs(
|
|
26267
|
-
motion.div,
|
|
26268
|
-
{
|
|
26269
|
-
initial: { opacity: 0, y: -5 },
|
|
26270
|
-
animate: { opacity: 1, y: 0 },
|
|
26271
|
-
transition: { duration: 0.3 },
|
|
26272
|
-
className: `flex items-center space-x-1.5 bg-white/60 backdrop-blur-sm px-2 py-0.5 rounded-md shadow-xs ${className || ""}`,
|
|
26273
|
-
children: [
|
|
26274
|
-
/* @__PURE__ */ jsx("svg", { xmlns: "http://www.w3.org/2000/svg", className: "h-3 w-3 text-blue-600", viewBox: "0 0 20 20", fill: "currentColor", children: /* @__PURE__ */ jsx("path", { fillRule: "evenodd", d: "M6 2a1 1 0 00-1 1v1H4a2 2 0 00-2 2v10a2 2 0 002 2h12a2 2 0 002-2V6a2 2 0 00-2-2h-1V3a1 1 0 10-2 0v1H7V3a1 1 0 00-1-1zm0 5a1 1 0 000 2h8a1 1 0 100-2H6z", clipRule: "evenodd" }) }),
|
|
26275
|
-
/* @__PURE__ */ jsx("span", { className: "text-[11px] font-medium text-gray-800 tracking-tight", children: date })
|
|
26276
|
-
]
|
|
26520
|
+
} else {
|
|
26521
|
+
video.src = src;
|
|
26277
26522
|
}
|
|
26278
|
-
|
|
26279
|
-
|
|
26280
|
-
|
|
26281
|
-
|
|
26282
|
-
var CardHeader3 = CardHeader2;
|
|
26283
|
-
var CardTitle3 = CardTitle2;
|
|
26284
|
-
var CardContent3 = CardContent2;
|
|
26285
|
-
var MetricCard2 = ({ title, value, unit = "", trend = null }) => {
|
|
26286
|
-
const getTrendColor = (trendValue) => {
|
|
26287
|
-
if (trendValue === null || trendValue === void 0) return "";
|
|
26288
|
-
return trendValue > 0 ? "text-green-500" : trendValue < 0 ? "text-red-500" : "text-gray-500";
|
|
26289
|
-
};
|
|
26290
|
-
const getTrendSymbol = (trendValue) => {
|
|
26291
|
-
if (trendValue === null || trendValue === void 0) return "";
|
|
26292
|
-
return trendValue > 0 ? "\u2191" : trendValue < 0 ? "\u2193" : "";
|
|
26293
|
-
};
|
|
26294
|
-
return /* @__PURE__ */ jsxs(Card3, { className: "bg-white", children: [
|
|
26295
|
-
/* @__PURE__ */ jsx(CardHeader3, { className: "pb-2", children: /* @__PURE__ */ jsx(CardTitle3, { className: "text-sm font-medium text-gray-500", children: title }) }),
|
|
26296
|
-
/* @__PURE__ */ jsx(CardContent3, { children: /* @__PURE__ */ jsxs("div", { className: "flex items-baseline justify-between", children: [
|
|
26297
|
-
/* @__PURE__ */ jsxs("div", { className: "text-2xl font-semibold", children: [
|
|
26298
|
-
value,
|
|
26299
|
-
unit && /* @__PURE__ */ jsx("span", { className: "ml-1 text-sm text-gray-500", children: unit })
|
|
26300
|
-
] }),
|
|
26301
|
-
trend !== null && trend !== void 0 && // Check trend for null/undefined before accessing
|
|
26302
|
-
/* @__PURE__ */ jsx("div", { className: `flex items-center ${getTrendColor(trend)}`, children: /* @__PURE__ */ jsxs("span", { className: "text-sm", children: [
|
|
26303
|
-
getTrendSymbol(trend),
|
|
26304
|
-
" ",
|
|
26305
|
-
Math.abs(trend),
|
|
26306
|
-
"%"
|
|
26307
|
-
] }) })
|
|
26308
|
-
] }) })
|
|
26309
|
-
] });
|
|
26310
|
-
};
|
|
26311
|
-
var MetricCard_default = MetricCard2;
|
|
26312
|
-
var TimePickerDropdown = ({
|
|
26313
|
-
value,
|
|
26314
|
-
onChange,
|
|
26315
|
-
placeholder = "Select time",
|
|
26316
|
-
className = "",
|
|
26317
|
-
disabled = false
|
|
26318
|
-
}) => {
|
|
26319
|
-
const [isOpen, setIsOpen] = useState(false);
|
|
26320
|
-
const [searchTerm, setSearchTerm] = useState("");
|
|
26321
|
-
const dropdownRef = useRef(null);
|
|
26322
|
-
const inputRef = useRef(null);
|
|
26323
|
-
const generateTimeSlots = () => {
|
|
26324
|
-
const slots = [];
|
|
26325
|
-
for (let hour = 0; hour < 24; hour++) {
|
|
26326
|
-
for (let minute = 0; minute < 60; minute += 15) {
|
|
26327
|
-
const time24 = `${hour.toString().padStart(2, "0")}:${minute.toString().padStart(2, "0")}`;
|
|
26328
|
-
const hour12 = hour === 0 ? 12 : hour > 12 ? hour - 12 : hour;
|
|
26329
|
-
const ampm = hour < 12 ? "AM" : "PM";
|
|
26330
|
-
const time12 = `${hour12}:${minute.toString().padStart(2, "0")} ${ampm}`;
|
|
26331
|
-
slots.push({ value: time24, label: time12 });
|
|
26332
|
-
}
|
|
26333
|
-
}
|
|
26334
|
-
return slots;
|
|
26335
|
-
};
|
|
26336
|
-
const timeSlots = generateTimeSlots();
|
|
26337
|
-
const filteredSlots = timeSlots.filter(
|
|
26338
|
-
(slot) => slot.label.toLowerCase().includes(searchTerm.toLowerCase())
|
|
26339
|
-
);
|
|
26340
|
-
const getDisplayValue = (value2) => {
|
|
26341
|
-
if (!value2) return "";
|
|
26342
|
-
const normalizedValue = value2.substring(0, 5);
|
|
26343
|
-
const slot = timeSlots.find((s) => s.value === normalizedValue);
|
|
26344
|
-
return slot ? slot.label : value2;
|
|
26345
|
-
};
|
|
26346
|
-
useEffect(() => {
|
|
26347
|
-
const handleClickOutside = (event) => {
|
|
26348
|
-
if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
|
|
26349
|
-
setIsOpen(false);
|
|
26350
|
-
setSearchTerm("");
|
|
26523
|
+
const handleCanPlay = () => {
|
|
26524
|
+
if (!hlsRef.current) {
|
|
26525
|
+
setIsReady(true);
|
|
26526
|
+
onReady?.(player);
|
|
26351
26527
|
}
|
|
26352
26528
|
};
|
|
26353
|
-
|
|
26354
|
-
|
|
26355
|
-
|
|
26356
|
-
|
|
26357
|
-
|
|
26358
|
-
|
|
26359
|
-
setSearchTerm("");
|
|
26360
|
-
} else if (e.key === "Enter") {
|
|
26361
|
-
e.preventDefault();
|
|
26362
|
-
if (filteredSlots.length > 0) {
|
|
26363
|
-
onChange(filteredSlots[0].value);
|
|
26364
|
-
setIsOpen(false);
|
|
26365
|
-
setSearchTerm("");
|
|
26366
|
-
}
|
|
26367
|
-
}
|
|
26368
|
-
};
|
|
26369
|
-
const handleSelect = (timeValue) => {
|
|
26370
|
-
onChange(timeValue);
|
|
26371
|
-
setIsOpen(false);
|
|
26372
|
-
setSearchTerm("");
|
|
26373
|
-
};
|
|
26374
|
-
const handleToggle = () => {
|
|
26375
|
-
if (disabled) return;
|
|
26376
|
-
setIsOpen(!isOpen);
|
|
26377
|
-
if (!isOpen) {
|
|
26378
|
-
setTimeout(() => inputRef.current?.focus(), 100);
|
|
26379
|
-
}
|
|
26380
|
-
};
|
|
26381
|
-
return /* @__PURE__ */ jsxs("div", { className: `relative ${className}`, ref: dropdownRef, children: [
|
|
26382
|
-
/* @__PURE__ */ jsx(
|
|
26383
|
-
"button",
|
|
26384
|
-
{
|
|
26385
|
-
type: "button",
|
|
26386
|
-
onClick: handleToggle,
|
|
26387
|
-
disabled,
|
|
26388
|
-
className: `
|
|
26389
|
-
w-full px-3 py-2 text-left bg-white border border-gray-300 rounded-md shadow-sm
|
|
26390
|
-
focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500
|
|
26391
|
-
hover:border-gray-400 transition-colors duration-200
|
|
26392
|
-
${disabled ? "bg-gray-50 cursor-not-allowed" : "cursor-pointer"}
|
|
26393
|
-
${isOpen ? "ring-2 ring-blue-500 border-blue-500" : ""}
|
|
26394
|
-
`,
|
|
26395
|
-
children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
|
|
26396
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
26397
|
-
/* @__PURE__ */ jsx(Clock, { className: "h-4 w-4 text-gray-400" }),
|
|
26398
|
-
/* @__PURE__ */ jsx("span", { className: `text-sm ${value ? "text-gray-900" : "text-gray-500"}`, children: value ? getDisplayValue(value) : placeholder })
|
|
26399
|
-
] }),
|
|
26400
|
-
/* @__PURE__ */ jsx(
|
|
26401
|
-
ChevronDown,
|
|
26402
|
-
{
|
|
26403
|
-
className: `h-4 w-4 text-gray-400 transition-transform duration-200 ${isOpen ? "rotate-180" : ""}`
|
|
26404
|
-
}
|
|
26405
|
-
)
|
|
26406
|
-
] })
|
|
26407
|
-
}
|
|
26408
|
-
),
|
|
26409
|
-
isOpen && /* @__PURE__ */ jsxs("div", { className: "absolute z-50 w-full mt-1 bg-white border border-gray-300 rounded-md shadow-lg max-h-60 overflow-hidden", children: [
|
|
26410
|
-
/* @__PURE__ */ jsx("div", { className: "p-2 border-b border-gray-200", children: /* @__PURE__ */ jsx(
|
|
26411
|
-
"input",
|
|
26412
|
-
{
|
|
26413
|
-
ref: inputRef,
|
|
26414
|
-
type: "text",
|
|
26415
|
-
placeholder: "Search time...",
|
|
26416
|
-
value: searchTerm,
|
|
26417
|
-
onChange: (e) => setSearchTerm(e.target.value),
|
|
26418
|
-
onKeyDown: handleKeyDown,
|
|
26419
|
-
className: "w-full px-3 py-2 text-sm border border-gray-200 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
|
|
26420
|
-
}
|
|
26421
|
-
) }),
|
|
26422
|
-
/* @__PURE__ */ jsx("div", { className: "overflow-y-auto max-h-48", children: filteredSlots.length === 0 ? /* @__PURE__ */ jsx("div", { className: "px-3 py-2 text-sm text-gray-500 text-center", children: "No times found" }) : filteredSlots.map((slot) => /* @__PURE__ */ jsx(
|
|
26423
|
-
"button",
|
|
26424
|
-
{
|
|
26425
|
-
type: "button",
|
|
26426
|
-
onClick: () => handleSelect(slot.value),
|
|
26427
|
-
className: `
|
|
26428
|
-
w-full px-3 py-2 text-left text-sm hover:bg-blue-50 hover:text-blue-600
|
|
26429
|
-
transition-colors duration-150 border-b border-gray-100 last:border-b-0
|
|
26430
|
-
${slot.value === value ? "bg-blue-50 text-blue-600 font-medium" : "text-gray-700"}
|
|
26431
|
-
`,
|
|
26432
|
-
children: slot.label
|
|
26433
|
-
},
|
|
26434
|
-
slot.value
|
|
26435
|
-
)) })
|
|
26436
|
-
] })
|
|
26437
|
-
] });
|
|
26438
|
-
};
|
|
26439
|
-
var SilentErrorBoundary = class extends React23__default.Component {
|
|
26440
|
-
constructor(props) {
|
|
26441
|
-
super(props);
|
|
26442
|
-
this.handleClearAndReload = () => {
|
|
26443
|
-
console.log("[ErrorBoundary] User initiated reset");
|
|
26444
|
-
if (typeof window !== "undefined") {
|
|
26445
|
-
try {
|
|
26446
|
-
localStorage.clear();
|
|
26447
|
-
sessionStorage.clear();
|
|
26448
|
-
console.log("[ErrorBoundary] Cleared all storage");
|
|
26449
|
-
} catch (error) {
|
|
26450
|
-
console.error("[ErrorBoundary] Failed to clear storage:", error);
|
|
26451
|
-
}
|
|
26452
|
-
}
|
|
26453
|
-
window.location.href = "/login";
|
|
26529
|
+
const handlePlay = () => eventCallbacksRef.current.onPlay?.(player);
|
|
26530
|
+
const handlePause = () => eventCallbacksRef.current.onPause?.(player);
|
|
26531
|
+
const handlePlaying = () => {
|
|
26532
|
+
setIsLoading(false);
|
|
26533
|
+
eventCallbacksRef.current.onLoadingChange?.(false);
|
|
26534
|
+
eventCallbacksRef.current.onPlaying?.(player);
|
|
26454
26535
|
};
|
|
26455
|
-
|
|
26456
|
-
|
|
26457
|
-
|
|
26458
|
-
lastError: null,
|
|
26459
|
-
errorInfo: null
|
|
26536
|
+
const handleTimeUpdate = () => {
|
|
26537
|
+
const currentTime2 = video.currentTime || 0;
|
|
26538
|
+
eventCallbacksRef.current.onTimeUpdate?.(player, currentTime2);
|
|
26460
26539
|
};
|
|
26461
|
-
|
|
26462
|
-
|
|
26463
|
-
|
|
26464
|
-
|
|
26465
|
-
|
|
26466
|
-
|
|
26467
|
-
error: error.message,
|
|
26468
|
-
stack: error.stack,
|
|
26469
|
-
componentStack: errorInfo.componentStack,
|
|
26470
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
26471
|
-
});
|
|
26472
|
-
this.setState((prev) => ({
|
|
26473
|
-
errorCount: prev.errorCount + 1,
|
|
26474
|
-
lastError: error,
|
|
26475
|
-
errorInfo
|
|
26476
|
-
}));
|
|
26477
|
-
try {
|
|
26478
|
-
if (typeof window !== "undefined" && window.mixpanel) {
|
|
26479
|
-
window.mixpanel.track("React Render Error", {
|
|
26480
|
-
error: error.message,
|
|
26481
|
-
component: errorInfo.componentStack?.split("\n")[1] || "unknown",
|
|
26482
|
-
errorCount: this.state.errorCount + 1
|
|
26483
|
-
});
|
|
26484
|
-
}
|
|
26485
|
-
} catch (analyticsError) {
|
|
26486
|
-
console.warn("[ErrorBoundary] Analytics tracking failed:", analyticsError);
|
|
26487
|
-
}
|
|
26488
|
-
}
|
|
26489
|
-
render() {
|
|
26490
|
-
if (!this.state.hasError) {
|
|
26491
|
-
return this.props.children;
|
|
26492
|
-
}
|
|
26493
|
-
return /* @__PURE__ */ jsx("div", { className: "flex h-screen w-screen items-center justify-center bg-slate-50", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center space-y-6 text-center", children: [
|
|
26494
|
-
/* @__PURE__ */ jsx(OptifyeLogoLoader_default, { size: "lg", message: "Loading Dashboard..." }),
|
|
26495
|
-
/* @__PURE__ */ jsx("p", { className: "text-sm text-gray-500", children: "Taking longer than usual..." }),
|
|
26496
|
-
/* @__PURE__ */ jsx("div", { className: "pt-4", children: /* @__PURE__ */ jsx(
|
|
26497
|
-
"a",
|
|
26498
|
-
{
|
|
26499
|
-
href: "#",
|
|
26500
|
-
onClick: (e) => {
|
|
26501
|
-
e.preventDefault();
|
|
26502
|
-
this.handleClearAndReload();
|
|
26503
|
-
},
|
|
26504
|
-
className: "text-xs text-gray-400 hover:text-gray-600 underline transition-colors",
|
|
26505
|
-
children: "Reset and try again"
|
|
26506
|
-
}
|
|
26507
|
-
) }),
|
|
26508
|
-
process.env.NODE_ENV === "development" && /* @__PURE__ */ jsx("p", { className: "text-xs text-gray-400 italic mt-4", children: "Check console for error details" })
|
|
26509
|
-
] }) });
|
|
26510
|
-
}
|
|
26511
|
-
};
|
|
26512
|
-
var PlayPauseIndicator = ({
|
|
26513
|
-
show,
|
|
26514
|
-
isPlaying,
|
|
26515
|
-
duration = 600
|
|
26516
|
-
}) => {
|
|
26517
|
-
const [isVisible, setIsVisible] = useState(false);
|
|
26518
|
-
const [isFading, setIsFading] = useState(false);
|
|
26519
|
-
useEffect(() => {
|
|
26520
|
-
if (show) {
|
|
26521
|
-
setIsVisible(true);
|
|
26522
|
-
setIsFading(false);
|
|
26523
|
-
const fadeTimer = setTimeout(() => {
|
|
26524
|
-
setIsFading(true);
|
|
26525
|
-
}, 100);
|
|
26526
|
-
const hideTimer = setTimeout(() => {
|
|
26527
|
-
setIsVisible(false);
|
|
26528
|
-
setIsFading(false);
|
|
26529
|
-
}, duration);
|
|
26530
|
-
return () => {
|
|
26531
|
-
clearTimeout(fadeTimer);
|
|
26532
|
-
clearTimeout(hideTimer);
|
|
26533
|
-
};
|
|
26534
|
-
}
|
|
26535
|
-
}, [show, duration]);
|
|
26536
|
-
if (!isVisible) return null;
|
|
26537
|
-
return /* @__PURE__ */ jsx(
|
|
26538
|
-
"div",
|
|
26539
|
-
{
|
|
26540
|
-
className: "absolute inset-0 flex items-center justify-center pointer-events-none z-10",
|
|
26541
|
-
style: {
|
|
26542
|
-
opacity: isFading ? 0 : 1,
|
|
26543
|
-
transition: `opacity ${duration - 100}ms ease-out`
|
|
26544
|
-
},
|
|
26545
|
-
children: /* @__PURE__ */ jsx("div", { className: "bg-black/70 rounded-full p-6", children: isPlaying ? (
|
|
26546
|
-
// Play icon (triangle)
|
|
26547
|
-
/* @__PURE__ */ jsx(
|
|
26548
|
-
"svg",
|
|
26549
|
-
{
|
|
26550
|
-
xmlns: "http://www.w3.org/2000/svg",
|
|
26551
|
-
viewBox: "0 0 24 24",
|
|
26552
|
-
fill: "white",
|
|
26553
|
-
className: "w-16 h-16",
|
|
26554
|
-
children: /* @__PURE__ */ jsx("path", { d: "M8 5v14l11-7z" })
|
|
26555
|
-
}
|
|
26556
|
-
)
|
|
26557
|
-
) : (
|
|
26558
|
-
// Pause icon (two bars)
|
|
26559
|
-
/* @__PURE__ */ jsx(
|
|
26560
|
-
"svg",
|
|
26561
|
-
{
|
|
26562
|
-
xmlns: "http://www.w3.org/2000/svg",
|
|
26563
|
-
viewBox: "0 0 24 24",
|
|
26564
|
-
fill: "white",
|
|
26565
|
-
className: "w-16 h-16",
|
|
26566
|
-
children: /* @__PURE__ */ jsx("path", { d: "M6 4h4v16H6V4zm8 0h4v16h-4V4z" })
|
|
26567
|
-
}
|
|
26568
|
-
)
|
|
26569
|
-
) })
|
|
26570
|
-
}
|
|
26571
|
-
);
|
|
26572
|
-
};
|
|
26573
|
-
var ERROR_MAPPING = {
|
|
26574
|
-
1: {
|
|
26575
|
-
// MEDIA_ERR_ABORTED
|
|
26576
|
-
code: 1,
|
|
26577
|
-
type: "recoverable" /* RECOVERABLE */,
|
|
26578
|
-
message: "Video loading was interrupted",
|
|
26579
|
-
canRetry: true
|
|
26580
|
-
},
|
|
26581
|
-
2: {
|
|
26582
|
-
// MEDIA_ERR_NETWORK
|
|
26583
|
-
code: 2,
|
|
26584
|
-
type: "recoverable" /* RECOVERABLE */,
|
|
26585
|
-
message: "Network error - please check your internet connection",
|
|
26586
|
-
canRetry: true
|
|
26587
|
-
},
|
|
26588
|
-
3: {
|
|
26589
|
-
// MEDIA_ERR_DECODE
|
|
26590
|
-
code: 3,
|
|
26591
|
-
type: "non_recoverable" /* NON_RECOVERABLE */,
|
|
26592
|
-
message: "Stream corrupted due to internet connection",
|
|
26593
|
-
canRetry: false
|
|
26594
|
-
},
|
|
26595
|
-
4: {
|
|
26596
|
-
// MEDIA_ERR_SRC_NOT_SUPPORTED
|
|
26597
|
-
code: 4,
|
|
26598
|
-
type: "non_recoverable" /* NON_RECOVERABLE */,
|
|
26599
|
-
message: "Video format not supported by your browser. Please use Google Chrome.",
|
|
26600
|
-
canRetry: false
|
|
26601
|
-
}
|
|
26602
|
-
};
|
|
26603
|
-
var videoPlayerStyles = `
|
|
26604
|
-
.video-player-container {
|
|
26605
|
-
width: 100%;
|
|
26606
|
-
height: 100%;
|
|
26607
|
-
background-color: #000;
|
|
26608
|
-
display: flex;
|
|
26609
|
-
align-items: center;
|
|
26610
|
-
justify-content: center;
|
|
26611
|
-
}
|
|
26612
|
-
|
|
26613
|
-
/* Center the video player and maintain aspect ratio */
|
|
26614
|
-
.video-js {
|
|
26615
|
-
width: 100%;
|
|
26616
|
-
height: 100%;
|
|
26617
|
-
max-width: 100%;
|
|
26618
|
-
max-height: 100%;
|
|
26619
|
-
}
|
|
26620
|
-
|
|
26621
|
-
/* Ensure video maintains aspect ratio and shows fully */
|
|
26622
|
-
.video-js .vjs-tech {
|
|
26623
|
-
position: absolute;
|
|
26624
|
-
top: 0;
|
|
26625
|
-
left: 0;
|
|
26626
|
-
width: 100%;
|
|
26627
|
-
height: 100%;
|
|
26628
|
-
object-fit: contain;
|
|
26629
|
-
}
|
|
26630
|
-
|
|
26631
|
-
/* Hide default Video.js loading spinner */
|
|
26632
|
-
.video-js .vjs-loading-spinner {
|
|
26633
|
-
display: none !important;
|
|
26634
|
-
}
|
|
26635
|
-
|
|
26636
|
-
/* Custom loading indicator styles */
|
|
26637
|
-
.video-player-loading {
|
|
26638
|
-
position: absolute;
|
|
26639
|
-
top: 50%;
|
|
26640
|
-
left: 50%;
|
|
26641
|
-
transform: translate(-50%, -50%);
|
|
26642
|
-
z-index: 10;
|
|
26643
|
-
}
|
|
26644
|
-
`;
|
|
26645
|
-
if (typeof document !== "undefined") {
|
|
26646
|
-
const styleId = "video-player-custom-styles";
|
|
26647
|
-
if (!document.getElementById(styleId)) {
|
|
26648
|
-
const style = document.createElement("style");
|
|
26649
|
-
style.id = styleId;
|
|
26650
|
-
style.textContent = videoPlayerStyles;
|
|
26651
|
-
document.head.appendChild(style);
|
|
26652
|
-
}
|
|
26653
|
-
}
|
|
26654
|
-
var VideoPlayer = React23__default.forwardRef(({
|
|
26655
|
-
src,
|
|
26656
|
-
poster,
|
|
26657
|
-
autoplay = false,
|
|
26658
|
-
controls = true,
|
|
26659
|
-
loop = false,
|
|
26660
|
-
muted = false,
|
|
26661
|
-
playsInline = true,
|
|
26662
|
-
className = "",
|
|
26663
|
-
options = {},
|
|
26664
|
-
externalLoadingControl = false,
|
|
26665
|
-
onLoadingChange,
|
|
26666
|
-
onReady,
|
|
26667
|
-
onPlay,
|
|
26668
|
-
onPause,
|
|
26669
|
-
onPlaying,
|
|
26670
|
-
onTimeUpdate,
|
|
26671
|
-
onDurationChange,
|
|
26672
|
-
onEnded,
|
|
26673
|
-
onError,
|
|
26674
|
-
onLoadStart,
|
|
26675
|
-
onLoadedMetadata,
|
|
26676
|
-
onLoadedData,
|
|
26677
|
-
onSeeking,
|
|
26678
|
-
onSeeked,
|
|
26679
|
-
onClick
|
|
26680
|
-
}, ref) => {
|
|
26681
|
-
const videoRef = useRef(null);
|
|
26682
|
-
const playerRef = useRef(null);
|
|
26683
|
-
const [isReady, setIsReady] = useState(false);
|
|
26684
|
-
const [isLoading, setIsLoading] = useState(true);
|
|
26685
|
-
const [showIndicator, setShowIndicator] = useState(false);
|
|
26686
|
-
const [indicatorIsPlaying, setIndicatorIsPlaying] = useState(false);
|
|
26687
|
-
const indicatorKeyRef = useRef(0);
|
|
26688
|
-
const defaultOptions = {
|
|
26689
|
-
controls: false,
|
|
26690
|
-
// Always disable Video.js controls - we use custom controls
|
|
26691
|
-
// Don't use fluid or fill - let the video maintain its natural aspect ratio
|
|
26692
|
-
fluid: false,
|
|
26693
|
-
// Disable fluid mode to prevent stretching
|
|
26694
|
-
responsive: false,
|
|
26695
|
-
// Disable responsive mode
|
|
26696
|
-
fill: false,
|
|
26697
|
-
// Don't fill - maintain aspect ratio
|
|
26698
|
-
playsinline: playsInline,
|
|
26699
|
-
preload: "metadata",
|
|
26700
|
-
autoplay: autoplay ? "any" : false,
|
|
26701
|
-
muted,
|
|
26702
|
-
loop,
|
|
26703
|
-
poster,
|
|
26704
|
-
// Optimized HLS configuration for VOD content with LARGE SEGMENTS (40MB)
|
|
26705
|
-
// Strategy: Aggressive buffer reduction for faster startup with large segments
|
|
26706
|
-
html5: {
|
|
26707
|
-
vhs: {
|
|
26708
|
-
// VHS (Video HTTP Streaming) options for HLS
|
|
26709
|
-
withCredentials: false,
|
|
26710
|
-
handleManifestRedirect: true,
|
|
26711
|
-
overrideNative: !videojs.browser.IS_SAFARI,
|
|
26712
|
-
// Use native HLS on Safari
|
|
26713
|
-
enableLowInitialPlaylist: true,
|
|
26714
|
-
smoothQualityChange: true,
|
|
26715
|
-
// Optimized bandwidth and buffering for VOD
|
|
26716
|
-
bandwidth: 5e7,
|
|
26717
|
-
// Start with high bandwidth assumption (50 Mbps)
|
|
26718
|
-
initialBandwidth: 5e7,
|
|
26719
|
-
// Assume good connection initially
|
|
26720
|
-
limitRenditionByPlayerDimensions: true,
|
|
26721
|
-
// Buffer configuration optimized for large segments (40MB each)
|
|
26722
|
-
maxBufferLength: 3,
|
|
26723
|
-
// Start playing with just 3 seconds ahead
|
|
26724
|
-
maxMaxBufferLength: 8,
|
|
26725
|
-
// Maximum 8 seconds buffer for faster startup
|
|
26726
|
-
maxBufferSize: 50 * 1e3 * 1e3,
|
|
26727
|
-
// 50MB max buffer size (1.25 segments)
|
|
26728
|
-
maxBufferHole: 0.25,
|
|
26729
|
-
// Smaller holes for better continuity
|
|
26730
|
-
bufferBasedABR: false,
|
|
26731
|
-
// Disable for more predictable behavior
|
|
26732
|
-
// Segment loading optimization for large segments (40MB)
|
|
26733
|
-
maxPlaylistRetries: 3,
|
|
26734
|
-
playlistRetryDelay: 500,
|
|
26735
|
-
// 500ms between retries
|
|
26736
|
-
playlistExclusionDuration: 60,
|
|
26737
|
-
segmentLoadingRetryAttempts: 5,
|
|
26738
|
-
// More retries for large segments
|
|
26739
|
-
segmentLoadingRetryDelay: 500,
|
|
26740
|
-
// Faster retry for responsiveness
|
|
26741
|
-
segmentLoadingTimeOut: 6e4,
|
|
26742
|
-
// 60s timeout for 40MB segments
|
|
26743
|
-
manifestLoadingTimeOut: 15e3,
|
|
26744
|
-
// 15s timeout for manifest
|
|
26745
|
-
// Performance optimizations
|
|
26746
|
-
experimentalBufferBasedCodecSwitching: true,
|
|
26747
|
-
experimentalCacheEncryptionKeys: true,
|
|
26748
|
-
handlePartialData: true,
|
|
26749
|
-
allowSeeksWithinUnsafeLiveWindow: false,
|
|
26750
|
-
// VOD content
|
|
26751
|
-
experimentalLLHLS: false,
|
|
26752
|
-
// Disable Low Latency HLS for VOD
|
|
26753
|
-
// Connection settings
|
|
26754
|
-
// Chrome 130+ started throwing "Cannot perform Construct on a detached ArrayBuffer"
|
|
26755
|
-
// whenever the transmux worker tried to rehydrate transferred buffers that originated
|
|
26756
|
-
// from Blob-based playlists. Disabling the worker keeps playback stable at the cost
|
|
26757
|
-
// of slightly higher main-thread usage, which is acceptable for the dashboard usage.
|
|
26758
|
-
enableWorker: false,
|
|
26759
|
-
progressive: true,
|
|
26760
|
-
// Progressive download
|
|
26761
|
-
// Adaptive bitrate settings (if multi-quality available)
|
|
26762
|
-
abrEwmaFastLive: 3,
|
|
26763
|
-
abrEwmaSlowLive: 9,
|
|
26764
|
-
abrBandWidthFactor: 0.95,
|
|
26765
|
-
abrBandWidthUpFactor: 0.7,
|
|
26766
|
-
abrMaxWithRealBitrate: false,
|
|
26767
|
-
// Request options optimized for large segments
|
|
26768
|
-
requestOptions: {
|
|
26769
|
-
timeout: 9e4,
|
|
26770
|
-
// 90s timeout for 40MB segments
|
|
26771
|
-
maxRetry: 5
|
|
26772
|
-
// More retries for reliability
|
|
26773
|
-
}
|
|
26774
|
-
},
|
|
26775
|
-
nativeVideoTracks: false,
|
|
26776
|
-
nativeAudioTracks: false,
|
|
26777
|
-
nativeTextTracks: false
|
|
26778
|
-
},
|
|
26779
|
-
// Improved seeking and scrubbing
|
|
26780
|
-
inactivityTimeout: 3e3,
|
|
26781
|
-
// Better error handling
|
|
26782
|
-
errorDisplay: false,
|
|
26783
|
-
// We'll handle errors with callbacks
|
|
26784
|
-
// Fullscreen options
|
|
26785
|
-
fullscreen: {
|
|
26786
|
-
options: {
|
|
26787
|
-
navigationUI: "hide"
|
|
26788
|
-
}
|
|
26789
|
-
},
|
|
26790
|
-
...options
|
|
26791
|
-
};
|
|
26792
|
-
const initializePlayer = useCallback(() => {
|
|
26793
|
-
if (!videoRef.current || playerRef.current) return;
|
|
26794
|
-
const videoElement = document.createElement("video-js");
|
|
26795
|
-
videoElement.className = "vjs-default-skin";
|
|
26796
|
-
videoRef.current.appendChild(videoElement);
|
|
26797
|
-
const player = videojs(videoElement, defaultOptions);
|
|
26798
|
-
playerRef.current = player;
|
|
26799
|
-
player.ready(() => {
|
|
26800
|
-
setIsReady(true);
|
|
26801
|
-
onReady?.(player);
|
|
26802
|
-
});
|
|
26803
|
-
player.on("play", () => onPlay?.(player));
|
|
26804
|
-
player.on("pause", () => onPause?.(player));
|
|
26805
|
-
player.on("playing", () => onPlaying?.(player));
|
|
26806
|
-
player.on("timeupdate", () => {
|
|
26807
|
-
const currentTime2 = player.currentTime() || 0;
|
|
26808
|
-
onTimeUpdate?.(player, currentTime2);
|
|
26809
|
-
});
|
|
26810
|
-
player.on("durationchange", () => {
|
|
26811
|
-
const duration2 = player.duration() || 0;
|
|
26812
|
-
onDurationChange?.(player, duration2);
|
|
26813
|
-
});
|
|
26814
|
-
player.on("ended", () => onEnded?.(player));
|
|
26815
|
-
player.on("loadstart", () => {
|
|
26540
|
+
const handleDurationChange = () => {
|
|
26541
|
+
const duration2 = video.duration || 0;
|
|
26542
|
+
eventCallbacksRef.current.onDurationChange?.(player, duration2);
|
|
26543
|
+
};
|
|
26544
|
+
const handleEnded = () => eventCallbacksRef.current.onEnded?.(player);
|
|
26545
|
+
const handleLoadStart = () => {
|
|
26816
26546
|
setIsLoading(true);
|
|
26817
|
-
onLoadingChange?.(true);
|
|
26818
|
-
onLoadStart?.(player);
|
|
26819
|
-
}
|
|
26820
|
-
|
|
26547
|
+
eventCallbacksRef.current.onLoadingChange?.(true);
|
|
26548
|
+
eventCallbacksRef.current.onLoadStart?.(player);
|
|
26549
|
+
};
|
|
26550
|
+
const handleLoadedMetadata = () => eventCallbacksRef.current.onLoadedMetadata?.(player);
|
|
26551
|
+
const handleLoadedData = () => {
|
|
26821
26552
|
setIsLoading(false);
|
|
26822
|
-
onLoadingChange?.(false);
|
|
26823
|
-
onLoadedData?.(player);
|
|
26824
|
-
}
|
|
26825
|
-
|
|
26553
|
+
eventCallbacksRef.current.onLoadingChange?.(false);
|
|
26554
|
+
eventCallbacksRef.current.onLoadedData?.(player);
|
|
26555
|
+
};
|
|
26556
|
+
const handleWaiting = () => {
|
|
26826
26557
|
setIsLoading(true);
|
|
26827
|
-
onLoadingChange?.(true);
|
|
26828
|
-
}
|
|
26829
|
-
|
|
26830
|
-
|
|
26831
|
-
|
|
26832
|
-
|
|
26833
|
-
|
|
26834
|
-
|
|
26835
|
-
|
|
26836
|
-
|
|
26837
|
-
|
|
26838
|
-
|
|
26839
|
-
|
|
26840
|
-
|
|
26841
|
-
const errorInfo = ERROR_MAPPING[errorCode] || {
|
|
26842
|
-
code: errorCode || 0,
|
|
26843
|
-
type: "non_recoverable" /* NON_RECOVERABLE */,
|
|
26844
|
-
message: "Unknown playback error occurred",
|
|
26845
|
-
canRetry: false
|
|
26846
|
-
};
|
|
26847
|
-
console.error("[VideoPlayer] Video.js error:", {
|
|
26848
|
-
code: errorCode,
|
|
26849
|
-
type: errorInfo.type,
|
|
26850
|
-
message: errorInfo.message,
|
|
26851
|
-
canRetry: errorInfo.canRetry,
|
|
26852
|
-
originalError: error
|
|
26853
|
-
});
|
|
26854
|
-
onError?.(player, errorInfo);
|
|
26855
|
-
});
|
|
26856
|
-
if (src) {
|
|
26857
|
-
const isHLS = src.endsWith(".m3u8") || src.startsWith("#EXTM3U");
|
|
26858
|
-
let videoSrc = src;
|
|
26859
|
-
let blobUrl = null;
|
|
26860
|
-
if (src.startsWith("#EXTM3U")) {
|
|
26861
|
-
const safariMode = isSafari();
|
|
26862
|
-
const browserName = getBrowserName();
|
|
26863
|
-
if (safariMode) {
|
|
26864
|
-
const clipIdMatch = src.match(/# Clip ID: ([a-f0-9-]+)/i);
|
|
26865
|
-
if (clipIdMatch) {
|
|
26866
|
-
videoSrc = `/api/clips/playlist/${clipIdMatch[1]}`;
|
|
26867
|
-
console.log(`[VideoPlayer] Safari detected (${browserName}) - using playlist proxy URL:`, videoSrc);
|
|
26868
|
-
} else {
|
|
26869
|
-
console.warn("[VideoPlayer] Safari detected but no clip ID found in playlist, trying blob URL fallback");
|
|
26870
|
-
const blob = new Blob([src], { type: "application/vnd.apple.mpegurl" });
|
|
26871
|
-
blobUrl = URL.createObjectURL(blob);
|
|
26872
|
-
videoSrc = blobUrl;
|
|
26873
|
-
player._blobUrl = videoSrc;
|
|
26874
|
-
}
|
|
26875
|
-
} else {
|
|
26876
|
-
const blob = new Blob([src], { type: "application/vnd.apple.mpegurl" });
|
|
26877
|
-
blobUrl = URL.createObjectURL(blob);
|
|
26878
|
-
videoSrc = blobUrl;
|
|
26879
|
-
console.log(`[VideoPlayer] Non-Safari browser (${browserName}) - using blob URL for optimal performance`);
|
|
26880
|
-
player._blobUrl = videoSrc;
|
|
26881
|
-
}
|
|
26558
|
+
eventCallbacksRef.current.onLoadingChange?.(true);
|
|
26559
|
+
};
|
|
26560
|
+
const handleSeeking = () => eventCallbacksRef.current.onSeeking?.(player);
|
|
26561
|
+
const handleSeeked = () => eventCallbacksRef.current.onSeeked?.(player);
|
|
26562
|
+
const handleError = () => {
|
|
26563
|
+
const error = video.error;
|
|
26564
|
+
if (error) {
|
|
26565
|
+
const errorInfo = {
|
|
26566
|
+
code: error.code,
|
|
26567
|
+
type: error.code <= 2 ? "recoverable" : "non_recoverable",
|
|
26568
|
+
message: error.message || "Unknown error occurred",
|
|
26569
|
+
canRetry: error.code <= 2
|
|
26570
|
+
};
|
|
26571
|
+
eventCallbacksRef.current.onError?.(player, errorInfo);
|
|
26882
26572
|
}
|
|
26883
|
-
|
|
26884
|
-
|
|
26885
|
-
|
|
26886
|
-
|
|
26887
|
-
|
|
26573
|
+
};
|
|
26574
|
+
video.addEventListener("canplay", handleCanPlay);
|
|
26575
|
+
video.addEventListener("play", handlePlay);
|
|
26576
|
+
video.addEventListener("pause", handlePause);
|
|
26577
|
+
video.addEventListener("playing", handlePlaying);
|
|
26578
|
+
video.addEventListener("timeupdate", handleTimeUpdate);
|
|
26579
|
+
video.addEventListener("durationchange", handleDurationChange);
|
|
26580
|
+
video.addEventListener("ended", handleEnded);
|
|
26581
|
+
video.addEventListener("loadstart", handleLoadStart);
|
|
26582
|
+
video.addEventListener("loadedmetadata", handleLoadedMetadata);
|
|
26583
|
+
video.addEventListener("loadeddata", handleLoadedData);
|
|
26584
|
+
video.addEventListener("waiting", handleWaiting);
|
|
26585
|
+
video.addEventListener("seeking", handleSeeking);
|
|
26586
|
+
video.addEventListener("seeked", handleSeeked);
|
|
26587
|
+
video.addEventListener("error", handleError);
|
|
26588
|
+
return () => {
|
|
26589
|
+
video.removeEventListener("canplay", handleCanPlay);
|
|
26590
|
+
video.removeEventListener("play", handlePlay);
|
|
26591
|
+
video.removeEventListener("pause", handlePause);
|
|
26592
|
+
video.removeEventListener("playing", handlePlaying);
|
|
26593
|
+
video.removeEventListener("timeupdate", handleTimeUpdate);
|
|
26594
|
+
video.removeEventListener("durationchange", handleDurationChange);
|
|
26595
|
+
video.removeEventListener("ended", handleEnded);
|
|
26596
|
+
video.removeEventListener("loadstart", handleLoadStart);
|
|
26597
|
+
video.removeEventListener("loadedmetadata", handleLoadedMetadata);
|
|
26598
|
+
video.removeEventListener("loadeddata", handleLoadedData);
|
|
26599
|
+
video.removeEventListener("waiting", handleWaiting);
|
|
26600
|
+
video.removeEventListener("seeking", handleSeeking);
|
|
26601
|
+
video.removeEventListener("seeked", handleSeeked);
|
|
26602
|
+
video.removeEventListener("error", handleError);
|
|
26603
|
+
};
|
|
26888
26604
|
}, [
|
|
26889
26605
|
src,
|
|
26890
|
-
|
|
26891
|
-
|
|
26892
|
-
|
|
26893
|
-
onPause,
|
|
26894
|
-
onTimeUpdate,
|
|
26895
|
-
onDurationChange,
|
|
26896
|
-
onEnded,
|
|
26897
|
-
onError,
|
|
26898
|
-
onLoadStart,
|
|
26899
|
-
onLoadedMetadata,
|
|
26900
|
-
onSeeking,
|
|
26901
|
-
onSeeked
|
|
26606
|
+
cleanupBlobUrl,
|
|
26607
|
+
playerLikeObject,
|
|
26608
|
+
configVersion
|
|
26902
26609
|
]);
|
|
26903
26610
|
useEffect(() => {
|
|
26904
|
-
|
|
26905
|
-
const isHLS = src.endsWith(".m3u8") || src.startsWith("#EXTM3U");
|
|
26906
|
-
let videoSrc = src;
|
|
26907
|
-
let blobUrl = null;
|
|
26908
|
-
if (src.startsWith("#EXTM3U")) {
|
|
26909
|
-
const safariMode = isSafari();
|
|
26910
|
-
const browserName = getBrowserName();
|
|
26911
|
-
if (safariMode) {
|
|
26912
|
-
const clipIdMatch = src.match(/# Clip ID: ([a-f0-9-]+)/i);
|
|
26913
|
-
if (clipIdMatch) {
|
|
26914
|
-
videoSrc = `/api/clips/playlist/${clipIdMatch[1]}`;
|
|
26915
|
-
console.log(`[VideoPlayer] Safari detected (${browserName}) - using playlist proxy URL for source update:`, videoSrc);
|
|
26916
|
-
} else {
|
|
26917
|
-
console.warn("[VideoPlayer] Safari detected but no clip ID found in playlist (source update), trying blob URL fallback");
|
|
26918
|
-
const blob = new Blob([src], { type: "application/vnd.apple.mpegurl" });
|
|
26919
|
-
blobUrl = URL.createObjectURL(blob);
|
|
26920
|
-
videoSrc = blobUrl;
|
|
26921
|
-
}
|
|
26922
|
-
} else {
|
|
26923
|
-
const blob = new Blob([src], { type: "application/vnd.apple.mpegurl" });
|
|
26924
|
-
blobUrl = URL.createObjectURL(blob);
|
|
26925
|
-
videoSrc = blobUrl;
|
|
26926
|
-
console.log(`[VideoPlayer] Non-Safari browser (${browserName}) - using blob URL for source update`);
|
|
26927
|
-
}
|
|
26928
|
-
}
|
|
26929
|
-
playerRef.current.src({
|
|
26930
|
-
src: videoSrc,
|
|
26931
|
-
type: isHLS ? "application/x-mpegURL" : "video/mp4"
|
|
26932
|
-
});
|
|
26933
|
-
return () => {
|
|
26934
|
-
if (blobUrl) {
|
|
26935
|
-
URL.revokeObjectURL(blobUrl);
|
|
26936
|
-
}
|
|
26937
|
-
};
|
|
26938
|
-
}
|
|
26939
|
-
}, [src]);
|
|
26940
|
-
useEffect(() => {
|
|
26941
|
-
initializePlayer();
|
|
26611
|
+
const cleanup = initializePlayer();
|
|
26942
26612
|
return () => {
|
|
26943
|
-
|
|
26944
|
-
|
|
26945
|
-
|
|
26946
|
-
|
|
26947
|
-
}
|
|
26948
|
-
playerRef.current.dispose();
|
|
26949
|
-
playerRef.current = null;
|
|
26950
|
-
setIsReady(false);
|
|
26613
|
+
cleanup?.();
|
|
26614
|
+
if (hlsRef.current) {
|
|
26615
|
+
hlsRef.current.destroy();
|
|
26616
|
+
hlsRef.current = null;
|
|
26951
26617
|
}
|
|
26618
|
+
cleanupBlobUrl();
|
|
26619
|
+
setIsReady(false);
|
|
26952
26620
|
};
|
|
26953
|
-
}, []);
|
|
26621
|
+
}, [src, initializePlayer, cleanupBlobUrl]);
|
|
26622
|
+
useEffect(() => {
|
|
26623
|
+
if (videoRef.current) {
|
|
26624
|
+
if (autoplay) {
|
|
26625
|
+
videoRef.current.play().catch((err) => {
|
|
26626
|
+
console.warn("[HlsVideoPlayer] Autoplay failed:", err);
|
|
26627
|
+
});
|
|
26628
|
+
}
|
|
26629
|
+
}
|
|
26630
|
+
}, [autoplay]);
|
|
26954
26631
|
const play = useCallback(() => {
|
|
26955
|
-
return
|
|
26632
|
+
return videoRef.current?.play();
|
|
26956
26633
|
}, []);
|
|
26957
26634
|
const pause = useCallback(() => {
|
|
26958
|
-
|
|
26635
|
+
videoRef.current?.pause();
|
|
26959
26636
|
}, []);
|
|
26960
26637
|
const currentTime = useCallback((time2) => {
|
|
26961
|
-
if (time2 !== void 0) {
|
|
26962
|
-
|
|
26638
|
+
if (time2 !== void 0 && videoRef.current) {
|
|
26639
|
+
videoRef.current.currentTime = time2;
|
|
26963
26640
|
return time2;
|
|
26964
26641
|
}
|
|
26965
|
-
return
|
|
26642
|
+
return videoRef.current?.currentTime || 0;
|
|
26966
26643
|
}, []);
|
|
26967
26644
|
const duration = useCallback(() => {
|
|
26968
|
-
return
|
|
26645
|
+
return videoRef.current?.duration || 0;
|
|
26969
26646
|
}, []);
|
|
26970
26647
|
const paused = useCallback(() => {
|
|
26971
|
-
return
|
|
26648
|
+
return videoRef.current?.paused ?? true;
|
|
26972
26649
|
}, []);
|
|
26973
26650
|
const mute = useCallback((isMuted) => {
|
|
26974
|
-
if (isMuted !== void 0) {
|
|
26975
|
-
|
|
26651
|
+
if (isMuted !== void 0 && videoRef.current) {
|
|
26652
|
+
videoRef.current.muted = isMuted;
|
|
26976
26653
|
return isMuted;
|
|
26977
26654
|
}
|
|
26978
|
-
return
|
|
26655
|
+
return videoRef.current?.muted ?? false;
|
|
26979
26656
|
}, []);
|
|
26980
26657
|
const volume = useCallback((level) => {
|
|
26981
|
-
if (level !== void 0) {
|
|
26982
|
-
|
|
26658
|
+
if (level !== void 0 && videoRef.current) {
|
|
26659
|
+
videoRef.current.volume = level;
|
|
26983
26660
|
return level;
|
|
26984
26661
|
}
|
|
26985
|
-
return
|
|
26662
|
+
return videoRef.current?.volume ?? 1;
|
|
26986
26663
|
}, []);
|
|
26987
|
-
const
|
|
26988
|
-
if (
|
|
26989
|
-
|
|
26990
|
-
|
|
26991
|
-
setIsReady(false);
|
|
26664
|
+
const playbackRate = useCallback((rate) => {
|
|
26665
|
+
if (rate !== void 0 && videoRef.current) {
|
|
26666
|
+
videoRef.current.playbackRate = rate;
|
|
26667
|
+
return rate;
|
|
26992
26668
|
}
|
|
26669
|
+
return videoRef.current?.playbackRate ?? 1;
|
|
26993
26670
|
}, []);
|
|
26994
|
-
|
|
26995
|
-
|
|
26671
|
+
useImperativeHandle(ref, () => ({
|
|
26672
|
+
hls: hlsRef.current,
|
|
26673
|
+
video: videoRef.current,
|
|
26996
26674
|
play,
|
|
26997
26675
|
pause,
|
|
26998
26676
|
currentTime,
|
|
@@ -27000,13 +26678,15 @@ var VideoPlayer = React23__default.forwardRef(({
|
|
|
27000
26678
|
paused,
|
|
27001
26679
|
mute,
|
|
27002
26680
|
volume,
|
|
26681
|
+
playbackRate,
|
|
27003
26682
|
dispose,
|
|
27004
|
-
isReady
|
|
27005
|
-
|
|
26683
|
+
isReady,
|
|
26684
|
+
// For backward compatibility with Video.js API
|
|
26685
|
+
player: playerLikeObject()
|
|
26686
|
+
}), [play, pause, currentTime, duration, paused, mute, volume, playbackRate, dispose, isReady, playerLikeObject]);
|
|
27006
26687
|
const handleClickWithIndicator = useCallback(() => {
|
|
27007
|
-
if (!onClick || !
|
|
27008
|
-
const
|
|
27009
|
-
const willBePlaying = player.paused();
|
|
26688
|
+
if (!onClick || !videoRef.current) return;
|
|
26689
|
+
const willBePlaying = videoRef.current.paused;
|
|
27010
26690
|
setIndicatorIsPlaying(willBePlaying);
|
|
27011
26691
|
setShowIndicator(false);
|
|
27012
26692
|
setTimeout(() => {
|
|
@@ -27015,17 +26695,30 @@ var VideoPlayer = React23__default.forwardRef(({
|
|
|
27015
26695
|
}, 0);
|
|
27016
26696
|
onClick();
|
|
27017
26697
|
}, [onClick]);
|
|
27018
|
-
return /* @__PURE__ */ jsxs("div", { className: `video-player-wrapper ${className}`, style: { position: "relative", width: "100%", height: "100%" }, children: [
|
|
26698
|
+
return /* @__PURE__ */ jsxs("div", { className: `hls-video-player-wrapper ${className}`, style: { position: "relative", width: "100%", height: "100%" }, children: [
|
|
27019
26699
|
/* @__PURE__ */ jsx(
|
|
27020
26700
|
"div",
|
|
27021
26701
|
{
|
|
27022
|
-
className: "video-player-container",
|
|
27023
|
-
ref:
|
|
27024
|
-
|
|
26702
|
+
className: "hls-video-player-container",
|
|
26703
|
+
ref: videoContainerRef,
|
|
26704
|
+
children: /* @__PURE__ */ jsx(
|
|
26705
|
+
"video",
|
|
26706
|
+
{
|
|
26707
|
+
ref: videoRef,
|
|
26708
|
+
className: "hls-video-element",
|
|
26709
|
+
poster,
|
|
26710
|
+
controls,
|
|
26711
|
+
loop,
|
|
26712
|
+
muted,
|
|
26713
|
+
playsInline,
|
|
26714
|
+
autoPlay: autoplay,
|
|
26715
|
+
preload: "metadata"
|
|
26716
|
+
}
|
|
26717
|
+
)
|
|
27025
26718
|
}
|
|
27026
26719
|
),
|
|
27027
|
-
isLoading && !externalLoadingControl && /* @__PURE__ */ jsx("div", { className: "video-player-loading", children: /* @__PURE__ */ jsx(OptifyeLogoLoader_default, { size: "md", message: "Loading video..." }) }),
|
|
27028
|
-
onClick && /* @__PURE__ */ jsx(
|
|
26720
|
+
isLoading && !externalLoadingControl && /* @__PURE__ */ jsx("div", { className: "hls-video-player-loading", children: /* @__PURE__ */ jsx(OptifyeLogoLoader_default, { size: "md", message: "Loading video..." }) }),
|
|
26721
|
+
onClick && !controls && /* @__PURE__ */ jsx(
|
|
27029
26722
|
"div",
|
|
27030
26723
|
{
|
|
27031
26724
|
onClick: handleClickWithIndicator,
|
|
@@ -27041,7 +26734,7 @@ var VideoPlayer = React23__default.forwardRef(({
|
|
|
27041
26734
|
"aria-label": "Click to play/pause"
|
|
27042
26735
|
}
|
|
27043
26736
|
),
|
|
27044
|
-
onClick && /* @__PURE__ */ jsx(
|
|
26737
|
+
onClick && !controls && /* @__PURE__ */ jsx(
|
|
27045
26738
|
PlayPauseIndicator,
|
|
27046
26739
|
{
|
|
27047
26740
|
show: showIndicator,
|
|
@@ -27051,13 +26744,25 @@ var VideoPlayer = React23__default.forwardRef(({
|
|
|
27051
26744
|
)
|
|
27052
26745
|
] });
|
|
27053
26746
|
});
|
|
27054
|
-
|
|
27055
|
-
var
|
|
26747
|
+
HlsVideoPlayer.displayName = "HlsVideoPlayer";
|
|
26748
|
+
var VideoPlayer = HlsVideoPlayer;
|
|
26749
|
+
var CroppedHlsVideoPlayer = forwardRef(({
|
|
27056
26750
|
crop,
|
|
27057
26751
|
debug = false,
|
|
27058
26752
|
onClick,
|
|
27059
26753
|
...videoProps
|
|
27060
26754
|
}, ref) => {
|
|
26755
|
+
const {
|
|
26756
|
+
onReady: onReadyProp,
|
|
26757
|
+
onPlay: onPlayProp,
|
|
26758
|
+
onPause: onPauseProp,
|
|
26759
|
+
onEnded: onEndedProp,
|
|
26760
|
+
onSeeking: onSeekingProp,
|
|
26761
|
+
onSeeked: onSeekedProp,
|
|
26762
|
+
onLoadedMetadata: onLoadedMetadataProp,
|
|
26763
|
+
className: inheritedClassName = ""
|
|
26764
|
+
} = videoProps;
|
|
26765
|
+
const videoSrc = videoProps.src;
|
|
27061
26766
|
const videoContainerRef = useRef(null);
|
|
27062
26767
|
const hiddenVideoRef = useRef(null);
|
|
27063
26768
|
const canvasRef = useRef(null);
|
|
@@ -27076,8 +26781,11 @@ var CroppedVideoPlayer = forwardRef(({
|
|
|
27076
26781
|
}
|
|
27077
26782
|
}, []);
|
|
27078
26783
|
useImperativeHandle(ref, () => ({
|
|
27079
|
-
get
|
|
27080
|
-
return hiddenVideoRef.current?.
|
|
26784
|
+
get hls() {
|
|
26785
|
+
return hiddenVideoRef.current?.hls || null;
|
|
26786
|
+
},
|
|
26787
|
+
get video() {
|
|
26788
|
+
return hiddenVideoRef.current?.video || null;
|
|
27081
26789
|
},
|
|
27082
26790
|
play: () => hiddenVideoRef.current?.play() || void 0,
|
|
27083
26791
|
pause: () => hiddenVideoRef.current?.pause(),
|
|
@@ -27091,12 +26799,36 @@ var CroppedVideoPlayer = forwardRef(({
|
|
|
27091
26799
|
paused: () => hiddenVideoRef.current?.paused() || true,
|
|
27092
26800
|
mute: (isMuted) => hiddenVideoRef.current?.mute(isMuted) || false,
|
|
27093
26801
|
volume: (level) => hiddenVideoRef.current?.volume(level) || 0,
|
|
26802
|
+
playbackRate: (rate) => hiddenVideoRef.current?.playbackRate(rate) || 1,
|
|
27094
26803
|
dispose: () => {
|
|
27095
26804
|
hiddenVideoRef.current?.dispose();
|
|
27096
26805
|
stopCanvasRendering();
|
|
27097
26806
|
},
|
|
27098
26807
|
get isReady() {
|
|
27099
26808
|
return hiddenVideoRef.current?.isReady || false;
|
|
26809
|
+
},
|
|
26810
|
+
// For backward compatibility with Video.js API
|
|
26811
|
+
get player() {
|
|
26812
|
+
const video = hiddenVideoRef.current?.video;
|
|
26813
|
+
if (!video) return null;
|
|
26814
|
+
return {
|
|
26815
|
+
el: () => video,
|
|
26816
|
+
currentTime: () => video.currentTime || 0,
|
|
26817
|
+
duration: () => video.duration || 0,
|
|
26818
|
+
paused: () => video.paused ?? true,
|
|
26819
|
+
play: () => video.play(),
|
|
26820
|
+
pause: () => video.pause(),
|
|
26821
|
+
muted: (val) => {
|
|
26822
|
+
if (val !== void 0) video.muted = val;
|
|
26823
|
+
return video.muted;
|
|
26824
|
+
},
|
|
26825
|
+
volume: (val) => {
|
|
26826
|
+
if (val !== void 0) video.volume = val;
|
|
26827
|
+
return video.volume;
|
|
26828
|
+
},
|
|
26829
|
+
error: () => null,
|
|
26830
|
+
dispose: () => hiddenVideoRef.current?.dispose()
|
|
26831
|
+
};
|
|
27100
26832
|
}
|
|
27101
26833
|
}), [stopCanvasRendering]);
|
|
27102
26834
|
const calculateCanvasDimensions = useCallback(() => {
|
|
@@ -27156,24 +26888,38 @@ var CroppedVideoPlayer = forwardRef(({
|
|
|
27156
26888
|
animationFrameRef.current = requestAnimationFrame(renderFrameToCanvas);
|
|
27157
26889
|
}, [crop]);
|
|
27158
26890
|
const handleVideoReady = useCallback((player) => {
|
|
27159
|
-
console.log("[
|
|
27160
|
-
const videoEl =
|
|
26891
|
+
console.log("[CroppedHlsVideoPlayer] Video player ready");
|
|
26892
|
+
const videoEl = hiddenVideoRef.current?.video;
|
|
27161
26893
|
if (videoEl) {
|
|
27162
26894
|
videoElementRef.current = videoEl;
|
|
27163
26895
|
setIsVideoReady(true);
|
|
27164
26896
|
}
|
|
27165
|
-
|
|
27166
|
-
}, [
|
|
26897
|
+
onReadyProp?.(player);
|
|
26898
|
+
}, [onReadyProp]);
|
|
27167
26899
|
const handleVideoPlay = useCallback((player) => {
|
|
27168
|
-
console.log("[
|
|
26900
|
+
console.log("[CroppedHlsVideoPlayer] Video playing, starting canvas rendering");
|
|
27169
26901
|
if (crop && canvasRef.current) {
|
|
27170
26902
|
setIsProcessing(true);
|
|
27171
26903
|
renderFrameToCanvas();
|
|
27172
26904
|
}
|
|
27173
|
-
|
|
27174
|
-
}, [crop, renderFrameToCanvas,
|
|
26905
|
+
onPlayProp?.(player);
|
|
26906
|
+
}, [crop, renderFrameToCanvas, onPlayProp]);
|
|
27175
26907
|
const handleVideoPause = useCallback((player) => {
|
|
27176
|
-
console.log("[
|
|
26908
|
+
console.log("[CroppedHlsVideoPlayer] Video paused, stopping canvas rendering and CLEARING canvas");
|
|
26909
|
+
stopCanvasRendering();
|
|
26910
|
+
setIsProcessing(false);
|
|
26911
|
+
if (canvasRef.current) {
|
|
26912
|
+
const ctx = canvasRef.current.getContext("2d");
|
|
26913
|
+
if (ctx) {
|
|
26914
|
+
ctx.clearRect(0, 0, canvasRef.current.width, canvasRef.current.height);
|
|
26915
|
+
ctx.fillStyle = "black";
|
|
26916
|
+
ctx.fillRect(0, 0, canvasRef.current.width, canvasRef.current.height);
|
|
26917
|
+
}
|
|
26918
|
+
}
|
|
26919
|
+
onPauseProp?.(player);
|
|
26920
|
+
}, [stopCanvasRendering, onPauseProp]);
|
|
26921
|
+
const handleVideoEnded = useCallback((player) => {
|
|
26922
|
+
console.log("[CroppedHlsVideoPlayer] Video ended, CLEARING canvas");
|
|
27177
26923
|
stopCanvasRendering();
|
|
27178
26924
|
setIsProcessing(false);
|
|
27179
26925
|
if (canvasRef.current) {
|
|
@@ -27184,159 +26930,677 @@ var CroppedVideoPlayer = forwardRef(({
|
|
|
27184
26930
|
ctx.fillRect(0, 0, canvasRef.current.width, canvasRef.current.height);
|
|
27185
26931
|
}
|
|
27186
26932
|
}
|
|
27187
|
-
|
|
27188
|
-
}, [stopCanvasRendering,
|
|
27189
|
-
const
|
|
27190
|
-
console.log("[
|
|
27191
|
-
|
|
27192
|
-
|
|
27193
|
-
|
|
27194
|
-
|
|
27195
|
-
|
|
27196
|
-
|
|
27197
|
-
|
|
27198
|
-
|
|
26933
|
+
onEndedProp?.(player);
|
|
26934
|
+
}, [stopCanvasRendering, onEndedProp]);
|
|
26935
|
+
const handleSeeking = useCallback((player) => {
|
|
26936
|
+
console.log("[CroppedHlsVideoPlayer] Video seeking");
|
|
26937
|
+
if (crop && !videoElementRef.current?.paused) {
|
|
26938
|
+
renderFrameToCanvas();
|
|
26939
|
+
}
|
|
26940
|
+
onSeekingProp?.(player);
|
|
26941
|
+
}, [crop, renderFrameToCanvas, onSeekingProp]);
|
|
26942
|
+
const handleSeeked = useCallback((player) => {
|
|
26943
|
+
console.log("[CroppedHlsVideoPlayer] Video seeked");
|
|
26944
|
+
if (crop && !videoElementRef.current?.paused) {
|
|
26945
|
+
renderFrameToCanvas();
|
|
26946
|
+
}
|
|
26947
|
+
onSeekedProp?.(player);
|
|
26948
|
+
}, [crop, renderFrameToCanvas, onSeekedProp]);
|
|
26949
|
+
const handleLoadedMetadata = useCallback((player) => {
|
|
26950
|
+
console.log("[CroppedHlsVideoPlayer] Video metadata loaded");
|
|
26951
|
+
calculateCanvasDimensions();
|
|
26952
|
+
onLoadedMetadataProp?.(player);
|
|
26953
|
+
}, [calculateCanvasDimensions, onLoadedMetadataProp]);
|
|
26954
|
+
useEffect(() => {
|
|
26955
|
+
calculateCanvasDimensions();
|
|
26956
|
+
const handleResize = () => {
|
|
26957
|
+
calculateCanvasDimensions();
|
|
26958
|
+
};
|
|
26959
|
+
window.addEventListener("resize", handleResize);
|
|
26960
|
+
return () => {
|
|
26961
|
+
window.removeEventListener("resize", handleResize);
|
|
26962
|
+
};
|
|
26963
|
+
}, [calculateCanvasDimensions]);
|
|
26964
|
+
useLayoutEffect(() => {
|
|
26965
|
+
if (canvasRef.current && crop) {
|
|
26966
|
+
const canvas = canvasRef.current;
|
|
26967
|
+
const ctx = canvas.getContext("2d");
|
|
26968
|
+
if (ctx) {
|
|
26969
|
+
console.log("[CroppedHlsVideoPlayer] Source changing - CLEARING CANVAS IMMEDIATELY");
|
|
26970
|
+
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
26971
|
+
ctx.fillStyle = "black";
|
|
26972
|
+
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
|
26973
|
+
}
|
|
26974
|
+
}
|
|
26975
|
+
}, [videoSrc, crop]);
|
|
26976
|
+
useEffect(() => {
|
|
26977
|
+
return () => {
|
|
26978
|
+
stopCanvasRendering();
|
|
26979
|
+
};
|
|
26980
|
+
}, [stopCanvasRendering]);
|
|
26981
|
+
if (!crop) {
|
|
26982
|
+
return /* @__PURE__ */ jsx(HlsVideoPlayer, { ref, ...videoProps, onClick });
|
|
26983
|
+
}
|
|
26984
|
+
const handleClickWithIndicator = () => {
|
|
26985
|
+
if (!onClick || !hiddenVideoRef.current?.video) return;
|
|
26986
|
+
const video = hiddenVideoRef.current.video;
|
|
26987
|
+
const willBePlaying = video.paused;
|
|
26988
|
+
setIndicatorIsPlaying(willBePlaying);
|
|
26989
|
+
setShowIndicator(false);
|
|
26990
|
+
setTimeout(() => {
|
|
26991
|
+
indicatorKeyRef.current += 1;
|
|
26992
|
+
setShowIndicator(true);
|
|
26993
|
+
}, 0);
|
|
26994
|
+
onClick();
|
|
26995
|
+
};
|
|
26996
|
+
return /* @__PURE__ */ jsxs(
|
|
26997
|
+
"div",
|
|
26998
|
+
{
|
|
26999
|
+
ref: videoContainerRef,
|
|
27000
|
+
className: `relative w-full h-full flex items-center justify-center bg-black ${onClick ? "cursor-pointer" : ""} ${inheritedClassName}`,
|
|
27001
|
+
onClick: handleClickWithIndicator,
|
|
27002
|
+
children: [
|
|
27003
|
+
/* @__PURE__ */ jsx("div", { className: "hidden", children: /* @__PURE__ */ jsx(
|
|
27004
|
+
HlsVideoPlayer,
|
|
27005
|
+
{
|
|
27006
|
+
ref: hiddenVideoRef,
|
|
27007
|
+
...videoProps,
|
|
27008
|
+
onReady: handleVideoReady,
|
|
27009
|
+
onPlay: handleVideoPlay,
|
|
27010
|
+
onPause: handleVideoPause,
|
|
27011
|
+
onEnded: handleVideoEnded,
|
|
27012
|
+
onSeeking: handleSeeking,
|
|
27013
|
+
onSeeked: handleSeeked,
|
|
27014
|
+
onLoadedMetadata: handleLoadedMetadata,
|
|
27015
|
+
onLoadedData: videoProps.onLoadedData,
|
|
27016
|
+
onPlaying: videoProps.onPlaying,
|
|
27017
|
+
onLoadingChange: videoProps.onLoadingChange
|
|
27018
|
+
}
|
|
27019
|
+
) }),
|
|
27020
|
+
/* @__PURE__ */ jsx(
|
|
27021
|
+
"canvas",
|
|
27022
|
+
{
|
|
27023
|
+
ref: canvasRef,
|
|
27024
|
+
width: canvasDimensions.width,
|
|
27025
|
+
height: canvasDimensions.height,
|
|
27026
|
+
className: "max-w-full max-h-full",
|
|
27027
|
+
style: {
|
|
27028
|
+
display: isVideoReady ? "block" : "none",
|
|
27029
|
+
width: `${canvasDimensions.width}px`,
|
|
27030
|
+
height: `${canvasDimensions.height}px`
|
|
27031
|
+
}
|
|
27032
|
+
}
|
|
27033
|
+
),
|
|
27034
|
+
!isVideoReady && /* @__PURE__ */ jsx("div", { className: "absolute inset-0 flex items-center justify-center", children: /* @__PURE__ */ jsx(OptifyeLogoLoader_default, { size: "md", message: "Loading video..." }) }),
|
|
27035
|
+
debug && isVideoReady && /* @__PURE__ */ jsxs("div", { className: "absolute top-2 left-2 bg-black/80 text-white text-xs p-2 rounded font-mono", children: [
|
|
27036
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
27037
|
+
"Crop: ",
|
|
27038
|
+
crop.x,
|
|
27039
|
+
",",
|
|
27040
|
+
crop.y,
|
|
27041
|
+
" ",
|
|
27042
|
+
crop.width,
|
|
27043
|
+
"x",
|
|
27044
|
+
crop.height,
|
|
27045
|
+
"%"
|
|
27046
|
+
] }),
|
|
27047
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
27048
|
+
"Canvas: ",
|
|
27049
|
+
canvasDimensions.width,
|
|
27050
|
+
"x",
|
|
27051
|
+
canvasDimensions.height,
|
|
27052
|
+
"px"
|
|
27053
|
+
] }),
|
|
27054
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
27055
|
+
"Processing: ",
|
|
27056
|
+
isProcessing ? "Yes" : "No"
|
|
27057
|
+
] })
|
|
27058
|
+
] }),
|
|
27059
|
+
onClick && /* @__PURE__ */ jsx(
|
|
27060
|
+
PlayPauseIndicator,
|
|
27061
|
+
{
|
|
27062
|
+
show: showIndicator,
|
|
27063
|
+
isPlaying: indicatorIsPlaying
|
|
27064
|
+
},
|
|
27065
|
+
indicatorKeyRef.current
|
|
27066
|
+
)
|
|
27067
|
+
]
|
|
27068
|
+
}
|
|
27069
|
+
);
|
|
27070
|
+
});
|
|
27071
|
+
CroppedHlsVideoPlayer.displayName = "CroppedHlsVideoPlayer";
|
|
27072
|
+
var CroppedVideoPlayer = CroppedHlsVideoPlayer;
|
|
27073
|
+
var getSupabaseClient2 = () => {
|
|
27074
|
+
const url = process.env.NEXT_PUBLIC_SUPABASE_URL;
|
|
27075
|
+
const key = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY;
|
|
27076
|
+
if (!url || !key) {
|
|
27077
|
+
throw new Error("Supabase configuration missing");
|
|
27078
|
+
}
|
|
27079
|
+
return createClient(url, key);
|
|
27080
|
+
};
|
|
27081
|
+
var getAuthToken3 = async () => {
|
|
27082
|
+
try {
|
|
27083
|
+
const supabase = getSupabaseClient2();
|
|
27084
|
+
const { data: { session } } = await supabase.auth.getSession();
|
|
27085
|
+
return session?.access_token || null;
|
|
27086
|
+
} catch (error) {
|
|
27087
|
+
console.error("[useWorkspaceCrop] Error getting auth token:", error);
|
|
27088
|
+
return null;
|
|
27089
|
+
}
|
|
27090
|
+
};
|
|
27091
|
+
function useWorkspaceCrop(workspaceId) {
|
|
27092
|
+
const [crop, setCrop] = useState(null);
|
|
27093
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
27094
|
+
const [error, setError] = useState(null);
|
|
27095
|
+
useEffect(() => {
|
|
27096
|
+
if (!workspaceId) {
|
|
27097
|
+
setIsLoading(false);
|
|
27098
|
+
return;
|
|
27099
|
+
}
|
|
27100
|
+
const fetchCrop = async () => {
|
|
27101
|
+
setIsLoading(true);
|
|
27102
|
+
setError(null);
|
|
27103
|
+
try {
|
|
27104
|
+
const token = await getAuthToken3();
|
|
27105
|
+
if (!token) {
|
|
27106
|
+
throw new Error("Authentication required");
|
|
27107
|
+
}
|
|
27108
|
+
const response = await fetch("/api/clips/supabase", {
|
|
27109
|
+
method: "POST",
|
|
27110
|
+
headers: {
|
|
27111
|
+
"Content-Type": "application/json",
|
|
27112
|
+
"Authorization": `Bearer ${token}`
|
|
27113
|
+
},
|
|
27114
|
+
body: JSON.stringify({
|
|
27115
|
+
action: "crop",
|
|
27116
|
+
workspaceId
|
|
27117
|
+
})
|
|
27118
|
+
});
|
|
27119
|
+
if (!response.ok) {
|
|
27120
|
+
throw new Error(`Failed to fetch crop: ${response.statusText}`);
|
|
27121
|
+
}
|
|
27122
|
+
const data = await response.json();
|
|
27123
|
+
console.log(`[useWorkspaceCrop] Fetched crop for workspace ${workspaceId}:`, data.crop);
|
|
27124
|
+
setCrop(data.crop);
|
|
27125
|
+
} catch (err) {
|
|
27126
|
+
console.error("[useWorkspaceCrop] Error fetching crop:", err);
|
|
27127
|
+
setError(err instanceof Error ? err.message : "Failed to fetch crop configuration");
|
|
27128
|
+
setCrop(null);
|
|
27129
|
+
} finally {
|
|
27130
|
+
setIsLoading(false);
|
|
27131
|
+
}
|
|
27132
|
+
};
|
|
27133
|
+
fetchCrop();
|
|
27134
|
+
}, [workspaceId]);
|
|
27135
|
+
return { crop, isLoading, error };
|
|
27136
|
+
}
|
|
27137
|
+
function Skeleton({ className, ...props }) {
|
|
27138
|
+
return /* @__PURE__ */ jsx("div", { className: cn("animate-pulse rounded-md bg-muted", className), ...props });
|
|
27139
|
+
}
|
|
27140
|
+
var Select = SelectPrimitive.Root;
|
|
27141
|
+
var SelectGroup = SelectPrimitive.Group;
|
|
27142
|
+
var SelectValue = SelectPrimitive.Value;
|
|
27143
|
+
var SelectTrigger = React23.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(
|
|
27144
|
+
SelectPrimitive.Trigger,
|
|
27145
|
+
{
|
|
27146
|
+
ref,
|
|
27147
|
+
className: cn(
|
|
27148
|
+
"flex h-11 sm:h-9 w-full items-center justify-between whitespace-nowrap rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm ring-offset-background data-[placeholder]:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-ring disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1 touch-manipulation",
|
|
27149
|
+
className
|
|
27150
|
+
),
|
|
27151
|
+
...props,
|
|
27152
|
+
children: [
|
|
27153
|
+
children,
|
|
27154
|
+
/* @__PURE__ */ jsx(SelectPrimitive.Icon, { asChild: true, children: /* @__PURE__ */ jsx(ChevronDown, { className: "h-4 w-4 opacity-50" }) })
|
|
27155
|
+
]
|
|
27156
|
+
}
|
|
27157
|
+
));
|
|
27158
|
+
SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
|
|
27159
|
+
var SelectScrollUpButton = React23.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
27160
|
+
SelectPrimitive.ScrollUpButton,
|
|
27161
|
+
{
|
|
27162
|
+
ref,
|
|
27163
|
+
className: cn("flex cursor-default items-center justify-center py-1", className),
|
|
27164
|
+
...props,
|
|
27165
|
+
children: /* @__PURE__ */ jsx(ChevronUp, { className: "h-4 w-4" })
|
|
27166
|
+
}
|
|
27167
|
+
));
|
|
27168
|
+
SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName;
|
|
27169
|
+
var SelectScrollDownButton = React23.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
27170
|
+
SelectPrimitive.ScrollDownButton,
|
|
27171
|
+
{
|
|
27172
|
+
ref,
|
|
27173
|
+
className: cn("flex cursor-default items-center justify-center py-1", className),
|
|
27174
|
+
...props,
|
|
27175
|
+
children: /* @__PURE__ */ jsx(ChevronDown, { className: "h-4 w-4" })
|
|
27176
|
+
}
|
|
27177
|
+
));
|
|
27178
|
+
SelectScrollDownButton.displayName = SelectPrimitive.ScrollDownButton.displayName;
|
|
27179
|
+
var SelectContent = React23.forwardRef(({ className, children, position = "popper", ...props }, ref) => /* @__PURE__ */ jsx(SelectPrimitive.Portal, { children: /* @__PURE__ */ jsxs(
|
|
27180
|
+
SelectPrimitive.Content,
|
|
27181
|
+
{
|
|
27182
|
+
ref,
|
|
27183
|
+
className: cn(
|
|
27184
|
+
"relative z-50 max-h-[--radix-select-content-available-height] min-w-[8rem] overflow-y-auto overflow-x-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-select-content-transform-origin]",
|
|
27185
|
+
position === "popper" && "data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
|
|
27186
|
+
className
|
|
27187
|
+
),
|
|
27188
|
+
position,
|
|
27189
|
+
...props,
|
|
27190
|
+
children: [
|
|
27191
|
+
/* @__PURE__ */ jsx(SelectScrollUpButton, {}),
|
|
27192
|
+
/* @__PURE__ */ jsx(
|
|
27193
|
+
SelectPrimitive.Viewport,
|
|
27194
|
+
{
|
|
27195
|
+
className: cn(
|
|
27196
|
+
"p-1",
|
|
27197
|
+
position === "popper" && "h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]"
|
|
27198
|
+
),
|
|
27199
|
+
children
|
|
27200
|
+
}
|
|
27201
|
+
),
|
|
27202
|
+
/* @__PURE__ */ jsx(SelectScrollDownButton, {})
|
|
27203
|
+
]
|
|
27204
|
+
}
|
|
27205
|
+
) }));
|
|
27206
|
+
SelectContent.displayName = SelectPrimitive.Content.displayName;
|
|
27207
|
+
var SelectLabel = React23.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
27208
|
+
SelectPrimitive.Label,
|
|
27209
|
+
{
|
|
27210
|
+
ref,
|
|
27211
|
+
className: cn("px-2 py-1.5 text-sm font-semibold", className),
|
|
27212
|
+
...props
|
|
27213
|
+
}
|
|
27214
|
+
));
|
|
27215
|
+
SelectLabel.displayName = SelectPrimitive.Label.displayName;
|
|
27216
|
+
var SelectItem = React23.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(
|
|
27217
|
+
SelectPrimitive.Item,
|
|
27218
|
+
{
|
|
27219
|
+
ref,
|
|
27220
|
+
className: cn(
|
|
27221
|
+
"relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-2 pr-8 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
|
27222
|
+
className
|
|
27223
|
+
),
|
|
27224
|
+
...props,
|
|
27225
|
+
children: [
|
|
27226
|
+
/* @__PURE__ */ jsx("span", { className: "absolute right-2 flex h-3.5 w-3.5 items-center justify-center", children: /* @__PURE__ */ jsx(SelectPrimitive.ItemIndicator, { children: /* @__PURE__ */ jsx(Check, { className: "h-4 w-4" }) }) }),
|
|
27227
|
+
/* @__PURE__ */ jsx(SelectPrimitive.ItemText, { children })
|
|
27228
|
+
]
|
|
27229
|
+
}
|
|
27230
|
+
));
|
|
27231
|
+
SelectItem.displayName = SelectPrimitive.Item.displayName;
|
|
27232
|
+
var SelectSeparator = React23.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
27233
|
+
SelectPrimitive.Separator,
|
|
27234
|
+
{
|
|
27235
|
+
ref,
|
|
27236
|
+
className: cn("-mx-1 my-1 h-px bg-muted", className),
|
|
27237
|
+
...props
|
|
27238
|
+
}
|
|
27239
|
+
));
|
|
27240
|
+
SelectSeparator.displayName = SelectPrimitive.Separator.displayName;
|
|
27241
|
+
var LoadingOverlay = ({
|
|
27242
|
+
isVisible,
|
|
27243
|
+
message = "Loading...",
|
|
27244
|
+
className
|
|
27245
|
+
}) => {
|
|
27246
|
+
if (!isVisible) return null;
|
|
27247
|
+
return /* @__PURE__ */ jsx(
|
|
27248
|
+
motion.div,
|
|
27249
|
+
{
|
|
27250
|
+
initial: { opacity: 0 },
|
|
27251
|
+
animate: { opacity: 1 },
|
|
27252
|
+
exit: { opacity: 0 },
|
|
27253
|
+
transition: { duration: 0.2 },
|
|
27254
|
+
className: `fixed inset-0 z-[100] flex items-center justify-center bg-black/30 backdrop-blur-sm ${className || ""}`,
|
|
27255
|
+
"aria-modal": "true",
|
|
27256
|
+
role: "dialog",
|
|
27257
|
+
children: /* @__PURE__ */ jsx("div", { className: "flex flex-col items-center space-y-3 rounded-lg bg-white p-8 shadow-xl", children: /* @__PURE__ */ jsx(OptifyeLogoLoader_default, { size: "md", message }) })
|
|
27258
|
+
}
|
|
27259
|
+
);
|
|
27260
|
+
};
|
|
27261
|
+
var LoadingOverlay_default = LoadingOverlay;
|
|
27262
|
+
var TimeDisplay = ({ className, variant = "default" }) => {
|
|
27263
|
+
const { dateTimeConfig } = useDashboardConfig();
|
|
27264
|
+
const [time2, setTime] = useState("");
|
|
27265
|
+
const dbTimezone = useAppTimezone();
|
|
27266
|
+
const timezoneToDisplay = dbTimezone || dateTimeConfig?.defaultTimezone || "UTC";
|
|
27267
|
+
const localeToUse = dateTimeConfig?.defaultLocale || "en-US";
|
|
27268
|
+
const timeSuffix = "";
|
|
27269
|
+
useEffect(() => {
|
|
27270
|
+
const updateTime = () => {
|
|
27271
|
+
const now2 = /* @__PURE__ */ new Date();
|
|
27272
|
+
const effectiveFormatOptions = {
|
|
27273
|
+
hour: "2-digit",
|
|
27274
|
+
minute: "2-digit",
|
|
27275
|
+
second: "2-digit",
|
|
27276
|
+
hour12: true,
|
|
27277
|
+
timeZone: timezoneToDisplay,
|
|
27278
|
+
...dateTimeConfig?.timeFormatOptions || {}
|
|
27279
|
+
// Allow override from config
|
|
27280
|
+
};
|
|
27281
|
+
try {
|
|
27282
|
+
setTime(new Intl.DateTimeFormat(localeToUse, effectiveFormatOptions).format(now2));
|
|
27283
|
+
} catch (e) {
|
|
27284
|
+
console.error("Error formatting time:", e);
|
|
27285
|
+
setTime("Error");
|
|
27286
|
+
}
|
|
27287
|
+
};
|
|
27288
|
+
updateTime();
|
|
27289
|
+
const interval = setInterval(updateTime, 1e3);
|
|
27290
|
+
return () => clearInterval(interval);
|
|
27291
|
+
}, [timezoneToDisplay, dateTimeConfig?.timeFormatOptions, localeToUse]);
|
|
27292
|
+
if (!time2) return null;
|
|
27293
|
+
if (variant === "minimal") {
|
|
27294
|
+
return /* @__PURE__ */ jsxs("span", { className: className || "", children: [
|
|
27295
|
+
time2,
|
|
27296
|
+
" ",
|
|
27297
|
+
timeSuffix
|
|
27298
|
+
] });
|
|
27299
|
+
}
|
|
27300
|
+
return /* @__PURE__ */ jsxs(
|
|
27301
|
+
motion.div,
|
|
27302
|
+
{
|
|
27303
|
+
initial: { opacity: 0, y: -5 },
|
|
27304
|
+
animate: { opacity: 1, y: 0 },
|
|
27305
|
+
transition: { duration: 0.3 },
|
|
27306
|
+
className: `flex items-center space-x-1.5 bg-white/60 backdrop-blur-sm px-2 py-0.5 rounded-md shadow-xs ${className || ""}`,
|
|
27307
|
+
children: [
|
|
27308
|
+
/* @__PURE__ */ jsx("svg", { xmlns: "http://www.w3.org/2000/svg", className: "h-3 w-3 text-[var(--primary-DEFAULT)]", viewBox: "0 0 20 20", fill: "currentColor", children: /* @__PURE__ */ jsx("path", { fillRule: "evenodd", d: "M10 18a8 8 0 100-16 8 8 0 000 16zm1-12a1 1 0 10-2 0v4a1 1 0 00.293.707l2.828 2.829a1 1 0 101.415-1.415L11 9.586V6z", clipRule: "evenodd" }) }),
|
|
27309
|
+
/* @__PURE__ */ jsxs("span", { className: "text-xs sm:text-[11px] font-medium text-gray-800 tabular-nums tracking-tight", children: [
|
|
27310
|
+
time2,
|
|
27311
|
+
" ",
|
|
27312
|
+
timeSuffix
|
|
27313
|
+
] })
|
|
27314
|
+
]
|
|
27315
|
+
}
|
|
27316
|
+
);
|
|
27317
|
+
};
|
|
27318
|
+
var TimeDisplay_default = TimeDisplay;
|
|
27319
|
+
var DateDisplay = ({ className, variant = "default" }) => {
|
|
27320
|
+
const { dateTimeConfig } = useDashboardConfig();
|
|
27321
|
+
const [date, setDate] = useState("");
|
|
27322
|
+
const timezoneToDisplay = dateTimeConfig?.defaultTimezone || "UTC";
|
|
27323
|
+
const localeToUse = dateTimeConfig?.defaultLocale || "en-US";
|
|
27324
|
+
useEffect(() => {
|
|
27325
|
+
const getCurrentFormattedDate = () => {
|
|
27326
|
+
const now2 = /* @__PURE__ */ new Date();
|
|
27327
|
+
const effectiveFormatOptions = {
|
|
27328
|
+
weekday: "short",
|
|
27329
|
+
day: "numeric",
|
|
27330
|
+
month: "short",
|
|
27331
|
+
timeZone: timezoneToDisplay,
|
|
27332
|
+
...dateTimeConfig?.dateFormatOptions || {}
|
|
27333
|
+
// Allow override from config
|
|
27334
|
+
};
|
|
27335
|
+
try {
|
|
27336
|
+
return new Intl.DateTimeFormat(localeToUse, effectiveFormatOptions).format(now2);
|
|
27337
|
+
} catch (e) {
|
|
27338
|
+
console.error("Error formatting date:", e);
|
|
27339
|
+
return "Error";
|
|
27340
|
+
}
|
|
27341
|
+
};
|
|
27342
|
+
const updateDate = () => {
|
|
27343
|
+
setDate(getCurrentFormattedDate());
|
|
27344
|
+
};
|
|
27345
|
+
updateDate();
|
|
27346
|
+
const interval = setInterval(() => {
|
|
27347
|
+
const currentDateStr = getCurrentFormattedDate();
|
|
27348
|
+
if (currentDateStr !== date) {
|
|
27349
|
+
updateDate();
|
|
27350
|
+
}
|
|
27351
|
+
}, 60 * 1e3);
|
|
27352
|
+
return () => clearInterval(interval);
|
|
27353
|
+
}, [date, timezoneToDisplay, dateTimeConfig?.dateFormatOptions, localeToUse]);
|
|
27354
|
+
if (!date) return null;
|
|
27355
|
+
if (variant === "minimal") {
|
|
27356
|
+
return /* @__PURE__ */ jsx("span", { className: className || "", children: date });
|
|
27357
|
+
}
|
|
27358
|
+
return /* @__PURE__ */ jsxs(
|
|
27359
|
+
motion.div,
|
|
27360
|
+
{
|
|
27361
|
+
initial: { opacity: 0, y: -5 },
|
|
27362
|
+
animate: { opacity: 1, y: 0 },
|
|
27363
|
+
transition: { duration: 0.3 },
|
|
27364
|
+
className: `flex items-center space-x-1.5 bg-white/60 backdrop-blur-sm px-2 py-0.5 rounded-md shadow-xs ${className || ""}`,
|
|
27365
|
+
children: [
|
|
27366
|
+
/* @__PURE__ */ jsx("svg", { xmlns: "http://www.w3.org/2000/svg", className: "h-3 w-3 text-blue-600", viewBox: "0 0 20 20", fill: "currentColor", children: /* @__PURE__ */ jsx("path", { fillRule: "evenodd", d: "M6 2a1 1 0 00-1 1v1H4a2 2 0 00-2 2v10a2 2 0 002 2h12a2 2 0 002-2V6a2 2 0 00-2-2h-1V3a1 1 0 10-2 0v1H7V3a1 1 0 00-1-1zm0 5a1 1 0 000 2h8a1 1 0 100-2H6z", clipRule: "evenodd" }) }),
|
|
27367
|
+
/* @__PURE__ */ jsx("span", { className: "text-[11px] font-medium text-gray-800 tracking-tight", children: date })
|
|
27368
|
+
]
|
|
27369
|
+
}
|
|
27370
|
+
);
|
|
27371
|
+
};
|
|
27372
|
+
var DateDisplay_default = DateDisplay;
|
|
27373
|
+
var Card3 = Card2;
|
|
27374
|
+
var CardHeader3 = CardHeader2;
|
|
27375
|
+
var CardTitle3 = CardTitle2;
|
|
27376
|
+
var CardContent3 = CardContent2;
|
|
27377
|
+
var MetricCard2 = ({ title, value, unit = "", trend = null }) => {
|
|
27378
|
+
const getTrendColor = (trendValue) => {
|
|
27379
|
+
if (trendValue === null || trendValue === void 0) return "";
|
|
27380
|
+
return trendValue > 0 ? "text-green-500" : trendValue < 0 ? "text-red-500" : "text-gray-500";
|
|
27381
|
+
};
|
|
27382
|
+
const getTrendSymbol = (trendValue) => {
|
|
27383
|
+
if (trendValue === null || trendValue === void 0) return "";
|
|
27384
|
+
return trendValue > 0 ? "\u2191" : trendValue < 0 ? "\u2193" : "";
|
|
27385
|
+
};
|
|
27386
|
+
return /* @__PURE__ */ jsxs(Card3, { className: "bg-white", children: [
|
|
27387
|
+
/* @__PURE__ */ jsx(CardHeader3, { className: "pb-2", children: /* @__PURE__ */ jsx(CardTitle3, { className: "text-sm font-medium text-gray-500", children: title }) }),
|
|
27388
|
+
/* @__PURE__ */ jsx(CardContent3, { children: /* @__PURE__ */ jsxs("div", { className: "flex items-baseline justify-between", children: [
|
|
27389
|
+
/* @__PURE__ */ jsxs("div", { className: "text-2xl font-semibold", children: [
|
|
27390
|
+
value,
|
|
27391
|
+
unit && /* @__PURE__ */ jsx("span", { className: "ml-1 text-sm text-gray-500", children: unit })
|
|
27392
|
+
] }),
|
|
27393
|
+
trend !== null && trend !== void 0 && // Check trend for null/undefined before accessing
|
|
27394
|
+
/* @__PURE__ */ jsx("div", { className: `flex items-center ${getTrendColor(trend)}`, children: /* @__PURE__ */ jsxs("span", { className: "text-sm", children: [
|
|
27395
|
+
getTrendSymbol(trend),
|
|
27396
|
+
" ",
|
|
27397
|
+
Math.abs(trend),
|
|
27398
|
+
"%"
|
|
27399
|
+
] }) })
|
|
27400
|
+
] }) })
|
|
27401
|
+
] });
|
|
27402
|
+
};
|
|
27403
|
+
var MetricCard_default = MetricCard2;
|
|
27404
|
+
var TimePickerDropdown = ({
|
|
27405
|
+
value,
|
|
27406
|
+
onChange,
|
|
27407
|
+
placeholder = "Select time",
|
|
27408
|
+
className = "",
|
|
27409
|
+
disabled = false
|
|
27410
|
+
}) => {
|
|
27411
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
27412
|
+
const [searchTerm, setSearchTerm] = useState("");
|
|
27413
|
+
const dropdownRef = useRef(null);
|
|
27414
|
+
const inputRef = useRef(null);
|
|
27415
|
+
const generateTimeSlots = () => {
|
|
27416
|
+
const slots = [];
|
|
27417
|
+
for (let hour = 0; hour < 24; hour++) {
|
|
27418
|
+
for (let minute = 0; minute < 60; minute += 15) {
|
|
27419
|
+
const time24 = `${hour.toString().padStart(2, "0")}:${minute.toString().padStart(2, "0")}`;
|
|
27420
|
+
const hour12 = hour === 0 ? 12 : hour > 12 ? hour - 12 : hour;
|
|
27421
|
+
const ampm = hour < 12 ? "AM" : "PM";
|
|
27422
|
+
const time12 = `${hour12}:${minute.toString().padStart(2, "0")} ${ampm}`;
|
|
27423
|
+
slots.push({ value: time24, label: time12 });
|
|
27424
|
+
}
|
|
27425
|
+
}
|
|
27426
|
+
return slots;
|
|
27427
|
+
};
|
|
27428
|
+
const timeSlots = generateTimeSlots();
|
|
27429
|
+
const filteredSlots = timeSlots.filter(
|
|
27430
|
+
(slot) => slot.label.toLowerCase().includes(searchTerm.toLowerCase())
|
|
27431
|
+
);
|
|
27432
|
+
const getDisplayValue = (value2) => {
|
|
27433
|
+
if (!value2) return "";
|
|
27434
|
+
const normalizedValue = value2.substring(0, 5);
|
|
27435
|
+
const slot = timeSlots.find((s) => s.value === normalizedValue);
|
|
27436
|
+
return slot ? slot.label : value2;
|
|
27437
|
+
};
|
|
27438
|
+
useEffect(() => {
|
|
27439
|
+
const handleClickOutside = (event) => {
|
|
27440
|
+
if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
|
|
27441
|
+
setIsOpen(false);
|
|
27442
|
+
setSearchTerm("");
|
|
27443
|
+
}
|
|
27444
|
+
};
|
|
27445
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
27446
|
+
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
27447
|
+
}, []);
|
|
27448
|
+
const handleKeyDown = (e) => {
|
|
27449
|
+
if (e.key === "Escape") {
|
|
27450
|
+
setIsOpen(false);
|
|
27451
|
+
setSearchTerm("");
|
|
27452
|
+
} else if (e.key === "Enter") {
|
|
27453
|
+
e.preventDefault();
|
|
27454
|
+
if (filteredSlots.length > 0) {
|
|
27455
|
+
onChange(filteredSlots[0].value);
|
|
27456
|
+
setIsOpen(false);
|
|
27457
|
+
setSearchTerm("");
|
|
27199
27458
|
}
|
|
27200
27459
|
}
|
|
27201
|
-
|
|
27202
|
-
|
|
27203
|
-
|
|
27204
|
-
|
|
27205
|
-
|
|
27206
|
-
|
|
27207
|
-
|
|
27208
|
-
|
|
27209
|
-
|
|
27210
|
-
|
|
27211
|
-
|
|
27212
|
-
if (crop && !player.paused()) {
|
|
27213
|
-
renderFrameToCanvas();
|
|
27460
|
+
};
|
|
27461
|
+
const handleSelect = (timeValue) => {
|
|
27462
|
+
onChange(timeValue);
|
|
27463
|
+
setIsOpen(false);
|
|
27464
|
+
setSearchTerm("");
|
|
27465
|
+
};
|
|
27466
|
+
const handleToggle = () => {
|
|
27467
|
+
if (disabled) return;
|
|
27468
|
+
setIsOpen(!isOpen);
|
|
27469
|
+
if (!isOpen) {
|
|
27470
|
+
setTimeout(() => inputRef.current?.focus(), 100);
|
|
27214
27471
|
}
|
|
27215
|
-
|
|
27216
|
-
|
|
27217
|
-
|
|
27218
|
-
|
|
27219
|
-
|
|
27220
|
-
|
|
27221
|
-
|
|
27222
|
-
|
|
27223
|
-
|
|
27224
|
-
|
|
27225
|
-
|
|
27472
|
+
};
|
|
27473
|
+
return /* @__PURE__ */ jsxs("div", { className: `relative ${className}`, ref: dropdownRef, children: [
|
|
27474
|
+
/* @__PURE__ */ jsx(
|
|
27475
|
+
"button",
|
|
27476
|
+
{
|
|
27477
|
+
type: "button",
|
|
27478
|
+
onClick: handleToggle,
|
|
27479
|
+
disabled,
|
|
27480
|
+
className: `
|
|
27481
|
+
w-full px-3 py-2 text-left bg-white border border-gray-300 rounded-md shadow-sm
|
|
27482
|
+
focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500
|
|
27483
|
+
hover:border-gray-400 transition-colors duration-200
|
|
27484
|
+
${disabled ? "bg-gray-50 cursor-not-allowed" : "cursor-pointer"}
|
|
27485
|
+
${isOpen ? "ring-2 ring-blue-500 border-blue-500" : ""}
|
|
27486
|
+
`,
|
|
27487
|
+
children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
|
|
27488
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
27489
|
+
/* @__PURE__ */ jsx(Clock, { className: "h-4 w-4 text-gray-400" }),
|
|
27490
|
+
/* @__PURE__ */ jsx("span", { className: `text-sm ${value ? "text-gray-900" : "text-gray-500"}`, children: value ? getDisplayValue(value) : placeholder })
|
|
27491
|
+
] }),
|
|
27492
|
+
/* @__PURE__ */ jsx(
|
|
27493
|
+
ChevronDown,
|
|
27494
|
+
{
|
|
27495
|
+
className: `h-4 w-4 text-gray-400 transition-transform duration-200 ${isOpen ? "rotate-180" : ""}`
|
|
27496
|
+
}
|
|
27497
|
+
)
|
|
27498
|
+
] })
|
|
27499
|
+
}
|
|
27500
|
+
),
|
|
27501
|
+
isOpen && /* @__PURE__ */ jsxs("div", { className: "absolute z-50 w-full mt-1 bg-white border border-gray-300 rounded-md shadow-lg max-h-60 overflow-hidden", children: [
|
|
27502
|
+
/* @__PURE__ */ jsx("div", { className: "p-2 border-b border-gray-200", children: /* @__PURE__ */ jsx(
|
|
27503
|
+
"input",
|
|
27504
|
+
{
|
|
27505
|
+
ref: inputRef,
|
|
27506
|
+
type: "text",
|
|
27507
|
+
placeholder: "Search time...",
|
|
27508
|
+
value: searchTerm,
|
|
27509
|
+
onChange: (e) => setSearchTerm(e.target.value),
|
|
27510
|
+
onKeyDown: handleKeyDown,
|
|
27511
|
+
className: "w-full px-3 py-2 text-sm border border-gray-200 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
|
|
27512
|
+
}
|
|
27513
|
+
) }),
|
|
27514
|
+
/* @__PURE__ */ jsx("div", { className: "overflow-y-auto max-h-48", children: filteredSlots.length === 0 ? /* @__PURE__ */ jsx("div", { className: "px-3 py-2 text-sm text-gray-500 text-center", children: "No times found" }) : filteredSlots.map((slot) => /* @__PURE__ */ jsx(
|
|
27515
|
+
"button",
|
|
27516
|
+
{
|
|
27517
|
+
type: "button",
|
|
27518
|
+
onClick: () => handleSelect(slot.value),
|
|
27519
|
+
className: `
|
|
27520
|
+
w-full px-3 py-2 text-left text-sm hover:bg-blue-50 hover:text-blue-600
|
|
27521
|
+
transition-colors duration-150 border-b border-gray-100 last:border-b-0
|
|
27522
|
+
${slot.value === value ? "bg-blue-50 text-blue-600 font-medium" : "text-gray-700"}
|
|
27523
|
+
`,
|
|
27524
|
+
children: slot.label
|
|
27525
|
+
},
|
|
27526
|
+
slot.value
|
|
27527
|
+
)) })
|
|
27528
|
+
] })
|
|
27529
|
+
] });
|
|
27530
|
+
};
|
|
27531
|
+
var SilentErrorBoundary = class extends React23__default.Component {
|
|
27532
|
+
constructor(props) {
|
|
27533
|
+
super(props);
|
|
27534
|
+
this.handleClearAndReload = () => {
|
|
27535
|
+
console.log("[ErrorBoundary] User initiated reset");
|
|
27536
|
+
if (typeof window !== "undefined") {
|
|
27537
|
+
try {
|
|
27538
|
+
localStorage.clear();
|
|
27539
|
+
sessionStorage.clear();
|
|
27540
|
+
console.log("[ErrorBoundary] Cleared all storage");
|
|
27541
|
+
} catch (error) {
|
|
27542
|
+
console.error("[ErrorBoundary] Failed to clear storage:", error);
|
|
27543
|
+
}
|
|
27544
|
+
}
|
|
27545
|
+
window.location.href = "/login";
|
|
27226
27546
|
};
|
|
27227
|
-
|
|
27228
|
-
|
|
27229
|
-
|
|
27547
|
+
this.state = {
|
|
27548
|
+
hasError: false,
|
|
27549
|
+
errorCount: 0,
|
|
27550
|
+
lastError: null,
|
|
27551
|
+
errorInfo: null
|
|
27230
27552
|
};
|
|
27231
|
-
}
|
|
27232
|
-
|
|
27233
|
-
|
|
27234
|
-
|
|
27235
|
-
|
|
27236
|
-
|
|
27237
|
-
|
|
27238
|
-
|
|
27239
|
-
|
|
27240
|
-
|
|
27553
|
+
}
|
|
27554
|
+
static getDerivedStateFromError(error) {
|
|
27555
|
+
return { hasError: true };
|
|
27556
|
+
}
|
|
27557
|
+
componentDidCatch(error, errorInfo) {
|
|
27558
|
+
console.error("[ErrorBoundary] Caught render error:", {
|
|
27559
|
+
error: error.message,
|
|
27560
|
+
stack: error.stack,
|
|
27561
|
+
componentStack: errorInfo.componentStack,
|
|
27562
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
27563
|
+
});
|
|
27564
|
+
this.setState((prev) => ({
|
|
27565
|
+
errorCount: prev.errorCount + 1,
|
|
27566
|
+
lastError: error,
|
|
27567
|
+
errorInfo
|
|
27568
|
+
}));
|
|
27569
|
+
try {
|
|
27570
|
+
if (typeof window !== "undefined" && window.mixpanel) {
|
|
27571
|
+
window.mixpanel.track("React Render Error", {
|
|
27572
|
+
error: error.message,
|
|
27573
|
+
component: errorInfo.componentStack?.split("\n")[1] || "unknown",
|
|
27574
|
+
errorCount: this.state.errorCount + 1
|
|
27575
|
+
});
|
|
27241
27576
|
}
|
|
27577
|
+
} catch (analyticsError) {
|
|
27578
|
+
console.warn("[ErrorBoundary] Analytics tracking failed:", analyticsError);
|
|
27242
27579
|
}
|
|
27243
|
-
}, [videoProps.src, crop]);
|
|
27244
|
-
useEffect(() => {
|
|
27245
|
-
return () => {
|
|
27246
|
-
stopCanvasRendering();
|
|
27247
|
-
};
|
|
27248
|
-
}, [stopCanvasRendering]);
|
|
27249
|
-
if (!crop) {
|
|
27250
|
-
return /* @__PURE__ */ jsx(VideoPlayer, { ref, ...videoProps, onClick });
|
|
27251
27580
|
}
|
|
27252
|
-
|
|
27253
|
-
if (!
|
|
27254
|
-
|
|
27255
|
-
const willBePlaying = player.paused();
|
|
27256
|
-
setIndicatorIsPlaying(willBePlaying);
|
|
27257
|
-
setShowIndicator(false);
|
|
27258
|
-
setTimeout(() => {
|
|
27259
|
-
indicatorKeyRef.current += 1;
|
|
27260
|
-
setShowIndicator(true);
|
|
27261
|
-
}, 0);
|
|
27262
|
-
onClick();
|
|
27263
|
-
};
|
|
27264
|
-
return /* @__PURE__ */ jsxs(
|
|
27265
|
-
"div",
|
|
27266
|
-
{
|
|
27267
|
-
ref: videoContainerRef,
|
|
27268
|
-
className: `relative w-full h-full flex items-center justify-center bg-black ${onClick ? "cursor-pointer" : ""} ${videoProps.className || ""}`,
|
|
27269
|
-
onClick: handleClickWithIndicator,
|
|
27270
|
-
children: [
|
|
27271
|
-
/* @__PURE__ */ jsx("div", { className: "hidden", children: /* @__PURE__ */ jsx(
|
|
27272
|
-
VideoPlayer,
|
|
27273
|
-
{
|
|
27274
|
-
ref: hiddenVideoRef,
|
|
27275
|
-
...videoProps,
|
|
27276
|
-
onReady: handleVideoReady,
|
|
27277
|
-
onPlay: handleVideoPlay,
|
|
27278
|
-
onPause: handleVideoPause,
|
|
27279
|
-
onEnded: handleVideoEnded,
|
|
27280
|
-
onSeeking: handleSeeking,
|
|
27281
|
-
onSeeked: handleSeeked,
|
|
27282
|
-
onLoadedMetadata: handleLoadedMetadata,
|
|
27283
|
-
onLoadedData: videoProps.onLoadedData,
|
|
27284
|
-
onPlaying: videoProps.onPlaying,
|
|
27285
|
-
onLoadingChange: videoProps.onLoadingChange
|
|
27286
|
-
}
|
|
27287
|
-
) }),
|
|
27288
|
-
/* @__PURE__ */ jsx(
|
|
27289
|
-
"canvas",
|
|
27290
|
-
{
|
|
27291
|
-
ref: canvasRef,
|
|
27292
|
-
width: canvasDimensions.width,
|
|
27293
|
-
height: canvasDimensions.height,
|
|
27294
|
-
className: "max-w-full max-h-full",
|
|
27295
|
-
style: {
|
|
27296
|
-
display: isVideoReady ? "block" : "none",
|
|
27297
|
-
width: `${canvasDimensions.width}px`,
|
|
27298
|
-
height: `${canvasDimensions.height}px`
|
|
27299
|
-
}
|
|
27300
|
-
}
|
|
27301
|
-
),
|
|
27302
|
-
!isVideoReady && /* @__PURE__ */ jsx("div", { className: "absolute inset-0 flex items-center justify-center", children: /* @__PURE__ */ jsx(OptifyeLogoLoader_default, { size: "md", message: "Loading video..." }) }),
|
|
27303
|
-
debug && isVideoReady && /* @__PURE__ */ jsxs("div", { className: "absolute top-2 left-2 bg-black/80 text-white text-xs p-2 rounded font-mono", children: [
|
|
27304
|
-
/* @__PURE__ */ jsxs("div", { children: [
|
|
27305
|
-
"Crop: ",
|
|
27306
|
-
crop.x,
|
|
27307
|
-
",",
|
|
27308
|
-
crop.y,
|
|
27309
|
-
" ",
|
|
27310
|
-
crop.width,
|
|
27311
|
-
"x",
|
|
27312
|
-
crop.height,
|
|
27313
|
-
"%"
|
|
27314
|
-
] }),
|
|
27315
|
-
/* @__PURE__ */ jsxs("div", { children: [
|
|
27316
|
-
"Canvas: ",
|
|
27317
|
-
canvasDimensions.width,
|
|
27318
|
-
"x",
|
|
27319
|
-
canvasDimensions.height,
|
|
27320
|
-
"px"
|
|
27321
|
-
] }),
|
|
27322
|
-
/* @__PURE__ */ jsxs("div", { children: [
|
|
27323
|
-
"Processing: ",
|
|
27324
|
-
isProcessing ? "Yes" : "No"
|
|
27325
|
-
] })
|
|
27326
|
-
] }),
|
|
27327
|
-
onClick && /* @__PURE__ */ jsx(
|
|
27328
|
-
PlayPauseIndicator,
|
|
27329
|
-
{
|
|
27330
|
-
show: showIndicator,
|
|
27331
|
-
isPlaying: indicatorIsPlaying
|
|
27332
|
-
},
|
|
27333
|
-
indicatorKeyRef.current
|
|
27334
|
-
)
|
|
27335
|
-
]
|
|
27581
|
+
render() {
|
|
27582
|
+
if (!this.state.hasError) {
|
|
27583
|
+
return this.props.children;
|
|
27336
27584
|
}
|
|
27337
|
-
|
|
27338
|
-
})
|
|
27339
|
-
|
|
27585
|
+
return /* @__PURE__ */ jsx("div", { className: "flex h-screen w-screen items-center justify-center bg-slate-50", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center space-y-6 text-center", children: [
|
|
27586
|
+
/* @__PURE__ */ jsx(OptifyeLogoLoader_default, { size: "lg", message: "Loading Dashboard..." }),
|
|
27587
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm text-gray-500", children: "Taking longer than usual..." }),
|
|
27588
|
+
/* @__PURE__ */ jsx("div", { className: "pt-4", children: /* @__PURE__ */ jsx(
|
|
27589
|
+
"a",
|
|
27590
|
+
{
|
|
27591
|
+
href: "#",
|
|
27592
|
+
onClick: (e) => {
|
|
27593
|
+
e.preventDefault();
|
|
27594
|
+
this.handleClearAndReload();
|
|
27595
|
+
},
|
|
27596
|
+
className: "text-xs text-gray-400 hover:text-gray-600 underline transition-colors",
|
|
27597
|
+
children: "Reset and try again"
|
|
27598
|
+
}
|
|
27599
|
+
) }),
|
|
27600
|
+
process.env.NODE_ENV === "development" && /* @__PURE__ */ jsx("p", { className: "text-xs text-gray-400 italic mt-4", children: "Check console for error details" })
|
|
27601
|
+
] }) });
|
|
27602
|
+
}
|
|
27603
|
+
};
|
|
27340
27604
|
var BackButton = ({
|
|
27341
27605
|
onClick,
|
|
27342
27606
|
text = "Back",
|
|
@@ -27701,70 +27965,6 @@ var NewClipsNotification = ({
|
|
|
27701
27965
|
}
|
|
27702
27966
|
);
|
|
27703
27967
|
};
|
|
27704
|
-
var getSupabaseClient2 = () => {
|
|
27705
|
-
const url = process.env.NEXT_PUBLIC_SUPABASE_URL;
|
|
27706
|
-
const key = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY;
|
|
27707
|
-
if (!url || !key) {
|
|
27708
|
-
throw new Error("Supabase configuration missing");
|
|
27709
|
-
}
|
|
27710
|
-
return createClient(url, key);
|
|
27711
|
-
};
|
|
27712
|
-
var getAuthToken3 = async () => {
|
|
27713
|
-
try {
|
|
27714
|
-
const supabase = getSupabaseClient2();
|
|
27715
|
-
const { data: { session } } = await supabase.auth.getSession();
|
|
27716
|
-
return session?.access_token || null;
|
|
27717
|
-
} catch (error) {
|
|
27718
|
-
console.error("[useWorkspaceCrop] Error getting auth token:", error);
|
|
27719
|
-
return null;
|
|
27720
|
-
}
|
|
27721
|
-
};
|
|
27722
|
-
function useWorkspaceCrop(workspaceId) {
|
|
27723
|
-
const [crop, setCrop] = useState(null);
|
|
27724
|
-
const [isLoading, setIsLoading] = useState(true);
|
|
27725
|
-
const [error, setError] = useState(null);
|
|
27726
|
-
useEffect(() => {
|
|
27727
|
-
if (!workspaceId) {
|
|
27728
|
-
setIsLoading(false);
|
|
27729
|
-
return;
|
|
27730
|
-
}
|
|
27731
|
-
const fetchCrop = async () => {
|
|
27732
|
-
setIsLoading(true);
|
|
27733
|
-
setError(null);
|
|
27734
|
-
try {
|
|
27735
|
-
const token = await getAuthToken3();
|
|
27736
|
-
if (!token) {
|
|
27737
|
-
throw new Error("Authentication required");
|
|
27738
|
-
}
|
|
27739
|
-
const response = await fetch("/api/clips/supabase", {
|
|
27740
|
-
method: "POST",
|
|
27741
|
-
headers: {
|
|
27742
|
-
"Content-Type": "application/json",
|
|
27743
|
-
"Authorization": `Bearer ${token}`
|
|
27744
|
-
},
|
|
27745
|
-
body: JSON.stringify({
|
|
27746
|
-
action: "crop",
|
|
27747
|
-
workspaceId
|
|
27748
|
-
})
|
|
27749
|
-
});
|
|
27750
|
-
if (!response.ok) {
|
|
27751
|
-
throw new Error(`Failed to fetch crop: ${response.statusText}`);
|
|
27752
|
-
}
|
|
27753
|
-
const data = await response.json();
|
|
27754
|
-
console.log(`[useWorkspaceCrop] Fetched crop for workspace ${workspaceId}:`, data.crop);
|
|
27755
|
-
setCrop(data.crop);
|
|
27756
|
-
} catch (err) {
|
|
27757
|
-
console.error("[useWorkspaceCrop] Error fetching crop:", err);
|
|
27758
|
-
setError(err instanceof Error ? err.message : "Failed to fetch crop configuration");
|
|
27759
|
-
setCrop(null);
|
|
27760
|
-
} finally {
|
|
27761
|
-
setIsLoading(false);
|
|
27762
|
-
}
|
|
27763
|
-
};
|
|
27764
|
-
fetchCrop();
|
|
27765
|
-
}, [workspaceId]);
|
|
27766
|
-
return { crop, isLoading, error };
|
|
27767
|
-
}
|
|
27768
27968
|
var parseCycleTime = (value) => {
|
|
27769
27969
|
if (typeof value === "number" && Number.isFinite(value)) {
|
|
27770
27970
|
return value;
|
|
@@ -29020,6 +29220,11 @@ var BottlenecksContent = ({
|
|
|
29020
29220
|
return Number.isFinite(numericValue) ? numericValue : null;
|
|
29021
29221
|
})();
|
|
29022
29222
|
const videoRef = useRef(null);
|
|
29223
|
+
const videoPlayerOptions = useMemo(() => ({
|
|
29224
|
+
fluid: false,
|
|
29225
|
+
responsive: false,
|
|
29226
|
+
fill: false
|
|
29227
|
+
}), []);
|
|
29023
29228
|
const [initialFilter, setInitialFilter] = useState("");
|
|
29024
29229
|
const currentIndexRef = useRef(0);
|
|
29025
29230
|
const activeFilterRef = useRef(initialFilter);
|
|
@@ -29030,6 +29235,7 @@ var BottlenecksContent = ({
|
|
|
29030
29235
|
const [duration, setDuration] = useState(0);
|
|
29031
29236
|
const [currentIndex, setCurrentIndex] = useState(0);
|
|
29032
29237
|
const [currentClipId, setCurrentClipId] = useState(null);
|
|
29238
|
+
const [playbackSpeed, setPlaybackSpeed] = useState(1);
|
|
29033
29239
|
const [isTransitioning, setIsTransitioning] = useState(false);
|
|
29034
29240
|
const [pendingVideo, setPendingVideo] = useState(null);
|
|
29035
29241
|
const [isVideoBuffering, setIsVideoBuffering] = useState(false);
|
|
@@ -29047,6 +29253,31 @@ var BottlenecksContent = ({
|
|
|
29047
29253
|
const [categoryMetadata, setCategoryMetadata] = useState([]);
|
|
29048
29254
|
const [currentMetadataIndex, setCurrentMetadataIndex] = useState(0);
|
|
29049
29255
|
const [metadataCache, setMetadataCache] = useState({});
|
|
29256
|
+
const invalidateMetadataCache = useCallback((categories) => {
|
|
29257
|
+
setMetadataCache((prevCache) => {
|
|
29258
|
+
if (!prevCache || Object.keys(prevCache).length === 0) {
|
|
29259
|
+
return prevCache;
|
|
29260
|
+
}
|
|
29261
|
+
const targetCategories = categories ? (Array.isArray(categories) ? categories : [categories]).filter(Boolean) : null;
|
|
29262
|
+
let updatedCache = null;
|
|
29263
|
+
const shouldInvalidate = (key) => {
|
|
29264
|
+
if (!targetCategories || targetCategories.length === 0) {
|
|
29265
|
+
return true;
|
|
29266
|
+
}
|
|
29267
|
+
const [categoryId] = key.split("-");
|
|
29268
|
+
return targetCategories.includes(categoryId);
|
|
29269
|
+
};
|
|
29270
|
+
Object.keys(prevCache).forEach((cacheKey) => {
|
|
29271
|
+
if (shouldInvalidate(cacheKey)) {
|
|
29272
|
+
if (!updatedCache) {
|
|
29273
|
+
updatedCache = { ...prevCache };
|
|
29274
|
+
}
|
|
29275
|
+
delete updatedCache[cacheKey];
|
|
29276
|
+
}
|
|
29277
|
+
});
|
|
29278
|
+
return updatedCache || prevCache;
|
|
29279
|
+
});
|
|
29280
|
+
}, []);
|
|
29050
29281
|
const [triageClips, setTriageClips] = useState([]);
|
|
29051
29282
|
const [isLoadingTriageClips, setIsLoadingTriageClips] = useState(false);
|
|
29052
29283
|
const [isFullscreen, setIsFullscreen] = useState(false);
|
|
@@ -29066,6 +29297,12 @@ var BottlenecksContent = ({
|
|
|
29066
29297
|
onNewClips: (notification) => {
|
|
29067
29298
|
console.log(`[BottlenecksContent] New clips detected:`, notification);
|
|
29068
29299
|
if (notification.clips.length > 0) {
|
|
29300
|
+
const categoryIds = notification.clips.map((clip) => clip.clip_type).filter(Boolean).map((value) => String(value));
|
|
29301
|
+
if (categoryIds.length > 0) {
|
|
29302
|
+
invalidateMetadataCache(categoryIds);
|
|
29303
|
+
} else {
|
|
29304
|
+
invalidateMetadataCache();
|
|
29305
|
+
}
|
|
29069
29306
|
fetchClipCounts();
|
|
29070
29307
|
}
|
|
29071
29308
|
}
|
|
@@ -29112,24 +29349,37 @@ var BottlenecksContent = ({
|
|
|
29112
29349
|
shift: shift || "0"
|
|
29113
29350
|
});
|
|
29114
29351
|
useEffect(() => {
|
|
29115
|
-
if (clipTypes.length > 0
|
|
29116
|
-
const
|
|
29117
|
-
|
|
29118
|
-
|
|
29119
|
-
|
|
29120
|
-
|
|
29121
|
-
|
|
29122
|
-
|
|
29352
|
+
if (clipTypes.length > 0) {
|
|
29353
|
+
const currentFilterCount = initialFilter ? dynamicCounts[initialFilter] || 0 : 0;
|
|
29354
|
+
const hasAnyCounts = Object.values(dynamicCounts).some((c) => c > 0);
|
|
29355
|
+
const userHasNotNavigated = !initialFilter || activeFilterRef.current === initialFilter;
|
|
29356
|
+
const shouldRunSelection = !initialFilter || userHasNotNavigated && currentFilterCount === 0 && hasAnyCounts;
|
|
29357
|
+
if (shouldRunSelection) {
|
|
29358
|
+
let selectedType = null;
|
|
29359
|
+
if (clipTypes.length === 1) {
|
|
29360
|
+
selectedType = clipTypes[0];
|
|
29361
|
+
} else {
|
|
29362
|
+
const priorityOrder = ["cycle_completion", "fast-cycles", "slow-cycles", "idle_time"];
|
|
29363
|
+
for (const priorityType of priorityOrder) {
|
|
29364
|
+
const type = clipTypes.find((t) => t.type === priorityType && (dynamicCounts[t.type] || 0) > 0);
|
|
29365
|
+
if (type) {
|
|
29366
|
+
selectedType = type;
|
|
29367
|
+
break;
|
|
29368
|
+
}
|
|
29369
|
+
}
|
|
29370
|
+
if (!selectedType) {
|
|
29371
|
+
selectedType = clipTypes.find((type) => (dynamicCounts[type.type] || 0) > 0);
|
|
29372
|
+
}
|
|
29373
|
+
if (!selectedType) {
|
|
29374
|
+
selectedType = clipTypes[0];
|
|
29375
|
+
}
|
|
29376
|
+
}
|
|
29377
|
+
if (selectedType && selectedType.type !== initialFilter) {
|
|
29378
|
+
console.log(`[BottlenecksContent] Auto-selecting filter: ${selectedType.type} (count: ${dynamicCounts[selectedType.type] || 0})`);
|
|
29379
|
+
setInitialFilter(selectedType.type);
|
|
29380
|
+
setActiveFilter(selectedType.type);
|
|
29381
|
+
activeFilterRef.current = selectedType.type;
|
|
29123
29382
|
}
|
|
29124
|
-
}
|
|
29125
|
-
if (!selectedType) {
|
|
29126
|
-
selectedType = clipTypes.find((type) => (dynamicCounts[type.type] || 0) > 0);
|
|
29127
|
-
}
|
|
29128
|
-
const firstType = selectedType || clipTypes[0];
|
|
29129
|
-
if (firstType) {
|
|
29130
|
-
setInitialFilter(firstType.type);
|
|
29131
|
-
setActiveFilter(firstType.type);
|
|
29132
|
-
activeFilterRef.current = firstType.type;
|
|
29133
29383
|
}
|
|
29134
29384
|
}
|
|
29135
29385
|
}, [clipTypes, dynamicCounts, initialFilter]);
|
|
@@ -29181,7 +29431,7 @@ var BottlenecksContent = ({
|
|
|
29181
29431
|
} finally {
|
|
29182
29432
|
fetchInProgressRef.current.delete(operationKey);
|
|
29183
29433
|
}
|
|
29184
|
-
}, [workspaceId, date, s3ClipsService, effectiveShift, dashboardConfig, updateClipCounts]);
|
|
29434
|
+
}, [workspaceId, date, s3ClipsService, effectiveShift, dashboardConfig, updateClipCounts, timezone, totalOutput]);
|
|
29185
29435
|
const loadingCategoryRef = useRef(null);
|
|
29186
29436
|
const loadFirstVideoForCategory = useCallback(async (category) => {
|
|
29187
29437
|
if (!workspaceId || !s3ClipsService || !isMountedRef.current) return;
|
|
@@ -29271,15 +29521,16 @@ var BottlenecksContent = ({
|
|
|
29271
29521
|
loadingCategoryRef.current = null;
|
|
29272
29522
|
fetchInProgressRef.current.delete(operationKey);
|
|
29273
29523
|
}
|
|
29274
|
-
}, [workspaceId, date, s3ClipsService, mergedCounts, effectiveShift]);
|
|
29524
|
+
}, [workspaceId, date, s3ClipsService, mergedCounts, effectiveShift, timezone]);
|
|
29275
29525
|
const handleRefreshClips = useCallback(async () => {
|
|
29276
29526
|
console.log("[BottlenecksContent] Refreshing clips after new additions");
|
|
29277
29527
|
acknowledgeNewClips();
|
|
29528
|
+
invalidateMetadataCache();
|
|
29278
29529
|
await fetchClipCounts();
|
|
29279
29530
|
if (activeFilter && mergedCounts[activeFilter] > 0) {
|
|
29280
29531
|
await loadFirstVideoForCategory(activeFilter);
|
|
29281
29532
|
}
|
|
29282
|
-
}, [acknowledgeNewClips, fetchClipCounts, activeFilter, mergedCounts, loadFirstVideoForCategory]);
|
|
29533
|
+
}, [acknowledgeNewClips, fetchClipCounts, activeFilter, mergedCounts, loadFirstVideoForCategory, invalidateMetadataCache]);
|
|
29283
29534
|
useEffect(() => {
|
|
29284
29535
|
if (s3ClipsService) {
|
|
29285
29536
|
fetchClipCounts();
|
|
@@ -29449,38 +29700,38 @@ var BottlenecksContent = ({
|
|
|
29449
29700
|
loadingTimeoutRef.current = null;
|
|
29450
29701
|
}
|
|
29451
29702
|
}, []);
|
|
29452
|
-
const loadCategoryMetadata = useCallback(async (categoryId, autoLoadFirstVideo = false) => {
|
|
29703
|
+
const loadCategoryMetadata = useCallback(async (categoryId, autoLoadFirstVideo = false, forceRefresh = false) => {
|
|
29453
29704
|
if (!workspaceId) {
|
|
29454
29705
|
return;
|
|
29455
29706
|
}
|
|
29456
|
-
const
|
|
29457
|
-
|
|
29458
|
-
|
|
29459
|
-
|
|
29460
|
-
|
|
29461
|
-
|
|
29462
|
-
|
|
29463
|
-
|
|
29464
|
-
|
|
29465
|
-
|
|
29466
|
-
|
|
29467
|
-
|
|
29468
|
-
|
|
29469
|
-
|
|
29470
|
-
|
|
29471
|
-
|
|
29472
|
-
|
|
29707
|
+
const resolvedDate = date || getOperationalDate(timezone);
|
|
29708
|
+
const cacheKey = `${categoryId}-${resolvedDate}-${effectiveShift}`;
|
|
29709
|
+
const cachedMetadata = !forceRefresh ? metadataCache[cacheKey] : void 0;
|
|
29710
|
+
try {
|
|
29711
|
+
if (cachedMetadata) {
|
|
29712
|
+
console.log(`[BottlenecksContent] Using cached metadata for ${categoryId}`);
|
|
29713
|
+
setCategoryMetadata(cachedMetadata);
|
|
29714
|
+
categoryMetadataRef.current = cachedMetadata;
|
|
29715
|
+
if (autoLoadFirstVideo && cachedMetadata.length > 0 && s3ClipsService) {
|
|
29716
|
+
const firstClipMeta = cachedMetadata[0];
|
|
29717
|
+
try {
|
|
29718
|
+
const video = await s3ClipsService.getClipById(firstClipMeta.clipId);
|
|
29719
|
+
if (video && isMountedRef.current) {
|
|
29720
|
+
setCurrentClipId(firstClipMeta.clipId);
|
|
29721
|
+
setAllVideos([video]);
|
|
29722
|
+
setCurrentIndex(0);
|
|
29723
|
+
setCurrentMetadataIndex(0);
|
|
29724
|
+
currentMetadataIndexRef.current = 0;
|
|
29725
|
+
console.log(`[BottlenecksContent] Auto-loaded first video from cache: ${video.id} (1/${cachedMetadata.length})`);
|
|
29726
|
+
}
|
|
29727
|
+
} catch (error2) {
|
|
29728
|
+
console.error(`[BottlenecksContent] Error loading first video from cache:`, error2);
|
|
29729
|
+
clearLoadingState();
|
|
29473
29730
|
}
|
|
29474
|
-
} catch (error2) {
|
|
29475
|
-
console.error(`[BottlenecksContent] Error loading first video from cache:`, error2);
|
|
29476
|
-
setIsCategoryLoading(false);
|
|
29477
|
-
clearLoadingState();
|
|
29478
29731
|
}
|
|
29732
|
+
return;
|
|
29479
29733
|
}
|
|
29480
|
-
|
|
29481
|
-
}
|
|
29482
|
-
try {
|
|
29483
|
-
console.log(`[BottlenecksContent] Loading metadata for category: ${categoryId}`);
|
|
29734
|
+
console.log(`[BottlenecksContent] Loading metadata for category: ${categoryId}${forceRefresh ? " (force refresh)" : ""}`);
|
|
29484
29735
|
const { createClient: createClient5 } = await import('@supabase/supabase-js');
|
|
29485
29736
|
const supabase = createClient5(
|
|
29486
29737
|
process.env.NEXT_PUBLIC_SUPABASE_URL || "",
|
|
@@ -29505,8 +29756,8 @@ var BottlenecksContent = ({
|
|
|
29505
29756
|
action: "percentile-clips",
|
|
29506
29757
|
percentileAction: percentileType,
|
|
29507
29758
|
workspaceId,
|
|
29508
|
-
startDate: `${
|
|
29509
|
-
endDate: `${
|
|
29759
|
+
startDate: `${resolvedDate}T00:00:00Z`,
|
|
29760
|
+
endDate: `${resolvedDate}T23:59:59Z`,
|
|
29510
29761
|
percentile: 10,
|
|
29511
29762
|
shiftId: effectiveShift,
|
|
29512
29763
|
limit: 100
|
|
@@ -29522,7 +29773,7 @@ var BottlenecksContent = ({
|
|
|
29522
29773
|
body: JSON.stringify({
|
|
29523
29774
|
action: "clip-metadata",
|
|
29524
29775
|
workspaceId,
|
|
29525
|
-
date:
|
|
29776
|
+
date: resolvedDate,
|
|
29526
29777
|
shift: effectiveShift,
|
|
29527
29778
|
category: categoryId,
|
|
29528
29779
|
page: 1,
|
|
@@ -29567,19 +29818,22 @@ var BottlenecksContent = ({
|
|
|
29567
29818
|
setCurrentIndex(0);
|
|
29568
29819
|
setCurrentMetadataIndex(0);
|
|
29569
29820
|
currentMetadataIndexRef.current = 0;
|
|
29570
|
-
setIsCategoryLoading(false);
|
|
29571
29821
|
console.log(`[BottlenecksContent] Auto-loaded first video: ${video.id} (1/${metadataClips.length})`);
|
|
29572
29822
|
}
|
|
29573
29823
|
} catch (error2) {
|
|
29574
29824
|
console.error(`[BottlenecksContent] Error loading first video:`, error2);
|
|
29575
|
-
setIsCategoryLoading(false);
|
|
29576
29825
|
}
|
|
29577
29826
|
}
|
|
29827
|
+
} else {
|
|
29828
|
+
setCategoryMetadata([]);
|
|
29829
|
+
categoryMetadataRef.current = [];
|
|
29578
29830
|
}
|
|
29579
29831
|
} catch (error2) {
|
|
29580
29832
|
console.error(`[BottlenecksContent] Error loading category metadata:`, error2);
|
|
29833
|
+
} finally {
|
|
29834
|
+
setIsCategoryLoading(false);
|
|
29581
29835
|
}
|
|
29582
|
-
}, [workspaceId, date, effectiveShift, isPercentileCategory, metadataCache, s3ClipsService]);
|
|
29836
|
+
}, [workspaceId, date, effectiveShift, isPercentileCategory, metadataCache, s3ClipsService, timezone, clearLoadingState]);
|
|
29583
29837
|
const loadAndPlayClipById = useCallback(async (clipId, categoryId, position) => {
|
|
29584
29838
|
if (!workspaceId || !s3ClipsService || !isMountedRef.current) return;
|
|
29585
29839
|
console.log(`[BottlenecksContent] Loading clip by ID: ${clipId}, category=${categoryId}, position=${position}`);
|
|
@@ -29603,21 +29857,31 @@ var BottlenecksContent = ({
|
|
|
29603
29857
|
}
|
|
29604
29858
|
try {
|
|
29605
29859
|
await loadCategoryMetadata(categoryId, false);
|
|
29606
|
-
|
|
29607
|
-
|
|
29608
|
-
|
|
29609
|
-
|
|
29610
|
-
|
|
29611
|
-
|
|
29612
|
-
|
|
29613
|
-
|
|
29614
|
-
|
|
29615
|
-
|
|
29616
|
-
|
|
29617
|
-
|
|
29618
|
-
|
|
29619
|
-
|
|
29620
|
-
|
|
29860
|
+
let metadataArray = categoryMetadataRef.current;
|
|
29861
|
+
const clipExistsInMetadata = metadataArray.some((clip) => clip.clipId === clipId);
|
|
29862
|
+
if (metadataArray.length === 0 || !clipExistsInMetadata) {
|
|
29863
|
+
console.warn(`[BottlenecksContent] Clip ${clipId} not found in metadata for ${categoryId} (cache hit: ${metadataArray.length > 0}) - forcing refresh`);
|
|
29864
|
+
await loadCategoryMetadata(categoryId, false, true);
|
|
29865
|
+
metadataArray = categoryMetadataRef.current;
|
|
29866
|
+
}
|
|
29867
|
+
if (metadataArray.length === 0) {
|
|
29868
|
+
throw new Error(`No metadata available for category ${categoryId}`);
|
|
29869
|
+
}
|
|
29870
|
+
const clickedClipIndex = metadataArray.findIndex((clip) => clip.clipId === clipId);
|
|
29871
|
+
if (clickedClipIndex === -1) {
|
|
29872
|
+
throw new Error(`Clip ${clipId} not found after metadata refresh`);
|
|
29873
|
+
}
|
|
29874
|
+
setCurrentMetadataIndex(clickedClipIndex);
|
|
29875
|
+
currentMetadataIndexRef.current = clickedClipIndex;
|
|
29876
|
+
const video = await s3ClipsService.getClipById(clipId);
|
|
29877
|
+
if (video) {
|
|
29878
|
+
setPendingVideo(video);
|
|
29879
|
+
setCurrentClipId(clipId);
|
|
29880
|
+
setAllVideos([video]);
|
|
29881
|
+
setCurrentIndex(0);
|
|
29882
|
+
console.log(`[BottlenecksContent] Loaded clip ${clipId} (${clickedClipIndex + 1}/${metadataArray.length})`);
|
|
29883
|
+
} else {
|
|
29884
|
+
throw new Error(`Failed to load video data for clip ${clipId}`);
|
|
29621
29885
|
}
|
|
29622
29886
|
} catch (error2) {
|
|
29623
29887
|
console.error(`[BottlenecksContent] Error loading clip by ID (${clipId}):`, error2);
|
|
@@ -29631,7 +29895,7 @@ var BottlenecksContent = ({
|
|
|
29631
29895
|
clearLoadingState();
|
|
29632
29896
|
}
|
|
29633
29897
|
}
|
|
29634
|
-
}, [workspaceId, s3ClipsService,
|
|
29898
|
+
}, [workspaceId, s3ClipsService, updateActiveFilter, clearLoadingState, loadCategoryMetadata]);
|
|
29635
29899
|
useCallback(async (categoryId, clipIndex) => {
|
|
29636
29900
|
console.warn("[BottlenecksContent] loadAndPlayClip is deprecated, use loadAndPlayClipById instead");
|
|
29637
29901
|
if (!workspaceId || !s3ClipsService || !isMountedRef.current) return;
|
|
@@ -29658,7 +29922,7 @@ var BottlenecksContent = ({
|
|
|
29658
29922
|
});
|
|
29659
29923
|
setIsNavigating(false);
|
|
29660
29924
|
}
|
|
29661
|
-
}, [workspaceId, s3ClipsService, date, effectiveShift, loadAndPlayClipById]);
|
|
29925
|
+
}, [workspaceId, s3ClipsService, date, effectiveShift, loadAndPlayClipById, timezone]);
|
|
29662
29926
|
const handleNext = useCallback(async () => {
|
|
29663
29927
|
if (!isMountedRef.current) return;
|
|
29664
29928
|
const currentFilter = activeFilterRef.current;
|
|
@@ -29675,8 +29939,18 @@ var BottlenecksContent = ({
|
|
|
29675
29939
|
}
|
|
29676
29940
|
try {
|
|
29677
29941
|
const currentMetaIndex = currentMetadataIndexRef.current;
|
|
29678
|
-
|
|
29942
|
+
let metadataArray = categoryMetadataRef.current;
|
|
29943
|
+
if (metadataArray.length === 0) {
|
|
29944
|
+
console.log(`[handleNext] Metadata empty for ${currentFilter}, loading before navigation`);
|
|
29945
|
+
await loadCategoryMetadata(currentFilter, false);
|
|
29946
|
+
metadataArray = categoryMetadataRef.current;
|
|
29947
|
+
}
|
|
29679
29948
|
console.log(`[handleNext] Unified navigation: ${currentFilter}, metadata index: ${currentMetaIndex}/${metadataArray.length}`);
|
|
29949
|
+
if (metadataArray.length === 0) {
|
|
29950
|
+
console.warn("[handleNext] No metadata available after refresh - stopping navigation");
|
|
29951
|
+
clearLoadingState();
|
|
29952
|
+
return;
|
|
29953
|
+
}
|
|
29680
29954
|
if (currentMetaIndex < metadataArray.length - 1) {
|
|
29681
29955
|
const nextMetadataIndex = currentMetaIndex + 1;
|
|
29682
29956
|
const nextClipMeta = metadataArray[nextMetadataIndex];
|
|
@@ -29711,7 +29985,7 @@ var BottlenecksContent = ({
|
|
|
29711
29985
|
});
|
|
29712
29986
|
clearLoadingState();
|
|
29713
29987
|
}
|
|
29714
|
-
}, [clearLoadingState, s3ClipsService]);
|
|
29988
|
+
}, [clearLoadingState, s3ClipsService, loadCategoryMetadata]);
|
|
29715
29989
|
const handlePrevious = useCallback(async () => {
|
|
29716
29990
|
if (!isMountedRef.current) return;
|
|
29717
29991
|
const currentFilter = activeFilterRef.current;
|
|
@@ -29728,8 +30002,18 @@ var BottlenecksContent = ({
|
|
|
29728
30002
|
}
|
|
29729
30003
|
try {
|
|
29730
30004
|
const currentMetaIndex = currentMetadataIndexRef.current;
|
|
29731
|
-
|
|
30005
|
+
let metadataArray = categoryMetadataRef.current;
|
|
30006
|
+
if (metadataArray.length === 0) {
|
|
30007
|
+
console.log(`[handlePrevious] Metadata empty for ${currentFilter}, loading before navigation`);
|
|
30008
|
+
await loadCategoryMetadata(currentFilter, false);
|
|
30009
|
+
metadataArray = categoryMetadataRef.current;
|
|
30010
|
+
}
|
|
29732
30011
|
console.log(`[handlePrevious] Unified navigation: ${currentFilter}, metadata index: ${currentMetaIndex}/${metadataArray.length}`);
|
|
30012
|
+
if (metadataArray.length === 0) {
|
|
30013
|
+
console.warn("[handlePrevious] No metadata available after refresh - stopping navigation");
|
|
30014
|
+
clearLoadingState();
|
|
30015
|
+
return;
|
|
30016
|
+
}
|
|
29733
30017
|
if (currentMetaIndex > 0) {
|
|
29734
30018
|
const prevMetadataIndex = currentMetaIndex - 1;
|
|
29735
30019
|
const prevClipMeta = metadataArray[prevMetadataIndex];
|
|
@@ -29760,7 +30044,7 @@ var BottlenecksContent = ({
|
|
|
29760
30044
|
});
|
|
29761
30045
|
clearLoadingState();
|
|
29762
30046
|
}
|
|
29763
|
-
}, [clearLoadingState, s3ClipsService]);
|
|
30047
|
+
}, [clearLoadingState, s3ClipsService, loadCategoryMetadata]);
|
|
29764
30048
|
const currentVideo = useMemo(() => {
|
|
29765
30049
|
if (!filteredVideos || filteredVideos.length === 0 || currentIndex >= filteredVideos.length) {
|
|
29766
30050
|
return null;
|
|
@@ -29773,7 +30057,10 @@ var BottlenecksContent = ({
|
|
|
29773
30057
|
if (error?.isRetrying) {
|
|
29774
30058
|
setError(null);
|
|
29775
30059
|
}
|
|
29776
|
-
|
|
30060
|
+
if (videoRef.current?.playbackRate && playbackSpeed !== 1) {
|
|
30061
|
+
videoRef.current.playbackRate(playbackSpeed);
|
|
30062
|
+
}
|
|
30063
|
+
}, [error, playbackSpeed]);
|
|
29777
30064
|
const handleVideoPlay = useCallback(async (player) => {
|
|
29778
30065
|
setIsPlaying(true);
|
|
29779
30066
|
setIsInitialLoading(false);
|
|
@@ -29943,7 +30230,13 @@ var BottlenecksContent = ({
|
|
|
29943
30230
|
player.pause();
|
|
29944
30231
|
}
|
|
29945
30232
|
};
|
|
29946
|
-
const
|
|
30233
|
+
const handlePlaybackSpeedChange = useCallback((speed) => {
|
|
30234
|
+
setPlaybackSpeed(speed);
|
|
30235
|
+
if (videoRef.current?.playbackRate) {
|
|
30236
|
+
videoRef.current.playbackRate(speed);
|
|
30237
|
+
}
|
|
30238
|
+
}, []);
|
|
30239
|
+
useCallback((e) => {
|
|
29947
30240
|
e.stopPropagation();
|
|
29948
30241
|
setIsFullscreen((prev) => !prev);
|
|
29949
30242
|
}, []);
|
|
@@ -30117,12 +30410,7 @@ var BottlenecksContent = ({
|
|
|
30117
30410
|
onLoadedData: handleLoadedData,
|
|
30118
30411
|
onPlaying: handleVideoPlaying,
|
|
30119
30412
|
onLoadingChange: handleVideoLoadingChange,
|
|
30120
|
-
options:
|
|
30121
|
-
// Ensure full height is always visible - no cropping
|
|
30122
|
-
fluid: false,
|
|
30123
|
-
responsive: false,
|
|
30124
|
-
fill: false
|
|
30125
|
-
}
|
|
30413
|
+
options: videoPlayerOptions
|
|
30126
30414
|
}
|
|
30127
30415
|
)
|
|
30128
30416
|
}
|
|
@@ -30183,58 +30471,7 @@ var BottlenecksContent = ({
|
|
|
30183
30471
|
/* @__PURE__ */ jsx("span", { className: "font-medium mr-2", children: getClipTypeLabel(currentVideo) }),
|
|
30184
30472
|
/* @__PURE__ */ jsx("span", { className: "opacity-80 hidden sm:inline", children: currentVideo.description })
|
|
30185
30473
|
] }) })
|
|
30186
|
-
)
|
|
30187
|
-
/* @__PURE__ */ jsx("div", { className: "absolute bottom-0 left-0 right-0 p-3 bg-gradient-to-t from-black/70 to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-300 z-10", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between text-white", children: [
|
|
30188
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
30189
|
-
/* @__PURE__ */ jsx(
|
|
30190
|
-
"button",
|
|
30191
|
-
{
|
|
30192
|
-
onClick: (e) => {
|
|
30193
|
-
e.stopPropagation();
|
|
30194
|
-
togglePlayback();
|
|
30195
|
-
},
|
|
30196
|
-
className: "p-1.5 hover:bg-white/20 rounded-full focus:outline-none focus:ring-2 focus:ring-white/50",
|
|
30197
|
-
"aria-label": isPlaying ? "Pause" : "Play",
|
|
30198
|
-
children: isPlaying ? /* @__PURE__ */ jsx("svg", { xmlns: "http://www.w3.org/2000/svg", className: "h-5 w-5", viewBox: "0 0 20 20", fill: "currentColor", children: /* @__PURE__ */ jsx("path", { fillRule: "evenodd", d: "M18 10a8 8 0 11-16 0 8 8 0 0116 0zM7 8a1 1 0 00-1 1v2a1 1 0 102 0V9a1 1 0 00-1-1zm5 0a1 1 0 00-1 1v2a1 1 0 102 0V9a1 1 0 00-1-1z", clipRule: "evenodd" }) }) : /* @__PURE__ */ jsx("svg", { xmlns: "http://www.w3.org/2000/svg", className: "h-5 w-5", viewBox: "0 0 20 20", fill: "currentColor", children: /* @__PURE__ */ jsx("path", { fillRule: "evenodd", d: "M10 18a8 8 0 100-16 8 8 0 000 16zM9.555 7.168A1 1 0 008 8.118l-.001 3.764a1 1 0 001.555.832l3.196-1.882a1 1 0 000-1.664l-3.196-1.882z", clipRule: "evenodd" }) })
|
|
30199
|
-
}
|
|
30200
|
-
),
|
|
30201
|
-
/* @__PURE__ */ jsxs("span", { className: "text-xs font-mono px-2", children: [
|
|
30202
|
-
formatTime2(currentTime),
|
|
30203
|
-
" / ",
|
|
30204
|
-
formatTime2(duration)
|
|
30205
|
-
] })
|
|
30206
|
-
] }),
|
|
30207
|
-
/* @__PURE__ */ jsx(
|
|
30208
|
-
"input",
|
|
30209
|
-
{
|
|
30210
|
-
type: "range",
|
|
30211
|
-
min: "0",
|
|
30212
|
-
max: duration || 0,
|
|
30213
|
-
value: currentTime,
|
|
30214
|
-
onChange: (e) => {
|
|
30215
|
-
if (videoRef.current) {
|
|
30216
|
-
videoRef.current.currentTime(Number(e.target.value));
|
|
30217
|
-
}
|
|
30218
|
-
},
|
|
30219
|
-
className: "flex-grow mx-3 h-2.5 bg-white/30 rounded-full appearance-none cursor-pointer focus:outline-none focus:ring-2 focus:ring-white/50 touch-manipulation",
|
|
30220
|
-
style: {
|
|
30221
|
-
WebkitAppearance: "none",
|
|
30222
|
-
appearance: "none"
|
|
30223
|
-
},
|
|
30224
|
-
"aria-label": "Seek slider"
|
|
30225
|
-
}
|
|
30226
|
-
),
|
|
30227
|
-
/* @__PURE__ */ jsx(
|
|
30228
|
-
"button",
|
|
30229
|
-
{
|
|
30230
|
-
onClick: toggleFullscreen,
|
|
30231
|
-
className: "p-1.5 hover:bg-white/20 rounded-full focus:outline-none focus:ring-2 focus:ring-white/50",
|
|
30232
|
-
"aria-label": "Fullscreen",
|
|
30233
|
-
title: "Expand to fullscreen",
|
|
30234
|
-
children: /* @__PURE__ */ jsx(Maximize2, { className: "h-5 w-5" })
|
|
30235
|
-
}
|
|
30236
|
-
)
|
|
30237
|
-
] }) })
|
|
30474
|
+
)
|
|
30238
30475
|
] }) }) }) : (
|
|
30239
30476
|
/* Priority 5: Show "no clips found" only if we have counts and there are truly no clips for workspace */
|
|
30240
30477
|
hasInitialLoad && Object.keys(mergedCounts).length > 0 && Object.values(mergedCounts).every((count) => count === 0) ? /* @__PURE__ */ jsx("div", { className: `flex items-center justify-center ${triageMode ? "h-full" : "h-[calc(100%-4rem)]"}`, children: /* @__PURE__ */ jsxs("div", { className: "text-center p-8", children: [
|
|
@@ -30452,11 +30689,7 @@ var BottlenecksContent = ({
|
|
|
30452
30689
|
onLoadedData: handleLoadedData,
|
|
30453
30690
|
onPlaying: handleVideoPlaying,
|
|
30454
30691
|
onLoadingChange: handleVideoLoadingChange,
|
|
30455
|
-
options:
|
|
30456
|
-
fluid: false,
|
|
30457
|
-
responsive: false,
|
|
30458
|
-
fill: false
|
|
30459
|
-
}
|
|
30692
|
+
options: videoPlayerOptions
|
|
30460
30693
|
}
|
|
30461
30694
|
)
|
|
30462
30695
|
}
|
|
@@ -30464,45 +30697,32 @@ var BottlenecksContent = ({
|
|
|
30464
30697
|
(isTransitioning || isVideoBuffering && isInitialLoading) && !error && /* @__PURE__ */ jsx("div", { className: "absolute inset-0 z-30 flex items-center justify-center bg-black", children: /* @__PURE__ */ jsx(OptifyeLogoLoader_default, { size: "md", message: "Loading video..." }) }),
|
|
30465
30698
|
!isTransitioning && isVideoBuffering && !isInitialLoading && !error && /* @__PURE__ */ jsx("div", { className: "absolute inset-0 z-30 flex items-center justify-center bg-black/60", children: /* @__PURE__ */ jsx(OptifyeLogoLoader_default, { size: "md", message: "Loading video..." }) }),
|
|
30466
30699
|
/* @__PURE__ */ jsx("div", { className: "absolute bottom-0 left-0 right-0 p-4 bg-gradient-to-t from-black/70 to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-300 z-10", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between text-white", children: [
|
|
30467
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-
|
|
30468
|
-
/* @__PURE__ */ jsx(
|
|
30469
|
-
|
|
30700
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
30701
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm font-medium", children: "Speed:" }),
|
|
30702
|
+
/* @__PURE__ */ jsxs(
|
|
30703
|
+
"select",
|
|
30470
30704
|
{
|
|
30471
|
-
|
|
30472
|
-
|
|
30473
|
-
|
|
30474
|
-
|
|
30475
|
-
|
|
30476
|
-
|
|
30477
|
-
|
|
30705
|
+
value: playbackSpeed,
|
|
30706
|
+
onChange: (e) => handlePlaybackSpeedChange(Number(e.target.value)),
|
|
30707
|
+
className: "px-2 py-1 bg-white/20 hover:bg-white/30 rounded text-sm font-medium cursor-pointer focus:outline-none focus:ring-2 focus:ring-white/50 transition-colors",
|
|
30708
|
+
"aria-label": "Playback speed",
|
|
30709
|
+
children: [
|
|
30710
|
+
/* @__PURE__ */ jsx("option", { value: "0.25", children: "0.25x" }),
|
|
30711
|
+
/* @__PURE__ */ jsx("option", { value: "0.5", children: "0.5x" }),
|
|
30712
|
+
/* @__PURE__ */ jsx("option", { value: "0.75", children: "0.75x" }),
|
|
30713
|
+
/* @__PURE__ */ jsx("option", { value: "1", children: "1x" }),
|
|
30714
|
+
/* @__PURE__ */ jsx("option", { value: "1.25", children: "1.25x" }),
|
|
30715
|
+
/* @__PURE__ */ jsx("option", { value: "1.5", children: "1.5x" }),
|
|
30716
|
+
/* @__PURE__ */ jsx("option", { value: "1.75", children: "1.75x" }),
|
|
30717
|
+
/* @__PURE__ */ jsx("option", { value: "2", children: "2x" }),
|
|
30718
|
+
/* @__PURE__ */ jsx("option", { value: "3", children: "3x" }),
|
|
30719
|
+
/* @__PURE__ */ jsx("option", { value: "4", children: "4x" }),
|
|
30720
|
+
/* @__PURE__ */ jsx("option", { value: "5", children: "5x" }),
|
|
30721
|
+
/* @__PURE__ */ jsx("option", { value: "10", children: "10x" })
|
|
30722
|
+
]
|
|
30478
30723
|
}
|
|
30479
|
-
)
|
|
30480
|
-
/* @__PURE__ */ jsxs("span", { className: "text-sm font-mono px-2", children: [
|
|
30481
|
-
formatTime2(currentTime),
|
|
30482
|
-
" / ",
|
|
30483
|
-
formatTime2(duration)
|
|
30484
|
-
] })
|
|
30724
|
+
)
|
|
30485
30725
|
] }),
|
|
30486
|
-
/* @__PURE__ */ jsx(
|
|
30487
|
-
"input",
|
|
30488
|
-
{
|
|
30489
|
-
type: "range",
|
|
30490
|
-
min: "0",
|
|
30491
|
-
max: duration || 0,
|
|
30492
|
-
value: currentTime,
|
|
30493
|
-
onChange: (e) => {
|
|
30494
|
-
if (videoRef.current) {
|
|
30495
|
-
videoRef.current.currentTime(Number(e.target.value));
|
|
30496
|
-
}
|
|
30497
|
-
},
|
|
30498
|
-
className: "flex-grow mx-4 h-2.5 bg-white/30 rounded-full appearance-none cursor-pointer focus:outline-none focus:ring-2 focus:ring-white/50 touch-manipulation",
|
|
30499
|
-
style: {
|
|
30500
|
-
WebkitAppearance: "none",
|
|
30501
|
-
appearance: "none"
|
|
30502
|
-
},
|
|
30503
|
-
"aria-label": "Seek slider"
|
|
30504
|
-
}
|
|
30505
|
-
),
|
|
30506
30726
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
30507
30727
|
/* @__PURE__ */ jsx(
|
|
30508
30728
|
"button",
|
|
@@ -37603,26 +37823,26 @@ var SingleVideoStream = ({
|
|
|
37603
37823
|
const hlsStreamUrl = streamUrl || getCameraStreamUrl(workspaceName, baseUrl);
|
|
37604
37824
|
console.log(`Using camera URL for ${workspaceName}: ${hlsStreamUrl}`);
|
|
37605
37825
|
const mergedHlsConfig = { ...DEFAULT_HLS_CONFIG, ...hlsConfig };
|
|
37606
|
-
if (
|
|
37607
|
-
const hls = new
|
|
37826
|
+
if (Hls3.isSupported()) {
|
|
37827
|
+
const hls = new Hls3(mergedHlsConfig);
|
|
37608
37828
|
hlsRef.current = hls;
|
|
37609
|
-
hls.on(
|
|
37829
|
+
hls.on(Hls3.Events.MEDIA_ATTACHED, () => {
|
|
37610
37830
|
console.log("HLS media attached");
|
|
37611
37831
|
hls.loadSource(hlsStreamUrl);
|
|
37612
37832
|
});
|
|
37613
|
-
hls.on(
|
|
37833
|
+
hls.on(Hls3.Events.MANIFEST_PARSED, () => {
|
|
37614
37834
|
console.log("HLS manifest parsed");
|
|
37615
37835
|
attemptPlay(video);
|
|
37616
37836
|
});
|
|
37617
|
-
hls.on(
|
|
37837
|
+
hls.on(Hls3.Events.ERROR, (_, data) => {
|
|
37618
37838
|
if (data.fatal) {
|
|
37619
37839
|
console.error("Fatal HLS error:", data.type, data.details);
|
|
37620
37840
|
switch (data.type) {
|
|
37621
|
-
case
|
|
37841
|
+
case Hls3.ErrorTypes.NETWORK_ERROR:
|
|
37622
37842
|
console.error("Fatal network error encountered");
|
|
37623
37843
|
setError("Network error: Please check your connection");
|
|
37624
37844
|
break;
|
|
37625
|
-
case
|
|
37845
|
+
case Hls3.ErrorTypes.MEDIA_ERROR:
|
|
37626
37846
|
console.error("Fatal media error encountered, trying to recover");
|
|
37627
37847
|
hls.recoverMediaError();
|
|
37628
37848
|
break;
|
|
@@ -42383,9 +42603,9 @@ var MetricCards = memo(({ lineInfo }) => {
|
|
|
42383
42603
|
animate: "animate",
|
|
42384
42604
|
className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3 sm:gap-4 mb-2 md:h-[35vh] h-auto",
|
|
42385
42605
|
children: [
|
|
42386
|
-
/* @__PURE__ */ jsxs(motion.div, { variants: itemVariants, className: "bg-white rounded-xl shadow-sm p-3 sm:p-4 overflow-hidden h-[
|
|
42387
|
-
/* @__PURE__ */ jsx("h2", { className: "text-sm sm:text-base font-semibold text-gray-700 mb-
|
|
42388
|
-
/* @__PURE__ */ jsx("div", { className: "h-[calc(100%-
|
|
42606
|
+
/* @__PURE__ */ jsxs(motion.div, { variants: itemVariants, className: "bg-white rounded-xl shadow-sm p-3 sm:p-4 overflow-hidden h-[240px] sm:h-[260px] md:h-auto", children: [
|
|
42607
|
+
/* @__PURE__ */ jsx("h2", { className: "text-sm sm:text-base font-semibold text-gray-700 mb-2 text-center", children: "Line Output" }),
|
|
42608
|
+
/* @__PURE__ */ jsx("div", { className: "h-[calc(100%-2.5rem)]", children: /* @__PURE__ */ jsx("div", { className: "w-full h-full flex items-center justify-center", children: /* @__PURE__ */ jsx(
|
|
42389
42609
|
OutputProgressChart,
|
|
42390
42610
|
{
|
|
42391
42611
|
currentOutput: lineInfo?.metrics.current_output || 0,
|
|
@@ -42393,9 +42613,9 @@ var MetricCards = memo(({ lineInfo }) => {
|
|
|
42393
42613
|
}
|
|
42394
42614
|
) }) })
|
|
42395
42615
|
] }),
|
|
42396
|
-
/* @__PURE__ */ jsxs(motion.div, { variants: itemVariants, className: "bg-white rounded-xl shadow-sm p-3 sm:p-4 overflow-hidden h-[
|
|
42616
|
+
/* @__PURE__ */ jsxs(motion.div, { variants: itemVariants, className: "bg-white rounded-xl shadow-sm p-3 sm:p-4 overflow-hidden h-[240px] sm:h-[260px] md:h-auto", children: [
|
|
42397
42617
|
/* @__PURE__ */ jsx("h2", { className: "text-sm sm:text-base font-semibold text-gray-700 text-center mb-2", children: "Underperforming Workspaces" }),
|
|
42398
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-center h-[calc(100%-
|
|
42618
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-center h-[calc(100%-2.5rem)]", children: [
|
|
42399
42619
|
/* @__PURE__ */ jsx("span", { className: "text-4xl sm:text-5xl md:text-6xl lg:text-7xl font-bold text-red-600", children: lineInfo?.metrics.underperforming_workspaces }),
|
|
42400
42620
|
/* @__PURE__ */ jsxs("span", { className: "text-xl sm:text-2xl md:text-2xl lg:text-3xl text-gray-500 ml-1 sm:ml-2", children: [
|
|
42401
42621
|
"/ ",
|
|
@@ -42403,9 +42623,9 @@ var MetricCards = memo(({ lineInfo }) => {
|
|
|
42403
42623
|
] })
|
|
42404
42624
|
] })
|
|
42405
42625
|
] }),
|
|
42406
|
-
/* @__PURE__ */ jsxs(motion.div, { variants: itemVariants, className: "bg-white rounded-xl shadow-sm p-3 sm:p-4 overflow-hidden h-[
|
|
42626
|
+
/* @__PURE__ */ jsxs(motion.div, { variants: itemVariants, className: "bg-white rounded-xl shadow-sm p-3 sm:p-4 overflow-hidden h-[240px] sm:h-[260px] md:h-auto", children: [
|
|
42407
42627
|
/* @__PURE__ */ jsx("h2", { className: "text-sm sm:text-base font-semibold text-gray-700 text-center mb-2", children: "Average Efficiency" }),
|
|
42408
|
-
/* @__PURE__ */ jsx("div", { className: "flex items-center justify-center h-[calc(100%-
|
|
42628
|
+
/* @__PURE__ */ jsx("div", { className: "flex items-center justify-center h-[calc(100%-2.5rem)]", children: /* @__PURE__ */ jsxs("span", { className: `text-4xl sm:text-5xl md:text-6xl lg:text-7xl font-bold ${(lineInfo?.metrics.avg_efficiency || 0) >= 90 ? "text-green-600" : (lineInfo?.metrics.avg_efficiency || 0) >= 70 ? "text-yellow-600" : "text-red-600"}`, children: [
|
|
42409
42629
|
lineInfo?.metrics.avg_efficiency.toFixed(1),
|
|
42410
42630
|
"%"
|
|
42411
42631
|
] }) })
|
|
@@ -51923,4 +52143,4 @@ function shuffleArray(array) {
|
|
|
51923
52143
|
return shuffled;
|
|
51924
52144
|
}
|
|
51925
52145
|
|
|
51926
|
-
export { ACTION_NAMES, AIAgentView_default as AIAgentView, AcceptInvite, AcceptInviteView_default as AcceptInviteView, AdvancedFilterDialog, AdvancedFilterPanel, AudioService, AuthCallback, AuthCallbackView_default as AuthCallbackView, AuthProvider, AuthService, AuthenticatedBottleneckClipsView, AuthenticatedFactoryView, AuthenticatedHelpView, AuthenticatedHomeView, AuthenticatedShiftsView, AuthenticatedTargetsView, AuthenticatedTicketsView, AuthenticatedWorkspaceHealthView, AxelNotificationPopup, AxelOrb, BackButton, BackButtonMinimal, BarChart, BaseHistoryCalendar, BottleneckClipsModal, BottleneckClipsView_default as BottleneckClipsView, BottlenecksContent, BreakNotificationPopup, CachePrefetchStatus, Card2 as Card, CardContent2 as CardContent, CardDescription2 as CardDescription, CardFooter2 as CardFooter, CardHeader2 as CardHeader, CardTitle2 as CardTitle, ClipFilterProvider, CompactWorkspaceHealthCard, CongratulationsOverlay, CroppedVideoPlayer, CycleTimeChart, CycleTimeOverTimeChart, DEFAULT_ANALYTICS_CONFIG, DEFAULT_AUTH_CONFIG, DEFAULT_CONFIG, DEFAULT_DATABASE_CONFIG, DEFAULT_DATE_TIME_CONFIG, DEFAULT_ENDPOINTS_CONFIG, DEFAULT_ENTITY_CONFIG, DEFAULT_MAP_VIEW_CONFIG, DEFAULT_SHIFT_CONFIG, DEFAULT_THEME_CONFIG, DEFAULT_VIDEO_CONFIG, DEFAULT_WORKSPACE_CONFIG, DEFAULT_WORKSPACE_POSITIONS, DashboardHeader, DashboardLayout, DashboardOverridesProvider, DashboardProvider, DateDisplay_default as DateDisplay, DateTimeDisplay, DebugAuth, DebugAuthView_default as DebugAuthView, DetailedHealthStatus, DiagnosisVideoModal, EmptyStateMessage, EncouragementOverlay, FactoryView_default as FactoryView, FileManagerFilters, FilterDialogTrigger, FirstTimeLoginDebug, FirstTimeLoginHandler, GaugeChart, GridComponentsPlaceholder, HamburgerButton, Header, HealthStatusGrid, HealthStatusIndicator, HelpView_default as HelpView, HomeView_default as HomeView, HourlyOutputChart2 as HourlyOutputChart, ISTTimer_default as ISTTimer, InlineEditableText, InteractiveOnboardingTour, InvitationService, KPICard, KPIDetailView_default as KPIDetailView, KPIGrid, KPIHeader, KPISection, KPIsOverviewView_default as KPIsOverviewView, LINE_1_UUID, LINE_2_UUID, LargeOutputProgressChart, LeaderboardDetailView_default as LeaderboardDetailView, Legend6 as Legend, LineChart, LineHistoryCalendar, LineMonthlyHistory, LineMonthlyPdfGenerator, LinePdfExportButton, LinePdfGenerator, LineWhatsAppShareButton, LinesService, LiveTimer, LoadingInline, LoadingOverlay_default as LoadingOverlay, LoadingPage_default as LoadingPage, LoadingSkeleton, LoadingState, LoginPage, LoginView_default as LoginView, Logo, MainLayout, MapGridView, MetricCard_default as MetricCard, MinimalOnboardingPopup, NewClipsNotification, NoWorkspaceData, OnboardingDemo, OnboardingTour, OptifyeAgentClient, OptifyeLogoLoader_default as OptifyeLogoLoader, OutputProgressChart, PageHeader, PieChart4 as PieChart, PlayPauseIndicator, PrefetchConfigurationError, PrefetchError, PrefetchEvents, PrefetchStatus, PrefetchTimeoutError, ProfileView_default as ProfileView, RegistryProvider, S3ClipsSupabaseService as S3ClipsService, S3Service, SKUManagementView, SOPComplianceChart, SSEChatClient, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, ShiftDisplay_default as ShiftDisplay, ShiftsView_default as ShiftsView, SideNavBar, SignupWithInvitation, SilentErrorBoundary, SimpleOnboardingPopup, SingleVideoStream_default as SingleVideoStream, Skeleton, SubscriptionManager, SubscriptionManagerProvider, SupabaseProvider, SupervisorDropdown_default as SupervisorDropdown, SupervisorManagementView_default as SupervisorManagementView, SupervisorService, TargetWorkspaceGrid, TargetsView_default as TargetsView, TeamManagementView_default as TeamManagementView, ThreadSidebar, TicketHistory_default as TicketHistory, TicketHistoryService, TicketsView_default as TicketsView, TimeDisplay_default as TimeDisplay, TimePickerDropdown, Timer_default as Timer, TimezoneProvider, TimezoneService, UserManagementService, UserService, VideoCard, VideoGridView, VideoPlayer, VideoPreloader, WORKSPACE_POSITIONS, WhatsAppShareButton, WorkspaceCard, WorkspaceDetailView_default as WorkspaceDetailView, WorkspaceDisplayNameExample, WorkspaceGrid, WorkspaceGridItem, WorkspaceHealthCard, WorkspaceHealthView_default as WorkspaceHealthView, WorkspaceHistoryCalendar, WorkspaceMetricCards, WorkspaceMetricCardsImpl, WorkspaceMonthlyDataFetcher, WorkspaceMonthlyHistory, WorkspaceMonthlyPdfGenerator, WorkspacePdfExportButton, WorkspacePdfGenerator, WorkspaceWhatsAppShareButton, actionService, apiUtils, authCoreService, authOTPService, authRateLimitService, checkRateLimit2 as checkRateLimit, clearAllRateLimits2 as clearAllRateLimits, clearRateLimit2 as clearRateLimit, clearS3VideoCache, clearS3VideoFromCache, clearWorkspaceDisplayNamesCache, cn, createInvitationService, createLinesService, createStreamProxyHandler, createSupabaseClient, createSupervisorService, createThrottledReload, createUserManagementService, createUserService, dashboardService, deleteThread, forceRefreshWorkspaceDisplayNames, formatDateInZone, formatDateTimeInZone, formatISTDate, formatIdleTime, formatRelativeTime, formatTimeInZone, fromUrlFriendlyName, getAllLineDisplayNames, getAllThreadMessages, getAllWorkspaceDisplayNamesAsync, getAnonClient, getBrowserName, getCameraNumber, getCompanyMetricsTableName, getConfigurableShortWorkspaceDisplayName, getConfigurableWorkspaceDisplayName, getConfiguredLineIds, getCoreSessionRecordingProperties, getCoreSessionReplayUrl, getCurrentShift, getCurrentTimeInZone, getDashboardHeaderTimeInZone, getDaysDifferenceInZone, getDefaultCameraStreamUrl, getDefaultLineId, getDefaultTabForWorkspace, getLineDisplayName, getManufacturingInsights, getMetricsTablePrefix, getNextUpdateInterval, getOperationalDate, getS3SignedUrl, getS3VideoSrc, getShortWorkspaceDisplayName, getShortWorkspaceDisplayNameAsync, getStoredWorkspaceMappings, getSubscriptionManager, getThreadMessages, getUserThreads, getUserThreadsPaginated, getWorkspaceDisplayName, getWorkspaceDisplayNameAsync, getWorkspaceDisplayNamesMap, getWorkspaceFromUrl, getWorkspaceNavigationParams, identifyCoreUser, initializeCoreMixpanel, isLegacyConfiguration, isPrefetchError, isSafari, isTransitionPeriod, isUrlPermanentlyFailed, isValidFactoryViewConfiguration, isValidLineInfoPayload, isValidPrefetchParams, isValidPrefetchStatus, isValidWorkspaceDetailedMetricsPayload, isValidWorkspaceMetricsPayload, isWorkspaceDisplayNamesLoaded, isWorkspaceDisplayNamesLoading, linesService, mergeWithDefaultConfig, migrateLegacyConfiguration, optifyeAgentClient, parseS3Uri, preInitializeWorkspaceDisplayNames, preloadS3Video, preloadS3VideoUrl, preloadS3VideosUrl, preloadVideoUrl, preloadVideosUrl, qualityService, realtimeService, refreshWorkspaceDisplayNames, resetCoreMixpanel, resetFailedUrl, resetSubscriptionManager, s3VideoPreloader, shuffleArray, simulateApiDelay, skuService, startCoreSessionRecording, stopCoreSessionRecording, storeWorkspaceMapping, streamProxyConfig, throttledReloadDashboard, toUrlFriendlyName, trackCoreEvent, trackCorePageView, updateThreadTitle, useAccessControl, useActiveBreaks, useActiveLineId, useAllWorkspaceMetrics, useAnalyticsConfig, useAppTimezone, useAudioService, useAuth, useAuthConfig, useAxelNotifications, useCanSaveTargets, useClipFilter, useClipTypes, useClipTypesWithCounts, useComponentOverride, useCustomConfig, useDashboardConfig, useDashboardMetrics, useDatabaseConfig, useDateFormatter, useDateTimeConfig, useDynamicShiftConfig, useEndpointsConfig, useEntityConfig, useFactoryOverviewMetrics, useFeatureFlags, useFormatNumber, useHasLineAccess, useHistoricWorkspaceMetrics, useHlsStream, useHlsStreamWithCropping, useHookOverride, useHourEndTimer, useHourlyTargetAchievements, useHourlyTargetMisses, useLeaderboardMetrics, useLineDetailedMetrics, useLineKPIs, useLineMetrics, useLineShiftConfig, useLineSupervisor, useLineWorkspaceMetrics, useMessages, useMetrics, useNavigation, useOverrides, usePageOverride, usePrefetchClipCounts, useRealtimeLineMetrics, useRegistry, useSKUs, useSessionKeepAlive, useShiftConfig, useShifts, useSubscriptionManager, useSubscriptionManagerSafe, useSupabase, useSupabaseClient, useTargets, useTeamManagementPermissions, useTheme, useThemeConfig, useThreads, useTicketHistory, useTimezoneContext, useUserLineAccess, useVideoConfig, useWorkspaceConfig, useWorkspaceDetailedMetrics, useWorkspaceDisplayName, useWorkspaceDisplayNames, useWorkspaceDisplayNamesMap, useWorkspaceHealthById, useWorkspaceHealthStatus, useWorkspaceMetrics, useWorkspaceNavigation, useWorkspaceOperators, userService, videoPrefetchManager, videoPreloader, whatsappService, withAccessControl, withAuth, withRegistry, withTimezone, workspaceHealthService, workspaceService };
|
|
52146
|
+
export { ACTION_NAMES, AIAgentView_default as AIAgentView, AcceptInvite, AcceptInviteView_default as AcceptInviteView, AdvancedFilterDialog, AdvancedFilterPanel, AudioService, AuthCallback, AuthCallbackView_default as AuthCallbackView, AuthProvider, AuthService, AuthenticatedBottleneckClipsView, AuthenticatedFactoryView, AuthenticatedHelpView, AuthenticatedHomeView, AuthenticatedShiftsView, AuthenticatedTargetsView, AuthenticatedTicketsView, AuthenticatedWorkspaceHealthView, AxelNotificationPopup, AxelOrb, BackButton, BackButtonMinimal, BarChart, BaseHistoryCalendar, BottleneckClipsModal, BottleneckClipsView_default as BottleneckClipsView, BottlenecksContent, BreakNotificationPopup, CachePrefetchStatus, Card2 as Card, CardContent2 as CardContent, CardDescription2 as CardDescription, CardFooter2 as CardFooter, CardHeader2 as CardHeader, CardTitle2 as CardTitle, ClipFilterProvider, CompactWorkspaceHealthCard, CongratulationsOverlay, CroppedHlsVideoPlayer, CroppedVideoPlayer, CycleTimeChart, CycleTimeOverTimeChart, DEFAULT_ANALYTICS_CONFIG, DEFAULT_AUTH_CONFIG, DEFAULT_CONFIG, DEFAULT_DATABASE_CONFIG, DEFAULT_DATE_TIME_CONFIG, DEFAULT_ENDPOINTS_CONFIG, DEFAULT_ENTITY_CONFIG, DEFAULT_MAP_VIEW_CONFIG, DEFAULT_SHIFT_CONFIG, DEFAULT_THEME_CONFIG, DEFAULT_VIDEO_CONFIG, DEFAULT_WORKSPACE_CONFIG, DEFAULT_WORKSPACE_POSITIONS, DashboardHeader, DashboardLayout, DashboardOverridesProvider, DashboardProvider, DateDisplay_default as DateDisplay, DateTimeDisplay, DebugAuth, DebugAuthView_default as DebugAuthView, DetailedHealthStatus, DiagnosisVideoModal, EmptyStateMessage, EncouragementOverlay, FactoryView_default as FactoryView, FileManagerFilters, FilterDialogTrigger, FirstTimeLoginDebug, FirstTimeLoginHandler, GaugeChart, GridComponentsPlaceholder, HamburgerButton, Header, HealthStatusGrid, HealthStatusIndicator, HelpView_default as HelpView, HlsVideoPlayer, HomeView_default as HomeView, HourlyOutputChart2 as HourlyOutputChart, ISTTimer_default as ISTTimer, InlineEditableText, InteractiveOnboardingTour, InvitationService, KPICard, KPIDetailView_default as KPIDetailView, KPIGrid, KPIHeader, KPISection, KPIsOverviewView_default as KPIsOverviewView, LINE_1_UUID, LINE_2_UUID, LargeOutputProgressChart, LeaderboardDetailView_default as LeaderboardDetailView, Legend6 as Legend, LineChart, LineHistoryCalendar, LineMonthlyHistory, LineMonthlyPdfGenerator, LinePdfExportButton, LinePdfGenerator, LineWhatsAppShareButton, LinesService, LiveTimer, LoadingInline, LoadingOverlay_default as LoadingOverlay, LoadingPage_default as LoadingPage, LoadingSkeleton, LoadingState, LoginPage, LoginView_default as LoginView, Logo, MainLayout, MapGridView, MetricCard_default as MetricCard, MinimalOnboardingPopup, NewClipsNotification, NoWorkspaceData, OnboardingDemo, OnboardingTour, OptifyeAgentClient, OptifyeLogoLoader_default as OptifyeLogoLoader, OutputProgressChart, PageHeader, PieChart4 as PieChart, PlayPauseIndicator, PrefetchConfigurationError, PrefetchError, PrefetchEvents, PrefetchStatus, PrefetchTimeoutError, ProfileView_default as ProfileView, RegistryProvider, S3ClipsSupabaseService as S3ClipsService, S3Service, SKUManagementView, SOPComplianceChart, SSEChatClient, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, ShiftDisplay_default as ShiftDisplay, ShiftsView_default as ShiftsView, SideNavBar, SignupWithInvitation, SilentErrorBoundary, SimpleOnboardingPopup, SingleVideoStream_default as SingleVideoStream, Skeleton, SubscriptionManager, SubscriptionManagerProvider, SupabaseProvider, SupervisorDropdown_default as SupervisorDropdown, SupervisorManagementView_default as SupervisorManagementView, SupervisorService, TargetWorkspaceGrid, TargetsView_default as TargetsView, TeamManagementView_default as TeamManagementView, ThreadSidebar, TicketHistory_default as TicketHistory, TicketHistoryService, TicketsView_default as TicketsView, TimeDisplay_default as TimeDisplay, TimePickerDropdown, Timer_default as Timer, TimezoneProvider, TimezoneService, UserManagementService, UserService, VideoCard, VideoGridView, VideoPlayer, VideoPreloader, WORKSPACE_POSITIONS, WhatsAppShareButton, WorkspaceCard, WorkspaceDetailView_default as WorkspaceDetailView, WorkspaceDisplayNameExample, WorkspaceGrid, WorkspaceGridItem, WorkspaceHealthCard, WorkspaceHealthView_default as WorkspaceHealthView, WorkspaceHistoryCalendar, WorkspaceMetricCards, WorkspaceMetricCardsImpl, WorkspaceMonthlyDataFetcher, WorkspaceMonthlyHistory, WorkspaceMonthlyPdfGenerator, WorkspacePdfExportButton, WorkspacePdfGenerator, WorkspaceWhatsAppShareButton, actionService, apiUtils, authCoreService, authOTPService, authRateLimitService, checkRateLimit2 as checkRateLimit, clearAllRateLimits2 as clearAllRateLimits, clearRateLimit2 as clearRateLimit, clearS3VideoCache, clearS3VideoFromCache, clearWorkspaceDisplayNamesCache, cn, createInvitationService, createLinesService, createStreamProxyHandler, createSupabaseClient, createSupervisorService, createThrottledReload, createUserManagementService, createUserService, dashboardService, deleteThread, forceRefreshWorkspaceDisplayNames, formatDateInZone, formatDateTimeInZone, formatISTDate, formatIdleTime, formatRelativeTime, formatTimeInZone, fromUrlFriendlyName, getAllLineDisplayNames, getAllThreadMessages, getAllWorkspaceDisplayNamesAsync, getAnonClient, getBrowserName, getCameraNumber, getCompanyMetricsTableName, getConfigurableShortWorkspaceDisplayName, getConfigurableWorkspaceDisplayName, getConfiguredLineIds, getCoreSessionRecordingProperties, getCoreSessionReplayUrl, getCurrentShift, getCurrentTimeInZone, getDashboardHeaderTimeInZone, getDaysDifferenceInZone, getDefaultCameraStreamUrl, getDefaultLineId, getDefaultTabForWorkspace, getLineDisplayName, getManufacturingInsights, getMetricsTablePrefix, getNextUpdateInterval, getOperationalDate, getS3SignedUrl, getS3VideoSrc, getShortWorkspaceDisplayName, getShortWorkspaceDisplayNameAsync, getStoredWorkspaceMappings, getSubscriptionManager, getThreadMessages, getUserThreads, getUserThreadsPaginated, getWorkspaceDisplayName, getWorkspaceDisplayNameAsync, getWorkspaceDisplayNamesMap, getWorkspaceFromUrl, getWorkspaceNavigationParams, identifyCoreUser, initializeCoreMixpanel, isLegacyConfiguration, isPrefetchError, isSafari, isTransitionPeriod, isUrlPermanentlyFailed, isValidFactoryViewConfiguration, isValidLineInfoPayload, isValidPrefetchParams, isValidPrefetchStatus, isValidWorkspaceDetailedMetricsPayload, isValidWorkspaceMetricsPayload, isWorkspaceDisplayNamesLoaded, isWorkspaceDisplayNamesLoading, linesService, mergeWithDefaultConfig, migrateLegacyConfiguration, optifyeAgentClient, parseS3Uri, preInitializeWorkspaceDisplayNames, preloadS3Video, preloadS3VideoUrl, preloadS3VideosUrl, preloadVideoUrl, preloadVideosUrl, qualityService, realtimeService, refreshWorkspaceDisplayNames, resetCoreMixpanel, resetFailedUrl, resetSubscriptionManager, s3VideoPreloader, shuffleArray, simulateApiDelay, skuService, startCoreSessionRecording, stopCoreSessionRecording, storeWorkspaceMapping, streamProxyConfig, throttledReloadDashboard, toUrlFriendlyName, trackCoreEvent, trackCorePageView, updateThreadTitle, useAccessControl, useActiveBreaks, useActiveLineId, useAllWorkspaceMetrics, useAnalyticsConfig, useAppTimezone, useAudioService, useAuth, useAuthConfig, useAxelNotifications, useCanSaveTargets, useClipFilter, useClipTypes, useClipTypesWithCounts, useComponentOverride, useCustomConfig, useDashboardConfig, useDashboardMetrics, useDatabaseConfig, useDateFormatter, useDateTimeConfig, useDynamicShiftConfig, useEndpointsConfig, useEntityConfig, useFactoryOverviewMetrics, useFeatureFlags, useFormatNumber, useHasLineAccess, useHistoricWorkspaceMetrics, useHlsStream, useHlsStreamWithCropping, useHookOverride, useHourEndTimer, useHourlyTargetAchievements, useHourlyTargetMisses, useLeaderboardMetrics, useLineDetailedMetrics, useLineKPIs, useLineMetrics, useLineShiftConfig, useLineSupervisor, useLineWorkspaceMetrics, useMessages, useMetrics, useNavigation, useOverrides, usePageOverride, usePrefetchClipCounts, useRealtimeLineMetrics, useRegistry, useSKUs, useSessionKeepAlive, useShiftConfig, useShifts, useSubscriptionManager, useSubscriptionManagerSafe, useSupabase, useSupabaseClient, useTargets, useTeamManagementPermissions, useTheme, useThemeConfig, useThreads, useTicketHistory, useTimezoneContext, useUserLineAccess, useVideoConfig, useWorkspaceConfig, useWorkspaceDetailedMetrics, useWorkspaceDisplayName, useWorkspaceDisplayNames, useWorkspaceDisplayNamesMap, useWorkspaceHealthById, useWorkspaceHealthStatus, useWorkspaceMetrics, useWorkspaceNavigation, useWorkspaceOperators, userService, videoPrefetchManager, videoPreloader, whatsappService, withAccessControl, withAuth, withRegistry, withTimezone, workspaceHealthService, workspaceService };
|