@optifye/dashboard-core 6.0.3 → 6.0.5

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,5 +1,5 @@
1
- import * as React14 from 'react';
2
- import React14__default, { createContext, useRef, useCallback, useState, useMemo, useEffect, memo, useContext, useLayoutEffect, useId, Children, isValidElement, useInsertionEffect, forwardRef, Fragment as Fragment$1, createElement, Component } from 'react';
1
+ import * as React19 from 'react';
2
+ import React19__default, { createContext, useRef, useCallback, useState, useMemo, useEffect, memo, useContext, useLayoutEffect, useId, Children, isValidElement, useInsertionEffect, forwardRef, 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';
@@ -10,15 +10,15 @@ import Hls2 from 'hls.js';
10
10
  import useSWR from 'swr';
11
11
  import { noop, warning, invariant, progress, secondsToMilliseconds, millisecondsToSeconds, memo as memo$1 } from 'motion-utils';
12
12
  import { getValueTransition, hover, press, isPrimaryPointer, GroupPlaybackControls, setDragLock, supportsLinearEasing, attachTimeline, isGenerator, calcGeneratorDuration, isWaapiSupportedEasing, mapEasingToNativeEasing, maxGeneratorDuration, generateLinearEasing, isBezierDefinition } from 'motion-dom';
13
- import { Bar, LabelList, ResponsiveContainer, BarChart as BarChart$1, CartesianGrid, XAxis, YAxis, Tooltip, ReferenceLine, Cell, PieChart, Pie, Legend, LineChart as LineChart$1, Line, ComposedChart, Area, ScatterChart, Scatter } from 'recharts';
13
+ import { BarChart as BarChart$1, CartesianGrid, XAxis, YAxis, Tooltip, Legend, Bar, LabelList, ResponsiveContainer, LineChart as LineChart$1, Line, PieChart, Pie, Cell, ReferenceLine, ComposedChart, Area, ScatterChart, Scatter } from 'recharts';
14
14
  import { Slot } from '@radix-ui/react-slot';
15
- import { Camera, ChevronDown, ChevronUp, Check, ShieldCheck, Star, Award, X, Coffee, Plus, Clock, Minus, ArrowDown, ArrowUp, Search, CheckCircle, AlertTriangle, Info, Share2, Download, User, XCircle, ChevronLeft, ChevronRight, AlertCircle, Sun, Moon, MessageSquare, Trash2, ArrowLeft, RefreshCw, Menu, Send, Copy, Edit2, UserCheck, Save, LogOut, Calendar, Settings, LifeBuoy, Loader2, ArrowLeftIcon as ArrowLeftIcon$1, Settings2, CheckCircle2, EyeOff, Eye, Zap, UserCircle } from 'lucide-react';
15
+ import { Camera, ChevronDown, ChevronUp, Check, ShieldCheck, Star, Award, X, Coffee, Plus, Clock, Minus, ArrowDown, ArrowUp, Search, CheckCircle, AlertTriangle, Info, Share2, Download, User, XCircle, ChevronLeft, ChevronRight, AlertCircle, Sun, Moon, MessageSquare, Trash2, ArrowLeft, RefreshCw, Menu, Send, Copy, Edit2, UserCheck, Save, LogOut, Calendar, Package, Settings, LifeBuoy, Loader2, ArrowLeftIcon as ArrowLeftIcon$1, Settings2, CheckCircle2, EyeOff, Eye, Zap, UserCircle } from 'lucide-react';
16
16
  import { DayPicker, useNavigation as useNavigation$1 } from 'react-day-picker';
17
17
  import html2canvas from 'html2canvas';
18
18
  import jsPDF, { jsPDF as jsPDF$1 } from 'jspdf';
19
19
  import * as SelectPrimitive from '@radix-ui/react-select';
20
20
  import { S3Client, ListObjectsV2Command, GetObjectCommand } from '@aws-sdk/client-s3';
21
- import { HomeIcon, TrophyIcon, ChartBarIcon, AdjustmentsHorizontalIcon, ClockIcon, SparklesIcon, QuestionMarkCircleIcon, UserCircleIcon, ArrowRightIcon, ArrowLeftIcon, ChatBubbleLeftRightIcon, CheckCircleIcon, ExclamationCircleIcon, DocumentTextIcon, EnvelopeIcon, InformationCircleIcon, ChevronLeftIcon, ChevronRightIcon } from '@heroicons/react/24/outline';
21
+ import { HomeIcon, TrophyIcon, ChartBarIcon, AdjustmentsHorizontalIcon, ClockIcon, CubeIcon, SparklesIcon, QuestionMarkCircleIcon, UserCircleIcon, ArrowRightIcon, ArrowLeftIcon, ChatBubbleLeftRightIcon, CheckCircleIcon, ExclamationCircleIcon, DocumentTextIcon, EnvelopeIcon, InformationCircleIcon, ChevronLeftIcon, ChevronRightIcon } from '@heroicons/react/24/outline';
22
22
  import { Readable } from 'stream';
23
23
  import { toast } from 'sonner';
24
24
  import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
@@ -205,14 +205,14 @@ var _getDashboardConfigInstance = () => {
205
205
  }
206
206
  return dashboardConfigInstance;
207
207
  };
