@optifye/dashboard-core 6.9.7 → 6.9.9
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 -32
- package/dist/index.d.mts +58 -37
- package/dist/index.d.ts +58 -37
- package/dist/index.js +1095 -1020
- package/dist/index.mjs +1094 -1020
- 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);
|
|
@@ -9576,9 +9574,6 @@ var getAllWorkspaceDisplayNamesAsync = async (companyId, lineId) => {
|
|
|
9576
9574
|
Object.entries(runtimeWorkspaceDisplayNames).forEach(([lineId2, lineNames]) => {
|
|
9577
9575
|
Object.entries(lineNames).forEach(([workspaceId, displayName]) => {
|
|
9578
9576
|
allNames[`${lineId2}_${workspaceId}`] = displayName;
|
|
9579
|
-
if (!allNames[workspaceId]) {
|
|
9580
|
-
allNames[workspaceId] = displayName;
|
|
9581
|
-
}
|
|
9582
9577
|
});
|
|
9583
9578
|
});
|
|
9584
9579
|
return allNames;
|
|
@@ -14057,9 +14052,9 @@ var S3VideoPreloader = class {
|
|
|
14057
14052
|
this.processQueue();
|
|
14058
14053
|
};
|
|
14059
14054
|
if (url.endsWith(".m3u8")) {
|
|
14060
|
-
import('hls.js').then(({ default:
|
|
14061
|
-
if (
|
|
14062
|
-
const hls = new
|
|
14055
|
+
import('hls.js').then(({ default: Hls4 }) => {
|
|
14056
|
+
if (Hls4.isSupported()) {
|
|
14057
|
+
const hls = new Hls4({
|
|
14063
14058
|
maxBufferLength: 10,
|
|
14064
14059
|
startFragPrefetch: true,
|
|
14065
14060
|
lowLatencyMode: false,
|
|
@@ -14071,7 +14066,7 @@ var S3VideoPreloader = class {
|
|
|
14071
14066
|
hls.destroy();
|
|
14072
14067
|
cleanup();
|
|
14073
14068
|
}, 4e3);
|
|
14074
|
-
hls.on(
|
|
14069
|
+
hls.on(Hls4.Events.BUFFER_APPENDED, () => {
|
|
14075
14070
|
window.clearTimeout(timeout);
|
|
14076
14071
|
hls.destroy();
|
|
14077
14072
|
cleanup();
|
|
@@ -23075,7 +23070,7 @@ var OutputProgressChartComponent = ({
|
|
|
23075
23070
|
];
|
|
23076
23071
|
const COLORS = ["#00AB45", "#f3f4f6"];
|
|
23077
23072
|
const percentage = (currentOutput / targetOutput * 100).toFixed(1);
|
|
23078
|
-
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)" }, children: [
|
|
23079
23074
|
/* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsx(PieChart, { children: /* @__PURE__ */ jsx(
|
|
23080
23075
|
Pie,
|
|
23081
23076
|
{
|
|
@@ -24707,7 +24702,8 @@ var VideoGridView = React23__default.memo(({
|
|
|
24707
24702
|
displayName: (
|
|
24708
24703
|
// Create line-aware lookup key: lineId_workspaceName
|
|
24709
24704
|
// This ensures correct mapping when multiple lines have same workspace names
|
|
24710
|
-
displayNames[`${workspace.line_id}_${workspace.workspace_name}`] ||
|
|
24705
|
+
displayNames[`${workspace.line_id}_${workspace.workspace_name}`] || // Always pass line_id to fallback to ensure correct mapping per line
|
|
24706
|
+
getWorkspaceDisplayName(workspace.workspace_name, workspace.line_id)
|
|
24711
24707
|
),
|
|
24712
24708
|
useRAF: canvasConfig?.useRAF,
|
|
24713
24709
|
compact: !selectedLine,
|
|
@@ -24757,7 +24753,8 @@ var MapGridView = React23__default.memo(({
|
|
|
24757
24753
|
efficiency: workspace.efficiency,
|
|
24758
24754
|
action_count: workspace.action_count
|
|
24759
24755
|
});
|
|
24760
|
-
const displayName = displayNames[`${workspace.line_id}_${workspace.workspace_name}`] ||
|
|
24756
|
+
const displayName = displayNames[`${workspace.line_id}_${workspace.workspace_name}`] || // Always pass line_id to fallback to ensure correct mapping per line
|
|
24757
|
+
getWorkspaceDisplayName(workspace.workspace_name, workspace.line_id);
|
|
24761
24758
|
const navParams = getWorkspaceNavigationParams(workspaceId, displayName, workspace.line_id);
|
|
24762
24759
|
router.push(`/workspace/${workspaceId}${navParams}`);
|
|
24763
24760
|
}, [router, displayNames]);
|
|
@@ -24786,7 +24783,8 @@ var MapGridView = React23__default.memo(({
|
|
|
24786
24783
|
if (!workspace) return null;
|
|
24787
24784
|
const workspaceId = workspace.workspace_uuid || workspace.workspace_name;
|
|
24788
24785
|
getPerformanceColor(workspace.efficiency);
|
|
24789
|
-
const workspaceDisplayName = displayNames[`${workspace.line_id}_${workspace.workspace_name}`] ||
|
|
24786
|
+
const workspaceDisplayName = displayNames[`${workspace.line_id}_${workspace.workspace_name}`] || // Always pass line_id to fallback to ensure correct mapping per line
|
|
24787
|
+
getWorkspaceDisplayName(workspace.workspace_name, workspace.line_id);
|
|
24790
24788
|
return /* @__PURE__ */ jsx(
|
|
24791
24789
|
motion.div,
|
|
24792
24790
|
{
|
|
@@ -26024,12 +26022,6 @@ var AxelNotificationPopup = ({
|
|
|
26024
26022
|
};
|
|
26025
26023
|
|
|
26026
26024
|
// 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
26025
|
var getSeverityColor = (severity) => {
|
|
26034
26026
|
switch (severity) {
|
|
26035
26027
|
case "low":
|
|
@@ -26042,473 +26034,6 @@ var getSeverityColor = (severity) => {
|
|
|
26042
26034
|
return "bg-gray-500";
|
|
26043
26035
|
}
|
|
26044
26036
|
};
|
|
26045
|
-
function Skeleton({ className, ...props }) {
|
|
26046
|
-
return /* @__PURE__ */ jsx("div", { className: cn("animate-pulse rounded-md bg-muted", className), ...props });
|
|
26047
|
-
}
|
|
26048
|
-
var Select = SelectPrimitive.Root;
|
|
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
|
|
26153
|
-
}) => {
|
|
26154
|
-
if (!isVisible) return null;
|
|
26155
|
-
return /* @__PURE__ */ jsx(
|
|
26156
|
-
motion.div,
|
|
26157
|
-
{
|
|
26158
|
-
initial: { opacity: 0 },
|
|
26159
|
-
animate: { opacity: 1 },
|
|
26160
|
-
exit: { opacity: 0 },
|
|
26161
|
-
transition: { duration: 0.2 },
|
|
26162
|
-
className: `fixed inset-0 z-[100] flex items-center justify-center bg-black/30 backdrop-blur-sm ${className || ""}`,
|
|
26163
|
-
"aria-modal": "true",
|
|
26164
|
-
role: "dialog",
|
|
26165
|
-
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 }) })
|
|
26166
|
-
}
|
|
26167
|
-
);
|
|
26168
|
-
};
|
|
26169
|
-
var LoadingOverlay_default = LoadingOverlay;
|
|
26170
|
-
var TimeDisplay = ({ className, variant = "default" }) => {
|
|
26171
|
-
const { dateTimeConfig } = useDashboardConfig();
|
|
26172
|
-
const [time2, setTime] = useState("");
|
|
26173
|
-
const dbTimezone = useAppTimezone();
|
|
26174
|
-
const timezoneToDisplay = dbTimezone || dateTimeConfig?.defaultTimezone || "UTC";
|
|
26175
|
-
const localeToUse = dateTimeConfig?.defaultLocale || "en-US";
|
|
26176
|
-
const timeSuffix = "";
|
|
26177
|
-
useEffect(() => {
|
|
26178
|
-
const updateTime = () => {
|
|
26179
|
-
const now2 = /* @__PURE__ */ new Date();
|
|
26180
|
-
const effectiveFormatOptions = {
|
|
26181
|
-
hour: "2-digit",
|
|
26182
|
-
minute: "2-digit",
|
|
26183
|
-
second: "2-digit",
|
|
26184
|
-
hour12: true,
|
|
26185
|
-
timeZone: timezoneToDisplay,
|
|
26186
|
-
...dateTimeConfig?.timeFormatOptions || {}
|
|
26187
|
-
// Allow override from config
|
|
26188
|
-
};
|
|
26189
|
-
try {
|
|
26190
|
-
setTime(new Intl.DateTimeFormat(localeToUse, effectiveFormatOptions).format(now2));
|
|
26191
|
-
} catch (e) {
|
|
26192
|
-
console.error("Error formatting time:", e);
|
|
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
|
-
] });
|
|
26207
|
-
}
|
|
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
|
-
};
|
|
26226
|
-
var TimeDisplay_default = TimeDisplay;
|
|
26227
|
-
var DateDisplay = ({ className, variant = "default" }) => {
|
|
26228
|
-
const { dateTimeConfig } = useDashboardConfig();
|
|
26229
|
-
const [date, setDate] = useState("");
|
|
26230
|
-
const timezoneToDisplay = dateTimeConfig?.defaultTimezone || "UTC";
|
|
26231
|
-
const localeToUse = dateTimeConfig?.defaultLocale || "en-US";
|
|
26232
|
-
useEffect(() => {
|
|
26233
|
-
const getCurrentFormattedDate = () => {
|
|
26234
|
-
const now2 = /* @__PURE__ */ new Date();
|
|
26235
|
-
const effectiveFormatOptions = {
|
|
26236
|
-
weekday: "short",
|
|
26237
|
-
day: "numeric",
|
|
26238
|
-
month: "short",
|
|
26239
|
-
timeZone: timezoneToDisplay,
|
|
26240
|
-
...dateTimeConfig?.dateFormatOptions || {}
|
|
26241
|
-
// Allow override from config
|
|
26242
|
-
};
|
|
26243
|
-
try {
|
|
26244
|
-
return new Intl.DateTimeFormat(localeToUse, effectiveFormatOptions).format(now2);
|
|
26245
|
-
} catch (e) {
|
|
26246
|
-
console.error("Error formatting date:", e);
|
|
26247
|
-
return "Error";
|
|
26248
|
-
}
|
|
26249
|
-
};
|
|
26250
|
-
const updateDate = () => {
|
|
26251
|
-
setDate(getCurrentFormattedDate());
|
|
26252
|
-
};
|
|
26253
|
-
updateDate();
|
|
26254
|
-
const interval = setInterval(() => {
|
|
26255
|
-
const currentDateStr = getCurrentFormattedDate();
|
|
26256
|
-
if (currentDateStr !== date) {
|
|
26257
|
-
updateDate();
|
|
26258
|
-
}
|
|
26259
|
-
}, 60 * 1e3);
|
|
26260
|
-
return () => clearInterval(interval);
|
|
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
|
-
]
|
|
26277
|
-
}
|
|
26278
|
-
);
|
|
26279
|
-
};
|
|
26280
|
-
var DateDisplay_default = DateDisplay;
|
|
26281
|
-
var Card3 = Card2;
|
|
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("");
|
|
26351
|
-
}
|
|
26352
|
-
};
|
|
26353
|
-
document.addEventListener("mousedown", handleClickOutside);
|
|
26354
|
-
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
26355
|
-
}, []);
|
|
26356
|
-
const handleKeyDown = (e) => {
|
|
26357
|
-
if (e.key === "Escape") {
|
|
26358
|
-
setIsOpen(false);
|
|
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";
|
|
26454
|
-
};
|
|
26455
|
-
this.state = {
|
|
26456
|
-
hasError: false,
|
|
26457
|
-
errorCount: 0,
|
|
26458
|
-
lastError: null,
|
|
26459
|
-
errorInfo: null
|
|
26460
|
-
};
|
|
26461
|
-
}
|
|
26462
|
-
static getDerivedStateFromError(error) {
|
|
26463
|
-
return { hasError: true };
|
|
26464
|
-
}
|
|
26465
|
-
componentDidCatch(error, errorInfo) {
|
|
26466
|
-
console.error("[ErrorBoundary] Caught render error:", {
|
|
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
26037
|
var PlayPauseIndicator = ({
|
|
26513
26038
|
show,
|
|
26514
26039
|
isPlaying,
|
|
@@ -26571,37 +26096,33 @@ var PlayPauseIndicator = ({
|
|
|
26571
26096
|
);
|
|
26572
26097
|
};
|
|
26573
26098
|
var ERROR_MAPPING = {
|
|
26574
|
-
|
|
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
|
|
26099
|
+
"networkError": {
|
|
26583
26100
|
code: 2,
|
|
26584
|
-
type: "recoverable"
|
|
26101
|
+
type: "recoverable",
|
|
26585
26102
|
message: "Network error - please check your internet connection",
|
|
26586
26103
|
canRetry: true
|
|
26587
26104
|
},
|
|
26588
|
-
|
|
26589
|
-
// MEDIA_ERR_DECODE
|
|
26105
|
+
"mediaError": {
|
|
26590
26106
|
code: 3,
|
|
26591
|
-
type: "non_recoverable"
|
|
26107
|
+
type: "non_recoverable",
|
|
26592
26108
|
message: "Stream corrupted due to internet connection",
|
|
26593
26109
|
canRetry: false
|
|
26594
26110
|
},
|
|
26595
|
-
|
|
26596
|
-
|
|
26111
|
+
"muxError": {
|
|
26112
|
+
code: 3,
|
|
26113
|
+
type: "non_recoverable",
|
|
26114
|
+
message: "Error processing media stream",
|
|
26115
|
+
canRetry: false
|
|
26116
|
+
},
|
|
26117
|
+
"otherError": {
|
|
26597
26118
|
code: 4,
|
|
26598
|
-
type: "non_recoverable"
|
|
26119
|
+
type: "non_recoverable",
|
|
26599
26120
|
message: "Video format not supported by your browser. Please use Google Chrome.",
|
|
26600
26121
|
canRetry: false
|
|
26601
26122
|
}
|
|
26602
26123
|
};
|
|
26603
|
-
var
|
|
26604
|
-
.video-player-container {
|
|
26124
|
+
var hlsVideoPlayerStyles = `
|
|
26125
|
+
.hls-video-player-container {
|
|
26605
26126
|
width: 100%;
|
|
26606
26127
|
height: 100%;
|
|
26607
26128
|
background-color: #000;
|
|
@@ -26609,32 +26130,18 @@ var videoPlayerStyles = `
|
|
|
26609
26130
|
align-items: center;
|
|
26610
26131
|
justify-content: center;
|
|
26611
26132
|
}
|
|
26612
|
-
|
|
26613
|
-
/* Center the video
|
|
26614
|
-
.video-
|
|
26133
|
+
|
|
26134
|
+
/* Center the video and maintain aspect ratio */
|
|
26135
|
+
.hls-video-element {
|
|
26615
26136
|
width: 100%;
|
|
26616
26137
|
height: 100%;
|
|
26617
26138
|
max-width: 100%;
|
|
26618
26139
|
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
26140
|
object-fit: contain;
|
|
26629
26141
|
}
|
|
26630
|
-
|
|
26631
|
-
/* Hide default Video.js loading spinner */
|
|
26632
|
-
.video-js .vjs-loading-spinner {
|
|
26633
|
-
display: none !important;
|
|
26634
|
-
}
|
|
26635
|
-
|
|
26142
|
+
|
|
26636
26143
|
/* Custom loading indicator styles */
|
|
26637
|
-
.video-player-loading {
|
|
26144
|
+
.hls-video-player-loading {
|
|
26638
26145
|
position: absolute;
|
|
26639
26146
|
top: 50%;
|
|
26640
26147
|
left: 50%;
|
|
@@ -26643,15 +26150,41 @@ var videoPlayerStyles = `
|
|
|
26643
26150
|
}
|
|
26644
26151
|
`;
|
|
26645
26152
|
if (typeof document !== "undefined") {
|
|
26646
|
-
const styleId = "video-player-custom-styles";
|
|
26153
|
+
const styleId = "hls-video-player-custom-styles";
|
|
26647
26154
|
if (!document.getElementById(styleId)) {
|
|
26648
26155
|
const style = document.createElement("style");
|
|
26649
26156
|
style.id = styleId;
|
|
26650
|
-
style.textContent =
|
|
26157
|
+
style.textContent = hlsVideoPlayerStyles;
|
|
26651
26158
|
document.head.appendChild(style);
|
|
26652
26159
|
}
|
|
26653
26160
|
}
|
|
26654
|
-
var
|
|
26161
|
+
var BASE_HLS_CONFIG = {
|
|
26162
|
+
maxBufferLength: 3,
|
|
26163
|
+
maxMaxBufferLength: 8,
|
|
26164
|
+
maxBufferSize: 50 * 1e3 * 1e3,
|
|
26165
|
+
maxBufferHole: 0.25,
|
|
26166
|
+
manifestLoadingTimeOut: 15e3,
|
|
26167
|
+
manifestLoadingMaxRetry: 3,
|
|
26168
|
+
manifestLoadingRetryDelay: 500,
|
|
26169
|
+
levelLoadingTimeOut: 6e4,
|
|
26170
|
+
levelLoadingMaxRetry: 5,
|
|
26171
|
+
levelLoadingRetryDelay: 500,
|
|
26172
|
+
fragLoadingTimeOut: 6e4,
|
|
26173
|
+
fragLoadingMaxRetry: 5,
|
|
26174
|
+
fragLoadingRetryDelay: 500,
|
|
26175
|
+
startPosition: -1,
|
|
26176
|
+
debug: false,
|
|
26177
|
+
enableWorker: true,
|
|
26178
|
+
lowLatencyMode: false,
|
|
26179
|
+
progressive: true,
|
|
26180
|
+
abrEwmaSlowLive: 9,
|
|
26181
|
+
abrEwmaFastLive: 3,
|
|
26182
|
+
abrBandWidthFactor: 0.95,
|
|
26183
|
+
abrBandWidthUpFactor: 0.7,
|
|
26184
|
+
abrMaxWithRealBitrate: false,
|
|
26185
|
+
abrEwmaDefaultEstimate: 5e7
|
|
26186
|
+
};
|
|
26187
|
+
var HlsVideoPlayer = forwardRef(({
|
|
26655
26188
|
src,
|
|
26656
26189
|
poster,
|
|
26657
26190
|
autoplay = false,
|
|
@@ -26660,7 +26193,9 @@ var VideoPlayer = React23__default.forwardRef(({
|
|
|
26660
26193
|
muted = false,
|
|
26661
26194
|
playsInline = true,
|
|
26662
26195
|
className = "",
|
|
26196
|
+
hlsConfig = {},
|
|
26663
26197
|
options = {},
|
|
26198
|
+
// Backward compatibility with Video.js
|
|
26664
26199
|
externalLoadingControl = false,
|
|
26665
26200
|
onLoadingChange,
|
|
26666
26201
|
onReady,
|
|
@@ -26678,321 +26213,396 @@ var VideoPlayer = React23__default.forwardRef(({
|
|
|
26678
26213
|
onSeeked,
|
|
26679
26214
|
onClick
|
|
26680
26215
|
}, ref) => {
|
|
26216
|
+
const videoContainerRef = useRef(null);
|
|
26681
26217
|
const videoRef = useRef(null);
|
|
26682
|
-
const
|
|
26218
|
+
const hlsRef = useRef(null);
|
|
26219
|
+
const blobUrlRef = useRef(null);
|
|
26683
26220
|
const [isReady, setIsReady] = useState(false);
|
|
26684
26221
|
const [isLoading, setIsLoading] = useState(true);
|
|
26685
26222
|
const [showIndicator, setShowIndicator] = useState(false);
|
|
26686
26223
|
const [indicatorIsPlaying, setIndicatorIsPlaying] = useState(false);
|
|
26687
26224
|
const indicatorKeyRef = useRef(0);
|
|
26688
|
-
const
|
|
26689
|
-
|
|
26690
|
-
|
|
26691
|
-
|
|
26692
|
-
|
|
26693
|
-
|
|
26694
|
-
|
|
26695
|
-
|
|
26696
|
-
|
|
26697
|
-
|
|
26698
|
-
|
|
26699
|
-
|
|
26700
|
-
|
|
26701
|
-
|
|
26702
|
-
|
|
26703
|
-
|
|
26704
|
-
|
|
26705
|
-
|
|
26706
|
-
|
|
26707
|
-
|
|
26708
|
-
|
|
26709
|
-
|
|
26710
|
-
|
|
26711
|
-
|
|
26712
|
-
|
|
26713
|
-
|
|
26714
|
-
|
|
26715
|
-
|
|
26716
|
-
|
|
26717
|
-
|
|
26718
|
-
|
|
26719
|
-
|
|
26720
|
-
|
|
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", () => {
|
|
26816
|
-
setIsLoading(true);
|
|
26817
|
-
onLoadingChange?.(true);
|
|
26818
|
-
onLoadStart?.(player);
|
|
26819
|
-
});
|
|
26820
|
-
player.on("loadeddata", () => {
|
|
26821
|
-
setIsLoading(false);
|
|
26822
|
-
onLoadingChange?.(false);
|
|
26823
|
-
onLoadedData?.(player);
|
|
26824
|
-
});
|
|
26825
|
-
player.on("waiting", () => {
|
|
26826
|
-
setIsLoading(true);
|
|
26827
|
-
onLoadingChange?.(true);
|
|
26828
|
-
});
|
|
26829
|
-
player.on("playing", () => {
|
|
26830
|
-
setIsLoading(false);
|
|
26831
|
-
onLoadingChange?.(false);
|
|
26832
|
-
});
|
|
26833
|
-
player.on("loadedmetadata", () => {
|
|
26834
|
-
onLoadedMetadata?.(player);
|
|
26835
|
-
});
|
|
26836
|
-
player.on("seeking", () => onSeeking?.(player));
|
|
26837
|
-
player.on("seeked", () => onSeeked?.(player));
|
|
26838
|
-
player.on("error", () => {
|
|
26839
|
-
const error = player.error();
|
|
26840
|
-
const errorCode = error?.code ?? 0;
|
|
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
|
-
}
|
|
26882
|
-
}
|
|
26883
|
-
player.src({
|
|
26884
|
-
src: videoSrc,
|
|
26885
|
-
type: isHLS ? "application/x-mpegURL" : "video/mp4"
|
|
26886
|
-
});
|
|
26887
|
-
}
|
|
26225
|
+
const eventCallbacksRef = useRef({
|
|
26226
|
+
onReady,
|
|
26227
|
+
onPlay,
|
|
26228
|
+
onPause,
|
|
26229
|
+
onPlaying,
|
|
26230
|
+
onTimeUpdate,
|
|
26231
|
+
onDurationChange,
|
|
26232
|
+
onEnded,
|
|
26233
|
+
onError,
|
|
26234
|
+
onLoadStart,
|
|
26235
|
+
onLoadedMetadata,
|
|
26236
|
+
onLoadedData,
|
|
26237
|
+
onSeeking,
|
|
26238
|
+
onSeeked,
|
|
26239
|
+
onLoadingChange
|
|
26240
|
+
});
|
|
26241
|
+
useEffect(() => {
|
|
26242
|
+
eventCallbacksRef.current = {
|
|
26243
|
+
onReady,
|
|
26244
|
+
onPlay,
|
|
26245
|
+
onPause,
|
|
26246
|
+
onPlaying,
|
|
26247
|
+
onTimeUpdate,
|
|
26248
|
+
onDurationChange,
|
|
26249
|
+
onEnded,
|
|
26250
|
+
onError,
|
|
26251
|
+
onLoadStart,
|
|
26252
|
+
onLoadedMetadata,
|
|
26253
|
+
onLoadedData,
|
|
26254
|
+
onSeeking,
|
|
26255
|
+
onSeeked,
|
|
26256
|
+
onLoadingChange
|
|
26257
|
+
};
|
|
26888
26258
|
}, [
|
|
26889
|
-
src,
|
|
26890
|
-
defaultOptions,
|
|
26891
26259
|
onReady,
|
|
26892
26260
|
onPlay,
|
|
26893
26261
|
onPause,
|
|
26262
|
+
onPlaying,
|
|
26894
26263
|
onTimeUpdate,
|
|
26895
26264
|
onDurationChange,
|
|
26896
26265
|
onEnded,
|
|
26897
26266
|
onError,
|
|
26898
26267
|
onLoadStart,
|
|
26899
26268
|
onLoadedMetadata,
|
|
26269
|
+
onLoadedData,
|
|
26900
26270
|
onSeeking,
|
|
26901
|
-
onSeeked
|
|
26271
|
+
onSeeked,
|
|
26272
|
+
onLoadingChange
|
|
26902
26273
|
]);
|
|
26274
|
+
const stableHlsConfigRef = useRef(hlsConfig);
|
|
26275
|
+
const stableOptionsRef = useRef(options);
|
|
26276
|
+
const configSignatureRef = useRef("");
|
|
26277
|
+
const [configVersion, setConfigVersion] = useState(0);
|
|
26903
26278
|
useEffect(() => {
|
|
26904
|
-
|
|
26905
|
-
|
|
26906
|
-
|
|
26907
|
-
|
|
26279
|
+
const serialized = JSON.stringify({
|
|
26280
|
+
hlsConfig: hlsConfig || null,
|
|
26281
|
+
options: options || null
|
|
26282
|
+
});
|
|
26283
|
+
if (!configSignatureRef.current) {
|
|
26284
|
+
configSignatureRef.current = serialized;
|
|
26285
|
+
stableHlsConfigRef.current = hlsConfig;
|
|
26286
|
+
stableOptionsRef.current = options;
|
|
26287
|
+
return;
|
|
26288
|
+
}
|
|
26289
|
+
if (configSignatureRef.current !== serialized) {
|
|
26290
|
+
configSignatureRef.current = serialized;
|
|
26291
|
+
stableHlsConfigRef.current = hlsConfig;
|
|
26292
|
+
stableOptionsRef.current = options;
|
|
26293
|
+
setConfigVersion((prev) => prev + 1);
|
|
26294
|
+
}
|
|
26295
|
+
}, [hlsConfig, options]);
|
|
26296
|
+
const cleanupBlobUrl = useCallback(() => {
|
|
26297
|
+
if (blobUrlRef.current) {
|
|
26298
|
+
URL.revokeObjectURL(blobUrlRef.current);
|
|
26299
|
+
blobUrlRef.current = null;
|
|
26300
|
+
}
|
|
26301
|
+
}, []);
|
|
26302
|
+
const dispose = useCallback(() => {
|
|
26303
|
+
if (hlsRef.current) {
|
|
26304
|
+
hlsRef.current.destroy();
|
|
26305
|
+
hlsRef.current = null;
|
|
26306
|
+
}
|
|
26307
|
+
cleanupBlobUrl();
|
|
26308
|
+
setIsReady(false);
|
|
26309
|
+
}, [cleanupBlobUrl]);
|
|
26310
|
+
const playerLikeObject = useCallback(() => {
|
|
26311
|
+
return {
|
|
26312
|
+
el: () => videoRef.current,
|
|
26313
|
+
currentTime: () => videoRef.current?.currentTime || 0,
|
|
26314
|
+
duration: () => videoRef.current?.duration || 0,
|
|
26315
|
+
paused: () => videoRef.current?.paused ?? true,
|
|
26316
|
+
play: () => videoRef.current?.play(),
|
|
26317
|
+
pause: () => videoRef.current?.pause(),
|
|
26318
|
+
muted: (val) => {
|
|
26319
|
+
if (videoRef.current) {
|
|
26320
|
+
if (val !== void 0) videoRef.current.muted = val;
|
|
26321
|
+
return videoRef.current.muted;
|
|
26322
|
+
}
|
|
26323
|
+
return false;
|
|
26324
|
+
},
|
|
26325
|
+
volume: (val) => {
|
|
26326
|
+
if (videoRef.current) {
|
|
26327
|
+
if (val !== void 0) videoRef.current.volume = val;
|
|
26328
|
+
return videoRef.current.volume;
|
|
26329
|
+
}
|
|
26330
|
+
return 1;
|
|
26331
|
+
},
|
|
26332
|
+
error: () => null,
|
|
26333
|
+
dispose: () => dispose()
|
|
26334
|
+
};
|
|
26335
|
+
}, [dispose]);
|
|
26336
|
+
const initializePlayer = useCallback(() => {
|
|
26337
|
+
if (!videoRef.current || !src) return;
|
|
26338
|
+
const video = videoRef.current;
|
|
26339
|
+
const player = playerLikeObject();
|
|
26340
|
+
const mergedHlsConfig = {
|
|
26341
|
+
...BASE_HLS_CONFIG,
|
|
26342
|
+
...stableHlsConfigRef.current || {},
|
|
26343
|
+
...stableOptionsRef.current || {}
|
|
26344
|
+
};
|
|
26345
|
+
cleanupBlobUrl();
|
|
26346
|
+
const isHLS = src.endsWith(".m3u8") || src.startsWith("#EXTM3U");
|
|
26347
|
+
if (isHLS) {
|
|
26908
26348
|
if (src.startsWith("#EXTM3U")) {
|
|
26909
26349
|
const safariMode = isSafari();
|
|
26910
26350
|
const browserName = getBrowserName();
|
|
26911
26351
|
if (safariMode) {
|
|
26912
26352
|
const clipIdMatch = src.match(/# Clip ID: ([a-f0-9-]+)/i);
|
|
26913
26353
|
if (clipIdMatch) {
|
|
26914
|
-
|
|
26915
|
-
console.log(`[
|
|
26354
|
+
const proxyUrl = `/api/clips/playlist/${clipIdMatch[1]}`;
|
|
26355
|
+
console.log(`[HlsVideoPlayer] Safari detected (${browserName}) - using playlist proxy URL:`, proxyUrl);
|
|
26356
|
+
video.src = proxyUrl;
|
|
26916
26357
|
} else {
|
|
26917
|
-
console.warn("[
|
|
26358
|
+
console.warn("[HlsVideoPlayer] Safari detected but no clip ID found in playlist, trying blob URL fallback");
|
|
26918
26359
|
const blob = new Blob([src], { type: "application/vnd.apple.mpegurl" });
|
|
26919
|
-
blobUrl = URL.createObjectURL(blob);
|
|
26920
|
-
|
|
26360
|
+
const blobUrl = URL.createObjectURL(blob);
|
|
26361
|
+
blobUrlRef.current = blobUrl;
|
|
26362
|
+
video.src = blobUrl;
|
|
26921
26363
|
}
|
|
26922
|
-
} else {
|
|
26364
|
+
} else if (Hls3.isSupported()) {
|
|
26923
26365
|
const blob = new Blob([src], { type: "application/vnd.apple.mpegurl" });
|
|
26924
|
-
blobUrl = URL.createObjectURL(blob);
|
|
26925
|
-
|
|
26926
|
-
console.log(`[
|
|
26366
|
+
const blobUrl = URL.createObjectURL(blob);
|
|
26367
|
+
blobUrlRef.current = blobUrl;
|
|
26368
|
+
console.log(`[HlsVideoPlayer] Non-Safari browser (${browserName}) - using HLS.js with blob URL`);
|
|
26369
|
+
const hls = new Hls3(mergedHlsConfig);
|
|
26370
|
+
hlsRef.current = hls;
|
|
26371
|
+
hls.on(Events.MANIFEST_PARSED, () => {
|
|
26372
|
+
console.log("[HlsVideoPlayer] Manifest parsed, ready to play");
|
|
26373
|
+
setIsReady(true);
|
|
26374
|
+
eventCallbacksRef.current.onReady?.(player);
|
|
26375
|
+
});
|
|
26376
|
+
hls.on(Events.ERROR, (event, data) => {
|
|
26377
|
+
console.error("[HlsVideoPlayer] HLS.js error:", data);
|
|
26378
|
+
if (data.fatal) {
|
|
26379
|
+
let errorInfo;
|
|
26380
|
+
switch (data.type) {
|
|
26381
|
+
case ErrorTypes.NETWORK_ERROR:
|
|
26382
|
+
errorInfo = ERROR_MAPPING.networkError;
|
|
26383
|
+
console.log("[HlsVideoPlayer] Attempting to recover from network error");
|
|
26384
|
+
hls.startLoad();
|
|
26385
|
+
break;
|
|
26386
|
+
case ErrorTypes.MEDIA_ERROR:
|
|
26387
|
+
errorInfo = ERROR_MAPPING.mediaError;
|
|
26388
|
+
console.log("[HlsVideoPlayer] Attempting to recover from media error");
|
|
26389
|
+
hls.recoverMediaError();
|
|
26390
|
+
break;
|
|
26391
|
+
case ErrorTypes.MUX_ERROR:
|
|
26392
|
+
errorInfo = ERROR_MAPPING.muxError;
|
|
26393
|
+
break;
|
|
26394
|
+
default:
|
|
26395
|
+
errorInfo = ERROR_MAPPING.otherError;
|
|
26396
|
+
break;
|
|
26397
|
+
}
|
|
26398
|
+
errorInfo.details = data.details;
|
|
26399
|
+
eventCallbacksRef.current.onError?.(player, errorInfo);
|
|
26400
|
+
}
|
|
26401
|
+
});
|
|
26402
|
+
hls.on(Events.FRAG_LOADING, () => {
|
|
26403
|
+
setIsLoading(true);
|
|
26404
|
+
eventCallbacksRef.current.onLoadingChange?.(true);
|
|
26405
|
+
});
|
|
26406
|
+
hls.on(Events.FRAG_LOADED, () => {
|
|
26407
|
+
setIsLoading(false);
|
|
26408
|
+
eventCallbacksRef.current.onLoadingChange?.(false);
|
|
26409
|
+
});
|
|
26410
|
+
hls.loadSource(blobUrl);
|
|
26411
|
+
hls.attachMedia(video);
|
|
26412
|
+
} else {
|
|
26413
|
+
console.error("[HlsVideoPlayer] HLS.js not supported and not Safari - cannot play HLS content");
|
|
26414
|
+
const errorInfo = ERROR_MAPPING.otherError;
|
|
26415
|
+
onError?.(player, errorInfo);
|
|
26927
26416
|
}
|
|
26928
|
-
}
|
|
26929
|
-
|
|
26930
|
-
|
|
26931
|
-
|
|
26932
|
-
|
|
26933
|
-
|
|
26934
|
-
|
|
26935
|
-
|
|
26417
|
+
} else {
|
|
26418
|
+
if (Hls3.isSupported() && !isSafari()) {
|
|
26419
|
+
const hls = new Hls3(mergedHlsConfig);
|
|
26420
|
+
hlsRef.current = hls;
|
|
26421
|
+
hls.on(Events.MANIFEST_PARSED, () => {
|
|
26422
|
+
setIsReady(true);
|
|
26423
|
+
eventCallbacksRef.current.onReady?.(player);
|
|
26424
|
+
});
|
|
26425
|
+
hls.on(Events.ERROR, (event, data) => {
|
|
26426
|
+
console.error("[HlsVideoPlayer] HLS.js error:", data);
|
|
26427
|
+
if (data.fatal) {
|
|
26428
|
+
let errorInfo;
|
|
26429
|
+
switch (data.type) {
|
|
26430
|
+
case ErrorTypes.NETWORK_ERROR:
|
|
26431
|
+
errorInfo = ERROR_MAPPING.networkError;
|
|
26432
|
+
hls.startLoad();
|
|
26433
|
+
break;
|
|
26434
|
+
case ErrorTypes.MEDIA_ERROR:
|
|
26435
|
+
errorInfo = ERROR_MAPPING.mediaError;
|
|
26436
|
+
hls.recoverMediaError();
|
|
26437
|
+
break;
|
|
26438
|
+
default:
|
|
26439
|
+
errorInfo = ERROR_MAPPING.otherError;
|
|
26440
|
+
break;
|
|
26441
|
+
}
|
|
26442
|
+
errorInfo.details = data.details;
|
|
26443
|
+
eventCallbacksRef.current.onError?.(player, errorInfo);
|
|
26444
|
+
}
|
|
26445
|
+
});
|
|
26446
|
+
hls.loadSource(src);
|
|
26447
|
+
hls.attachMedia(video);
|
|
26448
|
+
} else {
|
|
26449
|
+
video.src = src;
|
|
26936
26450
|
}
|
|
26937
|
-
}
|
|
26451
|
+
}
|
|
26452
|
+
} else {
|
|
26453
|
+
video.src = src;
|
|
26938
26454
|
}
|
|
26939
|
-
|
|
26455
|
+
const handleCanPlay = () => {
|
|
26456
|
+
if (!hlsRef.current) {
|
|
26457
|
+
setIsReady(true);
|
|
26458
|
+
onReady?.(player);
|
|
26459
|
+
}
|
|
26460
|
+
};
|
|
26461
|
+
const handlePlay = () => eventCallbacksRef.current.onPlay?.(player);
|
|
26462
|
+
const handlePause = () => eventCallbacksRef.current.onPause?.(player);
|
|
26463
|
+
const handlePlaying = () => {
|
|
26464
|
+
setIsLoading(false);
|
|
26465
|
+
eventCallbacksRef.current.onLoadingChange?.(false);
|
|
26466
|
+
eventCallbacksRef.current.onPlaying?.(player);
|
|
26467
|
+
};
|
|
26468
|
+
const handleTimeUpdate = () => {
|
|
26469
|
+
const currentTime2 = video.currentTime || 0;
|
|
26470
|
+
eventCallbacksRef.current.onTimeUpdate?.(player, currentTime2);
|
|
26471
|
+
};
|
|
26472
|
+
const handleDurationChange = () => {
|
|
26473
|
+
const duration2 = video.duration || 0;
|
|
26474
|
+
eventCallbacksRef.current.onDurationChange?.(player, duration2);
|
|
26475
|
+
};
|
|
26476
|
+
const handleEnded = () => eventCallbacksRef.current.onEnded?.(player);
|
|
26477
|
+
const handleLoadStart = () => {
|
|
26478
|
+
setIsLoading(true);
|
|
26479
|
+
eventCallbacksRef.current.onLoadingChange?.(true);
|
|
26480
|
+
eventCallbacksRef.current.onLoadStart?.(player);
|
|
26481
|
+
};
|
|
26482
|
+
const handleLoadedMetadata = () => eventCallbacksRef.current.onLoadedMetadata?.(player);
|
|
26483
|
+
const handleLoadedData = () => {
|
|
26484
|
+
setIsLoading(false);
|
|
26485
|
+
eventCallbacksRef.current.onLoadingChange?.(false);
|
|
26486
|
+
eventCallbacksRef.current.onLoadedData?.(player);
|
|
26487
|
+
};
|
|
26488
|
+
const handleWaiting = () => {
|
|
26489
|
+
setIsLoading(true);
|
|
26490
|
+
eventCallbacksRef.current.onLoadingChange?.(true);
|
|
26491
|
+
};
|
|
26492
|
+
const handleSeeking = () => eventCallbacksRef.current.onSeeking?.(player);
|
|
26493
|
+
const handleSeeked = () => eventCallbacksRef.current.onSeeked?.(player);
|
|
26494
|
+
const handleError = () => {
|
|
26495
|
+
const error = video.error;
|
|
26496
|
+
if (error) {
|
|
26497
|
+
const errorInfo = {
|
|
26498
|
+
code: error.code,
|
|
26499
|
+
type: error.code <= 2 ? "recoverable" : "non_recoverable",
|
|
26500
|
+
message: error.message || "Unknown error occurred",
|
|
26501
|
+
canRetry: error.code <= 2
|
|
26502
|
+
};
|
|
26503
|
+
eventCallbacksRef.current.onError?.(player, errorInfo);
|
|
26504
|
+
}
|
|
26505
|
+
};
|
|
26506
|
+
video.addEventListener("canplay", handleCanPlay);
|
|
26507
|
+
video.addEventListener("play", handlePlay);
|
|
26508
|
+
video.addEventListener("pause", handlePause);
|
|
26509
|
+
video.addEventListener("playing", handlePlaying);
|
|
26510
|
+
video.addEventListener("timeupdate", handleTimeUpdate);
|
|
26511
|
+
video.addEventListener("durationchange", handleDurationChange);
|
|
26512
|
+
video.addEventListener("ended", handleEnded);
|
|
26513
|
+
video.addEventListener("loadstart", handleLoadStart);
|
|
26514
|
+
video.addEventListener("loadedmetadata", handleLoadedMetadata);
|
|
26515
|
+
video.addEventListener("loadeddata", handleLoadedData);
|
|
26516
|
+
video.addEventListener("waiting", handleWaiting);
|
|
26517
|
+
video.addEventListener("seeking", handleSeeking);
|
|
26518
|
+
video.addEventListener("seeked", handleSeeked);
|
|
26519
|
+
video.addEventListener("error", handleError);
|
|
26520
|
+
return () => {
|
|
26521
|
+
video.removeEventListener("canplay", handleCanPlay);
|
|
26522
|
+
video.removeEventListener("play", handlePlay);
|
|
26523
|
+
video.removeEventListener("pause", handlePause);
|
|
26524
|
+
video.removeEventListener("playing", handlePlaying);
|
|
26525
|
+
video.removeEventListener("timeupdate", handleTimeUpdate);
|
|
26526
|
+
video.removeEventListener("durationchange", handleDurationChange);
|
|
26527
|
+
video.removeEventListener("ended", handleEnded);
|
|
26528
|
+
video.removeEventListener("loadstart", handleLoadStart);
|
|
26529
|
+
video.removeEventListener("loadedmetadata", handleLoadedMetadata);
|
|
26530
|
+
video.removeEventListener("loadeddata", handleLoadedData);
|
|
26531
|
+
video.removeEventListener("waiting", handleWaiting);
|
|
26532
|
+
video.removeEventListener("seeking", handleSeeking);
|
|
26533
|
+
video.removeEventListener("seeked", handleSeeked);
|
|
26534
|
+
video.removeEventListener("error", handleError);
|
|
26535
|
+
};
|
|
26536
|
+
}, [
|
|
26537
|
+
src,
|
|
26538
|
+
cleanupBlobUrl,
|
|
26539
|
+
playerLikeObject,
|
|
26540
|
+
configVersion
|
|
26541
|
+
]);
|
|
26940
26542
|
useEffect(() => {
|
|
26941
|
-
initializePlayer();
|
|
26543
|
+
const cleanup = initializePlayer();
|
|
26942
26544
|
return () => {
|
|
26943
|
-
|
|
26944
|
-
|
|
26945
|
-
|
|
26946
|
-
|
|
26947
|
-
}
|
|
26948
|
-
playerRef.current.dispose();
|
|
26949
|
-
playerRef.current = null;
|
|
26950
|
-
setIsReady(false);
|
|
26545
|
+
cleanup?.();
|
|
26546
|
+
if (hlsRef.current) {
|
|
26547
|
+
hlsRef.current.destroy();
|
|
26548
|
+
hlsRef.current = null;
|
|
26951
26549
|
}
|
|
26550
|
+
cleanupBlobUrl();
|
|
26551
|
+
setIsReady(false);
|
|
26952
26552
|
};
|
|
26953
|
-
}, []);
|
|
26553
|
+
}, [src, initializePlayer, cleanupBlobUrl]);
|
|
26554
|
+
useEffect(() => {
|
|
26555
|
+
if (videoRef.current) {
|
|
26556
|
+
if (autoplay) {
|
|
26557
|
+
videoRef.current.play().catch((err) => {
|
|
26558
|
+
console.warn("[HlsVideoPlayer] Autoplay failed:", err);
|
|
26559
|
+
});
|
|
26560
|
+
}
|
|
26561
|
+
}
|
|
26562
|
+
}, [autoplay]);
|
|
26954
26563
|
const play = useCallback(() => {
|
|
26955
|
-
return
|
|
26564
|
+
return videoRef.current?.play();
|
|
26956
26565
|
}, []);
|
|
26957
26566
|
const pause = useCallback(() => {
|
|
26958
|
-
|
|
26567
|
+
videoRef.current?.pause();
|
|
26959
26568
|
}, []);
|
|
26960
26569
|
const currentTime = useCallback((time2) => {
|
|
26961
|
-
if (time2 !== void 0) {
|
|
26962
|
-
|
|
26570
|
+
if (time2 !== void 0 && videoRef.current) {
|
|
26571
|
+
videoRef.current.currentTime = time2;
|
|
26963
26572
|
return time2;
|
|
26964
26573
|
}
|
|
26965
|
-
return
|
|
26574
|
+
return videoRef.current?.currentTime || 0;
|
|
26966
26575
|
}, []);
|
|
26967
26576
|
const duration = useCallback(() => {
|
|
26968
|
-
return
|
|
26577
|
+
return videoRef.current?.duration || 0;
|
|
26969
26578
|
}, []);
|
|
26970
26579
|
const paused = useCallback(() => {
|
|
26971
|
-
return
|
|
26580
|
+
return videoRef.current?.paused ?? true;
|
|
26972
26581
|
}, []);
|
|
26973
26582
|
const mute = useCallback((isMuted) => {
|
|
26974
|
-
if (isMuted !== void 0) {
|
|
26975
|
-
|
|
26583
|
+
if (isMuted !== void 0 && videoRef.current) {
|
|
26584
|
+
videoRef.current.muted = isMuted;
|
|
26976
26585
|
return isMuted;
|
|
26977
26586
|
}
|
|
26978
|
-
return
|
|
26587
|
+
return videoRef.current?.muted ?? false;
|
|
26979
26588
|
}, []);
|
|
26980
26589
|
const volume = useCallback((level) => {
|
|
26981
|
-
if (level !== void 0) {
|
|
26982
|
-
|
|
26590
|
+
if (level !== void 0 && videoRef.current) {
|
|
26591
|
+
videoRef.current.volume = level;
|
|
26983
26592
|
return level;
|
|
26984
26593
|
}
|
|
26985
|
-
return
|
|
26594
|
+
return videoRef.current?.volume ?? 1;
|
|
26986
26595
|
}, []);
|
|
26987
|
-
const
|
|
26988
|
-
if (
|
|
26989
|
-
|
|
26990
|
-
|
|
26991
|
-
setIsReady(false);
|
|
26596
|
+
const playbackRate = useCallback((rate) => {
|
|
26597
|
+
if (rate !== void 0 && videoRef.current) {
|
|
26598
|
+
videoRef.current.playbackRate = rate;
|
|
26599
|
+
return rate;
|
|
26992
26600
|
}
|
|
26601
|
+
return videoRef.current?.playbackRate ?? 1;
|
|
26993
26602
|
}, []);
|
|
26994
|
-
|
|
26995
|
-
|
|
26603
|
+
useImperativeHandle(ref, () => ({
|
|
26604
|
+
hls: hlsRef.current,
|
|
26605
|
+
video: videoRef.current,
|
|
26996
26606
|
play,
|
|
26997
26607
|
pause,
|
|
26998
26608
|
currentTime,
|
|
@@ -27000,13 +26610,15 @@ var VideoPlayer = React23__default.forwardRef(({
|
|
|
27000
26610
|
paused,
|
|
27001
26611
|
mute,
|
|
27002
26612
|
volume,
|
|
26613
|
+
playbackRate,
|
|
27003
26614
|
dispose,
|
|
27004
|
-
isReady
|
|
27005
|
-
|
|
26615
|
+
isReady,
|
|
26616
|
+
// For backward compatibility with Video.js API
|
|
26617
|
+
player: playerLikeObject()
|
|
26618
|
+
}), [play, pause, currentTime, duration, paused, mute, volume, playbackRate, dispose, isReady, playerLikeObject]);
|
|
27006
26619
|
const handleClickWithIndicator = useCallback(() => {
|
|
27007
|
-
if (!onClick || !
|
|
27008
|
-
const
|
|
27009
|
-
const willBePlaying = player.paused();
|
|
26620
|
+
if (!onClick || !videoRef.current) return;
|
|
26621
|
+
const willBePlaying = videoRef.current.paused;
|
|
27010
26622
|
setIndicatorIsPlaying(willBePlaying);
|
|
27011
26623
|
setShowIndicator(false);
|
|
27012
26624
|
setTimeout(() => {
|
|
@@ -27015,17 +26627,30 @@ var VideoPlayer = React23__default.forwardRef(({
|
|
|
27015
26627
|
}, 0);
|
|
27016
26628
|
onClick();
|
|
27017
26629
|
}, [onClick]);
|
|
27018
|
-
return /* @__PURE__ */ jsxs("div", { className: `video-player-wrapper ${className}`, style: { position: "relative", width: "100%", height: "100%" }, children: [
|
|
26630
|
+
return /* @__PURE__ */ jsxs("div", { className: `hls-video-player-wrapper ${className}`, style: { position: "relative", width: "100%", height: "100%" }, children: [
|
|
27019
26631
|
/* @__PURE__ */ jsx(
|
|
27020
26632
|
"div",
|
|
27021
26633
|
{
|
|
27022
|
-
className: "video-player-container",
|
|
27023
|
-
ref:
|
|
27024
|
-
|
|
26634
|
+
className: "hls-video-player-container",
|
|
26635
|
+
ref: videoContainerRef,
|
|
26636
|
+
children: /* @__PURE__ */ jsx(
|
|
26637
|
+
"video",
|
|
26638
|
+
{
|
|
26639
|
+
ref: videoRef,
|
|
26640
|
+
className: "hls-video-element",
|
|
26641
|
+
poster,
|
|
26642
|
+
controls,
|
|
26643
|
+
loop,
|
|
26644
|
+
muted,
|
|
26645
|
+
playsInline,
|
|
26646
|
+
autoPlay: autoplay,
|
|
26647
|
+
preload: "metadata"
|
|
26648
|
+
}
|
|
26649
|
+
)
|
|
27025
26650
|
}
|
|
27026
26651
|
),
|
|
27027
|
-
isLoading && !externalLoadingControl && /* @__PURE__ */ jsx("div", { className: "video-player-loading", children: /* @__PURE__ */ jsx(OptifyeLogoLoader_default, { size: "md", message: "Loading video..." }) }),
|
|
27028
|
-
onClick && /* @__PURE__ */ jsx(
|
|
26652
|
+
isLoading && !externalLoadingControl && /* @__PURE__ */ jsx("div", { className: "hls-video-player-loading", children: /* @__PURE__ */ jsx(OptifyeLogoLoader_default, { size: "md", message: "Loading video..." }) }),
|
|
26653
|
+
onClick && !controls && /* @__PURE__ */ jsx(
|
|
27029
26654
|
"div",
|
|
27030
26655
|
{
|
|
27031
26656
|
onClick: handleClickWithIndicator,
|
|
@@ -27041,7 +26666,7 @@ var VideoPlayer = React23__default.forwardRef(({
|
|
|
27041
26666
|
"aria-label": "Click to play/pause"
|
|
27042
26667
|
}
|
|
27043
26668
|
),
|
|
27044
|
-
onClick && /* @__PURE__ */ jsx(
|
|
26669
|
+
onClick && !controls && /* @__PURE__ */ jsx(
|
|
27045
26670
|
PlayPauseIndicator,
|
|
27046
26671
|
{
|
|
27047
26672
|
show: showIndicator,
|
|
@@ -27051,13 +26676,25 @@ var VideoPlayer = React23__default.forwardRef(({
|
|
|
27051
26676
|
)
|
|
27052
26677
|
] });
|
|
27053
26678
|
});
|
|
27054
|
-
|
|
27055
|
-
var
|
|
26679
|
+
HlsVideoPlayer.displayName = "HlsVideoPlayer";
|
|
26680
|
+
var VideoPlayer = HlsVideoPlayer;
|
|
26681
|
+
var CroppedHlsVideoPlayer = forwardRef(({
|
|
27056
26682
|
crop,
|
|
27057
26683
|
debug = false,
|
|
27058
26684
|
onClick,
|
|
27059
26685
|
...videoProps
|
|
27060
26686
|
}, ref) => {
|
|
26687
|
+
const {
|
|
26688
|
+
onReady: onReadyProp,
|
|
26689
|
+
onPlay: onPlayProp,
|
|
26690
|
+
onPause: onPauseProp,
|
|
26691
|
+
onEnded: onEndedProp,
|
|
26692
|
+
onSeeking: onSeekingProp,
|
|
26693
|
+
onSeeked: onSeekedProp,
|
|
26694
|
+
onLoadedMetadata: onLoadedMetadataProp,
|
|
26695
|
+
className: inheritedClassName = ""
|
|
26696
|
+
} = videoProps;
|
|
26697
|
+
const videoSrc = videoProps.src;
|
|
27061
26698
|
const videoContainerRef = useRef(null);
|
|
27062
26699
|
const hiddenVideoRef = useRef(null);
|
|
27063
26700
|
const canvasRef = useRef(null);
|
|
@@ -27076,8 +26713,11 @@ var CroppedVideoPlayer = forwardRef(({
|
|
|
27076
26713
|
}
|
|
27077
26714
|
}, []);
|
|
27078
26715
|
useImperativeHandle(ref, () => ({
|
|
27079
|
-
get
|
|
27080
|
-
return hiddenVideoRef.current?.
|
|
26716
|
+
get hls() {
|
|
26717
|
+
return hiddenVideoRef.current?.hls || null;
|
|
26718
|
+
},
|
|
26719
|
+
get video() {
|
|
26720
|
+
return hiddenVideoRef.current?.video || null;
|
|
27081
26721
|
},
|
|
27082
26722
|
play: () => hiddenVideoRef.current?.play() || void 0,
|
|
27083
26723
|
pause: () => hiddenVideoRef.current?.pause(),
|
|
@@ -27091,12 +26731,36 @@ var CroppedVideoPlayer = forwardRef(({
|
|
|
27091
26731
|
paused: () => hiddenVideoRef.current?.paused() || true,
|
|
27092
26732
|
mute: (isMuted) => hiddenVideoRef.current?.mute(isMuted) || false,
|
|
27093
26733
|
volume: (level) => hiddenVideoRef.current?.volume(level) || 0,
|
|
26734
|
+
playbackRate: (rate) => hiddenVideoRef.current?.playbackRate(rate) || 1,
|
|
27094
26735
|
dispose: () => {
|
|
27095
26736
|
hiddenVideoRef.current?.dispose();
|
|
27096
26737
|
stopCanvasRendering();
|
|
27097
26738
|
},
|
|
27098
26739
|
get isReady() {
|
|
27099
26740
|
return hiddenVideoRef.current?.isReady || false;
|
|
26741
|
+
},
|
|
26742
|
+
// For backward compatibility with Video.js API
|
|
26743
|
+
get player() {
|
|
26744
|
+
const video = hiddenVideoRef.current?.video;
|
|
26745
|
+
if (!video) return null;
|
|
26746
|
+
return {
|
|
26747
|
+
el: () => video,
|
|
26748
|
+
currentTime: () => video.currentTime || 0,
|
|
26749
|
+
duration: () => video.duration || 0,
|
|
26750
|
+
paused: () => video.paused ?? true,
|
|
26751
|
+
play: () => video.play(),
|
|
26752
|
+
pause: () => video.pause(),
|
|
26753
|
+
muted: (val) => {
|
|
26754
|
+
if (val !== void 0) video.muted = val;
|
|
26755
|
+
return video.muted;
|
|
26756
|
+
},
|
|
26757
|
+
volume: (val) => {
|
|
26758
|
+
if (val !== void 0) video.volume = val;
|
|
26759
|
+
return video.volume;
|
|
26760
|
+
},
|
|
26761
|
+
error: () => null,
|
|
26762
|
+
dispose: () => hiddenVideoRef.current?.dispose()
|
|
26763
|
+
};
|
|
27100
26764
|
}
|
|
27101
26765
|
}), [stopCanvasRendering]);
|
|
27102
26766
|
const calculateCanvasDimensions = useCallback(() => {
|
|
@@ -27156,24 +26820,24 @@ var CroppedVideoPlayer = forwardRef(({
|
|
|
27156
26820
|
animationFrameRef.current = requestAnimationFrame(renderFrameToCanvas);
|
|
27157
26821
|
}, [crop]);
|
|
27158
26822
|
const handleVideoReady = useCallback((player) => {
|
|
27159
|
-
console.log("[
|
|
27160
|
-
const videoEl =
|
|
26823
|
+
console.log("[CroppedHlsVideoPlayer] Video player ready");
|
|
26824
|
+
const videoEl = hiddenVideoRef.current?.video;
|
|
27161
26825
|
if (videoEl) {
|
|
27162
26826
|
videoElementRef.current = videoEl;
|
|
27163
26827
|
setIsVideoReady(true);
|
|
27164
26828
|
}
|
|
27165
|
-
|
|
27166
|
-
}, [
|
|
26829
|
+
onReadyProp?.(player);
|
|
26830
|
+
}, [onReadyProp]);
|
|
27167
26831
|
const handleVideoPlay = useCallback((player) => {
|
|
27168
|
-
console.log("[
|
|
26832
|
+
console.log("[CroppedHlsVideoPlayer] Video playing, starting canvas rendering");
|
|
27169
26833
|
if (crop && canvasRef.current) {
|
|
27170
26834
|
setIsProcessing(true);
|
|
27171
26835
|
renderFrameToCanvas();
|
|
27172
26836
|
}
|
|
27173
|
-
|
|
27174
|
-
}, [crop, renderFrameToCanvas,
|
|
26837
|
+
onPlayProp?.(player);
|
|
26838
|
+
}, [crop, renderFrameToCanvas, onPlayProp]);
|
|
27175
26839
|
const handleVideoPause = useCallback((player) => {
|
|
27176
|
-
console.log("[
|
|
26840
|
+
console.log("[CroppedHlsVideoPlayer] Video paused, stopping canvas rendering and CLEARING canvas");
|
|
27177
26841
|
stopCanvasRendering();
|
|
27178
26842
|
setIsProcessing(false);
|
|
27179
26843
|
if (canvasRef.current) {
|
|
@@ -27184,10 +26848,10 @@ var CroppedVideoPlayer = forwardRef(({
|
|
|
27184
26848
|
ctx.fillRect(0, 0, canvasRef.current.width, canvasRef.current.height);
|
|
27185
26849
|
}
|
|
27186
26850
|
}
|
|
27187
|
-
|
|
27188
|
-
}, [stopCanvasRendering,
|
|
26851
|
+
onPauseProp?.(player);
|
|
26852
|
+
}, [stopCanvasRendering, onPauseProp]);
|
|
27189
26853
|
const handleVideoEnded = useCallback((player) => {
|
|
27190
|
-
console.log("[
|
|
26854
|
+
console.log("[CroppedHlsVideoPlayer] Video ended, CLEARING canvas");
|
|
27191
26855
|
stopCanvasRendering();
|
|
27192
26856
|
setIsProcessing(false);
|
|
27193
26857
|
if (canvasRef.current) {
|
|
@@ -27198,27 +26862,27 @@ var CroppedVideoPlayer = forwardRef(({
|
|
|
27198
26862
|
ctx.fillRect(0, 0, canvasRef.current.width, canvasRef.current.height);
|
|
27199
26863
|
}
|
|
27200
26864
|
}
|
|
27201
|
-
|
|
27202
|
-
}, [stopCanvasRendering,
|
|
26865
|
+
onEndedProp?.(player);
|
|
26866
|
+
}, [stopCanvasRendering, onEndedProp]);
|
|
27203
26867
|
const handleSeeking = useCallback((player) => {
|
|
27204
|
-
console.log("[
|
|
27205
|
-
if (crop && !
|
|
26868
|
+
console.log("[CroppedHlsVideoPlayer] Video seeking");
|
|
26869
|
+
if (crop && !videoElementRef.current?.paused) {
|
|
27206
26870
|
renderFrameToCanvas();
|
|
27207
26871
|
}
|
|
27208
|
-
|
|
27209
|
-
}, [crop, renderFrameToCanvas,
|
|
26872
|
+
onSeekingProp?.(player);
|
|
26873
|
+
}, [crop, renderFrameToCanvas, onSeekingProp]);
|
|
27210
26874
|
const handleSeeked = useCallback((player) => {
|
|
27211
|
-
console.log("[
|
|
27212
|
-
if (crop && !
|
|
26875
|
+
console.log("[CroppedHlsVideoPlayer] Video seeked");
|
|
26876
|
+
if (crop && !videoElementRef.current?.paused) {
|
|
27213
26877
|
renderFrameToCanvas();
|
|
27214
26878
|
}
|
|
27215
|
-
|
|
27216
|
-
}, [crop, renderFrameToCanvas,
|
|
26879
|
+
onSeekedProp?.(player);
|
|
26880
|
+
}, [crop, renderFrameToCanvas, onSeekedProp]);
|
|
27217
26881
|
const handleLoadedMetadata = useCallback((player) => {
|
|
27218
|
-
console.log("[
|
|
26882
|
+
console.log("[CroppedHlsVideoPlayer] Video metadata loaded");
|
|
27219
26883
|
calculateCanvasDimensions();
|
|
27220
|
-
|
|
27221
|
-
}, [calculateCanvasDimensions,
|
|
26884
|
+
onLoadedMetadataProp?.(player);
|
|
26885
|
+
}, [calculateCanvasDimensions, onLoadedMetadataProp]);
|
|
27222
26886
|
useEffect(() => {
|
|
27223
26887
|
calculateCanvasDimensions();
|
|
27224
26888
|
const handleResize = () => {
|
|
@@ -27234,25 +26898,25 @@ var CroppedVideoPlayer = forwardRef(({
|
|
|
27234
26898
|
const canvas = canvasRef.current;
|
|
27235
26899
|
const ctx = canvas.getContext("2d");
|
|
27236
26900
|
if (ctx) {
|
|
27237
|
-
console.log("[
|
|
26901
|
+
console.log("[CroppedHlsVideoPlayer] Source changing - CLEARING CANVAS IMMEDIATELY");
|
|
27238
26902
|
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
27239
26903
|
ctx.fillStyle = "black";
|
|
27240
26904
|
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
|
27241
26905
|
}
|
|
27242
26906
|
}
|
|
27243
|
-
}, [
|
|
26907
|
+
}, [videoSrc, crop]);
|
|
27244
26908
|
useEffect(() => {
|
|
27245
26909
|
return () => {
|
|
27246
26910
|
stopCanvasRendering();
|
|
27247
26911
|
};
|
|
27248
26912
|
}, [stopCanvasRendering]);
|
|
27249
26913
|
if (!crop) {
|
|
27250
|
-
return /* @__PURE__ */ jsx(
|
|
26914
|
+
return /* @__PURE__ */ jsx(HlsVideoPlayer, { ref, ...videoProps, onClick });
|
|
27251
26915
|
}
|
|
27252
26916
|
const handleClickWithIndicator = () => {
|
|
27253
|
-
if (!onClick || !hiddenVideoRef.current?.
|
|
27254
|
-
const
|
|
27255
|
-
const willBePlaying =
|
|
26917
|
+
if (!onClick || !hiddenVideoRef.current?.video) return;
|
|
26918
|
+
const video = hiddenVideoRef.current.video;
|
|
26919
|
+
const willBePlaying = video.paused;
|
|
27256
26920
|
setIndicatorIsPlaying(willBePlaying);
|
|
27257
26921
|
setShowIndicator(false);
|
|
27258
26922
|
setTimeout(() => {
|
|
@@ -27265,11 +26929,11 @@ var CroppedVideoPlayer = forwardRef(({
|
|
|
27265
26929
|
"div",
|
|
27266
26930
|
{
|
|
27267
26931
|
ref: videoContainerRef,
|
|
27268
|
-
className: `relative w-full h-full flex items-center justify-center bg-black ${onClick ? "cursor-pointer" : ""} ${
|
|
26932
|
+
className: `relative w-full h-full flex items-center justify-center bg-black ${onClick ? "cursor-pointer" : ""} ${inheritedClassName}`,
|
|
27269
26933
|
onClick: handleClickWithIndicator,
|
|
27270
26934
|
children: [
|
|
27271
26935
|
/* @__PURE__ */ jsx("div", { className: "hidden", children: /* @__PURE__ */ jsx(
|
|
27272
|
-
|
|
26936
|
+
HlsVideoPlayer,
|
|
27273
26937
|
{
|
|
27274
26938
|
ref: hiddenVideoRef,
|
|
27275
26939
|
...videoProps,
|
|
@@ -27336,7 +27000,539 @@ var CroppedVideoPlayer = forwardRef(({
|
|
|
27336
27000
|
}
|
|
27337
27001
|
);
|
|
27338
27002
|
});
|
|
27339
|
-
|
|
27003
|
+
CroppedHlsVideoPlayer.displayName = "CroppedHlsVideoPlayer";
|
|
27004
|
+
var CroppedVideoPlayer = CroppedHlsVideoPlayer;
|
|
27005
|
+
var getSupabaseClient2 = () => {
|
|
27006
|
+
const url = process.env.NEXT_PUBLIC_SUPABASE_URL;
|
|
27007
|
+
const key = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY;
|
|
27008
|
+
if (!url || !key) {
|
|
27009
|
+
throw new Error("Supabase configuration missing");
|
|
27010
|
+
}
|
|
27011
|
+
return createClient(url, key);
|
|
27012
|
+
};
|
|
27013
|
+
var getAuthToken3 = async () => {
|
|
27014
|
+
try {
|
|
27015
|
+
const supabase = getSupabaseClient2();
|
|
27016
|
+
const { data: { session } } = await supabase.auth.getSession();
|
|
27017
|
+
return session?.access_token || null;
|
|
27018
|
+
} catch (error) {
|
|
27019
|
+
console.error("[useWorkspaceCrop] Error getting auth token:", error);
|
|
27020
|
+
return null;
|
|
27021
|
+
}
|
|
27022
|
+
};
|
|
27023
|
+
function useWorkspaceCrop(workspaceId) {
|
|
27024
|
+
const [crop, setCrop] = useState(null);
|
|
27025
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
27026
|
+
const [error, setError] = useState(null);
|
|
27027
|
+
useEffect(() => {
|
|
27028
|
+
if (!workspaceId) {
|
|
27029
|
+
setIsLoading(false);
|
|
27030
|
+
return;
|
|
27031
|
+
}
|
|
27032
|
+
const fetchCrop = async () => {
|
|
27033
|
+
setIsLoading(true);
|
|
27034
|
+
setError(null);
|
|
27035
|
+
try {
|
|
27036
|
+
const token = await getAuthToken3();
|
|
27037
|
+
if (!token) {
|
|
27038
|
+
throw new Error("Authentication required");
|
|
27039
|
+
}
|
|
27040
|
+
const response = await fetch("/api/clips/supabase", {
|
|
27041
|
+
method: "POST",
|
|
27042
|
+
headers: {
|
|
27043
|
+
"Content-Type": "application/json",
|
|
27044
|
+
"Authorization": `Bearer ${token}`
|
|
27045
|
+
},
|
|
27046
|
+
body: JSON.stringify({
|
|
27047
|
+
action: "crop",
|
|
27048
|
+
workspaceId
|
|
27049
|
+
})
|
|
27050
|
+
});
|
|
27051
|
+
if (!response.ok) {
|
|
27052
|
+
throw new Error(`Failed to fetch crop: ${response.statusText}`);
|
|
27053
|
+
}
|
|
27054
|
+
const data = await response.json();
|
|
27055
|
+
console.log(`[useWorkspaceCrop] Fetched crop for workspace ${workspaceId}:`, data.crop);
|
|
27056
|
+
setCrop(data.crop);
|
|
27057
|
+
} catch (err) {
|
|
27058
|
+
console.error("[useWorkspaceCrop] Error fetching crop:", err);
|
|
27059
|
+
setError(err instanceof Error ? err.message : "Failed to fetch crop configuration");
|
|
27060
|
+
setCrop(null);
|
|
27061
|
+
} finally {
|
|
27062
|
+
setIsLoading(false);
|
|
27063
|
+
}
|
|
27064
|
+
};
|
|
27065
|
+
fetchCrop();
|
|
27066
|
+
}, [workspaceId]);
|
|
27067
|
+
return { crop, isLoading, error };
|
|
27068
|
+
}
|
|
27069
|
+
function Skeleton({ className, ...props }) {
|
|
27070
|
+
return /* @__PURE__ */ jsx("div", { className: cn("animate-pulse rounded-md bg-muted", className), ...props });
|
|
27071
|
+
}
|
|
27072
|
+
var Select = SelectPrimitive.Root;
|
|
27073
|
+
var SelectGroup = SelectPrimitive.Group;
|
|
27074
|
+
var SelectValue = SelectPrimitive.Value;
|
|
27075
|
+
var SelectTrigger = React23.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(
|
|
27076
|
+
SelectPrimitive.Trigger,
|
|
27077
|
+
{
|
|
27078
|
+
ref,
|
|
27079
|
+
className: cn(
|
|
27080
|
+
"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",
|
|
27081
|
+
className
|
|
27082
|
+
),
|
|
27083
|
+
...props,
|
|
27084
|
+
children: [
|
|
27085
|
+
children,
|
|
27086
|
+
/* @__PURE__ */ jsx(SelectPrimitive.Icon, { asChild: true, children: /* @__PURE__ */ jsx(ChevronDown, { className: "h-4 w-4 opacity-50" }) })
|
|
27087
|
+
]
|
|
27088
|
+
}
|
|
27089
|
+
));
|
|
27090
|
+
SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
|
|
27091
|
+
var SelectScrollUpButton = React23.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
27092
|
+
SelectPrimitive.ScrollUpButton,
|
|
27093
|
+
{
|
|
27094
|
+
ref,
|
|
27095
|
+
className: cn("flex cursor-default items-center justify-center py-1", className),
|
|
27096
|
+
...props,
|
|
27097
|
+
children: /* @__PURE__ */ jsx(ChevronUp, { className: "h-4 w-4" })
|
|
27098
|
+
}
|
|
27099
|
+
));
|
|
27100
|
+
SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName;
|
|
27101
|
+
var SelectScrollDownButton = React23.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
27102
|
+
SelectPrimitive.ScrollDownButton,
|
|
27103
|
+
{
|
|
27104
|
+
ref,
|
|
27105
|
+
className: cn("flex cursor-default items-center justify-center py-1", className),
|
|
27106
|
+
...props,
|
|
27107
|
+
children: /* @__PURE__ */ jsx(ChevronDown, { className: "h-4 w-4" })
|
|
27108
|
+
}
|
|
27109
|
+
));
|
|
27110
|
+
SelectScrollDownButton.displayName = SelectPrimitive.ScrollDownButton.displayName;
|
|
27111
|
+
var SelectContent = React23.forwardRef(({ className, children, position = "popper", ...props }, ref) => /* @__PURE__ */ jsx(SelectPrimitive.Portal, { children: /* @__PURE__ */ jsxs(
|
|
27112
|
+
SelectPrimitive.Content,
|
|
27113
|
+
{
|
|
27114
|
+
ref,
|
|
27115
|
+
className: cn(
|
|
27116
|
+
"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]",
|
|
27117
|
+
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",
|
|
27118
|
+
className
|
|
27119
|
+
),
|
|
27120
|
+
position,
|
|
27121
|
+
...props,
|
|
27122
|
+
children: [
|
|
27123
|
+
/* @__PURE__ */ jsx(SelectScrollUpButton, {}),
|
|
27124
|
+
/* @__PURE__ */ jsx(
|
|
27125
|
+
SelectPrimitive.Viewport,
|
|
27126
|
+
{
|
|
27127
|
+
className: cn(
|
|
27128
|
+
"p-1",
|
|
27129
|
+
position === "popper" && "h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]"
|
|
27130
|
+
),
|
|
27131
|
+
children
|
|
27132
|
+
}
|
|
27133
|
+
),
|
|
27134
|
+
/* @__PURE__ */ jsx(SelectScrollDownButton, {})
|
|
27135
|
+
]
|
|
27136
|
+
}
|
|
27137
|
+
) }));
|
|
27138
|
+
SelectContent.displayName = SelectPrimitive.Content.displayName;
|
|
27139
|
+
var SelectLabel = React23.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
27140
|
+
SelectPrimitive.Label,
|
|
27141
|
+
{
|
|
27142
|
+
ref,
|
|
27143
|
+
className: cn("px-2 py-1.5 text-sm font-semibold", className),
|
|
27144
|
+
...props
|
|
27145
|
+
}
|
|
27146
|
+
));
|
|
27147
|
+
SelectLabel.displayName = SelectPrimitive.Label.displayName;
|
|
27148
|
+
var SelectItem = React23.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(
|
|
27149
|
+
SelectPrimitive.Item,
|
|
27150
|
+
{
|
|
27151
|
+
ref,
|
|
27152
|
+
className: cn(
|
|
27153
|
+
"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",
|
|
27154
|
+
className
|
|
27155
|
+
),
|
|
27156
|
+
...props,
|
|
27157
|
+
children: [
|
|
27158
|
+
/* @__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" }) }) }),
|
|
27159
|
+
/* @__PURE__ */ jsx(SelectPrimitive.ItemText, { children })
|
|
27160
|
+
]
|
|
27161
|
+
}
|
|
27162
|
+
));
|
|
27163
|
+
SelectItem.displayName = SelectPrimitive.Item.displayName;
|
|
27164
|
+
var SelectSeparator = React23.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
27165
|
+
SelectPrimitive.Separator,
|
|
27166
|
+
{
|
|
27167
|
+
ref,
|
|
27168
|
+
className: cn("-mx-1 my-1 h-px bg-muted", className),
|
|
27169
|
+
...props
|
|
27170
|
+
}
|
|
27171
|
+
));
|
|
27172
|
+
SelectSeparator.displayName = SelectPrimitive.Separator.displayName;
|
|
27173
|
+
var LoadingOverlay = ({
|
|
27174
|
+
isVisible,
|
|
27175
|
+
message = "Loading...",
|
|
27176
|
+
className
|
|
27177
|
+
}) => {
|
|
27178
|
+
if (!isVisible) return null;
|
|
27179
|
+
return /* @__PURE__ */ jsx(
|
|
27180
|
+
motion.div,
|
|
27181
|
+
{
|
|
27182
|
+
initial: { opacity: 0 },
|
|
27183
|
+
animate: { opacity: 1 },
|
|
27184
|
+
exit: { opacity: 0 },
|
|
27185
|
+
transition: { duration: 0.2 },
|
|
27186
|
+
className: `fixed inset-0 z-[100] flex items-center justify-center bg-black/30 backdrop-blur-sm ${className || ""}`,
|
|
27187
|
+
"aria-modal": "true",
|
|
27188
|
+
role: "dialog",
|
|
27189
|
+
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 }) })
|
|
27190
|
+
}
|
|
27191
|
+
);
|
|
27192
|
+
};
|
|
27193
|
+
var LoadingOverlay_default = LoadingOverlay;
|
|
27194
|
+
var TimeDisplay = ({ className, variant = "default" }) => {
|
|
27195
|
+
const { dateTimeConfig } = useDashboardConfig();
|
|
27196
|
+
const [time2, setTime] = useState("");
|
|
27197
|
+
const dbTimezone = useAppTimezone();
|
|
27198
|
+
const timezoneToDisplay = dbTimezone || dateTimeConfig?.defaultTimezone || "UTC";
|
|
27199
|
+
const localeToUse = dateTimeConfig?.defaultLocale || "en-US";
|
|
27200
|
+
const timeSuffix = "";
|
|
27201
|
+
useEffect(() => {
|
|
27202
|
+
const updateTime = () => {
|
|
27203
|
+
const now2 = /* @__PURE__ */ new Date();
|
|
27204
|
+
const effectiveFormatOptions = {
|
|
27205
|
+
hour: "2-digit",
|
|
27206
|
+
minute: "2-digit",
|
|
27207
|
+
second: "2-digit",
|
|
27208
|
+
hour12: true,
|
|
27209
|
+
timeZone: timezoneToDisplay,
|
|
27210
|
+
...dateTimeConfig?.timeFormatOptions || {}
|
|
27211
|
+
// Allow override from config
|
|
27212
|
+
};
|
|
27213
|
+
try {
|
|
27214
|
+
setTime(new Intl.DateTimeFormat(localeToUse, effectiveFormatOptions).format(now2));
|
|
27215
|
+
} catch (e) {
|
|
27216
|
+
console.error("Error formatting time:", e);
|
|
27217
|
+
setTime("Error");
|
|
27218
|
+
}
|
|
27219
|
+
};
|
|
27220
|
+
updateTime();
|
|
27221
|
+
const interval = setInterval(updateTime, 1e3);
|
|
27222
|
+
return () => clearInterval(interval);
|
|
27223
|
+
}, [timezoneToDisplay, dateTimeConfig?.timeFormatOptions, localeToUse]);
|
|
27224
|
+
if (!time2) return null;
|
|
27225
|
+
if (variant === "minimal") {
|
|
27226
|
+
return /* @__PURE__ */ jsxs("span", { className: className || "", children: [
|
|
27227
|
+
time2,
|
|
27228
|
+
" ",
|
|
27229
|
+
timeSuffix
|
|
27230
|
+
] });
|
|
27231
|
+
}
|
|
27232
|
+
return /* @__PURE__ */ jsxs(
|
|
27233
|
+
motion.div,
|
|
27234
|
+
{
|
|
27235
|
+
initial: { opacity: 0, y: -5 },
|
|
27236
|
+
animate: { opacity: 1, y: 0 },
|
|
27237
|
+
transition: { duration: 0.3 },
|
|
27238
|
+
className: `flex items-center space-x-1.5 bg-white/60 backdrop-blur-sm px-2 py-0.5 rounded-md shadow-xs ${className || ""}`,
|
|
27239
|
+
children: [
|
|
27240
|
+
/* @__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" }) }),
|
|
27241
|
+
/* @__PURE__ */ jsxs("span", { className: "text-xs sm:text-[11px] font-medium text-gray-800 tabular-nums tracking-tight", children: [
|
|
27242
|
+
time2,
|
|
27243
|
+
" ",
|
|
27244
|
+
timeSuffix
|
|
27245
|
+
] })
|
|
27246
|
+
]
|
|
27247
|
+
}
|
|
27248
|
+
);
|
|
27249
|
+
};
|
|
27250
|
+
var TimeDisplay_default = TimeDisplay;
|
|
27251
|
+
var DateDisplay = ({ className, variant = "default" }) => {
|
|
27252
|
+
const { dateTimeConfig } = useDashboardConfig();
|
|
27253
|
+
const [date, setDate] = useState("");
|
|
27254
|
+
const timezoneToDisplay = dateTimeConfig?.defaultTimezone || "UTC";
|
|
27255
|
+
const localeToUse = dateTimeConfig?.defaultLocale || "en-US";
|
|
27256
|
+
useEffect(() => {
|
|
27257
|
+
const getCurrentFormattedDate = () => {
|
|
27258
|
+
const now2 = /* @__PURE__ */ new Date();
|
|
27259
|
+
const effectiveFormatOptions = {
|
|
27260
|
+
weekday: "short",
|
|
27261
|
+
day: "numeric",
|
|
27262
|
+
month: "short",
|
|
27263
|
+
timeZone: timezoneToDisplay,
|
|
27264
|
+
...dateTimeConfig?.dateFormatOptions || {}
|
|
27265
|
+
// Allow override from config
|
|
27266
|
+
};
|
|
27267
|
+
try {
|
|
27268
|
+
return new Intl.DateTimeFormat(localeToUse, effectiveFormatOptions).format(now2);
|
|
27269
|
+
} catch (e) {
|
|
27270
|
+
console.error("Error formatting date:", e);
|
|
27271
|
+
return "Error";
|
|
27272
|
+
}
|
|
27273
|
+
};
|
|
27274
|
+
const updateDate = () => {
|
|
27275
|
+
setDate(getCurrentFormattedDate());
|
|
27276
|
+
};
|
|
27277
|
+
updateDate();
|
|
27278
|
+
const interval = setInterval(() => {
|
|
27279
|
+
const currentDateStr = getCurrentFormattedDate();
|
|
27280
|
+
if (currentDateStr !== date) {
|
|
27281
|
+
updateDate();
|
|
27282
|
+
}
|
|
27283
|
+
}, 60 * 1e3);
|
|
27284
|
+
return () => clearInterval(interval);
|
|
27285
|
+
}, [date, timezoneToDisplay, dateTimeConfig?.dateFormatOptions, localeToUse]);
|
|
27286
|
+
if (!date) return null;
|
|
27287
|
+
if (variant === "minimal") {
|
|
27288
|
+
return /* @__PURE__ */ jsx("span", { className: className || "", children: date });
|
|
27289
|
+
}
|
|
27290
|
+
return /* @__PURE__ */ jsxs(
|
|
27291
|
+
motion.div,
|
|
27292
|
+
{
|
|
27293
|
+
initial: { opacity: 0, y: -5 },
|
|
27294
|
+
animate: { opacity: 1, y: 0 },
|
|
27295
|
+
transition: { duration: 0.3 },
|
|
27296
|
+
className: `flex items-center space-x-1.5 bg-white/60 backdrop-blur-sm px-2 py-0.5 rounded-md shadow-xs ${className || ""}`,
|
|
27297
|
+
children: [
|
|
27298
|
+
/* @__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" }) }),
|
|
27299
|
+
/* @__PURE__ */ jsx("span", { className: "text-[11px] font-medium text-gray-800 tracking-tight", children: date })
|
|
27300
|
+
]
|
|
27301
|
+
}
|
|
27302
|
+
);
|
|
27303
|
+
};
|
|
27304
|
+
var DateDisplay_default = DateDisplay;
|
|
27305
|
+
var Card3 = Card2;
|
|
27306
|
+
var CardHeader3 = CardHeader2;
|
|
27307
|
+
var CardTitle3 = CardTitle2;
|
|
27308
|
+
var CardContent3 = CardContent2;
|
|
27309
|
+
var MetricCard2 = ({ title, value, unit = "", trend = null }) => {
|
|
27310
|
+
const getTrendColor = (trendValue) => {
|
|
27311
|
+
if (trendValue === null || trendValue === void 0) return "";
|
|
27312
|
+
return trendValue > 0 ? "text-green-500" : trendValue < 0 ? "text-red-500" : "text-gray-500";
|
|
27313
|
+
};
|
|
27314
|
+
const getTrendSymbol = (trendValue) => {
|
|
27315
|
+
if (trendValue === null || trendValue === void 0) return "";
|
|
27316
|
+
return trendValue > 0 ? "\u2191" : trendValue < 0 ? "\u2193" : "";
|
|
27317
|
+
};
|
|
27318
|
+
return /* @__PURE__ */ jsxs(Card3, { className: "bg-white", children: [
|
|
27319
|
+
/* @__PURE__ */ jsx(CardHeader3, { className: "pb-2", children: /* @__PURE__ */ jsx(CardTitle3, { className: "text-sm font-medium text-gray-500", children: title }) }),
|
|
27320
|
+
/* @__PURE__ */ jsx(CardContent3, { children: /* @__PURE__ */ jsxs("div", { className: "flex items-baseline justify-between", children: [
|
|
27321
|
+
/* @__PURE__ */ jsxs("div", { className: "text-2xl font-semibold", children: [
|
|
27322
|
+
value,
|
|
27323
|
+
unit && /* @__PURE__ */ jsx("span", { className: "ml-1 text-sm text-gray-500", children: unit })
|
|
27324
|
+
] }),
|
|
27325
|
+
trend !== null && trend !== void 0 && // Check trend for null/undefined before accessing
|
|
27326
|
+
/* @__PURE__ */ jsx("div", { className: `flex items-center ${getTrendColor(trend)}`, children: /* @__PURE__ */ jsxs("span", { className: "text-sm", children: [
|
|
27327
|
+
getTrendSymbol(trend),
|
|
27328
|
+
" ",
|
|
27329
|
+
Math.abs(trend),
|
|
27330
|
+
"%"
|
|
27331
|
+
] }) })
|
|
27332
|
+
] }) })
|
|
27333
|
+
] });
|
|
27334
|
+
};
|
|
27335
|
+
var MetricCard_default = MetricCard2;
|
|
27336
|
+
var TimePickerDropdown = ({
|
|
27337
|
+
value,
|
|
27338
|
+
onChange,
|
|
27339
|
+
placeholder = "Select time",
|
|
27340
|
+
className = "",
|
|
27341
|
+
disabled = false
|
|
27342
|
+
}) => {
|
|
27343
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
27344
|
+
const [searchTerm, setSearchTerm] = useState("");
|
|
27345
|
+
const dropdownRef = useRef(null);
|
|
27346
|
+
const inputRef = useRef(null);
|
|
27347
|
+
const generateTimeSlots = () => {
|
|
27348
|
+
const slots = [];
|
|
27349
|
+
for (let hour = 0; hour < 24; hour++) {
|
|
27350
|
+
for (let minute = 0; minute < 60; minute += 15) {
|
|
27351
|
+
const time24 = `${hour.toString().padStart(2, "0")}:${minute.toString().padStart(2, "0")}`;
|
|
27352
|
+
const hour12 = hour === 0 ? 12 : hour > 12 ? hour - 12 : hour;
|
|
27353
|
+
const ampm = hour < 12 ? "AM" : "PM";
|
|
27354
|
+
const time12 = `${hour12}:${minute.toString().padStart(2, "0")} ${ampm}`;
|
|
27355
|
+
slots.push({ value: time24, label: time12 });
|
|
27356
|
+
}
|
|
27357
|
+
}
|
|
27358
|
+
return slots;
|
|
27359
|
+
};
|
|
27360
|
+
const timeSlots = generateTimeSlots();
|
|
27361
|
+
const filteredSlots = timeSlots.filter(
|
|
27362
|
+
(slot) => slot.label.toLowerCase().includes(searchTerm.toLowerCase())
|
|
27363
|
+
);
|
|
27364
|
+
const getDisplayValue = (value2) => {
|
|
27365
|
+
if (!value2) return "";
|
|
27366
|
+
const normalizedValue = value2.substring(0, 5);
|
|
27367
|
+
const slot = timeSlots.find((s) => s.value === normalizedValue);
|
|
27368
|
+
return slot ? slot.label : value2;
|
|
27369
|
+
};
|
|
27370
|
+
useEffect(() => {
|
|
27371
|
+
const handleClickOutside = (event) => {
|
|
27372
|
+
if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
|
|
27373
|
+
setIsOpen(false);
|
|
27374
|
+
setSearchTerm("");
|
|
27375
|
+
}
|
|
27376
|
+
};
|
|
27377
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
27378
|
+
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
27379
|
+
}, []);
|
|
27380
|
+
const handleKeyDown = (e) => {
|
|
27381
|
+
if (e.key === "Escape") {
|
|
27382
|
+
setIsOpen(false);
|
|
27383
|
+
setSearchTerm("");
|
|
27384
|
+
} else if (e.key === "Enter") {
|
|
27385
|
+
e.preventDefault();
|
|
27386
|
+
if (filteredSlots.length > 0) {
|
|
27387
|
+
onChange(filteredSlots[0].value);
|
|
27388
|
+
setIsOpen(false);
|
|
27389
|
+
setSearchTerm("");
|
|
27390
|
+
}
|
|
27391
|
+
}
|
|
27392
|
+
};
|
|
27393
|
+
const handleSelect = (timeValue) => {
|
|
27394
|
+
onChange(timeValue);
|
|
27395
|
+
setIsOpen(false);
|
|
27396
|
+
setSearchTerm("");
|
|
27397
|
+
};
|
|
27398
|
+
const handleToggle = () => {
|
|
27399
|
+
if (disabled) return;
|
|
27400
|
+
setIsOpen(!isOpen);
|
|
27401
|
+
if (!isOpen) {
|
|
27402
|
+
setTimeout(() => inputRef.current?.focus(), 100);
|
|
27403
|
+
}
|
|
27404
|
+
};
|
|
27405
|
+
return /* @__PURE__ */ jsxs("div", { className: `relative ${className}`, ref: dropdownRef, children: [
|
|
27406
|
+
/* @__PURE__ */ jsx(
|
|
27407
|
+
"button",
|
|
27408
|
+
{
|
|
27409
|
+
type: "button",
|
|
27410
|
+
onClick: handleToggle,
|
|
27411
|
+
disabled,
|
|
27412
|
+
className: `
|
|
27413
|
+
w-full px-3 py-2 text-left bg-white border border-gray-300 rounded-md shadow-sm
|
|
27414
|
+
focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500
|
|
27415
|
+
hover:border-gray-400 transition-colors duration-200
|
|
27416
|
+
${disabled ? "bg-gray-50 cursor-not-allowed" : "cursor-pointer"}
|
|
27417
|
+
${isOpen ? "ring-2 ring-blue-500 border-blue-500" : ""}
|
|
27418
|
+
`,
|
|
27419
|
+
children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
|
|
27420
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
27421
|
+
/* @__PURE__ */ jsx(Clock, { className: "h-4 w-4 text-gray-400" }),
|
|
27422
|
+
/* @__PURE__ */ jsx("span", { className: `text-sm ${value ? "text-gray-900" : "text-gray-500"}`, children: value ? getDisplayValue(value) : placeholder })
|
|
27423
|
+
] }),
|
|
27424
|
+
/* @__PURE__ */ jsx(
|
|
27425
|
+
ChevronDown,
|
|
27426
|
+
{
|
|
27427
|
+
className: `h-4 w-4 text-gray-400 transition-transform duration-200 ${isOpen ? "rotate-180" : ""}`
|
|
27428
|
+
}
|
|
27429
|
+
)
|
|
27430
|
+
] })
|
|
27431
|
+
}
|
|
27432
|
+
),
|
|
27433
|
+
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: [
|
|
27434
|
+
/* @__PURE__ */ jsx("div", { className: "p-2 border-b border-gray-200", children: /* @__PURE__ */ jsx(
|
|
27435
|
+
"input",
|
|
27436
|
+
{
|
|
27437
|
+
ref: inputRef,
|
|
27438
|
+
type: "text",
|
|
27439
|
+
placeholder: "Search time...",
|
|
27440
|
+
value: searchTerm,
|
|
27441
|
+
onChange: (e) => setSearchTerm(e.target.value),
|
|
27442
|
+
onKeyDown: handleKeyDown,
|
|
27443
|
+
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"
|
|
27444
|
+
}
|
|
27445
|
+
) }),
|
|
27446
|
+
/* @__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(
|
|
27447
|
+
"button",
|
|
27448
|
+
{
|
|
27449
|
+
type: "button",
|
|
27450
|
+
onClick: () => handleSelect(slot.value),
|
|
27451
|
+
className: `
|
|
27452
|
+
w-full px-3 py-2 text-left text-sm hover:bg-blue-50 hover:text-blue-600
|
|
27453
|
+
transition-colors duration-150 border-b border-gray-100 last:border-b-0
|
|
27454
|
+
${slot.value === value ? "bg-blue-50 text-blue-600 font-medium" : "text-gray-700"}
|
|
27455
|
+
`,
|
|
27456
|
+
children: slot.label
|
|
27457
|
+
},
|
|
27458
|
+
slot.value
|
|
27459
|
+
)) })
|
|
27460
|
+
] })
|
|
27461
|
+
] });
|
|
27462
|
+
};
|
|
27463
|
+
var SilentErrorBoundary = class extends React23__default.Component {
|
|
27464
|
+
constructor(props) {
|
|
27465
|
+
super(props);
|
|
27466
|
+
this.handleClearAndReload = () => {
|
|
27467
|
+
console.log("[ErrorBoundary] User initiated reset");
|
|
27468
|
+
if (typeof window !== "undefined") {
|
|
27469
|
+
try {
|
|
27470
|
+
localStorage.clear();
|
|
27471
|
+
sessionStorage.clear();
|
|
27472
|
+
console.log("[ErrorBoundary] Cleared all storage");
|
|
27473
|
+
} catch (error) {
|
|
27474
|
+
console.error("[ErrorBoundary] Failed to clear storage:", error);
|
|
27475
|
+
}
|
|
27476
|
+
}
|
|
27477
|
+
window.location.href = "/login";
|
|
27478
|
+
};
|
|
27479
|
+
this.state = {
|
|
27480
|
+
hasError: false,
|
|
27481
|
+
errorCount: 0,
|
|
27482
|
+
lastError: null,
|
|
27483
|
+
errorInfo: null
|
|
27484
|
+
};
|
|
27485
|
+
}
|
|
27486
|
+
static getDerivedStateFromError(error) {
|
|
27487
|
+
return { hasError: true };
|
|
27488
|
+
}
|
|
27489
|
+
componentDidCatch(error, errorInfo) {
|
|
27490
|
+
console.error("[ErrorBoundary] Caught render error:", {
|
|
27491
|
+
error: error.message,
|
|
27492
|
+
stack: error.stack,
|
|
27493
|
+
componentStack: errorInfo.componentStack,
|
|
27494
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
27495
|
+
});
|
|
27496
|
+
this.setState((prev) => ({
|
|
27497
|
+
errorCount: prev.errorCount + 1,
|
|
27498
|
+
lastError: error,
|
|
27499
|
+
errorInfo
|
|
27500
|
+
}));
|
|
27501
|
+
try {
|
|
27502
|
+
if (typeof window !== "undefined" && window.mixpanel) {
|
|
27503
|
+
window.mixpanel.track("React Render Error", {
|
|
27504
|
+
error: error.message,
|
|
27505
|
+
component: errorInfo.componentStack?.split("\n")[1] || "unknown",
|
|
27506
|
+
errorCount: this.state.errorCount + 1
|
|
27507
|
+
});
|
|
27508
|
+
}
|
|
27509
|
+
} catch (analyticsError) {
|
|
27510
|
+
console.warn("[ErrorBoundary] Analytics tracking failed:", analyticsError);
|
|
27511
|
+
}
|
|
27512
|
+
}
|
|
27513
|
+
render() {
|
|
27514
|
+
if (!this.state.hasError) {
|
|
27515
|
+
return this.props.children;
|
|
27516
|
+
}
|
|
27517
|
+
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: [
|
|
27518
|
+
/* @__PURE__ */ jsx(OptifyeLogoLoader_default, { size: "lg", message: "Loading Dashboard..." }),
|
|
27519
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm text-gray-500", children: "Taking longer than usual..." }),
|
|
27520
|
+
/* @__PURE__ */ jsx("div", { className: "pt-4", children: /* @__PURE__ */ jsx(
|
|
27521
|
+
"a",
|
|
27522
|
+
{
|
|
27523
|
+
href: "#",
|
|
27524
|
+
onClick: (e) => {
|
|
27525
|
+
e.preventDefault();
|
|
27526
|
+
this.handleClearAndReload();
|
|
27527
|
+
},
|
|
27528
|
+
className: "text-xs text-gray-400 hover:text-gray-600 underline transition-colors",
|
|
27529
|
+
children: "Reset and try again"
|
|
27530
|
+
}
|
|
27531
|
+
) }),
|
|
27532
|
+
process.env.NODE_ENV === "development" && /* @__PURE__ */ jsx("p", { className: "text-xs text-gray-400 italic mt-4", children: "Check console for error details" })
|
|
27533
|
+
] }) });
|
|
27534
|
+
}
|
|
27535
|
+
};
|
|
27340
27536
|
var BackButton = ({
|
|
27341
27537
|
onClick,
|
|
27342
27538
|
text = "Back",
|
|
@@ -27701,70 +27897,6 @@ var NewClipsNotification = ({
|
|
|
27701
27897
|
}
|
|
27702
27898
|
);
|
|
27703
27899
|
};
|
|
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
27900
|
var parseCycleTime = (value) => {
|
|
27769
27901
|
if (typeof value === "number" && Number.isFinite(value)) {
|
|
27770
27902
|
return value;
|
|
@@ -29020,6 +29152,11 @@ var BottlenecksContent = ({
|
|
|
29020
29152
|
return Number.isFinite(numericValue) ? numericValue : null;
|
|
29021
29153
|
})();
|
|
29022
29154
|
const videoRef = useRef(null);
|
|
29155
|
+
const videoPlayerOptions = useMemo(() => ({
|
|
29156
|
+
fluid: false,
|
|
29157
|
+
responsive: false,
|
|
29158
|
+
fill: false
|
|
29159
|
+
}), []);
|
|
29023
29160
|
const [initialFilter, setInitialFilter] = useState("");
|
|
29024
29161
|
const currentIndexRef = useRef(0);
|
|
29025
29162
|
const activeFilterRef = useRef(initialFilter);
|
|
@@ -29030,6 +29167,7 @@ var BottlenecksContent = ({
|
|
|
29030
29167
|
const [duration, setDuration] = useState(0);
|
|
29031
29168
|
const [currentIndex, setCurrentIndex] = useState(0);
|
|
29032
29169
|
const [currentClipId, setCurrentClipId] = useState(null);
|
|
29170
|
+
const [playbackSpeed, setPlaybackSpeed] = useState(1);
|
|
29033
29171
|
const [isTransitioning, setIsTransitioning] = useState(false);
|
|
29034
29172
|
const [pendingVideo, setPendingVideo] = useState(null);
|
|
29035
29173
|
const [isVideoBuffering, setIsVideoBuffering] = useState(false);
|
|
@@ -29773,7 +29911,10 @@ var BottlenecksContent = ({
|
|
|
29773
29911
|
if (error?.isRetrying) {
|
|
29774
29912
|
setError(null);
|
|
29775
29913
|
}
|
|
29776
|
-
|
|
29914
|
+
if (videoRef.current?.playbackRate && playbackSpeed !== 1) {
|
|
29915
|
+
videoRef.current.playbackRate(playbackSpeed);
|
|
29916
|
+
}
|
|
29917
|
+
}, [error, playbackSpeed]);
|
|
29777
29918
|
const handleVideoPlay = useCallback(async (player) => {
|
|
29778
29919
|
setIsPlaying(true);
|
|
29779
29920
|
setIsInitialLoading(false);
|
|
@@ -29943,7 +30084,13 @@ var BottlenecksContent = ({
|
|
|
29943
30084
|
player.pause();
|
|
29944
30085
|
}
|
|
29945
30086
|
};
|
|
29946
|
-
const
|
|
30087
|
+
const handlePlaybackSpeedChange = useCallback((speed) => {
|
|
30088
|
+
setPlaybackSpeed(speed);
|
|
30089
|
+
if (videoRef.current?.playbackRate) {
|
|
30090
|
+
videoRef.current.playbackRate(speed);
|
|
30091
|
+
}
|
|
30092
|
+
}, []);
|
|
30093
|
+
useCallback((e) => {
|
|
29947
30094
|
e.stopPropagation();
|
|
29948
30095
|
setIsFullscreen((prev) => !prev);
|
|
29949
30096
|
}, []);
|
|
@@ -30117,12 +30264,7 @@ var BottlenecksContent = ({
|
|
|
30117
30264
|
onLoadedData: handleLoadedData,
|
|
30118
30265
|
onPlaying: handleVideoPlaying,
|
|
30119
30266
|
onLoadingChange: handleVideoLoadingChange,
|
|
30120
|
-
options:
|
|
30121
|
-
// Ensure full height is always visible - no cropping
|
|
30122
|
-
fluid: false,
|
|
30123
|
-
responsive: false,
|
|
30124
|
-
fill: false
|
|
30125
|
-
}
|
|
30267
|
+
options: videoPlayerOptions
|
|
30126
30268
|
}
|
|
30127
30269
|
)
|
|
30128
30270
|
}
|
|
@@ -30183,58 +30325,7 @@ var BottlenecksContent = ({
|
|
|
30183
30325
|
/* @__PURE__ */ jsx("span", { className: "font-medium mr-2", children: getClipTypeLabel(currentVideo) }),
|
|
30184
30326
|
/* @__PURE__ */ jsx("span", { className: "opacity-80 hidden sm:inline", children: currentVideo.description })
|
|
30185
30327
|
] }) })
|
|
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
|
-
] }) })
|
|
30328
|
+
)
|
|
30238
30329
|
] }) }) }) : (
|
|
30239
30330
|
/* Priority 5: Show "no clips found" only if we have counts and there are truly no clips for workspace */
|
|
30240
30331
|
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 +30543,7 @@ var BottlenecksContent = ({
|
|
|
30452
30543
|
onLoadedData: handleLoadedData,
|
|
30453
30544
|
onPlaying: handleVideoPlaying,
|
|
30454
30545
|
onLoadingChange: handleVideoLoadingChange,
|
|
30455
|
-
options:
|
|
30456
|
-
fluid: false,
|
|
30457
|
-
responsive: false,
|
|
30458
|
-
fill: false
|
|
30459
|
-
}
|
|
30546
|
+
options: videoPlayerOptions
|
|
30460
30547
|
}
|
|
30461
30548
|
)
|
|
30462
30549
|
}
|
|
@@ -30464,45 +30551,32 @@ var BottlenecksContent = ({
|
|
|
30464
30551
|
(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
30552
|
!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
30553
|
/* @__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
|
-
|
|
30554
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
30555
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm font-medium", children: "Speed:" }),
|
|
30556
|
+
/* @__PURE__ */ jsxs(
|
|
30557
|
+
"select",
|
|
30470
30558
|
{
|
|
30471
|
-
|
|
30472
|
-
|
|
30473
|
-
|
|
30474
|
-
|
|
30475
|
-
|
|
30476
|
-
|
|
30477
|
-
|
|
30559
|
+
value: playbackSpeed,
|
|
30560
|
+
onChange: (e) => handlePlaybackSpeedChange(Number(e.target.value)),
|
|
30561
|
+
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",
|
|
30562
|
+
"aria-label": "Playback speed",
|
|
30563
|
+
children: [
|
|
30564
|
+
/* @__PURE__ */ jsx("option", { value: "0.25", children: "0.25x" }),
|
|
30565
|
+
/* @__PURE__ */ jsx("option", { value: "0.5", children: "0.5x" }),
|
|
30566
|
+
/* @__PURE__ */ jsx("option", { value: "0.75", children: "0.75x" }),
|
|
30567
|
+
/* @__PURE__ */ jsx("option", { value: "1", children: "1x" }),
|
|
30568
|
+
/* @__PURE__ */ jsx("option", { value: "1.25", children: "1.25x" }),
|
|
30569
|
+
/* @__PURE__ */ jsx("option", { value: "1.5", children: "1.5x" }),
|
|
30570
|
+
/* @__PURE__ */ jsx("option", { value: "1.75", children: "1.75x" }),
|
|
30571
|
+
/* @__PURE__ */ jsx("option", { value: "2", children: "2x" }),
|
|
30572
|
+
/* @__PURE__ */ jsx("option", { value: "3", children: "3x" }),
|
|
30573
|
+
/* @__PURE__ */ jsx("option", { value: "4", children: "4x" }),
|
|
30574
|
+
/* @__PURE__ */ jsx("option", { value: "5", children: "5x" }),
|
|
30575
|
+
/* @__PURE__ */ jsx("option", { value: "10", children: "10x" })
|
|
30576
|
+
]
|
|
30478
30577
|
}
|
|
30479
|
-
)
|
|
30480
|
-
/* @__PURE__ */ jsxs("span", { className: "text-sm font-mono px-2", children: [
|
|
30481
|
-
formatTime2(currentTime),
|
|
30482
|
-
" / ",
|
|
30483
|
-
formatTime2(duration)
|
|
30484
|
-
] })
|
|
30578
|
+
)
|
|
30485
30579
|
] }),
|
|
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
30580
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
30507
30581
|
/* @__PURE__ */ jsx(
|
|
30508
30582
|
"button",
|
|
@@ -37603,26 +37677,26 @@ var SingleVideoStream = ({
|
|
|
37603
37677
|
const hlsStreamUrl = streamUrl || getCameraStreamUrl(workspaceName, baseUrl);
|
|
37604
37678
|
console.log(`Using camera URL for ${workspaceName}: ${hlsStreamUrl}`);
|
|
37605
37679
|
const mergedHlsConfig = { ...DEFAULT_HLS_CONFIG, ...hlsConfig };
|
|
37606
|
-
if (
|
|
37607
|
-
const hls = new
|
|
37680
|
+
if (Hls3.isSupported()) {
|
|
37681
|
+
const hls = new Hls3(mergedHlsConfig);
|
|
37608
37682
|
hlsRef.current = hls;
|
|
37609
|
-
hls.on(
|
|
37683
|
+
hls.on(Hls3.Events.MEDIA_ATTACHED, () => {
|
|
37610
37684
|
console.log("HLS media attached");
|
|
37611
37685
|
hls.loadSource(hlsStreamUrl);
|
|
37612
37686
|
});
|
|
37613
|
-
hls.on(
|
|
37687
|
+
hls.on(Hls3.Events.MANIFEST_PARSED, () => {
|
|
37614
37688
|
console.log("HLS manifest parsed");
|
|
37615
37689
|
attemptPlay(video);
|
|
37616
37690
|
});
|
|
37617
|
-
hls.on(
|
|
37691
|
+
hls.on(Hls3.Events.ERROR, (_, data) => {
|
|
37618
37692
|
if (data.fatal) {
|
|
37619
37693
|
console.error("Fatal HLS error:", data.type, data.details);
|
|
37620
37694
|
switch (data.type) {
|
|
37621
|
-
case
|
|
37695
|
+
case Hls3.ErrorTypes.NETWORK_ERROR:
|
|
37622
37696
|
console.error("Fatal network error encountered");
|
|
37623
37697
|
setError("Network error: Please check your connection");
|
|
37624
37698
|
break;
|
|
37625
|
-
case
|
|
37699
|
+
case Hls3.ErrorTypes.MEDIA_ERROR:
|
|
37626
37700
|
console.error("Fatal media error encountered, trying to recover");
|
|
37627
37701
|
hls.recoverMediaError();
|
|
37628
37702
|
break;
|
|
@@ -42383,9 +42457,9 @@ var MetricCards = memo(({ lineInfo }) => {
|
|
|
42383
42457
|
animate: "animate",
|
|
42384
42458
|
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
42459
|
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%-
|
|
42460
|
+
/* @__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: [
|
|
42461
|
+
/* @__PURE__ */ jsx("h2", { className: "text-sm sm:text-base font-semibold text-gray-700 mb-2 text-center", children: "Line Output" }),
|
|
42462
|
+
/* @__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
42463
|
OutputProgressChart,
|
|
42390
42464
|
{
|
|
42391
42465
|
currentOutput: lineInfo?.metrics.current_output || 0,
|
|
@@ -42393,9 +42467,9 @@ var MetricCards = memo(({ lineInfo }) => {
|
|
|
42393
42467
|
}
|
|
42394
42468
|
) }) })
|
|
42395
42469
|
] }),
|
|
42396
|
-
/* @__PURE__ */ jsxs(motion.div, { variants: itemVariants, className: "bg-white rounded-xl shadow-sm p-3 sm:p-4 overflow-hidden h-[
|
|
42470
|
+
/* @__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
42471
|
/* @__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%-
|
|
42472
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-center h-[calc(100%-2.5rem)]", children: [
|
|
42399
42473
|
/* @__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
42474
|
/* @__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
42475
|
"/ ",
|
|
@@ -42403,9 +42477,9 @@ var MetricCards = memo(({ lineInfo }) => {
|
|
|
42403
42477
|
] })
|
|
42404
42478
|
] })
|
|
42405
42479
|
] }),
|
|
42406
|
-
/* @__PURE__ */ jsxs(motion.div, { variants: itemVariants, className: "bg-white rounded-xl shadow-sm p-3 sm:p-4 overflow-hidden h-[
|
|
42480
|
+
/* @__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
42481
|
/* @__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%-
|
|
42482
|
+
/* @__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
42483
|
lineInfo?.metrics.avg_efficiency.toFixed(1),
|
|
42410
42484
|
"%"
|
|
42411
42485
|
] }) })
|
|
@@ -51923,4 +51997,4 @@ function shuffleArray(array) {
|
|
|
51923
51997
|
return shuffled;
|
|
51924
51998
|
}
|
|
51925
51999
|
|
|
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 };
|
|
52000
|
+
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 };
|