@optifye/dashboard-core 6.6.7 → 6.6.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.mjs CHANGED
@@ -1,12 +1,12 @@
1
- import * as React20 from 'react';
2
- import React20__default, { createContext, useRef, useCallback, useState, useMemo, useEffect, memo, forwardRef, useImperativeHandle, useContext, useLayoutEffect, useId, Children, isValidElement, useInsertionEffect, Fragment as Fragment$1, createElement, Component } from 'react';
1
+ import * as React21 from 'react';
2
+ import React21__default, { createContext, useRef, useCallback, useState, useMemo, useEffect, memo, forwardRef, useImperativeHandle, useContext, useLayoutEffect, useId, Children, isValidElement, useInsertionEffect, Fragment as Fragment$1, createElement, Component } from 'react';
3
3
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
4
4
  import { useRouter } from 'next/router';
5
5
  import { toZonedTime, formatInTimeZone } from 'date-fns-tz';
6
6
  import { subDays, format, parseISO, isValid, formatDistanceToNow, isFuture, isToday } from 'date-fns';
7
7
  import mixpanel from 'mixpanel-browser';
8
8
  import { EventEmitter } from 'events';
9
- import { REALTIME_SUBSCRIBE_STATES, createClient } from '@supabase/supabase-js';
9
+ import { createClient, REALTIME_SUBSCRIBE_STATES } from '@supabase/supabase-js';
10
10
  import Hls2 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';
@@ -153,8 +153,9 @@ var DEFAULT_WORKSPACE_CONFIG = {
153
153
  totalWorkspaces: 42
154
154
  };