208
- var DashboardConfigContext = React14.createContext(void 0);
208
+ var DashboardConfigContext = React19.createContext(void 0);
209
209
  var DashboardProvider = ({ config: userProvidedConfig, children }) => {
210
- const fullConfig = React14.useMemo(() => mergeWithDefaultConfig(userProvidedConfig), [userProvidedConfig]);
210
+ const fullConfig = React19.useMemo(() => mergeWithDefaultConfig(userProvidedConfig), [userProvidedConfig]);
211
211
  _setDashboardConfigInstance(fullConfig);
212
- React14.useEffect(() => {
212
+ React19.useEffect(() => {
213
213
  _setDashboardConfigInstance(fullConfig);
214
214
  }, [fullConfig]);
215
- React14.useEffect(() => {
215
+ React19.useEffect(() => {
216
216
  if (!fullConfig.theme) return;
217
217
  const styleId = "dashboard-core-theme-vars";
218
218
  let styleEl = document.getElementById(styleId);
@@ -238,7 +238,7 @@ var DashboardProvider = ({ config: userProvidedConfig, children }) => {
238
238
  return /* @__PURE__ */ jsx(DashboardConfigContext.Provider, { value: fullConfig, children });
239
239
  };
240
240
  var useDashboardConfig = () => {
241
- const ctx = React14.useContext(DashboardConfigContext);
241
+ const ctx = React19.useContext(DashboardConfigContext);
242
242
  if (!ctx) throw new Error("useDashboardConfig must be used within a DashboardProvider");
243
243
  return ctx;
244
244
  };
@@ -331,6 +331,56 @@ var actionService = {
331
331
  return data || [];
332
332
  }
333
333
  };
334
+ function createMemoizedFunction(fn, getCacheKey) {
335
+ const cache = /* @__PURE__ */ new Map();
336
+ const CACHE_DURATION3 = 5 * 60 * 1e3;
337
+ return (...args) => {
338
+ const key = getCacheKey(...args);
339
+ const cached = cache.get(key);
340
+ if (cached && Date.now() - cached.timestamp < CACHE_DURATION3) {
341
+ return cached.result;
342
+ }
343
+ const result = fn(...args);
344
+ cache.set(key, { result, timestamp: Date.now() });
345
+ if (cache.size > 100) {
346
+ const firstKey = cache.keys().next().value;
347
+ if (firstKey) cache.delete(firstKey);
348
+ }
349
+ return result;
350
+ };
351
+ }
352
+ var memoizedEfficiencyFilter = createMemoizedFunction(
353
+ (data, minEfficiency, maxEfficiency) => {
354
+ return data.filter((item) => {
355
+ const eff = item.efficiency ?? 0;
356
+ return eff >= minEfficiency && (maxEfficiency === void 0 || eff < maxEfficiency);
357
+ });
358
+ },
359
+ (data, min, max = void 0) => `${data.length}-${min}-${max}`
360
+ );
361
+ var memoizedAverageEfficiency = createMemoizedFunction(
362
+ (data, minThreshold = 10) => {
363
+ const validItems = data.filter((item) => (item.efficiency ?? 0) >= minThreshold);
364
+ if (validItems.length === 0) return 0;
365
+ const sum = validItems.reduce((acc, item) => acc + (item.efficiency ?? 0), 0);
366
+ return sum / validItems.length;
367
+ },
368
+ (data, threshold) => `${data.length}-${threshold}`
369
+ );
370
+ var memoizedOutputArrayAggregation = createMemoizedFunction(
371
+ (arrays) => {
372
+ if (arrays.length === 0) return [];
373
+ const maxLength = Math.max(...arrays.map((arr) => arr.length));
374
+ const result = new Array(maxLength).fill(0);
375
+ for (const arr of arrays) {
376
+ for (let i = 0; i < arr.length; i++) {
377
+ result[i] += arr[i];
378
+ }
379
+ }
380
+ return result;
381
+ },
382
+ (arrays) => arrays.map((arr) => arr.length).join("-")
383
+ );
334
384
  var getOperationalDate = (timezone = "Asia/Kolkata", date = /* @__PURE__ */ new Date(), shiftStartTime = "06:00") => {
335
385
  const zonedDate = toZonedTime(date, timezone);
336
386
  const hours = zonedDate.getHours();
@@ -437,6 +487,76 @@ var getMetricsTablePrefix = (companyId) => {
437
487
  return "performance_metrics";
438
488
  };
439
489
 
490
+ // src/lib/utils/lineConfig.ts
491
+ function getConfiguredLineIds(entityConfig) {
492
+ if (entityConfig.lines && Object.keys(entityConfig.lines).length > 0) {
493
+ return Object.keys(entityConfig.lines);
494
+ }
495
+ const lineIds = [];
496
+ if (entityConfig.defaultLineId) {
497
+ lineIds.push(entityConfig.defaultLineId);
498
+ }
499
+ if (entityConfig.secondaryLineId && entityConfig.secondaryLineId !== entityConfig.defaultLineId) {
500
+ lineIds.push(entityConfig.secondaryLineId);
501
+ }
502
+ return lineIds;
503
+ }
504
+ function getLineDisplayName(entityConfig, lineId) {
505
+ if (entityConfig.lines && entityConfig.lines[lineId]) {
506
+ return entityConfig.lines[lineId];
507
+ }
508
+ if (entityConfig.lineNames && entityConfig.lineNames[lineId]) {
509
+ return entityConfig.lineNames[lineId];
510
+ }
511
+ return `Line ${lineId.substring(0, 8)}`;
512
+ }
513
+ function getAllLineDisplayNames(entityConfig) {
514
+ const displayNames = {};
515
+ if (entityConfig.lineNames) {
516
+ Object.assign(displayNames, entityConfig.lineNames);
517
+ }
518
+ if (entityConfig.lines) {
519
+ Object.assign(displayNames, entityConfig.lines);
520
+ }
521
+ return displayNames;
522
+ }
523
+ function getDefaultLineId(entityConfig) {
524
+ if (entityConfig.lines && Object.keys(entityConfig.lines).length > 0) {
525
+ return Object.keys(entityConfig.lines)[0];
526
+ }
527
+ return entityConfig.defaultLineId;
528
+ }
529
+ function isLegacyConfiguration(entityConfig) {
530
+ return !entityConfig.lines || Object.keys(entityConfig.lines).length === 0;
531
+ }
532
+ function migrateLegacyConfiguration(entityConfig) {
533
+ if (!isLegacyConfiguration(entityConfig)) {
534
+ return entityConfig;
535
+ }
536
+ const lines = {};
537
+ if (entityConfig.defaultLineId) {
538
+ lines[entityConfig.defaultLineId] = getLineDisplayName(entityConfig, entityConfig.defaultLineId);
539
+ }
540
+ if (entityConfig.secondaryLineId && entityConfig.secondaryLineId !== entityConfig.defaultLineId) {
541
+ lines[entityConfig.secondaryLineId] = getLineDisplayName(entityConfig, entityConfig.secondaryLineId);
542
+ }
543
+ if (entityConfig.lineNames) {
544
+ Object.entries(entityConfig.lineNames).forEach(([id3, name]) => {
545
+ if (!lines[id3]) {
546
+ lines[id3] = name;
547
+ }
548
+ });
549
+ }
550
+ return {
551
+ ...entityConfig,
552
+ lines
553
+ };
554
+ }
555
+ function isValidFactoryViewConfiguration(entityConfig) {
556
+ const lineIds = getConfiguredLineIds(entityConfig);
557
+ return lineIds.length > 0;
558
+ }
559
+
440
560
  // src/lib/services/dashboardService.ts
441
561
  var getTable2 = (dbConfig, tableName) => {
442
562
  const defaults2 = DEFAULT_DATABASE_CONFIG.tables;
@@ -458,32 +578,42 @@ var dashboardService = {
458
578
  const companyId = entityConfig.companyId;
459
579
  const metricsTablePrefixStr = getMetricsTablePrefix();
460
580
  const metricsTable = `${metricsTablePrefixStr}_${companyId ? companyId.replace(/-/g, "_") : "unknown_company"}`;
461
- const defaultLineId = entityConfig.defaultLineId;
462
- const secondaryLineId = entityConfig.secondaryLineId;
581
+ const configuredLineIds = getConfiguredLineIds(entityConfig);
582
+ const defaultLineId = configuredLineIds[0];
463
583
  const factoryViewId = entityConfig.factoryViewId ?? "factory";
464
584
  const defaultTimezone = dateTimeConfig.defaultTimezone;
465
585
  const { shiftId, date } = getCurrentShift(defaultTimezone, shiftConfig);
466
586
  const lineId = lineIdInput;
467
587
  if (lineId === factoryViewId) {
468
- if (!defaultLineId || !secondaryLineId || !companyId) {
469
- throw new Error("Factory View requires defaultLineId, secondaryLineId, and companyId to be configured.");
588
+ if (!isValidFactoryViewConfiguration(entityConfig) || !companyId) {
589
+ throw new Error("Factory View requires at least one configured line and companyId to be configured.");
470
590
  }
471
- const { data: lineData2, error: lineError2 } = await supabase.from(linesTable).select(`
472
- id,
473
- line_name,
474
- factory_id,
475
- factories!lines_factory_id_fkey(factory_name),
476
- company_id,
477
- companies!lines_company_id_fkey(company_name:name)
478
- `).eq("id", defaultLineId).maybeSingle();
479
- if (lineError2) throw lineError2;
480
- if (!lineData2) throw new Error(`Configured default line (${defaultLineId}) not found`);
481
- const { data: metricsData, error: metricsError } = await supabase.from(lineMetricsTable).select("*").in("line_id", [defaultLineId, secondaryLineId]).eq("shift_id", shiftId).eq("date", date);
482
- if (metricsError) throw metricsError;
483
- const { data: performanceData2, error: performanceError2 } = await supabase.from(metricsTable).select("efficiency").in("line_id", [defaultLineId, secondaryLineId]).eq("shift_id", shiftId).eq("date", date);
484
- if (performanceError2) throw performanceError2;
485
- const underperformingCount2 = performanceData2?.filter((w) => w.efficiency >= 10 && w.efficiency < 70).length || 0;
486
- const totalValidWorkspaces2 = performanceData2?.filter((w) => w.efficiency >= 10).length || 0;
591
+ const [lineResult, metricsResult, performanceResult] = await Promise.all([
592
+ // Get Line 1's info for general factory details
593
+ supabase.from(linesTable).select(`
594
+ id,
595
+ line_name,
596
+ factory_id,
597
+ factories!lines_factory_id_fkey(factory_name),
598
+ company_id,
599
+ companies!lines_company_id_fkey(company_name:name)
600
+ `).eq("id", defaultLineId).maybeSingle(),
601
+ // Get metrics from line_metrics table for all configured lines
602
+ supabase.from(lineMetricsTable).select("*").in("line_id", configuredLineIds).eq("shift_id", shiftId).eq("date", date),
603
+ // Get performance data from the dynamic metrics table for all configured lines
604
+ supabase.from(metricsTable).select("efficiency").in("line_id", configuredLineIds).eq("shift_id", shiftId).eq("date", date)
605
+ ]);
606
+ if (lineResult.error) throw lineResult.error;
607
+ if (!lineResult.data) throw new Error(`Configured default line (${defaultLineId}) not found`);
608
+ if (metricsResult.error) throw metricsResult.error;
609
+ if (performanceResult.error) throw performanceResult.error;
610
+ const lineData2 = lineResult.data;
611
+ const metricsData = metricsResult.data;
612
+ const performanceData2 = performanceResult.data;
613
+ const underperformingWorkspaces2 = memoizedEfficiencyFilter(performanceData2 || [], 10, 70);
614
+ const validWorkspaces2 = memoizedEfficiencyFilter(performanceData2 || [], 10);
615
+ const underperformingCount2 = underperformingWorkspaces2.length;
616
+ validWorkspaces2.length;
487
617
  const combinedMetrics = (metricsData || []).reduce((acc, m) => {
488
618
  acc.avg_efficiency += m.efficiency ?? 0;
489
619
  acc.current_output += m.current_output ?? 0;
@@ -503,13 +633,13 @@ var dashboardService = {
503
633
  shift_id: shiftId,
504
634
  date,
505
635
  metrics: {
506
- avg_efficiency: (performanceData2?.reduce((sum, m) => sum + (m.efficiency || 0), 0) || 0) / (totalValidWorkspaces2 || 1),
507
- // Use performance data for avg efficiency
636
+ avg_efficiency: memoizedAverageEfficiency(performanceData2 || [], 10),
637
+ // Use memoized calculation for efficiency
508
638
  avg_cycle_time: 0,
509
639
  // Needs calculation logic if required for factory view
510
640
  current_output: combinedMetrics.current_output,
511
641
  ideal_output: combinedMetrics.ideal_output,
512
- total_workspaces: 44,
642
+ total_workspaces: 0,
513
643
  // SRC ALIGNMENT: Use hardcoded 44 for factory view total_workspaces
514
644
  underperforming_workspaces: underperformingCount2,
515
645
  underperforming_workspace_names: [],
@@ -547,9 +677,11 @@ var dashboardService = {
547
677
  }
548
678
  const { data: performanceData, error: performanceError } = await supabase.from(metricsTable).select("efficiency").eq("line_id", lineId).eq("shift_id", shiftId).eq("date", date);
549
679
  if (performanceError) throw performanceError;
550
- const underperformingCount = performanceData?.filter((w) => w.efficiency >= 10 && w.efficiency < 70).length || 0;
551
- const totalValidWorkspaces = performanceData?.filter((w) => w.efficiency >= 10).length || 0;
552
- const avgEfficiencyFromPerf = (performanceData?.reduce((sum, m) => sum + (m.efficiency || 0), 0) || 0) / (totalValidWorkspaces || 1);
680
+ const underperformingWorkspaces = memoizedEfficiencyFilter(performanceData || [], 10, 70);
681
+ const validWorkspaces = memoizedEfficiencyFilter(performanceData || [], 10);
682
+ const underperformingCount = underperformingWorkspaces.length;
683
+ validWorkspaces.length;
684
+ const avgEfficiencyFromPerf = memoizedAverageEfficiency(performanceData || [], 10);
553
685
  const useFallbackMetrics = !metricsFromDb;
554
686
  let metricsForReturn;
555
687
  if (useFallbackMetrics) {
@@ -616,8 +748,8 @@ var dashboardService = {
616
748
  }
617
749
  const metricsTablePrefixStr = getMetricsTablePrefix();
618
750
  const metricsTable = `${metricsTablePrefixStr}_${companyId.replace(/-/g, "_")}`;
619
- const defaultLineId = entityConfig.defaultLineId;
620
- const secondaryLineId = entityConfig.secondaryLineId;
751
+ const configuredLineIds = getConfiguredLineIds(entityConfig);
752
+ configuredLineIds[0];
621
753
  const factoryViewId = entityConfig.factoryViewId ?? "factory";
622
754
  const defaultTimezone = dateTimeConfig.defaultTimezone;
623
755
  const currentShiftResult = getCurrentShift(defaultTimezone, shiftConfig);
@@ -626,10 +758,10 @@ var dashboardService = {
626
758
  const lineId = lineIdInput;
627
759
  let query = supabase.from(metricsTable).select("company_id,line_id,shift_id,date,workspace_id,workspace_name,total_output,avg_pph,performance_score,avg_cycle_time,trend_score,ideal_output,efficiency,total_day_output").eq("shift_id", queryShiftId).eq("date", queryDate);
628
760
  if (!lineId || lineId === factoryViewId) {
629
- if (!defaultLineId || !secondaryLineId) {
630
- throw new Error("Factory View requires defaultLineId and secondaryLineId to be configured for workspace data.");
761
+ if (!isValidFactoryViewConfiguration(entityConfig)) {
762
+ throw new Error("Factory View requires at least one configured line for workspace data.");
631
763
  }
632
- query = query.in("line_id", [defaultLineId, secondaryLineId]);
764
+ query = query.in("line_id", configuredLineIds);
633
765
  } else {
634
766
  query = query.eq("line_id", lineId);
635
767
  }
@@ -854,8 +986,8 @@ var dashboardService = {
854
986
  const companyId = entityConfig.companyId;
855
987
  const metricsTablePrefixStr = getMetricsTablePrefix();
856
988
  const metricsTable = `${metricsTablePrefixStr}_${companyId ? companyId.replace(/-/g, "_") : "unknown_company"}`;
857
- const defaultLineId = entityConfig.defaultLineId;
858
- const secondaryLineId = entityConfig.secondaryLineId;
989
+ const configuredLineIds = getConfiguredLineIds(entityConfig);
990
+ const defaultLineId = configuredLineIds[0];
859
991
  const factoryViewId = entityConfig.factoryViewId ?? "factory";
860
992
  const defaultTimezone = dateTimeConfig.defaultTimezone;
861
993
  const lineIdToQuery = lineIdInput || factoryViewId;
@@ -864,22 +996,29 @@ var dashboardService = {
864
996
  const queryShiftId = shiftProp !== void 0 ? shiftProp : currentShiftResult.shiftId;
865
997
  try {
866
998
  if (lineIdToQuery === factoryViewId) {
867
- if (!defaultLineId || !companyId) {
868
- throw new Error("Factory View requires at least defaultLineId and companyId to be configured.");
999
+ if (!isValidFactoryViewConfiguration(entityConfig) || !companyId) {
1000
+ throw new Error("Factory View requires at least one configured line and companyId to be configured.");
869
1001
  }
870
- const { data: line1Data, error: line1Error } = await supabase.from(linesTable).select("id, line_name, factory_id, factories!lines_factory_id_fkey(factory_name), company_id, companies!lines_company_id_fkey(company_name:name)").eq("id", defaultLineId).single();
871
- if (line1Error) throw line1Error;
872
- if (!line1Data) {
1002
+ const lineIdsToQuery = configuredLineIds;
1003
+ const [line1Result, metricsResult2, performanceResult2] = await Promise.all([
1004
+ supabase.from(linesTable).select("id, line_name, factory_id, factories!lines_factory_id_fkey(factory_name), company_id, companies!lines_company_id_fkey(company_name:name)").eq("id", defaultLineId).single(),
1005
+ supabase.from(lineMetricsTable).select("*").in("line_id", lineIdsToQuery).eq("shift_id", queryShiftId).eq("date", queryDate),
1006
+ supabase.from(metricsTable).select("efficiency").in("line_id", lineIdsToQuery).eq("shift_id", queryShiftId).eq("date", queryDate)
1007
+ ]);
1008
+ if (line1Result.error) throw line1Result.error;
1009
+ if (!line1Result.data) {
873
1010
  throw new Error(`Default line ${defaultLineId} for Factory View not found.`);
874
1011
  }
875
- const lineIdsToQuery = [defaultLineId, secondaryLineId].filter((id3) => id3 !== void 0 && id3 !== null);
876
- const { data: metricsData, error: metricsError2 } = await supabase.from(lineMetricsTable).select("*").in("line_id", lineIdsToQuery).eq("shift_id", queryShiftId).eq("date", queryDate);
877
- if (metricsError2) throw metricsError2;
878
- const { data: performanceData2, error: performanceError2 } = await supabase.from(metricsTable).select("efficiency").in("line_id", lineIdsToQuery).eq("shift_id", queryShiftId).eq("date", queryDate);
879
- if (performanceError2) throw performanceError2;
880
- const underperformingCount2 = performanceData2?.filter((w) => w.efficiency >= 10 && w.efficiency < 70).length || 0;
881
- const totalValidWorkspaces2 = performanceData2?.filter((w) => w.efficiency >= 10).length || 0;
882
- const avgEfficiencyFromPerf2 = (performanceData2?.reduce((sum, m) => sum + (m.efficiency || 0), 0) || 0) / (totalValidWorkspaces2 || 1);
1012
+ if (metricsResult2.error) throw metricsResult2.error;
1013
+ if (performanceResult2.error) throw performanceResult2.error;
1014
+ const line1Data = line1Result.data;
1015
+ const metricsData = metricsResult2.data;
1016
+ const performanceData2 = performanceResult2.data;
1017
+ const underperformingWorkspaces2 = memoizedEfficiencyFilter(performanceData2 || [], 10, 70);
1018
+ const validWorkspaces2 = memoizedEfficiencyFilter(performanceData2 || [], 10);
1019
+ const underperformingCount2 = underperformingWorkspaces2.length;
1020
+ const totalValidWorkspaces2 = validWorkspaces2.length;
1021
+ const avgEfficiencyFromPerf2 = memoizedAverageEfficiency(performanceData2 || [], 10);
883
1022
  const initialAccumulator = {
884
1023
  avg_cycle_time: 0,
885
1024
  current_output: 0,
@@ -887,7 +1026,8 @@ var dashboardService = {
887
1026
  line_threshold: 0,
888
1027
  threshold_pph: 0,
889
1028
  total_workspaces: 0,
890
- output_array: []
1029
+ output_array: [],
1030
+ outputArrays: []
891
1031
  };
892
1032
  const combinedMetricsData = (metricsData || []).reduce((acc, m) => {
893
1033
  acc.avg_cycle_time += m.avg_cycle_time ?? 0;
@@ -897,14 +1037,7 @@ var dashboardService = {
897
1037
  acc.threshold_pph += m.threshold_pph ?? 0;
898
1038
  acc.total_workspaces += m.total_workspaces ?? 0;
899
1039
  if (m.output_array && m.output_array.length > 0) {
900
- const currentMOutputArray = m.output_array;
901
- if (!acc.output_array || acc.output_array.length === 0) acc.output_array = [...currentMOutputArray];
902
- else {
903
- acc.output_array = acc.output_array.map((val, i) => val + (currentMOutputArray[i] ?? 0));
904
- if (currentMOutputArray.length > acc.output_array.length) {
905
- acc.output_array.push(...currentMOutputArray.slice(acc.output_array.length));
906
- }
907
- }
1040
+ acc.outputArrays.push(m.output_array);
908
1041
  }
909
1042
  return acc;
910
1043
  }, initialAccumulator);
@@ -925,7 +1058,7 @@ var dashboardService = {
925
1058
  avg_cycle_time: combinedMetricsData.avg_cycle_time / numLines,
926
1059
  current_output: combinedMetricsData.current_output,
927
1060
  ideal_output: combinedMetricsData.ideal_output,
928
- total_workspaces: combinedMetricsData.total_workspaces || 44,
1061
+ total_workspaces: combinedMetricsData.total_workspaces || 0,
929
1062
  // Use combined or default
930
1063
  underperforming_workspaces: underperformingCount2,
931
1064
  line_threshold: combinedMetricsData.line_threshold,
@@ -933,7 +1066,7 @@ var dashboardService = {
933
1066
  shift_start: metricsData?.[0]?.shift_start || shiftConfig.dayShift?.startTime || "06:00",
934
1067
  shift_end: metricsData?.[0]?.shift_end || shiftConfig.dayShift?.endTime || "18:00",
935
1068
  last_updated: (/* @__PURE__ */ new Date()).toISOString(),
936
- output_array: combinedMetricsData.output_array,
1069
+ output_array: combinedMetricsData.outputArrays.length > 0 ? memoizedOutputArrayAggregation(combinedMetricsData.outputArrays) : [],
937
1070
  underperforming_workspace_names: [],
938
1071
  underperforming_workspace_uuids: [],
939
1072
  poorest_performing_workspaces: []
@@ -943,18 +1076,25 @@ var dashboardService = {
943
1076
  if (!companyId) {
944
1077
  throw new Error("Company ID must be configured for detailed line requests.");
945
1078
  }
946
- const { data: lineData, error: lineError } = await supabase.from(linesTable).select("id, line_name, factory_id, factories!lines_factory_id_fkey(factory_name), company_id, companies!lines_company_id_fkey(company_name:name)").eq("id", lineIdToQuery).single();
947
- if (lineError) throw lineError;
948
- if (!lineData) {
1079
+ const [lineResult, metricsResult, performanceResult] = await Promise.all([
1080
+ supabase.from(linesTable).select("id, line_name, factory_id, factories!lines_factory_id_fkey(factory_name), company_id, companies!lines_company_id_fkey(company_name:name)").eq("id", lineIdToQuery).single(),
1081
+ supabase.from(lineMetricsTable).select("*").eq("line_id", lineIdToQuery).eq("shift_id", queryShiftId).eq("date", queryDate).maybeSingle(),
1082
+ supabase.from(metricsTable).select("efficiency").eq("line_id", lineIdToQuery).eq("shift_id", queryShiftId).eq("date", queryDate)
1083
+ ]);
1084
+ if (lineResult.error) throw lineResult.error;
1085
+ if (!lineResult.data) {
949
1086
  throw new Error(`Line ${lineIdToQuery} not found.`);
950
1087
  }
951
- const { data: metrics2, error: metricsError } = await supabase.from(lineMetricsTable).select("*").eq("line_id", lineIdToQuery).eq("shift_id", queryShiftId).eq("date", queryDate).maybeSingle();
952
- if (metricsError) throw metricsError;
953
- const { data: performanceData, error: performanceError } = await supabase.from(metricsTable).select("efficiency").eq("line_id", lineIdToQuery).eq("shift_id", queryShiftId).eq("date", queryDate);
954
- if (performanceError) throw performanceError;
955
- const underperformingCount = performanceData?.filter((w) => w.efficiency >= 10 && w.efficiency < 70).length || 0;
956
- const totalValidWorkspaces = performanceData?.filter((w) => w.efficiency >= 10).length || 0;
957
- const avgEfficiencyFromPerf = (performanceData?.reduce((sum, m) => sum + (m.efficiency || 0), 0) || 0) / (totalValidWorkspaces || 1);
1088
+ if (metricsResult.error) throw metricsResult.error;
1089
+ if (performanceResult.error) throw performanceResult.error;
1090
+ const lineData = lineResult.data;
1091
+ const metrics2 = metricsResult.data;
1092
+ const performanceData = performanceResult.data;
1093
+ const underperformingWorkspaces = memoizedEfficiencyFilter(performanceData || [], 10, 70);
1094
+ const validWorkspaces = memoizedEfficiencyFilter(performanceData || [], 10);
1095
+ const underperformingCount = underperformingWorkspaces.length;
1096
+ const totalValidWorkspaces = validWorkspaces.length;
1097
+ const avgEfficiencyFromPerf = memoizedAverageEfficiency(performanceData || [], 10);
958
1098
  return {
959
1099
  line_id: lineData.id,
960
1100
  line_name: lineData.line_name,
@@ -1030,8 +1170,7 @@ var dashboardService = {
1030
1170
  const dbConfig = config.databaseConfig ?? DEFAULT_DATABASE_CONFIG;
1031
1171
  const entityConfig = config.entityConfig ?? DEFAULT_ENTITY_CONFIG;
1032
1172
  const lineMetricsTable = getTable2(dbConfig, "lineMetrics");
1033
- const defaultLineId = entityConfig.defaultLineId;
1034
- const secondaryLineId = entityConfig.secondaryLineId;
1173
+ const configuredLineIds = getConfiguredLineIds(entityConfig);
1035
1174
  const factoryViewId = entityConfig.factoryViewId ?? "factory";
1036
1175
  const startDate = new Date(year, month, 1);
1037
1176
  const endDate = new Date(year, month + 1, 0);
@@ -1040,10 +1179,10 @@ var dashboardService = {
1040
1179
  const formattedEndDate = formatDate(endDate);
1041
1180
  let query = supabase.from(lineMetricsTable).select("date, shift_id, avg_efficiency, underperforming_workspaces, total_workspaces").gte("date", formattedStartDate).lte("date", formattedEndDate);
1042
1181
  if (lineIdInput === factoryViewId) {
1043
- if (!defaultLineId || !secondaryLineId) {
1044
- throw new Error("Factory View requires defaultLineId and secondaryLineId for monthly data.");
1182
+ if (!isValidFactoryViewConfiguration(entityConfig)) {
1183
+ throw new Error("Factory View requires at least one configured line for monthly data.");
1045
1184
  }
1046
- query = query.in("line_id", [defaultLineId, secondaryLineId]);
1185
+ query = query.in("line_id", configuredLineIds);
1047
1186
  } else {
1048
1187
  query = query.eq("line_id", lineIdInput);
1049
1188
  }
@@ -1074,8 +1213,7 @@ var dashboardService = {
1074
1213
  const companyId = entityConfig.companyId;
1075
1214
  const metricsTablePrefixStr = getMetricsTablePrefix();
1076
1215
  const metricsTable = `${metricsTablePrefixStr}_${companyId ? companyId.replace(/-/g, "_") : "unknown_company"}`;
1077
- const defaultLineId = entityConfig.defaultLineId;
1078
- const secondaryLineId = entityConfig.secondaryLineId;
1216
+ const configuredLineIds = getConfiguredLineIds(entityConfig);
1079
1217
  const factoryViewId = entityConfig.factoryViewId ?? "factory";
1080
1218
  const worstPerformingEndpoint = endpointsConfig?.worstPerformingWorkspaces;
1081
1219
  if (!worstPerformingEndpoint) throw new Error("worstPerformingWorkspaces endpoint must be configured.");
@@ -1087,7 +1225,7 @@ var dashboardService = {
1087
1225
  const currentMonth = monthInput !== void 0 ? monthInput : currentDate.getMonth();
1088
1226
  const currentYear = yearInput !== void 0 ? yearInput : currentDate.getFullYear();
1089
1227
  const bodyPayload = {
1090
- lineId: lineIdInput === factoryViewId ? [defaultLineId, secondaryLineId] : lineIdInput,
1228
+ lineId: lineIdInput === factoryViewId ? configuredLineIds : lineIdInput,
1091
1229
  month: currentMonth,
1092
1230
  year: currentYear,
1093
1231
  companyId,
@@ -1641,6 +1779,128 @@ var workspaceService = {
1641
1779
  }
1642
1780
  };
1643
1781
 
1782
+ // src/lib/services/skuService.ts
1783
+ var getTable4 = (dbConfig, tableName) => {
1784
+ const globalConfig = _getDashboardConfigInstance();
1785
+ const defaults2 = globalConfig?.databaseConfig?.tables;
1786
+ const userValue = dbConfig?.tables?.[tableName];
1787
+ const hardcodedDefaults = {
1788
+ skus: "skus"
1789
+ };
1790
+ return userValue ?? defaults2?.[tableName] ?? hardcodedDefaults[tableName];
1791
+ };
1792
+ var skuService = {
1793
+ /**
1794
+ * Fetch all active SKUs for a company
1795
+ */
1796
+ async getSKUs(companyId) {
1797
+ const supabase = _getSupabaseInstance();
1798
+ if (!supabase) throw new Error("Supabase client not initialized");
1799
+ const config = _getDashboardConfigInstance();
1800
+ const dbConfig = config?.databaseConfig;
1801
+ const skusTable = getTable4(dbConfig, "skus");
1802
+ const { data, error } = await supabase.from(skusTable).select("*").eq("company_id", companyId).eq("is_active", true).order("created_at", { ascending: false });
1803
+ if (error) {
1804
+ console.error(`Error fetching SKUs from ${skusTable}:`, error);
1805
+ throw error;
1806
+ }
1807
+ return data || [];
1808
+ },
1809
+ /**
1810
+ * Get a single SKU by ID
1811
+ */
1812
+ async getSKU(skuId) {
1813
+ const supabase = _getSupabaseInstance();
1814
+ if (!supabase) throw new Error("Supabase client not initialized");
1815
+ const config = _getDashboardConfigInstance();
1816
+ const dbConfig = config?.databaseConfig;
1817
+ const skusTable = getTable4(dbConfig, "skus");
1818
+ const { data, error } = await supabase.from(skusTable).select("*").eq("id", skuId).single();
1819
+ if (error) {
1820
+ console.error(`Error fetching SKU from ${skusTable}:`, error);
1821
+ throw error;
1822
+ }
1823
+ return data;
1824
+ },
1825
+ /**
1826
+ * Create a new SKU
1827
+ */
1828
+ async createSKU(skuData) {
1829
+ const supabase = _getSupabaseInstance();
1830
+ if (!supabase) throw new Error("Supabase client not initialized");
1831
+ const config = _getDashboardConfigInstance();
1832
+ const dbConfig = config?.databaseConfig;
1833
+ const skusTable = getTable4(dbConfig, "skus");
1834
+ const { data, error } = await supabase.from(skusTable).insert([{
1835
+ ...skuData,
1836
+ attributes: skuData.attributes || {},
1837
+ is_active: skuData.is_active ?? true
1838
+ }]).select("*").single();
1839
+ if (error) {
1840
+ console.error(`Error creating SKU in ${skusTable}:`, error);
1841
+ throw error;
1842
+ }
1843
+ return data;
1844
+ },
1845
+ /**
1846
+ * Update an existing SKU
1847
+ */
1848
+ async updateSKU(skuId, updates) {
1849
+ const supabase = _getSupabaseInstance();
1850
+ if (!supabase) throw new Error("Supabase client not initialized");
1851
+ const config = _getDashboardConfigInstance();
1852
+ const dbConfig = config?.databaseConfig;
1853
+ const skusTable = getTable4(dbConfig, "skus");
1854
+ const { data, error } = await supabase.from(skusTable).update({
1855
+ ...updates,
1856
+ updated_at: (/* @__PURE__ */ new Date()).toISOString()
1857
+ }).eq("id", skuId).select("*").single();
1858
+ if (error) {
1859
+ console.error(`Error updating SKU in ${skusTable}:`, error);
1860
+ throw error;
1861
+ }
1862
+ return data;
1863
+ },
1864
+ /**
1865
+ * Soft delete a SKU (set is_active to false)
1866
+ */
1867
+ async deleteSKU(skuId) {
1868
+ const supabase = _getSupabaseInstance();
1869
+ if (!supabase) throw new Error("Supabase client not initialized");
1870
+ const config = _getDashboardConfigInstance();
1871
+ const dbConfig = config?.databaseConfig;
1872
+ const skusTable = getTable4(dbConfig, "skus");
1873
+ const { error } = await supabase.from(skusTable).update({
1874
+ is_active: false,
1875
+ updated_at: (/* @__PURE__ */ new Date()).toISOString()
1876
+ }).eq("id", skuId);
1877
+ if (error) {
1878
+ console.error(`Error deleting SKU from ${skusTable}:`, error);
1879
+ throw error;
1880
+ }
1881
+ },
1882
+ /**
1883
+ * Check if a SKU ID already exists for a company
1884
+ */
1885
+ async checkSKUExists(companyId, skuId, excludeId) {
1886
+ const supabase = _getSupabaseInstance();
1887
+ if (!supabase) throw new Error("Supabase client not initialized");
1888
+ const config = _getDashboardConfigInstance();
1889
+ const dbConfig = config?.databaseConfig;
1890
+ const skusTable = getTable4(dbConfig, "skus");
1891
+ let query = supabase.from(skusTable).select("id").eq("company_id", companyId).eq("sku_id", skuId).eq("is_active", true);
1892
+ if (excludeId) {
1893
+ query = query.neq("id", excludeId);
1894
+ }
1895
+ const { data, error } = await query;
1896
+ if (error) {
1897
+ console.error(`Error checking SKU existence in ${skusTable}:`, error);
1898
+ throw error;
1899
+ }
1900
+ return data && data.length > 0 || false;
1901
+ }
1902
+ };
1903
+
1644
1904
  // src/lib/services/authCoreService.ts
1645
1905
  var AUTH_ERROR_MESSAGES = {
1646
1906
  "Invalid login credentials": "Invalid email or password",
@@ -2070,6 +2330,349 @@ async function deleteThread(threadId) {
2070
2330
  const { error } = await supabase.schema("ai").from("chat_threads").delete().eq("id", threadId);
2071
2331
  if (error) throw error;
2072
2332
  }
2333
+
2334
+ // src/lib/services/cacheService.ts
2335
+ var CacheService = class {
2336
+ constructor() {
2337
+ this.memoryCache = /* @__PURE__ */ new Map();
2338
+ this.DEFAULT_DURATION = 5 * 60 * 1e3;
2339
+ }
2340
+ // 5 minutes
2341
+ /**
2342
+ * Generate a cache key from multiple parts
2343
+ */
2344
+ generateKey(...parts) {
2345
+ return parts.filter((p) => p !== void 0 && p !== null).join(":");
2346
+ }
2347
+ /**
2348
+ * Get item from cache
2349
+ */
2350
+ get(key, options) {
2351
+ const storage = options?.storage || "memory";
2352
+ try {
2353
+ let cacheItem = null;
2354
+ if (storage === "memory") {
2355
+ cacheItem = this.memoryCache.get(key) || null;
2356
+ } else if (storage === "localStorage" || storage === "sessionStorage") {
2357
+ const stored = window[storage].getItem(key);
2358
+ if (stored) {
2359
+ cacheItem = JSON.parse(stored);
2360
+ }
2361
+ }
2362
+ if (!cacheItem) {
2363
+ return null;
2364
+ }
2365
+ if (Date.now() > cacheItem.expiresAt) {
2366
+ this.delete(key, options);
2367
+ return null;
2368
+ }
2369
+ return cacheItem.data;
2370
+ } catch (error) {
2371
+ console.error(`Error getting cache item ${key}:`, error);
2372
+ return null;
2373
+ }
2374
+ }
2375
+ /**
2376
+ * Set item in cache
2377
+ */
2378
+ set(key, data, options) {
2379
+ const storage = options?.storage || "memory";
2380
+ const duration = options?.duration || this.DEFAULT_DURATION;
2381
+ const cacheItem = {
2382
+ data,
2383
+ timestamp: Date.now(),
2384
+ expiresAt: Date.now() + duration
2385
+ };
2386
+ try {
2387
+ if (storage === "memory") {
2388
+ this.memoryCache.set(key, cacheItem);
2389
+ if (this.memoryCache.size > 100) {
2390
+ const firstKey = this.memoryCache.keys().next().value;
2391
+ if (firstKey) {
2392
+ this.memoryCache.delete(firstKey);
2393
+ }
2394
+ }
2395
+ } else if (storage === "localStorage" || storage === "sessionStorage") {
2396
+ window[storage].setItem(key, JSON.stringify(cacheItem));
2397
+ }
2398
+ } catch (error) {
2399
+ console.error(`Error setting cache item ${key}:`, error);
2400
+ }
2401
+ }
2402
+ /**
2403
+ * Delete item from cache
2404
+ */
2405
+ delete(key, options) {
2406
+ const storage = options?.storage || "memory";
2407
+ try {
2408
+ if (storage === "memory") {
2409
+ this.memoryCache.delete(key);
2410
+ } else if (storage === "localStorage" || storage === "sessionStorage") {
2411
+ window[storage].removeItem(key);
2412
+ }
2413
+ } catch (error) {
2414
+ console.error(`Error deleting cache item ${key}:`, error);
2415
+ }
2416
+ }
2417
+ /**
2418
+ * Clear all items from cache
2419
+ */
2420
+ clear(options) {
2421
+ const storage = options?.storage || "memory";
2422
+ try {
2423
+ if (storage === "memory") {
2424
+ this.memoryCache.clear();
2425
+ } else if (storage === "localStorage" || storage === "sessionStorage") {
2426
+ const keys = Object.keys(window[storage]);
2427
+ keys.forEach((key) => {
2428
+ try {
2429
+ const item = window[storage].getItem(key);
2430
+ if (item) {
2431
+ const parsed = JSON.parse(item);
2432
+ if (parsed.timestamp && parsed.expiresAt && parsed.data !== void 0) {
2433
+ window[storage].removeItem(key);
2434
+ }
2435
+ }
2436
+ } catch {
2437
+ }
2438
+ });
2439
+ }
2440
+ } catch (error) {
2441
+ console.error("Error clearing cache:", error);
2442
+ }
2443
+ }
2444
+ /**
2445
+ * Get or set item in cache with a factory function
2446
+ */
2447
+ async getOrSet(key, factory, options) {
2448
+ const cached = this.get(key, options);
2449
+ if (cached !== null) {
2450
+ return cached;
2451
+ }
2452
+ const data = await factory();
2453
+ this.set(key, data, options);
2454
+ return data;
2455
+ }
2456
+ /**
2457
+ * Invalidate cache entries matching a pattern
2458
+ */
2459
+ invalidatePattern(pattern, options) {
2460
+ const storage = options?.storage || "memory";
2461
+ const regex = typeof pattern === "string" ? new RegExp(pattern) : pattern;
2462
+ try {
2463
+ if (storage === "memory") {
2464
+ const keysToDelete = [];
2465
+ this.memoryCache.forEach((_, key) => {
2466
+ if (regex.test(key)) {
2467
+ keysToDelete.push(key);
2468
+ }
2469
+ });
2470
+ keysToDelete.forEach((key) => this.memoryCache.delete(key));
2471
+ } else if (storage === "localStorage" || storage === "sessionStorage") {
2472
+ const keys = Object.keys(window[storage]);
2473
+ keys.forEach((key) => {
2474
+ if (regex.test(key)) {
2475
+ window[storage].removeItem(key);
2476
+ }
2477
+ });
2478
+ }
2479
+ } catch (error) {
2480
+ console.error("Error invalidating cache pattern:", error);
2481
+ }
2482
+ }
2483
+ /**
2484
+ * Clean up expired items
2485
+ */
2486
+ cleanup(options) {
2487
+ const storage = options?.storage || "memory";
2488
+ const now2 = Date.now();
2489
+ try {
2490
+ if (storage === "memory") {
2491
+ const keysToDelete = [];
2492
+ this.memoryCache.forEach((item, key) => {
2493
+ if (now2 > item.expiresAt) {
2494
+ keysToDelete.push(key);
2495
+ }
2496
+ });
2497
+ keysToDelete.forEach((key) => this.memoryCache.delete(key));
2498
+ } else if (storage === "localStorage" || storage === "sessionStorage") {
2499
+ const keys = Object.keys(window[storage]);
2500
+ keys.forEach((key) => {
2501
+ try {
2502
+ const item = window[storage].getItem(key);
2503
+ if (item) {
2504
+ const parsed = JSON.parse(item);
2505
+ if (parsed.expiresAt && now2 > parsed.expiresAt) {
2506
+ window[storage].removeItem(key);
2507
+ }
2508
+ }
2509
+ } catch {
2510
+ }
2511
+ });
2512
+ }
2513
+ } catch (error) {
2514
+ console.error("Error cleaning up cache:", error);
2515
+ }
2516
+ }
2517
+ };
2518
+ var cacheService = new CacheService();
2519
+ if (typeof window !== "undefined") {
2520
+ setInterval(() => {
2521
+ cacheService.cleanup({ storage: "localStorage" });
2522
+ cacheService.cleanup({ storage: "sessionStorage" });
2523
+ cacheService.cleanup({ storage: "memory" });
2524
+ }, 60 * 1e3);
2525
+ }
2526
+
2527
+ // src/lib/services/subscriptionManager.ts
2528
+ var SubscriptionManager = class {
2529
+ constructor(supabase) {
2530
+ this.subscriptions = /* @__PURE__ */ new Map();
2531
+ this.debounceTimers = /* @__PURE__ */ new Map();
2532
+ this.supabase = supabase;
2533
+ }
2534
+ /**
2535
+ * Generate a unique key for a subscription configuration
2536
+ */
2537
+ generateKey(config) {
2538
+ const { table, schema = "public", event = "*", filter: filter2 = "" } = config;
2539
+ return `${schema}:${table}:${event}:${filter2}`;
2540
+ }
2541
+ /**
2542
+ * Subscribe to real-time changes with automatic deduplication
2543
+ */
2544
+ subscribe(config) {
2545
+ const key = this.generateKey(config);
2546
+ const existing = this.subscriptions.get(key);
2547
+ if (existing) {
2548
+ existing.configs.push(config);
2549
+ existing.refCount++;
2550
+ console.log(`[SubscriptionManager] Reusing existing subscription for ${key}, refCount: ${existing.refCount}`);
2551
+ return () => this.unsubscribe(key, config.callback);
2552
+ }
2553
+ const channelName = `subscription-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
2554
+ const channel = this.supabase.channel(channelName);
2555
+ channel.on(
2556
+ "postgres_changes",
2557
+ {
2558
+ event: config.event || "*",
2559
+ schema: config.schema || "public",
2560
+ table: config.table,
2561
+ ...config.filter && { filter: config.filter }
2562
+ },
2563
+ (payload) => {
2564
+ this.debouncedCallback(key, () => {
2565
+ const subscription = this.subscriptions.get(key);
2566
+ if (subscription) {
2567
+ subscription.configs.forEach((cfg) => {
2568
+ try {
2569
+ cfg.callback(payload);
2570
+ } catch (error) {
2571
+ console.error("[SubscriptionManager] Error in callback:", error);
2572
+ }
2573
+ });
2574
+ }
2575
+ });
2576
+ }
2577
+ );
2578
+ channel.subscribe((status) => {
2579
+ console.log(`[SubscriptionManager] Subscription status for ${key}:`, status);
2580
+ });
2581
+ this.subscriptions.set(key, {
2582
+ channel,
2583
+ configs: [config],
2584
+ refCount: 1
2585
+ });
2586
+ console.log(`[SubscriptionManager] Created new subscription for ${key}`);
2587
+ return () => this.unsubscribe(key, config.callback);
2588
+ }
2589
+ /**
2590
+ * Debounce callbacks to prevent excessive updates
2591
+ */
2592
+ debouncedCallback(key, callback, delay2 = 500) {
2593
+ const existingTimer = this.debounceTimers.get(key);
2594
+ if (existingTimer) {
2595
+ clearTimeout(existingTimer);
2596
+ }
2597
+ const timer = setTimeout(() => {
2598
+ callback();
2599
+ this.debounceTimers.delete(key);
2600
+ }, delay2);
2601
+ this.debounceTimers.set(key, timer);
2602
+ }
2603
+ /**
2604
+ * Unsubscribe from a specific subscription
2605
+ */
2606
+ unsubscribe(key, callback) {
2607
+ const subscription = this.subscriptions.get(key);
2608
+ if (!subscription) {
2609
+ console.warn(`[SubscriptionManager] No subscription found for key: ${key}`);
2610
+ return;
2611
+ }
2612
+ subscription.configs = subscription.configs.filter((cfg) => cfg.callback !== callback);
2613
+ subscription.refCount--;
2614
+ console.log(`[SubscriptionManager] Unsubscribed from ${key}, refCount: ${subscription.refCount}`);
2615
+ if (subscription.refCount <= 0) {
2616
+ this.supabase.removeChannel(subscription.channel);
2617
+ this.subscriptions.delete(key);
2618
+ const timer = this.debounceTimers.get(key);
2619
+ if (timer) {
2620
+ clearTimeout(timer);
2621
+ this.debounceTimers.delete(key);
2622
+ }
2623
+ console.log(`[SubscriptionManager] Removed subscription for ${key}`);
2624
+ }
2625
+ }
2626
+ /**
2627
+ * Subscribe to multiple tables with a single callback
2628
+ */
2629
+ subscribeMultiple(configs, callback) {
2630
+ const unsubscribeFunctions = configs.map(
2631
+ (config) => this.subscribe({ ...config, callback })
2632
+ );
2633
+ return () => {
2634
+ unsubscribeFunctions.forEach((fn) => fn());
2635
+ };
2636
+ }
2637
+ /**
2638
+ * Get current subscription statistics
2639
+ */
2640
+ getStats() {
2641
+ let totalCallbacks = 0;
2642
+ this.subscriptions.forEach((sub) => {
2643
+ totalCallbacks += sub.configs.length;
2644
+ });
2645
+ return {
2646
+ totalSubscriptions: this.subscriptions.size,
2647
+ totalCallbacks
2648
+ };
2649
+ }
2650
+ /**
2651
+ * Clean up all subscriptions
2652
+ */
2653
+ cleanup() {
2654
+ this.debounceTimers.forEach((timer) => clearTimeout(timer));
2655
+ this.debounceTimers.clear();
2656
+ this.subscriptions.forEach((subscription) => {
2657
+ this.supabase.removeChannel(subscription.channel);
2658
+ });
2659
+ this.subscriptions.clear();
2660
+ console.log("[SubscriptionManager] All subscriptions cleaned up");
2661
+ }
2662
+ };
2663
+ var managerInstance = null;
2664
+ function getSubscriptionManager(supabase) {
2665
+ if (!managerInstance) {
2666
+ managerInstance = new SubscriptionManager(supabase);
2667
+ }
2668
+ return managerInstance;
2669
+ }
2670
+ function resetSubscriptionManager() {
2671
+ if (managerInstance) {
2672
+ managerInstance.cleanup();
2673
+ managerInstance = null;
2674
+ }
2675
+ }
2073
2676
  var AuthContext = createContext({
2074
2677
  session: null,
2075
2678
  user: null,
@@ -2289,6 +2892,36 @@ var useSupabase = () => {
2289
2892
  }
2290
2893
  return context.supabase;
2291
2894
  };
2895
+ var SubscriptionManagerContext = createContext({
2896
+ subscriptionManager: null
2897
+ });
2898
+ var SubscriptionManagerProvider = ({ children }) => {
2899
+ const supabase = useSupabase();
2900
+ const subscriptionManager = useMemo(() => {
2901
+ if (!supabase) return null;
2902
+ return getSubscriptionManager(supabase);
2903
+ }, [supabase]);
2904
+ useEffect(() => {
2905
+ return () => {
2906
+ if (subscriptionManager) {
2907
+ console.log("[SubscriptionManagerProvider] Cleaning up subscriptions");
2908
+ subscriptionManager.cleanup();
2909
+ }
2910
+ };
2911
+ }, [subscriptionManager]);
2912
+ return /* @__PURE__ */ jsx(SubscriptionManagerContext.Provider, { value: { subscriptionManager }, children });
2913
+ };
2914
+ var useSubscriptionManager = () => {
2915
+ const { subscriptionManager } = useContext(SubscriptionManagerContext);
2916
+ if (!subscriptionManager) {
2917
+ throw new Error("useSubscriptionManager must be used within a SubscriptionManagerProvider");
2918
+ }
2919
+ return subscriptionManager;
2920
+ };
2921
+ var useSubscriptionManagerSafe = () => {
2922
+ const { subscriptionManager } = useContext(SubscriptionManagerContext);
2923
+ return subscriptionManager;
2924
+ };
2292
2925
  var DEFAULT_COMPANY_ID = "default-company-id";
2293
2926
  var useWorkspaceMetrics = (workspaceId) => {
2294
2927
  const supabase = useSupabase();
@@ -2545,7 +3178,7 @@ var useWorkspaceDetailedMetrics = (workspaceId, date, shiftId) => {
2545
3178
  const defaultTimezone = dateTimeConfig.defaultTimezone;
2546
3179
  const workspaceMetricsBaseTable = databaseConfig.tables?.workspaces ?? "workspace_metrics";
2547
3180
  const workspaceActionsTable = databaseConfig.tables?.actions ?? "workspace_actions";
2548
- const fetchMetrics = useCallback(async () => {
3181
+ const fetchMetrics = useCallback(async (skipCache = false) => {
2549
3182
  if (!workspaceId || isFetchingRef.current) return;
2550
3183
  try {
2551
3184
  isFetchingRef.current = true;
@@ -2554,6 +3187,28 @@ var useWorkspaceDetailedMetrics = (workspaceId, date, shiftId) => {
2554
3187
  const queryShiftId = shiftId !== void 0 ? shiftId : currentShift.shiftId;
2555
3188
  console.log("[useWorkspaceDetailedMetrics] Using shift ID:", queryShiftId, "from input shift:", shiftId);
2556
3189
  console.log("[useWorkspaceDetailedMetrics] Using date:", queryDate, "from input date:", date);
3190
+ const cacheKey = cacheService.generateKey(
3191
+ "workspace-detailed-metrics",
3192
+ workspaceId,
3193
+ queryDate,
3194
+ queryShiftId,
3195
+ companyId
3196
+ );
3197
+ if (!skipCache) {
3198
+ const cachedData = cacheService.get(cacheKey, {
3199
+ storage: "memory",
3200
+ duration: 5 * 60 * 1e3
3201
+ // 5 minutes
3202
+ });
3203
+ if (cachedData) {
3204
+ console.log("[useWorkspaceDetailedMetrics] Using cached data for:", cacheKey);
3205
+ setMetrics(cachedData);
3206
+ setIsLoading(false);
3207
+ updateQueueRef.current = false;
3208
+ isFetchingRef.current = false;
3209
+ return;
3210
+ }
3211
+ }
2557
3212
  console.log(`[useWorkspaceDetailedMetrics] Querying ${metricsTable} for workspace: ${workspaceId}, date: ${queryDate}, shift: ${queryShiftId}`);
2558
3213
  const { data, error: fetchError } = await supabase.from(metricsTable).select("*").eq("workspace_id", workspaceId).eq("date", queryDate).eq("shift_id", queryShiftId).maybeSingle();
2559
3214
  if (fetchError) throw fetchError;
@@ -2656,6 +3311,18 @@ var useWorkspaceDetailedMetrics = (workspaceId, date, shiftId) => {
2656
3311
  setIsLoading(false);
2657
3312
  updateQueueRef.current = false;
2658
3313
  isFetchingRef.current = false;
3314
+ const fallbackCacheKey = cacheService.generateKey(
3315
+ "workspace-detailed-metrics",
3316
+ workspaceId,
3317
+ recentData.date,
3318
+ recentData.shift_id,
3319
+ companyId
3320
+ );
3321
+ cacheService.set(fallbackCacheKey, transformedData2, {
3322
+ storage: "memory",
3323
+ duration: 2 * 60 * 1e3
3324
+ // 2 minutes for fallback data
3325
+ });
2659
3326
  return;
2660
3327
  } else {
2661
3328
  console.warn("[useWorkspaceDetailedMetrics] No data found for workspace:", workspaceId, "at all");
@@ -2769,6 +3436,11 @@ var useWorkspaceDetailedMetrics = (workspaceId, date, shiftId) => {
2769
3436
  ...data.sop_check !== void 0 && { sop_check: data.sop_check }
2770
3437
  };
2771
3438
  setMetrics(transformedData);
3439
+ cacheService.set(cacheKey, transformedData, {
3440
+ storage: "memory",
3441
+ duration: 5 * 60 * 1e3
3442
+ // 5 minutes
3443
+ });
2772
3444
  } catch (err) {
2773
3445
  console.error("Error fetching workspace metrics:", err);
2774
3446
  setError({ message: err.message, code: err.code });
@@ -2803,7 +3475,7 @@ var useWorkspaceDetailedMetrics = (workspaceId, date, shiftId) => {
2803
3475
  },
2804
3476
  async (payload) => {
2805
3477
  console.log(`Received ${metricsTablePrefix} update:`, payload);
2806
- await fetchMetrics();
3478
+ await fetchMetrics(true);
2807
3479
  }
2808
3480
  ).subscribe((status) => {
2809
3481
  console.log(`Workspace detailed metrics subscription status:`, status);
@@ -2837,6 +3509,14 @@ var useWorkspaceDetailedMetrics = (workspaceId, date, shiftId) => {
2837
3509
  matches: payloadData?.date === operationalDate && payloadData?.shift_id === queryShiftId
2838
3510
  });
2839
3511
  if (payloadData?.date === operationalDate && payloadData?.shift_id === queryShiftId) {
3512
+ const cacheKey = cacheService.generateKey(
3513
+ "workspace-detailed-metrics",
3514
+ workspaceId,
3515
+ operationalDate,
3516
+ queryShiftId,
3517
+ companyId
3518
+ );
3519
+ cacheService.delete(cacheKey, { storage: "memory" });
2840
3520
  queueUpdate();
2841
3521
  }
2842
3522
  }
@@ -2862,6 +3542,14 @@ var useWorkspaceDetailedMetrics = (workspaceId, date, shiftId) => {
2862
3542
  matches: payloadData?.date === operationalDate && payloadData?.shift_id === queryShiftId
2863
3543
  });
2864
3544
  if (payloadData?.date === operationalDate && payloadData?.shift_id === queryShiftId) {
3545
+ const cacheKey = cacheService.generateKey(
3546
+ "workspace-detailed-metrics",
3547
+ workspaceId,
3548
+ operationalDate,
3549
+ queryShiftId,
3550
+ companyId
3551
+ );
3552
+ cacheService.delete(cacheKey, { storage: "memory" });
2865
3553
  queueUpdate();
2866
3554
  }
2867
3555
  }
@@ -2887,6 +3575,14 @@ var useWorkspaceDetailedMetrics = (workspaceId, date, shiftId) => {
2887
3575
  matches: payloadData?.date === operationalDate && payloadData?.shift_id === queryShiftId
2888
3576
  });
2889
3577
  if (payloadData?.date === operationalDate && payloadData?.shift_id === queryShiftId) {
3578
+ const cacheKey = cacheService.generateKey(
3579
+ "workspace-detailed-metrics",
3580
+ workspaceId,
3581
+ operationalDate,
3582
+ queryShiftId,
3583
+ companyId
3584
+ );
3585
+ cacheService.delete(cacheKey, { storage: "memory" });
2890
3586
  queueUpdate();
2891
3587
  }
2892
3588
  }
@@ -2913,7 +3609,8 @@ var useWorkspaceDetailedMetrics = (workspaceId, date, shiftId) => {
2913
3609
  metrics: metrics2,
2914
3610
  isLoading,
2915
3611
  error,
2916
- refetch: fetchMetrics
3612
+ refetch: () => fetchMetrics(true)
3613
+ // Force refresh without cache
2917
3614
  };
2918
3615
  };
2919
3616
  var useLineWorkspaceMetrics = (lineId, options) => {
@@ -3191,11 +3888,11 @@ var useLineDetailedMetrics = (lineIdFromProp) => {
3191
3888
  let targetLineIdsForSubscription = [];
3192
3889
  const factoryViewIdentifier = entityConfig.factoryViewId || "factory";
3193
3890
  if (lineIdToUse === factoryViewIdentifier) {
3194
- if (entityConfig.defaultLineId && entityConfig.secondaryLineId) {
3195
- targetLineIdsForSubscription = [entityConfig.defaultLineId, entityConfig.secondaryLineId];
3891
+ if (isValidFactoryViewConfiguration(entityConfig)) {
3892
+ targetLineIdsForSubscription = getConfiguredLineIds(entityConfig);
3196
3893
  filterString += `,line_id=in.(${targetLineIdsForSubscription.join(",")})`;
3197
3894
  } else {
3198
- console.warn("[useLineDetailedMetrics] Factory view selected but defaultLineId/secondaryLineId not in entityConfig. Realtime updates may be incomplete.");
3895
+ console.warn("[useLineDetailedMetrics] Factory view selected but no lines configured in entityConfig. Realtime updates may be incomplete.");
3199
3896
  return;
3200
3897
  }
3201
3898
  } else {
@@ -3413,9 +4110,9 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId }) => {
3413
4110
  try {
3414
4111
  const currentShiftDetails = getCurrentShift(defaultTimezone, shiftConfig);
3415
4112
  const operationalDate = getOperationalDate(defaultTimezone);
3416
- const targetLineIds = currentLineIdToUse === (entityConfig.factoryViewId || "factory") ? [entityConfig.defaultLineId, entityConfig.secondaryLineId].filter((id3) => !!id3) : [currentLineIdToUse];
4113
+ const targetLineIds = currentLineIdToUse === (entityConfig.factoryViewId || "factory") ? getConfiguredLineIds(entityConfig) : [currentLineIdToUse];
3417
4114
  if (targetLineIds.length === 0 && currentLineIdToUse === (entityConfig.factoryViewId || "factory")) {
3418
- throw new Error("Factory view selected, but defaultLineId and/or secondaryLineId are not configured in entityConfig.");
4115
+ throw new Error("Factory view selected, but no lines are configured in entityConfig.");
3419
4116
  }
3420
4117
  if (targetLineIds.length === 0) {
3421
4118
  throw new Error("No target line IDs available for fetching metrics.");
@@ -3515,7 +4212,7 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId }) => {
3515
4212
  }
3516
4213
  const currentShiftDetails = getCurrentShift(defaultTimezone, shiftConfig);
3517
4214
  const operationalDateForSubscription = getOperationalDate(defaultTimezone);
3518
- const targetLineIds = currentLineIdToUse === (entityConfig.factoryViewId || "factory") ? [entityConfig.defaultLineId, entityConfig.secondaryLineId].filter((id3) => !!id3) : [currentLineIdToUse];
4215
+ const targetLineIds = currentLineIdToUse === (entityConfig.factoryViewId || "factory") ? getConfiguredLineIds(entityConfig) : [currentLineIdToUse];
3519
4216
  if (targetLineIds.length === 0) return;
3520
4217
  const wsMetricsFilter = `date=eq.${operationalDateForSubscription}&shift_id=eq.${currentShiftDetails.shiftId}&line_id=in.(${targetLineIds.join(",")})`;
3521
4218
  const lineMetricsFilter = `date=eq.${operationalDateForSubscription}&shift_id=eq.${currentShiftDetails.shiftId}&line_id=in.(${targetLineIds.join(",")})`;
@@ -3684,11 +4381,8 @@ var useLineKPIs = ({ lineId }) => {
3684
4381
  const currentShiftDetails = getCurrentShift(defaultTimezone, shiftConfig);
3685
4382
  const operationalDate = currentShiftDetails.date;
3686
4383
  const factoryViewIdentifier = entityConfig.factoryViewId || "factory";
3687
- const targetLineIds = currentLineId === factoryViewIdentifier ? [entityConfig.defaultLineId, entityConfig.secondaryLineId].filter((id3) => !!id3) : [currentLineId];
3688
- if (targetLineIds.length === 0 && currentLineId === factoryViewIdentifier) {
3689
- console.warn("[useLineKPIs] Factory view: defaultLineId/secondaryLineId not in entityConfig. Cannot subscribe effectively.");
3690
- return;
3691
- } else if (targetLineIds.length === 0) {
4384
+ const targetLineIds = currentLineId === factoryViewIdentifier ? getConfiguredLineIds(entityConfig) : [currentLineId];
4385
+ if (targetLineIds.length === 0) {
3692
4386
  console.warn("[useLineKPIs] No target line IDs for subscription. LineId:", currentLineId);
3693
4387
  return;
3694
4388
  }
@@ -3788,10 +4482,8 @@ var useRealtimeLineMetrics = ({
3788
4482
  currentTime: (/* @__PURE__ */ new Date()).toLocaleString("en-US", { timeZone: dateTimeConfig.defaultTimezone || "Asia/Kolkata" })
3789
4483
  });
3790
4484
  const factoryViewId = entityConfig.factoryViewId || "factory";
3791
- const defaultLineId = entityConfig.defaultLineId;
3792
- const secondaryLineId = entityConfig.secondaryLineId;
3793
4485
  if (lineIdRef.current === factoryViewId) {
3794
- const targetLineIds = [defaultLineId, secondaryLineId].filter(Boolean);
4486
+ const targetLineIds = getConfiguredLineIds(entityConfig);
3795
4487
  if (targetLineIds.length === 0) {
3796
4488
  throw new Error("No configured line IDs for factory view");
3797
4489
  }
@@ -4005,9 +4697,7 @@ var useRealtimeLineMetrics = ({
4005
4697
  console.log("Setting up line metrics subscriptions for:", lineIdRef.current);
4006
4698
  }
4007
4699
  const factoryViewId = entityConfig.factoryViewId || "factory";
4008
- const defaultLineId = entityConfig.defaultLineId;
4009
- const secondaryLineId = entityConfig.secondaryLineId;
4010
- const targetLineIds = lineIdRef.current === factoryViewId ? [defaultLineId, secondaryLineId].filter(Boolean) : [lineIdRef.current];
4700
+ const targetLineIds = lineIdRef.current === factoryViewId ? getConfiguredLineIds(entityConfig) : [lineIdRef.current];
4011
4701
  if (targetLineIds.length === 0) {
4012
4702
  return;
4013
4703
  }
@@ -5130,19 +5820,39 @@ var useActiveBreaks = (lineIds) => {
5130
5820
  let breaks = [];
5131
5821
  if (activeShift.breaks) {
5132
5822
  if (Array.isArray(activeShift.breaks)) {
5133
- breaks = activeShift.breaks.map((breakItem) => ({
5134
- startTime: breakItem.start || breakItem.startTime || "00:00",
5135
- endTime: breakItem.end || breakItem.endTime || "00:00",
5136
- duration: breakItem.duration || 0,
5137
- remarks: breakItem.remarks || breakItem.name || ""
5138
- }));
5823
+ breaks = activeShift.breaks.map((breakItem) => {
5824
+ const startTime = breakItem.start || breakItem.startTime || "00:00";
5825
+ const endTime = breakItem.end || breakItem.endTime || "00:00";
5826
+ let duration = breakItem.duration || 0;
5827
+ if (!duration || duration === 0) {
5828
+ const startMinutes = parseTimeToMinutes2(startTime);
5829
+ const endMinutes = parseTimeToMinutes2(endTime);
5830
+ duration = endMinutes < startMinutes ? endMinutes + 24 * 60 - startMinutes : endMinutes - startMinutes;
5831
+ }
5832
+ return {
5833
+ startTime,
5834
+ endTime,
5835
+ duration,
5836
+ remarks: breakItem.remarks || breakItem.name || ""
5837
+ };
5838
+ });
5139
5839
  } else if (activeShift.breaks.breaks && Array.isArray(activeShift.breaks.breaks)) {
5140
- breaks = activeShift.breaks.breaks.map((breakItem) => ({
5141
- startTime: breakItem.start || breakItem.startTime || "00:00",
5142
- endTime: breakItem.end || breakItem.endTime || "00:00",
5143
- duration: breakItem.duration || 0,
5144
- remarks: breakItem.remarks || breakItem.name || ""
5145
- }));
5840
+ breaks = activeShift.breaks.breaks.map((breakItem) => {
5841
+ const startTime = breakItem.start || breakItem.startTime || "00:00";
5842
+ const endTime = breakItem.end || breakItem.endTime || "00:00";
5843
+ let duration = breakItem.duration || 0;
5844
+ if (!duration || duration === 0) {
5845
+ const startMinutes = parseTimeToMinutes2(startTime);
5846
+ const endMinutes = parseTimeToMinutes2(endTime);
5847
+ duration = endMinutes < startMinutes ? endMinutes + 24 * 60 - startMinutes : endMinutes - startMinutes;
5848
+ }
5849
+ return {
5850
+ startTime,
5851
+ endTime,
5852
+ duration,
5853
+ remarks: breakItem.remarks || breakItem.name || ""
5854
+ };
5855
+ });
5146
5856
  }
5147
5857
  }
5148
5858
  for (const breakItem of breaks) {
@@ -5204,12 +5914,32 @@ var useAllWorkspaceMetrics = (options) => {
5204
5914
  return `${metricsTablePrefix}_${companyId.replace(/-/g, "_")}`;
5205
5915
  }, [entityConfig.companyId]);
5206
5916
  const schema = databaseConfig.schema ?? "public";
5207
- const fetchWorkspaceMetrics = useCallback(async () => {
5917
+ const fetchWorkspaceMetrics = useCallback(async (skipCache = false) => {
5208
5918
  if (!initialized) {
5209
5919
  setLoading(true);
5210
5920
  }
5211
5921
  setError(null);
5212
5922
  try {
5923
+ const cacheKey = cacheService.generateKey(
5924
+ "all-workspace-metrics",
5925
+ entityConfig.companyId,
5926
+ queryDate,
5927
+ queryShiftId
5928
+ );
5929
+ if (!skipCache && !loading) {
5930
+ const cachedData = cacheService.get(cacheKey, {
5931
+ storage: "memory",
5932
+ duration: 5 * 60 * 1e3
5933
+ // 5 minutes
5934
+ });
5935
+ if (cachedData) {
5936
+ console.log("[useAllWorkspaceMetrics] Using cached data for:", cacheKey);
5937
+ setWorkspaces(cachedData);
5938
+ setInitialized(true);
5939
+ setLoading(false);
5940
+ return;
5941
+ }
5942
+ }
5213
5943
  console.log("Fetching all workspace metrics with params:", {
5214
5944
  queryDate,
5215
5945
  queryShiftId,
@@ -5246,6 +5976,11 @@ var useAllWorkspaceMetrics = (options) => {
5246
5976
  }));
5247
5977
  setWorkspaces(transformedData);
5248
5978
  setInitialized(true);
5979
+ cacheService.set(cacheKey, transformedData, {
5980
+ storage: "memory",
5981
+ duration: 5 * 60 * 1e3
5982
+ // 5 minutes
5983
+ });
5249
5984
  } catch (err) {
5250
5985
  console.error("Error fetching all workspace metrics:", err);
5251
5986
  setError({ message: err.message, code: err.code || "FETCH_ERROR" });
@@ -5270,7 +6005,14 @@ var useAllWorkspaceMetrics = (options) => {
5270
6005
  },
5271
6006
  async (payload) => {
5272
6007
  console.log("All workspace metrics update received:", payload);
5273
- await fetchWorkspaceMetrics();
6008
+ const cacheKey = cacheService.generateKey(
6009
+ "all-workspace-metrics",
6010
+ entityConfig.companyId,
6011
+ queryDate,
6012
+ queryShiftId
6013
+ );
6014
+ cacheService.delete(cacheKey, { storage: "memory" });
6015
+ await fetchWorkspaceMetrics(true);
5274
6016
  }
5275
6017
  ).subscribe();
5276
6018
  return channel2;
@@ -5281,16 +6023,80 @@ var useAllWorkspaceMetrics = (options) => {
5281
6023
  supabase.removeChannel(channel);
5282
6024
  }
5283
6025
  };
5284
- }, [queryDate, queryShiftId, metricsTable, fetchWorkspaceMetrics, initialized, supabase, schema]);
6026
+ }, [queryDate, queryShiftId, metricsTable, fetchWorkspaceMetrics, initialized, supabase, schema, entityConfig.companyId]);
5285
6027
  useEffect(() => {
5286
6028
  setInitialized(false);
5287
6029
  }, [queryDate, queryShiftId]);
5288
- const refreshWorkspaces = fetchWorkspaceMetrics;
6030
+ const refreshWorkspaces = useCallback(() => fetchWorkspaceMetrics(true), [fetchWorkspaceMetrics]);
5289
6031
  return useMemo(
5290
6032
  () => ({ workspaces, loading, error, refreshWorkspaces }),
5291
6033
  [workspaces, loading, error, refreshWorkspaces]
5292
6034
  );
5293
6035
  };
6036
+ var useSKUs = (companyId) => {
6037
+ const [skus, setSKUs] = useState([]);
6038
+ const [isLoading, setIsLoading] = useState(true);
6039
+ const [error, setError] = useState(null);
6040
+ const supabase = useSupabase();
6041
+ const config = useDashboardConfig();
6042
+ const dbConfig = config?.databaseConfig;
6043
+ const skusTable = dbConfig?.tables?.skus || "skus";
6044
+ const fetchSKUs = useCallback(async () => {
6045
+ if (!companyId) {
6046
+ setIsLoading(false);
6047
+ return;
6048
+ }
6049
+ try {
6050
+ setIsLoading(true);
6051
+ setError(null);
6052
+ const data = await skuService.getSKUs(companyId);
6053
+ setSKUs(data);
6054
+ } catch (err) {
6055
+ setError(err instanceof Error ? err : new Error("Failed to fetch SKUs"));
6056
+ console.error("Error fetching SKUs:", err);
6057
+ } finally {
6058
+ setIsLoading(false);
6059
+ }
6060
+ }, [companyId]);
6061
+ useEffect(() => {
6062
+ fetchSKUs();
6063
+ }, [fetchSKUs]);
6064
+ useEffect(() => {
6065
+ if (!supabase || !companyId) return;
6066
+ const channel = supabase.channel(`skus:${companyId}`).on(
6067
+ "postgres_changes",
6068
+ {
6069
+ event: "*",
6070
+ schema: dbConfig?.schema || "public",
6071
+ table: skusTable,
6072
+ filter: `company_id=eq.${companyId}`
6073
+ },
6074
+ (payload) => {
6075
+ console.log("SKU change received:", payload);
6076
+ if (payload.eventType === "INSERT") {
6077
+ setSKUs((prev) => [...prev, payload.new]);
6078
+ } else if (payload.eventType === "UPDATE") {
6079
+ setSKUs(
6080
+ (prev) => prev.map(
6081
+ (sku) => sku.id === payload.new.id ? payload.new : sku
6082
+ )
6083
+ );
6084
+ } else if (payload.eventType === "DELETE") {
6085
+ setSKUs((prev) => prev.filter((sku) => sku.id !== payload.old.id));
6086
+ }
6087
+ }
6088
+ ).subscribe();
6089
+ return () => {
6090
+ supabase.removeChannel(channel);
6091
+ };
6092
+ }, [supabase, companyId, dbConfig?.schema, skusTable]);
6093
+ return {
6094
+ skus,
6095
+ isLoading,
6096
+ error,
6097
+ refetch: fetchSKUs
6098
+ };
6099
+ };
5294
6100
  var MAX_RETRIES = 10;
5295
6101
  var RETRY_DELAY = 500;
5296
6102
  function useNavigation(customNavigate) {
@@ -8522,7 +9328,7 @@ var MotionConfigContext = createContext({
8522
9328
  });
8523
9329
 
8524
9330
  // ../../node_modules/framer-motion/dist/es/components/AnimatePresence/PopChild.mjs
8525
- var PopChildMeasure = class extends React14.Component {
9331
+ var PopChildMeasure = class extends React19.Component {
8526
9332
  getSnapshotBeforeUpdate(prevProps) {
8527
9333
  const element = this.props.childRef.current;
8528
9334
  if (element && prevProps.isPresent && !this.props.isPresent) {
@@ -8577,7 +9383,7 @@ function PopChild({ children, isPresent }) {
8577
9383
  document.head.removeChild(style);
8578
9384
  };
8579
9385
  }, [isPresent]);
8580
- return jsx(PopChildMeasure, { isPresent, childRef: ref, sizeRef: size, children: React14.cloneElement(children, { ref }) });
9386
+ return jsx(PopChildMeasure, { isPresent, childRef: ref, sizeRef: size, children: React19.cloneElement(children, { ref }) });
8581
9387
  }
8582
9388
 
8583
9389
  // ../../node_modules/framer-motion/dist/es/components/AnimatePresence/PresenceChild.mjs
@@ -8614,7 +9420,7 @@ var PresenceChild = ({ children, initial, isPresent, onExitComplete, custom, pre
8614
9420
  useMemo(() => {
8615
9421
  presenceChildren.forEach((_, key) => presenceChildren.set(key, false));
8616
9422
  }, [isPresent]);
8617
- React14.useEffect(() => {
9423
+ React19.useEffect(() => {
8618
9424
  !isPresent && !presenceChildren.size && onExitComplete && onExitComplete();
8619
9425
  }, [isPresent]);
8620
9426
  if (mode === "popLayout") {
@@ -10021,7 +10827,7 @@ function removeItem(arr, item) {
10021
10827
  }
10022
10828
 
10023
10829
  // ../../node_modules/framer-motion/dist/es/utils/subscription-manager.mjs
10024
- var SubscriptionManager = class {
10830
+ var SubscriptionManager3 = class {
10025
10831
  constructor() {
10026
10832
  this.subscriptions = [];
10027
10833
  }
@@ -10150,7 +10956,7 @@ var MotionValue = class {
10150
10956
  }
10151
10957
  on(eventName, callback) {
10152
10958
  if (!this.events[eventName]) {
10153
- this.events[eventName] = new SubscriptionManager();
10959
+ this.events[eventName] = new SubscriptionManager3();
10154
10960
  }
10155
10961
  const unsubscribe = this.events[eventName].add(callback);
10156
10962
  if (eventName === "change") {
@@ -14144,7 +14950,7 @@ function createProjectionNode2({ attachResizeListener, defaultParent, measureScr
14144
14950
  }
14145
14951
  addEventListener(name, handler) {
14146
14952
  if (!this.eventHandlers.has(name)) {
14147
- this.eventHandlers.set(name, new SubscriptionManager());
14953
+ this.eventHandlers.set(name, new SubscriptionManager3());
14148
14954
  }
14149
14955
  return this.eventHandlers.get(name).add(handler);
14150
14956
  }
@@ -15734,7 +16540,7 @@ var VisualElement = class {
15734
16540
  }
15735
16541
  on(eventName, callback) {
15736
16542
  if (!this.events[eventName]) {
15737
- this.events[eventName] = new SubscriptionManager();
16543
+ this.events[eventName] = new SubscriptionManager3();
15738
16544
  }
15739
16545
  return this.events[eventName].add(callback);
15740
16546
  }
@@ -15883,7 +16689,7 @@ var LoadingPage = ({
15883
16689
  subMessage = "Please wait while we prepare your data",
15884
16690
  className
15885
16691
  }) => {
15886
- React14__default.useEffect(() => {
16692
+ React19__default.useEffect(() => {
15887
16693
  console.log("LoadingPage rendered with message:", message);
15888
16694
  const timeout = setTimeout(() => {
15889
16695
  console.warn("LoadingPage has been visible for more than 8 seconds. This might indicate an issue.");
@@ -15926,10 +16732,10 @@ var withAuth = (WrappedComponent2, options) => {
15926
16732
  return function WithAuthComponent(props) {
15927
16733
  const { session, loading } = useAuth();
15928
16734
  const router = useRouter();
15929
- React14.useEffect(() => {
16735
+ React19.useEffect(() => {
15930
16736
  console.log("withAuth state:", { loading, hasSession: !!session, requireAuth: defaultOptions.requireAuth });
15931
16737
  }, [session, loading]);
15932
- React14.useEffect(() => {
16738
+ React19.useEffect(() => {
15933
16739
  if (!loading && defaultOptions.requireAuth && !session) {
15934
16740
  console.log("Redirecting to login from withAuth");
15935
16741
  router.replace(defaultOptions.redirectTo);
@@ -16257,7 +17063,7 @@ var DebugAuth = () => {
16257
17063
  ] }) });
16258
17064
  };
16259
17065
  var DEFAULT_BAR_RADIUS = [4, 4, 0, 0];
16260
- var BarChart = ({
17066
+ var BarChartComponent = ({
16261
17067
  data,
16262
17068
  bars,
16263
17069
  xAxisDataKey = "name",
@@ -16345,7 +17151,35 @@ var BarChart = ({
16345
17151
  }
16346
17152
  return /* @__PURE__ */ jsx("div", { className: clsx("w-full", className), children: chartContent });
16347
17153
  };
16348
- var LineChart = ({
17154
+ var BarChart = React19__default.memo(BarChartComponent, (prevProps, nextProps) => {
17155
+ 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) {
17156
+ return false;
17157
+ }
17158
+ if (prevProps.data.length !== nextProps.data.length) {
17159
+ return false;
17160
+ }
17161
+ if (!prevProps.data.every((item, idx) => {
17162
+ const nextItem = nextProps.data[idx];
17163
+ return Object.keys(item).every((key) => item[key] === nextItem[key]);
17164
+ })) {
17165
+ return false;
17166
+ }
17167
+ if (prevProps.bars.length !== nextProps.bars.length) {
17168
+ return false;
17169
+ }
17170
+ if (!prevProps.bars.every((bar, idx) => {
17171
+ const nextBar = nextProps.bars[idx];
17172
+ return bar.dataKey === nextBar.dataKey && bar.name === nextBar.name && bar.fill === nextBar.fill && JSON.stringify(bar.radius) === JSON.stringify(nextBar.radius) && bar.labelList === nextBar.labelList;
17173
+ })) {
17174
+ return false;
17175
+ }
17176
+ if (prevProps.tooltipFormatter !== nextProps.tooltipFormatter || JSON.stringify(prevProps.legendPayload) !== JSON.stringify(nextProps.legendPayload)) {
17177
+ return false;
17178
+ }
17179
+ return true;
17180
+ });
17181
+ BarChart.displayName = "BarChart";
17182
+ var LineChartComponent = ({
16349
17183
  data,
16350
17184
  lines,
16351
17185
  xAxisDataKey = "name",
@@ -16436,7 +17270,35 @@ var LineChart = ({
16436
17270
  }
16437
17271
  return /* @__PURE__ */ jsx("div", { className: clsx("w-full", className), children: chartContent });
16438
17272
  };
16439
- var OutputProgressChart = ({
17273
+ var LineChart = React19__default.memo(LineChartComponent, (prevProps, nextProps) => {
17274
+ 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)) {
17275
+ return false;
17276
+ }
17277
+ if (prevProps.data.length !== nextProps.data.length) {
17278
+ return false;
17279
+ }
17280
+ if (!prevProps.data.every((item, idx) => {
17281
+ const nextItem = nextProps.data[idx];
17282
+ return Object.keys(item).every((key) => item[key] === nextItem[key]);
17283
+ })) {
17284
+ return false;
17285
+ }
17286
+ if (prevProps.lines.length !== nextProps.lines.length) {
17287
+ return false;
17288
+ }
17289
+ if (!prevProps.lines.every((line, idx) => {
17290
+ const nextLine = nextProps.lines[idx];
17291
+ return line.dataKey === nextLine.dataKey && line.name === nextLine.name && line.stroke === nextLine.stroke && line.strokeWidth === nextLine.strokeWidth && line.type === nextLine.type && JSON.stringify(line.dot) === JSON.stringify(nextLine.dot) && JSON.stringify(line.activeDot) === JSON.stringify(nextLine.activeDot) && line.labelList === nextLine.labelList;
17292
+ })) {
17293
+ return false;
17294
+ }
17295
+ if (prevProps.tooltipFormatter !== nextProps.tooltipFormatter || prevProps.xAxisTickFormatter !== nextProps.xAxisTickFormatter || JSON.stringify(prevProps.legendPayload) !== JSON.stringify(nextProps.legendPayload)) {
17296
+ return false;
17297
+ }
17298
+ return true;
17299
+ });
17300
+ LineChart.displayName = "LineChart";
17301
+ var OutputProgressChartComponent = ({
16440
17302
  currentOutput,
16441
17303
  targetOutput,
16442
17304
  className = ""
@@ -16485,6 +17347,8 @@ var OutputProgressChart = ({
16485
17347
  ] }) })
16486
17348
  ] }) });
16487
17349
  };
17350
+ var OutputProgressChart = React19__default.memo(OutputProgressChartComponent);
17351
+ OutputProgressChart.displayName = "OutputProgressChart";
16488
17352
  var LargeOutputProgressChart = ({
16489
17353
  currentOutput,
16490
17354
  targetOutput,
@@ -16534,7 +17398,7 @@ var LargeOutputProgressChart = ({
16534
17398
  ] }) })
16535
17399
  ] }) });
16536
17400
  };
16537
- var CycleTimeChart = ({
17401
+ var CycleTimeChartComponent = ({
16538
17402
  data = [],
16539
17403
  className = ""
16540
17404
  }) => {
@@ -16599,6 +17463,25 @@ var CycleTimeChart = ({
16599
17463
  }
16600
17464
  ) }) });
16601
17465
  };
17466
+ var CycleTimeChart = React19__default.memo(CycleTimeChartComponent, (prevProps, nextProps) => {
17467
+ if (prevProps.className !== nextProps.className) {
17468
+ return false;
17469
+ }
17470
+ if (!prevProps.data && !nextProps.data) {
17471
+ return true;
17472
+ }
17473
+ if (!prevProps.data || !nextProps.data) {
17474
+ return false;
17475
+ }
17476
+ if (prevProps.data.length !== nextProps.data.length) {
17477
+ return false;
17478
+ }
17479
+ return prevProps.data.every((item, index) => {
17480
+ const nextItem = nextProps.data[index];
17481
+ return item.time === nextItem.time && item.value === nextItem.value;
17482
+ });
17483
+ });
17484
+ CycleTimeChart.displayName = "CycleTimeChart";
16602
17485
  var CycleTimeOverTimeChart = ({
16603
17486
  data,
16604
17487
  idealCycleTime,
@@ -16616,10 +17499,10 @@ var CycleTimeOverTimeChart = ({
16616
17499
  };
16617
17500
  const displayData = getDisplayData(data);
16618
17501
  const DURATION = displayData.length;
16619
- const [animatedData, setAnimatedData] = React14__default.useState(Array(DURATION).fill(0));
16620
- const prevDataRef = React14__default.useRef(Array(DURATION).fill(0));
16621
- const animationFrameRef = React14__default.useRef(null);
16622
- const animateToNewData = React14__default.useCallback((targetData) => {
17502
+ const [animatedData, setAnimatedData] = React19__default.useState(Array(DURATION).fill(0));
17503
+ const prevDataRef = React19__default.useRef(Array(DURATION).fill(0));
17504
+ const animationFrameRef = React19__default.useRef(null);
17505
+ const animateToNewData = React19__default.useCallback((targetData) => {
16623
17506
  const startData = [...prevDataRef.current];
16624
17507
  const startTime = performance.now();
16625
17508
  const duration = 1200;
@@ -16649,7 +17532,7 @@ var CycleTimeOverTimeChart = ({
16649
17532
  }
16650
17533
  animationFrameRef.current = requestAnimationFrame(animate);
16651
17534
  }, []);
16652
- React14__default.useEffect(() => {
17535
+ React19__default.useEffect(() => {
16653
17536
  if (JSON.stringify(data) !== JSON.stringify(prevDataRef.current)) {
16654
17537
  const processedData = getDisplayData(data);
16655
17538
  animateToNewData(processedData);
@@ -16873,7 +17756,7 @@ var CycleTimeOverTimeChart = ({
16873
17756
  renderLegend()
16874
17757
  ] });
16875
17758
  };
16876
- var Card = React14.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
17759
+ var Card = React19.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
16877
17760
  "div",
16878
17761
  {
16879
17762
  ref,
@@ -16885,7 +17768,7 @@ var Card = React14.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */
16885
17768
  }
16886
17769
  ));
16887
17770
  Card.displayName = "Card";
16888
- var CardHeader = React14.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
17771
+ var CardHeader = React19.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
16889
17772
  "div",
16890
17773
  {
16891
17774
  ref,
@@ -16894,7 +17777,7 @@ var CardHeader = React14.forwardRef(({ className, ...props }, ref) => /* @__PURE
16894
17777
  }
16895
17778
  ));
16896
17779
  CardHeader.displayName = "CardHeader";
16897
- var CardTitle = React14.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
17780
+ var CardTitle = React19.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
16898
17781
  "h3",
16899
17782
  {
16900
17783
  ref,
@@ -16906,7 +17789,7 @@ var CardTitle = React14.forwardRef(({ className, ...props }, ref) => /* @__PURE_
16906
17789
  }
16907
17790
  ));
16908
17791
  CardTitle.displayName = "CardTitle";
16909
- var CardDescription = React14.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
17792
+ var CardDescription = React19.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
16910
17793
  "p",
16911
17794
  {
16912
17795
  ref,
@@ -16915,9 +17798,9 @@ var CardDescription = React14.forwardRef(({ className, ...props }, ref) => /* @_
16915
17798
  }
16916
17799
  ));
16917
17800
  CardDescription.displayName = "CardDescription";
16918
- var CardContent = React14.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("p-6 pt-0", className), ...props }));
17801
+ var CardContent = React19.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("p-6 pt-0", className), ...props }));
16919
17802
  CardContent.displayName = "CardContent";
16920
- var CardFooter = React14.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
17803
+ var CardFooter = React19.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
16921
17804
  "div",
16922
17805
  {
16923
17806
  ref,
@@ -16993,7 +17876,7 @@ var buttonVariants = cva(
16993
17876
  }
16994
17877
  }
16995
17878
  );
16996
- var Button = React14.forwardRef(
17879
+ var Button = React19.forwardRef(
16997
17880
  ({ className, variant, size, asChild = false, ...props }, ref) => {
16998
17881
  const Comp = asChild ? Slot : "button";
16999
17882
  return /* @__PURE__ */ jsx(
@@ -17007,7 +17890,7 @@ var Button = React14.forwardRef(
17007
17890
  }
17008
17891
  );
17009
17892
  Button.displayName = "Button";
17010
- var HourlyOutputChart = ({
17893
+ var HourlyOutputChartComponent = ({
17011
17894
  data,
17012
17895
  pphThreshold,
17013
17896
  shiftStart,
@@ -17024,17 +17907,17 @@ var HourlyOutputChart = ({
17024
17907
  };
17025
17908
  const shiftStartTime = getTimeFromTimeString(shiftStart);
17026
17909
  const SHIFT_DURATION = 11;
17027
- const [animatedData, setAnimatedData] = React14__default.useState(Array(SHIFT_DURATION).fill(0));
17028
- const prevDataRef = React14__default.useRef(Array(SHIFT_DURATION).fill(0));
17029
- const animationFrameRef = React14__default.useRef(null);
17030
- const [idleBarState, setIdleBarState] = React14__default.useState({
17910
+ const [animatedData, setAnimatedData] = React19__default.useState(Array(SHIFT_DURATION).fill(0));
17911
+ const prevDataRef = React19__default.useRef(Array(SHIFT_DURATION).fill(0));
17912
+ const animationFrameRef = React19__default.useRef(null);
17913
+ const [idleBarState, setIdleBarState] = React19__default.useState({
17031
17914
  visible: showIdleTime,
17032
17915
  key: 0,
17033
17916
  shouldAnimate: false
17034
17917
  });
17035
- const prevShowIdleTimeRef = React14__default.useRef(showIdleTime);
17036
- const stateUpdateTimeoutRef = React14__default.useRef(null);
17037
- React14__default.useEffect(() => {
17918
+ const prevShowIdleTimeRef = React19__default.useRef(showIdleTime);
17919
+ const stateUpdateTimeoutRef = React19__default.useRef(null);
17920
+ React19__default.useEffect(() => {
17038
17921
  if (stateUpdateTimeoutRef.current) {
17039
17922
  clearTimeout(stateUpdateTimeoutRef.current);
17040
17923
  }
@@ -17059,7 +17942,7 @@ var HourlyOutputChart = ({
17059
17942
  }
17060
17943
  };
17061
17944
  }, [showIdleTime]);
17062
- const animateToNewData = React14__default.useCallback((targetData) => {
17945
+ const animateToNewData = React19__default.useCallback((targetData) => {
17063
17946
  const startData = [...prevDataRef.current];
17064
17947
  const startTime = performance.now();
17065
17948
  const duration = 1200;
@@ -17089,7 +17972,7 @@ var HourlyOutputChart = ({
17089
17972
  }
17090
17973
  animationFrameRef.current = requestAnimationFrame(animate);
17091
17974
  }, []);
17092
- React14__default.useEffect(() => {
17975
+ React19__default.useEffect(() => {
17093
17976
  if (JSON.stringify(data) !== JSON.stringify(prevDataRef.current)) {
17094
17977
  const shiftData = data.slice(0, SHIFT_DURATION);
17095
17978
  animateToNewData(shiftData);
@@ -17100,7 +17983,7 @@ var HourlyOutputChart = ({
17100
17983
  }
17101
17984
  };
17102
17985
  }, [data, animateToNewData]);
17103
- const formatHour = React14__default.useCallback((hourIndex) => {
17986
+ const formatHour = React19__default.useCallback((hourIndex) => {
17104
17987
  const startDecimalHour = shiftStartTime.decimalHour + hourIndex;
17105
17988
  const startHour = Math.floor(startDecimalHour) % 24;
17106
17989
  const startMinute = Math.round(startDecimalHour % 1 * 60);
@@ -17117,7 +18000,7 @@ var HourlyOutputChart = ({
17117
18000
  };
17118
18001
  return `${formatTime2(startHour, startMinute)}-${formatTime2(endHour, endMinute)}`;
17119
18002
  }, [shiftStartTime.decimalHour]);
17120
- const formatTimeRange = React14__default.useCallback((hourIndex) => {
18003
+ const formatTimeRange = React19__default.useCallback((hourIndex) => {
17121
18004
  const startDecimalHour = shiftStartTime.decimalHour + hourIndex;
17122
18005
  const startHour = Math.floor(startDecimalHour) % 24;
17123
18006
  const startMinute = Math.round(startDecimalHour % 1 * 60);
@@ -17131,7 +18014,7 @@ var HourlyOutputChart = ({
17131
18014
  };
17132
18015
  return `${formatTime2(startHour, startMinute)} - ${formatTime2(endHour, endMinute)}`;
17133
18016
  }, [shiftStartTime.decimalHour]);
17134
- const chartData = React14__default.useMemo(() => {
18017
+ const chartData = React19__default.useMemo(() => {
17135
18018
  return Array.from({ length: SHIFT_DURATION }, (_, i) => {
17136
18019
  const actualHour = (shiftStartTime.hour + i) % 24;
17137
18020
  const idleArray = idleTimeHourly?.[actualHour.toString()] || [];
@@ -17148,7 +18031,7 @@ var HourlyOutputChart = ({
17148
18031
  };
17149
18032
  });
17150
18033
  }, [animatedData, data, pphThreshold, idleTimeHourly, shiftStartTime.hour, formatHour, formatTimeRange]);
17151
- const IdleBar = React14__default.useMemo(() => {
18034
+ const IdleBar = React19__default.useMemo(() => {
17152
18035
  if (!idleBarState.visible) return null;
17153
18036
  return /* @__PURE__ */ jsx(
17154
18037
  Bar,
@@ -17465,6 +18348,33 @@ var HourlyOutputChart = ({
17465
18348
  renderLegend()
17466
18349
  ] });
17467
18350
  };
18351
+ var HourlyOutputChart = React19__default.memo(HourlyOutputChartComponent, (prevProps, nextProps) => {
18352
+ if (prevProps.pphThreshold !== nextProps.pphThreshold || prevProps.shiftStart !== nextProps.shiftStart || prevProps.showIdleTime !== nextProps.showIdleTime || prevProps.className !== nextProps.className) {
18353
+ return false;
18354
+ }
18355
+ if (prevProps.data.length !== nextProps.data.length) {
18356
+ return false;
18357
+ }
18358
+ if (!prevProps.data.every((val, idx) => val === nextProps.data[idx])) {
18359
+ return false;
18360
+ }
18361
+ const prevIdle = prevProps.idleTimeHourly || {};
18362
+ const nextIdle = nextProps.idleTimeHourly || {};
18363
+ const prevKeys = Object.keys(prevIdle);
18364
+ const nextKeys = Object.keys(nextIdle);
18365
+ if (prevKeys.length !== nextKeys.length) {
18366
+ return false;
18367
+ }
18368
+ for (const key of prevKeys) {
18369
+ if (!nextIdle[key]) return false;
18370
+ const prevArray = prevIdle[key];
18371
+ const nextArray = nextIdle[key];
18372
+ if (prevArray.length !== nextArray.length) return false;
18373
+ if (!prevArray.every((val, idx) => val === nextArray[idx])) return false;
18374
+ }
18375
+ return true;
18376
+ });
18377
+ HourlyOutputChart.displayName = "HourlyOutputChart";
17468
18378
  function getTrendArrowAndColor(trend) {
17469
18379
  if (trend > 0) {
17470
18380
  return { arrow: "\u2191", color: "text-green-400" };
@@ -17474,7 +18384,7 @@ function getTrendArrowAndColor(trend) {
17474
18384
  return { arrow: "\u2192", color: "text-gray-400" };
17475
18385
  }
17476
18386
  }
17477
- var VideoCard = React14__default.memo(({
18387
+ var VideoCard = React19__default.memo(({
17478
18388
  workspace,
17479
18389
  hlsUrl,
17480
18390
  shouldPlay,
@@ -17617,7 +18527,7 @@ var VideoCard = React14__default.memo(({
17617
18527
  });
17618
18528
  VideoCard.displayName = "VideoCard";
17619
18529
  var DEFAULT_HLS_URL = "https://192.168.5.9:8443/cam1.m3u8";
17620
- var VideoGridView = React14__default.memo(({
18530
+ var VideoGridView = React19__default.memo(({
17621
18531
  workspaces,
17622
18532
  selectedLine,
17623
18533
  className = "",
@@ -18419,7 +19329,7 @@ var EmptyStateMessage = ({
18419
19329
  iconClassName
18420
19330
  }) => {
18421
19331
  let IconContent = null;
18422
- if (React14__default.isValidElement(iconType)) {
19332
+ if (React19__default.isValidElement(iconType)) {
18423
19333
  IconContent = iconType;
18424
19334
  } else if (typeof iconType === "string") {
18425
19335
  const MappedIcon = IconMap[iconType];
@@ -18552,7 +19462,10 @@ var BreakNotificationPopup = ({
18552
19462
  /* @__PURE__ */ jsxs("div", { className: "flex items-center space-x-3 flex-1", children: [
18553
19463
  /* @__PURE__ */ jsx("div", { className: "w-2 h-2 bg-amber-500 rounded-full animate-pulse flex-shrink-0 mt-2" }),
18554
19464
  /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
18555
- /* @__PURE__ */ jsx("div", { className: "mb-1", children: /* @__PURE__ */ jsx("h4", { className: "font-semibold text-sm text-gray-900", children: breakItem.remarks || "Break" }) }),
19465
+ /* @__PURE__ */ jsxs("div", { className: "mb-1", children: [
19466
+ /* @__PURE__ */ jsx("h4", { className: "font-semibold text-sm text-gray-900", children: breakItem.remarks || "Break" }),
19467
+ (activeBreaks.length > 1 || lineNames[breakItem.lineId]) && /* @__PURE__ */ jsx("div", { className: "text-xs text-gray-500 mt-0.5", children: lineNames[breakItem.lineId] || `Line ${breakItem.lineId.substring(0, 8)}` })
19468
+ ] }),
18556
19469
  /* @__PURE__ */ jsx("div", { className: "mb-2", children: /* @__PURE__ */ jsxs("div", { className: "text-xs text-gray-600 font-medium", children: [
18557
19470
  breakItem.startTime,
18558
19471
  " - ",
@@ -18561,8 +19474,7 @@ var BreakNotificationPopup = ({
18561
19474
  /* @__PURE__ */ jsx("div", { className: "mb-2", children: /* @__PURE__ */ jsxs("div", { className: "text-xs text-gray-500", children: [
18562
19475
  formatTime2(breakItem.elapsedMinutes),
18563
19476
  " / ",
18564
- breakItem.duration,
18565
- " min"
19477
+ formatTime2(breakItem.duration)
18566
19478
  ] }) }),
18567
19479
  /* @__PURE__ */ jsx("div", { className: "mt-2", children: /* @__PURE__ */ jsx("div", { className: "w-full bg-gray-200 rounded-full h-1.5", children: /* @__PURE__ */ jsx(
18568
19480
  "div",
@@ -21001,7 +21913,7 @@ function Skeleton({ className, ...props }) {
21001
21913
  var Select = SelectPrimitive.Root;
21002
21914
  var SelectGroup = SelectPrimitive.Group;
21003
21915
  var SelectValue = SelectPrimitive.Value;
21004
- var SelectTrigger = React14.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(
21916
+ var SelectTrigger = React19.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(
21005
21917
  SelectPrimitive.Trigger,
21006
21918
  {
21007
21919
  ref,
@@ -21017,7 +21929,7 @@ var SelectTrigger = React14.forwardRef(({ className, children, ...props }, ref)
21017
21929
  }
21018
21930
  ));
21019
21931
  SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
21020
- var SelectScrollUpButton = React14.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
21932
+ var SelectScrollUpButton = React19.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
21021
21933
  SelectPrimitive.ScrollUpButton,
21022
21934
  {
21023
21935
  ref,
@@ -21027,7 +21939,7 @@ var SelectScrollUpButton = React14.forwardRef(({ className, ...props }, ref) =>
21027
21939
  }
21028
21940
  ));
21029
21941
  SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName;
21030
- var SelectScrollDownButton = React14.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
21942
+ var SelectScrollDownButton = React19.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
21031
21943
  SelectPrimitive.ScrollDownButton,
21032
21944
  {
21033
21945
  ref,
@@ -21037,7 +21949,7 @@ var SelectScrollDownButton = React14.forwardRef(({ className, ...props }, ref) =
21037
21949
  }
21038
21950
  ));
21039
21951
  SelectScrollDownButton.displayName = SelectPrimitive.ScrollDownButton.displayName;
21040
- var SelectContent = React14.forwardRef(({ className, children, position = "popper", ...props }, ref) => /* @__PURE__ */ jsx(SelectPrimitive.Portal, { children: /* @__PURE__ */ jsxs(
21952
+ var SelectContent = React19.forwardRef(({ className, children, position = "popper", ...props }, ref) => /* @__PURE__ */ jsx(SelectPrimitive.Portal, { children: /* @__PURE__ */ jsxs(
21041
21953
  SelectPrimitive.Content,
21042
21954
  {
21043
21955
  ref,
@@ -21065,7 +21977,7 @@ var SelectContent = React14.forwardRef(({ className, children, position = "poppe
21065
21977
  }
21066
21978
  ) }));
21067
21979
  SelectContent.displayName = SelectPrimitive.Content.displayName;
21068
- var SelectLabel = React14.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
21980
+ var SelectLabel = React19.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
21069
21981
  SelectPrimitive.Label,
21070
21982
  {
21071
21983
  ref,
@@ -21074,7 +21986,7 @@ var SelectLabel = React14.forwardRef(({ className, ...props }, ref) => /* @__PUR
21074
21986
  }
21075
21987
  ));
21076
21988
  SelectLabel.displayName = SelectPrimitive.Label.displayName;
21077
- var SelectItem = React14.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(
21989
+ var SelectItem = React19.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(
21078
21990
  SelectPrimitive.Item,
21079
21991
  {
21080
21992
  ref,
@@ -21090,7 +22002,7 @@ var SelectItem = React14.forwardRef(({ className, children, ...props }, ref) =>
21090
22002
  }
21091
22003
  ));
21092
22004
  SelectItem.displayName = SelectPrimitive.Item.displayName;
21093
- var SelectSeparator = React14.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
22005
+ var SelectSeparator = React19.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
21094
22006
  SelectPrimitive.Separator,
21095
22007
  {
21096
22008
  ref,
@@ -21965,7 +22877,7 @@ var BottlenecksContent = ({
21965
22877
  className
21966
22878
  }) => {
21967
22879
  const dashboardConfig = useDashboardConfig();
21968
- const sopCategories = React14__default.useMemo(() => {
22880
+ const sopCategories = React19__default.useMemo(() => {
21969
22881
  const sopConfig = dashboardConfig?.s3Config?.sopCategories;
21970
22882
  if (!sopConfig) return null;
21971
22883
  if (sopConfig.workspaceOverrides && sopConfig.workspaceOverrides[workspaceId]) {
@@ -22944,7 +23856,7 @@ var arePropsEqual = (prevProps, nextProps) => {
22944
23856
  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
22945
23857
  prevProps.position.id === nextProps.position.id;
22946
23858
  };
22947
- var WorkspaceGridItem = React14__default.memo(({
23859
+ var WorkspaceGridItem = React19__default.memo(({
22948
23860
  data,
22949
23861
  position,
22950
23862
  isBottleneck = false,
@@ -23037,7 +23949,7 @@ var WorkspaceGridItem = React14__default.memo(({
23037
23949
  );
23038
23950
  }, arePropsEqual);
23039
23951
  WorkspaceGridItem.displayName = "WorkspaceGridItem";
23040
- var WorkspaceGrid = React14__default.memo(({
23952
+ var WorkspaceGrid = React19__default.memo(({
23041
23953
  workspaces,
23042
23954
  isPdfMode = false,
23043
23955
  customWorkspacePositions,
@@ -23227,7 +24139,7 @@ var KPICard = ({
23227
24139
  }) => {
23228
24140
  useThemeConfig();
23229
24141
  const { formatNumber } = useFormatNumber();
23230
- const trendInfo = React14__default.useMemo(() => {
24142
+ const trendInfo = React19__default.useMemo(() => {
23231
24143
  let trendValue = trend || "neutral";
23232
24144
  if (change !== void 0 && trend === void 0) {
23233
24145
  trendValue = change > 0 ? "up" : change < 0 ? "down" : "neutral";
@@ -23250,7 +24162,7 @@ var KPICard = ({
23250
24162
  const shouldShowTrend = !(change === 0 && trend === void 0);
23251
24163
  return { trendValue, Icon: Icon2, colorClass, shouldShowTrend };
23252
24164
  }, [trend, change]);
23253
- const formattedValue = React14__default.useMemo(() => {
24165
+ const formattedValue = React19__default.useMemo(() => {
23254
24166
  if (title === "Quality Compliance" && typeof value === "number") {
23255
24167
  return value.toFixed(1);
23256
24168
  }
@@ -23264,7 +24176,7 @@ var KPICard = ({
23264
24176
  }
23265
24177
  return value;
23266
24178
  }, [value, title]);
23267
- const formattedChange = React14__default.useMemo(() => {
24179
+ const formattedChange = React19__default.useMemo(() => {
23268
24180
  if (change === void 0 || change === 0) return null;
23269
24181
  const absChange = Math.abs(change);
23270
24182
  return formatNumber(absChange, { minimumFractionDigits: 0, maximumFractionDigits: 1 });
@@ -23751,7 +24663,7 @@ var Breadcrumbs = ({ items }) => {
23751
24663
  }
23752
24664
  }
23753
24665
  };
23754
- 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(React14__default.Fragment, { children: [
24666
+ 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(React19__default.Fragment, { children: [
23755
24667
  index > 0 && /* @__PURE__ */ jsx(ChevronRight, { className: "h-3 w-3 text-gray-400 dark:text-gray-500" }),
23756
24668
  /* @__PURE__ */ jsxs(
23757
24669
  "span",
@@ -23943,7 +24855,9 @@ var SideNavBar = memo(({
23943
24855
  const router = useRouter();
23944
24856
  const { navigate } = useNavigation();
23945
24857
  const entityConfig = useEntityConfig();
24858
+ const dashboardConfig = useDashboardConfig();
23946
24859
  const lineId = entityConfig.defaultLineId || LINE_1_UUID;
24860
+ const skuEnabled = dashboardConfig?.skuConfig?.enabled || false;
23947
24861
  const pathname = propPathname || router.pathname;
23948
24862
  const getButtonClasses = useCallback((path) => {
23949
24863
  const isActive = pathname === path || pathname.startsWith(path + "/");
@@ -24018,6 +24932,14 @@ var SideNavBar = memo(({
24018
24932
  }
24019
24933
  }
24020
24934
  }), [navigate]);
24935
+ const handleSKUsClick = useCallback(() => navigate("/skus", {
24936
+ trackingEvent: {
24937
+ name: "SKU Management Page Clicked",
24938
+ properties: {
24939
+ source: "side_nav"
24940
+ }
24941
+ }
24942
+ }), [navigate]);
24021
24943
  const homeButtonClasses = useMemo(() => getButtonClasses("/"), [getButtonClasses, pathname]);
24022
24944
  const leaderboardButtonClasses = useMemo(() => getButtonClasses("/leaderboard"), [getButtonClasses, pathname]);
24023
24945
  const kpisButtonClasses = useMemo(() => getButtonClasses("/kpis"), [getButtonClasses, pathname]);
@@ -24026,6 +24948,7 @@ var SideNavBar = memo(({
24026
24948
  const aiAgentButtonClasses = useMemo(() => getButtonClasses("/ai-agent"), [getButtonClasses, pathname]);
24027
24949
  const profileButtonClasses = useMemo(() => getButtonClasses("/profile"), [getButtonClasses, pathname]);
24028
24950
  const helpButtonClasses = useMemo(() => getButtonClasses("/help"), [getButtonClasses, pathname]);
24951
+ const skusButtonClasses = useMemo(() => getButtonClasses("/skus"), [getButtonClasses, pathname]);
24029
24952
  return /* @__PURE__ */ jsxs("aside", { className: `w-20 h-screen bg-white shadow-lg border-r border-gray-100 flex flex-col items-center fixed ${className}`, children: [
24030
24953
  /* @__PURE__ */ jsx("div", { className: "w-full py-6 px-4 flex-shrink-0", children: /* @__PURE__ */ jsx(
24031
24954
  "button",
@@ -24126,6 +25049,21 @@ var SideNavBar = memo(({
24126
25049
  ]
24127
25050
  }
24128
25051
  ),
25052
+ skuEnabled && /* @__PURE__ */ jsxs(
25053
+ "button",
25054
+ {
25055
+ onClick: handleSKUsClick,
25056
+ className: skusButtonClasses,
25057
+ "aria-label": "SKU Management",
25058
+ tabIndex: 0,
25059
+ role: "tab",
25060
+ "aria-selected": pathname === "/skus" || pathname.startsWith("/skus/"),
25061
+ children: [
25062
+ /* @__PURE__ */ jsx(CubeIcon, { className: "w-5 h-5 mb-1" }),
25063
+ /* @__PURE__ */ jsx("span", { className: "text-[10px] font-medium leading-tight", children: "SKUs" })
25064
+ ]
25065
+ }
25066
+ ),
24129
25067
  /* @__PURE__ */ jsxs(
24130
25068
  "button",
24131
25069
  {
@@ -24310,6 +25248,103 @@ var Header = ({
24310
25248
  ] })
24311
25249
  ] }) });
24312
25250
  };
25251
+ var LoadingState = ({
25252
+ message = "Loading...",
25253
+ subMessage,
25254
+ size = "lg",
25255
+ className = ""
25256
+ }) => {
25257
+ return /* @__PURE__ */ jsx("div", { className: `flex h-full w-full items-center justify-center bg-gray-50/50 ${className}`, children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center space-y-4 text-center", children: [
25258
+ /* @__PURE__ */ jsx(LoadingSpinner_default, { size }),
25259
+ /* @__PURE__ */ jsxs("div", { children: [
25260
+ /* @__PURE__ */ jsx("h3", { className: "text-lg font-medium text-gray-900", children: message }),
25261
+ subMessage && /* @__PURE__ */ jsx("p", { className: "mt-1 text-sm text-gray-600", children: subMessage })
25262
+ ] })
25263
+ ] }) });
25264
+ };
25265
+ var LoadingSkeleton = ({
25266
+ type,
25267
+ count = 1,
25268
+ className = "",
25269
+ showLoadingIndicator = true
25270
+ }) => {
25271
+ const renderSkeleton = () => {
25272
+ switch (type) {
25273
+ case "card":
25274
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-3 p-4 border rounded-lg relative", children: [
25275
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-3/4" }),
25276
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-8 w-1/2" }),
25277
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-3 w-full" }),
25278
+ showLoadingIndicator && /* @__PURE__ */ jsx("div", { className: "absolute top-2 right-2", children: /* @__PURE__ */ jsxs("div", { className: "flex space-x-1", children: [
25279
+ /* @__PURE__ */ jsx("div", { className: "w-1.5 h-1.5 bg-blue-500 rounded-full animate-bounce", style: { animationDelay: "0ms" } }),
25280
+ /* @__PURE__ */ jsx("div", { className: "w-1.5 h-1.5 bg-blue-500 rounded-full animate-bounce", style: { animationDelay: "150ms" } }),
25281
+ /* @__PURE__ */ jsx("div", { className: "w-1.5 h-1.5 bg-blue-500 rounded-full animate-bounce", style: { animationDelay: "300ms" } })
25282
+ ] }) })
25283
+ ] });
25284
+ case "chart":
25285
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-3 p-4 relative", children: [
25286
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-6 w-1/3" }),
25287
+ /* @__PURE__ */ jsxs("div", { className: "relative", children: [
25288
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-64 w-full" }),
25289
+ showLoadingIndicator && /* @__PURE__ */ jsx("div", { className: "absolute inset-0 flex items-center justify-center", children: /* @__PURE__ */ jsx("div", { className: "bg-white/80 rounded-lg p-3 shadow-sm", children: /* @__PURE__ */ jsxs("svg", { className: "animate-spin h-6 w-6 text-blue-500", xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", children: [
25290
+ /* @__PURE__ */ jsx("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }),
25291
+ /* @__PURE__ */ jsx("path", { className: "opacity-75", fill: "currentColor", d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" })
25292
+ ] }) }) })
25293
+ ] })
25294
+ ] });
25295
+ case "table":
25296
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
25297
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-10 w-full" }),
25298
+ [...Array(5)].map((_, i) => /* @__PURE__ */ jsx(Skeleton, { className: "h-12 w-full" }, i))
25299
+ ] });
25300
+ case "list":
25301
+ return /* @__PURE__ */ jsx("div", { className: "space-y-2", children: [...Array(5)].map((_, i) => /* @__PURE__ */ jsxs("div", { className: "flex items-center space-x-3", children: [
25302
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-10 w-10 rounded-full" }),
25303
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 space-y-2", children: [
25304
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-3/4" }),
25305
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-3 w-1/2" })
25306
+ ] })
25307
+ ] }, i)) });
25308
+ case "kpi":
25309
+ return /* @__PURE__ */ jsx("div", { className: "grid grid-cols-2 md:grid-cols-4 gap-4", children: [...Array(4)].map((_, i) => /* @__PURE__ */ jsxs("div", { className: "p-4 border rounded-lg space-y-2", children: [
25310
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-2/3" }),
25311
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-8 w-1/2" }),
25312
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-3 w-full" })
25313
+ ] }, i)) });
25314
+ case "workspace-card":
25315
+ return /* @__PURE__ */ jsxs("div", { className: "p-4 border rounded-lg space-y-3", children: [
25316
+ /* @__PURE__ */ jsxs("div", { className: "flex justify-between items-start", children: [
25317
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-5 w-1/3" }),
25318
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-5 w-16" })
25319
+ ] }),
25320
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-32 w-full" }),
25321
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-2", children: [
25322
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-8 w-full" }),
25323
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-8 w-full" })
25324
+ ] })
25325
+ ] });
25326
+ case "video-grid":
25327
+ return /* @__PURE__ */ jsx("div", { className: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4", children: [...Array(6)].map((_, i) => /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
25328
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-48 w-full rounded-lg" }),
25329
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-3/4" }),
25330
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-3 w-1/2" })
25331
+ ] }, i)) });
25332
+ default:
25333
+ return /* @__PURE__ */ jsx(Skeleton, { className: "h-20 w-full" });
25334
+ }
25335
+ };
25336
+ return /* @__PURE__ */ jsx("div", { className, children: [...Array(count)].map((_, index) => /* @__PURE__ */ jsx("div", { children: renderSkeleton() }, index)) });
25337
+ };
25338
+ var LoadingInline = ({
25339
+ message,
25340
+ size = "sm",
25341
+ className = ""
25342
+ }) => {
25343
+ return /* @__PURE__ */ jsxs("div", { className: `inline-flex items-center space-x-2 ${className}`, children: [
25344
+ /* @__PURE__ */ jsx(LoadingSpinner_default, { size }),
25345
+ message && /* @__PURE__ */ jsx("span", { className: "text-sm text-gray-600", children: message })
25346
+ ] });
25347
+ };
24313
25348
  var DEFAULT_HLS_CONFIG = {
24314
25349
  maxBufferLength: 15,
24315
25350
  // Moderate buffer length for faster startup
@@ -24569,7 +25604,7 @@ var ThreadSidebar = ({
24569
25604
  ] });
24570
25605
  };
24571
25606
  var axelProfilePng = "/axel-profile.png";
24572
- var ProfilePicture = React14__default.memo(({ alt = "Axel", className = "w-12 h-12" }) => {
25607
+ var ProfilePicture = React19__default.memo(({ alt = "Axel", className = "w-12 h-12" }) => {
24573
25608
  return /* @__PURE__ */ jsx("div", { className: "flex-shrink-0", children: /* @__PURE__ */ jsx("div", { className: `${className} rounded-xl overflow-hidden shadow-sm`, children: /* @__PURE__ */ jsx(
24574
25609
  "img",
24575
25610
  {
@@ -24687,6 +25722,7 @@ var AIAgentView = () => {
24687
25722
  const textareaRef = useRef(null);
24688
25723
  const messagesEndRef = useRef(null);
24689
25724
  const containerRef = useRef(null);
25725
+ const renderedContentCache = useRef(/* @__PURE__ */ new Map());
24690
25726
  const { createThread, mutate: mutateThreads } = useThreads();
24691
25727
  const { messages, addMessage, setMessages } = useMessages(activeThreadId);
24692
25728
  const agnoApiUrl = config.endpoints?.agnoApiUrl || "https://optifye-agent-production.up.railway.app";
@@ -25172,6 +26208,10 @@ var AIAgentView = () => {
25172
26208
  });
25173
26209
  }
25174
26210
  const renderAssistantContent = (content) => {
26211
+ const cached = renderedContentCache.current.get(content);
26212
+ if (cached) {
26213
+ return cached;
26214
+ }
25175
26215
  const parseChartPatterns = (text) => {
25176
26216
  const chartElements = [];
25177
26217
  let lastIndex = 0;
@@ -26036,16 +27076,20 @@ var AIAgentView = () => {
26036
27076
  }
26037
27077
  };
26038
27078
  const chartContent = parseChartPatterns(content);
27079
+ let finalNode;
26039
27080
  if (chartContent) {
26040
- return /* @__PURE__ */ jsx("div", { className: "formatted-content", children: chartContent });
27081
+ finalNode = /* @__PURE__ */ jsx("div", { className: "formatted-content", children: chartContent });
27082
+ } else {
27083
+ finalNode = /* @__PURE__ */ jsx(
27084
+ "div",
27085
+ {
27086
+ className: "formatted-content",
27087
+ dangerouslySetInnerHTML: { __html: formatMessage(content) }
27088
+ }
27089
+ );
26041
27090
  }
26042
- return /* @__PURE__ */ jsx(
26043
- "div",
26044
- {
26045
- className: "formatted-content",
26046
- dangerouslySetInnerHTML: { __html: formatMessage(content) }
26047
- }
26048
- );
27091
+ renderedContentCache.current.set(content, finalNode);
27092
+ return finalNode;
26049
27093
  };
26050
27094
  return /* @__PURE__ */ jsxs("div", { className: "flex h-screen bg-white", children: [
26051
27095
  /* @__PURE__ */ jsx("style", { dangerouslySetInnerHTML: {
@@ -26416,20 +27460,33 @@ var DEFAULT_SHIFT_CONFIG2 = {
26416
27460
  var FactoryView = ({
26417
27461
  line1Id,
26418
27462
  line2Id,
27463
+ lineIds,
27464
+ lineNames = {},
26419
27465
  factoryName = "Plant 1",
26420
27466
  timezone = DEFAULT_TIMEZONE,
26421
27467
  shiftConfig = DEFAULT_SHIFT_CONFIG2,
26422
27468
  productIds = {}
26423
27469
  }) => {
27470
+ const effectiveLineIds = useMemo(() => {
27471
+ if (lineIds && lineIds.length > 0) {
27472
+ return lineIds;
27473
+ }
27474
+ const ids = [];
27475
+ if (line1Id) ids.push(line1Id);
27476
+ if (line2Id && line2Id !== line1Id) ids.push(line2Id);
27477
+ return ids;
27478
+ }, [lineIds, line1Id, line2Id]);
26424
27479
  const router = useRouter();
26425
27480
  const supabase = useSupabase();
26426
- const line1DataHook = useLineDetailedMetrics(line1Id);
26427
- const line2DataHook = useLineDetailedMetrics(line2Id);
27481
+ const lineDataHooks = effectiveLineIds.map((lineId) => ({
27482
+ lineId,
27483
+ hook: useLineDetailedMetrics(lineId)
27484
+ }));
26428
27485
  const [lines, setLines] = useState([]);
26429
27486
  const [loading, setLoading] = useState(true);
26430
27487
  const [error, setError] = useState(null);
26431
27488
  useMemo(() => {
26432
- const processLineData = (hookData, defaultName) => {
27489
+ const processLineData = (hookData, lineId) => {
26433
27490
  const currentLineInfo = hookData.lineData;
26434
27491
  let last5HoursData = [];
26435
27492
  if (currentLineInfo && currentLineInfo.metrics && currentLineInfo.metrics.output_array && currentLineInfo.metrics.output_array.length > 0) {
@@ -26450,6 +27507,7 @@ var FactoryView = ({
26450
27507
  }
26451
27508
  }
26452
27509
  }
27510
+ const defaultName = lineNames[lineId] || `Line ${lineId.substring(0, 8)}`;
26453
27511
  return {
26454
27512
  name: currentLineInfo?.line_name || defaultName,
26455
27513
  metrics: currentLineInfo,
@@ -26458,11 +27516,8 @@ var FactoryView = ({
26458
27516
  last5Hours: last5HoursData.slice(-5)
26459
27517
  };
26460
27518
  };
26461
- return [
26462
- processLineData(line1DataHook, "Line 1"),
26463
- processLineData(line2DataHook, "Line 2")
26464
- ];
26465
- }, [line1DataHook, line2DataHook]);
27519
+ return lineDataHooks.map(({ lineId, hook }) => processLineData(hook, lineId));
27520
+ }, [lineDataHooks, lineNames]);
26466
27521
  useEffect(() => {
26467
27522
  const fetchHourlyData = async () => {
26468
27523
  try {
@@ -26473,45 +27528,37 @@ var FactoryView = ({
26473
27528
  }
26474
27529
  const { shiftId } = getCurrentShift(timezone, shiftConfig);
26475
27530
  const date = getOperationalDate();
26476
- const { data: hourlyDataLine1, error: errorL1 } = await supabase.from("line_hourly_metrics").select("hour, efficiency").eq("line_id", line1Id).eq("shift_id", shiftId).eq("date", date).order("hour", { ascending: false }).limit(5);
26477
- if (errorL1) throw errorL1;
26478
- const { data: hourlyDataLine2, error: errorL2 } = await supabase.from("line_hourly_metrics").select("hour, efficiency").eq("line_id", line2Id).eq("shift_id", shiftId).eq("date", date).order("hour", { ascending: false }).limit(5);
26479
- if (errorL2) throw errorL2;
26480
- const linesData = [];
26481
- if (line1DataHook.lineData && line1DataHook.lineData.metrics && line1DataHook.lineData.metrics.output_array) {
26482
- linesData.push({
26483
- details: {
26484
- id: line1Id,
26485
- line_name: line1DataHook.lineData.line_name || "Line 1",
26486
- factory_id: line1DataHook.lineData.factory_id || "",
26487
- factory_name: line1DataHook.lineData.factory_name || "Factory 1"
26488
- },
26489
- current_output: line1DataHook.lineData.metrics.current_output || 0,
26490
- ideal_output: line1DataHook.lineData.metrics.ideal_output || 0,
26491
- avg_efficiency: line1DataHook.lineData.metrics.avg_efficiency || 0,
26492
- total_workspaces: line1DataHook.lineData.metrics.total_workspaces || 0,
26493
- underperforming_workspaces: line1DataHook.lineData.metrics.underperforming_workspaces || 0,
26494
- last5Hours: (hourlyDataLine1 || []).map((h) => ({ hour: h.hour, efficiency: h.efficiency })).reverse(),
26495
- productId: productIds[line1Id] || "Product A"
26496
- });
26497
- }
26498
- if (line2DataHook.lineData && line2DataHook.lineData.metrics && line2DataHook.lineData.metrics.output_array) {
26499
- linesData.push({
26500
- details: {
26501
- id: line2Id,
26502
- line_name: line2DataHook.lineData.line_name || "Line 2",
26503
- factory_id: line2DataHook.lineData.factory_id || "",
26504
- factory_name: line2DataHook.lineData.factory_name || "Factory 2"
26505
- },
26506
- current_output: line2DataHook.lineData.metrics.current_output || 0,
26507
- ideal_output: line2DataHook.lineData.metrics.ideal_output || 0,
26508
- avg_efficiency: line2DataHook.lineData.metrics.avg_efficiency || 0,
26509
- total_workspaces: line2DataHook.lineData.metrics.total_workspaces || 0,
26510
- underperforming_workspaces: line2DataHook.lineData.metrics.underperforming_workspaces || 0,
26511
- last5Hours: (hourlyDataLine2 || []).map((h) => ({ hour: h.hour, efficiency: h.efficiency })).reverse(),
26512
- productId: productIds[line2Id] || "Product B"
26513
- });
27531
+ const hourlyDataPromises = effectiveLineIds.map(
27532
+ (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)
27533
+ );
27534
+ const hourlyDataResults = await Promise.all(hourlyDataPromises);
27535
+ for (let i = 0; i < hourlyDataResults.length; i++) {
27536
+ if (hourlyDataResults[i].error) {
27537
+ throw hourlyDataResults[i].error;
27538
+ }
26514
27539
  }
27540
+ const linesData = [];
27541
+ lineDataHooks.forEach(({ lineId, hook }, index) => {
27542
+ const lineData = hook.lineData;
27543
+ const hourlyData = hourlyDataResults[index].data;
27544
+ if (lineData && lineData.metrics && lineData.metrics.output_array) {
27545
+ linesData.push({
27546
+ details: {
27547
+ id: lineId,
27548
+ line_name: lineData.line_name || lineNames[lineId] || `Line ${index + 1}`,
27549
+ factory_id: lineData.factory_id || "",
27550
+ factory_name: lineData.factory_name || factoryName
27551
+ },
27552
+ current_output: lineData.metrics.current_output || 0,
27553
+ ideal_output: lineData.metrics.ideal_output || 0,
27554
+ avg_efficiency: lineData.metrics.avg_efficiency || 0,
27555
+ total_workspaces: lineData.metrics.total_workspaces || 0,
27556
+ underperforming_workspaces: lineData.metrics.underperforming_workspaces || 0,
27557
+ last5Hours: (hourlyData || []).map((h) => ({ hour: h.hour, efficiency: h.efficiency })).reverse(),
27558
+ productId: productIds[lineId] || `Product ${String.fromCharCode(65 + index)}`
27559
+ });
27560
+ }
27561
+ });
26515
27562
  setLines(linesData);
26516
27563
  setLoading(false);
26517
27564
  } catch (err) {
@@ -26520,10 +27567,11 @@ var FactoryView = ({
26520
27567
  setLoading(false);
26521
27568
  }
26522
27569
  };
26523
- if (!line1DataHook.loading && !line2DataHook.loading) {
27570
+ const allHooksLoaded = lineDataHooks.every(({ hook }) => !hook.loading);
27571
+ if (allHooksLoaded) {
26524
27572
  fetchHourlyData();
26525
27573
  }
26526
- }, [supabase, line1DataHook, line2DataHook, line1Id, line2Id, timezone, shiftConfig, productIds]);
27574
+ }, [supabase, lineDataHooks, effectiveLineIds, lineNames, factoryName, timezone, shiftConfig, productIds]);
26527
27575
  const getShiftName = () => {
26528
27576
  const now2 = /* @__PURE__ */ new Date();
26529
27577
  const currentHour = now2.getHours();
@@ -26537,7 +27585,7 @@ var FactoryView = ({
26537
27585
  return /* @__PURE__ */ jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z" }) });
26538
27586
  }
26539
27587
  };
26540
- if (loading || line1DataHook.loading || line2DataHook.loading) {
27588
+ if (loading || lineDataHooks.some((hookData) => hookData.hook.loading)) {
26541
27589
  return /* @__PURE__ */ jsx("div", { className: "p-4", children: /* @__PURE__ */ jsxs("div", { className: "animate-pulse space-y-4", children: [
26542
27590
  /* @__PURE__ */ jsx("div", { className: "h-12 bg-gray-200 rounded" }),
26543
27591
  /* @__PURE__ */ jsx("div", { className: "h-12 bg-gray-200 rounded" })
@@ -27288,7 +28336,6 @@ var AuthenticatedHelpView = withAuth(HelpView);
27288
28336
  var HelpView_default = HelpView;
27289
28337
  var KPISection2 = KPISection;
27290
28338
  var LoadingPageCmp = LoadingPage_default;
27291
- var LoadingOverlayCmp = LoadingOverlay_default;
27292
28339
  function HomeView({
27293
28340
  defaultLineId,
27294
28341
  factoryViewId,
@@ -27307,6 +28354,7 @@ function HomeView({
27307
28354
  const [isChangingFilter, setIsChangingFilter] = useState(false);
27308
28355
  const [errorMessage, setErrorMessage] = useState(null);
27309
28356
  const [displayNamesInitialized, setDisplayNamesInitialized] = useState(false);
28357
+ const [hasInitialDataLoaded, setHasInitialDataLoaded] = useState(false);
27310
28358
  useEffect(() => {
27311
28359
  const initDisplayNames = async () => {
27312
28360
  try {
@@ -27357,17 +28405,17 @@ function HomeView({
27357
28405
  lineId: selectedLineId,
27358
28406
  onLineMetricsUpdate
27359
28407
  });
27360
- const lineIdsForBreaks = useMemo(() => {
27361
- if (selectedLineId === factoryViewId) {
27362
- return allLineIds;
27363
- }
27364
- return [selectedLineId];
27365
- }, [selectedLineId, factoryViewId, allLineIds]);
27366
28408
  const {
27367
- activeBreaks,
28409
+ activeBreaks: allActiveBreaks,
27368
28410
  isLoading: breaksLoading,
27369
28411
  error: breaksError
27370
- } = useActiveBreaks(lineIdsForBreaks);
28412
+ } = useActiveBreaks(allLineIds);
28413
+ const activeBreaks = useMemo(() => {
28414
+ if (selectedLineId === factoryViewId) {
28415
+ return allActiveBreaks;
28416
+ }
28417
+ return allActiveBreaks.filter((breakItem) => breakItem.lineId === selectedLineId);
28418
+ }, [allActiveBreaks, selectedLineId, factoryViewId]);
27371
28419
  const memoizedWorkspaceMetrics = useMemo(() => workspaceMetrics, [
27372
28420
  // Only update reference if meaningful properties change
27373
28421
  workspaceMetrics.length,
@@ -27407,6 +28455,11 @@ function HomeView({
27407
28455
  }
27408
28456
  }
27409
28457
  }, [metricsLoading, kpisLoading, workspaceMetrics, isChangingFilter, selectedLineId, factoryViewId]);
28458
+ useEffect(() => {
28459
+ if (!metricsLoading && !kpisLoading && !hasInitialDataLoaded) {
28460
+ setHasInitialDataLoaded(true);
28461
+ }
28462
+ }, [metricsLoading, kpisLoading, hasInitialDataLoaded]);
27410
28463
  const lineTitle = useMemo(() => {
27411
28464
  return factoryName;
27412
28465
  }, [factoryName]);
@@ -27419,9 +28472,10 @@ function HomeView({
27419
28472
  /* @__PURE__ */ jsx(SelectContent, { className: "z-50 bg-white shadow-lg border border-gray-200 rounded-md", children: availableLineIds.map((id3) => /* @__PURE__ */ jsx(SelectItem, { value: id3, children: lineNames[id3] || (id3 === factoryViewId ? "All Lines" : `Line ${id3.substring(0, 4)}`) }, id3)) })
27420
28473
  ] });
27421
28474
  }, [availableLineIds, handleLineChange, selectedLineId, lineNames, factoryViewId, allLineIds.length]);
27422
- const isLoading = !isHydrated || metricsLoading || kpisLoading || isChangingFilter || displayNamesLoading || !displayNamesInitialized;
27423
- if (isLoading) {
27424
- return /* @__PURE__ */ jsx("div", { className: "min-h-screen bg-slate-50", children: /* @__PURE__ */ jsx(LoadingPageCmp, { message: "Loading dashboard..." }) });
28475
+ const isInitialLoading = !isHydrated || !displayNamesInitialized && displayNamesLoading;
28476
+ const isDataLoading = metricsLoading || kpisLoading;
28477
+ if (isInitialLoading) {
28478
+ return /* @__PURE__ */ jsx(LoadingPageCmp, { message: "Loading Dashboard..." });
27425
28479
  }
27426
28480
  if (errorMessage || displayNamesError) {
27427
28481
  return /* @__PURE__ */ jsx("div", { className: "flex h-screen items-center justify-center", children: /* @__PURE__ */ jsx("div", { className: "rounded-lg bg-white p-6 shadow-lg", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center space-x-3 text-red-500", children: [
@@ -27432,52 +28486,64 @@ function HomeView({
27432
28486
  ] })
27433
28487
  ] }) }) });
27434
28488
  }
27435
- if ((metricsLoading || kpisLoading) && (!workspaceMetrics || workspaceMetrics.length === 0) && selectedLineId !== factoryViewId) {
27436
- return /* @__PURE__ */ jsx("div", { className: "min-h-screen bg-slate-50", children: /* @__PURE__ */ jsx(LoadingPageCmp, { message: "Loading metrics..." }) });
27437
- }
27438
- return /* @__PURE__ */ jsxs(
28489
+ return /* @__PURE__ */ jsx(
27439
28490
  motion.div,
27440
28491
  {
27441
28492
  className: "flex min-h-screen bg-slate-50",
27442
28493
  initial: { opacity: 1 },
27443
28494
  animate: { opacity: 1 },
27444
- children: [
27445
- /* @__PURE__ */ jsx(LoadingOverlayCmp, { isVisible: isChangingFilter, message: "Loading new metrics..." }),
27446
- /* @__PURE__ */ jsxs("div", { className: "relative flex flex-1", children: [
27447
- /* @__PURE__ */ jsxs("main", { className: "flex flex-1 flex-col", children: [
27448
- /* @__PURE__ */ jsx("div", { className: "sticky top-0 z-30 sm:static bg-white shadow-sm border-b border-gray-200/80", children: /* @__PURE__ */ jsx("div", { className: "flex flex-col sm:flex-row sm:items-center sm:justify-between px-3 sm:px-6 lg:px-8 py-1.5 sm:py-2.5", children: /* @__PURE__ */ jsx(
27449
- DashboardHeader,
27450
- {
27451
- lineTitle,
27452
- className: "w-full",
27453
- headerControls: memoizedKPIs ? /* @__PURE__ */ jsx(KPISection2, { kpis: memoizedKPIs, className: "w-full sm:w-auto" }) : null
27454
- }
27455
- ) }) }),
27456
- /* @__PURE__ */ jsxs("div", { className: "flex-1 overflow-y-auto sm:overflow-hidden relative", children: [
27457
- lineSelectorComponent && /* @__PURE__ */ jsx("div", { className: "absolute right-3 top-2 sm:right-6 sm:top-3 z-30", children: lineSelectorComponent }),
27458
- memoizedWorkspaceMetrics.length > 0 ? /* @__PURE__ */ jsx("div", { className: "h-full sm:h-full min-h-[calc(100vh-80px)] sm:min-h-0", children: React14__default.createElement(WorkspaceGrid, {
27459
- workspaces: memoizedWorkspaceMetrics,
27460
- lineNames,
27461
- factoryView: factoryViewId,
27462
- videoSources,
27463
- className: "h-full"
27464
- }) }) : /* @__PURE__ */ jsx(NoWorkspaceData, { message: "No workspace data available. Select another line or check configurations." })
27465
- ] })
27466
- ] }),
27467
- /* @__PURE__ */ jsx(
27468
- BreakNotificationPopup,
28495
+ children: /* @__PURE__ */ jsxs("div", { className: "relative flex flex-1", children: [
28496
+ /* @__PURE__ */ jsxs("main", { className: "flex flex-1 flex-col", children: [
28497
+ /* @__PURE__ */ jsx("div", { className: "sticky top-0 z-30 sm:static bg-white shadow-sm border-b border-gray-200/80", children: /* @__PURE__ */ jsx("div", { className: "flex flex-col sm:flex-row sm:items-center sm:justify-between px-3 sm:px-6 lg:px-8 py-1.5 sm:py-2.5", children: /* @__PURE__ */ jsx(
28498
+ DashboardHeader,
27469
28499
  {
27470
- activeBreaks,
27471
- lineNames,
27472
- isVisible: !breaksLoading && !breaksError
28500
+ lineTitle,
28501
+ className: "w-full",
28502
+ headerControls: memoizedKPIs ? /* @__PURE__ */ jsx(KPISection2, { kpis: memoizedKPIs, className: "w-full sm:w-auto" }) : null
27473
28503
  }
27474
- )
27475
- ] })
27476
- ]
28504
+ ) }) }),
28505
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 overflow-y-auto sm:overflow-hidden relative", children: [
28506
+ lineSelectorComponent && /* @__PURE__ */ jsx("div", { className: "absolute right-3 top-2 sm:right-6 sm:top-3 z-30", children: lineSelectorComponent }),
28507
+ /* @__PURE__ */ jsx("div", { className: "h-full sm:h-full min-h-[calc(100vh-80px)] sm:min-h-0", children: isDataLoading && hasInitialDataLoaded && memoizedWorkspaceMetrics.length === 0 ? /* @__PURE__ */ jsx("div", { className: "px-3 sm:px-6 lg:px-8 py-4", children: /* @__PURE__ */ jsx(LoadingSkeleton, { type: "workspace-card", count: 8, className: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4" }) }) : memoizedWorkspaceMetrics.length > 0 ? /* @__PURE__ */ jsx(
28508
+ motion.div,
28509
+ {
28510
+ initial: { opacity: 0, scale: 0.98 },
28511
+ animate: { opacity: 1, scale: 1 },
28512
+ transition: { duration: 0.3 },
28513
+ className: "h-full",
28514
+ children: React19__default.createElement(WorkspaceGrid, {
28515
+ workspaces: memoizedWorkspaceMetrics,
28516
+ lineNames,
28517
+ factoryView: factoryViewId,
28518
+ videoSources,
28519
+ className: "h-full"
28520
+ })
28521
+ },
28522
+ selectedLineId
28523
+ ) : /* @__PURE__ */ jsx(
28524
+ motion.div,
28525
+ {
28526
+ initial: { opacity: 0 },
28527
+ animate: { opacity: 1 },
28528
+ transition: { duration: 0.3 },
28529
+ children: /* @__PURE__ */ jsx(NoWorkspaceData, { message: "No workspace data available. Select another line or check configurations." })
28530
+ }
28531
+ ) })
28532
+ ] })
28533
+ ] }),
28534
+ /* @__PURE__ */ jsx(
28535
+ BreakNotificationPopup,
28536
+ {
28537
+ activeBreaks,
28538
+ lineNames,
28539
+ isVisible: !breaksLoading && !breaksError
28540
+ }
28541
+ )
28542
+ ] })
27477
28543
  }
27478
28544
  );
27479
28545
  }
27480
- var AuthenticatedHomeView = withAuth(React14__default.memo(HomeView));
28546
+ var AuthenticatedHomeView = withAuth(React19__default.memo(HomeView));
27481
28547
  var HomeView_default = HomeView;
27482
28548
 
27483
28549
  // src/views/kpi-detail-view.types.ts
@@ -28310,7 +29376,7 @@ var LineCard = ({ line, onClick }) => {
28310
29376
  const { kpis, isLoading, error } = useLineKPIs({ lineId: line.id });
28311
29377
  const shiftConfig = useShiftConfig();
28312
29378
  const dateTimeConfig = useDateTimeConfig();
28313
- const isOnTrack = React14__default.useMemo(() => {
29379
+ const isOnTrack = React19__default.useMemo(() => {
28314
29380
  if (!kpis) return null;
28315
29381
  const currentTime = /* @__PURE__ */ new Date();
28316
29382
  const timezone = dateTimeConfig.defaultTimezone || "Asia/Kolkata";
@@ -30335,7 +31401,7 @@ var BulkConfigureModal = ({
30335
31401
  },
30336
31402
  className: "w-full rounded-lg border border-gray-300 bg-white px-3 py-2 text-sm\n shadow-sm focus:border-blue-500 focus:ring-blue-500 \n transition-all duration-200 hover:border-blue-400",
30337
31403
  min: "0",
30338
- step: "1",
31404
+ step: "0.01",
30339
31405
  placeholder: "Enter cycle time"
30340
31406
  }
30341
31407
  ),
@@ -30456,6 +31522,343 @@ var BulkConfigureModal = ({
30456
31522
  );
30457
31523
  };
30458
31524
  var BulkConfigureModal_default = BulkConfigureModal;
31525
+ var SKUModal = ({
31526
+ isOpen,
31527
+ onClose,
31528
+ onSave,
31529
+ editingSKU
31530
+ }) => {
31531
+ const config = useDashboardConfig();
31532
+ const defaultProductionTarget = config?.skuConfig?.defaultProductionTarget || 1e3;
31533
+ const [formData, setFormData] = useState({
31534
+ sku_id: "",
31535
+ production_target: defaultProductionTarget,
31536
+ attributes: {}
31537
+ });
31538
+ const [isSaving, setIsSaving] = useState(false);
31539
+ const [error, setError] = useState(null);
31540
+ useEffect(() => {
31541
+ if (editingSKU) {
31542
+ setFormData({
31543
+ sku_id: editingSKU.sku_id,
31544
+ production_target: editingSKU.production_target,
31545
+ attributes: editingSKU.attributes || {}
31546
+ });
31547
+ } else {
31548
+ setFormData({
31549
+ sku_id: "",
31550
+ production_target: defaultProductionTarget,
31551
+ attributes: {}
31552
+ });
31553
+ }
31554
+ setError(null);
31555
+ }, [editingSKU, defaultProductionTarget]);
31556
+ const handleSubmit = async (e) => {
31557
+ e.preventDefault();
31558
+ setError(null);
31559
+ if (!formData.sku_id.trim()) {
31560
+ setError("SKU ID is required");
31561
+ return;
31562
+ }
31563
+ if (formData.production_target <= 0) {
31564
+ setError("Production target must be greater than 0");
31565
+ return;
31566
+ }
31567
+ setIsSaving(true);
31568
+ try {
31569
+ const skuData = {
31570
+ sku_id: formData.sku_id.trim(),
31571
+ production_target: formData.production_target,
31572
+ attributes: formData.attributes,
31573
+ company_id: config?.entityConfig?.companyId || ""
31574
+ };
31575
+ await onSave(skuData);
31576
+ onClose();
31577
+ } catch (err) {
31578
+ setError(err instanceof Error ? err.message : "Failed to save SKU");
31579
+ } finally {
31580
+ setIsSaving(false);
31581
+ }
31582
+ };
31583
+ if (!isOpen) return null;
31584
+ return /* @__PURE__ */ jsx("div", { className: "fixed inset-0 bg-black/50 backdrop-blur-sm flex items-center justify-center z-50 p-4", children: /* @__PURE__ */ jsxs("div", { className: "bg-white rounded-xl shadow-2xl max-w-md w-full transform transition-all", children: [
31585
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between p-6 border-b border-gray-200", children: [
31586
+ /* @__PURE__ */ jsx("h2", { className: "text-xl font-semibold text-gray-900", children: editingSKU ? "Edit SKU" : "Add New SKU" }),
31587
+ /* @__PURE__ */ jsx(
31588
+ "button",
31589
+ {
31590
+ onClick: onClose,
31591
+ className: "text-gray-400 hover:text-gray-600 transition-colors p-1 hover:bg-gray-100 rounded-lg",
31592
+ disabled: isSaving,
31593
+ children: /* @__PURE__ */ jsx(X, { className: "w-5 h-5" })
31594
+ }
31595
+ )
31596
+ ] }),
31597
+ /* @__PURE__ */ jsxs("form", { onSubmit: handleSubmit, className: "p-6", children: [
31598
+ error && /* @__PURE__ */ jsx("div", { className: "mb-4 p-3 bg-red-50 border border-red-200 text-red-700 rounded-lg text-sm", children: error }),
31599
+ /* @__PURE__ */ jsxs("div", { className: "space-y-5", children: [
31600
+ /* @__PURE__ */ jsxs("div", { children: [
31601
+ /* @__PURE__ */ jsxs("label", { htmlFor: "sku_id", className: "block text-sm font-medium text-gray-700 mb-2", children: [
31602
+ "SKU ID ",
31603
+ /* @__PURE__ */ jsx("span", { className: "text-red-500", children: "*" })
31604
+ ] }),
31605
+ /* @__PURE__ */ jsx(
31606
+ "input",
31607
+ {
31608
+ type: "text",
31609
+ id: "sku_id",
31610
+ value: formData.sku_id,
31611
+ onChange: (e) => setFormData({ ...formData, sku_id: e.target.value }),
31612
+ className: "w-full px-4 py-2.5 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all duration-200",
31613
+ placeholder: "Enter SKU ID",
31614
+ disabled: isSaving || !!editingSKU,
31615
+ required: true
31616
+ }
31617
+ )
31618
+ ] }),
31619
+ /* @__PURE__ */ jsxs("div", { children: [
31620
+ /* @__PURE__ */ jsxs("label", { htmlFor: "production_target", className: "block text-sm font-medium text-gray-700 mb-2", children: [
31621
+ "Production Target ",
31622
+ /* @__PURE__ */ jsx("span", { className: "text-red-500", children: "*" })
31623
+ ] }),
31624
+ /* @__PURE__ */ jsx(
31625
+ "input",
31626
+ {
31627
+ type: "number",
31628
+ id: "production_target",
31629
+ value: formData.production_target,
31630
+ onChange: (e) => setFormData({ ...formData, production_target: parseInt(e.target.value) || 0 }),
31631
+ className: "w-full px-4 py-2.5 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all duration-200",
31632
+ placeholder: "Enter production target",
31633
+ min: "1",
31634
+ disabled: isSaving,
31635
+ required: true
31636
+ }
31637
+ ),
31638
+ /* @__PURE__ */ jsx("p", { className: "mt-1.5 text-sm text-gray-500", children: "Units per day for this SKU" })
31639
+ ] }),
31640
+ /* @__PURE__ */ jsxs("div", { children: [
31641
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium text-gray-700 mb-2", children: "Additional Attributes (Optional)" }),
31642
+ /* @__PURE__ */ jsx(
31643
+ "textarea",
31644
+ {
31645
+ value: JSON.stringify(formData.attributes, null, 2),
31646
+ onChange: (e) => {
31647
+ try {
31648
+ const parsed = JSON.parse(e.target.value);
31649
+ setFormData({ ...formData, attributes: parsed });
31650
+ } catch {
31651
+ }
31652
+ },
31653
+ className: "w-full px-4 py-2.5 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent font-mono text-sm transition-all duration-200",
31654
+ rows: 4,
31655
+ placeholder: '{"color": "red", "size": "large"}',
31656
+ disabled: isSaving
31657
+ }
31658
+ ),
31659
+ /* @__PURE__ */ jsx("p", { className: "mt-1.5 text-sm text-gray-500", children: "Enter valid JSON for additional SKU attributes" })
31660
+ ] })
31661
+ ] }),
31662
+ /* @__PURE__ */ jsxs("div", { className: "flex justify-end space-x-3 mt-6 pt-4 border-t border-gray-200", children: [
31663
+ /* @__PURE__ */ jsx(
31664
+ "button",
31665
+ {
31666
+ type: "button",
31667
+ onClick: onClose,
31668
+ className: "px-4 py-2 text-sm font-medium text-gray-700 bg-white border border-gray-300 rounded-lg hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-gray-500 transition-all duration-200",
31669
+ disabled: isSaving,
31670
+ children: "Cancel"
31671
+ }
31672
+ ),
31673
+ /* @__PURE__ */ jsx(
31674
+ "button",
31675
+ {
31676
+ type: "submit",
31677
+ className: "px-4 py-2 text-sm font-medium text-white bg-blue-600 border border-transparent rounded-lg hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 disabled:opacity-50 disabled:cursor-not-allowed transition-all duration-200 shadow-sm",
31678
+ disabled: isSaving,
31679
+ children: isSaving ? "Saving..." : editingSKU ? "Update" : "Create"
31680
+ }
31681
+ )
31682
+ ] })
31683
+ ] })
31684
+ ] }) });
31685
+ };
31686
+ var SKUSelector = ({
31687
+ onSelect,
31688
+ selectedSKU,
31689
+ availableSKUs,
31690
+ className = "",
31691
+ lineId,
31692
+ disabled = false,
31693
+ required = false
31694
+ }) => {
31695
+ const [isOpen, setIsOpen] = useState(false);
31696
+ const [searchTerm, setSearchTerm] = useState("");
31697
+ const dropdownRef = useRef(null);
31698
+ useEffect(() => {
31699
+ const handleClickOutside = (event) => {
31700
+ if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
31701
+ setIsOpen(false);
31702
+ }
31703
+ };
31704
+ document.addEventListener("mousedown", handleClickOutside);
31705
+ return () => {
31706
+ document.removeEventListener("mousedown", handleClickOutside);
31707
+ };
31708
+ }, []);
31709
+ const filteredSKUs = availableSKUs.filter(
31710
+ (sku) => sku.sku_id.toLowerCase().includes(searchTerm.toLowerCase()) || JSON.stringify(sku.attributes).toLowerCase().includes(searchTerm.toLowerCase())
31711
+ );
31712
+ const handleSelect = (sku) => {
31713
+ onSelect(sku);
31714
+ setIsOpen(false);
31715
+ setSearchTerm("");
31716
+ };
31717
+ return /* @__PURE__ */ jsxs("div", { className: `relative ${className}`, ref: dropdownRef, children: [
31718
+ /* @__PURE__ */ jsx(
31719
+ "button",
31720
+ {
31721
+ type: "button",
31722
+ onClick: () => !disabled && setIsOpen(!isOpen),
31723
+ className: `
31724
+ w-full px-3 py-2 text-left bg-white border rounded-md shadow-sm
31725
+ ${disabled ? "bg-gray-100 cursor-not-allowed" : "hover:bg-gray-50 cursor-pointer"}
31726
+ ${required && !selectedSKU ? "border-red-300" : "border-gray-300"}
31727
+ focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500
31728
+ `,
31729
+ disabled,
31730
+ children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
31731
+ /* @__PURE__ */ jsx("span", { className: selectedSKU ? "text-gray-900" : "text-gray-500", children: selectedSKU ? /* @__PURE__ */ jsxs("div", { children: [
31732
+ /* @__PURE__ */ jsx("span", { className: "font-medium", children: selectedSKU.sku_id }),
31733
+ /* @__PURE__ */ jsxs("span", { className: "text-sm text-gray-500 ml-2", children: [
31734
+ "(Target: ",
31735
+ selectedSKU.production_target,
31736
+ " units/day)"
31737
+ ] })
31738
+ ] }) : "Select SKU" }),
31739
+ /* @__PURE__ */ jsx(ChevronDown, { className: `w-4 h-4 text-gray-400 transition-transform ${isOpen ? "rotate-180" : ""}` })
31740
+ ] })
31741
+ }
31742
+ ),
31743
+ isOpen && /* @__PURE__ */ jsxs("div", { className: "absolute z-10 w-full mt-1 bg-white border border-gray-300 rounded-md shadow-lg", children: [
31744
+ /* @__PURE__ */ jsx("div", { className: "p-2 border-b", children: /* @__PURE__ */ jsxs("div", { className: "relative", children: [
31745
+ /* @__PURE__ */ jsx(Search, { className: "absolute left-3 top-1/2 transform -translate-y-1/2 w-4 h-4 text-gray-400" }),
31746
+ /* @__PURE__ */ jsx(
31747
+ "input",
31748
+ {
31749
+ type: "text",
31750
+ value: searchTerm,
31751
+ onChange: (e) => setSearchTerm(e.target.value),
31752
+ placeholder: "Search SKUs...",
31753
+ className: "w-full pl-9 pr-3 py-2 text-sm border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500",
31754
+ onClick: (e) => e.stopPropagation()
31755
+ }
31756
+ )
31757
+ ] }) }),
31758
+ /* @__PURE__ */ jsxs("div", { className: "max-h-60 overflow-y-auto", children: [
31759
+ !required && /* @__PURE__ */ jsx(
31760
+ "button",
31761
+ {
31762
+ onClick: () => handleSelect(null),
31763
+ className: "w-full px-3 py-2 text-left text-sm hover:bg-gray-100 focus:outline-none focus:bg-gray-100",
31764
+ children: /* @__PURE__ */ jsx("span", { className: "text-gray-500", children: "No SKU" })
31765
+ }
31766
+ ),
31767
+ filteredSKUs.length === 0 ? /* @__PURE__ */ jsx("div", { className: "px-3 py-2 text-sm text-gray-500", children: "No SKUs found" }) : filteredSKUs.map((sku) => /* @__PURE__ */ jsx(
31768
+ "button",
31769
+ {
31770
+ onClick: () => handleSelect(sku),
31771
+ className: `
31772
+ w-full px-3 py-2 text-left text-sm hover:bg-gray-100 focus:outline-none focus:bg-gray-100
31773
+ ${selectedSKU?.id === sku.id ? "bg-blue-50" : ""}
31774
+ `,
31775
+ children: /* @__PURE__ */ jsxs("div", { children: [
31776
+ /* @__PURE__ */ jsx("div", { className: "font-medium", children: sku.sku_id }),
31777
+ /* @__PURE__ */ jsxs("div", { className: "text-xs text-gray-500", children: [
31778
+ "Target: ",
31779
+ sku.production_target,
31780
+ " units/day",
31781
+ Object.keys(sku.attributes || {}).length > 0 && /* @__PURE__ */ jsxs("span", { className: "ml-2", children: [
31782
+ "\u2022 ",
31783
+ Object.entries(sku.attributes).map(([key, value]) => `${key}: ${value}`).join(", ")
31784
+ ] })
31785
+ ] })
31786
+ ] })
31787
+ },
31788
+ sku.id
31789
+ ))
31790
+ ] })
31791
+ ] })
31792
+ ] });
31793
+ };
31794
+ var SKUList = ({
31795
+ skus,
31796
+ onEdit,
31797
+ onDelete,
31798
+ isLoading = false
31799
+ }) => {
31800
+ if (isLoading) {
31801
+ return /* @__PURE__ */ jsx("div", { className: "bg-white rounded-xl shadow-sm border border-gray-200 p-8", children: /* @__PURE__ */ jsxs("div", { className: "flex justify-center items-center", children: [
31802
+ /* @__PURE__ */ jsx("div", { className: "animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600" }),
31803
+ /* @__PURE__ */ jsx("span", { className: "ml-3 text-gray-600", children: "Loading SKUs..." })
31804
+ ] }) });
31805
+ }
31806
+ if (skus.length === 0) {
31807
+ return /* @__PURE__ */ jsx("div", { className: "bg-white rounded-xl shadow-sm border border-gray-200 p-12", children: /* @__PURE__ */ jsxs("div", { className: "text-center", children: [
31808
+ /* @__PURE__ */ jsx(Package, { className: "mx-auto h-12 w-12 text-gray-400" }),
31809
+ /* @__PURE__ */ jsx("h3", { className: "mt-2 text-lg font-medium text-gray-900", children: "No SKUs found" }),
31810
+ /* @__PURE__ */ jsx("p", { className: "mt-1 text-sm text-gray-500", children: "Get started by creating a new SKU for production planning." })
31811
+ ] }) });
31812
+ }
31813
+ return /* @__PURE__ */ jsx("div", { className: "bg-white rounded-xl shadow-sm border border-gray-200 overflow-hidden", children: /* @__PURE__ */ jsx("div", { className: "overflow-x-auto", children: /* @__PURE__ */ jsxs("table", { className: "min-w-full divide-y divide-gray-200", children: [
31814
+ /* @__PURE__ */ jsx("thead", { className: "bg-gray-50", children: /* @__PURE__ */ jsxs("tr", { children: [
31815
+ /* @__PURE__ */ jsx("th", { scope: "col", className: "px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider", children: "SKU ID" }),
31816
+ /* @__PURE__ */ jsx("th", { scope: "col", className: "px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider", children: "Production Target" }),
31817
+ /* @__PURE__ */ jsx("th", { scope: "col", className: "px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider", children: "Attributes" }),
31818
+ /* @__PURE__ */ jsx("th", { scope: "col", className: "px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider", children: "Status" }),
31819
+ /* @__PURE__ */ jsx("th", { scope: "col", className: "px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider", children: "Created" }),
31820
+ /* @__PURE__ */ jsx("th", { scope: "col", className: "relative px-6 py-3", children: /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Actions" }) })
31821
+ ] }) }),
31822
+ /* @__PURE__ */ jsx("tbody", { className: "bg-white divide-y divide-gray-200", children: skus.map((sku) => /* @__PURE__ */ jsxs("tr", { className: "hover:bg-gray-50 transition-colors duration-150", children: [
31823
+ /* @__PURE__ */ jsx("td", { className: "px-6 py-4 whitespace-nowrap", children: /* @__PURE__ */ jsx("div", { className: "text-sm font-semibold text-gray-900", children: sku.sku_id }) }),
31824
+ /* @__PURE__ */ jsx("td", { className: "px-6 py-4 whitespace-nowrap", children: /* @__PURE__ */ jsxs("div", { className: "text-sm font-medium text-gray-700", children: [
31825
+ sku.production_target.toLocaleString(),
31826
+ " units/day"
31827
+ ] }) }),
31828
+ /* @__PURE__ */ jsx("td", { className: "px-6 py-4", children: /* @__PURE__ */ jsx("div", { className: "text-sm text-gray-500", children: Object.keys(sku.attributes || {}).length === 0 ? /* @__PURE__ */ jsx("span", { className: "text-gray-400", children: "No attributes" }) : /* @__PURE__ */ jsx("div", { className: "max-w-xs truncate", children: Object.entries(sku.attributes).map(([key, value], index) => /* @__PURE__ */ jsxs("span", { children: [
31829
+ index > 0 && ", ",
31830
+ /* @__PURE__ */ jsxs("span", { className: "font-medium", children: [
31831
+ key,
31832
+ ":"
31833
+ ] }),
31834
+ " ",
31835
+ String(value)
31836
+ ] }, key)) }) }) }),
31837
+ /* @__PURE__ */ jsx("td", { className: "px-6 py-4 whitespace-nowrap", children: /* @__PURE__ */ jsx("span", { className: `inline-flex px-2 py-1 text-xs font-semibold rounded-full ${sku.is_active ? "bg-green-100 text-green-800" : "bg-gray-100 text-gray-800"}`, children: sku.is_active ? "Active" : "Inactive" }) }),
31838
+ /* @__PURE__ */ jsx("td", { className: "px-6 py-4 whitespace-nowrap text-sm text-gray-500", children: new Date(sku.created_at).toLocaleDateString() }),
31839
+ /* @__PURE__ */ jsxs("td", { className: "px-6 py-4 whitespace-nowrap text-right text-sm font-medium", children: [
31840
+ /* @__PURE__ */ jsx(
31841
+ "button",
31842
+ {
31843
+ onClick: () => onEdit(sku),
31844
+ className: "text-blue-600 hover:text-blue-800 mr-3 transition-colors duration-150 p-1 hover:bg-blue-50 rounded",
31845
+ title: "Edit SKU",
31846
+ children: /* @__PURE__ */ jsx(Edit2, { className: "w-4 h-4" })
31847
+ }
31848
+ ),
31849
+ /* @__PURE__ */ jsx(
31850
+ "button",
31851
+ {
31852
+ onClick: () => onDelete(sku),
31853
+ className: "text-red-600 hover:text-red-800 transition-colors duration-150 p-1 hover:bg-red-50 rounded",
31854
+ title: "Delete SKU",
31855
+ children: /* @__PURE__ */ jsx(Trash2, { className: "w-4 h-4" })
31856
+ }
31857
+ )
31858
+ ] })
31859
+ ] }, sku.id)) })
31860
+ ] }) }) });
31861
+ };
30459
31862
  var TargetsViewUI = ({
30460
31863
  isLoading,
30461
31864
  lineWorkspaces,
@@ -30474,7 +31877,12 @@ var TargetsViewUI = ({
30474
31877
  onShiftChange,
30475
31878
  onSaveLine,
30476
31879
  onToggleBulkConfigure,
30477
- onBulkConfigure
31880
+ onBulkConfigure,
31881
+ // SKU props
31882
+ skuEnabled = false,
31883
+ skus = [],
31884
+ onUpdateSelectedSKU,
31885
+ skuRequired = false
30478
31886
  }) => {
30479
31887
  if (isLoading) {
30480
31888
  return /* @__PURE__ */ jsx("div", { className: "flex h-screen bg-gray-50", children: /* @__PURE__ */ jsx("div", { className: "flex-1 flex items-center justify-center", children: /* @__PURE__ */ jsx(Loader2, { className: "w-8 h-8 animate-spin text-blue-600" }) }) });
@@ -30590,6 +31998,26 @@ var TargetsViewUI = ({
30590
31998
  ] })
30591
31999
  ] }) }),
30592
32000
  line.isOpen && /* @__PURE__ */ jsxs("div", { id: `line-${lineId}-content`, className: "border-t border-gray-200", children: [
32001
+ skuEnabled && /* @__PURE__ */ jsx("div", { className: "px-6 py-4 border-b border-gray-200 bg-gray-50/50", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-4", children: [
32002
+ /* @__PURE__ */ jsx("label", { htmlFor: `sku-${lineId}`, className: "text-sm font-medium text-gray-700", children: "Select SKU:" }),
32003
+ /* @__PURE__ */ jsx("div", { className: "flex-1 max-w-md", children: /* @__PURE__ */ jsx(
32004
+ SKUSelector,
32005
+ {
32006
+ onSelect: (sku) => onUpdateSelectedSKU?.(lineId, sku),
32007
+ selectedSKU: line.selectedSKU || null,
32008
+ availableSKUs: skus,
32009
+ lineId,
32010
+ required: skuRequired,
32011
+ className: "w-full"
32012
+ }
32013
+ ) }),
32014
+ line.selectedSKU && /* @__PURE__ */ jsxs("div", { className: "text-sm text-gray-600", children: [
32015
+ /* @__PURE__ */ jsx("span", { className: "font-medium", children: "Production Target:" }),
32016
+ " ",
32017
+ line.selectedSKU.production_target.toLocaleString(),
32018
+ " units/day"
32019
+ ] })
32020
+ ] }) }),
30593
32021
  /* @__PURE__ */ jsx("div", { className: "px-6 py-3 bg-gray-50 border-b border-gray-200", children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-12 gap-6 text-sm font-medium text-gray-600", children: [
30594
32022
  /* @__PURE__ */ jsx("div", { className: "col-span-2", children: "Workspace" }),
30595
32023
  /* @__PURE__ */ jsx("div", { className: "col-span-2", children: "Action Type" }),
@@ -30636,7 +32064,7 @@ var TargetsViewUI = ({
30636
32064
  onChange: (e) => onUpdateWorkspaceTarget(lineId, workspace.id, "targetCycleTime", Number(e.target.value) || ""),
30637
32065
  className: "block w-full rounded-lg border border-gray-300 bg-white px-3 py-2 text-sm\n shadow-sm focus:border-blue-500 focus:ring-blue-500 \n transition-all duration-200 hover:border-gray-400",
30638
32066
  min: "0",
30639
- step: "1",
32067
+ step: "0.01",
30640
32068
  placeholder: "Enter cycle time"
30641
32069
  }
30642
32070
  ) }),
@@ -30727,6 +32155,9 @@ var TargetsView = ({
30727
32155
  const supabase = useSupabase();
30728
32156
  const auth = useAuth();
30729
32157
  userId || auth?.user?.id;
32158
+ const dashboardConfig = useDashboardConfig();
32159
+ const { skus, isLoading: skusLoading } = useSKUs(companyId);
32160
+ const skuEnabled = dashboardConfig?.skuConfig?.enabled || false;
30730
32161
  useEffect(() => {
30731
32162
  const fetchLineDetails = async () => {
30732
32163
  if (!supabase || lineIds.length === 0) return;
@@ -31094,6 +32525,41 @@ var TargetsView = ({
31094
32525
  }
31095
32526
  }));
31096
32527
  };
32528
+ const updateSelectedSKU = (lineId, sku) => {
32529
+ setLineWorkspaces((prev) => ({
32530
+ ...prev,
32531
+ [lineId]: {
32532
+ ...prev[lineId],
32533
+ selectedSKU: sku,
32534
+ productId: sku?.sku_id || prev[lineId].productId
32535
+ // Update productId with SKU ID
32536
+ }
32537
+ }));
32538
+ if (sku && sku.production_target > 0) {
32539
+ const lineData = lineWorkspaces[lineId];
32540
+ const workspaceCount = lineData.workspaces.length;
32541
+ if (workspaceCount > 0) {
32542
+ const targetPerWorkspace = Math.floor(sku.production_target / workspaceCount);
32543
+ const pphPerWorkspace = calculatePPH(
32544
+ lineData.shiftHours > 0 ? lineData.shiftHours * 3600 / targetPerWorkspace : 0,
32545
+ lineData.breaks,
32546
+ lineData.shiftHours
32547
+ );
32548
+ setLineWorkspaces((prev) => ({
32549
+ ...prev,
32550
+ [lineId]: {
32551
+ ...prev[lineId],
32552
+ workspaces: prev[lineId].workspaces.map((ws) => ({
32553
+ ...ws,
32554
+ targetDayOutput: targetPerWorkspace,
32555
+ targetPPH: pphPerWorkspace,
32556
+ targetCycleTime: lineData.shiftHours > 0 ? parseFloat((lineData.shiftHours * 3600 / targetPerWorkspace).toFixed(2)) : ""
32557
+ }))
32558
+ }
32559
+ }));
32560
+ }
32561
+ }
32562
+ };
31097
32563
  const updateWorkspaceTarget = (lineId, workspaceId, field, value) => {
31098
32564
  setLineWorkspaces((prev) => {
31099
32565
  const shiftHours = prev[lineId].shiftHours;
@@ -31226,6 +32692,11 @@ var TargetsView = ({
31226
32692
  return;
31227
32693
  }
31228
32694
  console.log(`[handleSaveLine] factoryId for ${lineId}: ${lineDataToSave.factoryId}`);
32695
+ if (skuEnabled && dashboardConfig?.skuConfig?.requireSKUSelection && !lineDataToSave.selectedSKU) {
32696
+ console.log(`[handleSaveLine] Exiting: SKU selection required but not selected for lineId: ${lineId}`);
32697
+ toast.error("Please select a SKU before saving.");
32698
+ return;
32699
+ }
31229
32700
  const currentFactoryId = lineDataToSave.factoryId;
31230
32701
  const currentDate = getOperationalDate();
31231
32702
  console.log(`[handleSaveLine] currentDate: ${currentDate}, selectedShift: ${selectedShift}`);
@@ -31239,8 +32710,9 @@ var TargetsView = ({
31239
32710
  ideal_cycle_time: Number(ws.targetCycleTime) || 0,
31240
32711
  total_day_output: Number(ws.targetDayOutput) || 0,
31241
32712
  action_name: ws.actionType === "assembly" ? ACTION_NAMES.ASSEMBLY : ACTION_NAMES.PACKAGING,
31242
- updated_by: currentEffectiveUserId
32713
+ updated_by: currentEffectiveUserId,
31243
32714
  // Use the potentially hardcoded ID
32715
+ ...skuEnabled && lineDataToSave.selectedSKU ? { sku_id: lineDataToSave.selectedSKU.id } : {}
31244
32716
  }));
31245
32717
  console.log(`[handleSaveLine] workspaceThresholdUpdates for ${lineId}:`, workspaceThresholdUpdates);
31246
32718
  await workspaceService.updateActionThresholds(workspaceThresholdUpdates);
@@ -31252,7 +32724,8 @@ var TargetsView = ({
31252
32724
  shift_id: selectedShift,
31253
32725
  product_code: lineDataToSave.productId,
31254
32726
  threshold_day_output: lineDataToSave.workspaces.reduce((acc, ws) => acc + (Number(ws.targetDayOutput) || 0), 0),
31255
- threshold_pph: lineDataToSave.workspaces.reduce((acc, ws) => acc + (Number(ws.targetPPH) || 0), 0)
32727
+ threshold_pph: lineDataToSave.workspaces.reduce((acc, ws) => acc + (Number(ws.targetPPH) || 0), 0),
32728
+ ...skuEnabled && lineDataToSave.selectedSKU ? { sku_id: lineDataToSave.selectedSKU.id } : {}
31256
32729
  };
31257
32730
  console.log(`[handleSaveLine] lineThresholdData for upsert on ${lineId}:`, lineThresholdData);
31258
32731
  const { error: lineUpsertError } = await supabase.from("line_thresholds").upsert(lineThresholdData, { onConflict: "factory_id,line_id,date,shift_id" });
@@ -31347,7 +32820,7 @@ var TargetsView = ({
31347
32820
  return /* @__PURE__ */ jsx(
31348
32821
  TargetsViewUI_default,
31349
32822
  {
31350
- isLoading,
32823
+ isLoading: isLoading || skusLoading,
31351
32824
  lineWorkspaces,
31352
32825
  lineNames,
31353
32826
  savingLines,
@@ -31364,7 +32837,11 @@ var TargetsView = ({
31364
32837
  onShiftChange: handleShiftChange,
31365
32838
  onSaveLine: handleSaveLine,
31366
32839
  onToggleBulkConfigure: handleToggleBulkConfigure,
31367
- onBulkConfigure: handleBulkConfigure
32840
+ onBulkConfigure: handleBulkConfigure,
32841
+ skuEnabled,
32842
+ skus,
32843
+ onUpdateSelectedSKU: updateSelectedSKU,
32844
+ skuRequired: dashboardConfig?.skuConfig?.requireSKUSelection || false
31368
32845
  }
31369
32846
  );
31370
32847
  };
@@ -31623,7 +33100,43 @@ var WorkspaceDetailView = ({
31623
33100
  }
31624
33101
  };
31625
33102
  if (loading) {
31626
- return /* @__PURE__ */ jsx("div", { className: "min-h-screen flex items-center justify-center bg-slate-50", children: /* @__PURE__ */ jsx("div", { className: "text-xl text-gray-600", children: "Loading workspace details..." }) });
33103
+ return /* @__PURE__ */ jsx(
33104
+ motion.div,
33105
+ {
33106
+ className: "min-h-screen bg-slate-50",
33107
+ initial: { opacity: 0 },
33108
+ animate: { opacity: 1 },
33109
+ transition: { duration: 0.3 },
33110
+ children: /* @__PURE__ */ jsxs("div", { className: "min-h-screen w-full flex flex-col bg-slate-50", children: [
33111
+ /* @__PURE__ */ jsx("header", { className: "sticky top-0 z-10 px-2 sm:px-2.5 lg:px-3 py-1.5 sm:py-2 lg:py-3 flex flex-col shadow-sm bg-white", children: /* @__PURE__ */ jsxs("div", { className: "relative flex items-center", children: [
33112
+ /* @__PURE__ */ jsx("div", { className: "absolute left-0 animate-pulse", children: /* @__PURE__ */ jsx("div", { className: "h-8 w-20 bg-gray-200 rounded" }) }),
33113
+ /* @__PURE__ */ jsx("div", { className: "absolute left-1/2 transform -translate-x-1/2 animate-pulse", children: /* @__PURE__ */ jsx("div", { className: "h-6 w-40 bg-gray-200 rounded" }) }),
33114
+ /* @__PURE__ */ jsx("div", { className: "w-full h-8" })
33115
+ ] }) }),
33116
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 p-4 sm:p-6 lg:p-8", children: [
33117
+ /* @__PURE__ */ jsx("div", { className: "mb-6", children: /* @__PURE__ */ jsxs("div", { className: "flex space-x-4 justify-center animate-pulse", children: [
33118
+ /* @__PURE__ */ jsx("div", { className: "h-10 w-32 bg-gray-200 rounded-lg" }),
33119
+ /* @__PURE__ */ jsx("div", { className: "h-10 w-32 bg-gray-200 rounded-lg" }),
33120
+ /* @__PURE__ */ jsx("div", { className: "h-10 w-32 bg-gray-200 rounded-lg" })
33121
+ ] }) }),
33122
+ /* @__PURE__ */ jsx("div", { className: "grid grid-cols-2 md:grid-cols-4 gap-4 mb-6", children: [1, 2, 3, 4].map((i) => /* @__PURE__ */ jsx("div", { className: "bg-white rounded-lg p-4 shadow-sm", children: /* @__PURE__ */ jsxs("div", { className: "animate-pulse", children: [
33123
+ /* @__PURE__ */ jsx("div", { className: "h-4 w-20 bg-gray-200 rounded mb-2" }),
33124
+ /* @__PURE__ */ jsx("div", { className: "h-8 w-16 bg-gray-200 rounded" })
33125
+ ] }) }, i)) }),
33126
+ /* @__PURE__ */ jsx("div", { className: "bg-white rounded-lg p-6 shadow-sm", children: /* @__PURE__ */ jsxs("div", { className: "animate-pulse", children: [
33127
+ /* @__PURE__ */ jsx("div", { className: "h-6 w-40 bg-gray-200 rounded mb-4" }),
33128
+ /* @__PURE__ */ jsx("div", { className: "h-64 bg-gray-100 rounded relative overflow-hidden", children: /* @__PURE__ */ jsx("div", { className: "absolute inset-0 flex items-center justify-center", children: /* @__PURE__ */ jsxs("div", { className: "bg-white/80 rounded-lg p-4 shadow-sm", children: [
33129
+ /* @__PURE__ */ jsxs("svg", { className: "animate-spin h-8 w-8 text-blue-500", xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", children: [
33130
+ /* @__PURE__ */ jsx("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }),
33131
+ /* @__PURE__ */ jsx("path", { className: "opacity-75", fill: "currentColor", d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" })
33132
+ ] }),
33133
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-gray-600 mt-2", children: "Loading chart data..." })
33134
+ ] }) }) })
33135
+ ] }) })
33136
+ ] })
33137
+ ] })
33138
+ }
33139
+ );
31627
33140
  }
31628
33141
  if (error) {
31629
33142
  return /* @__PURE__ */ jsxs("div", { className: "min-h-screen p-8 bg-slate-50", children: [
@@ -32063,6 +33576,144 @@ var WorkspaceDetailView = ({
32063
33576
  };
32064
33577
  var WrappedComponent = withAuth(WorkspaceDetailView);
32065
33578
  var WorkspaceDetailView_default = WrappedComponent;
33579
+ var SKUManagementView = () => {
33580
+ const config = useDashboardConfig();
33581
+ const companyId = config?.entityConfig?.companyId || "";
33582
+ const router = useRouter();
33583
+ const { skus, isLoading, error, refetch } = useSKUs(companyId);
33584
+ const [isModalOpen, setIsModalOpen] = useState(false);
33585
+ const [editingSKU, setEditingSKU] = useState(null);
33586
+ const [deleteConfirmSKU, setDeleteConfirmSKU] = useState(null);
33587
+ useEffect(() => {
33588
+ trackCoreEvent("SKU Management Page Viewed");
33589
+ }, []);
33590
+ const handleCreateOrUpdate = async (skuData) => {
33591
+ try {
33592
+ if (editingSKU) {
33593
+ await skuService.updateSKU(editingSKU.id, {
33594
+ production_target: skuData.production_target,
33595
+ attributes: skuData.attributes
33596
+ });
33597
+ trackCoreEvent("SKU Updated", {
33598
+ sku_id: editingSKU.sku_id,
33599
+ production_target: skuData.production_target
33600
+ });
33601
+ } else {
33602
+ const exists = await skuService.checkSKUExists(companyId, skuData.sku_id);
33603
+ if (exists) {
33604
+ throw new Error("SKU ID already exists");
33605
+ }
33606
+ await skuService.createSKU(skuData);
33607
+ trackCoreEvent("SKU Created", {
33608
+ sku_id: skuData.sku_id,
33609
+ production_target: skuData.production_target
33610
+ });
33611
+ }
33612
+ setIsModalOpen(false);
33613
+ setEditingSKU(null);
33614
+ refetch();
33615
+ } catch (error2) {
33616
+ console.error("Error saving SKU:", error2);
33617
+ throw error2;
33618
+ }
33619
+ };
33620
+ const handleEdit = (sku) => {
33621
+ setEditingSKU(sku);
33622
+ setIsModalOpen(true);
33623
+ };
33624
+ const handleDelete = async (sku) => {
33625
+ if (deleteConfirmSKU?.id === sku.id) {
33626
+ try {
33627
+ await skuService.deleteSKU(sku.id);
33628
+ trackCoreEvent("SKU Deleted", { sku_id: sku.sku_id });
33629
+ setDeleteConfirmSKU(null);
33630
+ refetch();
33631
+ } catch (error2) {
33632
+ console.error("Error deleting SKU:", error2);
33633
+ }
33634
+ } else {
33635
+ setDeleteConfirmSKU(sku);
33636
+ setTimeout(() => setDeleteConfirmSKU(null), 3e3);
33637
+ }
33638
+ };
33639
+ const handleAddNew = () => {
33640
+ setEditingSKU(null);
33641
+ setIsModalOpen(true);
33642
+ };
33643
+ const handleBack = () => {
33644
+ router.push("/");
33645
+ };
33646
+ if (!config?.skuConfig?.enabled) {
33647
+ return /* @__PURE__ */ jsx("div", { className: "min-h-screen bg-slate-50 flex items-center justify-center", children: /* @__PURE__ */ jsxs("div", { className: "text-center", children: [
33648
+ /* @__PURE__ */ jsx(Package, { className: "mx-auto h-12 w-12 text-gray-400" }),
33649
+ /* @__PURE__ */ jsx("h3", { className: "mt-2 text-sm font-medium text-gray-900", children: "SKU Management Disabled" }),
33650
+ /* @__PURE__ */ jsx("p", { className: "mt-1 text-sm text-gray-500", children: "SKU management is not enabled for this workspace." })
33651
+ ] }) });
33652
+ }
33653
+ return /* @__PURE__ */ jsxs("div", { className: "min-h-screen bg-slate-50", children: [
33654
+ /* @__PURE__ */ jsx("div", { className: "sticky top-0 z-10 bg-white border-b border-gray-200/80 shadow-sm", children: /* @__PURE__ */ jsx("div", { className: "px-4 sm:px-8 py-4", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center relative", children: [
33655
+ /* @__PURE__ */ jsxs(
33656
+ "button",
33657
+ {
33658
+ onClick: handleBack,
33659
+ className: "absolute left-0 flex items-center gap-2 text-gray-600 hover:text-gray-900 transition-colors",
33660
+ children: [
33661
+ /* @__PURE__ */ jsx(ArrowLeft, { className: "h-5 w-5" }),
33662
+ /* @__PURE__ */ jsx("span", { children: "Back" })
33663
+ ]
33664
+ }
33665
+ ),
33666
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 text-center mx-auto", children: [
33667
+ /* @__PURE__ */ jsx("h1", { className: "text-2xl font-semibold text-gray-900", children: "SKU Management" }),
33668
+ /* @__PURE__ */ jsx("p", { className: "mt-1 text-sm text-gray-500", children: "Manage Stock Keeping Units (SKUs) for production planning" })
33669
+ ] }),
33670
+ /* @__PURE__ */ jsxs(
33671
+ "button",
33672
+ {
33673
+ onClick: handleAddNew,
33674
+ className: "absolute right-0 inline-flex items-center px-4 py-2 bg-blue-600 text-white text-sm font-medium rounded-lg hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 transition-all duration-200 shadow-sm",
33675
+ children: [
33676
+ /* @__PURE__ */ jsx(Plus, { className: "w-4 h-4 mr-2" }),
33677
+ "Add SKU"
33678
+ ]
33679
+ }
33680
+ )
33681
+ ] }) }) }),
33682
+ /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-auto", children: /* @__PURE__ */ jsxs("div", { className: "px-4 sm:px-8 py-6", children: [
33683
+ /* @__PURE__ */ jsx("div", { className: "mb-6 bg-gradient-to-r from-blue-50 to-blue-50/50 p-4 rounded-xl border border-blue-100", children: /* @__PURE__ */ jsx("p", { className: "text-sm text-blue-700 font-medium", children: "Create and manage SKUs with production targets. These will be available for selection in the production targets page." }) }),
33684
+ error ? /* @__PURE__ */ jsxs("div", { className: "bg-red-50 border border-red-200 text-red-700 p-4 rounded-lg", children: [
33685
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-medium", children: "Error loading SKUs" }),
33686
+ /* @__PURE__ */ jsx("p", { className: "text-sm mt-1", children: error.message })
33687
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
33688
+ /* @__PURE__ */ jsx(
33689
+ SKUList,
33690
+ {
33691
+ skus,
33692
+ onEdit: handleEdit,
33693
+ onDelete: handleDelete,
33694
+ isLoading
33695
+ }
33696
+ ),
33697
+ deleteConfirmSKU && /* @__PURE__ */ jsx("div", { className: "mt-4 bg-yellow-50 border border-yellow-200 text-yellow-800 p-4 rounded-lg", children: /* @__PURE__ */ jsxs("p", { className: "text-sm", children: [
33698
+ "Click delete again to confirm deletion of SKU: ",
33699
+ /* @__PURE__ */ jsx("strong", { children: deleteConfirmSKU.sku_id })
33700
+ ] }) })
33701
+ ] })
33702
+ ] }) }),
33703
+ /* @__PURE__ */ jsx(
33704
+ SKUModal,
33705
+ {
33706
+ isOpen: isModalOpen,
33707
+ onClose: () => {
33708
+ setIsModalOpen(false);
33709
+ setEditingSKU(null);
33710
+ },
33711
+ onSave: handleCreateOrUpdate,
33712
+ editingSKU
33713
+ }
33714
+ )
33715
+ ] });
33716
+ };
32066
33717
  var S3Service = class {
32067
33718
  constructor(config) {
32068
33719
  this.s3Client = null;
@@ -32301,4 +33952,4 @@ var S3Service = class {
32301
33952
  }
32302
33953
  };
32303
33954
 
32304
- export { ACTION_NAMES, AIAgentView_default as AIAgentView, AuthCallback, AuthCallbackView_default as AuthCallbackView, AuthProvider, AuthenticatedFactoryView, AuthenticatedHelpView, AuthenticatedHomeView, AuthenticatedTargetsView, BarChart, BaseHistoryCalendar, BottlenecksContent, BreakNotificationPopup, Card2 as Card, CardContent2 as CardContent, CardDescription2 as CardDescription, CardFooter2 as CardFooter, CardHeader2 as CardHeader, CardTitle2 as CardTitle, 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, EmptyStateMessage, FactoryView_default as FactoryView, GaugeChart, GridComponentsPlaceholder, Header, HelpView_default as HelpView, HomeView_default as HomeView, HourlyOutputChart2 as HourlyOutputChart, ISTTimer_default as ISTTimer, 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, LiveTimer, LoadingOverlay_default as LoadingOverlay, LoadingPage_default as LoadingPage, LoadingSpinner_default as LoadingSpinner, LoginPage, LoginView_default as LoginView, MainLayout, MetricCard_default as MetricCard, NoWorkspaceData, OptifyeAgentClient, OutputProgressChart, PageHeader, PieChart4 as PieChart, ProfileView_default as ProfileView, RegistryProvider, S3Service, SOPComplianceChart, SSEChatClient, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, ShiftDisplay_default as ShiftDisplay, ShiftsView_default as ShiftsView, SideNavBar, SingleVideoStream_default as SingleVideoStream, Skeleton, SlackAPI, SupabaseProvider, TargetWorkspaceGrid, TargetsView_default as TargetsView, ThreadSidebar, TimeDisplay_default as TimeDisplay, TimePickerDropdown, VideoCard, VideoGridView, VideoPreloader, WORKSPACE_POSITIONS, WhatsAppShareButton, WorkspaceCard, WorkspaceDetailView_default as WorkspaceDetailView, WorkspaceDisplayNameExample, WorkspaceGrid, WorkspaceGridItem, WorkspaceHistoryCalendar, WorkspaceMetricCards, WorkspaceMonthlyDataFetcher, WorkspaceMonthlyPdfGenerator, WorkspacePdfExportButton, WorkspacePdfGenerator, WorkspaceWhatsAppShareButton, actionService, apiUtils, authCoreService, authOTPService, authRateLimitService, checkRateLimit2 as checkRateLimit, clearAllRateLimits2 as clearAllRateLimits, clearRateLimit2 as clearRateLimit, clearS3VideoCache, clearS3VideoFromCache, clearWorkspaceDisplayNamesCache, cn, createStreamProxyHandler, createSupabaseClient, createThrottledReload, dashboardService, deleteThread, forceRefreshWorkspaceDisplayNames, formatDateInZone, formatDateTimeInZone, formatISTDate, formatIdleTime, formatTimeInZone, fromUrlFriendlyName, getAllThreadMessages, getAllWorkspaceDisplayNamesAsync, getAnonClient, getCameraNumber, getCompanyMetricsTableName, getConfigurableShortWorkspaceDisplayName, getConfigurableWorkspaceDisplayName, getCurrentShift, getCurrentTimeInZone, getDashboardHeaderTimeInZone, getDaysDifferenceInZone, getDefaultCameraStreamUrl, getDefaultTabForWorkspace, getManufacturingInsights, getMetricsTablePrefix, getOperationalDate, getS3SignedUrl, getS3VideoSrc, getShortWorkspaceDisplayName, getShortWorkspaceDisplayNameAsync, getStoredWorkspaceMappings, getThreadMessages, getUserThreads, getUserThreadsPaginated, getWorkspaceDisplayName, getWorkspaceDisplayNameAsync, getWorkspaceDisplayNamesMap, getWorkspaceFromUrl, getWorkspaceNavigationParams, identifyCoreUser, initializeCoreMixpanel, isTransitionPeriod, isValidLineInfoPayload, isValidWorkspaceDetailedMetricsPayload, isValidWorkspaceMetricsPayload, isWorkspaceDisplayNamesLoaded, isWorkspaceDisplayNamesLoading, mergeWithDefaultConfig, optifyeAgentClient, preInitializeWorkspaceDisplayNames, preloadS3Video, preloadS3VideoUrl, preloadS3VideosUrl, preloadVideoUrl, preloadVideosUrl, qualityService, realtimeService, refreshWorkspaceDisplayNames, resetCoreMixpanel, s3VideoPreloader, storeWorkspaceMapping, streamProxyConfig, throttledReloadDashboard, toUrlFriendlyName, trackCoreEvent, trackCorePageView, updateThreadTitle, useActiveBreaks, useAllWorkspaceMetrics, useAnalyticsConfig, useAuth, useAuthConfig, useComponentOverride, useCustomConfig, useDashboardConfig, useDashboardMetrics, useDatabaseConfig, useDateFormatter, useDateTimeConfig, useEndpointsConfig, useEntityConfig, useFactoryOverviewMetrics, useFeatureFlags, useFormatNumber, useHistoricWorkspaceMetrics, useHlsStream, useHlsStreamWithCropping, useHookOverride, useLeaderboardMetrics, useLineDetailedMetrics, useLineKPIs, useLineMetrics, useLineWorkspaceMetrics, useMessages, useMetrics, useNavigation, useOverrides, usePageOverride, useRealtimeLineMetrics, useRegistry, useShiftConfig, useShifts, useSupabase, useSupabaseClient, useTargets, useTheme, useThemeConfig, useThreads, useVideoConfig, useWorkspaceConfig, useWorkspaceDetailedMetrics, useWorkspaceDisplayName, useWorkspaceDisplayNames, useWorkspaceDisplayNamesMap, useWorkspaceMetrics, useWorkspaceNavigation, useWorkspaceOperators, videoPreloader, whatsappService, withAuth, withRegistry, workspaceService };
33955
+ export { ACTION_NAMES, AIAgentView_default as AIAgentView, AuthCallback, AuthCallbackView_default as AuthCallbackView, AuthProvider, AuthenticatedFactoryView, AuthenticatedHelpView, AuthenticatedHomeView, AuthenticatedTargetsView, BarChart, BaseHistoryCalendar, BottlenecksContent, BreakNotificationPopup, Card2 as Card, CardContent2 as CardContent, CardDescription2 as CardDescription, CardFooter2 as CardFooter, CardHeader2 as CardHeader, CardTitle2 as CardTitle, 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, EmptyStateMessage, FactoryView_default as FactoryView, GaugeChart, GridComponentsPlaceholder, Header, HelpView_default as HelpView, HomeView_default as HomeView, HourlyOutputChart2 as HourlyOutputChart, ISTTimer_default as ISTTimer, 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, LiveTimer, LoadingInline, LoadingOverlay_default as LoadingOverlay, LoadingPage_default as LoadingPage, LoadingSkeleton, LoadingSpinner_default as LoadingSpinner, LoadingState, LoginPage, LoginView_default as LoginView, MainLayout, MetricCard_default as MetricCard, NoWorkspaceData, OptifyeAgentClient, OutputProgressChart, PageHeader, PieChart4 as PieChart, ProfileView_default as ProfileView, RegistryProvider, S3Service, SKUManagementView, SOPComplianceChart, SSEChatClient, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, ShiftDisplay_default as ShiftDisplay, ShiftsView_default as ShiftsView, SideNavBar, SingleVideoStream_default as SingleVideoStream, Skeleton, SlackAPI, SubscriptionManager, SubscriptionManagerProvider, SupabaseProvider, TargetWorkspaceGrid, TargetsView_default as TargetsView, ThreadSidebar, TimeDisplay_default as TimeDisplay, TimePickerDropdown, VideoCard, VideoGridView, VideoPreloader, WORKSPACE_POSITIONS, WhatsAppShareButton, WorkspaceCard, WorkspaceDetailView_default as WorkspaceDetailView, WorkspaceDisplayNameExample, WorkspaceGrid, WorkspaceGridItem, WorkspaceHistoryCalendar, WorkspaceMetricCards, WorkspaceMonthlyDataFetcher, WorkspaceMonthlyPdfGenerator, WorkspacePdfExportButton, WorkspacePdfGenerator, WorkspaceWhatsAppShareButton, actionService, apiUtils, authCoreService, authOTPService, authRateLimitService, cacheService, checkRateLimit2 as checkRateLimit, clearAllRateLimits2 as clearAllRateLimits, clearRateLimit2 as clearRateLimit, clearS3VideoCache, clearS3VideoFromCache, clearWorkspaceDisplayNamesCache, cn, createStreamProxyHandler, createSupabaseClient, createThrottledReload, dashboardService, deleteThread, forceRefreshWorkspaceDisplayNames, formatDateInZone, formatDateTimeInZone, formatISTDate, formatIdleTime, formatTimeInZone, fromUrlFriendlyName, getAllLineDisplayNames, getAllThreadMessages, getAllWorkspaceDisplayNamesAsync, getAnonClient, getCameraNumber, getCompanyMetricsTableName, getConfigurableShortWorkspaceDisplayName, getConfigurableWorkspaceDisplayName, getConfiguredLineIds, 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, isTransitionPeriod, isValidFactoryViewConfiguration, isValidLineInfoPayload, isValidWorkspaceDetailedMetricsPayload, isValidWorkspaceMetricsPayload, isWorkspaceDisplayNamesLoaded, isWorkspaceDisplayNamesLoading, mergeWithDefaultConfig, migrateLegacyConfiguration, optifyeAgentClient, preInitializeWorkspaceDisplayNames, preloadS3Video, preloadS3VideoUrl, preloadS3VideosUrl, preloadVideoUrl, preloadVideosUrl, qualityService, realtimeService, refreshWorkspaceDisplayNames, resetCoreMixpanel, resetSubscriptionManager, s3VideoPreloader, skuService, storeWorkspaceMapping, streamProxyConfig, throttledReloadDashboard, toUrlFriendlyName, trackCoreEvent, trackCorePageView, updateThreadTitle, useActiveBreaks, useAllWorkspaceMetrics, useAnalyticsConfig, useAuth, useAuthConfig, useComponentOverride, useCustomConfig, useDashboardConfig, useDashboardMetrics, useDatabaseConfig, useDateFormatter, useDateTimeConfig, useEndpointsConfig, useEntityConfig, useFactoryOverviewMetrics, useFeatureFlags, useFormatNumber, useHistoricWorkspaceMetrics, useHlsStream, useHlsStreamWithCropping, useHookOverride, useLeaderboardMetrics, useLineDetailedMetrics, useLineKPIs, useLineMetrics, useLineWorkspaceMetrics, useMessages, useMetrics, useNavigation, useOverrides, usePageOverride, useRealtimeLineMetrics, useRegistry, useSKUs, useShiftConfig, useShifts, useSubscriptionManager, useSubscriptionManagerSafe, useSupabase, useSupabaseClient, useTargets, useTheme, useThemeConfig, useThreads, useVideoConfig, useWorkspaceConfig, useWorkspaceDetailedMetrics, useWorkspaceDisplayName, useWorkspaceDisplayNames, useWorkspaceDisplayNamesMap, useWorkspaceMetrics, useWorkspaceNavigation, useWorkspaceOperators, videoPreloader, whatsappService, withAuth, withRegistry, workspaceService };