@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.css +3680 -0
- package/dist/index.d.mts +341 -19
- package/dist/index.d.ts +341 -19
- package/dist/index.js +2573 -902
- package/dist/index.mjs +1948 -297
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import * as
|
|
2
|
-
import
|
|
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 {
|
|
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 =
|
|
208
|
+
var DashboardConfigContext = React19.createContext(void 0);
|
|
209
209
|
var DashboardProvider = ({ config: userProvidedConfig, children }) => {
|
|
210
|
-
const fullConfig =
|
|
210
|
+
const fullConfig = React19.useMemo(() => mergeWithDefaultConfig(userProvidedConfig), [userProvidedConfig]);
|
|
211
211
|
_setDashboardConfigInstance(fullConfig);
|
|
212
|
-
|
|
212
|
+
React19.useEffect(() => {
|
|
213
213
|
_setDashboardConfigInstance(fullConfig);
|
|
214
214
|
}, [fullConfig]);
|
|
215
|
-
|
|
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 =
|
|
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
|
|
462
|
-
const
|
|
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 (!
|
|
469
|
-
throw new Error("Factory View requires
|
|
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
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
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
|
|
507
|
-
// Use
|
|
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:
|
|
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
|
|
551
|
-
const
|
|
552
|
-
const
|
|
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
|
|
620
|
-
|
|
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 (!
|
|
630
|
-
throw new Error("Factory View requires
|
|
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",
|
|
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
|
|
858
|
-
const
|
|
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 (!
|
|
868
|
-
throw new Error("Factory View requires at least
|
|
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
|
|
871
|
-
|
|
872
|
-
|
|
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
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
const
|
|
879
|
-
|
|
880
|
-
const
|
|
881
|
-
const
|
|
882
|
-
const
|
|
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
|
-
|
|
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 ||
|
|
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.
|
|
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
|
|
947
|
-
|
|
948
|
-
|
|
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
|
-
|
|
952
|
-
if (
|
|
953
|
-
const
|
|
954
|
-
|
|
955
|
-
const
|
|
956
|
-
const
|
|
957
|
-
const
|
|
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
|
|
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 (!
|
|
1044
|
-
throw new Error("Factory View requires
|
|
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",
|
|
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
|
|
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 ?
|
|
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
|
|
3195
|
-
targetLineIdsForSubscription =
|
|
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
|
|
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") ?
|
|
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
|
|
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") ?
|
|
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 ?
|
|
3688
|
-
if (targetLineIds.length === 0
|
|
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 =
|
|
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
|
|
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
|
|
5135
|
-
endTime
|
|
5136
|
-
duration
|
|
5137
|
-
|
|
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
|
|
5142
|
-
endTime
|
|
5143
|
-
duration
|
|
5144
|
-
|
|
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
|
-
|
|
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
|
|
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:
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
16735
|
+
React19.useEffect(() => {
|
|
15930
16736
|
console.log("withAuth state:", { loading, hasSession: !!session, requireAuth: defaultOptions.requireAuth });
|
|
15931
16737
|
}, [session, loading]);
|
|
15932
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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] =
|
|
16620
|
-
const prevDataRef =
|
|
16621
|
-
const animationFrameRef =
|
|
16622
|
-
const animateToNewData =
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
|
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] =
|
|
17028
|
-
const prevDataRef =
|
|
17029
|
-
const animationFrameRef =
|
|
17030
|
-
const [idleBarState, setIdleBarState] =
|
|
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 =
|
|
17036
|
-
const stateUpdateTimeoutRef =
|
|
17037
|
-
|
|
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 =
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 (
|
|
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__ */
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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(
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
26043
|
-
|
|
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
|
|
26427
|
-
|
|
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,
|
|
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
|
-
|
|
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
|
|
26477
|
-
|
|
26478
|
-
|
|
26479
|
-
|
|
26480
|
-
|
|
26481
|
-
|
|
26482
|
-
|
|
26483
|
-
|
|
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
|
-
|
|
27570
|
+
const allHooksLoaded = lineDataHooks.every(({ hook }) => !hook.loading);
|
|
27571
|
+
if (allHooksLoaded) {
|
|
26524
27572
|
fetchHourlyData();
|
|
26525
27573
|
}
|
|
26526
|
-
}, [supabase,
|
|
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 ||
|
|
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(
|
|
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
|
|
27423
|
-
|
|
27424
|
-
|
|
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
|
-
|
|
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__ */
|
|
27446
|
-
|
|
27447
|
-
|
|
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
|
-
|
|
27471
|
-
|
|
27472
|
-
|
|
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(
|
|
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 =
|
|
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: "
|
|
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: "
|
|
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(
|
|
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 };
|