155
155
  var DEFAULT_DATE_TIME_CONFIG = {
156
- defaultTimezone: "Asia/Kolkata",
157
- defaultLocale: "en-IN",
156
+ defaultTimezone: "UTC",
157
+ // Should be overridden by database timezone
158
+ defaultLocale: "en-US",
158
159
  dateFormatOptions: {
159
160
  day: "2-digit",
160
161
  month: "short",
@@ -268,14 +269,14 @@ var _getDashboardConfigInstance = () => {
268
269
  }
269
270
  return dashboardConfigInstance;
270
271
  };
271
- var DashboardConfigContext = React20.createContext(void 0);
272
+ var DashboardConfigContext = React21.createContext(void 0);
272
273
  var DashboardProvider = ({ config: userProvidedConfig, children }) => {
273
- const fullConfig = React20.useMemo(() => mergeWithDefaultConfig(userProvidedConfig), [userProvidedConfig]);
274
+ const fullConfig = React21.useMemo(() => mergeWithDefaultConfig(userProvidedConfig), [userProvidedConfig]);
274
275
  _setDashboardConfigInstance(fullConfig);
275
- React20.useEffect(() => {
276
+ React21.useEffect(() => {
276
277
  _setDashboardConfigInstance(fullConfig);
277
278
  }, [fullConfig]);
278
- React20.useEffect(() => {
279
+ React21.useEffect(() => {
279
280
  if (!fullConfig.theme) return;
280
281
  const styleId = "dashboard-core-theme-vars";
281
282
  let styleEl = document.getElementById(styleId);
@@ -301,7 +302,7 @@ var DashboardProvider = ({ config: userProvidedConfig, children }) => {
301
302
  return /* @__PURE__ */ jsx(DashboardConfigContext.Provider, { value: fullConfig, children });
302
303
  };
303
304
  var useDashboardConfig = () => {
304
- const ctx = React20.useContext(DashboardConfigContext);
305
+ const ctx = React21.useContext(DashboardConfigContext);
305
306
  if (!ctx) throw new Error("useDashboardConfig must be used within a DashboardProvider");
306
307
  return ctx;
307
308
  };
@@ -426,7 +427,7 @@ var memoizedOutputArrayAggregation = createMemoizedFunction(
426
427
  },
427
428
  (arrays) => arrays.map((arr) => arr.length).join("-")
428
429
  );
429
- var getOperationalDate = (timezone = "Asia/Kolkata", date = /* @__PURE__ */ new Date(), shiftStartTime = "06:00") => {
430
+ var getOperationalDate = (timezone, date = /* @__PURE__ */ new Date(), shiftStartTime = "06:00") => {
430
431
  const zonedDate = toZonedTime(date, timezone);
431
432
  const hours = zonedDate.getHours();
432
433
  const [startHour = 6] = shiftStartTime.split(":").map(Number);
@@ -1888,7 +1889,7 @@ var workspaceService = {
1888
1889
  }
1889
1890
  const totalDayOutput = outputWorkspaces.reduce((sum, ws) => sum + (ws.action_total_day_output || 0), 0);
1890
1891
  const totalPPH = outputWorkspaces.reduce((sum, ws) => sum + (ws.action_pph_threshold || 0), 0);
1891
- const operationalDate = getOperationalDate(defaultTimezone);
1892
+ const operationalDate = getOperationalDate(defaultTimezone || "UTC");
1892
1893
  const thresholdData = {
1893
1894
  factory_id: configuredFactoryId,
1894
1895
  line_id: lineId,
@@ -4022,7 +4023,7 @@ var S3ClipsSupabaseService = class {
4022
4023
  description: this.getDescriptionFromClipType(clip.clip_type_name),
4023
4024
  type: clip.clip_type_name,
4024
4025
  originalUri: `clips:${clip.clip_id}`,
4025
- cycle_time_seconds: clip.metadata?.request?.metadata?.cycle_time ? clip.metadata.request.metadata.cycle_time / 20 : void 0,
4026
+ cycle_time_seconds: clip.metadata?.request?.metadata?.cycle_time ? clip.metadata.request.metadata.cycle_time / (clip.metadata?.playlist?.fps || 20) : void 0,
4026
4027
  creation_timestamp: clip.created_at,
4027
4028
  percentile: clip.cycle_time_percentile || clip.idle_time_percentile
4028
4029
  }));
@@ -4528,6 +4529,154 @@ var createSupervisorService = (supabase) => {
4528
4529
  var simulateApiDelay = (ms = 1e3) => {
4529
4530
  return new Promise((resolve) => setTimeout(resolve, ms));
4530
4531
  };
4532
+ var TimezoneService = class _TimezoneService {
4533
+ constructor() {
4534
+ this.timezoneCache = /* @__PURE__ */ new Map();
4535
+ this.supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL || "";
4536
+ this.supabaseAnonKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY || "";
4537
+ }
4538
+ static getInstance() {
4539
+ if (!_TimezoneService.instance) {
4540
+ _TimezoneService.instance = new _TimezoneService();
4541
+ }
4542
+ return _TimezoneService.instance;
4543
+ }
4544
+ /**
4545
+ * Fetch timezone for a specific line from Supabase
4546
+ */
4547
+ async getTimezoneForLine(lineId, defaultTimezone = "Asia/Kolkata") {
4548
+ if (this.timezoneCache.has(lineId)) {
4549
+ return this.timezoneCache.get(lineId);
4550
+ }
4551
+ try {
4552
+ const supabase = createClient(this.supabaseUrl, this.supabaseAnonKey);
4553
+ const { data, error } = await supabase.from("line_operating_hours").select("timezone").eq("line_id", lineId).order("created_at", { ascending: false }).limit(1).single();
4554
+ if (error) {
4555
+ console.warn(`Failed to fetch timezone for line ${lineId}:`, error);
4556
+ return defaultTimezone;
4557
+ }
4558
+ if (data?.timezone) {
4559
+ this.timezoneCache.set(lineId, data.timezone);
4560
+ return data.timezone;
4561
+ }
4562
+ return defaultTimezone;
4563
+ } catch (error) {
4564
+ console.error("Error fetching timezone:", error);
4565
+ return defaultTimezone;
4566
+ }
4567
+ }
4568
+ /**
4569
+ * Fetch timezone for a company's factory
4570
+ */
4571
+ async getTimezoneForCompany(companyId, defaultTimezone = "Asia/Kolkata") {
4572
+ const cacheKey = `company-${companyId}`;
4573
+ if (this.timezoneCache.has(cacheKey)) {
4574
+ return this.timezoneCache.get(cacheKey);
4575
+ }
4576
+ try {
4577
+ const supabase = createClient(this.supabaseUrl, this.supabaseAnonKey);
4578
+ const { data, error } = await supabase.from("line_operating_hours").select(`
4579
+ timezone,
4580
+ line:lines!inner(
4581
+ company_id
4582
+ )
4583
+ `).eq("lines.company_id", companyId).order("created_at", { ascending: false }).limit(1);
4584
+ if (error) {
4585
+ console.warn(`Failed to fetch timezone for company ${companyId}:`, error);
4586
+ return defaultTimezone;
4587
+ }
4588
+ if (data?.[0]?.timezone) {
4589
+ this.timezoneCache.set(cacheKey, data[0].timezone);
4590
+ return data[0].timezone;
4591
+ }
4592
+ return defaultTimezone;
4593
+ } catch (error) {
4594
+ console.error("Error fetching company timezone:", error);
4595
+ return defaultTimezone;
4596
+ }
4597
+ }
4598
+ /**
4599
+ * Fetch timezone for a workspace
4600
+ */
4601
+ async getTimezoneForWorkspace(workspaceId, defaultTimezone = "Asia/Kolkata") {
4602
+ const cacheKey = `workspace-${workspaceId}`;
4603
+ if (this.timezoneCache.has(cacheKey)) {
4604
+ return this.timezoneCache.get(cacheKey);
4605
+ }
4606
+ try {
4607
+ const supabase = createClient(this.supabaseUrl, this.supabaseAnonKey);
4608
+ const { data: workspaceData, error: workspaceError } = await supabase.from("workspaces").select("line_id").eq("id", workspaceId).single();
4609
+ if (workspaceError) {
4610
+ console.warn(`Failed to fetch workspace ${workspaceId}:`, workspaceError);
4611
+ return defaultTimezone;
4612
+ }
4613
+ if (workspaceData?.line_id) {
4614
+ return this.getTimezoneForLine(workspaceData.line_id, defaultTimezone);
4615
+ }
4616
+ const { data: cameraData, error: cameraError } = await supabase.from("cameras").select("line_id").eq("workspace_id", workspaceId).limit(1).single();
4617
+ if (!cameraError && cameraData?.line_id) {
4618
+ return this.getTimezoneForLine(cameraData.line_id, defaultTimezone);
4619
+ }
4620
+ return defaultTimezone;
4621
+ } catch (error) {
4622
+ console.error("Error fetching workspace timezone:", error);
4623
+ return defaultTimezone;
4624
+ }
4625
+ }
4626
+ /**
4627
+ * Batch fetch timezones for multiple lines
4628
+ */
4629
+ async getTimezonesForLines(lineIds, defaultTimezone = "Asia/Kolkata") {
4630
+ const result = /* @__PURE__ */ new Map();
4631
+ const uncachedLineIds = lineIds.filter((id3) => !this.timezoneCache.has(id3));
4632
+ if (uncachedLineIds.length === 0) {
4633
+ lineIds.forEach((id3) => {
4634
+ result.set(id3, this.timezoneCache.get(id3) || defaultTimezone);
4635
+ });
4636
+ return result;
4637
+ }
4638
+ try {
4639
+ const supabase = createClient(this.supabaseUrl, this.supabaseAnonKey);
4640
+ const { data, error } = await supabase.from("line_operating_hours").select("line_id, timezone").in("line_id", uncachedLineIds).order("created_at", { ascending: false });
4641
+ if (error) {
4642
+ console.warn("Failed to fetch timezones for lines:", error);
4643
+ lineIds.forEach((id3) => result.set(id3, defaultTimezone));
4644
+ return result;
4645
+ }
4646
+ const timezoneMap = /* @__PURE__ */ new Map();
4647
+ data?.forEach((item) => {
4648
+ if (!timezoneMap.has(item.line_id)) {
4649
+ timezoneMap.set(item.line_id, item.timezone);
4650
+ this.timezoneCache.set(item.line_id, item.timezone);
4651
+ }
4652
+ });
4653
+ lineIds.forEach((id3) => {
4654
+ const timezone = this.timezoneCache.get(id3) || timezoneMap.get(id3) || defaultTimezone;
4655
+ result.set(id3, timezone);
4656
+ });
4657
+ return result;
4658
+ } catch (error) {
4659
+ console.error("Error batch fetching timezones:", error);
4660
+ lineIds.forEach((id3) => result.set(id3, defaultTimezone));
4661
+ return result;
4662
+ }
4663
+ }
4664
+ /**
4665
+ * Clear timezone cache
4666
+ */
4667
+ clearCache() {
4668
+ this.timezoneCache.clear();
4669
+ }
4670
+ /**
4671
+ * Clear specific entry from cache
4672
+ */
4673
+ clearCacheEntry(key) {
4674
+ this.timezoneCache.delete(key);
4675
+ this.timezoneCache.delete(`company-${key}`);
4676
+ this.timezoneCache.delete(`workspace-${key}`);
4677
+ }
4678
+ };
4679
+ var timezoneService = TimezoneService.getInstance();
4531
4680
  var AuthContext = createContext({
4532
4681
  session: null,
4533
4682
  user: null,
@@ -5001,18 +5150,96 @@ var useClipFilter = () => {
5001
5150
  }
5002
5151
  return context;
5003
5152
  };
5153
+ var TimezoneContext = createContext(void 0);
5154
+ function TimezoneProvider({
5155
+ children,
5156
+ workspaceId: propWorkspaceId,
5157
+ lineId: propLineId,
5158
+ companyId: propCompanyId,
5159
+ fallbackTimezone = "Asia/Kolkata"
5160
+ // Last resort fallback ONLY
5161
+ }) {
5162
+ const dashboardConfig = useDashboardConfig();
5163
+ const workspaceConfig = useWorkspaceConfig();
5164
+ const [timezone, setTimezone] = useState(fallbackTimezone);
5165
+ const [isLoading, setIsLoading] = useState(true);
5166
+ const [error, setError] = useState(null);
5167
+ const workspaceId = propWorkspaceId || (workspaceConfig && typeof workspaceConfig === "object" && "id" in workspaceConfig ? workspaceConfig.id : void 0);
5168
+ const lineId = propLineId;
5169
+ const companyId = propCompanyId || (dashboardConfig && typeof dashboardConfig === "object" && "company" in dashboardConfig ? dashboardConfig.company?.id : void 0);
5170
+ const fetchTimezone = async () => {
5171
+ setIsLoading(true);
5172
+ setError(null);
5173
+ try {
5174
+ let fetchedTimezone = null;
5175
+ if (lineId) {
5176
+ console.log(`[TimezoneContext] Fetching timezone for line: ${lineId}`);
5177
+ fetchedTimezone = await timezoneService.getTimezoneForLine(lineId, fallbackTimezone);
5178
+ } else if (workspaceId) {
5179
+ console.log(`[TimezoneContext] Fetching timezone for workspace: ${workspaceId}`);
5180
+ fetchedTimezone = await timezoneService.getTimezoneForWorkspace(workspaceId, fallbackTimezone);
5181
+ } else if (companyId) {
5182
+ console.log(`[TimezoneContext] Fetching timezone for company: ${companyId}`);
5183
+ fetchedTimezone = await timezoneService.getTimezoneForCompany(companyId, fallbackTimezone);
5184
+ } else {
5185
+ console.warn("[TimezoneContext] No ID available to fetch timezone, using fallback");
5186
+ fetchedTimezone = fallbackTimezone;
5187
+ }
5188
+ console.log(`[TimezoneContext] Timezone resolved to: ${fetchedTimezone}`);
5189
+ if (fetchedTimezone === fallbackTimezone) {
5190
+ console.warn(`[TimezoneContext] WARNING: Using fallback timezone ${fallbackTimezone}. This should not happen in production!`);
5191
+ }
5192
+ setTimezone(fetchedTimezone);
5193
+ } catch (err) {
5194
+ console.error("[TimezoneContext] Error fetching timezone:", err);
5195
+ setError(err instanceof Error ? err : new Error("Failed to fetch timezone"));
5196
+ console.error(`[TimezoneContext] CRITICAL: Failed to fetch timezone from database, falling back to ${fallbackTimezone}`);
5197
+ setTimezone(fallbackTimezone);
5198
+ } finally {
5199
+ setIsLoading(false);
5200
+ }
5201
+ };
5202
+ useEffect(() => {
5203
+ fetchTimezone();
5204
+ }, [lineId, workspaceId, companyId]);
5205
+ const value = {
5206
+ timezone,
5207
+ isLoading,
5208
+ error,
5209
+ refetch: fetchTimezone
5210
+ };
5211
+ return /* @__PURE__ */ jsx(TimezoneContext.Provider, { value, children });
5212
+ }
5213
+ function useTimezoneContext() {
5214
+ const context = useContext(TimezoneContext);
5215
+ if (!context) {
5216
+ throw new Error("useTimezoneContext must be used within TimezoneProvider");
5217
+ }
5218
+ return context;
5219
+ }
5220
+ function useAppTimezone() {
5221
+ const { timezone } = useTimezoneContext();
5222
+ return timezone;
5223
+ }
5224
+ function withTimezone(Component3) {
5225
+ return function WithTimezoneComponent(props) {
5226
+ const timezone = useAppTimezone();
5227
+ return /* @__PURE__ */ jsx(Component3, { ...props, timezone });
5228
+ };
5229
+ }
5004
5230
  var DEFAULT_COMPANY_ID = "default-company-id";
5005
5231
  var useWorkspaceMetrics = (workspaceId) => {
5006
5232
  const supabase = useSupabase();
5007
5233
  const entityConfig = useEntityConfig();
5008
5234
  useDatabaseConfig();
5009
5235
  const dateTimeConfig = useDateTimeConfig();
5236
+ const timezone = useAppTimezone();
5010
5237
  const [workspaceMetrics, setWorkspaceMetrics] = useState(null);
5011
5238
  const [isLoading, setIsLoading] = useState(true);
5012
5239
  const [error, setError] = useState(null);
5013
5240
  const fetchWorkspaceMetrics = useCallback(async () => {
5014
5241
  try {
5015
- const operationalDate = getOperationalDate(dateTimeConfig.defaultTimezone);
5242
+ const operationalDate = getOperationalDate(timezone || dateTimeConfig.defaultTimezone || "UTC");
5016
5243
  const { data, error: fetchError } = await supabase.from("overview_workspace_metrics").select("*").eq("workspace_id", workspaceId).eq("date", operationalDate).single();
5017
5244
  if (fetchError) throw fetchError;
5018
5245
  setWorkspaceMetrics(data);
@@ -5025,7 +5252,7 @@ var useWorkspaceMetrics = (workspaceId) => {
5025
5252
  }, [supabase, workspaceId, dateTimeConfig.defaultTimezone]);
5026
5253
  useEffect(() => {
5027
5254
  let channels = [];
5028
- const operationalDate = getOperationalDate(dateTimeConfig.defaultTimezone);
5255
+ const operationalDate = getOperationalDate(timezone || dateTimeConfig.defaultTimezone || "UTC");
5029
5256
  const setupSubscriptions = () => {
5030
5257
  const companyId = entityConfig.companyId || DEFAULT_COMPANY_ID;
5031
5258
  const metricsTablePrefix = getMetricsTablePrefix();
@@ -5076,12 +5303,13 @@ var useWorkspaceMetrics = (workspaceId) => {
5076
5303
  var useLineMetrics = (lineId) => {
5077
5304
  const supabase = useSupabase();
5078
5305
  const dateTimeConfig = useDateTimeConfig();
5306
+ const timezone = useAppTimezone();
5079
5307
  const [lineMetrics, setLineMetrics] = useState(null);
5080
5308
  const [isLoading, setIsLoading] = useState(true);
5081
5309
  const [error, setError] = useState(null);
5082
5310
  const fetchLineMetrics = useCallback(async () => {
5083
5311
  try {
5084
- const operationalDate = getOperationalDate(dateTimeConfig.defaultTimezone);
5312
+ const operationalDate = getOperationalDate(timezone || dateTimeConfig.defaultTimezone || "UTC");
5085
5313
  const { data, error: fetchError } = await supabase.from("overview_line_metrics").select("*").eq("line_id", lineId).eq("date", operationalDate).single();
5086
5314
  if (fetchError) throw fetchError;
5087
5315
  setLineMetrics(data);
@@ -5094,7 +5322,7 @@ var useLineMetrics = (lineId) => {
5094
5322
  }, [supabase, lineId, dateTimeConfig.defaultTimezone]);
5095
5323
  useEffect(() => {
5096
5324
  let channels = [];
5097
- const operationalDate = getOperationalDate(dateTimeConfig.defaultTimezone);
5325
+ const operationalDate = getOperationalDate(timezone || dateTimeConfig.defaultTimezone || "UTC");
5098
5326
  const setupSubscriptions = () => {
5099
5327
  const lineMetricsChannel = supabase.channel("line-base-metrics").on(
5100
5328
  "postgres_changes",
@@ -5729,7 +5957,7 @@ var useWorkspaceDetailedMetrics = (workspaceId, date, shiftId) => {
5729
5957
  return;
5730
5958
  }
5731
5959
  const channels = [];
5732
- const operationalDate = date || getOperationalDate();
5960
+ const operationalDate = date || getOperationalDate(defaultTimezone || "UTC");
5733
5961
  const currentShift = getCurrentShift(defaultTimezone, shiftConfig);
5734
5962
  const queryShiftId = shiftId ?? currentShift.shiftId;
5735
5963
  const metricsChannel = supabase.channel(`workspace-metrics-${workspaceId}`).on(
@@ -5833,6 +6061,7 @@ var useLineWorkspaceMetrics = (lineId, options) => {
5833
6061
  const databaseConfig = useDatabaseConfig();
5834
6062
  const dateTimeConfig = useDateTimeConfig();
5835
6063
  const shiftConfig = useShiftConfig();
6064
+ const timezone = useAppTimezone();
5836
6065
  const supabase = useSupabase();
5837
6066
  const [workspaces, setWorkspaces] = useState([]);
5838
6067
  const [loading, setLoading] = useState(true);
@@ -5846,8 +6075,8 @@ var useLineWorkspaceMetrics = (lineId, options) => {
5846
6075
  return options?.initialShiftId !== void 0 ? options.initialShiftId : currentShift.shiftId;
5847
6076
  }, [options?.initialShiftId, dateTimeConfig.defaultTimezone, shiftConfig]);
5848
6077
  const queryDate = useMemo(() => {
5849
- return options?.initialDate || getOperationalDate(dateTimeConfig.defaultTimezone);
5850
- }, [options?.initialDate, dateTimeConfig.defaultTimezone]);
6078
+ return options?.initialDate || getOperationalDate(timezone || dateTimeConfig.defaultTimezone || "UTC");
6079
+ }, [options?.initialDate, timezone, dateTimeConfig.defaultTimezone]);
5851
6080
  const metricsTable = useMemo(() => {
5852
6081
  const companyId = entityConfig.companyId;
5853
6082
  if (!companyId) return "";
@@ -6634,7 +6863,8 @@ var useRealtimeLineMetrics = ({
6634
6863
  () => urlShiftId !== void 0 ? urlShiftId : currentShift.shiftId,
6635
6864
  [urlShiftId, currentShift.shiftId]
6636
6865
  );
6637
- const date = useMemo(() => urlDate || getOperationalDate(dateTimeConfig.defaultTimezone), [urlDate, dateTimeConfig.defaultTimezone]);
6866
+ const timezone = useAppTimezone();
6867
+ const date = useMemo(() => urlDate || getOperationalDate(timezone || dateTimeConfig.defaultTimezone || "UTC"), [urlDate, timezone, dateTimeConfig.defaultTimezone]);
6638
6868
  const fetchData = useCallback(async () => {
6639
6869
  try {
6640
6870
  if (!lineIdRef.current || isFetchingRef.current) return;
@@ -6874,7 +7104,7 @@ var useRealtimeLineMetrics = ({
6874
7104
  if (process.env.NODE_ENV === "development") {
6875
7105
  console.log("Line metrics update received:", payloadData);
6876
7106
  }
6877
- const currentDate = urlDate || getOperationalDate(dateTimeConfig.defaultTimezone);
7107
+ const currentDate = urlDate || getOperationalDate(timezone || dateTimeConfig.defaultTimezone || "UTC");
6878
7108
  if (payloadData?.date === currentDate && payloadData?.shift_id === shiftId) {
6879
7109
  queueUpdate();
6880
7110
  }
@@ -6897,7 +7127,7 @@ var useRealtimeLineMetrics = ({
6897
7127
  if (process.env.NODE_ENV === "development") {
6898
7128
  console.log(`${metricsTablePrefix} update received:`, payloadData);
6899
7129
  }
6900
- const currentDate = urlDate || getOperationalDate(dateTimeConfig.defaultTimezone);
7130
+ const currentDate = urlDate || getOperationalDate(timezone || dateTimeConfig.defaultTimezone || "UTC");
6901
7131
  if (payloadData?.date === currentDate && payloadData?.shift_id === shiftId) {
6902
7132
  queueUpdate();
6903
7133
  }
@@ -8212,6 +8442,7 @@ var useAllWorkspaceMetrics = (options) => {
8212
8442
  const databaseConfig = useDatabaseConfig();
8213
8443
  const dateTimeConfig = useDateTimeConfig();
8214
8444
  const shiftConfig = useShiftConfig();
8445
+ const timezone = useAppTimezone();
8215
8446
  const supabase = useSupabase();
8216
8447
  const [workspaces, setWorkspaces] = useState([]);
8217
8448
  const [loading, setLoading] = useState(true);
@@ -8225,8 +8456,8 @@ var useAllWorkspaceMetrics = (options) => {
8225
8456
  return options?.initialShiftId !== void 0 ? options.initialShiftId : currentShift.shiftId;
8226
8457
  }, [options?.initialShiftId, dateTimeConfig.defaultTimezone, shiftConfig]);
8227
8458
  const queryDate = useMemo(() => {
8228
- return options?.initialDate || getOperationalDate(dateTimeConfig.defaultTimezone);
8229
- }, [options?.initialDate, dateTimeConfig.defaultTimezone]);
8459
+ return options?.initialDate || getOperationalDate(timezone || dateTimeConfig.defaultTimezone || "UTC");
8460
+ }, [options?.initialDate, timezone, dateTimeConfig.defaultTimezone]);
8230
8461
  const metricsTable = useMemo(() => {
8231
8462
  const companyId = entityConfig.companyId;
8232
8463
  if (!companyId) return "";
@@ -12231,7 +12462,7 @@ var MotionConfigContext = createContext({
12231
12462
  });
12232
12463
 
12233
12464
  // ../../node_modules/framer-motion/dist/es/components/AnimatePresence/PopChild.mjs
12234
- var PopChildMeasure = class extends React20.Component {
12465
+ var PopChildMeasure = class extends React21.Component {
12235
12466
  getSnapshotBeforeUpdate(prevProps) {
12236
12467
  const element = this.props.childRef.current;
12237
12468
  if (element && prevProps.isPresent && !this.props.isPresent) {
@@ -12286,7 +12517,7 @@ function PopChild({ children, isPresent }) {
12286
12517
  document.head.removeChild(style);
12287
12518
  };
12288
12519
  }, [isPresent]);
12289
- return jsx(PopChildMeasure, { isPresent, childRef: ref, sizeRef: size, children: React20.cloneElement(children, { ref }) });
12520
+ return jsx(PopChildMeasure, { isPresent, childRef: ref, sizeRef: size, children: React21.cloneElement(children, { ref }) });
12290
12521
  }
12291
12522
 
12292
12523
  // ../../node_modules/framer-motion/dist/es/components/AnimatePresence/PresenceChild.mjs
@@ -12323,7 +12554,7 @@ var PresenceChild = ({ children, initial, isPresent, onExitComplete, custom, pre
12323
12554
  useMemo(() => {
12324
12555
  presenceChildren.forEach((_, key) => presenceChildren.set(key, false));
12325
12556
  }, [isPresent]);
12326
- React20.useEffect(() => {
12557
+ React21.useEffect(() => {
12327
12558
  !isPresent && !presenceChildren.size && onExitComplete && onExitComplete();
12328
12559
  }, [isPresent]);
12329
12560
  if (mode === "popLayout") {
@@ -19607,7 +19838,7 @@ var LoadingPage = ({
19607
19838
  subMessage = "Please wait while we prepare your data",
19608
19839
  className
19609
19840
  }) => {
19610
- React20__default.useEffect(() => {
19841
+ React21__default.useEffect(() => {
19611
19842
  console.log("LoadingPage rendered with message:", message);
19612
19843
  const timeout = setTimeout(() => {
19613
19844
  console.warn("LoadingPage has been visible for more than 8 seconds. This might indicate an issue.");
@@ -19648,15 +19879,15 @@ var withAuth = (WrappedComponent2, options) => {
19648
19879
  requireAuth: true,
19649
19880
  ...options
19650
19881
  };
19651
- const WithAuthComponent = React20.memo(function WithAuthComponent2(props) {
19882
+ const WithAuthComponent = React21.memo(function WithAuthComponent2(props) {
19652
19883
  const { session, loading, error } = useAuth();
19653
19884
  const router = useRouter();
19654
- React20.useEffect(() => {
19885
+ React21.useEffect(() => {
19655
19886
  if (process.env.NODE_ENV === "development" && process.env.DEBUG_AUTH === "true") {
19656
19887
  console.log("withAuth state:", { loading, hasSession: !!session, requireAuth: defaultOptions.requireAuth });
19657
19888
  }
19658
19889
  }, [session, loading]);
19659
- React20.useEffect(() => {
19890
+ React21.useEffect(() => {
19660
19891
  if (!loading && defaultOptions.requireAuth && !session && !error) {
19661
19892
  console.log("Redirecting to login from withAuth");
19662
19893
  router.replace(defaultOptions.redirectTo);
@@ -20032,11 +20263,11 @@ var BarChartComponent = ({
20032
20263
  aspect = 2,
20033
20264
  ...restOfChartProps
20034
20265
  }) => {
20035
- const containerRef = React20__default.useRef(null);
20036
- const [containerReady, setContainerReady] = React20__default.useState(false);
20266
+ const containerRef = React21__default.useRef(null);
20267
+ const [containerReady, setContainerReady] = React21__default.useState(false);
20037
20268
  const themeConfig = useThemeConfig();
20038
20269
  const { formatNumber } = useFormatNumber();
20039
- React20__default.useEffect(() => {
20270
+ React21__default.useEffect(() => {
20040
20271
  const checkContainerDimensions = () => {
20041
20272
  if (containerRef.current) {
20042
20273
  const rect = containerRef.current.getBoundingClientRect();
@@ -20134,7 +20365,7 @@ var BarChartComponent = ({
20134
20365
  }
20135
20366
  return /* @__PURE__ */ jsx("div", { className: clsx("w-full", className), children: chartContent });
20136
20367
  };
20137
- var BarChart = React20__default.memo(BarChartComponent, (prevProps, nextProps) => {
20368
+ var BarChart = React21__default.memo(BarChartComponent, (prevProps, nextProps) => {
20138
20369
  if (prevProps.xAxisDataKey !== nextProps.xAxisDataKey || prevProps.xAxisLabel !== nextProps.xAxisLabel || prevProps.yAxisLabel !== nextProps.yAxisLabel || prevProps.yAxisUnit !== nextProps.yAxisUnit || prevProps.layout !== nextProps.layout || prevProps.className !== nextProps.className || prevProps.showGrid !== nextProps.showGrid || prevProps.showLegend !== nextProps.showLegend || prevProps.showTooltip !== nextProps.showTooltip || prevProps.responsive !== nextProps.responsive || prevProps.aspect !== nextProps.aspect) {
20139
20370
  return false;
20140
20371
  }
@@ -20182,11 +20413,11 @@ var LineChartComponent = ({
20182
20413
  aspect = 2,
20183
20414
  ...restOfChartProps
20184
20415
  }) => {
20185
- const containerRef = React20__default.useRef(null);
20186
- const [containerReady, setContainerReady] = React20__default.useState(false);
20416
+ const containerRef = React21__default.useRef(null);
20417
+ const [containerReady, setContainerReady] = React21__default.useState(false);
20187
20418
  const themeConfig = useThemeConfig();
20188
20419
  const { formatNumber } = useFormatNumber();
20189
- React20__default.useEffect(() => {
20420
+ React21__default.useEffect(() => {
20190
20421
  const checkContainerDimensions = () => {
20191
20422
  if (containerRef.current) {
20192
20423
  const rect = containerRef.current.getBoundingClientRect();
@@ -20285,7 +20516,7 @@ var LineChartComponent = ({
20285
20516
  }
20286
20517
  return /* @__PURE__ */ jsx("div", { className: clsx("w-full", className), children: chartContent });
20287
20518
  };
20288
- var LineChart = React20__default.memo(LineChartComponent, (prevProps, nextProps) => {
20519
+ var LineChart = React21__default.memo(LineChartComponent, (prevProps, nextProps) => {
20289
20520
  if (prevProps.xAxisDataKey !== nextProps.xAxisDataKey || prevProps.xAxisLabel !== nextProps.xAxisLabel || prevProps.yAxisLabel !== nextProps.yAxisLabel || prevProps.yAxisUnit !== nextProps.yAxisUnit || prevProps.className !== nextProps.className || prevProps.showGrid !== nextProps.showGrid || prevProps.showLegend !== nextProps.showLegend || prevProps.showTooltip !== nextProps.showTooltip || prevProps.responsive !== nextProps.responsive || prevProps.aspect !== nextProps.aspect || JSON.stringify(prevProps.yAxisDomain) !== JSON.stringify(nextProps.yAxisDomain)) {
20290
20521
  return false;
20291
20522
  }
@@ -20362,7 +20593,7 @@ var OutputProgressChartComponent = ({
20362
20593
  ] }) })
20363
20594
  ] }) });
20364
20595
  };
20365
- var OutputProgressChart = React20__default.memo(OutputProgressChartComponent);
20596
+ var OutputProgressChart = React21__default.memo(OutputProgressChartComponent);
20366
20597
  OutputProgressChart.displayName = "OutputProgressChart";
20367
20598
  var LargeOutputProgressChart = ({
20368
20599
  currentOutput,
@@ -20478,7 +20709,7 @@ var CycleTimeChartComponent = ({
20478
20709
  }
20479
20710
  ) }) });
20480
20711
  };
20481
- var CycleTimeChart = React20__default.memo(CycleTimeChartComponent, (prevProps, nextProps) => {
20712
+ var CycleTimeChart = React21__default.memo(CycleTimeChartComponent, (prevProps, nextProps) => {
20482
20713
  if (prevProps.className !== nextProps.className) {
20483
20714
  return false;
20484
20715
  }
@@ -20504,8 +20735,8 @@ var CycleTimeOverTimeChart = ({
20504
20735
  className = ""
20505
20736
  }) => {
20506
20737
  const MAX_DATA_POINTS = 40;
20507
- const containerRef = React20__default.useRef(null);
20508
- const [containerReady, setContainerReady] = React20__default.useState(false);
20738
+ const containerRef = React21__default.useRef(null);
20739
+ const [containerReady, setContainerReady] = React21__default.useState(false);
20509
20740
  const getHourFromTimeString = (timeStr) => {
20510
20741
  const [hours, minutes] = timeStr.split(":");
20511
20742
  return parseInt(hours);
@@ -20516,10 +20747,10 @@ var CycleTimeOverTimeChart = ({
20516
20747
  };
20517
20748
  const displayData = getDisplayData(data);
20518
20749
  const DURATION = displayData.length;
20519
- const [animatedData, setAnimatedData] = React20__default.useState(Array(DURATION).fill(0));
20520
- const prevDataRef = React20__default.useRef(Array(DURATION).fill(0));
20521
- const animationFrameRef = React20__default.useRef(null);
20522
- const animateToNewData = React20__default.useCallback((targetData) => {
20750
+ const [animatedData, setAnimatedData] = React21__default.useState(Array(DURATION).fill(0));
20751
+ const prevDataRef = React21__default.useRef(Array(DURATION).fill(0));
20752
+ const animationFrameRef = React21__default.useRef(null);
20753
+ const animateToNewData = React21__default.useCallback((targetData) => {
20523
20754
  const startData = [...prevDataRef.current];
20524
20755
  const startTime = performance.now();
20525
20756
  const duration = 1200;
@@ -20549,7 +20780,7 @@ var CycleTimeOverTimeChart = ({
20549
20780
  }
20550
20781
  animationFrameRef.current = requestAnimationFrame(animate);
20551
20782
  }, []);
20552
- React20__default.useEffect(() => {
20783
+ React21__default.useEffect(() => {
20553
20784
  if (JSON.stringify(data) !== JSON.stringify(prevDataRef.current)) {
20554
20785
  const processedData = getDisplayData(data);
20555
20786
  animateToNewData(processedData);
@@ -20560,7 +20791,7 @@ var CycleTimeOverTimeChart = ({
20560
20791
  }
20561
20792
  };
20562
20793
  }, [data, animateToNewData]);
20563
- React20__default.useEffect(() => {
20794
+ React21__default.useEffect(() => {
20564
20795
  const checkContainerDimensions = () => {
20565
20796
  if (containerRef.current) {
20566
20797
  const rect = containerRef.current.getBoundingClientRect();
@@ -20803,7 +21034,7 @@ var CycleTimeOverTimeChart = ({
20803
21034
  }
20804
21035
  );
20805
21036
  };
20806
- var Card = React20.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
21037
+ var Card = React21.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
20807
21038
  "div",
20808
21039
  {
20809
21040
  ref,
@@ -20815,7 +21046,7 @@ var Card = React20.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */
20815
21046
  }
20816
21047
  ));
20817
21048
  Card.displayName = "Card";
20818
- var CardHeader = React20.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
21049
+ var CardHeader = React21.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
20819
21050
  "div",
20820
21051
  {
20821
21052
  ref,
@@ -20824,7 +21055,7 @@ var CardHeader = React20.forwardRef(({ className, ...props }, ref) => /* @__PURE
20824
21055
  }
20825
21056
  ));
20826
21057
  CardHeader.displayName = "CardHeader";
20827
- var CardTitle = React20.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
21058
+ var CardTitle = React21.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
20828
21059
  "h3",
20829
21060
  {
20830
21061
  ref,
@@ -20836,7 +21067,7 @@ var CardTitle = React20.forwardRef(({ className, ...props }, ref) => /* @__PURE_
20836
21067
  }
20837
21068
  ));
20838
21069
  CardTitle.displayName = "CardTitle";
20839
- var CardDescription = React20.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
21070
+ var CardDescription = React21.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
20840
21071
  "p",
20841
21072
  {
20842
21073
  ref,
@@ -20845,9 +21076,9 @@ var CardDescription = React20.forwardRef(({ className, ...props }, ref) => /* @_
20845
21076
  }
20846
21077
  ));
20847
21078
  CardDescription.displayName = "CardDescription";
20848
- var CardContent = React20.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("p-6 pt-0", className), ...props }));
21079
+ var CardContent = React21.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("p-6 pt-0", className), ...props }));
20849
21080
  CardContent.displayName = "CardContent";
20850
- var CardFooter = React20.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
21081
+ var CardFooter = React21.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
20851
21082
  "div",
20852
21083
  {
20853
21084
  ref,
@@ -20923,7 +21154,7 @@ var buttonVariants = cva(
20923
21154
  }
20924
21155
  }
20925
21156
  );
20926
- var Button = React20.forwardRef(
21157
+ var Button = React21.forwardRef(
20927
21158
  ({ className, variant, size, asChild = false, ...props }, ref) => {
20928
21159
  const Comp = asChild ? Slot : "button";
20929
21160
  return /* @__PURE__ */ jsx(
@@ -20946,8 +21177,8 @@ var HourlyOutputChartComponent = ({
20946
21177
  idleTimeHourly,
20947
21178
  className = ""
20948
21179
  }) => {
20949
- const containerRef = React20__default.useRef(null);
20950
- const [containerReady, setContainerReady] = React20__default.useState(false);
21180
+ const containerRef = React21__default.useRef(null);
21181
+ const [containerReady, setContainerReady] = React21__default.useState(false);
20951
21182
  const getTimeFromTimeString = (timeStr) => {
20952
21183
  const [hours, minutes] = timeStr.split(":");
20953
21184
  const hour = parseInt(hours);
@@ -20956,7 +21187,7 @@ var HourlyOutputChartComponent = ({
20956
21187
  return { hour, minute, decimalHour };
20957
21188
  };
20958
21189
  const shiftStartTime = getTimeFromTimeString(shiftStart);
20959
- const { shiftDuration, shiftEndTime, hasPartialLastHour } = React20__default.useMemo(() => {
21190
+ const { shiftDuration, shiftEndTime, hasPartialLastHour } = React21__default.useMemo(() => {
20960
21191
  console.log("[HourlyOutputChart] Calculating shift duration with:", {
20961
21192
  shiftStart,
20962
21193
  shiftEnd,
@@ -20991,12 +21222,12 @@ var HourlyOutputChartComponent = ({
20991
21222
  }, [shiftEnd, shiftStartTime.decimalHour]);
20992
21223
  const SHIFT_DURATION = shiftDuration;
20993
21224
  shiftEndTime ? shiftEndTime.hour : (shiftStartTime.hour + SHIFT_DURATION) % 24;
20994
- const [animatedData, setAnimatedData] = React20__default.useState(
21225
+ const [animatedData, setAnimatedData] = React21__default.useState(
20995
21226
  () => Array(SHIFT_DURATION).fill(0)
20996
21227
  );
20997
- const prevDataRef = React20__default.useRef(Array(SHIFT_DURATION).fill(0));
20998
- const animationFrameRef = React20__default.useRef(null);
20999
- React20__default.useEffect(() => {
21228
+ const prevDataRef = React21__default.useRef(Array(SHIFT_DURATION).fill(0));
21229
+ const animationFrameRef = React21__default.useRef(null);
21230
+ React21__default.useEffect(() => {
21000
21231
  setAnimatedData((prev) => {
21001
21232
  if (prev.length !== SHIFT_DURATION) {
21002
21233
  return Array(SHIFT_DURATION).fill(0);
@@ -21005,14 +21236,14 @@ var HourlyOutputChartComponent = ({
21005
21236
  });
21006
21237
  prevDataRef.current = Array(SHIFT_DURATION).fill(0);
21007
21238
  }, [SHIFT_DURATION]);
21008
- const [idleBarState, setIdleBarState] = React20__default.useState({
21239
+ const [idleBarState, setIdleBarState] = React21__default.useState({
21009
21240
  visible: showIdleTime,
21010
21241
  key: 0,
21011
21242
  shouldAnimate: false
21012
21243
  });
21013
- const prevShowIdleTimeRef = React20__default.useRef(showIdleTime);
21014
- const stateUpdateTimeoutRef = React20__default.useRef(null);
21015
- React20__default.useEffect(() => {
21244
+ const prevShowIdleTimeRef = React21__default.useRef(showIdleTime);
21245
+ const stateUpdateTimeoutRef = React21__default.useRef(null);
21246
+ React21__default.useEffect(() => {
21016
21247
  if (stateUpdateTimeoutRef.current) {
21017
21248
  clearTimeout(stateUpdateTimeoutRef.current);
21018
21249
  }
@@ -21037,7 +21268,7 @@ var HourlyOutputChartComponent = ({
21037
21268
  }
21038
21269
  };
21039
21270
  }, [showIdleTime]);
21040
- const animateToNewData = React20__default.useCallback((targetData) => {
21271
+ const animateToNewData = React21__default.useCallback((targetData) => {
21041
21272
  const startData = [...prevDataRef.current];
21042
21273
  const startTime = performance.now();
21043
21274
  const duration = 1200;
@@ -21067,7 +21298,7 @@ var HourlyOutputChartComponent = ({
21067
21298
  }
21068
21299
  animationFrameRef.current = requestAnimationFrame(animate);
21069
21300
  }, []);
21070
- React20__default.useEffect(() => {
21301
+ React21__default.useEffect(() => {
21071
21302
  if (JSON.stringify(data) !== JSON.stringify(prevDataRef.current)) {
21072
21303
  const shiftData = data.slice(0, SHIFT_DURATION);
21073
21304
  animateToNewData(shiftData);
@@ -21078,7 +21309,7 @@ var HourlyOutputChartComponent = ({
21078
21309
  }
21079
21310
  };
21080
21311
  }, [data, animateToNewData]);
21081
- React20__default.useEffect(() => {
21312
+ React21__default.useEffect(() => {
21082
21313
  const checkContainerDimensions = () => {
21083
21314
  if (containerRef.current) {
21084
21315
  const rect = containerRef.current.getBoundingClientRect();
@@ -21100,7 +21331,7 @@ var HourlyOutputChartComponent = ({
21100
21331
  clearTimeout(fallbackTimeout);
21101
21332
  };
21102
21333
  }, []);
21103
- const formatHour = React20__default.useCallback((hourIndex) => {
21334
+ const formatHour = React21__default.useCallback((hourIndex) => {
21104
21335
  const isLastHour = hourIndex === SHIFT_DURATION - 1;
21105
21336
  const startDecimalHour = shiftStartTime.decimalHour + hourIndex;
21106
21337
  const startHour = Math.floor(startDecimalHour) % 24;
@@ -21124,7 +21355,7 @@ var HourlyOutputChartComponent = ({
21124
21355
  };
21125
21356
  return `${formatTime3(startHour, startMinute)}-${formatTime3(endHour, endMinute)}`;
21126
21357
  }, [shiftStartTime.decimalHour, SHIFT_DURATION, shiftEndTime]);
21127
- const formatTimeRange = React20__default.useCallback((hourIndex) => {
21358
+ const formatTimeRange = React21__default.useCallback((hourIndex) => {
21128
21359
  const isLastHour = hourIndex === SHIFT_DURATION - 1;
21129
21360
  const startDecimalHour = shiftStartTime.decimalHour + hourIndex;
21130
21361
  const startHour = Math.floor(startDecimalHour) % 24;
@@ -21145,7 +21376,7 @@ var HourlyOutputChartComponent = ({
21145
21376
  };
21146
21377
  return `${formatTime3(startHour, startMinute)} - ${formatTime3(endHour, endMinute)}`;
21147
21378
  }, [shiftStartTime.decimalHour, SHIFT_DURATION, shiftEndTime]);
21148
- const chartData = React20__default.useMemo(() => {
21379
+ const chartData = React21__default.useMemo(() => {
21149
21380
  return Array.from({ length: SHIFT_DURATION }, (_, i) => {
21150
21381
  const actualHour = (shiftStartTime.hour + i) % 24;
21151
21382
  const startMinute = shiftStartTime.minute;
@@ -21214,7 +21445,7 @@ var HourlyOutputChartComponent = ({
21214
21445
  };
21215
21446
  });
21216
21447
  }, [animatedData, data, pphThreshold, idleTimeHourly, shiftStartTime.hour, shiftStartTime.minute, shiftEndTime, formatHour, formatTimeRange, SHIFT_DURATION]);
21217
- const IdleBar = React20__default.useMemo(() => {
21448
+ const IdleBar = React21__default.useMemo(() => {
21218
21449
  if (!idleBarState.visible) return null;
21219
21450
  return /* @__PURE__ */ jsx(
21220
21451
  Bar,
@@ -21539,7 +21770,7 @@ var HourlyOutputChartComponent = ({
21539
21770
  }
21540
21771
  );
21541
21772
  };
21542
- var HourlyOutputChart = React20__default.memo(HourlyOutputChartComponent, (prevProps, nextProps) => {
21773
+ var HourlyOutputChart = React21__default.memo(HourlyOutputChartComponent, (prevProps, nextProps) => {
21543
21774
  if (prevProps.pphThreshold !== nextProps.pphThreshold || prevProps.shiftStart !== nextProps.shiftStart || prevProps.showIdleTime !== nextProps.showIdleTime || prevProps.className !== nextProps.className) {
21544
21775
  return false;
21545
21776
  }
@@ -21575,7 +21806,7 @@ function getTrendArrowAndColor(trend) {
21575
21806
  return { arrow: "\u2192", color: "text-gray-400" };
21576
21807
  }
21577
21808
  }
21578
- var VideoCard = React20__default.memo(({
21809
+ var VideoCard = React21__default.memo(({
21579
21810
  workspace,
21580
21811
  hlsUrl,
21581
21812
  shouldPlay,
@@ -21724,7 +21955,7 @@ var VideoCard = React20__default.memo(({
21724
21955
  });
21725
21956
  VideoCard.displayName = "VideoCard";
21726
21957
  var DEFAULT_HLS_URL = "https://192.168.5.9:8443/cam1.m3u8";
21727
- var VideoGridView = React20__default.memo(({
21958
+ var VideoGridView = React21__default.memo(({
21728
21959
  workspaces,
21729
21960
  selectedLine,
21730
21961
  className = "",
@@ -22639,7 +22870,7 @@ var EmptyStateMessage = ({
22639
22870
  iconClassName
22640
22871
  }) => {
22641
22872
  let IconContent = null;
22642
- if (React20__default.isValidElement(iconType)) {
22873
+ if (React21__default.isValidElement(iconType)) {
22643
22874
  IconContent = iconType;
22644
22875
  } else if (typeof iconType === "string") {
22645
22876
  const MappedIcon = IconMap[iconType];
@@ -23458,7 +23689,8 @@ var ShiftDisplay_default = ShiftDisplay;
23458
23689
  var TimeDisplay = ({ className, variant = "default" }) => {
23459
23690
  const { dateTimeConfig } = useDashboardConfig();
23460
23691
  const [time2, setTime] = useState("");
23461
- const timezoneToDisplay = dateTimeConfig?.defaultTimezone || "UTC";
23692
+ const dbTimezone = useAppTimezone();
23693
+ const timezoneToDisplay = dbTimezone || dateTimeConfig?.defaultTimezone || "UTC";
23462
23694
  const localeToUse = dateTimeConfig?.defaultLocale || "en-US";
23463
23695
  const timeSuffix = "";
23464
23696
  useEffect(() => {
@@ -23522,6 +23754,17 @@ var ISTTimer = memo(() => {
23522
23754
  });
23523
23755
  ISTTimer.displayName = "ISTTimer";
23524
23756
  var ISTTimer_default = ISTTimer;
23757
+ var TimeDisplay3 = TimeDisplay_default;
23758
+ var Timer = memo(() => {
23759
+ return /* @__PURE__ */ jsx(
23760
+ TimeDisplay3,
23761
+ {
23762
+ variant: "minimal"
23763
+ }
23764
+ );
23765
+ });
23766
+ Timer.displayName = "Timer";
23767
+ var Timer_default = Timer;
23525
23768
  var TicketHistory = ({ companyId }) => {
23526
23769
  const { tickets, loading, error } = useTicketHistory(companyId);
23527
23770
  const [expandedTickets, setExpandedTickets] = useState(/* @__PURE__ */ new Set());
@@ -26619,8 +26862,9 @@ var LiveTimer = () => {
26619
26862
  }, 1e3);
26620
26863
  return () => clearInterval(timer);
26621
26864
  }, []);
26622
- const formatter = new Intl.DateTimeFormat("en-IN", {
26623
- timeZone: "Asia/Kolkata",
26865
+ const timezone = useAppTimezone();
26866
+ const formatter = new Intl.DateTimeFormat("en-US", {
26867
+ timeZone: timezone,
26624
26868
  hour: "2-digit",
26625
26869
  minute: "2-digit",
26626
26870
  second: "2-digit",
@@ -26654,7 +26898,7 @@ function Skeleton({ className, ...props }) {
26654
26898
  var Select = SelectPrimitive.Root;
26655
26899
  var SelectGroup = SelectPrimitive.Group;
26656
26900
  var SelectValue = SelectPrimitive.Value;
26657
- var SelectTrigger = React20.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(
26901
+ var SelectTrigger = React21.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(
26658
26902
  SelectPrimitive.Trigger,
26659
26903
  {
26660
26904
  ref,
@@ -26670,7 +26914,7 @@ var SelectTrigger = React20.forwardRef(({ className, children, ...props }, ref)
26670
26914
  }
26671
26915
  ));
26672
26916
  SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
26673
- var SelectScrollUpButton = React20.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
26917
+ var SelectScrollUpButton = React21.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
26674
26918
  SelectPrimitive.ScrollUpButton,
26675
26919
  {
26676
26920
  ref,
@@ -26680,7 +26924,7 @@ var SelectScrollUpButton = React20.forwardRef(({ className, ...props }, ref) =>
26680
26924
  }
26681
26925
  ));
26682
26926
  SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName;
26683
- var SelectScrollDownButton = React20.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
26927
+ var SelectScrollDownButton = React21.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
26684
26928
  SelectPrimitive.ScrollDownButton,
26685
26929
  {
26686
26930
  ref,
@@ -26690,7 +26934,7 @@ var SelectScrollDownButton = React20.forwardRef(({ className, ...props }, ref) =
26690
26934
  }
26691
26935
  ));
26692
26936
  SelectScrollDownButton.displayName = SelectPrimitive.ScrollDownButton.displayName;
26693
- var SelectContent = React20.forwardRef(({ className, children, position = "popper", ...props }, ref) => /* @__PURE__ */ jsx(SelectPrimitive.Portal, { children: /* @__PURE__ */ jsxs(
26937
+ var SelectContent = React21.forwardRef(({ className, children, position = "popper", ...props }, ref) => /* @__PURE__ */ jsx(SelectPrimitive.Portal, { children: /* @__PURE__ */ jsxs(
26694
26938
  SelectPrimitive.Content,
26695
26939
  {
26696
26940
  ref,
@@ -26718,7 +26962,7 @@ var SelectContent = React20.forwardRef(({ className, children, position = "poppe
26718
26962
  }
26719
26963
  ) }));
26720
26964
  SelectContent.displayName = SelectPrimitive.Content.displayName;
26721
- var SelectLabel = React20.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
26965
+ var SelectLabel = React21.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
26722
26966
  SelectPrimitive.Label,
26723
26967
  {
26724
26968
  ref,
@@ -26727,7 +26971,7 @@ var SelectLabel = React20.forwardRef(({ className, ...props }, ref) => /* @__PUR
26727
26971
  }
26728
26972
  ));
26729
26973
  SelectLabel.displayName = SelectPrimitive.Label.displayName;
26730
- var SelectItem = React20.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(
26974
+ var SelectItem = React21.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(
26731
26975
  SelectPrimitive.Item,
26732
26976
  {
26733
26977
  ref,
@@ -26743,7 +26987,7 @@ var SelectItem = React20.forwardRef(({ className, children, ...props }, ref) =>
26743
26987
  }
26744
26988
  ));
26745
26989
  SelectItem.displayName = SelectPrimitive.Item.displayName;
26746
- var SelectSeparator = React20.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
26990
+ var SelectSeparator = React21.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
26747
26991
  SelectPrimitive.Separator,
26748
26992
  {
26749
26993
  ref,
@@ -27036,7 +27280,7 @@ if (typeof document !== "undefined") {
27036
27280
  document.head.appendChild(style);
27037
27281
  }
27038
27282
  }
27039
- var VideoPlayer = React20__default.forwardRef(({
27283
+ var VideoPlayer = React21__default.forwardRef(({
27040
27284
  src,
27041
27285
  poster,
27042
27286
  autoplay = false,
@@ -27046,15 +27290,19 @@ var VideoPlayer = React20__default.forwardRef(({
27046
27290
  playsInline = true,
27047
27291
  className = "",
27048
27292
  options = {},
27293
+ externalLoadingControl = false,
27294
+ onLoadingChange,
27049
27295
  onReady,
27050
27296
  onPlay,
27051
27297
  onPause,
27298
+ onPlaying,
27052
27299
  onTimeUpdate,
27053
27300
  onDurationChange,
27054
27301
  onEnded,
27055
27302
  onError,
27056
27303
  onLoadStart,
27057
27304
  onLoadedMetadata,
27305
+ onLoadedData,
27058
27306
  onSeeking,
27059
27307
  onSeeked
27060
27308
  }, ref) => {
@@ -27176,6 +27424,7 @@ var VideoPlayer = React20__default.forwardRef(({
27176
27424
  });
27177
27425
  player.on("play", () => onPlay?.(player));
27178
27426
  player.on("pause", () => onPause?.(player));
27427
+ player.on("playing", () => onPlaying?.(player));
27179
27428
  player.on("timeupdate", () => {
27180
27429
  const currentTime2 = player.currentTime() || 0;
27181
27430
  onTimeUpdate?.(player, currentTime2);
@@ -27187,16 +27436,21 @@ var VideoPlayer = React20__default.forwardRef(({
27187
27436
  player.on("ended", () => onEnded?.(player));
27188
27437
  player.on("loadstart", () => {
27189
27438
  setIsLoading(true);
27439
+ onLoadingChange?.(true);
27190
27440
  onLoadStart?.(player);
27191
27441
  });
27192
27442
  player.on("loadeddata", () => {
27193
27443
  setIsLoading(false);
27444
+ onLoadingChange?.(false);
27445
+ onLoadedData?.(player);
27194
27446
  });
27195
27447
  player.on("waiting", () => {
27196
27448
  setIsLoading(true);
27449
+ onLoadingChange?.(true);
27197
27450
  });
27198
27451
  player.on("playing", () => {
27199
27452
  setIsLoading(false);
27453
+ onLoadingChange?.(false);
27200
27454
  });
27201
27455
  player.on("loadedmetadata", () => {
27202
27456
  onLoadedMetadata?.(player);
@@ -27321,7 +27575,7 @@ var VideoPlayer = React20__default.forwardRef(({
27321
27575
  setIsReady(false);
27322
27576
  }
27323
27577
  }, []);
27324
- React20__default.useImperativeHandle(ref, () => ({
27578
+ React21__default.useImperativeHandle(ref, () => ({
27325
27579
  player: playerRef.current,
27326
27580
  play,
27327
27581
  pause,
@@ -27342,13 +27596,14 @@ var VideoPlayer = React20__default.forwardRef(({
27342
27596
  "data-vjs-player": true
27343
27597
  }
27344
27598
  ),
27345
- isLoading && /* @__PURE__ */ jsx("div", { className: "video-player-loading", children: /* @__PURE__ */ jsx(OptifyeLogoLoader_default, { size: "md", message: "Loading video..." }) })
27599
+ isLoading && !externalLoadingControl && /* @__PURE__ */ jsx("div", { className: "video-player-loading", children: /* @__PURE__ */ jsx(OptifyeLogoLoader_default, { size: "md", message: "Loading video..." }) })
27346
27600
  ] });
27347
27601
  });
27348
27602
  VideoPlayer.displayName = "VideoPlayer";
27349
27603
  var CroppedVideoPlayer = forwardRef(({
27350
27604
  crop,
27351
27605
  debug = false,
27606
+ onClick,
27352
27607
  ...videoProps
27353
27608
  }, ref) => {
27354
27609
  const videoContainerRef = useRef(null);
@@ -27366,7 +27621,9 @@ var CroppedVideoPlayer = forwardRef(({
27366
27621
  }
27367
27622
  }, []);
27368
27623
  useImperativeHandle(ref, () => ({
27369
- player: hiddenVideoRef.current?.player || null,
27624
+ get player() {
27625
+ return hiddenVideoRef.current?.player || null;
27626
+ },
27370
27627
  play: () => hiddenVideoRef.current?.play() || void 0,
27371
27628
  pause: () => hiddenVideoRef.current?.pause(),
27372
27629
  currentTime: (time2) => {
@@ -27383,7 +27640,9 @@ var CroppedVideoPlayer = forwardRef(({
27383
27640
  hiddenVideoRef.current?.dispose();
27384
27641
  stopCanvasRendering();
27385
27642
  },
27386
- isReady: hiddenVideoRef.current?.isReady || false
27643
+ get isReady() {
27644
+ return hiddenVideoRef.current?.isReady || false;
27645
+ }
27387
27646
  }), [stopCanvasRendering]);
27388
27647
  const calculateCanvasDimensions = useCallback(() => {
27389
27648
  if (!crop || !videoContainerRef.current) return;
@@ -27511,7 +27770,8 @@ var CroppedVideoPlayer = forwardRef(({
27511
27770
  "div",
27512
27771
  {
27513
27772
  ref: videoContainerRef,
27514
- className: `relative w-full h-full flex items-center justify-center bg-black ${videoProps.className || ""}`,
27773
+ className: `relative w-full h-full flex items-center justify-center bg-black ${onClick ? "cursor-pointer" : ""} ${videoProps.className || ""}`,
27774
+ onClick,
27515
27775
  children: [
27516
27776
  /* @__PURE__ */ jsx("div", { className: "hidden", children: /* @__PURE__ */ jsx(
27517
27777
  VideoPlayer,
@@ -27524,7 +27784,10 @@ var CroppedVideoPlayer = forwardRef(({
27524
27784
  onEnded: handleVideoEnded,
27525
27785
  onSeeking: handleSeeking,
27526
27786
  onSeeked: handleSeeked,
27527
- onLoadedMetadata: handleLoadedMetadata
27787
+ onLoadedMetadata: handleLoadedMetadata,
27788
+ onLoadedData: videoProps.onLoadedData,
27789
+ onPlaying: videoProps.onPlaying,
27790
+ onLoadingChange: videoProps.onLoadingChange
27528
27791
  }
27529
27792
  ) }),
27530
27793
  /* @__PURE__ */ jsx(
@@ -27537,9 +27800,7 @@ var CroppedVideoPlayer = forwardRef(({
27537
27800
  style: {
27538
27801
  display: isVideoReady ? "block" : "none",
27539
27802
  width: `${canvasDimensions.width}px`,
27540
- height: `${canvasDimensions.height}px`,
27541
- pointerEvents: "none"
27542
- // Allow clicks to pass through to controls
27803
+ height: `${canvasDimensions.height}px`
27543
27804
  }
27544
27805
  }
27545
27806
  ),
@@ -28101,6 +28362,7 @@ var FileManagerFilters = ({
28101
28362
  }) => {
28102
28363
  const [expandedNodes, setExpandedNodes] = useState(/* @__PURE__ */ new Set());
28103
28364
  const [searchTerm, setSearchTerm] = useState("");
28365
+ const timezone = useAppTimezone();
28104
28366
  const [clipMetadata, setClipMetadata] = useState({});
28105
28367
  const [loadingCategories, setLoadingCategories] = useState(/* @__PURE__ */ new Set());
28106
28368
  const [categoryPages, setCategoryPages] = useState({});
@@ -28156,8 +28418,8 @@ var FileManagerFilters = ({
28156
28418
  }, [workspaceId, date, shift]);
28157
28419
  const getAuthToken3 = async () => {
28158
28420
  try {
28159
- const { createClient: createClient4 } = await import('@supabase/supabase-js');
28160
- const supabase = createClient4(
28421
+ const { createClient: createClient5 } = await import('@supabase/supabase-js');
28422
+ const supabase = createClient5(
28161
28423
  process.env.NEXT_PUBLIC_SUPABASE_URL || "",
28162
28424
  process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY || ""
28163
28425
  );
@@ -28266,23 +28528,26 @@ var FileManagerFilters = ({
28266
28528
  }
28267
28529
  if (categoryCount > 0 && shouldShowCategory(category.id)) {
28268
28530
  const colorClasses = getColorClasses(category.color);
28269
- const clipNodes = filteredClips.map((clip) => {
28531
+ const clipNodes = filteredClips.map((clip, index) => {
28270
28532
  const timeString = new Date(clip.clip_timestamp).toLocaleTimeString("en-US", {
28271
28533
  hour12: false,
28272
28534
  hour: "2-digit",
28273
28535
  minute: "2-digit",
28274
- second: "2-digit"
28536
+ timeZone: timezone
28537
+ // Use database timezone for display
28275
28538
  });
28276
28539
  return {
28277
28540
  id: clip.id,
28278
- label: `${timeString} - ${clip.description}${clip.duration ? ` (${clip.duration.toFixed(1)}s)` : ""}`,
28541
+ label: `${timeString} - ${clip.description}${clip.duration && category.id !== "idle_time" ? ` (${clip.duration.toFixed(1)}s)` : ""}`,
28279
28542
  type: "video",
28280
28543
  icon: getSeverityIcon(clip.severity),
28281
28544
  timestamp: clip.clip_timestamp,
28282
28545
  severity: clip.severity,
28283
28546
  clipId: clip.clipId,
28284
28547
  // Store stable UUID for navigation
28285
- categoryId: category.id
28548
+ categoryId: category.id,
28549
+ clipPosition: index + 1
28550
+ // Store 1-based position
28286
28551
  };
28287
28552
  });
28288
28553
  tree.push({
@@ -28398,8 +28663,8 @@ var FileManagerFilters = ({
28398
28663
  onFilterChange(node.id);
28399
28664
  } else if (node.type === "video") {
28400
28665
  if (onClipSelect && node.categoryId !== void 0 && node.clipId !== void 0) {
28401
- console.log(`[FileManager] Selecting clip: category=${node.categoryId}, clipId=${node.clipId}`);
28402
- onClipSelect(node.categoryId, node.clipId);
28666
+ console.log(`[FileManager] Selecting clip: category=${node.categoryId}, clipId=${node.clipId}, position=${node.clipPosition}`);
28667
+ onClipSelect(node.categoryId, node.clipId, node.clipPosition);
28403
28668
  } else {
28404
28669
  const videoIndex = videos.findIndex((v) => v.id === node.id);
28405
28670
  if (videoIndex !== -1) {
@@ -28931,6 +29196,7 @@ var BottlenecksContent = ({
28931
29196
  className
28932
29197
  }) => {
28933
29198
  const dashboardConfig = useDashboardConfig();
29199
+ const timezone = useAppTimezone();
28934
29200
  const effectiveShift = useMemo(() => {
28935
29201
  if (shift !== void 0 && shift !== null) {
28936
29202
  const shiftStr = shift.toString();
@@ -28942,13 +29208,14 @@ var BottlenecksContent = ({
28942
29208
  return "0";
28943
29209
  } else {
28944
29210
  const currentShift = getCurrentShift(
28945
- dashboardConfig.dateTimeConfig?.defaultTimezone || "Asia/Kolkata",
29211
+ timezone,
29212
+ // Use dynamic timezone instead of hardcoded default
28946
29213
  dashboardConfig.shiftConfig
28947
29214
  );
28948
- console.log(`[BottlenecksContent] Using current operational shift: ${currentShift.shiftId}`);
29215
+ console.log(`[BottlenecksContent] Using current operational shift: ${currentShift.shiftId} with timezone: ${timezone}`);
28949
29216
  return currentShift.shiftId.toString();
28950
29217
  }
28951
- }, [shift, date, dashboardConfig]);
29218
+ }, [shift, date, timezone, dashboardConfig]);
28952
29219
  const { crop: workspaceCrop} = useWorkspaceCrop(workspaceId);
28953
29220
  const videoRef = useRef(null);
28954
29221
  const [initialFilter, setInitialFilter] = useState("");
@@ -28961,6 +29228,11 @@ var BottlenecksContent = ({
28961
29228
  const [duration, setDuration] = useState(0);
28962
29229
  const [currentIndex, setCurrentIndex] = useState(0);
28963
29230
  const [currentClipId, setCurrentClipId] = useState(null);
29231
+ const [isTransitioning, setIsTransitioning] = useState(false);
29232
+ const [pendingVideo, setPendingVideo] = useState(null);
29233
+ const [isVideoBuffering, setIsVideoBuffering] = useState(false);
29234
+ const [isInitialLoading, setIsInitialLoading] = useState(false);
29235
+ const loadingTimeoutRef = useRef(null);
28964
29236
  const [activeFilter, setActiveFilter] = useState(initialFilter);
28965
29237
  const previousFilterRef = useRef("");
28966
29238
  const [allVideos, setAllVideos] = useState([]);
@@ -28970,7 +29242,11 @@ var BottlenecksContent = ({
28970
29242
  const [isNavigating, setIsNavigating] = useState(false);
28971
29243
  const [error, setError] = useState(null);
28972
29244
  const [clipCounts, setClipCounts] = useState({});
28973
- const [categoryPosition, setCategoryPosition] = useState(1);
29245
+ const [categoryMetadata, setCategoryMetadata] = useState([]);
29246
+ const [currentMetadataIndex, setCurrentMetadataIndex] = useState(0);
29247
+ const [metadataCache, setMetadataCache] = useState({});
29248
+ const categoryMetadataRef = useRef([]);
29249
+ const currentMetadataIndexRef = useRef(0);
28974
29250
  const {
28975
29251
  newClipsNotification,
28976
29252
  hasNewClips,
@@ -28978,7 +29254,7 @@ var BottlenecksContent = ({
28978
29254
  clearNotification
28979
29255
  } = useClipsRealtimeUpdates({
28980
29256
  workspaceId,
28981
- date: date || getOperationalDate(),
29257
+ date: date || getOperationalDate(timezone),
28982
29258
  shiftId: effectiveShift,
28983
29259
  enabled: true,
28984
29260
  // Supabase implementation
@@ -29015,7 +29291,7 @@ var BottlenecksContent = ({
29015
29291
  counts: dynamicCounts
29016
29292
  } = useClipTypesWithCounts(
29017
29293
  workspaceId,
29018
- date || getOperationalDate(),
29294
+ date || getOperationalDate(timezone),
29019
29295
  effectiveShift
29020
29296
  // Use same shift as video loading for consistency
29021
29297
  );
@@ -29026,7 +29302,7 @@ var BottlenecksContent = ({
29026
29302
  clipTypesError,
29027
29303
  dynamicCounts,
29028
29304
  workspaceId,
29029
- date: date || getOperationalDate(),
29305
+ date: date || getOperationalDate(timezone),
29030
29306
  shift: shift || "0"
29031
29307
  });
29032
29308
  useEffect(() => {
@@ -29052,7 +29328,7 @@ var BottlenecksContent = ({
29052
29328
  }
29053
29329
  fetchInProgressRef.current.add(operationKey);
29054
29330
  try {
29055
- const operationalDate = date || getOperationalDate();
29331
+ const operationalDate = date || getOperationalDate(timezone);
29056
29332
  const shiftStr = effectiveShift;
29057
29333
  console.log(`[BottlenecksContent] Fetching clip counts directly with params:`, {
29058
29334
  workspaceId,
@@ -29098,7 +29374,7 @@ var BottlenecksContent = ({
29098
29374
  setError(null);
29099
29375
  }
29100
29376
  try {
29101
- const operationalDate = date || getOperationalDate();
29377
+ const operationalDate = date || getOperationalDate(timezone);
29102
29378
  const shiftStr = effectiveShift;
29103
29379
  console.log(`[BottlenecksContent] Loading first video for category: ${targetCategory}`);
29104
29380
  try {
@@ -29122,7 +29398,6 @@ var BottlenecksContent = ({
29122
29398
  setHasInitialLoad(true);
29123
29399
  loadingCategoryRef.current = null;
29124
29400
  setIsCategoryLoading(false);
29125
- setCategoryPosition(1);
29126
29401
  return;
29127
29402
  }
29128
29403
  } catch (directError) {
@@ -29148,7 +29423,6 @@ var BottlenecksContent = ({
29148
29423
  return prev;
29149
29424
  });
29150
29425
  setIsCategoryLoading(false);
29151
- setCategoryPosition(1);
29152
29426
  return;
29153
29427
  }
29154
29428
  } catch (indexError) {
@@ -29201,10 +29475,16 @@ var BottlenecksContent = ({
29201
29475
  setIsCategoryLoading(true);
29202
29476
  setError(null);
29203
29477
  setCurrentIndex(0);
29204
- setCategoryPosition(1);
29205
29478
  setIsNavigating(false);
29206
29479
  loadingCategoryRef.current = null;
29480
+ setCategoryMetadata([]);
29481
+ setCurrentMetadataIndex(0);
29482
+ categoryMetadataRef.current = [];
29483
+ currentMetadataIndexRef.current = 0;
29207
29484
  previousFilterRef.current = activeFilter;
29485
+ if (activeFilter !== "all") {
29486
+ loadCategoryMetadata(activeFilter, true);
29487
+ }
29208
29488
  const filtered = allVideos.filter((video) => {
29209
29489
  if (activeFilter === "all") return true;
29210
29490
  return video.type === activeFilter;
@@ -29238,14 +29518,11 @@ var BottlenecksContent = ({
29238
29518
  }
29239
29519
  }, []);
29240
29520
  const getCategoryCount = useCallback((categoryId) => {
29241
- if (isPercentileCategory(categoryId)) {
29242
- if (isPercentileCategory(activeFilter) && activeFilter === categoryId) {
29243
- return allVideos.length;
29244
- }
29245
- return 0;
29521
+ if (activeFilter === categoryId && categoryMetadata.length > 0) {
29522
+ return categoryMetadata.length;
29246
29523
  }
29247
29524
  return mergedCounts[categoryId] || 0;
29248
- }, [isPercentileCategory, allVideos, mergedCounts, activeFilter]);
29525
+ }, [activeFilter, categoryMetadata, mergedCounts]);
29249
29526
  const filteredVideos = useMemo(() => {
29250
29527
  if (!allVideos) return [];
29251
29528
  let filtered = [];
@@ -29268,29 +29545,61 @@ var BottlenecksContent = ({
29268
29545
  setError(null);
29269
29546
  }
29270
29547
  }, [isNavigating, currentIndex, filteredVideos.length]);
29271
- const loadAndPlayClipById = useCallback(async (clipId, categoryId) => {
29272
- if (!workspaceId || !s3ClipsService || !isMountedRef.current) return;
29273
- console.log(`[BottlenecksContent] Loading clip by ID: ${clipId}, category=${categoryId}`);
29274
- setIsNavigating(true);
29275
- setError(null);
29276
- if (activeFilterRef.current !== categoryId) {
29277
- updateActiveFilter(categoryId);
29548
+ const clearLoadingState = useCallback(() => {
29549
+ setIsTransitioning(false);
29550
+ setIsNavigating(false);
29551
+ if (loadingTimeoutRef.current) {
29552
+ clearTimeout(loadingTimeoutRef.current);
29553
+ loadingTimeoutRef.current = null;
29554
+ }
29555
+ }, []);
29556
+ const loadCategoryMetadata = useCallback(async (categoryId, autoLoadFirstVideo = false) => {
29557
+ if (!workspaceId) {
29558
+ return;
29559
+ }
29560
+ const cacheKey = `${categoryId}-${date || getOperationalDate(timezone)}-${effectiveShift}`;
29561
+ if (metadataCache[cacheKey]) {
29562
+ console.log(`[BottlenecksContent] Using cached metadata for ${categoryId}`);
29563
+ setCategoryMetadata(metadataCache[cacheKey]);
29564
+ categoryMetadataRef.current = metadataCache[cacheKey];
29565
+ if (autoLoadFirstVideo && metadataCache[cacheKey].length > 0 && s3ClipsService) {
29566
+ const firstClipMeta = metadataCache[cacheKey][0];
29567
+ try {
29568
+ const video = await s3ClipsService.getClipById(firstClipMeta.clipId);
29569
+ if (video && isMountedRef.current) {
29570
+ setCurrentClipId(firstClipMeta.clipId);
29571
+ setAllVideos([video]);
29572
+ setCurrentIndex(0);
29573
+ setCurrentMetadataIndex(0);
29574
+ currentMetadataIndexRef.current = 0;
29575
+ setIsCategoryLoading(false);
29576
+ console.log(`[BottlenecksContent] Auto-loaded first video from cache: ${video.id} (1/${metadataCache[cacheKey].length})`);
29577
+ }
29578
+ } catch (error2) {
29579
+ console.error(`[BottlenecksContent] Error loading first video from cache:`, error2);
29580
+ setIsCategoryLoading(false);
29581
+ clearLoadingState();
29582
+ }
29583
+ }
29584
+ return;
29278
29585
  }
29279
29586
  try {
29587
+ console.log(`[BottlenecksContent] Loading metadata for category: ${categoryId}`);
29588
+ const { createClient: createClient5 } = await import('@supabase/supabase-js');
29589
+ const supabase = createClient5(
29590
+ process.env.NEXT_PUBLIC_SUPABASE_URL || "",
29591
+ process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY || ""
29592
+ );
29593
+ const { data: { session } } = await supabase.auth.getSession();
29594
+ const authToken = session?.access_token;
29595
+ if (!authToken) {
29596
+ console.error("Authentication required for metadata loading");
29597
+ return;
29598
+ }
29599
+ let response;
29280
29600
  if (isPercentileCategory(categoryId)) {
29281
- console.log(`[BottlenecksContent] Loading percentile category: ${categoryId}`);
29282
29601
  const percentileType = categoryId === "fast-cycles" ? "fast-cycles" : categoryId === "slow-cycles" ? "slow-cycles" : "idle-times";
29283
- const { createClient: createClient4 } = await import('@supabase/supabase-js');
29284
- const supabase = createClient4(
29285
- process.env.NEXT_PUBLIC_SUPABASE_URL || "",
29286
- process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY || ""
29287
- );
29288
- const { data: { session } } = await supabase.auth.getSession();
29289
- const authToken = session?.access_token;
29290
- if (!authToken) {
29291
- throw new Error("Authentication required");
29292
- }
29293
- const response = await fetch("/api/clips/supabase", {
29602
+ response = await fetch("/api/clips/supabase", {
29294
29603
  method: "POST",
29295
29604
  headers: {
29296
29605
  "Content-Type": "application/json",
@@ -29300,53 +29609,125 @@ var BottlenecksContent = ({
29300
29609
  action: "percentile-clips",
29301
29610
  percentileAction: percentileType,
29302
29611
  workspaceId,
29303
- startDate: `${date || getOperationalDate()}T00:00:00Z`,
29304
- endDate: `${date || getOperationalDate()}T23:59:59Z`,
29612
+ startDate: `${date || getOperationalDate(timezone)}T00:00:00Z`,
29613
+ endDate: `${date || getOperationalDate(timezone)}T23:59:59Z`,
29305
29614
  percentile: 10,
29306
29615
  shiftId: effectiveShift,
29307
29616
  limit: 100
29308
29617
  })
29309
29618
  });
29310
- if (!response.ok) {
29311
- const errorData = await response.json();
29312
- throw new Error(errorData.error || `API error: ${response.status}`);
29619
+ } else {
29620
+ response = await fetch("/api/clips/supabase", {
29621
+ method: "POST",
29622
+ headers: {
29623
+ "Content-Type": "application/json",
29624
+ "Authorization": `Bearer ${authToken}`
29625
+ },
29626
+ body: JSON.stringify({
29627
+ action: "clip-metadata",
29628
+ workspaceId,
29629
+ date: date || getOperationalDate(timezone),
29630
+ shift: effectiveShift,
29631
+ category: categoryId,
29632
+ page: 1,
29633
+ limit: 1e3
29634
+ })
29635
+ });
29636
+ }
29637
+ if (!response.ok) {
29638
+ throw new Error(`Metadata API error: ${response.status}`);
29639
+ }
29640
+ const categoryData = await response.json();
29641
+ if (categoryData.clips && isMountedRef.current) {
29642
+ let metadataClips;
29643
+ if (isPercentileCategory(categoryId)) {
29644
+ metadataClips = categoryData.clips.map((clip, index) => ({
29645
+ id: clip.id,
29646
+ clipId: clip.id,
29647
+ clip_timestamp: clip.timestamp || clip.creation_timestamp,
29648
+ description: clip.description,
29649
+ severity: clip.severity,
29650
+ category: categoryId,
29651
+ duration: clip.cycle_time_seconds,
29652
+ index
29653
+ }));
29654
+ } else {
29655
+ metadataClips = categoryData.clips;
29313
29656
  }
29314
- const percentileData = await response.json();
29315
- if (percentileData.clips && percentileData.clips.length > 0 && isMountedRef.current) {
29316
- const clickedClipIndex = percentileData.clips.findIndex((clip) => clip.id === clipId);
29317
- if (clickedClipIndex !== -1) {
29318
- setCurrentClipId(clipId);
29319
- setAllVideos(percentileData.clips);
29320
- setCurrentIndex(clickedClipIndex);
29321
- setCategoryPosition(clickedClipIndex + 1);
29322
- console.log(`[BottlenecksContent] Loaded ${percentileData.clips.length} ${categoryId} clips, playing #${clickedClipIndex + 1}`);
29657
+ setMetadataCache((prev) => ({
29658
+ ...prev,
29659
+ [cacheKey]: metadataClips
29660
+ }));
29661
+ setCategoryMetadata(metadataClips);
29662
+ categoryMetadataRef.current = metadataClips;
29663
+ console.log(`[BottlenecksContent] Loaded metadata for ${categoryId}: ${metadataClips.length} clips`);
29664
+ if (autoLoadFirstVideo && metadataClips.length > 0 && s3ClipsService) {
29665
+ const firstClipMeta = metadataClips[0];
29666
+ try {
29667
+ const video = await s3ClipsService.getClipById(firstClipMeta.clipId);
29668
+ if (video && isMountedRef.current) {
29669
+ setCurrentClipId(firstClipMeta.clipId);
29670
+ setAllVideos([video]);
29671
+ setCurrentIndex(0);
29672
+ setCurrentMetadataIndex(0);
29673
+ currentMetadataIndexRef.current = 0;
29674
+ setIsCategoryLoading(false);
29675
+ console.log(`[BottlenecksContent] Auto-loaded first video: ${video.id} (1/${metadataClips.length})`);
29676
+ }
29677
+ } catch (error2) {
29678
+ console.error(`[BottlenecksContent] Error loading first video:`, error2);
29679
+ setIsCategoryLoading(false);
29323
29680
  }
29324
29681
  }
29325
- } else {
29326
- const video = await s3ClipsService.getClipById(clipId);
29327
- if (video && isMountedRef.current) {
29328
- console.log(`[BottlenecksContent] Processing loaded video by ID: ${video.id}`);
29329
- setCurrentClipId(clipId);
29330
- setAllVideos([video]);
29331
- setCurrentIndex(0);
29332
- setCategoryPosition(1);
29333
- console.log(`[BottlenecksContent] Successfully loaded clip by ID: ${video.id}`);
29682
+ }
29683
+ } catch (error2) {
29684
+ console.error(`[BottlenecksContent] Error loading category metadata:`, error2);
29685
+ }
29686
+ }, [workspaceId, date, effectiveShift, isPercentileCategory, metadataCache, s3ClipsService]);
29687
+ const loadAndPlayClipById = useCallback(async (clipId, categoryId, position) => {
29688
+ if (!workspaceId || !s3ClipsService || !isMountedRef.current) return;
29689
+ console.log(`[BottlenecksContent] Loading clip by ID: ${clipId}, category=${categoryId}, position=${position}`);
29690
+ setIsTransitioning(true);
29691
+ setIsInitialLoading(true);
29692
+ setError(null);
29693
+ loadingTimeoutRef.current = setTimeout(() => {
29694
+ console.warn("[BottlenecksContent] Loading timeout - clearing stuck loading state");
29695
+ clearLoadingState();
29696
+ }, 1e3);
29697
+ if (activeFilterRef.current !== categoryId) {
29698
+ updateActiveFilter(categoryId);
29699
+ }
29700
+ try {
29701
+ await loadCategoryMetadata(categoryId, false);
29702
+ const metadataArray = categoryMetadataRef.current;
29703
+ if (metadataArray.length > 0) {
29704
+ const clickedClipIndex = metadataArray.findIndex((clip) => clip.clipId === clipId);
29705
+ if (clickedClipIndex !== -1) {
29706
+ setCurrentMetadataIndex(clickedClipIndex);
29707
+ currentMetadataIndexRef.current = clickedClipIndex;
29708
+ const video = await s3ClipsService.getClipById(clipId);
29709
+ if (video) {
29710
+ setPendingVideo(video);
29711
+ setCurrentClipId(clipId);
29712
+ setAllVideos([video]);
29713
+ setCurrentIndex(0);
29714
+ console.log(`[BottlenecksContent] Loaded clip ${clipId} (${clickedClipIndex + 1}/${metadataArray.length})`);
29715
+ }
29334
29716
  }
29335
29717
  }
29336
- setIsNavigating(false);
29337
29718
  } catch (error2) {
29338
29719
  console.error(`[BottlenecksContent] Error loading clip by ID (${clipId}):`, error2);
29339
29720
  if (isMountedRef.current) {
29340
29721
  setError("Failed to load selected clip. Please try again.");
29341
- setIsNavigating(false);
29722
+ clearLoadingState();
29342
29723
  }
29343
29724
  }
29344
- }, [workspaceId, s3ClipsService, date, effectiveShift, updateActiveFilter]);
29725
+ }, [workspaceId, s3ClipsService, date, effectiveShift, updateActiveFilter, clearLoadingState]);
29345
29726
  useCallback(async (categoryId, clipIndex) => {
29346
29727
  console.warn("[BottlenecksContent] loadAndPlayClip is deprecated, use loadAndPlayClipById instead");
29347
29728
  if (!workspaceId || !s3ClipsService || !isMountedRef.current) return;
29348
29729
  try {
29349
- const operationalDate = date || getOperationalDate();
29730
+ const operationalDate = date || getOperationalDate(timezone);
29350
29731
  const shiftStr = effectiveShift;
29351
29732
  const video = await s3ClipsService.getClipByIndex(
29352
29733
  workspaceId,
@@ -29367,105 +29748,79 @@ var BottlenecksContent = ({
29367
29748
  const handleNext = useCallback(async () => {
29368
29749
  if (!isMountedRef.current) return;
29369
29750
  const currentFilter = activeFilterRef.current;
29370
- console.log(`[handleNext] Navigating in category: ${currentFilter}, current index: ${currentIndex}`);
29371
- setIsNavigating(true);
29751
+ setIsTransitioning(true);
29752
+ setIsInitialLoading(true);
29372
29753
  setError(null);
29373
29754
  try {
29374
- if (isPercentileCategory(currentFilter)) {
29375
- if (currentIndex < allVideos.length - 1) {
29376
- const nextIndex = currentIndex + 1;
29377
- const nextVideo = allVideos[nextIndex];
29378
- console.log(`[handleNext] Moving to next percentile clip: ${nextVideo.id} (index ${nextIndex})`);
29379
- setCurrentClipId(nextVideo.id);
29380
- setCurrentIndex(nextIndex);
29381
- setCategoryPosition(nextIndex + 1);
29382
- setIsNavigating(false);
29383
- } else {
29384
- console.log(`[handleNext] Already at last clip in percentile category`);
29385
- setIsNavigating(false);
29386
- }
29387
- } else {
29388
- if (!currentClipId || !s3ClipsService) {
29389
- setIsNavigating(false);
29390
- return;
29391
- }
29392
- const neighbors = await s3ClipsService.getNeighboringClips(
29393
- workspaceId,
29394
- date || getOperationalDate(),
29395
- effectiveShift,
29396
- currentFilter,
29397
- currentClipId
29398
- );
29399
- if (neighbors.next) {
29400
- console.log(`[handleNext] Found next clip: ${neighbors.next.id}`);
29401
- setCurrentClipId(neighbors.next.id || null);
29402
- setAllVideos([neighbors.next]);
29755
+ const currentMetaIndex = currentMetadataIndexRef.current;
29756
+ const metadataArray = categoryMetadataRef.current;
29757
+ console.log(`[handleNext] Unified navigation: ${currentFilter}, metadata index: ${currentMetaIndex}/${metadataArray.length}`);
29758
+ if (currentMetaIndex < metadataArray.length - 1) {
29759
+ const nextMetadataIndex = currentMetaIndex + 1;
29760
+ const nextClipMeta = metadataArray[nextMetadataIndex];
29761
+ console.log(`[handleNext] Loading next clip: ${nextClipMeta.clipId} at metadata index ${nextMetadataIndex}`);
29762
+ if (!s3ClipsService) {
29763
+ throw new Error("S3 clips service not available");
29764
+ }
29765
+ const nextVideo = await s3ClipsService.getClipById(nextClipMeta.clipId);
29766
+ if (nextVideo) {
29767
+ setPendingVideo(nextVideo);
29768
+ setCurrentClipId(nextClipMeta.clipId);
29769
+ setAllVideos([nextVideo]);
29403
29770
  setCurrentIndex(0);
29404
- setCategoryPosition(categoryPosition + 1);
29405
- setIsNavigating(false);
29406
- videoRetryCountRef.current = 0;
29771
+ setCurrentMetadataIndex(nextMetadataIndex);
29772
+ currentMetadataIndexRef.current = nextMetadataIndex;
29773
+ console.log(`[handleNext] Successfully loaded next clip: ${nextVideo.id} (${nextMetadataIndex + 1}/${metadataArray.length})`);
29407
29774
  } else {
29408
- console.log(`[handleNext] No next clip available`);
29409
- setIsNavigating(false);
29775
+ console.error(`[handleNext] Failed to load next video for clip ID: ${nextClipMeta.clipId}`);
29776
+ clearLoadingState();
29410
29777
  }
29778
+ } else {
29779
+ console.log(`[handleNext] Already at last clip in category`);
29780
+ clearLoadingState();
29411
29781
  }
29412
29782
  } catch (error2) {
29413
29783
  console.error(`[handleNext] Error navigating:`, error2);
29414
29784
  setError("Failed to navigate to next clip");
29415
- setIsNavigating(false);
29785
+ clearLoadingState();
29416
29786
  }
29417
- }, [currentIndex, allVideos, currentClipId, workspaceId, date, effectiveShift, s3ClipsService, categoryPosition, isPercentileCategory]);
29787
+ }, [clearLoadingState, s3ClipsService]);
29418
29788
  const handlePrevious = useCallback(async () => {
29419
29789
  if (!isMountedRef.current) return;
29420
29790
  const currentFilter = activeFilterRef.current;
29421
- console.log(`[handlePrevious] Navigating in category: ${currentFilter}, current index: ${currentIndex}`);
29422
- setIsNavigating(true);
29791
+ setIsTransitioning(true);
29792
+ setIsInitialLoading(true);
29423
29793
  setError(null);
29424
29794
  try {
29425
- if (isPercentileCategory(currentFilter)) {
29426
- if (currentIndex > 0) {
29427
- const prevIndex = currentIndex - 1;
29428
- const prevVideo = allVideos[prevIndex];
29429
- console.log(`[handlePrevious] Moving to previous percentile clip: ${prevVideo.id} (index ${prevIndex})`);
29430
- setCurrentClipId(prevVideo.id);
29431
- setCurrentIndex(prevIndex);
29432
- setCategoryPosition(prevIndex + 1);
29433
- setIsNavigating(false);
29434
- } else {
29435
- console.log(`[handlePrevious] Already at first clip in percentile category`);
29436
- setIsNavigating(false);
29437
- }
29438
- } else {
29439
- if (!currentClipId || !s3ClipsService) {
29440
- setIsNavigating(false);
29441
- return;
29442
- }
29443
- const neighbors = await s3ClipsService.getNeighboringClips(
29444
- workspaceId,
29445
- date || getOperationalDate(),
29446
- effectiveShift,
29447
- currentFilter,
29448
- currentClipId
29449
- );
29450
- if (neighbors.previous) {
29451
- console.log(`[handlePrevious] Found previous clip: ${neighbors.previous.id}`);
29452
- setCurrentClipId(neighbors.previous.id || null);
29453
- setAllVideos([neighbors.previous]);
29795
+ const currentMetaIndex = currentMetadataIndexRef.current;
29796
+ const metadataArray = categoryMetadataRef.current;
29797
+ console.log(`[handlePrevious] Unified navigation: ${currentFilter}, metadata index: ${currentMetaIndex}/${metadataArray.length}`);
29798
+ if (currentMetaIndex > 0) {
29799
+ const prevMetadataIndex = currentMetaIndex - 1;
29800
+ const prevClipMeta = metadataArray[prevMetadataIndex];
29801
+ if (!s3ClipsService) {
29802
+ throw new Error("S3 clips service not available");
29803
+ }
29804
+ const prevVideo = await s3ClipsService.getClipById(prevClipMeta.clipId);
29805
+ if (prevVideo) {
29806
+ setPendingVideo(prevVideo);
29807
+ setCurrentClipId(prevClipMeta.clipId);
29808
+ setAllVideos([prevVideo]);
29454
29809
  setCurrentIndex(0);
29455
- setCategoryPosition(Math.max(1, categoryPosition - 1));
29456
- setIsNavigating(false);
29457
- videoRetryCountRef.current = 0;
29458
- } else {
29459
- console.log(`[handlePrevious] No previous clip available`);
29460
- setIsNavigating(false);
29810
+ setCurrentMetadataIndex(prevMetadataIndex);
29811
+ currentMetadataIndexRef.current = prevMetadataIndex;
29812
+ console.log(`[handlePrevious] Loaded previous clip: ${prevVideo.id} (${prevMetadataIndex + 1}/${metadataArray.length})`);
29461
29813
  }
29814
+ } else {
29815
+ console.log(`[handlePrevious] Already at first clip in category`);
29816
+ clearLoadingState();
29462
29817
  }
29463
29818
  } catch (error2) {
29464
29819
  console.error(`[handlePrevious] Error navigating:`, error2);
29465
29820
  setError("Failed to navigate to previous clip");
29466
- setIsNavigating(false);
29821
+ clearLoadingState();
29467
29822
  }
29468
- }, [currentIndex, allVideos, currentClipId, workspaceId, date, effectiveShift, s3ClipsService, categoryPosition, isPercentileCategory]);
29823
+ }, [clearLoadingState, s3ClipsService]);
29469
29824
  const currentVideo = useMemo(() => {
29470
29825
  if (!filteredVideos || filteredVideos.length === 0 || currentIndex >= filteredVideos.length) {
29471
29826
  return null;
@@ -29473,7 +29828,7 @@ var BottlenecksContent = ({
29473
29828
  return filteredVideos[currentIndex];
29474
29829
  }, [filteredVideos, currentIndex]);
29475
29830
  const handleVideoReady = useCallback((player) => {
29476
- console.log("Video.js player ready");
29831
+ console.log("Video.js player ready - NOT clearing loading (wait for playing event)");
29477
29832
  videoRetryCountRef.current = 0;
29478
29833
  if (error?.includes("Retrying")) {
29479
29834
  setError(null);
@@ -29481,6 +29836,7 @@ var BottlenecksContent = ({
29481
29836
  }, [error]);
29482
29837
  const handleVideoPlay = useCallback(async (player) => {
29483
29838
  setIsPlaying(true);
29839
+ setIsInitialLoading(false);
29484
29840
  if (currentVideo && !currentVideo.creation_timestamp && s3ClipsService) {
29485
29841
  try {
29486
29842
  const originalUri = currentVideo.originalUri || currentVideo.src;
@@ -29510,6 +29866,17 @@ var BottlenecksContent = ({
29510
29866
  const handleDurationChange = useCallback((player, duration2) => {
29511
29867
  setDuration(duration2);
29512
29868
  }, []);
29869
+ const handleLoadedData = useCallback((player) => {
29870
+ console.log("Video data loaded - NOT clearing loading (wait for playing event)");
29871
+ }, []);
29872
+ const handleVideoPlaying = useCallback((player) => {
29873
+ console.log("Video playing - hiding transition overlay (most reliable)");
29874
+ clearLoadingState();
29875
+ }, [clearLoadingState]);
29876
+ const handleVideoLoadingChange = useCallback((isLoading2) => {
29877
+ console.log(`[BottlenecksContent] Video loading state changed: ${isLoading2}`);
29878
+ setIsVideoBuffering(isLoading2);
29879
+ }, []);
29513
29880
  const handleVideoEnded = useCallback((player) => {
29514
29881
  handleNext();
29515
29882
  }, [handleNext]);
@@ -29546,6 +29913,10 @@ var BottlenecksContent = ({
29546
29913
  isMountedRef.current = false;
29547
29914
  loadingCategoryRef.current = null;
29548
29915
  fetchInProgressRef.current.clear();
29916
+ if (loadingTimeoutRef.current) {
29917
+ clearTimeout(loadingTimeoutRef.current);
29918
+ loadingTimeoutRef.current = null;
29919
+ }
29549
29920
  setIsCategoryLoading(false);
29550
29921
  setIsNavigating(false);
29551
29922
  };
@@ -29555,6 +29926,14 @@ var BottlenecksContent = ({
29555
29926
  setError(null);
29556
29927
  }
29557
29928
  }, [currentIndex, filteredVideos]);
29929
+ useEffect(() => {
29930
+ if (!isTransitioning && pendingVideo) {
29931
+ const timer = setTimeout(() => {
29932
+ setPendingVideo(null);
29933
+ }, 200);
29934
+ return () => clearTimeout(timer);
29935
+ }
29936
+ }, [isTransitioning, pendingVideo]);
29558
29937
  useEffect(() => {
29559
29938
  const handleKeyDown = (e) => {
29560
29939
  if (e.key === "ArrowLeft") {
@@ -29655,173 +30034,166 @@ var BottlenecksContent = ({
29655
30034
  }
29656
30035
  const activeCategory = categoriesToShow.find((cat) => cat.type === activeFilter);
29657
30036
  if (activeCategory) {
29658
- return `${activeCategory.label} (${mergedCounts[activeCategory.type] || 0})`;
30037
+ return `${activeCategory.label} (${getCategoryCount(activeCategory.type)})`;
29659
30038
  }
29660
- return `${activeFilter.replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase())} (${mergedCounts[activeFilter] || 0})`;
30039
+ return `${activeFilter.replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase())} (${getCategoryCount(activeFilter)})`;
29661
30040
  })() }),
29662
30041
  /* @__PURE__ */ jsxs("div", { className: "flex items-center space-x-2", children: [
29663
30042
  /* @__PURE__ */ jsx(
29664
30043
  "button",
29665
30044
  {
29666
30045
  onClick: handlePrevious,
29667
- disabled: categoryPosition <= 1 || getCategoryCount(activeFilter) === 0,
29668
- className: `p-2 rounded-full transition-colors ${categoryPosition <= 1 || getCategoryCount(activeFilter) === 0 ? "text-gray-300 cursor-not-allowed" : "text-gray-600 hover:bg-gray-100"}`,
30046
+ disabled: currentMetadataIndex <= 0 || categoryMetadata.length === 0,
30047
+ className: `p-2 rounded-full transition-colors ${currentMetadataIndex <= 0 || categoryMetadata.length === 0 ? "text-gray-300 cursor-not-allowed" : "text-gray-600 hover:bg-gray-100"}`,
29669
30048
  "aria-label": "Previous video",
29670
30049
  children: /* @__PURE__ */ jsx(ChevronLeft, { className: "h-5 w-5" })
29671
30050
  }
29672
30051
  ),
29673
30052
  /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-1", children: [
29674
- /* @__PURE__ */ jsx("span", { className: "text-sm px-2 py-1 bg-blue-50 text-blue-700 rounded-full font-medium tabular-nums", children: getCategoryCount(activeFilter) > 0 ? `${categoryPosition} / ${getCategoryCount(activeFilter)}` : "0 / 0" }),
30053
+ /* @__PURE__ */ jsx("span", { className: "text-sm px-2 py-1 bg-blue-50 text-blue-700 rounded-full font-medium tabular-nums", children: categoryMetadata.length > 0 ? `${currentMetadataIndex + 1} / ${categoryMetadata.length}` : "0 / 0" }),
29675
30054
  error && /* @__PURE__ */ jsx("span", { className: "text-xs text-red-600 font-medium", children: error })
29676
30055
  ] }),
29677
30056
  /* @__PURE__ */ jsx(
29678
30057
  "button",
29679
30058
  {
29680
30059
  onClick: handleNext,
29681
- disabled: categoryPosition >= getCategoryCount(activeFilter) || getCategoryCount(activeFilter) === 0,
29682
- className: `p-2 rounded-full transition-colors ${categoryPosition >= getCategoryCount(activeFilter) || getCategoryCount(activeFilter) === 0 ? "text-gray-300 cursor-not-allowed" : "text-gray-600 hover:bg-gray-100"}`,
30060
+ disabled: currentMetadataIndex >= categoryMetadata.length - 1 || categoryMetadata.length === 0,
30061
+ className: `p-2 rounded-full transition-colors ${currentMetadataIndex >= categoryMetadata.length - 1 || categoryMetadata.length === 0 ? "text-gray-300 cursor-not-allowed" : "text-gray-600 hover:bg-gray-100"}`,
29683
30062
  "aria-label": "Next video",
29684
30063
  children: /* @__PURE__ */ jsx(ChevronRight, { className: "h-5 w-5" })
29685
30064
  }
29686
30065
  )
29687
30066
  ] })
29688
30067
  ] }) }),
29689
- /* Priority 1: Show loading if initial load hasn't completed yet */
29690
- isLoading && !hasInitialLoad ? /* @__PURE__ */ jsx("div", { className: "p-4 h-[calc(100%-4rem)]", children: /* @__PURE__ */ jsx("div", { className: "relative h-full", children: /* @__PURE__ */ jsx("div", { className: "relative w-full h-full overflow-hidden rounded-md shadow-inner bg-gray-900 flex items-center justify-center", children: /* @__PURE__ */ jsx(OptifyeLogoLoader_default, { size: "md", message: "Loading clips..." }) }) }) }) : (
29691
- /* Priority 2: Show loading if category is loading BUT only if no video is available */
29692
- isCategoryLoading && (!filteredVideos.length || !currentVideo) ? /* @__PURE__ */ jsx("div", { className: "p-4 h-[calc(100%-4rem)]", children: /* @__PURE__ */ jsx("div", { className: "relative h-full", children: /* @__PURE__ */ jsx("div", { className: "relative w-full h-full overflow-hidden rounded-md shadow-inner bg-gray-900 flex items-center justify-center", children: /* @__PURE__ */ jsx(OptifyeLogoLoader_default, { size: "md", message: "Loading videos..." }) }) }) }) : (
29693
- /* Priority 3: Show loading if navigating and current video not available */
29694
- isNavigating || currentIndex >= filteredVideos.length && currentIndex < (mergedCounts[activeFilter] || 0) ? /* @__PURE__ */ jsx("div", { className: "p-4 h-[calc(100%-4rem)]", children: /* @__PURE__ */ jsx("div", { className: "relative h-full", children: /* @__PURE__ */ jsx("div", { className: "relative w-full h-full overflow-hidden rounded-md shadow-inner bg-gray-900 flex items-center justify-center", children: /* @__PURE__ */ jsx(OptifyeLogoLoader_default, { size: "md", message: "Loading video..." }) }) }) }) : (
29695
- /* Priority 4: Show video if we have filtered videos and current video */
29696
- filteredVideos.length > 0 && currentVideo ? /* @__PURE__ */ jsx("div", { className: "p-4 h-[calc(100%-4rem)]", children: /* @__PURE__ */ jsx("div", { className: "relative h-full group", children: /* @__PURE__ */ jsxs("div", { className: "relative w-full h-full overflow-hidden rounded-md shadow-inner bg-gray-900", children: [
29697
- /* @__PURE__ */ jsx(
29698
- CroppedVideoPlayer,
29699
- {
29700
- ref: videoRef,
29701
- src: currentVideo.src,
29702
- className: "w-full h-full",
29703
- crop: workspaceCrop?.crop || null,
29704
- autoplay: true,
29705
- playsInline: true,
29706
- loop: false,
29707
- onReady: handleVideoReady,
29708
- onPlay: handleVideoPlay,
29709
- onPause: handleVideoPause,
29710
- onTimeUpdate: handleTimeUpdate,
29711
- onDurationChange: handleDurationChange,
29712
- onEnded: handleVideoEnded,
29713
- onError: handleVideoError,
29714
- options: {
29715
- // Ensure full height is always visible - no cropping
29716
- fluid: false,
29717
- responsive: false,
29718
- fill: false
29719
- }
29720
- },
29721
- currentVideo.id
29722
- ),
29723
- /* @__PURE__ */ jsx(
29724
- "div",
29725
- {
29726
- className: "absolute inset-0 z-10 cursor-pointer",
29727
- onClick: togglePlayback
30068
+ /* Show video if we have filtered videos and current video, or show loading */
30069
+ filteredVideos.length > 0 && currentVideo ? /* @__PURE__ */ jsx("div", { className: "p-4 h-[calc(100%-4rem)]", children: /* @__PURE__ */ jsx("div", { className: "relative h-full group", children: /* @__PURE__ */ jsxs("div", { className: "relative w-full h-full overflow-hidden rounded-md shadow-inner bg-gray-900", children: [
30070
+ /* @__PURE__ */ jsx(
30071
+ CroppedVideoPlayer,
30072
+ {
30073
+ ref: videoRef,
30074
+ src: currentVideo.src,
30075
+ className: "w-full h-full",
30076
+ crop: workspaceCrop?.crop || null,
30077
+ onClick: togglePlayback,
30078
+ autoplay: true,
30079
+ playsInline: true,
30080
+ loop: false,
30081
+ externalLoadingControl: true,
30082
+ onReady: handleVideoReady,
30083
+ onPlay: handleVideoPlay,
30084
+ onPause: handleVideoPause,
30085
+ onTimeUpdate: handleTimeUpdate,
30086
+ onDurationChange: handleDurationChange,
30087
+ onEnded: handleVideoEnded,
30088
+ onError: handleVideoError,
30089
+ onLoadedData: handleLoadedData,
30090
+ onPlaying: handleVideoPlaying,
30091
+ onLoadingChange: handleVideoLoadingChange,
30092
+ options: {
30093
+ // Ensure full height is always visible - no cropping
30094
+ fluid: false,
30095
+ responsive: false,
30096
+ fill: false
30097
+ }
30098
+ }
30099
+ ),
30100
+ (isTransitioning || isVideoBuffering && isInitialLoading) && /* @__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..." }) }),
30101
+ !isTransitioning && isVideoBuffering && !isInitialLoading && /* @__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..." }) }),
30102
+ error && /* @__PURE__ */ jsx("div", { className: "absolute inset-0 flex items-center justify-center bg-black/80 text-white p-4", children: /* @__PURE__ */ jsxs("div", { className: "text-center max-w-md", children: [
30103
+ /* @__PURE__ */ jsx("svg", { className: "w-16 h-16 mx-auto mb-4 text-red-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.732-.833-2.5 0L4.268 16.5c-.77.833.192 2.5 1.732 2.5z" }) }),
30104
+ /* @__PURE__ */ jsx("h3", { className: "text-lg font-semibold mb-2", children: "Video Stream Error" }),
30105
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-gray-300 mb-4", children: "The video stream appears to be corrupted or unavailable. This may be due to:" }),
30106
+ /* @__PURE__ */ jsxs("ul", { className: "text-sm text-gray-300 text-left space-y-1 mb-4", children: [
30107
+ /* @__PURE__ */ jsx("li", { children: "\u2022 Incomplete video encoding" }),
30108
+ /* @__PURE__ */ jsx("li", { children: "\u2022 Network connectivity issues" }),
30109
+ /* @__PURE__ */ jsx("li", { children: "\u2022 Server processing errors" })
30110
+ ] }),
30111
+ /* @__PURE__ */ jsx(
30112
+ "button",
30113
+ {
30114
+ onClick: () => {
30115
+ setError(null);
30116
+ if (videoRef.current) {
30117
+ videoRef.current.dispose();
29728
30118
  }
29729
- ),
29730
- error && /* @__PURE__ */ jsx("div", { className: "absolute inset-0 flex items-center justify-center bg-black/80 text-white p-4", children: /* @__PURE__ */ jsxs("div", { className: "text-center max-w-md", children: [
29731
- /* @__PURE__ */ jsx("svg", { className: "w-16 h-16 mx-auto mb-4 text-red-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.732-.833-2.5 0L4.268 16.5c-.77.833.192 2.5 1.732 2.5z" }) }),
29732
- /* @__PURE__ */ jsx("h3", { className: "text-lg font-semibold mb-2", children: "Video Stream Error" }),
29733
- /* @__PURE__ */ jsx("p", { className: "text-sm text-gray-300 mb-4", children: "The video stream appears to be corrupted or unavailable. This may be due to:" }),
29734
- /* @__PURE__ */ jsxs("ul", { className: "text-sm text-gray-300 text-left space-y-1 mb-4", children: [
29735
- /* @__PURE__ */ jsx("li", { children: "\u2022 Incomplete video encoding" }),
29736
- /* @__PURE__ */ jsx("li", { children: "\u2022 Network connectivity issues" }),
29737
- /* @__PURE__ */ jsx("li", { children: "\u2022 Server processing errors" })
29738
- ] }),
29739
- /* @__PURE__ */ jsx(
29740
- "button",
29741
- {
29742
- onClick: () => {
29743
- setError(null);
29744
- if (videoRef.current) {
29745
- videoRef.current.dispose();
29746
- }
29747
- },
29748
- className: "px-4 py-2 bg-blue-600 hover:bg-blue-700 rounded text-sm font-medium",
29749
- children: "Retry"
29750
- }
29751
- )
29752
- ] }) }),
29753
- (currentVideo.type === "cycle_completion" || currentVideo.type === "bottleneck" && currentVideo.description.toLowerCase().includes("cycle time")) && currentVideo.cycle_time_seconds || currentVideo.type === "idle_time" || currentVideo.type === "low_value" ? /* @__PURE__ */ jsx("div", { className: "absolute top-3 left-3 z-10 bg-black/60 backdrop-blur-sm px-3 py-1.5 rounded-lg text-white shadow-lg text-xs", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center", children: [
29754
- /* @__PURE__ */ jsx("div", { className: `flex-shrink-0 h-2.5 w-2.5 rounded-full ${currentVideo.type === "low_value" || currentVideo.type === "idle_time" ? "bg-purple-400" : isPercentileCategory(activeFilterRef.current) ? activeFilterRef.current === "fast-cycles" ? "bg-green-600" : activeFilterRef.current === "slow-cycles" ? "bg-red-700" : "bg-orange-500" : currentVideo.type === "cycle_completion" ? "bg-blue-600" : "bg-gray-500"} mr-2 animate-pulse` }),
29755
- (currentVideo.type === "cycle_completion" || currentVideo.type === "bottleneck" && currentVideo.description.toLowerCase().includes("cycle time")) && currentVideo.cycle_time_seconds ? /* @__PURE__ */ jsxs("span", { className: "opacity-90 font-mono bg-black/30 px-2 py-0.5 rounded", children: [
29756
- "Cycle time: ",
29757
- currentVideo.cycle_time_seconds.toFixed(1),
29758
- "s"
29759
- ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
29760
- /* @__PURE__ */ jsx("span", { className: "font-medium mr-2", children: getClipTypeLabel(currentVideo) }),
29761
- /* @__PURE__ */ jsx("span", { className: "opacity-80 hidden sm:inline", children: currentVideo.description })
29762
- ] })
29763
- ] }) }) : (
29764
- /* Right side display for other video types */
29765
- /* @__PURE__ */ jsx("div", { className: "absolute top-3 right-3 z-10 bg-black/60 backdrop-blur-sm px-3 py-1.5 rounded-lg text-white shadow-lg text-xs", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center", children: [
29766
- /* @__PURE__ */ jsx("div", { className: `flex-shrink-0 h-2.5 w-2.5 rounded-full ${getSeverityColor(currentVideo.severity)} mr-2 animate-pulse` }),
29767
- /* @__PURE__ */ jsx("span", { className: "font-medium mr-2", children: getClipTypeLabel(currentVideo) }),
29768
- /* @__PURE__ */ jsx("span", { className: "opacity-80 hidden sm:inline", children: currentVideo.description })
29769
- ] }) })
29770
- ),
29771
- /* @__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: [
29772
- /* @__PURE__ */ jsx(
29773
- "button",
29774
- {
29775
- onClick: togglePlayback,
29776
- className: "p-1.5 hover:bg-white/20 rounded-full focus:outline-none focus:ring-2 focus:ring-white/50",
29777
- "aria-label": isPlaying ? "Pause" : "Play",
29778
- 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" }) })
29779
- }
29780
- ),
29781
- /* @__PURE__ */ jsxs("span", { className: "text-xs font-mono px-2", children: [
29782
- formatTime2(currentTime),
29783
- " / ",
29784
- formatTime2(duration)
29785
- ] }),
29786
- /* @__PURE__ */ jsx(
29787
- "input",
29788
- {
29789
- type: "range",
29790
- min: "0",
29791
- max: duration || 0,
29792
- value: currentTime,
29793
- onChange: (e) => {
29794
- if (videoRef.current) {
29795
- videoRef.current.currentTime(Number(e.target.value));
29796
- }
29797
- },
29798
- 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",
29799
- style: {
29800
- WebkitAppearance: "none",
29801
- appearance: "none"
29802
- },
29803
- "aria-label": "Seek slider"
29804
- }
29805
- )
29806
- ] }) })
29807
- ] }) }) }) : (
29808
- /* Priority 5: Show "no clips found" only if we have counts and there are truly no clips for workspace */
29809
- hasInitialLoad && Object.keys(mergedCounts).length > 0 && Object.values(mergedCounts).every((count) => count === 0) ? /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center h-[calc(100%-4rem)]", children: /* @__PURE__ */ jsxs("div", { className: "text-center p-8", children: [
29810
- /* @__PURE__ */ jsx("svg", { className: "w-16 h-16 text-gray-300 mx-auto mb-4", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M15 10l4.553-2.276A1 1 0 0121 8.618v6.764a1 1 0 01-1.447.894L15 14M5 18h8a2 2 0 002-2V8a2 2 0 00-2-2H5a2 2 0 00-2 2v8a2 2 0 002 2z" }) }),
29811
- /* @__PURE__ */ jsx("h3", { className: "text-xl font-medium text-gray-700 mb-2", children: "No Clips Found" }),
29812
- /* @__PURE__ */ jsx("p", { className: "text-gray-500", children: "There were no video clips found for this workspace today." })
29813
- ] }) }) : (
29814
- /* Priority 6: Show "no matching clips" only if we have data loaded and specifically no clips for this filter */
29815
- hasInitialLoad && (mergedCounts[activeFilter] || 0) === 0 ? /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center h-[calc(100%-4rem)]", children: /* @__PURE__ */ jsxs("div", { className: "text-center p-8", children: [
29816
- /* @__PURE__ */ jsx("svg", { className: "w-16 h-16 text-gray-300 mx-auto mb-4", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M15 10l4.553-2.276A1 1 0 0121 8.618v6.764a1 1 0 01-1.447.894L15 14M5 18h8a2 2 0 002-2V8a2 2 0 00-2-2H5a2 2 0 00-2 2v8a2 2 0 002 2z" }) }),
29817
- /* @__PURE__ */ jsx("h3", { className: "text-xl font-medium text-gray-700 mb-2", children: "No Matching Clips" }),
29818
- /* @__PURE__ */ jsx("p", { className: "text-gray-500", children: "There are no clips matching the selected filter." })
29819
- ] }) }) : (
29820
- /* Priority 7: Default loading state for any other case */
29821
- /* @__PURE__ */ jsx("div", { className: "p-4 h-[calc(100%-4rem)]", children: /* @__PURE__ */ jsx("div", { className: "relative h-full", children: /* @__PURE__ */ jsx("div", { className: "relative w-full h-full overflow-hidden rounded-md shadow-inner bg-gray-900 flex items-center justify-center", children: /* @__PURE__ */ jsx(OptifyeLogoLoader_default, { size: "md", message: "Loading..." }) }) }) })
29822
- )
29823
- )
29824
- )
30119
+ },
30120
+ className: "px-4 py-2 bg-blue-600 hover:bg-blue-700 rounded text-sm font-medium",
30121
+ children: "Retry"
30122
+ }
30123
+ )
30124
+ ] }) }),
30125
+ (currentVideo.type === "cycle_completion" || currentVideo.type === "bottleneck" && currentVideo.description.toLowerCase().includes("cycle time")) && currentVideo.cycle_time_seconds || currentVideo.type === "idle_time" || currentVideo.type === "low_value" ? /* @__PURE__ */ jsx("div", { className: "absolute top-3 left-3 z-10 bg-black/60 backdrop-blur-sm px-3 py-1.5 rounded-lg text-white shadow-lg text-xs", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center", children: [
30126
+ /* @__PURE__ */ jsx("div", { className: `flex-shrink-0 h-2.5 w-2.5 rounded-full ${currentVideo.type === "low_value" || currentVideo.type === "idle_time" ? "bg-purple-400" : isPercentileCategory(activeFilterRef.current) ? activeFilterRef.current === "fast-cycles" ? "bg-green-600" : activeFilterRef.current === "slow-cycles" ? "bg-red-700" : "bg-orange-500" : currentVideo.type === "cycle_completion" ? "bg-blue-600" : "bg-gray-500"} mr-2 animate-pulse` }),
30127
+ (currentVideo.type === "cycle_completion" || currentVideo.type === "bottleneck" && currentVideo.description.toLowerCase().includes("cycle time")) && currentVideo.cycle_time_seconds ? /* @__PURE__ */ jsxs("span", { className: "opacity-90 font-mono bg-black/30 px-2 py-0.5 rounded", children: [
30128
+ "Cycle time: ",
30129
+ currentVideo.cycle_time_seconds.toFixed(1),
30130
+ "s"
30131
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
30132
+ /* @__PURE__ */ jsx("span", { className: "font-medium mr-2", children: getClipTypeLabel(currentVideo) }),
30133
+ /* @__PURE__ */ jsx("span", { className: "opacity-80 hidden sm:inline", children: currentVideo.description })
30134
+ ] })
30135
+ ] }) }) : (
30136
+ /* Right side display for other video types */
30137
+ /* @__PURE__ */ jsx("div", { className: "absolute top-3 right-3 z-10 bg-black/60 backdrop-blur-sm px-3 py-1.5 rounded-lg text-white shadow-lg text-xs", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center", children: [
30138
+ /* @__PURE__ */ jsx("div", { className: `flex-shrink-0 h-2.5 w-2.5 rounded-full ${getSeverityColor(currentVideo.severity)} mr-2 animate-pulse` }),
30139
+ /* @__PURE__ */ jsx("span", { className: "font-medium mr-2", children: getClipTypeLabel(currentVideo) }),
30140
+ /* @__PURE__ */ jsx("span", { className: "opacity-80 hidden sm:inline", children: currentVideo.description })
30141
+ ] }) })
30142
+ ),
30143
+ /* @__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: [
30144
+ /* @__PURE__ */ jsx(
30145
+ "button",
30146
+ {
30147
+ onClick: (e) => {
30148
+ e.stopPropagation();
30149
+ togglePlayback();
30150
+ },
30151
+ className: "p-1.5 hover:bg-white/20 rounded-full focus:outline-none focus:ring-2 focus:ring-white/50",
30152
+ "aria-label": isPlaying ? "Pause" : "Play",
30153
+ 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" }) })
30154
+ }
30155
+ ),
30156
+ /* @__PURE__ */ jsxs("span", { className: "text-xs font-mono px-2", children: [
30157
+ formatTime2(currentTime),
30158
+ " / ",
30159
+ formatTime2(duration)
30160
+ ] }),
30161
+ /* @__PURE__ */ jsx(
30162
+ "input",
30163
+ {
30164
+ type: "range",
30165
+ min: "0",
30166
+ max: duration || 0,
30167
+ value: currentTime,
30168
+ onChange: (e) => {
30169
+ if (videoRef.current) {
30170
+ videoRef.current.currentTime(Number(e.target.value));
30171
+ }
30172
+ },
30173
+ 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",
30174
+ style: {
30175
+ WebkitAppearance: "none",
30176
+ appearance: "none"
30177
+ },
30178
+ "aria-label": "Seek slider"
30179
+ }
30180
+ )
30181
+ ] }) })
30182
+ ] }) }) }) : (
30183
+ /* Priority 5: Show "no clips found" only if we have counts and there are truly no clips for workspace */
30184
+ hasInitialLoad && Object.keys(mergedCounts).length > 0 && Object.values(mergedCounts).every((count) => count === 0) ? /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center h-[calc(100%-4rem)]", children: /* @__PURE__ */ jsxs("div", { className: "text-center p-8", children: [
30185
+ /* @__PURE__ */ jsx("svg", { className: "w-16 h-16 text-gray-300 mx-auto mb-4", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M15 10l4.553-2.276A1 1 0 0121 8.618v6.764a1 1 0 01-1.447.894L15 14M5 18h8a2 2 0 002-2V8a2 2 0 00-2-2H5a2 2 0 00-2 2v8a2 2 0 002 2z" }) }),
30186
+ /* @__PURE__ */ jsx("h3", { className: "text-xl font-medium text-gray-700 mb-2", children: "No Clips Found" }),
30187
+ /* @__PURE__ */ jsx("p", { className: "text-gray-500", children: "There were no video clips found for this workspace today." })
30188
+ ] }) }) : (
30189
+ /* Priority 6: Show "no matching clips" only if we have data loaded and specifically no clips for this filter */
30190
+ hasInitialLoad && (mergedCounts[activeFilter] || 0) === 0 ? /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center h-[calc(100%-4rem)]", children: /* @__PURE__ */ jsxs("div", { className: "text-center p-8", children: [
30191
+ /* @__PURE__ */ jsx("svg", { className: "w-16 h-16 text-gray-300 mx-auto mb-4", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M15 10l4.553-2.276A1 1 0 0121 8.618v6.764a1 1 0 01-1.447.894L15 14M5 18h8a2 2 0 002-2V8a2 2 0 00-2-2H5a2 2 0 00-2 2v8a2 2 0 002 2z" }) }),
30192
+ /* @__PURE__ */ jsx("h3", { className: "text-xl font-medium text-gray-700 mb-2", children: "No Matching Clips" }),
30193
+ /* @__PURE__ */ jsx("p", { className: "text-gray-500", children: "There are no clips matching the selected filter." })
30194
+ ] }) }) : (
30195
+ /* Priority 7: Default loading state for any other case */
30196
+ /* @__PURE__ */ jsx("div", { className: "p-4 h-[calc(100%-4rem)]", children: /* @__PURE__ */ jsx("div", { className: "relative h-full", children: /* @__PURE__ */ jsx("div", { className: "relative w-full h-full overflow-hidden rounded-md shadow-inner bg-gray-900 flex items-center justify-center", children: /* @__PURE__ */ jsx(OptifyeLogoLoader_default, { size: "md", message: "Loading..." }) }) }) })
29825
30197
  )
29826
30198
  )
29827
30199
  )
@@ -29839,7 +30211,7 @@ var BottlenecksContent = ({
29839
30211
  currentVideoId: currentVideo?.id,
29840
30212
  counts: mergedCounts,
29841
30213
  workspaceId,
29842
- date: date || getOperationalDate(),
30214
+ date: date || getOperationalDate(timezone),
29843
30215
  shift: effectiveShift,
29844
30216
  onFilterChange: (filterId) => {
29845
30217
  updateActiveFilter(filterId);
@@ -29864,9 +30236,9 @@ var BottlenecksContent = ({
29864
30236
  }
29865
30237
  }
29866
30238
  },
29867
- onClipSelect: (categoryId, clipId) => {
29868
- console.log(`[BottlenecksContent] Clip selected: ${categoryId}, clipId ${clipId}`);
29869
- loadAndPlayClipById(clipId, categoryId);
30239
+ onClipSelect: (categoryId, clipId, position) => {
30240
+ console.log(`[BottlenecksContent] Clip selected: ${categoryId}, clipId ${clipId}, position=${position}`);
30241
+ loadAndPlayClipById(clipId, categoryId, position);
29870
30242
  const category = categoriesToShow.find((cat) => cat.type === categoryId);
29871
30243
  if (category) {
29872
30244
  trackCoreEvent(`${category.label} Clip Selected`, {
@@ -29993,7 +30365,7 @@ var arePropsEqual = (prevProps, nextProps) => {
29993
30365
  return prevProps.data.efficiency === nextProps.data.efficiency && prevProps.data.trend_score === nextProps.data.trend_score && prevProps.data.workspace_id === nextProps.data.workspace_id && prevProps.data.workspace_name === nextProps.data.workspace_name && prevProps.isBottleneck === nextProps.isBottleneck && prevProps.isLowEfficiency === nextProps.isLowEfficiency && prevProps.isVeryLowEfficiency === nextProps.isVeryLowEfficiency && // Position doesn't need deep equality check as it's generally static
29994
30366
  prevProps.position.id === nextProps.position.id;
29995
30367
  };
29996
- var WorkspaceGridItem = React20__default.memo(({
30368
+ var WorkspaceGridItem = React21__default.memo(({
29997
30369
  data,
29998
30370
  position,
29999
30371
  isBottleneck = false,
@@ -30086,7 +30458,7 @@ var WorkspaceGridItem = React20__default.memo(({
30086
30458
  );
30087
30459
  }, arePropsEqual);
30088
30460
  WorkspaceGridItem.displayName = "WorkspaceGridItem";
30089
- var WorkspaceGrid = React20__default.memo(({
30461
+ var WorkspaceGrid = React21__default.memo(({
30090
30462
  workspaces,
30091
30463
  isPdfMode = false,
30092
30464
  customWorkspacePositions,
@@ -30280,7 +30652,7 @@ var KPICard = ({
30280
30652
  }) => {
30281
30653
  useThemeConfig();
30282
30654
  const { formatNumber } = useFormatNumber();
30283
- const trendInfo = React20__default.useMemo(() => {
30655
+ const trendInfo = React21__default.useMemo(() => {
30284
30656
  let trendValue = trend || "neutral";
30285
30657
  if (change !== void 0 && trend === void 0) {
30286
30658
  trendValue = change > 0 ? "up" : change < 0 ? "down" : "neutral";
@@ -30303,7 +30675,7 @@ var KPICard = ({
30303
30675
  const shouldShowTrend = !(change === 0 && trend === void 0);
30304
30676
  return { trendValue, Icon: Icon2, colorClass, shouldShowTrend };
30305
30677
  }, [trend, change]);
30306
- const formattedValue = React20__default.useMemo(() => {
30678
+ const formattedValue = React21__default.useMemo(() => {
30307
30679
  if (title === "Quality Compliance" && typeof value === "number") {
30308
30680
  return value.toFixed(1);
30309
30681
  }
@@ -30317,7 +30689,7 @@ var KPICard = ({
30317
30689
  }
30318
30690
  return value;
30319
30691
  }, [value, title]);
30320
- const formattedChange = React20__default.useMemo(() => {
30692
+ const formattedChange = React21__default.useMemo(() => {
30321
30693
  if (change === void 0 || change === 0) return null;
30322
30694
  const absChange = Math.abs(change);
30323
30695
  return formatNumber(absChange, { minimumFractionDigits: 0, maximumFractionDigits: 1 });
@@ -31066,11 +31438,11 @@ var HealthStatusGrid = ({
31066
31438
  filteredWorkspaces.length === 0 && /* @__PURE__ */ jsx("div", { className: "text-center py-12", children: /* @__PURE__ */ jsx("p", { className: "text-gray-500 dark:text-gray-400", children: searchTerm || statusFilter !== "all" ? "No workspaces found matching your filters." : "No workspaces available." }) })
31067
31439
  ] });
31068
31440
  };
31069
- var ISTTimer2 = ISTTimer_default;
31441
+ var Timer2 = Timer_default;
31070
31442
  var DashboardHeader = memo(({ lineTitle, className = "", headerControls }) => {
31071
31443
  const dashboardConfig = useDashboardConfig();
31444
+ const timezone = useAppTimezone();
31072
31445
  const getShiftName = () => {
31073
- const timezone = dashboardConfig.dateTimeConfig?.defaultTimezone || "Asia/Kolkata";
31074
31446
  const currentShift = getCurrentShift(timezone, dashboardConfig.shiftConfig);
31075
31447
  return currentShift.shiftId === 0 ? "Day" : "Night";
31076
31448
  };
@@ -31089,10 +31461,7 @@ var DashboardHeader = memo(({ lineTitle, className = "", headerControls }) => {
31089
31461
  /* @__PURE__ */ jsx("div", { className: "h-1.5 w-1.5 sm:h-1.5 sm:w-1.5 md:h-2 md:w-2 rounded-full bg-green-500 animate-pulse ring-1 sm:ring-2 ring-green-500/30 ring-offset-1 flex-shrink-0" })
31090
31462
  ] }),
31091
31463
  /* @__PURE__ */ jsxs("div", { className: "mt-0.5 sm:mt-2 inline-flex flex-wrap items-center gap-1.5 sm:gap-3", children: [
31092
- /* @__PURE__ */ jsxs("div", { className: "text-[10px] sm:text-xs md:text-sm font-medium text-gray-500 sm:text-gray-600 whitespace-nowrap", children: [
31093
- /* @__PURE__ */ jsx(ISTTimer2, {}),
31094
- " IST"
31095
- ] }),
31464
+ /* @__PURE__ */ jsx("div", { className: "text-[10px] sm:text-xs md:text-sm font-medium text-gray-500 sm:text-gray-600 whitespace-nowrap", children: /* @__PURE__ */ jsx(Timer2, {}) }),
31096
31465
  /* @__PURE__ */ jsxs("div", { className: "inline-flex items-center gap-0.5 sm:gap-1", children: [
31097
31466
  /* @__PURE__ */ jsx("div", { className: "text-gray-500 sm:text-gray-600 scale-90 sm:scale-100", children: getShiftIcon() }),
31098
31467
  /* @__PURE__ */ jsxs("span", { className: "text-[10px] sm:text-xs md:text-sm font-medium text-gray-500 sm:text-gray-600 whitespace-nowrap", children: [
@@ -31487,7 +31856,7 @@ var Breadcrumbs = ({ items }) => {
31487
31856
  }
31488
31857
  }
31489
31858
  };
31490
- return /* @__PURE__ */ jsx("nav", { "aria-label": "Breadcrumb", className: "mb-1 flex items-center space-x-1 text-xs font-medium text-gray-500 dark:text-gray-400", children: items.map((item, index) => /* @__PURE__ */ jsxs(React20__default.Fragment, { children: [
31859
+ return /* @__PURE__ */ jsx("nav", { "aria-label": "Breadcrumb", className: "mb-1 flex items-center space-x-1 text-xs font-medium text-gray-500 dark:text-gray-400", children: items.map((item, index) => /* @__PURE__ */ jsxs(React21__default.Fragment, { children: [
31491
31860
  index > 0 && /* @__PURE__ */ jsx(ChevronRight, { className: "h-3 w-3 text-gray-400 dark:text-gray-500" }),
31492
31861
  /* @__PURE__ */ jsxs(
31493
31862
  "span",
@@ -33944,7 +34313,7 @@ var ThreadSidebar = ({
33944
34313
  ] });
33945
34314
  };
33946
34315
  var axelProfilePng = "/axel-profile.png";
33947
- var ProfilePicture = React20__default.memo(({ alt = "Axel", className = "w-8 h-8 sm:w-10 sm:h-10 md:w-12 md:h-12" }) => {
34316
+ var ProfilePicture = React21__default.memo(({ alt = "Axel", className = "w-8 h-8 sm:w-10 sm:h-10 md:w-12 md:h-12" }) => {
33948
34317
  return /* @__PURE__ */ jsx("div", { className: "flex-shrink-0", children: /* @__PURE__ */ jsx("div", { className: `${className} rounded-xl overflow-hidden shadow-sm`, children: /* @__PURE__ */ jsx(
33949
34318
  "img",
33950
34319
  {
@@ -35928,7 +36297,6 @@ function DebugAuthView() {
35928
36297
  return /* @__PURE__ */ jsx(DebugAuth, {});
35929
36298
  }
35930
36299
  var DebugAuthView_default = DebugAuthView;
35931
- var DEFAULT_TIMEZONE = "Asia/Kolkata";
35932
36300
  var DEFAULT_SHIFT_CONFIG2 = {
35933
36301
  dayShift: { id: 0, startTime: "06:00" },
35934
36302
  nightShift: { id: 1, startTime: "18:00" }
@@ -35939,10 +36307,12 @@ var FactoryView = ({
35939
36307
  lineIds,
35940
36308
  lineNames = {},
35941
36309
  factoryName = "Plant 1",
35942
- timezone = DEFAULT_TIMEZONE,
36310
+ timezone: propTimezone,
35943
36311
  shiftConfig = DEFAULT_SHIFT_CONFIG2,
35944
36312
  productIds = {}
35945
36313
  }) => {
36314
+ const contextTimezone = useAppTimezone();
36315
+ const timezone = propTimezone || contextTimezone;
35946
36316
  const effectiveLineIds = useMemo(() => {
35947
36317
  if (lineIds && lineIds.length > 0) {
35948
36318
  return lineIds;
@@ -36003,7 +36373,7 @@ var FactoryView = ({
36003
36373
  return;
36004
36374
  }
36005
36375
  const { shiftId } = getCurrentShift(timezone, shiftConfig);
36006
- const date = getOperationalDate();
36376
+ const date = getOperationalDate(timezone);
36007
36377
  const hourlyDataPromises = effectiveLineIds.map(
36008
36378
  (lineId) => supabase.from("line_hourly_metrics").select("hour, efficiency").eq("line_id", lineId).eq("shift_id", shiftId).eq("date", date).order("hour", { ascending: false }).limit(5)
36009
36379
  );
@@ -36485,6 +36855,7 @@ function HomeView({
36485
36855
  const [displayNamesInitialized, setDisplayNamesInitialized] = useState(false);
36486
36856
  const [hasInitialDataLoaded, setHasInitialDataLoaded] = useState(false);
36487
36857
  const dashboardConfig = useDashboardConfig();
36858
+ const timezone = useAppTimezone();
36488
36859
  useEffect(() => {
36489
36860
  const initDisplayNames = async () => {
36490
36861
  try {
@@ -36549,7 +36920,7 @@ function HomeView({
36549
36920
  useEffect(() => {
36550
36921
  if (!dashboardConfig?.s3Config) return;
36551
36922
  if (!workspaceMetrics || workspaceMetrics.length === 0) return;
36552
- getOperationalDate(dashboardConfig.dateTimeConfig?.defaultTimezone);
36923
+ getOperationalDate(timezone || dashboardConfig.dateTimeConfig?.defaultTimezone || "UTC");
36553
36924
  console.log(`[HomeView] Starting optimized prefetch for ${workspaceMetrics.length} workspaces`);
36554
36925
  workspaceMetrics.map((ws) => ws.workspace_uuid).filter(Boolean);
36555
36926
  }, [dashboardConfig, workspaceMetrics]);
@@ -36653,7 +37024,7 @@ function HomeView({
36653
37024
  animate: { opacity: 1, scale: 1 },
36654
37025
  transition: { duration: 0.3 },
36655
37026
  className: "h-full",
36656
- children: React20__default.createElement(WorkspaceGrid, {
37027
+ children: React21__default.createElement(WorkspaceGrid, {
36657
37028
  workspaces: memoizedWorkspaceMetrics,
36658
37029
  lineNames,
36659
37030
  factoryView: factoryViewId,
@@ -36679,7 +37050,7 @@ function HomeView({
36679
37050
  animate: { opacity: 1, scale: 1 },
36680
37051
  transition: { duration: 0.3 },
36681
37052
  className: "h-full",
36682
- children: React20__default.createElement(WorkspaceGrid, {
37053
+ children: React21__default.createElement(WorkspaceGrid, {
36683
37054
  workspaces: [],
36684
37055
  // Show empty grid while loading
36685
37056
  lineNames,
@@ -36706,7 +37077,7 @@ function HomeView({
36706
37077
  }
36707
37078
  );
36708
37079
  }
36709
- var AuthenticatedHomeView = withAuth(React20__default.memo(HomeView));
37080
+ var AuthenticatedHomeView = withAuth(React21__default.memo(HomeView));
36710
37081
  var HomeView_default = HomeView;
36711
37082
  function withWorkspaceDisplayNames(Component3, options = {}) {
36712
37083
  const {
@@ -37089,6 +37460,7 @@ var KPIDetailView = ({
37089
37460
  backLinkUrl,
37090
37461
  onBackClick
37091
37462
  }) => {
37463
+ const timezone = useAppTimezone();
37092
37464
  const [activeTab, setActiveTab] = useState("overview");
37093
37465
  const [currentMonth, setCurrentMonth] = useState(() => {
37094
37466
  if (urlMonth && typeof urlMonth === "string") {
@@ -37125,7 +37497,7 @@ var KPIDetailView = ({
37125
37497
  }, [urlShift]);
37126
37498
  const supabase = useSupabase();
37127
37499
  const dashboardConfig = useDashboardConfig();
37128
- const configuredTimezone = dashboardConfig.dateTimeConfig?.defaultTimezone || "Asia/Kolkata";
37500
+ const configuredTimezone = timezone || dashboardConfig.dateTimeConfig?.defaultTimezone || "UTC";
37129
37501
  useMemo(() => getCurrentTimeInZone(configuredTimezone), [configuredTimezone]);
37130
37502
  const supervisorEnabled = dashboardConfig?.supervisorConfig?.enabled || false;
37131
37503
  useEffect(() => {
@@ -37151,18 +37523,22 @@ var KPIDetailView = ({
37151
37523
  }
37152
37524
  }, [getShiftName]);
37153
37525
  const getDaysDifference2 = useCallback((date) => {
37154
- const today = /* @__PURE__ */ new Date();
37155
37526
  const compareDate = new Date(date);
37156
- const todayInZone = new Date(today.toLocaleString("en-US", { timeZone: configuredTimezone }));
37527
+ const shiftStartTime = dashboardConfig.shiftConfig?.dayShift?.startTime || "06:00";
37528
+ const operationalTodayString = getOperationalDate(configuredTimezone, /* @__PURE__ */ new Date(), shiftStartTime);
37529
+ const operationalTodayDate = new Date(operationalTodayString);
37157
37530
  const compareDateInZone = new Date(compareDate.toLocaleString("en-US", { timeZone: configuredTimezone }));
37158
- todayInZone.setHours(0, 0, 0, 0);
37531
+ operationalTodayDate.setHours(0, 0, 0, 0);
37159
37532
  compareDateInZone.setHours(0, 0, 0, 0);
37160
- const diffTime = todayInZone.getTime() - compareDateInZone.getTime();
37161
- const diffDays = Math.ceil(diffTime / (1e3 * 60 * 60 * 24));
37533
+ const diffTime = compareDateInZone.getTime() - operationalTodayDate.getTime();
37534
+ const diffDays = Math.round(diffTime / (1e3 * 60 * 60 * 24));
37162
37535
  if (diffDays === 0) return "Today";
37163
- if (diffDays === 1) return "Yesterday";
37164
- return `${diffDays} days ago`;
37165
- }, [configuredTimezone]);
37536
+ if (diffDays === -1) return "Yesterday";
37537
+ if (diffDays === 1) return "Tomorrow";
37538
+ if (diffDays < -1) return `${Math.abs(diffDays)} days ago`;
37539
+ if (diffDays > 1) return `${diffDays} days ahead`;
37540
+ return "Today";
37541
+ }, [configuredTimezone, dashboardConfig.shiftConfig]);
37166
37542
  const {
37167
37543
  metrics: metrics2,
37168
37544
  lineDetails,
@@ -37277,7 +37653,7 @@ var KPIDetailView = ({
37277
37653
  factory_id: lineDetails.factory_id,
37278
37654
  factory_name: lineDetails.factory.factory_name,
37279
37655
  shift_id: metrics2.shift_id ?? 0,
37280
- date: metrics2.date || getOperationalDate(),
37656
+ date: metrics2.date || getOperationalDate(timezone || "UTC"),
37281
37657
  metrics: {
37282
37658
  avg_efficiency: metrics2.avg_efficiency ?? 0,
37283
37659
  avg_cycle_time: metrics2.avg_cycle_time ?? 0,
@@ -37824,7 +38200,7 @@ var KPIDetailViewWithDisplayNames = withSelectedLineDisplayNames(KPIDetailView);
37824
38200
  var KPIDetailView_default = KPIDetailViewWithDisplayNames;
37825
38201
  var LineCard = ({ line, onClick, supervisorEnabled = false }) => {
37826
38202
  const { kpis, isLoading, error } = useLineKPIs({ lineId: line.id });
37827
- const isOnTrack = React20__default.useMemo(() => {
38203
+ const isOnTrack = React21__default.useMemo(() => {
37828
38204
  if (!kpis) return null;
37829
38205
  return kpis.efficiency.value > 90;
37830
38206
  }, [kpis]);
@@ -37932,7 +38308,8 @@ var KPIsOverviewView = ({
37932
38308
  const dateTimeConfig = useDateTimeConfig();
37933
38309
  const shiftConfig = useShiftConfig();
37934
38310
  const supervisorEnabled = dashboardConfig?.supervisorConfig?.enabled || false;
37935
- const configuredTimezone = dateTimeConfig.defaultTimezone || "Asia/Kolkata";
38311
+ const dbTimezone = useAppTimezone();
38312
+ const configuredTimezone = dbTimezone || dateTimeConfig.defaultTimezone || "UTC";
37936
38313
  useEffect(() => {
37937
38314
  const fetchLines = async () => {
37938
38315
  try {
@@ -39627,7 +40004,7 @@ var ShiftsView = ({
39627
40004
  ] })
39628
40005
  ] });
39629
40006
  };
39630
- var AuthenticatedShiftsView = withAuth(React20__default.memo(ShiftsView));
40007
+ var AuthenticatedShiftsView = withAuth(React21__default.memo(ShiftsView));
39631
40008
  var ShiftsView_default = ShiftsView;
39632
40009
 
39633
40010
  // src/lib/constants/actions.ts
@@ -40843,6 +41220,7 @@ var TargetsView = ({
40843
41220
  userId,
40844
41221
  onSaveChanges
40845
41222
  }) => {
41223
+ const timezone = useAppTimezone();
40846
41224
  const initialLineWorkspaces = useMemo(() => {
40847
41225
  return lineIds.reduce((acc, lineId) => ({
40848
41226
  ...acc,
@@ -41061,7 +41439,7 @@ var TargetsView = ({
41061
41439
  updatedLineWorkspaces[result.lineId].factoryId = result.factoryId;
41062
41440
  }
41063
41441
  });
41064
- const currentDate = getOperationalDate();
41442
+ const currentDate = getOperationalDate(timezone);
41065
41443
  for (const lineId of lineIds) {
41066
41444
  if (!updatedLineWorkspaces[lineId]?.factoryId) {
41067
41445
  console.warn(`Skipping workspace fetch for line ${lineId} - no factory ID`);
@@ -41142,7 +41520,7 @@ var TargetsView = ({
41142
41520
  }, [lineIds, companyId, loadOperatingHours]);
41143
41521
  const fetchAllShiftsData = useCallback(async (currentWorkspaces) => {
41144
41522
  if (!supabase) return;
41145
- const currentDate = getOperationalDate();
41523
+ const currentDate = getOperationalDate(timezone);
41146
41524
  const newAllShiftsData = {
41147
41525
  0: JSON.parse(JSON.stringify(currentWorkspaces)),
41148
41526
  // Deep clone for day shift
@@ -41381,7 +41759,7 @@ var TargetsView = ({
41381
41759
  return;
41382
41760
  }
41383
41761
  const currentFactoryId = lineDataToSave.factoryId;
41384
- const currentDate = getOperationalDate();
41762
+ const currentDate = getOperationalDate(timezone);
41385
41763
  console.log(`[handleSaveLine] currentDate: ${currentDate}, selectedShift: ${selectedShift}`);
41386
41764
  const workspaceThresholdUpdates = lineDataToSave.workspaces.map((ws) => ({
41387
41765
  line_id: lineId,
@@ -41543,37 +41921,43 @@ var TargetsView = ({
41543
41921
  };
41544
41922
  var TargetsViewWithDisplayNames = withAllWorkspaceDisplayNames(TargetsView);
41545
41923
  var TargetsView_default = TargetsViewWithDisplayNames;
41546
- var AuthenticatedTargetsView = withAuth(React20__default.memo(TargetsViewWithDisplayNames));
41924
+ var AuthenticatedTargetsView = withAuth(React21__default.memo(TargetsViewWithDisplayNames));
41547
41925
 
41548
41926
  // src/views/workspace-detail-view.utils.ts
41549
- var formatISTDate2 = (date = /* @__PURE__ */ new Date(), options) => {
41927
+ var formatDateInTimezone = (date = /* @__PURE__ */ new Date(), timezone, options) => {
41550
41928
  const defaultOptions = {
41551
41929
  day: "numeric",
41552
41930
  month: "long",
41553
41931
  year: "numeric",
41554
- timeZone: "Asia/Kolkata"
41932
+ timeZone: timezone
41555
41933
  };
41556
- const formatter = new Intl.DateTimeFormat("en-IN", {
41934
+ const formatter = new Intl.DateTimeFormat("en-US", {
41557
41935
  ...defaultOptions,
41558
41936
  ...options
41559
41937
  });
41560
41938
  return formatter.format(date);
41561
41939
  };
41940
+ var formatISTDate2 = (date = /* @__PURE__ */ new Date(), options) => {
41941
+ return formatDateInTimezone(date, "Asia/Kolkata", options);
41942
+ };
41562
41943
  var formatWorkspaceName3 = (name, lineId) => {
41563
41944
  return getWorkspaceDisplayName(name, lineId);
41564
41945
  };
41565
- var getDaysDifference = (date) => {
41566
- const today = /* @__PURE__ */ new Date();
41946
+ var getDaysDifference = (date, timezone = "UTC", shiftStartTime = "06:00") => {
41567
41947
  const compareDate = new Date(date);
41568
- const todayIST = new Date(today.toLocaleString("en-US", { timeZone: "Asia/Kolkata" }));
41569
- const compareDateIST = new Date(compareDate.toLocaleString("en-US", { timeZone: "Asia/Kolkata" }));
41570
- todayIST.setHours(0, 0, 0, 0);
41571
- compareDateIST.setHours(0, 0, 0, 0);
41572
- const diffTime = todayIST.getTime() - compareDateIST.getTime();
41573
- const diffDays = Math.ceil(diffTime / (1e3 * 60 * 60 * 24));
41948
+ const operationalTodayString = getOperationalDate(timezone, /* @__PURE__ */ new Date(), shiftStartTime);
41949
+ const operationalTodayDate = new Date(operationalTodayString);
41950
+ const compareDateInTz = new Date(compareDate.toLocaleString("en-US", { timeZone: timezone }));
41951
+ operationalTodayDate.setHours(0, 0, 0, 0);
41952
+ compareDateInTz.setHours(0, 0, 0, 0);
41953
+ const diffTime = compareDateInTz.getTime() - operationalTodayDate.getTime();
41954
+ const diffDays = Math.round(diffTime / (1e3 * 60 * 60 * 24));
41574
41955
  if (diffDays === 0) return "Today";
41575
- if (diffDays === 1) return "Yesterday";
41576
- return `${diffDays} days ago`;
41956
+ if (diffDays === -1) return "Yesterday";
41957
+ if (diffDays === 1) return "Tomorrow";
41958
+ if (diffDays < -1) return `${Math.abs(diffDays)} days ago`;
41959
+ if (diffDays > 1) return `${diffDays} days ahead`;
41960
+ return "Today";
41577
41961
  };
41578
41962
  var getInitialTab = (sourceType, defaultTab, fromMonthly, urlDate) => {
41579
41963
  if (sourceType === "lineMonthlyHistory") {
@@ -41621,7 +42005,8 @@ var WorkspaceDetailView = ({
41621
42005
  const [previousView, setPreviousView] = useState("dashboard");
41622
42006
  const [monthlyData, setMonthlyData] = useState([]);
41623
42007
  const [monthlyDataLoading, setMonthlyDataLoading] = useState(false);
41624
- const today = new Date((/* @__PURE__ */ new Date()).toLocaleString("en-US", { timeZone: "Asia/Kolkata" }));
42008
+ const timezone = useAppTimezone();
42009
+ const today = new Date((/* @__PURE__ */ new Date()).toLocaleString("en-US", { timeZone: timezone }));
41625
42010
  const [selectedMonth, setSelectedMonth] = useState(today.getMonth());
41626
42011
  const [selectedYear, setSelectedYear] = useState(today.getFullYear());
41627
42012
  const [selectedShift, setSelectedShift] = useState("day");
@@ -41678,7 +42063,7 @@ var WorkspaceDetailView = ({
41678
42063
  error: liveError
41679
42064
  } = useWorkspaceDetailedMetrics(
41680
42065
  workspaceId || "",
41681
- getOperationalDate(),
42066
+ getOperationalDate(timezone),
41682
42067
  void 0
41683
42068
  );
41684
42069
  const workspace = isHistoricView ? historicMetrics : liveMetrics;
@@ -41777,7 +42162,7 @@ var WorkspaceDetailView = ({
41777
42162
  }, [isClipsEnabled, activeTab]);
41778
42163
  useEffect(() => {
41779
42164
  if (liveMetrics && !date && !shift) {
41780
- const currentDate = getOperationalDate();
42165
+ const currentDate = getOperationalDate(timezone);
41781
42166
  if (liveMetrics.date !== currentDate) {
41782
42167
  setUsingFallbackData(true);
41783
42168
  if (activeTab !== "monthly_history") {
@@ -41795,10 +42180,10 @@ var WorkspaceDetailView = ({
41795
42180
  return date;
41796
42181
  } catch (e) {
41797
42182
  console.error("Error parsing historic date:", e);
41798
- return getOperationalDate();
42183
+ return getOperationalDate(timezone);
41799
42184
  }
41800
42185
  }
41801
- return getOperationalDate();
42186
+ return getOperationalDate(timezone);
41802
42187
  }, [isHistoricView, date]);
41803
42188
  const handleMonthlyDataLoaded = useCallback((data) => {
41804
42189
  console.log("[handleMonthlyDataLoaded] Received data:", {
@@ -42045,7 +42430,7 @@ var WorkspaceDetailView = ({
42045
42430
  /* @__PURE__ */ jsx("div", { className: "text-gray-700 scale-90", children: getShiftIcon(workspace.shift_type) }),
42046
42431
  /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-gray-700", children: workspace.shift_type })
42047
42432
  ] }),
42048
- !date && !shift && !usingFallbackData ? /* @__PURE__ */ jsx("div", { className: "inline-flex items-center px-2.5 py-1 bg-green-100 rounded-full", children: /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-green-700", children: /* @__PURE__ */ jsx(LiveTimer, {}) }) }) : date ? /* @__PURE__ */ jsx("div", { className: "inline-flex items-center px-2.5 py-1 bg-blue-100 rounded-full", children: /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-blue-700", children: getDaysDifference(workspace.date) }) }) : usingFallbackData ? /* @__PURE__ */ jsx("div", { className: "inline-flex items-center px-2.5 py-1 bg-amber-100 rounded-full", children: /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-amber-700", children: getDaysDifference(workspace.date) }) }) : null
42433
+ !date && !shift && !usingFallbackData ? /* @__PURE__ */ jsx("div", { className: "inline-flex items-center px-2.5 py-1 bg-green-100 rounded-full", children: /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-green-700", children: /* @__PURE__ */ jsx(LiveTimer, {}) }) }) : date ? /* @__PURE__ */ jsx("div", { className: "inline-flex items-center px-2.5 py-1 bg-blue-100 rounded-full", children: /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-blue-700", children: getDaysDifference(workspace.date, timezone, dashboardConfig?.shiftConfig?.dayShift?.startTime || "06:00") }) }) : usingFallbackData ? /* @__PURE__ */ jsx("div", { className: "inline-flex items-center px-2.5 py-1 bg-amber-100 rounded-full", children: /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-amber-700", children: getDaysDifference(workspace.date, timezone, dashboardConfig?.shiftConfig?.dayShift?.startTime || "06:00") }) }) : null
42049
42434
  ] }),
42050
42435
  /* @__PURE__ */ jsx("div", { className: "hidden sm:block mt-3 bg-blue-50 px-3 py-2 rounded-lg", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-center gap-3 md:gap-4", children: [
42051
42436
  !date && !shift && !usingFallbackData && /* @__PURE__ */ jsxs(Fragment, { children: [
@@ -42055,13 +42440,13 @@ var WorkspaceDetailView = ({
42055
42440
  /* @__PURE__ */ jsx("span", { className: "text-sm md:text-base font-medium text-blue-600", children: formatISTDate2(new Date(workspace.date)) }),
42056
42441
  /* @__PURE__ */ jsx("div", { className: "w-px h-4 bg-blue-300" }),
42057
42442
  date && /* @__PURE__ */ jsxs(Fragment, { children: [
42058
- /* @__PURE__ */ jsx("span", { className: "px-2 py-1 text-xs font-medium bg-blue-200 text-blue-800 rounded-md", children: getDaysDifference(workspace.date) }),
42443
+ /* @__PURE__ */ jsx("span", { className: "px-2 py-1 text-xs font-medium bg-blue-200 text-blue-800 rounded-md", children: getDaysDifference(workspace.date, timezone, dashboardConfig?.shiftConfig?.dayShift?.startTime || "06:00") }),
42059
42444
  /* @__PURE__ */ jsx("div", { className: "w-px h-4 bg-blue-300" })
42060
42445
  ] }),
42061
42446
  !date && !shift && usingFallbackData && /* @__PURE__ */ jsxs(Fragment, { children: [
42062
42447
  /* @__PURE__ */ jsxs("span", { className: "px-2 py-1 text-xs font-medium bg-amber-100 text-amber-700 rounded-md", children: [
42063
42448
  "Latest available data (",
42064
- getDaysDifference(workspace.date),
42449
+ getDaysDifference(workspace.date, timezone, dashboardConfig?.shiftConfig?.dayShift?.startTime || "06:00"),
42065
42450
  ")"
42066
42451
  ] }),
42067
42452
  /* @__PURE__ */ jsx("div", { className: "w-px h-4 bg-blue-300" })
@@ -42624,7 +43009,8 @@ var WorkspaceHealthView = ({
42624
43009
  }) => {
42625
43010
  const router = useRouter();
42626
43011
  const [groupBy, setGroupBy] = useState("line");
42627
- const operationalDate = getOperationalDate();
43012
+ const timezone = useAppTimezone();
43013
+ const operationalDate = getOperationalDate(timezone || "UTC");
42628
43014
  const currentHour = (/* @__PURE__ */ new Date()).getHours();
42629
43015
  const isNightShift = currentHour >= 18 || currentHour < 6;
42630
43016
  const shiftType = isNightShift ? "Night" : "Day";
@@ -43101,7 +43487,7 @@ var S3Service = class {
43101
43487
  /**
43102
43488
  * List S3 clips for a specific workspace and date
43103
43489
  */
43104
- async listS3Clips(workspaceId, date = getOperationalDate()) {
43490
+ async listS3Clips(workspaceId, date) {
43105
43491
  const prefix = `sop_violations/${workspaceId}/${date}/`;
43106
43492
  if (this.isSimulated()) {
43107
43493
  console.log("Running in simulated mode - generating mock data for:", prefix);
@@ -43260,7 +43646,7 @@ var S3Service = class {
43260
43646
  /**
43261
43647
  * Get all clips for a workspace on a specific date
43262
43648
  */
43263
- async getWorkspaceClips(workspaceId, date = getOperationalDate()) {
43649
+ async getWorkspaceClips(workspaceId, date) {
43264
43650
  try {
43265
43651
  if (!/^\d{4}-\d{2}-\d{2}$/.test(date)) {
43266
43652
  throw new Error("Invalid date format. Use YYYY-MM-DD.");
@@ -43688,4 +44074,4 @@ function shuffleArray(array) {
43688
44074
  return shuffled;
43689
44075
  }
43690
44076
 
43691
- export { ACTION_NAMES, AIAgentView_default as AIAgentView, AdvancedFilterDialog, AdvancedFilterPanel, AudioService, AuthCallback, AuthCallbackView_default as AuthCallbackView, AuthProvider, AuthenticatedFactoryView, AuthenticatedHelpView, AuthenticatedHomeView, AuthenticatedShiftsView, AuthenticatedTargetsView, AuthenticatedWorkspaceHealthView, BackButton, BackButtonMinimal, BarChart, BaseHistoryCalendar, 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_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, 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, 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, MainLayout, MetricCard_default as MetricCard, MinimalOnboardingPopup, NewClipsNotification, NoWorkspaceData, OnboardingDemo, OnboardingTour, OptifyeAgentClient, OptifyeLogoLoader_default as OptifyeLogoLoader, OutputProgressChart, PageHeader, PieChart4 as PieChart, 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, SimpleOnboardingPopup, SingleVideoStream_default as SingleVideoStream, Skeleton, SubscriptionManager, SubscriptionManagerProvider, SupabaseProvider, SupervisorDropdown_default as SupervisorDropdown, SupervisorManagementView_default as SupervisorManagementView, SupervisorService, TargetWorkspaceGrid, TargetsView_default as TargetsView, ThreadSidebar, TicketHistory_default as TicketHistory, TicketHistoryService, TimeDisplay_default as TimeDisplay, TimePickerDropdown, 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, createLinesService, createStreamProxyHandler, createSupabaseClient, createSupervisorService, createThrottledReload, createUserService, dashboardService, deleteThread, forceRefreshWorkspaceDisplayNames, formatDateInZone, formatDateTimeInZone, formatISTDate, formatIdleTime, formatTimeInZone, fromUrlFriendlyName, getAllLineDisplayNames, getAllThreadMessages, getAllWorkspaceDisplayNamesAsync, getAnonClient, getCameraNumber, getCompanyMetricsTableName, getConfigurableShortWorkspaceDisplayName, getConfigurableWorkspaceDisplayName, getConfiguredLineIds, getCoreSessionRecordingProperties, getCoreSessionReplayUrl, getCurrentShift, getCurrentTimeInZone, getDashboardHeaderTimeInZone, getDaysDifferenceInZone, getDefaultCameraStreamUrl, getDefaultLineId, getDefaultTabForWorkspace, getLineDisplayName, getManufacturingInsights, getMetricsTablePrefix, getOperationalDate, getS3SignedUrl, getS3VideoSrc, getShortWorkspaceDisplayName, getShortWorkspaceDisplayNameAsync, getStoredWorkspaceMappings, getSubscriptionManager, getThreadMessages, getUserThreads, getUserThreadsPaginated, getWorkspaceDisplayName, getWorkspaceDisplayNameAsync, getWorkspaceDisplayNamesMap, getWorkspaceFromUrl, getWorkspaceNavigationParams, identifyCoreUser, initializeCoreMixpanel, isLegacyConfiguration, isPrefetchError, 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, useAllWorkspaceMetrics, useAnalyticsConfig, useAudioService, useAuth, useAuthConfig, useCanSaveTargets, useClipFilter, useClipTypes, useClipTypesWithCounts, useComponentOverride, useCustomConfig, useDashboardConfig, useDashboardMetrics, useDatabaseConfig, useDateFormatter, useDateTimeConfig, useEndpointsConfig, useEntityConfig, useFactoryOverviewMetrics, useFeatureFlags, useFormatNumber, useHistoricWorkspaceMetrics, useHlsStream, useHlsStreamWithCropping, useHookOverride, useHourEndTimer, useHourlyTargetAchievements, useHourlyTargetMisses, useLeaderboardMetrics, useLineDetailedMetrics, useLineKPIs, useLineMetrics, useLineWorkspaceMetrics, useMessages, useMetrics, useNavigation, useOverrides, usePageOverride, usePrefetchClipCounts, useRealtimeLineMetrics, useRegistry, useSKUs, useShiftConfig, useShifts, useSubscriptionManager, useSubscriptionManagerSafe, useSupabase, useSupabaseClient, useTargets, useTheme, useThemeConfig, useThreads, useTicketHistory, useVideoConfig, useWorkspaceConfig, useWorkspaceDetailedMetrics, useWorkspaceDisplayName, useWorkspaceDisplayNames, useWorkspaceDisplayNamesMap, useWorkspaceHealth, useWorkspaceHealthById, useWorkspaceMetrics, useWorkspaceNavigation, useWorkspaceOperators, userService, videoPrefetchManager, videoPreloader, whatsappService, withAccessControl, withAuth, withRegistry, workspaceHealthService, workspaceService };
44077
+ export { ACTION_NAMES, AIAgentView_default as AIAgentView, AdvancedFilterDialog, AdvancedFilterPanel, AudioService, AuthCallback, AuthCallbackView_default as AuthCallbackView, AuthProvider, AuthenticatedFactoryView, AuthenticatedHelpView, AuthenticatedHomeView, AuthenticatedShiftsView, AuthenticatedTargetsView, AuthenticatedWorkspaceHealthView, BackButton, BackButtonMinimal, BarChart, BaseHistoryCalendar, 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_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, 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, 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, MainLayout, MetricCard_default as MetricCard, MinimalOnboardingPopup, NewClipsNotification, NoWorkspaceData, OnboardingDemo, OnboardingTour, OptifyeAgentClient, OptifyeLogoLoader_default as OptifyeLogoLoader, OutputProgressChart, PageHeader, PieChart4 as PieChart, 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, SimpleOnboardingPopup, SingleVideoStream_default as SingleVideoStream, Skeleton, SubscriptionManager, SubscriptionManagerProvider, SupabaseProvider, SupervisorDropdown_default as SupervisorDropdown, SupervisorManagementView_default as SupervisorManagementView, SupervisorService, TargetWorkspaceGrid, TargetsView_default as TargetsView, ThreadSidebar, TicketHistory_default as TicketHistory, TicketHistoryService, TimeDisplay_default as TimeDisplay, TimePickerDropdown, Timer_default as Timer, TimezoneProvider, TimezoneService, 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, createLinesService, createStreamProxyHandler, createSupabaseClient, createSupervisorService, createThrottledReload, createUserService, dashboardService, deleteThread, forceRefreshWorkspaceDisplayNames, formatDateInZone, formatDateTimeInZone, formatISTDate, formatIdleTime, formatTimeInZone, fromUrlFriendlyName, getAllLineDisplayNames, getAllThreadMessages, getAllWorkspaceDisplayNamesAsync, getAnonClient, getCameraNumber, getCompanyMetricsTableName, getConfigurableShortWorkspaceDisplayName, getConfigurableWorkspaceDisplayName, getConfiguredLineIds, getCoreSessionRecordingProperties, getCoreSessionReplayUrl, getCurrentShift, getCurrentTimeInZone, getDashboardHeaderTimeInZone, getDaysDifferenceInZone, getDefaultCameraStreamUrl, getDefaultLineId, getDefaultTabForWorkspace, getLineDisplayName, getManufacturingInsights, getMetricsTablePrefix, getOperationalDate, getS3SignedUrl, getS3VideoSrc, getShortWorkspaceDisplayName, getShortWorkspaceDisplayNameAsync, getStoredWorkspaceMappings, getSubscriptionManager, getThreadMessages, getUserThreads, getUserThreadsPaginated, getWorkspaceDisplayName, getWorkspaceDisplayNameAsync, getWorkspaceDisplayNamesMap, getWorkspaceFromUrl, getWorkspaceNavigationParams, identifyCoreUser, initializeCoreMixpanel, isLegacyConfiguration, isPrefetchError, 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, useAllWorkspaceMetrics, useAnalyticsConfig, useAppTimezone, useAudioService, useAuth, useAuthConfig, useCanSaveTargets, useClipFilter, useClipTypes, useClipTypesWithCounts, useComponentOverride, useCustomConfig, useDashboardConfig, useDashboardMetrics, useDatabaseConfig, useDateFormatter, useDateTimeConfig, useEndpointsConfig, useEntityConfig, useFactoryOverviewMetrics, useFeatureFlags, useFormatNumber, useHistoricWorkspaceMetrics, useHlsStream, useHlsStreamWithCropping, useHookOverride, useHourEndTimer, useHourlyTargetAchievements, useHourlyTargetMisses, useLeaderboardMetrics, useLineDetailedMetrics, useLineKPIs, useLineMetrics, useLineWorkspaceMetrics, useMessages, useMetrics, useNavigation, useOverrides, usePageOverride, usePrefetchClipCounts, useRealtimeLineMetrics, useRegistry, useSKUs, useShiftConfig, useShifts, useSubscriptionManager, useSubscriptionManagerSafe, useSupabase, useSupabaseClient, useTargets, useTheme, useThemeConfig, useThreads, useTicketHistory, useTimezoneContext, useVideoConfig, useWorkspaceConfig, useWorkspaceDetailedMetrics, useWorkspaceDisplayName, useWorkspaceDisplayNames, useWorkspaceDisplayNamesMap, useWorkspaceHealth, useWorkspaceHealthById, useWorkspaceMetrics, useWorkspaceNavigation, useWorkspaceOperators, userService, videoPrefetchManager, videoPreloader, whatsappService, withAccessControl, withAuth, withRegistry, withTimezone, workspaceHealthService, workspaceService };