@optifye/dashboard-core 6.10.13 → 6.10.14
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 +141 -33
- package/dist/index.d.mts +67 -2
- package/dist/index.d.ts +67 -2
- package/dist/index.js +1722 -1082
- package/dist/index.mjs +1726 -1087
- package/global.css +12 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -2,8 +2,8 @@ import * as React24 from 'react';
|
|
|
2
2
|
import React24__default, { createContext, useRef, useCallback, useState, useMemo, useEffect, forwardRef, useImperativeHandle, useLayoutEffect, memo, useContext, useId, Children, isValidElement, useInsertionEffect, Fragment as Fragment$1, createElement, Component } from 'react';
|
|
3
3
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
4
4
|
import { useRouter } from 'next/router';
|
|
5
|
-
import { toZonedTime, formatInTimeZone
|
|
6
|
-
import { subDays, format, parseISO, isValid,
|
|
5
|
+
import { fromZonedTime, toZonedTime, formatInTimeZone } from 'date-fns-tz';
|
|
6
|
+
import { addMinutes, subDays, format, parseISO, isValid, differenceInMinutes, formatDistanceToNow, isToday, isFuture, addDays, startOfDay, isBefore, startOfMonth, endOfMonth, eachDayOfInterval, getDay, isSameDay, isWithinInterval, subMonths, addMonths } from 'date-fns';
|
|
7
7
|
import mixpanel from 'mixpanel-browser';
|
|
8
8
|
import { EventEmitter } from 'events';
|
|
9
9
|
import { createClient, REALTIME_SUBSCRIBE_STATES } from '@supabase/supabase-js';
|
|
@@ -11,13 +11,13 @@ import Hls3, { Events, ErrorTypes } from 'hls.js';
|
|
|
11
11
|
import useSWR from 'swr';
|
|
12
12
|
import { noop, warning, invariant, progress, secondsToMilliseconds, millisecondsToSeconds, memo as memo$1 } from 'motion-utils';
|
|
13
13
|
import { getValueTransition, hover, press, isPrimaryPointer, GroupPlaybackControls, setDragLock, supportsLinearEasing, attachTimeline, isGenerator, calcGeneratorDuration, isWaapiSupportedEasing, mapEasingToNativeEasing, maxGeneratorDuration, generateLinearEasing, isBezierDefinition } from 'motion-dom';
|
|
14
|
-
import { Camera, ChevronDown, ChevronUp, Check, Map as Map$1, Video, ShieldCheck, Star, Award, ArrowLeft, X, Coffee, Plus, Clock, Calendar, Save, AlertCircle, Loader2, Minus, ArrowDown, ArrowUp, ChevronLeft, ChevronRight, Pause, Play, Wrench, XCircle, Package, UserX, Zap, HelpCircle, AlertTriangle, Tag,
|
|
14
|
+
import { Camera, ChevronDown, ChevronUp, Check, Map as Map$1, Video, ShieldCheck, Star, Award, ArrowLeft, X, Coffee, Plus, Clock, Calendar, Save, AlertCircle, Loader2, Minus, ArrowDown, ArrowUp, ChevronLeft, ChevronRight, TrendingUp, Sparkles, Pause, Play, Wrench, XCircle, Package, UserX, Zap, HelpCircle, AlertTriangle, Tag, Palette, CheckCircle2, RefreshCw, TrendingDown, FolderOpen, Folder, Sliders, Activity, Layers, Filter, Search, Edit2, ArrowRight, CheckCircle, User, Users, Shield, Building2, Mail, Lock, Info, Share2, Trophy, Target, Download, Sun, Moon, MousePointer, UserPlus, UserCog, Trash2, Eye, MoreVertical, BarChart3, MessageSquare, Menu, Send, Copy, UserCheck, LogOut, Settings, LifeBuoy, EyeOff, UserCircle } from 'lucide-react';
|
|
15
15
|
import { toast } from 'sonner';
|
|
16
16
|
import { BarChart as BarChart$1, CartesianGrid, XAxis, YAxis, ReferenceLine, Tooltip, Legend, Bar, LabelList, ResponsiveContainer, LineChart as LineChart$1, Line, PieChart, Pie, Cell, ComposedChart, Area, ScatterChart, Scatter } from 'recharts';
|
|
17
17
|
import { Slot } from '@radix-ui/react-slot';
|
|
18
18
|
import * as SelectPrimitive from '@radix-ui/react-select';
|
|
19
19
|
import { DayPicker, useNavigation as useNavigation$1 } from 'react-day-picker';
|
|
20
|
-
import { XMarkIcon, ArrowRightIcon, HomeIcon, TrophyIcon, ChartBarIcon, LightBulbIcon, AdjustmentsHorizontalIcon, ClockIcon, UsersIcon, TicketIcon, CubeIcon, SparklesIcon, QuestionMarkCircleIcon, HeartIcon, UserCircleIcon, ExclamationCircleIcon, EnvelopeIcon, DocumentTextIcon, ChevronUpIcon, ChevronDownIcon,
|
|
20
|
+
import { XMarkIcon, ArrowRightIcon, HomeIcon, TrophyIcon, ChartBarIcon, LightBulbIcon, AdjustmentsHorizontalIcon, ClockIcon, UsersIcon, TicketIcon, CubeIcon, SparklesIcon, QuestionMarkCircleIcon, HeartIcon, UserCircleIcon, ExclamationCircleIcon, EnvelopeIcon, DocumentTextIcon, ChevronUpIcon, ChevronDownIcon, Bars3Icon, CheckCircleIcon, ChatBubbleLeftRightIcon, ArrowLeftIcon, XCircleIcon, FunnelIcon, CalendarIcon, ChevronRightIcon, ChevronLeftIcon, InformationCircleIcon, PlayCircleIcon } from '@heroicons/react/24/outline';
|
|
21
21
|
import { CheckIcon } from '@heroicons/react/24/solid';
|
|
22
22
|
import html2canvas from 'html2canvas';
|
|
23
23
|
import jsPDF, { jsPDF as jsPDF$1 } from 'jspdf';
|
|
@@ -1552,7 +1552,7 @@ var dashboardService = {
|
|
|
1552
1552
|
};
|
|
1553
1553
|
const formattedStartDate = formatDate2(startDate);
|
|
1554
1554
|
const formattedEndDate = formatDate2(endDate);
|
|
1555
|
-
let query = supabase.from(lineMetricsTable).select("date, shift_id, avg_efficiency, underperforming_workspaces, total_workspaces").gte("date", formattedStartDate).lte("date", formattedEndDate);
|
|
1555
|
+
let query = supabase.from(lineMetricsTable).select("date, shift_id, avg_efficiency, underperforming_workspaces, total_workspaces, current_output, ideal_output, line_threshold").gte("date", formattedStartDate).lte("date", formattedEndDate);
|
|
1556
1556
|
if (lineIdInput === factoryViewId) {
|
|
1557
1557
|
if (!isValidFactoryViewConfiguration(entityConfig)) {
|
|
1558
1558
|
throw new Error("Factory View requires at least one configured line for monthly data.");
|
|
@@ -1571,7 +1571,10 @@ var dashboardService = {
|
|
|
1571
1571
|
shift_id: item.shift_id,
|
|
1572
1572
|
avg_efficiency: item.avg_efficiency || 0,
|
|
1573
1573
|
underperforming_workspaces: item.underperforming_workspaces || 0,
|
|
1574
|
-
total_workspaces: item.total_workspaces || 0
|
|
1574
|
+
total_workspaces: item.total_workspaces || 0,
|
|
1575
|
+
current_output: item.current_output || 0,
|
|
1576
|
+
ideal_output: item.ideal_output || 0,
|
|
1577
|
+
line_threshold: item.line_threshold || 0
|
|
1575
1578
|
}));
|
|
1576
1579
|
return transformedData;
|
|
1577
1580
|
} catch (err) {
|
|
@@ -9386,7 +9389,56 @@ var getUniformShiftGroup = (shiftConfigMap, timezone, now2 = /* @__PURE__ */ new
|
|
|
9386
9389
|
return groups.length === 1 ? groups[0] : null;
|
|
9387
9390
|
};
|
|
9388
9391
|
|
|
9392
|
+
// src/lib/types/efficiencyLegend.ts
|
|
9393
|
+
var DEFAULT_EFFICIENCY_LEGEND = {
|
|
9394
|
+
green_min: 80,
|
|
9395
|
+
green_max: 100,
|
|
9396
|
+
yellow_min: 70,
|
|
9397
|
+
yellow_max: 79,
|
|
9398
|
+
red_min: 0,
|
|
9399
|
+
red_max: 69,
|
|
9400
|
+
critical_threshold: 50
|
|
9401
|
+
};
|
|
9402
|
+
function getEfficiencyColor(efficiency, legend = DEFAULT_EFFICIENCY_LEGEND) {
|
|
9403
|
+
if (efficiency >= legend.green_min) {
|
|
9404
|
+
return "green";
|
|
9405
|
+
} else if (efficiency >= legend.yellow_min) {
|
|
9406
|
+
return "yellow";
|
|
9407
|
+
} else {
|
|
9408
|
+
return "red";
|
|
9409
|
+
}
|
|
9410
|
+
}
|
|
9411
|
+
function getEfficiencyColorClasses(efficiency, legend = DEFAULT_EFFICIENCY_LEGEND) {
|
|
9412
|
+
const color2 = getEfficiencyColor(efficiency, legend);
|
|
9413
|
+
switch (color2) {
|
|
9414
|
+
case "green":
|
|
9415
|
+
return "bg-[#00AB45]/90 hover:bg-[#00AB45]/95";
|
|
9416
|
+
case "yellow":
|
|
9417
|
+
return "bg-[#FFB020]/90 hover:bg-[#FFB020]/95";
|
|
9418
|
+
case "red":
|
|
9419
|
+
return "bg-[#E34329]/90 hover:bg-[#E34329]/95";
|
|
9420
|
+
default:
|
|
9421
|
+
return "bg-gray-300/90";
|
|
9422
|
+
}
|
|
9423
|
+
}
|
|
9424
|
+
|
|
9389
9425
|
// src/lib/hooks/useDashboardMetrics.ts
|
|
9426
|
+
var parseEfficiencyLegend = (legend) => {
|
|
9427
|
+
if (!legend) return null;
|
|
9428
|
+
const coerce = (value, fallback) => {
|
|
9429
|
+
const num = Number(value);
|
|
9430
|
+
return Number.isFinite(num) ? num : fallback;
|
|
9431
|
+
};
|
|
9432
|
+
return {
|
|
9433
|
+
green_min: coerce(legend.green_min, DEFAULT_EFFICIENCY_LEGEND.green_min),
|
|
9434
|
+
green_max: coerce(legend.green_max, DEFAULT_EFFICIENCY_LEGEND.green_max),
|
|
9435
|
+
yellow_min: coerce(legend.yellow_min, DEFAULT_EFFICIENCY_LEGEND.yellow_min),
|
|
9436
|
+
yellow_max: coerce(legend.yellow_max, DEFAULT_EFFICIENCY_LEGEND.yellow_max),
|
|
9437
|
+
red_min: coerce(legend.red_min, DEFAULT_EFFICIENCY_LEGEND.red_min),
|
|
9438
|
+
red_max: coerce(legend.red_max, DEFAULT_EFFICIENCY_LEGEND.red_max),
|
|
9439
|
+
critical_threshold: coerce(legend.critical_threshold, DEFAULT_EFFICIENCY_LEGEND.critical_threshold)
|
|
9440
|
+
};
|
|
9441
|
+
};
|
|
9390
9442
|
var useDashboardMetrics = ({ onLineMetricsUpdate, lineId, userAccessibleLineIds }) => {
|
|
9391
9443
|
const { supabaseUrl, supabaseKey } = useDashboardConfig();
|
|
9392
9444
|
const entityConfig = useEntityConfig();
|
|
@@ -9444,7 +9496,7 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId, userAccessibleLineIds
|
|
|
9444
9496
|
);
|
|
9445
9497
|
useEffect(() => {
|
|
9446
9498
|
lineIdRef.current = lineId;
|
|
9447
|
-
setMetrics({ workspaceMetrics: [], lineMetrics: [] });
|
|
9499
|
+
setMetrics({ workspaceMetrics: [], lineMetrics: [], metadata: void 0 });
|
|
9448
9500
|
setIsLoading(true);
|
|
9449
9501
|
}, [lineId]);
|
|
9450
9502
|
const fetchAllMetrics = useCallback(async () => {
|
|
@@ -9482,6 +9534,8 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId, userAccessibleLineIds
|
|
|
9482
9534
|
}
|
|
9483
9535
|
let allWorkspaceMetrics = [];
|
|
9484
9536
|
let allLineMetrics = [];
|
|
9537
|
+
let hasFlowBuffers = false;
|
|
9538
|
+
let efficiencyLegend;
|
|
9485
9539
|
if (isFactory && shiftGroups.length > 0) {
|
|
9486
9540
|
console.log(`[useDashboardMetrics] \u{1F3ED} Factory view: Fetching for ${shiftGroups.length} shift group(s)`);
|
|
9487
9541
|
const metricsPromises = shiftGroups.map(async (group) => {
|
|
@@ -9512,6 +9566,9 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId, userAccessibleLineIds
|
|
|
9512
9566
|
}
|
|
9513
9567
|
});
|
|
9514
9568
|
const results = await Promise.all(metricsPromises);
|
|
9569
|
+
hasFlowBuffers = results.some((result) => result?.metadata?.has_flow_buffers);
|
|
9570
|
+
const legendCandidate = results.find((result) => result?.efficiency_legend)?.efficiency_legend;
|
|
9571
|
+
efficiencyLegend = parseEfficiencyLegend(legendCandidate) ?? DEFAULT_EFFICIENCY_LEGEND;
|
|
9515
9572
|
results.forEach((result) => {
|
|
9516
9573
|
if (result.workspace_metrics) {
|
|
9517
9574
|
allWorkspaceMetrics.push(...result.workspace_metrics);
|
|
@@ -9564,6 +9621,8 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId, userAccessibleLineIds
|
|
|
9564
9621
|
});
|
|
9565
9622
|
allWorkspaceMetrics = backendData.workspace_metrics || [];
|
|
9566
9623
|
allLineMetrics = backendData.line_metrics || [];
|
|
9624
|
+
hasFlowBuffers = Boolean(backendData?.metadata?.has_flow_buffers);
|
|
9625
|
+
efficiencyLegend = parseEfficiencyLegend(backendData?.efficiency_legend) ?? DEFAULT_EFFICIENCY_LEGEND;
|
|
9567
9626
|
}
|
|
9568
9627
|
const transformedWorkspaceData = allWorkspaceMetrics.map((item) => ({
|
|
9569
9628
|
company_id: item.company_id || entityConfig.companyId,
|
|
@@ -9589,7 +9648,9 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId, userAccessibleLineIds
|
|
|
9589
9648
|
});
|
|
9590
9649
|
const newMetricsState = {
|
|
9591
9650
|
workspaceMetrics: transformedWorkspaceData,
|
|
9592
|
-
lineMetrics: allLineMetrics || []
|
|
9651
|
+
lineMetrics: allLineMetrics || [],
|
|
9652
|
+
metadata: { hasFlowBuffers },
|
|
9653
|
+
efficiencyLegend: efficiencyLegend ?? DEFAULT_EFFICIENCY_LEGEND
|
|
9593
9654
|
};
|
|
9594
9655
|
console.log("[useDashboardMetrics] Setting metrics state:", {
|
|
9595
9656
|
workspaceMetrics: newMetricsState.workspaceMetrics.length,
|
|
@@ -9741,6 +9802,8 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId, userAccessibleLineIds
|
|
|
9741
9802
|
return {
|
|
9742
9803
|
workspaceMetrics: metrics2?.workspaceMetrics || [],
|
|
9743
9804
|
lineMetrics: metrics2?.lineMetrics || [],
|
|
9805
|
+
efficiencyLegend: metrics2?.efficiencyLegend || DEFAULT_EFFICIENCY_LEGEND,
|
|
9806
|
+
metadata: metrics2?.metadata,
|
|
9744
9807
|
isLoading,
|
|
9745
9808
|
error,
|
|
9746
9809
|
refetch: fetchAllMetrics
|
|
@@ -13757,6 +13820,256 @@ function useIdleTimeReasons({
|
|
|
13757
13820
|
refetch: fetchData
|
|
13758
13821
|
};
|
|
13759
13822
|
}
|
|
13823
|
+
|
|
13824
|
+
// src/lib/services/clipClassificationService.ts
|
|
13825
|
+
function parseCleanLabel(rawLabel) {
|
|
13826
|
+
if (!rawLabel) return null;
|
|
13827
|
+
const patterns = [
|
|
13828
|
+
/"Clip Label"\s*:\s*"([^"]+)"/,
|
|
13829
|
+
// Old format
|
|
13830
|
+
/"clip_label"\s*:\s*"([^"]+)"/,
|
|
13831
|
+
// New format
|
|
13832
|
+
/'Clip Label'\s*:\s*'([^']+)'/,
|
|
13833
|
+
// Single quotes
|
|
13834
|
+
/'clip_label'\s*:\s*'([^']+)'/
|
|
13835
|
+
// Single quotes
|
|
13836
|
+
];
|
|
13837
|
+
for (const pattern of patterns) {
|
|
13838
|
+
const match = rawLabel.match(pattern);
|
|
13839
|
+
if (match) {
|
|
13840
|
+
const label = match[1].trim();
|
|
13841
|
+
return label.replace(/ /g, "_");
|
|
13842
|
+
}
|
|
13843
|
+
}
|
|
13844
|
+
return null;
|
|
13845
|
+
}
|
|
13846
|
+
async function fetchClassifications(clipIds, token) {
|
|
13847
|
+
if (!clipIds || clipIds.length === 0) {
|
|
13848
|
+
return {};
|
|
13849
|
+
}
|
|
13850
|
+
try {
|
|
13851
|
+
const CHUNK_SIZE = 50;
|
|
13852
|
+
const chunks = [];
|
|
13853
|
+
for (let i = 0; i < clipIds.length; i += CHUNK_SIZE) {
|
|
13854
|
+
chunks.push(clipIds.slice(i, i + CHUNK_SIZE));
|
|
13855
|
+
}
|
|
13856
|
+
console.log(`[fetchClassifications] Fetching ${clipIds.length} classifications in ${chunks.length} chunks`);
|
|
13857
|
+
const apiBase = process.env.NEXT_PUBLIC_BACKEND_URL || "http://localhost:8000";
|
|
13858
|
+
const chunkResults = await Promise.all(
|
|
13859
|
+
chunks.map(async (chunkIds) => {
|
|
13860
|
+
try {
|
|
13861
|
+
const response = await fetch(
|
|
13862
|
+
`${apiBase}/api/classification/batch?clip_ids=${chunkIds.join(",")}`,
|
|
13863
|
+
{
|
|
13864
|
+
headers: {
|
|
13865
|
+
"Authorization": `Bearer ${token}`,
|
|
13866
|
+
"Content-Type": "application/json"
|
|
13867
|
+
}
|
|
13868
|
+
}
|
|
13869
|
+
);
|
|
13870
|
+
if (!response.ok) {
|
|
13871
|
+
console.error(`Classification API error for chunk: ${response.status}`);
|
|
13872
|
+
return Object.fromEntries(
|
|
13873
|
+
chunkIds.map((id3) => [id3, { status: "processing" }])
|
|
13874
|
+
);
|
|
13875
|
+
}
|
|
13876
|
+
const data = await response.json();
|
|
13877
|
+
return data.classifications || {};
|
|
13878
|
+
} catch (error) {
|
|
13879
|
+
console.error("Error fetching chunk:", error);
|
|
13880
|
+
return Object.fromEntries(
|
|
13881
|
+
chunkIds.map((id3) => [id3, { status: "processing" }])
|
|
13882
|
+
);
|
|
13883
|
+
}
|
|
13884
|
+
})
|
|
13885
|
+
);
|
|
13886
|
+
const allClassifications = Object.assign({}, ...chunkResults);
|
|
13887
|
+
console.log(`[fetchClassifications] Total fetched: ${Object.keys(allClassifications).length} classifications`);
|
|
13888
|
+
return allClassifications;
|
|
13889
|
+
} catch (error) {
|
|
13890
|
+
console.error("Error fetching classifications:", error);
|
|
13891
|
+
return Object.fromEntries(
|
|
13892
|
+
clipIds.map((id3) => [id3, { status: "processing" }])
|
|
13893
|
+
);
|
|
13894
|
+
}
|
|
13895
|
+
}
|
|
13896
|
+
function useClassificationRealtimeUpdates({
|
|
13897
|
+
clipIds,
|
|
13898
|
+
enabled = true,
|
|
13899
|
+
onClassificationUpdate
|
|
13900
|
+
}) {
|
|
13901
|
+
const supabase = useSupabase();
|
|
13902
|
+
useEffect(() => {
|
|
13903
|
+
if (!enabled || !clipIds || clipIds.length === 0 || !supabase) {
|
|
13904
|
+
return;
|
|
13905
|
+
}
|
|
13906
|
+
const channelName = `classification:${clipIds.slice(0, 5).join("-")}`;
|
|
13907
|
+
console.log(`[useClassificationRealtimeUpdates] Subscribing to channel: ${channelName}`);
|
|
13908
|
+
const channel = supabase.channel(channelName).on(
|
|
13909
|
+
"postgres_changes",
|
|
13910
|
+
{
|
|
13911
|
+
event: "INSERT",
|
|
13912
|
+
schema: "public",
|
|
13913
|
+
table: "clip_classification",
|
|
13914
|
+
filter: `clip_id=in.(${clipIds.join(",")})`
|
|
13915
|
+
},
|
|
13916
|
+
(payload) => {
|
|
13917
|
+
console.log("[useClassificationRealtimeUpdates] New classification:", payload);
|
|
13918
|
+
try {
|
|
13919
|
+
const { clip_id, clip_label, confidence_score } = payload.new;
|
|
13920
|
+
const parsedLabel = parseCleanLabel(clip_label);
|
|
13921
|
+
if (parsedLabel) {
|
|
13922
|
+
onClassificationUpdate(clip_id, {
|
|
13923
|
+
status: "classified",
|
|
13924
|
+
label: parsedLabel,
|
|
13925
|
+
confidence: confidence_score || 0
|
|
13926
|
+
});
|
|
13927
|
+
} else {
|
|
13928
|
+
console.warn("[useClassificationRealtimeUpdates] Failed to parse label:", clip_label);
|
|
13929
|
+
}
|
|
13930
|
+
} catch (error) {
|
|
13931
|
+
console.error("[useClassificationRealtimeUpdates] Error processing update:", error);
|
|
13932
|
+
}
|
|
13933
|
+
}
|
|
13934
|
+
).subscribe((status) => {
|
|
13935
|
+
console.log(`[useClassificationRealtimeUpdates] Subscription status:`, status);
|
|
13936
|
+
});
|
|
13937
|
+
return () => {
|
|
13938
|
+
console.log(`[useClassificationRealtimeUpdates] Unsubscribing from ${channelName}`);
|
|
13939
|
+
supabase.removeChannel(channel);
|
|
13940
|
+
};
|
|
13941
|
+
}, [clipIds, enabled, supabase, onClassificationUpdate]);
|
|
13942
|
+
}
|
|
13943
|
+
|
|
13944
|
+
// src/lib/hooks/useIdleTimeClipClassifications.ts
|
|
13945
|
+
var DEFAULT_LIMIT = 200;
|
|
13946
|
+
var MAX_PAGES = 5;
|
|
13947
|
+
function useIdleTimeClipClassifications({
|
|
13948
|
+
workspaceId,
|
|
13949
|
+
date,
|
|
13950
|
+
shiftId,
|
|
13951
|
+
enabled = true,
|
|
13952
|
+
limit = DEFAULT_LIMIT
|
|
13953
|
+
}) {
|
|
13954
|
+
const { session } = useAuth();
|
|
13955
|
+
const [idleClips, setIdleClips] = useState([]);
|
|
13956
|
+
const [clipClassifications, setClipClassifications] = useState({});
|
|
13957
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
13958
|
+
const [error, setError] = useState(null);
|
|
13959
|
+
const lastRequestKeyRef = useRef("");
|
|
13960
|
+
const requestKey = useMemo(
|
|
13961
|
+
() => `${workspaceId || ""}-${date || ""}-${shiftId ?? ""}`,
|
|
13962
|
+
[workspaceId, date, shiftId]
|
|
13963
|
+
);
|
|
13964
|
+
const fetchIdleClips = useCallback(async () => {
|
|
13965
|
+
if (!enabled) {
|
|
13966
|
+
setIsLoading(false);
|
|
13967
|
+
return;
|
|
13968
|
+
}
|
|
13969
|
+
if (!workspaceId || !date || shiftId === void 0) {
|
|
13970
|
+
setIdleClips([]);
|
|
13971
|
+
setIsLoading(false);
|
|
13972
|
+
return;
|
|
13973
|
+
}
|
|
13974
|
+
if (!session?.access_token) {
|
|
13975
|
+
setError("Not authenticated");
|
|
13976
|
+
setIsLoading(false);
|
|
13977
|
+
return;
|
|
13978
|
+
}
|
|
13979
|
+
setIsLoading(true);
|
|
13980
|
+
setError(null);
|
|
13981
|
+
lastRequestKeyRef.current = requestKey;
|
|
13982
|
+
try {
|
|
13983
|
+
const collected = [];
|
|
13984
|
+
let page = 1;
|
|
13985
|
+
let hasMore = true;
|
|
13986
|
+
while (hasMore && page <= MAX_PAGES && collected.length < limit) {
|
|
13987
|
+
const response = await fetch("/api/clips/supabase", {
|
|
13988
|
+
method: "POST",
|
|
13989
|
+
headers: {
|
|
13990
|
+
"Content-Type": "application/json",
|
|
13991
|
+
"Authorization": `Bearer ${session.access_token}`
|
|
13992
|
+
},
|
|
13993
|
+
body: JSON.stringify({
|
|
13994
|
+
action: "clip-metadata",
|
|
13995
|
+
workspaceId,
|
|
13996
|
+
date,
|
|
13997
|
+
shift: shiftId.toString(),
|
|
13998
|
+
category: "idle_time",
|
|
13999
|
+
page,
|
|
14000
|
+
limit
|
|
14001
|
+
})
|
|
14002
|
+
});
|
|
14003
|
+
if (!response.ok) {
|
|
14004
|
+
throw new Error(`Idle clip metadata request failed: ${response.status}`);
|
|
14005
|
+
}
|
|
14006
|
+
const data = await response.json();
|
|
14007
|
+
const clips = Array.isArray(data?.clips) ? data.clips : [];
|
|
14008
|
+
const mapped = clips.map((clip) => ({
|
|
14009
|
+
id: clip.id,
|
|
14010
|
+
idle_start_time: clip.idle_start_time,
|
|
14011
|
+
idle_end_time: clip.idle_end_time
|
|
14012
|
+
}));
|
|
14013
|
+
collected.push(...mapped);
|
|
14014
|
+
hasMore = Boolean(data?.hasMore);
|
|
14015
|
+
page += 1;
|
|
14016
|
+
}
|
|
14017
|
+
if (lastRequestKeyRef.current === requestKey) {
|
|
14018
|
+
setIdleClips(collected);
|
|
14019
|
+
}
|
|
14020
|
+
} catch (err) {
|
|
14021
|
+
console.error("[useIdleTimeClipClassifications] Error fetching idle clips:", err);
|
|
14022
|
+
if (lastRequestKeyRef.current === requestKey) {
|
|
14023
|
+
setError(err instanceof Error ? err.message : "Failed to fetch idle clips");
|
|
14024
|
+
setIdleClips([]);
|
|
14025
|
+
}
|
|
14026
|
+
} finally {
|
|
14027
|
+
if (lastRequestKeyRef.current === requestKey) {
|
|
14028
|
+
setIsLoading(false);
|
|
14029
|
+
}
|
|
14030
|
+
}
|
|
14031
|
+
}, [enabled, workspaceId, date, shiftId, session?.access_token, requestKey, limit]);
|
|
14032
|
+
useEffect(() => {
|
|
14033
|
+
fetchIdleClips();
|
|
14034
|
+
}, [fetchIdleClips]);
|
|
14035
|
+
useEffect(() => {
|
|
14036
|
+
setClipClassifications({});
|
|
14037
|
+
}, [requestKey]);
|
|
14038
|
+
const idleClipIds = useMemo(
|
|
14039
|
+
() => idleClips.map((clip) => clip.id).filter(Boolean),
|
|
14040
|
+
[idleClips]
|
|
14041
|
+
);
|
|
14042
|
+
useEffect(() => {
|
|
14043
|
+
if (!enabled || idleClipIds.length === 0 || !session?.access_token) {
|
|
14044
|
+
return;
|
|
14045
|
+
}
|
|
14046
|
+
fetchClassifications(idleClipIds, session.access_token).then((classifications) => {
|
|
14047
|
+
setClipClassifications((prev) => ({
|
|
14048
|
+
...prev,
|
|
14049
|
+
...classifications
|
|
14050
|
+
}));
|
|
14051
|
+
}).catch((err) => {
|
|
14052
|
+
console.error("[useIdleTimeClipClassifications] Error fetching classifications:", err);
|
|
14053
|
+
});
|
|
14054
|
+
}, [enabled, idleClipIds, session?.access_token]);
|
|
14055
|
+
useClassificationRealtimeUpdates({
|
|
14056
|
+
clipIds: idleClipIds,
|
|
14057
|
+
enabled: enabled && idleClipIds.length > 0,
|
|
14058
|
+
onClassificationUpdate: useCallback((clipId, classification) => {
|
|
14059
|
+
setClipClassifications((prev) => ({
|
|
14060
|
+
...prev,
|
|
14061
|
+
[clipId]: classification
|
|
14062
|
+
}));
|
|
14063
|
+
}, [])
|
|
14064
|
+
});
|
|
14065
|
+
return {
|
|
14066
|
+
idleClips,
|
|
14067
|
+
clipClassifications,
|
|
14068
|
+
isLoading,
|
|
14069
|
+
error,
|
|
14070
|
+
refetch: fetchIdleClips
|
|
14071
|
+
};
|
|
14072
|
+
}
|
|
13760
14073
|
function useUserUsage(userId, options = {}) {
|
|
13761
14074
|
const { startDate, endDate, enabled = true } = options;
|
|
13762
14075
|
const { session } = useAuth();
|
|
@@ -26464,6 +26777,10 @@ var HourlyOutputChartComponent = ({
|
|
|
26464
26777
|
shiftEnd,
|
|
26465
26778
|
showIdleTime = false,
|
|
26466
26779
|
idleTimeHourly,
|
|
26780
|
+
idleTimeClips,
|
|
26781
|
+
idleTimeClipClassifications,
|
|
26782
|
+
shiftDate,
|
|
26783
|
+
timezone,
|
|
26467
26784
|
className = ""
|
|
26468
26785
|
}) => {
|
|
26469
26786
|
const containerRef = React24__default.useRef(null);
|
|
@@ -26476,6 +26793,37 @@ var HourlyOutputChartComponent = ({
|
|
|
26476
26793
|
return { hour, minute, decimalHour };
|
|
26477
26794
|
};
|
|
26478
26795
|
const shiftStartTime = getTimeFromTimeString(shiftStart);
|
|
26796
|
+
const shiftStartDateTime = React24__default.useMemo(() => {
|
|
26797
|
+
if (!shiftDate || !timezone) return null;
|
|
26798
|
+
const hour = shiftStartTime.hour.toString().padStart(2, "0");
|
|
26799
|
+
const minute = shiftStartTime.minute.toString().padStart(2, "0");
|
|
26800
|
+
return fromZonedTime(`${shiftDate}T${hour}:${minute}:00`, timezone);
|
|
26801
|
+
}, [shiftDate, timezone, shiftStartTime.hour, shiftStartTime.minute]);
|
|
26802
|
+
const idleClipRanges = React24__default.useMemo(() => {
|
|
26803
|
+
if (!idleTimeClips || idleTimeClips.length === 0) return [];
|
|
26804
|
+
return idleTimeClips.map((clip) => ({
|
|
26805
|
+
id: clip.id,
|
|
26806
|
+
start: clip.idle_start_time ? new Date(clip.idle_start_time) : null,
|
|
26807
|
+
end: clip.idle_end_time ? new Date(clip.idle_end_time) : null
|
|
26808
|
+
})).filter((clip) => clip.start && clip.end);
|
|
26809
|
+
}, [idleTimeClips]);
|
|
26810
|
+
const getIdleReasonForRange = React24__default.useCallback((rangeStart, rangeEnd) => {
|
|
26811
|
+
if (!rangeStart || !rangeEnd || idleClipRanges.length === 0) {
|
|
26812
|
+
return "Reason unavailable";
|
|
26813
|
+
}
|
|
26814
|
+
const matchingClip = idleClipRanges.find((clip) => rangeStart >= clip.start && rangeEnd <= clip.end) || idleClipRanges.find((clip) => rangeStart < clip.end && rangeEnd > clip.start);
|
|
26815
|
+
if (!matchingClip) {
|
|
26816
|
+
return "Reason unavailable";
|
|
26817
|
+
}
|
|
26818
|
+
const classification = idleTimeClipClassifications?.[matchingClip.id];
|
|
26819
|
+
if (!classification || classification.status === "processing") {
|
|
26820
|
+
return "Analyzing...";
|
|
26821
|
+
}
|
|
26822
|
+
if (!classification.label) {
|
|
26823
|
+
return "Reason unavailable";
|
|
26824
|
+
}
|
|
26825
|
+
return classification.label.replace(/_/g, " ");
|
|
26826
|
+
}, [idleClipRanges, idleTimeClipClassifications]);
|
|
26479
26827
|
const { shiftDuration, shiftEndTime, hasPartialLastHour } = React24__default.useMemo(() => {
|
|
26480
26828
|
console.log("[HourlyOutputChart] Calculating shift duration with:", {
|
|
26481
26829
|
shiftStart,
|
|
@@ -26723,6 +27071,7 @@ var HourlyOutputChartComponent = ({
|
|
|
26723
27071
|
}
|
|
26724
27072
|
idleMinutes = idleArray.filter((val) => val === "1" || val === 1).length;
|
|
26725
27073
|
return {
|
|
27074
|
+
hourIndex: i,
|
|
26726
27075
|
hour: formatHour(i),
|
|
26727
27076
|
timeRange: formatTimeRange2(i),
|
|
26728
27077
|
output: animatedData[i] || 0,
|
|
@@ -26916,9 +27265,10 @@ var HourlyOutputChartComponent = ({
|
|
|
26916
27265
|
}
|
|
26917
27266
|
}
|
|
26918
27267
|
const formatIdleTimestamp = (minuteIdx) => {
|
|
26919
|
-
const
|
|
26920
|
-
const hourOffset = hourIndex
|
|
26921
|
-
const
|
|
27268
|
+
const fallbackIndex = chartData.findIndex((item) => item.timeRange === data2.timeRange);
|
|
27269
|
+
const hourOffset = Number.isFinite(data2.hourIndex) ? data2.hourIndex : fallbackIndex;
|
|
27270
|
+
const safeHourOffset = hourOffset >= 0 ? hourOffset : 0;
|
|
27271
|
+
const totalMinutes = (shiftStartTime.hour + safeHourOffset) * 60 + shiftStartTime.minute + minuteIdx;
|
|
26922
27272
|
const hour = Math.floor(totalMinutes / 60) % 24;
|
|
26923
27273
|
const minute = totalMinutes % 60;
|
|
26924
27274
|
const period = hour >= 12 ? "PM" : "AM";
|
|
@@ -26949,27 +27299,23 @@ var HourlyOutputChartComponent = ({
|
|
|
26949
27299
|
const duration = range.end - range.start + 1;
|
|
26950
27300
|
const startTime = formatIdleTimestamp(range.start);
|
|
26951
27301
|
const endTime = formatIdleTimestamp(range.end + 1);
|
|
27302
|
+
const fallbackIndex = chartData.findIndex((item) => item.timeRange === data2.timeRange);
|
|
27303
|
+
const hourOffset = Number.isFinite(data2.hourIndex) ? data2.hourIndex : fallbackIndex;
|
|
27304
|
+
const safeHourOffset = hourOffset >= 0 ? hourOffset : 0;
|
|
27305
|
+
const rangeStartDate = shiftStartDateTime ? addMinutes(shiftStartDateTime, safeHourOffset * 60 + range.start) : null;
|
|
27306
|
+
const rangeEndDate = shiftStartDateTime ? addMinutes(shiftStartDateTime, safeHourOffset * 60 + range.end + 1) : null;
|
|
27307
|
+
const reasonLabel = getIdleReasonForRange(rangeStartDate, rangeEndDate);
|
|
26952
27308
|
return /* @__PURE__ */ jsxs("div", { className: "text-gray-600 flex items-center gap-2 text-xs", children: [
|
|
26953
27309
|
/* @__PURE__ */ jsx("span", { className: "inline-block w-1.5 h-1.5 bg-orange-400 rounded-full flex-shrink-0" }),
|
|
26954
|
-
/* @__PURE__ */
|
|
26955
|
-
startTime,
|
|
26956
|
-
|
|
26957
|
-
|
|
26958
|
-
|
|
26959
|
-
|
|
26960
|
-
|
|
26961
|
-
|
|
26962
|
-
] })
|
|
26963
|
-
startTime,
|
|
26964
|
-
" - ",
|
|
26965
|
-
endTime,
|
|
26966
|
-
" ",
|
|
26967
|
-
/* @__PURE__ */ jsxs("span", { className: "text-gray-400", children: [
|
|
26968
|
-
"(",
|
|
26969
|
-
duration,
|
|
26970
|
-
" min)"
|
|
26971
|
-
] })
|
|
26972
|
-
] }) })
|
|
27310
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
27311
|
+
duration === 1 ? /* @__PURE__ */ jsx(Fragment, { children: startTime }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
27312
|
+
startTime,
|
|
27313
|
+
" - ",
|
|
27314
|
+
endTime
|
|
27315
|
+
] }),
|
|
27316
|
+
/* @__PURE__ */ jsx("span", { className: "text-gray-400", children: " | " }),
|
|
27317
|
+
/* @__PURE__ */ jsx("span", { className: "text-gray-600", children: reasonLabel })
|
|
27318
|
+
] })
|
|
26973
27319
|
] }, index);
|
|
26974
27320
|
}) })
|
|
26975
27321
|
] })
|
|
@@ -27067,7 +27413,7 @@ var HourlyOutputChartComponent = ({
|
|
|
27067
27413
|
);
|
|
27068
27414
|
};
|
|
27069
27415
|
var HourlyOutputChart = React24__default.memo(HourlyOutputChartComponent, (prevProps, nextProps) => {
|
|
27070
|
-
if (prevProps.pphThreshold !== nextProps.pphThreshold || prevProps.shiftStart !== nextProps.shiftStart || prevProps.showIdleTime !== nextProps.showIdleTime || prevProps.className !== nextProps.className) {
|
|
27416
|
+
if (prevProps.pphThreshold !== nextProps.pphThreshold || prevProps.shiftStart !== nextProps.shiftStart || prevProps.shiftEnd !== nextProps.shiftEnd || prevProps.shiftDate !== nextProps.shiftDate || prevProps.timezone !== nextProps.timezone || prevProps.showIdleTime !== nextProps.showIdleTime || prevProps.className !== nextProps.className) {
|
|
27071
27417
|
return false;
|
|
27072
27418
|
}
|
|
27073
27419
|
if (prevProps.data.length !== nextProps.data.length) {
|
|
@@ -27090,6 +27436,33 @@ var HourlyOutputChart = React24__default.memo(HourlyOutputChartComponent, (prevP
|
|
|
27090
27436
|
if (prevArray.length !== nextArray.length) return false;
|
|
27091
27437
|
if (!prevArray.every((val, idx) => val === nextArray[idx])) return false;
|
|
27092
27438
|
}
|
|
27439
|
+
const prevIdleClips = prevProps.idleTimeClips || [];
|
|
27440
|
+
const nextIdleClips = nextProps.idleTimeClips || [];
|
|
27441
|
+
if (prevIdleClips.length !== nextIdleClips.length) {
|
|
27442
|
+
return false;
|
|
27443
|
+
}
|
|
27444
|
+
for (let i = 0; i < prevIdleClips.length; i += 1) {
|
|
27445
|
+
const prevClip = prevIdleClips[i];
|
|
27446
|
+
const nextClip = nextIdleClips[i];
|
|
27447
|
+
if (prevClip.id !== nextClip.id || prevClip.idle_start_time !== nextClip.idle_start_time || prevClip.idle_end_time !== nextClip.idle_end_time) {
|
|
27448
|
+
return false;
|
|
27449
|
+
}
|
|
27450
|
+
}
|
|
27451
|
+
const prevClassifications = prevProps.idleTimeClipClassifications || {};
|
|
27452
|
+
const nextClassifications = nextProps.idleTimeClipClassifications || {};
|
|
27453
|
+
const prevClassKeys = Object.keys(prevClassifications);
|
|
27454
|
+
const nextClassKeys = Object.keys(nextClassifications);
|
|
27455
|
+
if (prevClassKeys.length !== nextClassKeys.length) {
|
|
27456
|
+
return false;
|
|
27457
|
+
}
|
|
27458
|
+
for (const key of prevClassKeys) {
|
|
27459
|
+
const prevClass = prevClassifications[key];
|
|
27460
|
+
const nextClass = nextClassifications[key];
|
|
27461
|
+
if (!nextClass) return false;
|
|
27462
|
+
if (prevClass.status !== nextClass.status || prevClass.label !== nextClass.label || prevClass.confidence !== nextClass.confidence) {
|
|
27463
|
+
return false;
|
|
27464
|
+
}
|
|
27465
|
+
}
|
|
27093
27466
|
return true;
|
|
27094
27467
|
});
|
|
27095
27468
|
HourlyOutputChart.displayName = "HourlyOutputChart";
|
|
@@ -27109,6 +27482,7 @@ var VideoCard = React24__default.memo(({
|
|
|
27109
27482
|
onClick,
|
|
27110
27483
|
onFatalError,
|
|
27111
27484
|
isVeryLowEfficiency = false,
|
|
27485
|
+
legend,
|
|
27112
27486
|
cropping,
|
|
27113
27487
|
canvasFps = 30,
|
|
27114
27488
|
useRAF = true,
|
|
@@ -27120,6 +27494,7 @@ var VideoCard = React24__default.memo(({
|
|
|
27120
27494
|
}) => {
|
|
27121
27495
|
const videoRef = useRef(null);
|
|
27122
27496
|
const canvasRef = useRef(null);
|
|
27497
|
+
const effectiveLegend = legend || DEFAULT_EFFICIENCY_LEGEND;
|
|
27123
27498
|
if (cropping) {
|
|
27124
27499
|
useHlsStreamWithCropping(videoRef, canvasRef, {
|
|
27125
27500
|
src: hlsUrl,
|
|
@@ -27137,39 +27512,23 @@ var VideoCard = React24__default.memo(({
|
|
|
27137
27512
|
});
|
|
27138
27513
|
}
|
|
27139
27514
|
const workspaceDisplayName = displayName || getWorkspaceDisplayName(workspace.workspace_name, workspace.line_id);
|
|
27140
|
-
const
|
|
27141
|
-
|
|
27142
|
-
|
|
27143
|
-
|
|
27144
|
-
return "bg-[#FFD700]/30";
|
|
27145
|
-
} else {
|
|
27146
|
-
return "bg-[#FF2D0A]/30";
|
|
27147
|
-
}
|
|
27148
|
-
};
|
|
27149
|
-
const getEfficiencyBarColor = (efficiency) => {
|
|
27150
|
-
if (efficiency >= 80) {
|
|
27151
|
-
return "bg-[#00AB45]";
|
|
27152
|
-
} else if (efficiency >= 70) {
|
|
27153
|
-
return "bg-[#FFB020]";
|
|
27154
|
-
} else {
|
|
27155
|
-
return "bg-[#E34329]";
|
|
27156
|
-
}
|
|
27157
|
-
};
|
|
27158
|
-
const efficiencyOverlayClass = getEfficiencyOverlayColor(workspace.efficiency);
|
|
27159
|
-
const efficiencyBarClass = getEfficiencyBarColor(workspace.efficiency);
|
|
27515
|
+
const efficiencyColor = getEfficiencyColor(workspace.efficiency, effectiveLegend);
|
|
27516
|
+
const efficiencyOverlayClass = efficiencyColor === "green" ? "bg-[#00D654]/25" : efficiencyColor === "yellow" ? "bg-[#FFD700]/30" : "bg-[#FF2D0A]/30";
|
|
27517
|
+
const efficiencyBarClass = efficiencyColor === "green" ? "bg-[#00AB45]" : efficiencyColor === "yellow" ? "bg-[#FFB020]" : "bg-[#E34329]";
|
|
27518
|
+
const efficiencyStatus = efficiencyColor === "green" ? "High" : efficiencyColor === "yellow" ? "Medium" : "Low";
|
|
27160
27519
|
const trendInfo = workspace.trend !== void 0 ? getTrendArrowAndColor(workspace.trend) : null;
|
|
27161
27520
|
const handleClick = useCallback(() => {
|
|
27162
27521
|
trackCoreEvent("Workspace Card Clicked", {
|
|
27163
27522
|
workspace_id: workspace.workspace_uuid,
|
|
27164
27523
|
workspace_name: workspace.workspace_name,
|
|
27165
27524
|
efficiency: workspace.efficiency,
|
|
27166
|
-
status:
|
|
27525
|
+
status: efficiencyStatus,
|
|
27167
27526
|
trend: workspace.trend
|
|
27168
27527
|
});
|
|
27169
27528
|
if (onClick) {
|
|
27170
27529
|
onClick();
|
|
27171
27530
|
}
|
|
27172
|
-
}, [onClick, workspace]);
|
|
27531
|
+
}, [onClick, workspace, efficiencyStatus]);
|
|
27173
27532
|
return /* @__PURE__ */ jsxs(
|
|
27174
27533
|
"div",
|
|
27175
27534
|
{
|
|
@@ -27272,6 +27631,7 @@ var VideoGridView = React24__default.memo(({
|
|
|
27272
27631
|
workspaces,
|
|
27273
27632
|
selectedLine,
|
|
27274
27633
|
className = "",
|
|
27634
|
+
legend,
|
|
27275
27635
|
videoSources = {},
|
|
27276
27636
|
displayNames = {},
|
|
27277
27637
|
onWorkspaceHover,
|
|
@@ -27287,6 +27647,7 @@ var VideoGridView = React24__default.memo(({
|
|
|
27287
27647
|
const videoConfig = useVideoConfig();
|
|
27288
27648
|
const dashboardConfig = useDashboardConfig();
|
|
27289
27649
|
const { cropping, canvasConfig, hlsUrls } = videoConfig;
|
|
27650
|
+
const effectiveLegend = legend || DEFAULT_EFFICIENCY_LEGEND;
|
|
27290
27651
|
const mergedVideoSources = {
|
|
27291
27652
|
defaultHlsUrl: videoSources.defaultHlsUrl || hlsUrls?.defaultHlsUrl || DEFAULT_HLS_URL,
|
|
27292
27653
|
workspaceHlsUrls: { ...videoSources.workspaceHlsUrls, ...hlsUrls?.workspaceHlsUrls },
|
|
@@ -27481,6 +27842,7 @@ var VideoGridView = React24__default.memo(({
|
|
|
27481
27842
|
onClick: () => handleWorkspaceClick(workspace),
|
|
27482
27843
|
onFatalError: () => handleStreamError(workspaceId),
|
|
27483
27844
|
isVeryLowEfficiency,
|
|
27845
|
+
legend: effectiveLegend,
|
|
27484
27846
|
cropping: workspaceCropping,
|
|
27485
27847
|
canvasFps: canvasConfig?.fps,
|
|
27486
27848
|
displayName: (
|
|
@@ -27508,10 +27870,12 @@ var MapGridView = React24__default.memo(({
|
|
|
27508
27870
|
className = "",
|
|
27509
27871
|
displayNames = {},
|
|
27510
27872
|
onWorkspaceHover,
|
|
27511
|
-
onWorkspaceHoverEnd
|
|
27873
|
+
onWorkspaceHoverEnd,
|
|
27874
|
+
legend
|
|
27512
27875
|
}) => {
|
|
27513
27876
|
const router = useRouter();
|
|
27514
27877
|
const dashboardConfig = useDashboardConfig();
|
|
27878
|
+
const effectiveLegend = legend || DEFAULT_EFFICIENCY_LEGEND;
|
|
27515
27879
|
const mapViewConfig = dashboardConfig?.mapViewConfig;
|
|
27516
27880
|
const workspacePositions = mapViewConfig?.workspacePositions || [];
|
|
27517
27881
|
const aspectRatio2 = mapViewConfig?.aspectRatio || 16 / 9;
|
|
@@ -27523,10 +27887,11 @@ var MapGridView = React24__default.memo(({
|
|
|
27523
27887
|
return map;
|
|
27524
27888
|
}, [workspaces]);
|
|
27525
27889
|
const getPerformanceColor = useCallback((efficiency) => {
|
|
27526
|
-
|
|
27527
|
-
if (
|
|
27890
|
+
const color2 = getEfficiencyColor(efficiency, effectiveLegend);
|
|
27891
|
+
if (color2 === "green") return "border-green-500 bg-green-50";
|
|
27892
|
+
if (color2 === "yellow") return "border-yellow-500 bg-yellow-50";
|
|
27528
27893
|
return "border-red-500 bg-red-50";
|
|
27529
|
-
}, []);
|
|
27894
|
+
}, [effectiveLegend]);
|
|
27530
27895
|
const handleWorkspaceClick = useCallback((workspace) => {
|
|
27531
27896
|
const workspaceId = workspace.workspace_uuid || workspace.workspace_name;
|
|
27532
27897
|
trackCoreEvent("Workspace Detail Clicked", {
|
|
@@ -27566,7 +27931,7 @@ var MapGridView = React24__default.memo(({
|
|
|
27566
27931
|
const workspace = workspaceMetricsMap.get(wsKey);
|
|
27567
27932
|
if (!workspace) return null;
|
|
27568
27933
|
const workspaceId = workspace.workspace_uuid || workspace.workspace_name;
|
|
27569
|
-
getPerformanceColor(workspace.efficiency);
|
|
27934
|
+
const performanceColor = getPerformanceColor(workspace.efficiency);
|
|
27570
27935
|
const showExclamation = workspace.show_exclamation ?? (workspace.efficiency < 50 && workspace.efficiency >= 10);
|
|
27571
27936
|
const workspaceDisplayName = displayNames[`${workspace.line_id}_${workspace.workspace_name}`] || // Always pass line_id to fallback to ensure correct mapping per line
|
|
27572
27937
|
getWorkspaceDisplayName(workspace.workspace_name, workspace.line_id);
|
|
@@ -27591,7 +27956,7 @@ var MapGridView = React24__default.memo(({
|
|
|
27591
27956
|
className: `
|
|
27592
27957
|
relative rounded-lg border-2 shadow-lg hover:shadow-xl
|
|
27593
27958
|
transition-all duration-200 hover:scale-105 bg-white
|
|
27594
|
-
${
|
|
27959
|
+
${performanceColor}
|
|
27595
27960
|
${position.size === "conveyor" ? "w-32 h-24" : position.size === "large" ? "w-40 h-32" : "w-36 h-28"}
|
|
27596
27961
|
`,
|
|
27597
27962
|
children: [
|
|
@@ -28172,7 +28537,7 @@ var PieChart4 = ({
|
|
|
28172
28537
|
}
|
|
28173
28538
|
);
|
|
28174
28539
|
};
|
|
28175
|
-
const
|
|
28540
|
+
const CustomTooltip4 = ({ active, payload }) => {
|
|
28176
28541
|
if (active && payload && payload.length) {
|
|
28177
28542
|
const data2 = payload[0];
|
|
28178
28543
|
return /* @__PURE__ */ jsxs("div", { className: "bg-white px-3 py-2 shadow-lg rounded-lg border border-gray-200", children: [
|
|
@@ -28203,7 +28568,7 @@ var PieChart4 = ({
|
|
|
28203
28568
|
children: dataWithPercentage.map((entry, index) => /* @__PURE__ */ jsx(Cell, { fill: colors[index % colors.length] }, `cell-${index}`))
|
|
28204
28569
|
}
|
|
28205
28570
|
),
|
|
28206
|
-
/* @__PURE__ */ jsx(Tooltip, { content: /* @__PURE__ */ jsx(
|
|
28571
|
+
/* @__PURE__ */ jsx(Tooltip, { content: /* @__PURE__ */ jsx(CustomTooltip4, {}) }),
|
|
28207
28572
|
/* @__PURE__ */ jsx(
|
|
28208
28573
|
Legend,
|
|
28209
28574
|
{
|
|
@@ -28415,31 +28780,6 @@ var WhatsAppShareButton = ({
|
|
|
28415
28780
|
}
|
|
28416
28781
|
);
|
|
28417
28782
|
};
|
|
28418
|
-
var AxelOrb = ({
|
|
28419
|
-
className = "",
|
|
28420
|
-
size = "md",
|
|
28421
|
-
animate = false
|
|
28422
|
-
}) => {
|
|
28423
|
-
const sizeClasses = {
|
|
28424
|
-
sm: "w-8 h-8",
|
|
28425
|
-
md: "w-10 h-10",
|
|
28426
|
-
lg: "w-12 h-12",
|
|
28427
|
-
xl: "w-16 h-16",
|
|
28428
|
-
"2xl": "w-20 h-20"
|
|
28429
|
-
};
|
|
28430
|
-
return /* @__PURE__ */ jsx(
|
|
28431
|
-
"div",
|
|
28432
|
-
{
|
|
28433
|
-
className: `${sizeClasses[size]} rounded-full ${animate ? "animate-float" : ""} ${className}`,
|
|
28434
|
-
style: {
|
|
28435
|
-
background: "linear-gradient(to top, #078DDB 0%, #65ADD6 33%, #A3D0E6 66%, #C7E2EC 100%)",
|
|
28436
|
-
boxShadow: "0 4px 12px rgba(7, 141, 219, 0.4), 0 0 20px rgba(7, 141, 219, 0.2)"
|
|
28437
|
-
},
|
|
28438
|
-
"aria-label": "Axel AI",
|
|
28439
|
-
role: "img"
|
|
28440
|
-
}
|
|
28441
|
-
);
|
|
28442
|
-
};
|
|
28443
28783
|
var BreakNotificationPopup = ({
|
|
28444
28784
|
activeBreaks,
|
|
28445
28785
|
onDismiss,
|
|
@@ -28527,7 +28867,7 @@ var BreakNotificationPopup = ({
|
|
|
28527
28867
|
className: "relative z-10",
|
|
28528
28868
|
children: /* @__PURE__ */ jsx("div", { className: "bg-white text-gray-900 rounded-lg border border-gray-200 shadow-xl overflow-hidden", children: /* @__PURE__ */ jsx("div", { className: "p-3", children: /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between", children: [
|
|
28529
28869
|
/* @__PURE__ */ jsxs("div", { className: "flex items-start space-x-3 flex-1", children: [
|
|
28530
|
-
/* @__PURE__ */ jsx("div", { className: "flex-shrink-0", children: /* @__PURE__ */ jsx(
|
|
28870
|
+
/* @__PURE__ */ jsx("div", { className: "flex-shrink-0", children: /* @__PURE__ */ jsx("div", { className: "w-10 h-10 rounded-full bg-amber-100 flex items-center justify-center", children: /* @__PURE__ */ jsx(Coffee, { className: "w-5 h-5 text-amber-600" }) }) }),
|
|
28531
28871
|
/* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
|
|
28532
28872
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 mb-1.5", children: [
|
|
28533
28873
|
/* @__PURE__ */ jsxs("h4", { className: "font-semibold text-sm text-gray-900", children: [
|
|
@@ -28800,7 +29140,11 @@ var AxelNotificationPopup = ({
|
|
|
28800
29140
|
className: "p-3",
|
|
28801
29141
|
children: /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between", children: [
|
|
28802
29142
|
/* @__PURE__ */ jsxs("div", { className: "flex items-start space-x-3 flex-1", children: [
|
|
28803
|
-
/* @__PURE__ */
|
|
29143
|
+
/* @__PURE__ */ jsxs("div", { className: "flex-shrink-0", children: [
|
|
29144
|
+
suggestion.type === "improvement" && /* @__PURE__ */ jsx("div", { className: "w-10 h-10 rounded-full bg-blue-100 flex items-center justify-center", children: /* @__PURE__ */ jsx(TrendingUp, { className: "w-5 h-5 text-blue-600" }) }),
|
|
29145
|
+
(suggestion.type === "alert" || suggestion.type === "bottleneck_triage") && /* @__PURE__ */ jsx("div", { className: "w-10 h-10 rounded-full bg-red-100 flex items-center justify-center", children: /* @__PURE__ */ jsx(AlertCircle, { className: "w-5 h-5 text-red-600" }) }),
|
|
29146
|
+
suggestion.type === "insight" && /* @__PURE__ */ jsx("div", { className: "w-10 h-10 rounded-full bg-purple-100 flex items-center justify-center", children: /* @__PURE__ */ jsx(Sparkles, { className: "w-5 h-5 text-purple-600" }) })
|
|
29147
|
+
] }),
|
|
28804
29148
|
/* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
|
|
28805
29149
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 mb-1.5", children: [
|
|
28806
29150
|
/* @__PURE__ */ jsx("h4", { className: "font-semibold text-sm text-gray-900", children: suggestion.title }),
|
|
@@ -29535,10 +29879,9 @@ var HlsVideoPlayer = forwardRef(({
|
|
|
29535
29879
|
fetchSetup: function(context, initParams) {
|
|
29536
29880
|
const url = context.url;
|
|
29537
29881
|
if (isR2WorkerUrl(url, r2WorkerDomain) && authToken) {
|
|
29538
|
-
initParams.headers
|
|
29539
|
-
|
|
29540
|
-
|
|
29541
|
-
};
|
|
29882
|
+
const headers = initParams.headers instanceof Headers ? initParams.headers : new Headers(initParams.headers || {});
|
|
29883
|
+
headers.set("Authorization", `Bearer ${authToken}`);
|
|
29884
|
+
initParams.headers = headers;
|
|
29542
29885
|
}
|
|
29543
29886
|
return new Request(url, initParams);
|
|
29544
29887
|
}
|
|
@@ -32861,126 +33204,6 @@ function useClipsRealtimeUpdates({
|
|
|
32861
33204
|
hasNewClips: newClipsNotification !== null && newClipsNotification.count > 0
|
|
32862
33205
|
};
|
|
32863
33206
|
}
|
|
32864
|
-
|
|
32865
|
-
// src/lib/services/clipClassificationService.ts
|
|
32866
|
-
function parseCleanLabel(rawLabel) {
|
|
32867
|
-
if (!rawLabel) return null;
|
|
32868
|
-
const patterns = [
|
|
32869
|
-
/"Clip Label"\s*:\s*"([^"]+)"/,
|
|
32870
|
-
// Old format
|
|
32871
|
-
/"clip_label"\s*:\s*"([^"]+)"/,
|
|
32872
|
-
// New format
|
|
32873
|
-
/'Clip Label'\s*:\s*'([^']+)'/,
|
|
32874
|
-
// Single quotes
|
|
32875
|
-
/'clip_label'\s*:\s*'([^']+)'/
|
|
32876
|
-
// Single quotes
|
|
32877
|
-
];
|
|
32878
|
-
for (const pattern of patterns) {
|
|
32879
|
-
const match = rawLabel.match(pattern);
|
|
32880
|
-
if (match) {
|
|
32881
|
-
const label = match[1].trim();
|
|
32882
|
-
return label.replace(/ /g, "_");
|
|
32883
|
-
}
|
|
32884
|
-
}
|
|
32885
|
-
return null;
|
|
32886
|
-
}
|
|
32887
|
-
async function fetchClassifications(clipIds, token) {
|
|
32888
|
-
if (!clipIds || clipIds.length === 0) {
|
|
32889
|
-
return {};
|
|
32890
|
-
}
|
|
32891
|
-
try {
|
|
32892
|
-
const CHUNK_SIZE = 50;
|
|
32893
|
-
const chunks = [];
|
|
32894
|
-
for (let i = 0; i < clipIds.length; i += CHUNK_SIZE) {
|
|
32895
|
-
chunks.push(clipIds.slice(i, i + CHUNK_SIZE));
|
|
32896
|
-
}
|
|
32897
|
-
console.log(`[fetchClassifications] Fetching ${clipIds.length} classifications in ${chunks.length} chunks`);
|
|
32898
|
-
const apiBase = process.env.NEXT_PUBLIC_BACKEND_URL || "http://localhost:8000";
|
|
32899
|
-
const chunkResults = await Promise.all(
|
|
32900
|
-
chunks.map(async (chunkIds) => {
|
|
32901
|
-
try {
|
|
32902
|
-
const response = await fetch(
|
|
32903
|
-
`${apiBase}/api/classification/batch?clip_ids=${chunkIds.join(",")}`,
|
|
32904
|
-
{
|
|
32905
|
-
headers: {
|
|
32906
|
-
"Authorization": `Bearer ${token}`,
|
|
32907
|
-
"Content-Type": "application/json"
|
|
32908
|
-
}
|
|
32909
|
-
}
|
|
32910
|
-
);
|
|
32911
|
-
if (!response.ok) {
|
|
32912
|
-
console.error(`Classification API error for chunk: ${response.status}`);
|
|
32913
|
-
return Object.fromEntries(
|
|
32914
|
-
chunkIds.map((id3) => [id3, { status: "processing" }])
|
|
32915
|
-
);
|
|
32916
|
-
}
|
|
32917
|
-
const data = await response.json();
|
|
32918
|
-
return data.classifications || {};
|
|
32919
|
-
} catch (error) {
|
|
32920
|
-
console.error("Error fetching chunk:", error);
|
|
32921
|
-
return Object.fromEntries(
|
|
32922
|
-
chunkIds.map((id3) => [id3, { status: "processing" }])
|
|
32923
|
-
);
|
|
32924
|
-
}
|
|
32925
|
-
})
|
|
32926
|
-
);
|
|
32927
|
-
const allClassifications = Object.assign({}, ...chunkResults);
|
|
32928
|
-
console.log(`[fetchClassifications] Total fetched: ${Object.keys(allClassifications).length} classifications`);
|
|
32929
|
-
return allClassifications;
|
|
32930
|
-
} catch (error) {
|
|
32931
|
-
console.error("Error fetching classifications:", error);
|
|
32932
|
-
return Object.fromEntries(
|
|
32933
|
-
clipIds.map((id3) => [id3, { status: "processing" }])
|
|
32934
|
-
);
|
|
32935
|
-
}
|
|
32936
|
-
}
|
|
32937
|
-
function useClassificationRealtimeUpdates({
|
|
32938
|
-
clipIds,
|
|
32939
|
-
enabled = true,
|
|
32940
|
-
onClassificationUpdate
|
|
32941
|
-
}) {
|
|
32942
|
-
const supabase = useSupabase();
|
|
32943
|
-
useEffect(() => {
|
|
32944
|
-
if (!enabled || !clipIds || clipIds.length === 0 || !supabase) {
|
|
32945
|
-
return;
|
|
32946
|
-
}
|
|
32947
|
-
const channelName = `classification:${clipIds.slice(0, 5).join("-")}`;
|
|
32948
|
-
console.log(`[useClassificationRealtimeUpdates] Subscribing to channel: ${channelName}`);
|
|
32949
|
-
const channel = supabase.channel(channelName).on(
|
|
32950
|
-
"postgres_changes",
|
|
32951
|
-
{
|
|
32952
|
-
event: "INSERT",
|
|
32953
|
-
schema: "public",
|
|
32954
|
-
table: "clip_classification",
|
|
32955
|
-
filter: `clip_id=in.(${clipIds.join(",")})`
|
|
32956
|
-
},
|
|
32957
|
-
(payload) => {
|
|
32958
|
-
console.log("[useClassificationRealtimeUpdates] New classification:", payload);
|
|
32959
|
-
try {
|
|
32960
|
-
const { clip_id, clip_label, confidence_score } = payload.new;
|
|
32961
|
-
const parsedLabel = parseCleanLabel(clip_label);
|
|
32962
|
-
if (parsedLabel) {
|
|
32963
|
-
onClassificationUpdate(clip_id, {
|
|
32964
|
-
status: "classified",
|
|
32965
|
-
label: parsedLabel,
|
|
32966
|
-
confidence: confidence_score || 0
|
|
32967
|
-
});
|
|
32968
|
-
} else {
|
|
32969
|
-
console.warn("[useClassificationRealtimeUpdates] Failed to parse label:", clip_label);
|
|
32970
|
-
}
|
|
32971
|
-
} catch (error) {
|
|
32972
|
-
console.error("[useClassificationRealtimeUpdates] Error processing update:", error);
|
|
32973
|
-
}
|
|
32974
|
-
}
|
|
32975
|
-
).subscribe((status) => {
|
|
32976
|
-
console.log(`[useClassificationRealtimeUpdates] Subscription status:`, status);
|
|
32977
|
-
});
|
|
32978
|
-
return () => {
|
|
32979
|
-
console.log(`[useClassificationRealtimeUpdates] Unsubscribing from ${channelName}`);
|
|
32980
|
-
supabase.removeChannel(channel);
|
|
32981
|
-
};
|
|
32982
|
-
}, [clipIds, enabled, supabase, onClassificationUpdate]);
|
|
32983
|
-
}
|
|
32984
33207
|
var BottlenecksContent = ({
|
|
32985
33208
|
workspaceId,
|
|
32986
33209
|
workspaceName,
|
|
@@ -36428,6 +36651,31 @@ var DetailedHealthStatus = ({
|
|
|
36428
36651
|
}
|
|
36429
36652
|
);
|
|
36430
36653
|
};
|
|
36654
|
+
var AxelOrb = ({
|
|
36655
|
+
className = "",
|
|
36656
|
+
size = "md",
|
|
36657
|
+
animate = false
|
|
36658
|
+
}) => {
|
|
36659
|
+
const sizeClasses = {
|
|
36660
|
+
sm: "w-8 h-8",
|
|
36661
|
+
md: "w-10 h-10",
|
|
36662
|
+
lg: "w-12 h-12",
|
|
36663
|
+
xl: "w-16 h-16",
|
|
36664
|
+
"2xl": "w-20 h-20"
|
|
36665
|
+
};
|
|
36666
|
+
return /* @__PURE__ */ jsx(
|
|
36667
|
+
"div",
|
|
36668
|
+
{
|
|
36669
|
+
className: `${sizeClasses[size]} rounded-full ${animate ? "animate-float" : ""} ${className}`,
|
|
36670
|
+
style: {
|
|
36671
|
+
background: "linear-gradient(to top, #078DDB 0%, #65ADD6 33%, #A3D0E6 66%, #C7E2EC 100%)",
|
|
36672
|
+
boxShadow: "0 4px 12px rgba(7, 141, 219, 0.4), 0 0 20px rgba(7, 141, 219, 0.2)"
|
|
36673
|
+
},
|
|
36674
|
+
"aria-label": "Axel AI",
|
|
36675
|
+
role: "img"
|
|
36676
|
+
}
|
|
36677
|
+
);
|
|
36678
|
+
};
|
|
36431
36679
|
var LinePdfExportButton = ({
|
|
36432
36680
|
targetElement,
|
|
36433
36681
|
fileName = "line-export",
|
|
@@ -36545,10 +36793,10 @@ var LineHistoryCalendar = ({
|
|
|
36545
36793
|
}, [configuredTimezone]);
|
|
36546
36794
|
const monthBounds = useMemo(() => getMonthKeyBounds(year, month), [year, month]);
|
|
36547
36795
|
const calendarData = useMemo(() => {
|
|
36548
|
-
const
|
|
36549
|
-
const
|
|
36550
|
-
const totalDays =
|
|
36551
|
-
let startOffset =
|
|
36796
|
+
const startOfMonth2 = toZonedTime(new Date(year, month, 1), configuredTimezone);
|
|
36797
|
+
const endOfMonth2 = toZonedTime(new Date(year, month + 1, 0), configuredTimezone);
|
|
36798
|
+
const totalDays = endOfMonth2.getDate();
|
|
36799
|
+
let startOffset = startOfMonth2.getDay() - 1;
|
|
36552
36800
|
if (startOffset === -1) startOffset = 6;
|
|
36553
36801
|
const calendar = Array(startOffset).fill(null);
|
|
36554
36802
|
for (let day = 1; day <= totalDays; day++) {
|
|
@@ -36579,12 +36827,13 @@ var LineHistoryCalendar = ({
|
|
|
36579
36827
|
if (shift.hasData !== void 0) return shift.hasData;
|
|
36580
36828
|
return shift.total_workspaces > 0 || shift.avg_efficiency > 0 || shift.underperforming_workspaces > 0;
|
|
36581
36829
|
};
|
|
36582
|
-
const getPerformanceColor = (efficiency, date, hasData) => {
|
|
36830
|
+
const getPerformanceColor = (efficiency, date, hasData, isFilteredOut = false) => {
|
|
36583
36831
|
const istNow = todayInZone;
|
|
36584
36832
|
const nowString = `${istNow.getFullYear()}-${String(istNow.getMonth() + 1).padStart(2, "0")}-${String(istNow.getDate()).padStart(2, "0")}`;
|
|
36585
36833
|
const dateString = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}-${String(date.getDate()).padStart(2, "0")}`;
|
|
36586
36834
|
if (dateString > nowString) return "bg-gray-200 dark:bg-gray-700";
|
|
36587
36835
|
if (!hasData) return "bg-gray-300 dark:bg-gray-600";
|
|
36836
|
+
if (isFilteredOut) return "bg-gray-200 dark:bg-gray-700";
|
|
36588
36837
|
return efficiency >= 75 ? "bg-green-500 dark:bg-green-600" : "bg-red-500 dark:bg-red-600";
|
|
36589
36838
|
};
|
|
36590
36839
|
const isCurrentDate = (date) => {
|
|
@@ -36629,12 +36878,13 @@ var LineHistoryCalendar = ({
|
|
|
36629
36878
|
const showRange = rangeStart && rangeEnd ? !(rangeStart === monthBounds.startKey && rangeEnd === monthBounds.endKey) : false;
|
|
36630
36879
|
const inRange = showRange ? dateKey >= rangeStart && dateKey <= rangeEnd : false;
|
|
36631
36880
|
const isRangeEdge = inRange && (dateKey === rangeStart || dateKey === rangeEnd);
|
|
36881
|
+
const isFilteredOut = showRange && !inRange;
|
|
36632
36882
|
return /* @__PURE__ */ jsx(
|
|
36633
36883
|
"div",
|
|
36634
36884
|
{
|
|
36635
|
-
className: `group h-full ${isFuture || !hasData ? "cursor-not-allowed" : "cursor-pointer hover:opacity-90"}`,
|
|
36885
|
+
className: `group h-full ${isFuture || !hasData || isFilteredOut ? "cursor-not-allowed" : "cursor-pointer hover:opacity-90"}`,
|
|
36636
36886
|
onClick: () => {
|
|
36637
|
-
if (!isFuture && hasData) {
|
|
36887
|
+
if (!isFuture && hasData && !isFilteredOut) {
|
|
36638
36888
|
const dateObj2 = day.date instanceof Date ? day.date : new Date(day.date);
|
|
36639
36889
|
const year2 = dateObj2.getFullYear();
|
|
36640
36890
|
const month2 = String(dateObj2.getMonth() + 1).padStart(2, "0");
|
|
@@ -36666,7 +36916,7 @@ var LineHistoryCalendar = ({
|
|
|
36666
36916
|
}
|
|
36667
36917
|
},
|
|
36668
36918
|
children: /* @__PURE__ */ jsxs("div", { className: `
|
|
36669
|
-
${getPerformanceColor(shiftData.avg_efficiency || 0, dateObj, hasData)}
|
|
36919
|
+
${getPerformanceColor(shiftData.avg_efficiency || 0, dateObj, hasData, isFilteredOut)}
|
|
36670
36920
|
rounded-lg h-full p-2 relative
|
|
36671
36921
|
${isToday2 ? "ring-2 ring-blue-500 dark:ring-blue-400 ring-offset-2 dark:ring-offset-gray-800 shadow-md" : ""}
|
|
36672
36922
|
`, children: [
|
|
@@ -36677,10 +36927,11 @@ var LineHistoryCalendar = ({
|
|
|
36677
36927
|
}
|
|
36678
36928
|
),
|
|
36679
36929
|
/* @__PURE__ */ jsx("div", { className: `
|
|
36680
|
-
text-base font-medium
|
|
36930
|
+
text-base font-medium flex items-center relative z-10
|
|
36931
|
+
${hasData && !isFuture && !isFilteredOut ? "text-white" : "text-gray-400"}
|
|
36681
36932
|
${isToday2 ? "bg-blue-500 dark:bg-blue-600 rounded-full w-7 h-7 justify-center" : ""}
|
|
36682
36933
|
`, children: dateObj.getDate() }),
|
|
36683
|
-
!isFuture && hasData && renderStats(shiftData, dateObj)
|
|
36934
|
+
!isFuture && hasData && !isFilteredOut && renderStats(shiftData, dateObj)
|
|
36684
36935
|
] })
|
|
36685
36936
|
}
|
|
36686
36937
|
);
|
|
@@ -36855,54 +37106,19 @@ var IdleTimeReasonChart = ({
|
|
|
36855
37106
|
] });
|
|
36856
37107
|
};
|
|
36857
37108
|
var IdleTimeReasonChart_default = IdleTimeReasonChart;
|
|
37109
|
+
var WEEKDAYS2 = ["S", "M", "T", "W", "T", "F", "S"];
|
|
36858
37110
|
var MonthlyRangeFilter = ({
|
|
36859
37111
|
month,
|
|
36860
37112
|
year,
|
|
36861
|
-
timezone,
|
|
36862
37113
|
value,
|
|
36863
37114
|
onChange,
|
|
37115
|
+
onMonthNavigate,
|
|
36864
37116
|
className
|
|
36865
37117
|
}) => {
|
|
36866
37118
|
const monthBounds = useMemo(() => getMonthKeyBounds(year, month), [year, month]);
|
|
36867
|
-
const weekRanges = useMemo(() => getMonthWeekRanges(year, month, timezone), [year, month, timezone]);
|
|
36868
37119
|
const normalizedRange = useMemo(() => {
|
|
36869
37120
|
return normalizeDateKeyRange(value.startKey, value.endKey, monthBounds.startKey, monthBounds.endKey);
|
|
36870
37121
|
}, [value.startKey, value.endKey, monthBounds.startKey, monthBounds.endKey]);
|
|
36871
|
-
const monthLabel = useMemo(() => {
|
|
36872
|
-
return new Date(year, month).toLocaleString("default", { month: "long", year: "numeric" });
|
|
36873
|
-
}, [year, month]);
|
|
36874
|
-
const presetOptions = useMemo(() => {
|
|
36875
|
-
const fullMonthRangeLabel = `${formatDateKeyForDisplay(monthBounds.startKey, "MMM d")} - ${formatDateKeyForDisplay(monthBounds.endKey, "MMM d")}`;
|
|
36876
|
-
const presets = [
|
|
36877
|
-
{
|
|
36878
|
-
id: "full-month",
|
|
36879
|
-
label: "Full month",
|
|
36880
|
-
rangeLabel: fullMonthRangeLabel,
|
|
36881
|
-
startKey: monthBounds.startKey,
|
|
36882
|
-
endKey: monthBounds.endKey
|
|
36883
|
-
}
|
|
36884
|
-
];
|
|
36885
|
-
weekRanges.forEach((range, index) => {
|
|
36886
|
-
const rangeLabel = `${formatDateKeyForDisplay(range.startKey, "MMM d")} - ${formatDateKeyForDisplay(range.endKey, "MMM d")}`;
|
|
36887
|
-
presets.push({
|
|
36888
|
-
id: `week-${index + 1}`,
|
|
36889
|
-
label: `Week ${index + 1}`,
|
|
36890
|
-
rangeLabel,
|
|
36891
|
-
startKey: range.startKey,
|
|
36892
|
-
endKey: range.endKey
|
|
36893
|
-
});
|
|
36894
|
-
});
|
|
36895
|
-
return presets;
|
|
36896
|
-
}, [monthBounds.startKey, monthBounds.endKey, weekRanges]);
|
|
36897
|
-
const activePreset = useMemo(() => {
|
|
36898
|
-
return presetOptions.find(
|
|
36899
|
-
(preset) => preset.startKey === normalizedRange.startKey && preset.endKey === normalizedRange.endKey
|
|
36900
|
-
);
|
|
36901
|
-
}, [presetOptions, normalizedRange.startKey, normalizedRange.endKey]);
|
|
36902
|
-
const displayLabel = useMemo(() => {
|
|
36903
|
-
if (activePreset) return activePreset.label;
|
|
36904
|
-
return "Custom range";
|
|
36905
|
-
}, [activePreset]);
|
|
36906
37122
|
const fullMonthLabel = useMemo(() => {
|
|
36907
37123
|
const startLabel = formatDateKeyForDisplay(monthBounds.startKey, "MMM d");
|
|
36908
37124
|
const endLabel = formatDateKeyForDisplay(monthBounds.endKey, "MMM d, yyyy");
|
|
@@ -36911,14 +37127,26 @@ var MonthlyRangeFilter = ({
|
|
|
36911
37127
|
const displayRange = useMemo(() => {
|
|
36912
37128
|
return formatRangeLabel(normalizedRange, fullMonthLabel);
|
|
36913
37129
|
}, [normalizedRange, fullMonthLabel]);
|
|
36914
|
-
const [customStart, setCustomStart] = useState(normalizedRange.startKey);
|
|
36915
|
-
const [customEnd, setCustomEnd] = useState(normalizedRange.endKey);
|
|
36916
37130
|
const [isOpen, setIsOpen] = useState(false);
|
|
36917
37131
|
const dropdownRef = useRef(null);
|
|
37132
|
+
const [calendarMonth, setCalendarMonth] = useState(month);
|
|
37133
|
+
const [calendarYear, setCalendarYear] = useState(year);
|
|
37134
|
+
const [rangeStart, setRangeStart] = useState(parseDateKeyToDate(normalizedRange.startKey));
|
|
37135
|
+
const [rangeEnd, setRangeEnd] = useState(parseDateKeyToDate(normalizedRange.endKey));
|
|
37136
|
+
const [selecting, setSelecting] = useState(false);
|
|
36918
37137
|
useEffect(() => {
|
|
36919
|
-
|
|
36920
|
-
|
|
36921
|
-
}, [
|
|
37138
|
+
setCalendarMonth(month);
|
|
37139
|
+
setCalendarYear(year);
|
|
37140
|
+
}, [month, year]);
|
|
37141
|
+
useEffect(() => {
|
|
37142
|
+
if (isOpen) {
|
|
37143
|
+
setRangeStart(parseDateKeyToDate(normalizedRange.startKey));
|
|
37144
|
+
setRangeEnd(parseDateKeyToDate(normalizedRange.endKey));
|
|
37145
|
+
setSelecting(false);
|
|
37146
|
+
setCalendarMonth(month);
|
|
37147
|
+
setCalendarYear(year);
|
|
37148
|
+
}
|
|
37149
|
+
}, [isOpen, normalizedRange.startKey, normalizedRange.endKey, month, year]);
|
|
36922
37150
|
useEffect(() => {
|
|
36923
37151
|
const handleClickOutside = (event) => {
|
|
36924
37152
|
if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
|
|
@@ -36928,107 +37156,211 @@ var MonthlyRangeFilter = ({
|
|
|
36928
37156
|
document.addEventListener("mousedown", handleClickOutside);
|
|
36929
37157
|
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
36930
37158
|
}, []);
|
|
36931
|
-
const
|
|
36932
|
-
|
|
36933
|
-
|
|
36934
|
-
|
|
37159
|
+
const handleDayClick = (day) => {
|
|
37160
|
+
if (!selecting || !rangeStart) {
|
|
37161
|
+
setRangeStart(day);
|
|
37162
|
+
setRangeEnd(null);
|
|
37163
|
+
setSelecting(true);
|
|
37164
|
+
} else {
|
|
37165
|
+
if (day < rangeStart) {
|
|
37166
|
+
setRangeEnd(rangeStart);
|
|
37167
|
+
setRangeStart(day);
|
|
37168
|
+
} else {
|
|
37169
|
+
setRangeEnd(day);
|
|
37170
|
+
}
|
|
37171
|
+
setSelecting(false);
|
|
37172
|
+
}
|
|
36935
37173
|
};
|
|
36936
|
-
const
|
|
36937
|
-
if (
|
|
36938
|
-
|
|
36939
|
-
|
|
36940
|
-
|
|
37174
|
+
const handleApply = () => {
|
|
37175
|
+
if (rangeStart) {
|
|
37176
|
+
const endDate = rangeEnd || rangeStart;
|
|
37177
|
+
const startKey = format(rangeStart, "yyyy-MM-dd");
|
|
37178
|
+
const endKey = format(endDate, "yyyy-MM-dd");
|
|
37179
|
+
const normalized = normalizeDateKeyRange(startKey, endKey, monthBounds.startKey, monthBounds.endKey);
|
|
37180
|
+
onChange(normalized);
|
|
37181
|
+
setIsOpen(false);
|
|
37182
|
+
}
|
|
37183
|
+
};
|
|
37184
|
+
const handlePreviousMonth = () => {
|
|
37185
|
+
const prevMonthDate = subMonths(new Date(calendarYear, calendarMonth), 1);
|
|
37186
|
+
const newMonth = prevMonthDate.getMonth();
|
|
37187
|
+
const newYear = prevMonthDate.getFullYear();
|
|
37188
|
+
if (newYear < 2023) return;
|
|
37189
|
+
setCalendarMonth(newMonth);
|
|
37190
|
+
setCalendarYear(newYear);
|
|
37191
|
+
onMonthNavigate?.(newMonth, newYear);
|
|
36941
37192
|
};
|
|
37193
|
+
const handleNextMonth = () => {
|
|
37194
|
+
const nextMonthDate = addMonths(new Date(calendarYear, calendarMonth), 1);
|
|
37195
|
+
const newMonth = nextMonthDate.getMonth();
|
|
37196
|
+
const newYear = nextMonthDate.getFullYear();
|
|
37197
|
+
const currentDate = /* @__PURE__ */ new Date();
|
|
37198
|
+
if (newYear > currentDate.getFullYear() || newYear === currentDate.getFullYear() && newMonth > currentDate.getMonth()) {
|
|
37199
|
+
return;
|
|
37200
|
+
}
|
|
37201
|
+
setCalendarMonth(newMonth);
|
|
37202
|
+
setCalendarYear(newYear);
|
|
37203
|
+
onMonthNavigate?.(newMonth, newYear);
|
|
37204
|
+
};
|
|
37205
|
+
const canGoPrevious = !(calendarYear === 2023 && calendarMonth === 0);
|
|
37206
|
+
const canGoNext = !(calendarYear === (/* @__PURE__ */ new Date()).getFullYear() && calendarMonth === (/* @__PURE__ */ new Date()).getMonth());
|
|
37207
|
+
const monthDate = useMemo(() => new Date(calendarYear, calendarMonth), [calendarYear, calendarMonth]);
|
|
37208
|
+
const calendarDays = useMemo(() => {
|
|
37209
|
+
const start = startOfMonth(monthDate);
|
|
37210
|
+
const end = endOfMonth(monthDate);
|
|
37211
|
+
const days = eachDayOfInterval({ start, end });
|
|
37212
|
+
const startDayOfWeek = getDay(start);
|
|
37213
|
+
const emptySlots = Array(startDayOfWeek).fill(null);
|
|
37214
|
+
return [...emptySlots, ...days];
|
|
37215
|
+
}, [monthDate]);
|
|
37216
|
+
const isInRange = useCallback((day) => {
|
|
37217
|
+
if (!rangeStart) return false;
|
|
37218
|
+
if (!rangeEnd) return isSameDay(day, rangeStart);
|
|
37219
|
+
return isWithinInterval(day, {
|
|
37220
|
+
start: startOfDay(rangeStart),
|
|
37221
|
+
end: startOfDay(rangeEnd)
|
|
37222
|
+
});
|
|
37223
|
+
}, [rangeStart, rangeEnd]);
|
|
37224
|
+
const isRangeStart = useCallback((day) => {
|
|
37225
|
+
return rangeStart && isSameDay(day, rangeStart);
|
|
37226
|
+
}, [rangeStart]);
|
|
37227
|
+
const isRangeEnd = useCallback((day) => {
|
|
37228
|
+
return rangeEnd && isSameDay(day, rangeEnd);
|
|
37229
|
+
}, [rangeEnd]);
|
|
37230
|
+
const monthName = format(monthDate, "MMMM yyyy");
|
|
37231
|
+
const startDisplay = rangeStart ? format(rangeStart, "MMM d, yyyy") : "Start Date";
|
|
37232
|
+
const endDisplay = rangeEnd ? format(rangeEnd, "MMM d, yyyy") : "End Date";
|
|
36942
37233
|
return /* @__PURE__ */ jsxs("div", { className: `relative ${className ?? ""}`, ref: dropdownRef, children: [
|
|
36943
37234
|
/* @__PURE__ */ jsxs(
|
|
36944
37235
|
"button",
|
|
36945
37236
|
{
|
|
36946
37237
|
type: "button",
|
|
36947
37238
|
onClick: () => setIsOpen((prev) => !prev),
|
|
36948
|
-
className:
|
|
37239
|
+
className: clsx(
|
|
37240
|
+
"flex items-center gap-2 rounded-lg border bg-white px-3 py-2 text-left shadow-sm transition-all duration-200 focus:outline-none",
|
|
37241
|
+
isOpen ? "border-blue-500 ring-2 ring-blue-500/20" : "border-gray-200 hover:border-gray-300 hover:shadow"
|
|
37242
|
+
),
|
|
36949
37243
|
children: [
|
|
36950
|
-
/* @__PURE__ */ jsx(CalendarIcon, { className: "h-4 w-4 text-
|
|
36951
|
-
/* @__PURE__ */
|
|
36952
|
-
/* @__PURE__ */ jsx("span", { className: "text-[11px] uppercase tracking-[0.2em] text-slate-500", children: displayLabel }),
|
|
36953
|
-
/* @__PURE__ */ jsx("span", { className: "text-sm font-semibold text-slate-900", children: displayRange })
|
|
36954
|
-
] }),
|
|
37244
|
+
/* @__PURE__ */ jsx(CalendarIcon, { className: "h-4 w-4 text-gray-400" }),
|
|
37245
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-gray-900", children: displayRange }),
|
|
36955
37246
|
/* @__PURE__ */ jsx(
|
|
36956
37247
|
ChevronDownIcon,
|
|
36957
37248
|
{
|
|
36958
|
-
className:
|
|
37249
|
+
className: clsx(
|
|
37250
|
+
"ml-2 h-4 w-4 text-gray-400 transition-transform duration-200",
|
|
37251
|
+
isOpen && "rotate-180"
|
|
37252
|
+
)
|
|
36959
37253
|
}
|
|
36960
37254
|
)
|
|
36961
37255
|
]
|
|
36962
37256
|
}
|
|
36963
37257
|
),
|
|
36964
|
-
isOpen && /* @__PURE__ */
|
|
36965
|
-
/* @__PURE__ */
|
|
36966
|
-
|
|
36967
|
-
|
|
36968
|
-
|
|
37258
|
+
isOpen && /* @__PURE__ */ jsxs("div", { className: "absolute right-0 z-50 mt-2 w-[320px] overflow-hidden rounded-lg border border-gray-200 bg-white shadow-xl p-4 animate-in fade-in zoom-in-95 duration-200", children: [
|
|
37259
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 mb-4 pb-4 border-b border-gray-100", children: [
|
|
37260
|
+
/* @__PURE__ */ jsxs("div", { className: "flex-1", children: [
|
|
37261
|
+
/* @__PURE__ */ jsx("label", { className: "block text-[10px] uppercase tracking-wider font-medium text-gray-500 mb-1", children: "Start" }),
|
|
37262
|
+
/* @__PURE__ */ jsx("div", { className: clsx(
|
|
37263
|
+
"px-2 py-1.5 rounded-md text-sm font-medium border transition-colors",
|
|
37264
|
+
rangeStart ? "bg-blue-50 border-blue-200 text-blue-700" : "bg-gray-50 border-gray-100 text-gray-400"
|
|
37265
|
+
), children: startDisplay })
|
|
37266
|
+
] }),
|
|
37267
|
+
/* @__PURE__ */ jsx("div", { className: "pt-4 text-gray-300", children: /* @__PURE__ */ jsx(ChevronRightIcon, { className: "h-4 w-4" }) }),
|
|
37268
|
+
/* @__PURE__ */ jsxs("div", { className: "flex-1", children: [
|
|
37269
|
+
/* @__PURE__ */ jsx("label", { className: "block text-[10px] uppercase tracking-wider font-medium text-gray-500 mb-1", children: "End" }),
|
|
37270
|
+
/* @__PURE__ */ jsx("div", { className: clsx(
|
|
37271
|
+
"px-2 py-1.5 rounded-md text-sm font-medium border transition-colors",
|
|
37272
|
+
rangeEnd ? "bg-blue-50 border-blue-200 text-blue-700" : "bg-gray-50 border-gray-100 text-gray-400"
|
|
37273
|
+
), children: endDisplay })
|
|
37274
|
+
] })
|
|
37275
|
+
] }),
|
|
37276
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between mb-4", children: [
|
|
37277
|
+
/* @__PURE__ */ jsx(
|
|
36969
37278
|
"button",
|
|
36970
37279
|
{
|
|
36971
37280
|
type: "button",
|
|
36972
|
-
onClick:
|
|
36973
|
-
|
|
36974
|
-
|
|
36975
|
-
|
|
36976
|
-
|
|
36977
|
-
|
|
37281
|
+
onClick: handlePreviousMonth,
|
|
37282
|
+
disabled: !canGoPrevious,
|
|
37283
|
+
className: clsx(
|
|
37284
|
+
"p-1 rounded-md transition-colors",
|
|
37285
|
+
canGoPrevious ? "hover:bg-gray-100 text-gray-600" : "text-gray-300 cursor-not-allowed"
|
|
37286
|
+
),
|
|
37287
|
+
"aria-label": "Previous month",
|
|
37288
|
+
children: /* @__PURE__ */ jsx(ChevronLeftIcon, { className: "h-5 w-5" })
|
|
37289
|
+
}
|
|
37290
|
+
),
|
|
37291
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm font-semibold text-gray-900", children: monthName }),
|
|
37292
|
+
/* @__PURE__ */ jsx(
|
|
37293
|
+
"button",
|
|
37294
|
+
{
|
|
37295
|
+
type: "button",
|
|
37296
|
+
onClick: handleNextMonth,
|
|
37297
|
+
disabled: !canGoNext,
|
|
37298
|
+
className: clsx(
|
|
37299
|
+
"p-1 rounded-md transition-colors",
|
|
37300
|
+
canGoNext ? "hover:bg-gray-100 text-gray-600" : "text-gray-300 cursor-not-allowed"
|
|
37301
|
+
),
|
|
37302
|
+
"aria-label": "Next month",
|
|
37303
|
+
children: /* @__PURE__ */ jsx(ChevronRightIcon, { className: "h-5 w-5" })
|
|
37304
|
+
}
|
|
37305
|
+
)
|
|
37306
|
+
] }),
|
|
37307
|
+
/* @__PURE__ */ jsx("div", { className: "grid grid-cols-7 gap-1 mb-2", children: WEEKDAYS2.map((day, i) => /* @__PURE__ */ jsx("div", { className: "h-8 flex items-center justify-center text-xs font-medium text-gray-400", children: day }, i)) }),
|
|
37308
|
+
/* @__PURE__ */ jsx("div", { className: "grid grid-cols-7 gap-0", children: calendarDays.map((day, i) => {
|
|
37309
|
+
if (!day) {
|
|
37310
|
+
return /* @__PURE__ */ jsx("div", { className: "h-10" }, `empty-${i}`);
|
|
37311
|
+
}
|
|
37312
|
+
const inRange = isInRange(day);
|
|
37313
|
+
const isStart = isRangeStart(day);
|
|
37314
|
+
const isEnd = isRangeEnd(day);
|
|
37315
|
+
const isSingleDaySelection = isStart && (!rangeEnd || rangeEnd && isSameDay(rangeStart, rangeEnd));
|
|
37316
|
+
const hasSelection = rangeStart !== null;
|
|
37317
|
+
const dayNum = day.getDate();
|
|
37318
|
+
return /* @__PURE__ */ jsx(
|
|
37319
|
+
"button",
|
|
37320
|
+
{
|
|
37321
|
+
type: "button",
|
|
37322
|
+
onClick: () => handleDayClick(day),
|
|
37323
|
+
className: clsx(
|
|
37324
|
+
"h-10 w-full flex items-center justify-center text-sm font-medium transition-all duration-150 relative",
|
|
37325
|
+
// Not in range - fade when there's a selection
|
|
37326
|
+
!inRange && hasSelection && "text-gray-300 hover:text-gray-500 hover:bg-gray-50 rounded-md",
|
|
37327
|
+
!inRange && !hasSelection && "text-gray-700 hover:bg-gray-100 rounded-md",
|
|
37328
|
+
// Middle of range - subtle highlight
|
|
37329
|
+
inRange && !isStart && !isEnd && "bg-blue-50 text-blue-600",
|
|
37330
|
+
// Start of range
|
|
37331
|
+
isStart && !isSingleDaySelection && "bg-blue-600 text-white rounded-l-md shadow-sm z-10",
|
|
37332
|
+
// End of range
|
|
37333
|
+
isEnd && !isSingleDaySelection && "bg-blue-600 text-white rounded-r-md shadow-sm z-10",
|
|
37334
|
+
// Single day selection
|
|
37335
|
+
isSingleDaySelection && "bg-blue-600 text-white rounded-md shadow-sm z-10"
|
|
37336
|
+
),
|
|
37337
|
+
children: dayNum
|
|
36978
37338
|
},
|
|
36979
|
-
|
|
37339
|
+
day.toISOString()
|
|
36980
37340
|
);
|
|
36981
37341
|
}) }),
|
|
36982
|
-
/* @__PURE__ */ jsxs("div", { className: "mt-
|
|
36983
|
-
/* @__PURE__ */
|
|
36984
|
-
|
|
36985
|
-
|
|
36986
|
-
|
|
36987
|
-
|
|
36988
|
-
|
|
36989
|
-
|
|
36990
|
-
|
|
36991
|
-
|
|
36992
|
-
{
|
|
36993
|
-
type: "date",
|
|
36994
|
-
value: customStart,
|
|
36995
|
-
onChange: (event) => setCustomStart(event.target.value),
|
|
36996
|
-
min: monthBounds.startKey,
|
|
36997
|
-
max: monthBounds.endKey,
|
|
36998
|
-
className: "mt-1 w-full rounded-md border border-slate-200 bg-white px-2 py-2 text-sm text-slate-700 focus:border-blue-500 focus:outline-none focus:ring-2 focus:ring-blue-200"
|
|
36999
|
-
}
|
|
37000
|
-
)
|
|
37001
|
-
] }),
|
|
37002
|
-
/* @__PURE__ */ jsxs("div", { children: [
|
|
37003
|
-
/* @__PURE__ */ jsx("label", { className: "block text-[11px] font-medium text-slate-600", children: "End" }),
|
|
37004
|
-
/* @__PURE__ */ jsx(
|
|
37005
|
-
"input",
|
|
37006
|
-
{
|
|
37007
|
-
type: "date",
|
|
37008
|
-
value: customEnd,
|
|
37009
|
-
onChange: (event) => setCustomEnd(event.target.value),
|
|
37010
|
-
min: monthBounds.startKey,
|
|
37011
|
-
max: monthBounds.endKey,
|
|
37012
|
-
className: "mt-1 w-full rounded-md border border-slate-200 bg-white px-2 py-2 text-sm text-slate-700 focus:border-blue-500 focus:outline-none focus:ring-2 focus:ring-blue-200"
|
|
37013
|
-
}
|
|
37014
|
-
)
|
|
37015
|
-
] })
|
|
37016
|
-
] }),
|
|
37342
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-2 mt-4 pt-4 border-t border-gray-100", children: [
|
|
37343
|
+
/* @__PURE__ */ jsx(
|
|
37344
|
+
"button",
|
|
37345
|
+
{
|
|
37346
|
+
type: "button",
|
|
37347
|
+
onClick: () => setIsOpen(false),
|
|
37348
|
+
className: "rounded-lg px-3 py-1.5 text-sm font-medium text-gray-600 hover:bg-gray-50 hover:text-gray-900 transition-colors",
|
|
37349
|
+
children: "Cancel"
|
|
37350
|
+
}
|
|
37351
|
+
),
|
|
37017
37352
|
/* @__PURE__ */ jsx(
|
|
37018
37353
|
"button",
|
|
37019
37354
|
{
|
|
37020
37355
|
type: "button",
|
|
37021
|
-
onClick:
|
|
37022
|
-
|
|
37023
|
-
|
|
37356
|
+
onClick: handleApply,
|
|
37357
|
+
disabled: !rangeStart,
|
|
37358
|
+
className: "rounded-lg bg-blue-600 px-4 py-1.5 text-sm font-medium text-white shadow-sm hover:bg-blue-700 disabled:opacity-50 disabled:cursor-not-allowed transition-all",
|
|
37359
|
+
children: "Apply"
|
|
37024
37360
|
}
|
|
37025
37361
|
)
|
|
37026
|
-
] }),
|
|
37027
|
-
/* @__PURE__ */ jsxs("div", { className: "mt-3 text-xs text-slate-400", children: [
|
|
37028
|
-
"Month: ",
|
|
37029
|
-
monthLabel
|
|
37030
37362
|
] })
|
|
37031
|
-
] })
|
|
37363
|
+
] })
|
|
37032
37364
|
] });
|
|
37033
37365
|
};
|
|
37034
37366
|
var MonthlyRangeFilter_default = MonthlyRangeFilter;
|
|
@@ -37036,7 +37368,36 @@ var DEFAULT_PERFORMANCE_DATA = {
|
|
|
37036
37368
|
avg_efficiency: 0,
|
|
37037
37369
|
underperforming_workspaces: 0,
|
|
37038
37370
|
total_workspaces: 0,
|
|
37039
|
-
hasData: false
|
|
37371
|
+
hasData: false,
|
|
37372
|
+
output: 0,
|
|
37373
|
+
idealOutput: 0
|
|
37374
|
+
};
|
|
37375
|
+
var getOrdinal = (n) => {
|
|
37376
|
+
const suffix = ["th", "st", "nd", "rd"];
|
|
37377
|
+
const v = n % 100;
|
|
37378
|
+
return n + (suffix[(v - 20) % 10] || suffix[v] || suffix[0]);
|
|
37379
|
+
};
|
|
37380
|
+
var CustomTooltip2 = ({ active, payload, label }) => {
|
|
37381
|
+
if (active && payload && payload.length) {
|
|
37382
|
+
return /* @__PURE__ */ jsxs("div", { className: "bg-white/95 backdrop-blur-sm p-3 rounded-lg shadow-lg border border-gray-100", children: [
|
|
37383
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm font-semibold text-gray-800 mb-1", children: label }),
|
|
37384
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
|
|
37385
|
+
/* @__PURE__ */ jsxs("p", { className: "text-xs text-gray-600", children: [
|
|
37386
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium", children: "Actual:" }),
|
|
37387
|
+
" ",
|
|
37388
|
+
Math.round(payload[0].value),
|
|
37389
|
+
" units"
|
|
37390
|
+
] }),
|
|
37391
|
+
payload[0].payload.idealOutput > 0 && /* @__PURE__ */ jsxs("p", { className: "text-xs text-gray-600", children: [
|
|
37392
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium", children: "Target:" }),
|
|
37393
|
+
" ",
|
|
37394
|
+
Math.round(payload[0].payload.idealOutput),
|
|
37395
|
+
" units"
|
|
37396
|
+
] })
|
|
37397
|
+
] })
|
|
37398
|
+
] });
|
|
37399
|
+
}
|
|
37400
|
+
return null;
|
|
37040
37401
|
};
|
|
37041
37402
|
var getShiftData2 = (day, shiftId) => {
|
|
37042
37403
|
const shift = day.shifts[shiftId];
|
|
@@ -37075,7 +37436,7 @@ var LineMonthlyHistory = ({
|
|
|
37075
37436
|
}, [rangeStart, rangeEnd, monthBounds.startKey, monthBounds.endKey]);
|
|
37076
37437
|
const isFullRange = useMemo(() => isFullMonthRange(normalizedRange, year, month), [normalizedRange, year, month]);
|
|
37077
37438
|
const monthLabel = useMemo(() => new Date(year, month).toLocaleString("default", { month: "long" }), [year, month]);
|
|
37078
|
-
|
|
37439
|
+
useMemo(() => {
|
|
37079
37440
|
return isFullRange ? monthLabel : formatRangeLabel(normalizedRange, monthLabel);
|
|
37080
37441
|
}, [isFullRange, normalizedRange, monthLabel]);
|
|
37081
37442
|
const analysisMonthlyData = useMemo(() => {
|
|
@@ -37097,15 +37458,6 @@ var LineMonthlyHistory = ({
|
|
|
37097
37458
|
shiftId: selectedShiftId,
|
|
37098
37459
|
enabled: !!lineId
|
|
37099
37460
|
});
|
|
37100
|
-
if (isLoading) {
|
|
37101
|
-
return /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center h-[calc(100vh-10rem)]", children: /* @__PURE__ */ jsx(
|
|
37102
|
-
OptifyeLogoLoader_default,
|
|
37103
|
-
{
|
|
37104
|
-
size: "lg",
|
|
37105
|
-
message: "Loading monthly performance data..."
|
|
37106
|
-
}
|
|
37107
|
-
) });
|
|
37108
|
-
}
|
|
37109
37461
|
const averages = (analysisMonthlyData || []).reduce(
|
|
37110
37462
|
(acc, day) => {
|
|
37111
37463
|
const shiftData = getShiftData2(day, selectedShiftId);
|
|
@@ -37124,6 +37476,88 @@ var LineMonthlyHistory = ({
|
|
|
37124
37476
|
const avgEfficiency = averages.count > 0 ? averages.efficiency / averages.count : 0;
|
|
37125
37477
|
const avgUnderperforming = averages.count > 0 ? averages.underperforming / averages.count : 0;
|
|
37126
37478
|
const avgTotalWorkspaces = averages.count > 0 ? averages.totalWorkspaces / averages.count : 0;
|
|
37479
|
+
const hasRealData = (shift) => {
|
|
37480
|
+
if (shift.hasData !== void 0) return shift.hasData;
|
|
37481
|
+
return shift.avg_efficiency > 0 || shift.underperforming_workspaces > 0 || shift.total_workspaces > 0 || (shift.output || 0) > 0 || (shift.idealOutput || 0) > 0;
|
|
37482
|
+
};
|
|
37483
|
+
const chartData = useMemo(() => {
|
|
37484
|
+
const rangeStartDate = parseDateKeyToDate(normalizedRange.startKey);
|
|
37485
|
+
const rangeEndDate = parseDateKeyToDate(normalizedRange.endKey);
|
|
37486
|
+
const dayNumbers = [];
|
|
37487
|
+
for (let d = new Date(rangeStartDate); d <= rangeEndDate; d.setDate(d.getDate() + 1)) {
|
|
37488
|
+
dayNumbers.push(d.getDate());
|
|
37489
|
+
}
|
|
37490
|
+
const dailyData = [];
|
|
37491
|
+
let maxOutput = 0;
|
|
37492
|
+
let lastSetTarget = 0;
|
|
37493
|
+
for (let i = dayNumbers.length - 1; i >= 0; i--) {
|
|
37494
|
+
const day = dayNumbers[i];
|
|
37495
|
+
const dayData = analysisMonthlyData.find((d) => {
|
|
37496
|
+
const date = new Date(d.date);
|
|
37497
|
+
return date.getDate() === day;
|
|
37498
|
+
});
|
|
37499
|
+
const shiftData = dayData ? getShiftData2(dayData, selectedShiftId) : null;
|
|
37500
|
+
const idealOutput = shiftData ? shiftData.idealOutput || 0 : 0;
|
|
37501
|
+
if (idealOutput > 0) {
|
|
37502
|
+
lastSetTarget = idealOutput;
|
|
37503
|
+
break;
|
|
37504
|
+
}
|
|
37505
|
+
}
|
|
37506
|
+
for (const day of dayNumbers) {
|
|
37507
|
+
const dayData = analysisMonthlyData.find((d) => {
|
|
37508
|
+
const date = new Date(d.date);
|
|
37509
|
+
return date.getDate() === day;
|
|
37510
|
+
});
|
|
37511
|
+
const shiftData = dayData ? getShiftData2(dayData, selectedShiftId) : null;
|
|
37512
|
+
const output = shiftData && hasRealData(shiftData) ? shiftData.output || 0 : 0;
|
|
37513
|
+
const idealOutput = shiftData ? shiftData.idealOutput || 0 : 0;
|
|
37514
|
+
if (output > maxOutput) maxOutput = output;
|
|
37515
|
+
const color2 = output >= lastSetTarget ? "#00AB45" : "#E34329";
|
|
37516
|
+
dailyData.push({
|
|
37517
|
+
hour: getOrdinal(day),
|
|
37518
|
+
// Using ordinal format (1st, 2nd, 3rd, etc.)
|
|
37519
|
+
timeRange: `Day ${day}`,
|
|
37520
|
+
output,
|
|
37521
|
+
originalOutput: output,
|
|
37522
|
+
// For label display
|
|
37523
|
+
idealOutput,
|
|
37524
|
+
color: color2
|
|
37525
|
+
});
|
|
37526
|
+
}
|
|
37527
|
+
const calculatedMax = Math.max(maxOutput, lastSetTarget);
|
|
37528
|
+
const yAxisMax = calculatedMax > 0 ? calculatedMax * 1.1 : 100;
|
|
37529
|
+
return { data: dailyData, maxOutput, lastSetTarget, yAxisMax };
|
|
37530
|
+
}, [analysisMonthlyData, normalizedRange.startKey, normalizedRange.endKey, selectedShiftId]);
|
|
37531
|
+
const yAxisTicks = useMemo(() => {
|
|
37532
|
+
const max = chartData.yAxisMax;
|
|
37533
|
+
const target = chartData.lastSetTarget;
|
|
37534
|
+
if (!max || max <= 0) return void 0;
|
|
37535
|
+
const desiredIntervals = 4;
|
|
37536
|
+
const roughStep = max / desiredIntervals;
|
|
37537
|
+
const power = Math.pow(10, Math.floor(Math.log10(roughStep)));
|
|
37538
|
+
const normalized = roughStep / power;
|
|
37539
|
+
let step = 1 * power;
|
|
37540
|
+
if (normalized >= 1.5 && normalized < 3) step = 2 * power;
|
|
37541
|
+
else if (normalized >= 3 && normalized < 7) step = 5 * power;
|
|
37542
|
+
else if (normalized >= 7) step = 10 * power;
|
|
37543
|
+
const ticks = [];
|
|
37544
|
+
for (let v = 0; v <= max; v += step) {
|
|
37545
|
+
ticks.push(Math.round(v));
|
|
37546
|
+
}
|
|
37547
|
+
if (target > 0) {
|
|
37548
|
+
ticks.push(Math.round(target));
|
|
37549
|
+
}
|
|
37550
|
+
return Array.from(new Set(ticks)).filter((v) => v >= 0 && v <= max).sort((a, b) => a - b);
|
|
37551
|
+
}, [chartData.yAxisMax, chartData.lastSetTarget]);
|
|
37552
|
+
if (isLoading) {
|
|
37553
|
+
return /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center h-[calc(100vh-10rem)]", children: /* @__PURE__ */ jsx(
|
|
37554
|
+
OptifyeLogoLoader_default,
|
|
37555
|
+
{
|
|
37556
|
+
size: "lg",
|
|
37557
|
+
message: "Loading monthly performance data..."
|
|
37558
|
+
}
|
|
37559
|
+
) });
|
|
37560
|
+
}
|
|
37127
37561
|
const renderPerformanceSquares = (performances) => {
|
|
37128
37562
|
if (!performances || !Array.isArray(performances)) {
|
|
37129
37563
|
return null;
|
|
@@ -37215,64 +37649,18 @@ var LineMonthlyHistory = ({
|
|
|
37215
37649
|
year,
|
|
37216
37650
|
timezone,
|
|
37217
37651
|
value: normalizedRange,
|
|
37218
|
-
onChange: (nextRange) => onRangeChange?.(nextRange)
|
|
37652
|
+
onChange: (nextRange) => onRangeChange?.(nextRange),
|
|
37653
|
+
onMonthNavigate: (newMonth, newYear) => onCalendarMonthChange?.(new Date(newYear, newMonth))
|
|
37219
37654
|
}
|
|
37220
37655
|
) })
|
|
37221
37656
|
] }),
|
|
37222
37657
|
/* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 lg:grid-cols-2 gap-6 mt-6", children: [
|
|
37223
37658
|
/* @__PURE__ */ jsxs("div", { className: "bg-white rounded-xl shadow-sm border border-gray-100 p-6", children: [
|
|
37224
|
-
/* @__PURE__ */
|
|
37225
|
-
|
|
37226
|
-
|
|
37227
|
-
|
|
37228
|
-
|
|
37229
|
-
let newMonth = month - 1;
|
|
37230
|
-
let newYear = year;
|
|
37231
|
-
if (newMonth < 0) {
|
|
37232
|
-
newMonth = 11;
|
|
37233
|
-
newYear -= 1;
|
|
37234
|
-
}
|
|
37235
|
-
if (onCalendarMonthChange) {
|
|
37236
|
-
onCalendarMonthChange(new Date(newYear, newMonth));
|
|
37237
|
-
}
|
|
37238
|
-
},
|
|
37239
|
-
className: "p-2 rounded-full hover:bg-gray-100",
|
|
37240
|
-
"aria-label": "Previous month",
|
|
37241
|
-
children: /* @__PURE__ */ jsx(ChevronLeftIcon, { className: "w-5 h-5" })
|
|
37242
|
-
}
|
|
37243
|
-
),
|
|
37244
|
-
/* @__PURE__ */ jsxs("h2", { className: "text-lg font-semibold text-gray-700", children: [
|
|
37245
|
-
new Date(year, month).toLocaleString("default", { month: "long" }),
|
|
37246
|
-
" ",
|
|
37247
|
-
year
|
|
37248
|
-
] }),
|
|
37249
|
-
/* @__PURE__ */ jsx(
|
|
37250
|
-
"button",
|
|
37251
|
-
{
|
|
37252
|
-
onClick: () => {
|
|
37253
|
-
let newMonth = month + 1;
|
|
37254
|
-
let newYear = year;
|
|
37255
|
-
if (newMonth > 11) {
|
|
37256
|
-
newMonth = 0;
|
|
37257
|
-
newYear += 1;
|
|
37258
|
-
}
|
|
37259
|
-
const currentDate = /* @__PURE__ */ new Date();
|
|
37260
|
-
const currentYear = currentDate.getFullYear();
|
|
37261
|
-
const currentMonth = currentDate.getMonth();
|
|
37262
|
-
if (newYear > currentYear || newYear === currentYear && newMonth > currentMonth) {
|
|
37263
|
-
return;
|
|
37264
|
-
}
|
|
37265
|
-
if (onCalendarMonthChange) {
|
|
37266
|
-
onCalendarMonthChange(new Date(newYear, newMonth));
|
|
37267
|
-
}
|
|
37268
|
-
},
|
|
37269
|
-
className: `p-2 rounded-full ${(/* @__PURE__ */ new Date()).getFullYear() === year && (/* @__PURE__ */ new Date()).getMonth() === month ? "text-gray-300 cursor-not-allowed" : "hover:bg-gray-100 text-gray-600"}`,
|
|
37270
|
-
disabled: (/* @__PURE__ */ new Date()).getFullYear() === year && (/* @__PURE__ */ new Date()).getMonth() === month,
|
|
37271
|
-
"aria-label": "Next month",
|
|
37272
|
-
children: /* @__PURE__ */ jsx(ChevronRightIcon, { className: "w-5 h-5" })
|
|
37273
|
-
}
|
|
37274
|
-
)
|
|
37275
|
-
] }),
|
|
37659
|
+
/* @__PURE__ */ jsx("div", { className: "flex justify-center items-center mb-6", children: /* @__PURE__ */ jsxs("h2", { className: "text-lg font-semibold text-gray-700", children: [
|
|
37660
|
+
new Date(year, month).toLocaleString("default", { month: "long" }),
|
|
37661
|
+
" ",
|
|
37662
|
+
year
|
|
37663
|
+
] }) }),
|
|
37276
37664
|
/* @__PURE__ */ jsx(
|
|
37277
37665
|
LineHistoryCalendar_default,
|
|
37278
37666
|
{
|
|
@@ -37287,26 +37675,20 @@ var LineMonthlyHistory = ({
|
|
|
37287
37675
|
}
|
|
37288
37676
|
)
|
|
37289
37677
|
] }),
|
|
37290
|
-
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-
|
|
37291
|
-
/* @__PURE__ */ jsxs("div", { className: "grid grid-cols-
|
|
37292
|
-
/* @__PURE__ */ jsxs("div", { className: "bg-white rounded-xl shadow-sm border border-gray-100 p-
|
|
37293
|
-
/* @__PURE__ */ jsx("h3", { className: "text-
|
|
37294
|
-
/* @__PURE__ */
|
|
37295
|
-
|
|
37296
|
-
rangeLabel
|
|
37297
|
-
] }),
|
|
37298
|
-
/* @__PURE__ */ jsxs("div", { className: "text-4xl font-bold text-center text-gray-900", children: [
|
|
37678
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4", children: [
|
|
37679
|
+
/* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-4", children: [
|
|
37680
|
+
/* @__PURE__ */ jsxs("div", { className: "bg-white rounded-xl shadow-sm border border-gray-100 p-4 flex flex-col items-center justify-center", children: [
|
|
37681
|
+
/* @__PURE__ */ jsx("h3", { className: "text-sm font-semibold text-gray-700 mb-1 text-center", children: "Efficiency" }),
|
|
37682
|
+
/* @__PURE__ */ jsx("p", { className: "text-[10px] text-gray-400 mb-1 text-center uppercase tracking-wide", children: "Cumulative" }),
|
|
37683
|
+
/* @__PURE__ */ jsxs("div", { className: "text-2xl font-bold text-center text-gray-900", children: [
|
|
37299
37684
|
avgEfficiency.toFixed(1),
|
|
37300
37685
|
"%"
|
|
37301
37686
|
] })
|
|
37302
37687
|
] }),
|
|
37303
|
-
/* @__PURE__ */ jsxs("div", { className: "bg-white rounded-xl shadow-sm border border-gray-100 p-
|
|
37304
|
-
/* @__PURE__ */ jsx("h3", { className: "text-
|
|
37305
|
-
/* @__PURE__ */
|
|
37306
|
-
|
|
37307
|
-
rangeLabel
|
|
37308
|
-
] }),
|
|
37309
|
-
/* @__PURE__ */ jsxs("div", { className: "text-4xl font-bold text-center text-gray-900", children: [
|
|
37688
|
+
/* @__PURE__ */ jsxs("div", { className: "bg-white rounded-xl shadow-sm border border-gray-100 p-4 flex flex-col items-center justify-center", children: [
|
|
37689
|
+
/* @__PURE__ */ jsx("h3", { className: "text-sm font-semibold text-gray-700 mb-1 text-center", children: "Avg. Underperforming" }),
|
|
37690
|
+
/* @__PURE__ */ jsx("p", { className: "text-[10px] text-gray-400 mb-1 text-center uppercase tracking-wide", children: "Cumulative" }),
|
|
37691
|
+
/* @__PURE__ */ jsxs("div", { className: "text-2xl font-bold text-center text-gray-900", children: [
|
|
37310
37692
|
avgUnderperforming.toFixed(1),
|
|
37311
37693
|
"/",
|
|
37312
37694
|
avgTotalWorkspaces.toFixed(1)
|
|
@@ -37314,9 +37696,9 @@ var LineMonthlyHistory = ({
|
|
|
37314
37696
|
] })
|
|
37315
37697
|
] }),
|
|
37316
37698
|
/* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 lg:grid-cols-2 gap-4", children: [
|
|
37317
|
-
/* @__PURE__ */ jsxs("div", { className: "bg-white rounded-xl shadow-sm border border-gray-100 p-4 flex flex-col", children: [
|
|
37318
|
-
/* @__PURE__ */ jsx("h3", { className: "text-
|
|
37319
|
-
/* @__PURE__ */ jsx("div", { className: "flex-1 min-h-
|
|
37699
|
+
/* @__PURE__ */ jsxs("div", { className: "bg-white rounded-xl shadow-sm border border-gray-100 p-4 flex flex-col h-[220px]", children: [
|
|
37700
|
+
/* @__PURE__ */ jsx("h3", { className: "text-sm font-semibold text-gray-700 mb-1", children: "Idle time Breakdown" }),
|
|
37701
|
+
/* @__PURE__ */ jsx("div", { className: "flex-1 min-h-0 relative -ml-4", children: /* @__PURE__ */ jsx(
|
|
37320
37702
|
IdleTimeReasonChart,
|
|
37321
37703
|
{
|
|
37322
37704
|
data: idleReasonsChartData,
|
|
@@ -37326,34 +37708,117 @@ var LineMonthlyHistory = ({
|
|
|
37326
37708
|
chartKey
|
|
37327
37709
|
) })
|
|
37328
37710
|
] }),
|
|
37329
|
-
/* @__PURE__ */ jsxs("div", { className: "bg-white rounded-xl shadow-sm border border-gray-100 p-
|
|
37330
|
-
/* @__PURE__ */ jsx("h2", { className: "text-
|
|
37331
|
-
/* @__PURE__ */ jsxs("div", { className: "space-y-
|
|
37711
|
+
/* @__PURE__ */ jsxs("div", { className: "bg-white rounded-xl shadow-sm border border-gray-100 p-4 h-[220px] flex flex-col", children: [
|
|
37712
|
+
/* @__PURE__ */ jsx("h2", { className: "text-sm font-semibold text-gray-700 mb-3", children: "Top 3 Poorest Performers" }),
|
|
37713
|
+
/* @__PURE__ */ jsxs("div", { className: "flex-1 overflow-y-auto pr-1 space-y-1 custom-scrollbar", children: [
|
|
37332
37714
|
(underperformingWorkspaces[selectedShiftId] || []).slice(0, 3).map((workspace) => /* @__PURE__ */ jsx(
|
|
37333
37715
|
"button",
|
|
37334
37716
|
{
|
|
37335
37717
|
onClick: () => handleWorkspaceClick(workspace),
|
|
37336
|
-
className: "block hover:bg-gray-50 transition-colors rounded-lg w-full text-left",
|
|
37337
|
-
children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between py-2 px-2 border-b border-gray-
|
|
37338
|
-
/* @__PURE__ */ jsxs("div", { className: "font-medium text-gray-900 text-
|
|
37718
|
+
className: "block hover:bg-gray-50 transition-colors rounded-lg w-full text-left group",
|
|
37719
|
+
children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between py-2 px-2 border-b border-gray-50 group-last:border-b-0", children: [
|
|
37720
|
+
/* @__PURE__ */ jsxs("div", { className: "font-medium text-gray-900 text-xs", children: [
|
|
37339
37721
|
getWorkspaceDisplayName(workspace.workspace_name, lineId),
|
|
37340
|
-
workspace.avg_efficiency !== void 0 && /* @__PURE__ */ jsxs("span", { className: "ml-1 text-
|
|
37722
|
+
workspace.avg_efficiency !== void 0 && /* @__PURE__ */ jsxs("span", { className: "ml-1 text-[10px] text-gray-500", children: [
|
|
37341
37723
|
"(",
|
|
37342
37724
|
(workspace.avg_efficiency || 0).toFixed(1),
|
|
37343
37725
|
"%)"
|
|
37344
37726
|
] })
|
|
37345
37727
|
] }),
|
|
37346
|
-
/* @__PURE__ */
|
|
37347
|
-
/* @__PURE__ */ jsx("div", { className: "text-xs text-gray-500 hidden xl:block", children: "Last 5 days:" }),
|
|
37348
|
-
renderPerformanceSquares(workspace.last_5_days)
|
|
37349
|
-
] })
|
|
37728
|
+
/* @__PURE__ */ jsx("div", { className: "flex items-center gap-1.5", children: renderPerformanceSquares(workspace.last_5_days) })
|
|
37350
37729
|
] })
|
|
37351
37730
|
},
|
|
37352
37731
|
workspace.workspace_uuid
|
|
37353
37732
|
)),
|
|
37354
|
-
(!underperformingWorkspaces || !underperformingWorkspaces[selectedShiftId]?.length) && /* @__PURE__ */ jsx("div", { className: "text-center text-gray-
|
|
37733
|
+
(!underperformingWorkspaces || !underperformingWorkspaces[selectedShiftId]?.length) && /* @__PURE__ */ jsx("div", { className: "text-center text-gray-400 py-8 text-xs italic", children: "No underperforming workspaces" })
|
|
37355
37734
|
] })
|
|
37356
37735
|
] })
|
|
37736
|
+
] }),
|
|
37737
|
+
/* @__PURE__ */ jsxs("div", { className: "bg-white rounded-xl shadow-sm border border-gray-100 p-4", children: [
|
|
37738
|
+
/* @__PURE__ */ jsx("div", { className: "flex items-center justify-between mb-2", children: /* @__PURE__ */ jsx("h3", { className: "text-sm font-semibold text-gray-700", children: "Daily Output" }) }),
|
|
37739
|
+
/* @__PURE__ */ jsx("div", { style: { height: "220px" }, children: /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxs(
|
|
37740
|
+
BarChart$1,
|
|
37741
|
+
{
|
|
37742
|
+
data: chartData.data,
|
|
37743
|
+
margin: { top: 20, right: 10, bottom: 40, left: 10 },
|
|
37744
|
+
children: [
|
|
37745
|
+
/* @__PURE__ */ jsx(CartesianGrid, { strokeDasharray: "3 3", vertical: false, stroke: "#f3f4f6" }),
|
|
37746
|
+
/* @__PURE__ */ jsx(
|
|
37747
|
+
XAxis,
|
|
37748
|
+
{
|
|
37749
|
+
dataKey: "hour",
|
|
37750
|
+
tick: { fontSize: 10, fill: "#6b7280" },
|
|
37751
|
+
interval: 0,
|
|
37752
|
+
angle: -45,
|
|
37753
|
+
textAnchor: "end",
|
|
37754
|
+
height: 60
|
|
37755
|
+
}
|
|
37756
|
+
),
|
|
37757
|
+
/* @__PURE__ */ jsx(
|
|
37758
|
+
YAxis,
|
|
37759
|
+
{
|
|
37760
|
+
domain: [0, chartData.yAxisMax],
|
|
37761
|
+
width: 40,
|
|
37762
|
+
ticks: yAxisTicks,
|
|
37763
|
+
tick: (props) => {
|
|
37764
|
+
const { x, y, payload } = props;
|
|
37765
|
+
const value = Math.round(payload.value);
|
|
37766
|
+
const targetValue = Math.round(chartData.lastSetTarget);
|
|
37767
|
+
const isTarget = value === targetValue && targetValue > 0;
|
|
37768
|
+
return /* @__PURE__ */ jsx(
|
|
37769
|
+
"text",
|
|
37770
|
+
{
|
|
37771
|
+
x: x - 5,
|
|
37772
|
+
y: y + 4,
|
|
37773
|
+
textAnchor: "end",
|
|
37774
|
+
fontSize: "10",
|
|
37775
|
+
fill: isTarget ? "#E34329" : "#6b7280",
|
|
37776
|
+
fontWeight: isTarget ? "600" : "normal",
|
|
37777
|
+
children: value < 1e-3 ? "" : value.toLocaleString()
|
|
37778
|
+
}
|
|
37779
|
+
);
|
|
37780
|
+
}
|
|
37781
|
+
}
|
|
37782
|
+
),
|
|
37783
|
+
/* @__PURE__ */ jsx(
|
|
37784
|
+
Tooltip,
|
|
37785
|
+
{
|
|
37786
|
+
cursor: false,
|
|
37787
|
+
content: CustomTooltip2
|
|
37788
|
+
}
|
|
37789
|
+
),
|
|
37790
|
+
chartData.lastSetTarget > 0 && /* @__PURE__ */ jsx(
|
|
37791
|
+
ReferenceLine,
|
|
37792
|
+
{
|
|
37793
|
+
y: chartData.lastSetTarget,
|
|
37794
|
+
stroke: "#E34329",
|
|
37795
|
+
strokeDasharray: "5 5",
|
|
37796
|
+
strokeWidth: 2
|
|
37797
|
+
}
|
|
37798
|
+
),
|
|
37799
|
+
/* @__PURE__ */ jsx(
|
|
37800
|
+
Bar,
|
|
37801
|
+
{
|
|
37802
|
+
dataKey: "output",
|
|
37803
|
+
radius: [4, 4, 0, 0],
|
|
37804
|
+
isAnimationActive: true,
|
|
37805
|
+
animationBegin: 0,
|
|
37806
|
+
animationDuration: 1e3,
|
|
37807
|
+
animationEasing: "ease-out",
|
|
37808
|
+
children: chartData.data.map((entry, index) => /* @__PURE__ */ jsx(
|
|
37809
|
+
Cell,
|
|
37810
|
+
{
|
|
37811
|
+
fill: entry.output === 0 ? "#f3f4f6" : entry.color,
|
|
37812
|
+
className: entry.output > 0 ? "hover:opacity-80 transition-opacity cursor-pointer" : ""
|
|
37813
|
+
},
|
|
37814
|
+
`cell-${index}`
|
|
37815
|
+
))
|
|
37816
|
+
}
|
|
37817
|
+
)
|
|
37818
|
+
]
|
|
37819
|
+
},
|
|
37820
|
+
chartKey
|
|
37821
|
+
) }) })
|
|
37357
37822
|
] })
|
|
37358
37823
|
] })
|
|
37359
37824
|
] })
|
|
@@ -38494,7 +38959,7 @@ var styles = `
|
|
|
38494
38959
|
transform: scale(1) !important;
|
|
38495
38960
|
}
|
|
38496
38961
|
`;
|
|
38497
|
-
var
|
|
38962
|
+
var WEEKDAYS3 = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
|
|
38498
38963
|
var getTimeInZoneAsDate = (timezone) => {
|
|
38499
38964
|
const time2 = getCurrentTimeInZone(timezone);
|
|
38500
38965
|
return typeof time2 === "string" ? new Date(time2) : time2;
|
|
@@ -38526,10 +38991,10 @@ var WorkspaceHistoryCalendar = ({
|
|
|
38526
38991
|
return () => clearTimeout(timer);
|
|
38527
38992
|
}, [month, year]);
|
|
38528
38993
|
const calendarData = useMemo(() => {
|
|
38529
|
-
const
|
|
38530
|
-
const
|
|
38531
|
-
const totalDays =
|
|
38532
|
-
let startOffset =
|
|
38994
|
+
const startOfMonth2 = toZonedTime(new Date(year, month, 1), configuredTimezone);
|
|
38995
|
+
const endOfMonth2 = toZonedTime(new Date(year, month + 1, 0), configuredTimezone);
|
|
38996
|
+
const totalDays = endOfMonth2.getDate();
|
|
38997
|
+
let startOffset = startOfMonth2.getDay() - 1;
|
|
38533
38998
|
if (startOffset === -1) startOffset = 6;
|
|
38534
38999
|
const calendar = Array(startOffset).fill(null);
|
|
38535
39000
|
for (let day = 1; day <= totalDays; day++) {
|
|
@@ -38738,7 +39203,7 @@ var WorkspaceHistoryCalendar = ({
|
|
|
38738
39203
|
/* @__PURE__ */ jsx("p", { className: "text-xs sm:text-sm text-gray-500 mt-1", children: "Calendar view of daily performance" })
|
|
38739
39204
|
] }),
|
|
38740
39205
|
/* @__PURE__ */ jsxs("div", { className: "grid gap-3 sm:gap-4 lg:gap-6", children: [
|
|
38741
|
-
/* @__PURE__ */ jsx("div", { className: "grid grid-cols-7 gap-1 sm:gap-2", children:
|
|
39206
|
+
/* @__PURE__ */ jsx("div", { className: "grid grid-cols-7 gap-1 sm:gap-2", children: WEEKDAYS3.map((day) => /* @__PURE__ */ jsx("div", { className: "text-xs sm:text-sm font-medium text-gray-600 text-center", children: day.slice(0, 3) }, day)) }),
|
|
38742
39207
|
/* @__PURE__ */ jsx("div", { className: "grid grid-cols-7 gap-1 sm:gap-2", children: calendarData.calendar.map((day, index) => {
|
|
38743
39208
|
const startOffset = calendarData.startOffset;
|
|
38744
39209
|
const dayNumber = index >= startOffset ? index - startOffset + 1 : null;
|
|
@@ -38791,13 +39256,13 @@ var WorkspaceHistoryCalendar = ({
|
|
|
38791
39256
|
] })
|
|
38792
39257
|
] });
|
|
38793
39258
|
};
|
|
38794
|
-
var
|
|
38795
|
-
var
|
|
39259
|
+
var WEEKDAYS4 = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
|
|
39260
|
+
var getOrdinal2 = (n) => {
|
|
38796
39261
|
const suffix = ["th", "st", "nd", "rd"];
|
|
38797
39262
|
const v = n % 100;
|
|
38798
39263
|
return n + (suffix[(v - 20) % 10] || suffix[v] || suffix[0]);
|
|
38799
39264
|
};
|
|
38800
|
-
var
|
|
39265
|
+
var CustomTooltip3 = ({ active, payload, label }) => {
|
|
38801
39266
|
if (active && payload && payload.length) {
|
|
38802
39267
|
return /* @__PURE__ */ jsxs("div", { className: "bg-white/95 backdrop-blur-sm p-3 rounded-lg shadow-lg border border-gray-100", children: [
|
|
38803
39268
|
/* @__PURE__ */ jsx("p", { className: "text-sm font-semibold text-gray-800 mb-1", children: label }),
|
|
@@ -38900,7 +39365,7 @@ var WorkspaceMonthlyHistory = ({
|
|
|
38900
39365
|
if (output > maxOutput) maxOutput = output;
|
|
38901
39366
|
const color2 = output >= lastSetTarget ? "#00AB45" : "#E34329";
|
|
38902
39367
|
dailyData.push({
|
|
38903
|
-
hour:
|
|
39368
|
+
hour: getOrdinal2(day),
|
|
38904
39369
|
// Using ordinal format (1st, 2nd, 3rd, etc.)
|
|
38905
39370
|
timeRange: `Day ${day}`,
|
|
38906
39371
|
output,
|
|
@@ -38934,9 +39399,26 @@ var WorkspaceMonthlyHistory = ({
|
|
|
38934
39399
|
ticks.push(Math.round(v));
|
|
38935
39400
|
}
|
|
38936
39401
|
if (target > 0) {
|
|
38937
|
-
|
|
39402
|
+
const roundedTarget = Math.round(target);
|
|
39403
|
+
if (!ticks.includes(roundedTarget)) {
|
|
39404
|
+
let nearestIndex = -1;
|
|
39405
|
+
let nearestDistance = Number.POSITIVE_INFINITY;
|
|
39406
|
+
ticks.forEach((tick, index) => {
|
|
39407
|
+
if (tick === 0) return;
|
|
39408
|
+
const distance2 = Math.abs(tick - roundedTarget);
|
|
39409
|
+
if (distance2 < nearestDistance) {
|
|
39410
|
+
nearestDistance = distance2;
|
|
39411
|
+
nearestIndex = index;
|
|
39412
|
+
}
|
|
39413
|
+
});
|
|
39414
|
+
if (nearestIndex >= 0) {
|
|
39415
|
+
ticks[nearestIndex] = roundedTarget;
|
|
39416
|
+
} else {
|
|
39417
|
+
ticks.push(roundedTarget);
|
|
39418
|
+
}
|
|
39419
|
+
}
|
|
38938
39420
|
}
|
|
38939
|
-
return
|
|
39421
|
+
return ticks.filter((v) => v >= 0 && v <= max * 1.05).sort((a, b) => a - b);
|
|
38940
39422
|
}, [chartData.yAxisMax, chartData.lastSetTarget]);
|
|
38941
39423
|
const pieChartData = useMemo(() => {
|
|
38942
39424
|
const validShifts = analysisMonthlyData.map((d) => getShiftData(d, selectedShiftId)).filter(hasRealData);
|
|
@@ -38972,10 +39454,10 @@ var WorkspaceMonthlyHistory = ({
|
|
|
38972
39454
|
};
|
|
38973
39455
|
}, [analysisMonthlyData, selectedShiftId]);
|
|
38974
39456
|
const calendarData = useMemo(() => {
|
|
38975
|
-
const
|
|
38976
|
-
const
|
|
38977
|
-
const totalDays =
|
|
38978
|
-
let startOffset =
|
|
39457
|
+
const startOfMonth2 = new Date(year, month, 1);
|
|
39458
|
+
const endOfMonth2 = new Date(year, month + 1, 0);
|
|
39459
|
+
const totalDays = endOfMonth2.getDate();
|
|
39460
|
+
let startOffset = startOfMonth2.getDay() - 1;
|
|
38979
39461
|
if (startOffset === -1) startOffset = 6;
|
|
38980
39462
|
const calendar = Array(startOffset).fill(null);
|
|
38981
39463
|
for (let day = 1; day <= totalDays; day++) {
|
|
@@ -39042,68 +39524,19 @@ var WorkspaceMonthlyHistory = ({
|
|
|
39042
39524
|
year,
|
|
39043
39525
|
timezone,
|
|
39044
39526
|
value: normalizedRange,
|
|
39045
|
-
onChange: (nextRange) => onRangeChange?.(nextRange)
|
|
39527
|
+
onChange: (nextRange) => onRangeChange?.(nextRange),
|
|
39528
|
+
onMonthNavigate
|
|
39046
39529
|
}
|
|
39047
39530
|
) })
|
|
39048
39531
|
] }),
|
|
39049
39532
|
/* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 lg:grid-cols-2 gap-6 mt-6", children: [
|
|
39050
39533
|
/* @__PURE__ */ jsxs("div", { className: "bg-white rounded-xl shadow-sm border border-gray-100 p-6", children: [
|
|
39051
|
-
/* @__PURE__ */
|
|
39052
|
-
|
|
39053
|
-
|
|
39054
|
-
|
|
39055
|
-
|
|
39056
|
-
|
|
39057
|
-
let newYear = year;
|
|
39058
|
-
if (newMonth < 0) {
|
|
39059
|
-
newMonth = 11;
|
|
39060
|
-
newYear -= 1;
|
|
39061
|
-
}
|
|
39062
|
-
if (newYear < 2023) {
|
|
39063
|
-
return;
|
|
39064
|
-
}
|
|
39065
|
-
if (onMonthNavigate) {
|
|
39066
|
-
onMonthNavigate(newMonth, newYear);
|
|
39067
|
-
}
|
|
39068
|
-
},
|
|
39069
|
-
className: "p-2 rounded-full hover:bg-gray-100",
|
|
39070
|
-
"aria-label": "Previous month",
|
|
39071
|
-
children: /* @__PURE__ */ jsx(ChevronLeftIcon, { className: "w-5 h-5" })
|
|
39072
|
-
}
|
|
39073
|
-
),
|
|
39074
|
-
/* @__PURE__ */ jsxs("h2", { className: "text-lg font-semibold text-gray-700", children: [
|
|
39075
|
-
new Date(year, month).toLocaleString("default", { month: "long" }),
|
|
39076
|
-
" ",
|
|
39077
|
-
year
|
|
39078
|
-
] }),
|
|
39079
|
-
/* @__PURE__ */ jsx(
|
|
39080
|
-
"button",
|
|
39081
|
-
{
|
|
39082
|
-
onClick: () => {
|
|
39083
|
-
let newMonth = month + 1;
|
|
39084
|
-
let newYear = year;
|
|
39085
|
-
if (newMonth > 11) {
|
|
39086
|
-
newMonth = 0;
|
|
39087
|
-
newYear += 1;
|
|
39088
|
-
}
|
|
39089
|
-
const currentDate = /* @__PURE__ */ new Date();
|
|
39090
|
-
const currentYear = currentDate.getFullYear();
|
|
39091
|
-
const currentMonth = currentDate.getMonth();
|
|
39092
|
-
if (newYear > currentYear || newYear === currentYear && newMonth > currentMonth) {
|
|
39093
|
-
return;
|
|
39094
|
-
}
|
|
39095
|
-
if (onMonthNavigate) {
|
|
39096
|
-
onMonthNavigate(newMonth, newYear);
|
|
39097
|
-
}
|
|
39098
|
-
},
|
|
39099
|
-
className: `p-2 rounded-full ${(/* @__PURE__ */ new Date()).getFullYear() === year && (/* @__PURE__ */ new Date()).getMonth() === month ? "text-gray-300 cursor-not-allowed" : "hover:bg-gray-100 text-gray-600"}`,
|
|
39100
|
-
disabled: (/* @__PURE__ */ new Date()).getFullYear() === year && (/* @__PURE__ */ new Date()).getMonth() === month,
|
|
39101
|
-
"aria-label": "Next month",
|
|
39102
|
-
children: /* @__PURE__ */ jsx(ChevronRightIcon, { className: "w-5 h-5" })
|
|
39103
|
-
}
|
|
39104
|
-
)
|
|
39105
|
-
] }),
|
|
39106
|
-
/* @__PURE__ */ jsx("div", { className: "grid grid-cols-7 gap-2", children: WEEKDAYS3.map((day, idx) => /* @__PURE__ */ jsx("div", { className: "text-sm font-medium text-gray-500 dark:text-gray-400 text-center", children: day }, day)) }),
|
|
39534
|
+
/* @__PURE__ */ jsx("div", { className: "flex justify-center items-center mb-6", children: /* @__PURE__ */ jsxs("h2", { className: "text-lg font-semibold text-gray-700", children: [
|
|
39535
|
+
new Date(year, month).toLocaleString("default", { month: "long" }),
|
|
39536
|
+
" ",
|
|
39537
|
+
year
|
|
39538
|
+
] }) }),
|
|
39539
|
+
/* @__PURE__ */ jsx("div", { className: "grid grid-cols-7 gap-2", children: WEEKDAYS4.map((day, idx) => /* @__PURE__ */ jsx("div", { className: "text-sm font-medium text-gray-500 dark:text-gray-400 text-center", children: day }, day)) }),
|
|
39107
39540
|
/* @__PURE__ */ jsx("div", { className: "grid grid-cols-7 gap-2 mt-6", children: calendarData.calendar.map((day, index) => {
|
|
39108
39541
|
const dayNumber = index >= calendarData.startOffset ? index - calendarData.startOffset + 1 : null;
|
|
39109
39542
|
if (!dayNumber || dayNumber > new Date(year, month + 1, 0).getDate()) {
|
|
@@ -39120,6 +39553,7 @@ var WorkspaceMonthlyHistory = ({
|
|
|
39120
39553
|
const getPerformanceColor = () => {
|
|
39121
39554
|
if (isFuture) return "bg-gray-200 dark:bg-gray-700";
|
|
39122
39555
|
if (!hasData || !shiftData) return "bg-gray-300 dark:bg-gray-600";
|
|
39556
|
+
if (showRange && !inRange) return "bg-gray-200 dark:bg-gray-700";
|
|
39123
39557
|
return shiftData.efficiency >= 75 ? "bg-green-500 dark:bg-green-600" : "bg-red-500 dark:bg-red-600";
|
|
39124
39558
|
};
|
|
39125
39559
|
return /* @__PURE__ */ jsx("div", { className: "aspect-square relative", children: /* @__PURE__ */ jsx(
|
|
@@ -39139,7 +39573,8 @@ var WorkspaceMonthlyHistory = ({
|
|
|
39139
39573
|
}
|
|
39140
39574
|
),
|
|
39141
39575
|
/* @__PURE__ */ jsx("div", { className: `
|
|
39142
|
-
text-base font-medium
|
|
39576
|
+
text-base font-medium flex items-center relative z-10
|
|
39577
|
+
${hasData && !isFuture && (!showRange || inRange) ? "text-white" : "text-gray-400"}
|
|
39143
39578
|
${isToday2 ? "bg-blue-500 dark:bg-blue-600 rounded-full w-7 h-7 justify-center" : ""}
|
|
39144
39579
|
`, children: dayNumber }),
|
|
39145
39580
|
!isFuture && hasData && shiftData && /* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-black/80 rounded-lg p-2 text-white opacity-0 group-hover:opacity-100 transition-opacity", children: /* @__PURE__ */ jsxs("div", { className: "text-xs space-y-1", children: [
|
|
@@ -39295,13 +39730,13 @@ var WorkspaceMonthlyHistory = ({
|
|
|
39295
39730
|
YAxis,
|
|
39296
39731
|
{
|
|
39297
39732
|
domain: [0, chartData.yAxisMax],
|
|
39298
|
-
width:
|
|
39733
|
+
width: 40,
|
|
39299
39734
|
ticks: yAxisTicks,
|
|
39300
39735
|
tick: (props) => {
|
|
39301
39736
|
const { x, y, payload } = props;
|
|
39302
39737
|
const value = Math.round(payload.value);
|
|
39303
39738
|
const targetValue = Math.round(chartData.lastSetTarget);
|
|
39304
|
-
const isTarget =
|
|
39739
|
+
const isTarget = value === targetValue && targetValue > 0;
|
|
39305
39740
|
return /* @__PURE__ */ jsx(
|
|
39306
39741
|
"text",
|
|
39307
39742
|
{
|
|
@@ -39311,7 +39746,7 @@ var WorkspaceMonthlyHistory = ({
|
|
|
39311
39746
|
fontSize: "10",
|
|
39312
39747
|
fill: isTarget ? "#E34329" : "#6b7280",
|
|
39313
39748
|
fontWeight: isTarget ? "600" : "normal",
|
|
39314
|
-
children: value < 1e-3 ? "" : value.
|
|
39749
|
+
children: value < 1e-3 ? "" : value.toLocaleString()
|
|
39315
39750
|
}
|
|
39316
39751
|
);
|
|
39317
39752
|
}
|
|
@@ -39321,7 +39756,7 @@ var WorkspaceMonthlyHistory = ({
|
|
|
39321
39756
|
Tooltip,
|
|
39322
39757
|
{
|
|
39323
39758
|
cursor: false,
|
|
39324
|
-
content:
|
|
39759
|
+
content: CustomTooltip3
|
|
39325
39760
|
}
|
|
39326
39761
|
),
|
|
39327
39762
|
chartData.lastSetTarget > 0 && /* @__PURE__ */ jsx(
|
|
@@ -39950,13 +40385,15 @@ var LiveTimer = () => {
|
|
|
39950
40385
|
});
|
|
39951
40386
|
return /* @__PURE__ */ jsx("span", { children: formatter.format(time2) });
|
|
39952
40387
|
};
|
|
39953
|
-
var
|
|
39954
|
-
|
|
39955
|
-
|
|
39956
|
-
|
|
39957
|
-
|
|
39958
|
-
|
|
39959
|
-
|
|
40388
|
+
var getGradientEfficiencyClasses = (color2) => {
|
|
40389
|
+
switch (color2) {
|
|
40390
|
+
case "green":
|
|
40391
|
+
return "bg-gradient-to-r from-[#00AB45]/90 to-[#00AB45]/95";
|
|
40392
|
+
case "yellow":
|
|
40393
|
+
return "bg-gradient-to-r from-[#FFB020]/90 to-[#FFB020]/95";
|
|
40394
|
+
case "red":
|
|
40395
|
+
default:
|
|
40396
|
+
return "bg-gradient-to-r from-[#E34329]/90 to-[#E34329]/95";
|
|
39960
40397
|
}
|
|
39961
40398
|
};
|
|
39962
40399
|
var TREND_STYLES = {
|
|
@@ -40024,30 +40461,40 @@ var getWorkspaceStyles = (position, isPlaceholder = false) => {
|
|
|
40024
40461
|
${additionalStyles}
|
|
40025
40462
|
${isPlaceholder ? "cursor-default" : ""}`;
|
|
40026
40463
|
};
|
|
40027
|
-
var
|
|
40028
|
-
|
|
40029
|
-
|
|
40030
|
-
|
|
40031
|
-
|
|
40032
|
-
|
|
40033
|
-
|
|
40034
|
-
|
|
40035
|
-
|
|
40036
|
-
|
|
40464
|
+
var formatPercentRange = (min, max) => {
|
|
40465
|
+
const format7 = (value) => Number.isInteger(value) ? `${value}` : value.toFixed(1);
|
|
40466
|
+
return `${format7(min)}-${format7(max)}%`;
|
|
40467
|
+
};
|
|
40468
|
+
var Legend6 = ({ useBottleneckLabel = false, legend }) => {
|
|
40469
|
+
const effectiveLegend = legend || DEFAULT_EFFICIENCY_LEGEND;
|
|
40470
|
+
const exclamationLabel = useBottleneckLabel ? "Bottleneck" : "<50% efficiency";
|
|
40471
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-1.5 sm:gap-3 bg-white/95 rounded-lg shadow-sm px-2 sm:px-4 py-1 sm:py-1.5 border border-gray-200/60 backdrop-blur-sm text-[10px] sm:text-sm", children: [
|
|
40472
|
+
/* @__PURE__ */ jsx("div", { className: "font-medium text-gray-700 hidden sm:block", children: "Efficiency:" }),
|
|
40473
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 sm:gap-4", children: [
|
|
40474
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
|
|
40475
|
+
/* @__PURE__ */ jsx("div", { className: "w-1.5 h-1.5 sm:w-2.5 sm:h-2.5 rounded-[12px] bg-[#00AB45]/90 ring-1 ring-[#00AB45]/20" }),
|
|
40476
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium text-gray-600", children: formatPercentRange(effectiveLegend.green_min, effectiveLegend.green_max) })
|
|
40477
|
+
] }),
|
|
40478
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
|
|
40479
|
+
/* @__PURE__ */ jsx("div", { className: "w-1.5 h-1.5 sm:w-2.5 sm:h-2.5 rounded-[12px] bg-[#FFB020]/90 ring-1 ring-[#FFB020]/20" }),
|
|
40480
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium text-gray-600", children: formatPercentRange(effectiveLegend.yellow_min, effectiveLegend.yellow_max) })
|
|
40481
|
+
] }),
|
|
40482
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
|
|
40483
|
+
/* @__PURE__ */ jsx("div", { className: "w-1.5 h-1.5 sm:w-2.5 sm:h-2.5 rounded-[12px] bg-[#E34329]/90 ring-1 ring-[#E34329]/20" }),
|
|
40484
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium text-gray-600", children: formatPercentRange(effectiveLegend.red_min, effectiveLegend.red_max) })
|
|
40485
|
+
] })
|
|
40037
40486
|
] }),
|
|
40487
|
+
/* @__PURE__ */ jsx("div", { className: "hidden sm:block w-px h-6 bg-gray-200 mx-1" }),
|
|
40038
40488
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
|
|
40039
|
-
/* @__PURE__ */ jsx("div", { className: "w-
|
|
40040
|
-
/* @__PURE__ */ jsx("span", { className: "font-medium text-gray-600", children:
|
|
40489
|
+
/* @__PURE__ */ jsx("div", { className: "flex items-center justify-center w-3 h-3 sm:w-5 sm:h-5 bg-[#E34329]/90 rounded-full ring-1 ring-[#E34329]/20 text-white font-bold text-[8px] sm:text-xs", children: "!" }),
|
|
40490
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium text-gray-600", children: exclamationLabel })
|
|
40041
40491
|
] })
|
|
40042
|
-
] })
|
|
40043
|
-
|
|
40044
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
|
|
40045
|
-
/* @__PURE__ */ jsx("div", { className: "flex items-center justify-center w-3 h-3 sm:w-5 sm:h-5 bg-[#E34329]/90 rounded-full ring-1 ring-[#E34329]/20 text-white font-bold text-[8px] sm:text-xs", children: "!" }),
|
|
40046
|
-
/* @__PURE__ */ jsx("span", { className: "font-medium text-gray-600", children: "Bottleneck" })
|
|
40047
|
-
] })
|
|
40048
|
-
] });
|
|
40492
|
+
] });
|
|
40493
|
+
};
|
|
40049
40494
|
var arePropsEqual = (prevProps, nextProps) => {
|
|
40050
|
-
|
|
40495
|
+
const prevLegend = prevProps.legend || DEFAULT_EFFICIENCY_LEGEND;
|
|
40496
|
+
const nextLegend = nextProps.legend || DEFAULT_EFFICIENCY_LEGEND;
|
|
40497
|
+
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 && prevLegend.green_min === nextLegend.green_min && prevLegend.green_max === nextLegend.green_max && prevLegend.yellow_min === nextLegend.yellow_min && prevLegend.yellow_max === nextLegend.yellow_max && prevLegend.red_min === nextLegend.red_min && prevLegend.red_max === nextLegend.red_max && prevLegend.critical_threshold === nextLegend.critical_threshold && // Position doesn't need deep equality check as it's generally static
|
|
40051
40498
|
prevProps.position.id === nextProps.position.id;
|
|
40052
40499
|
};
|
|
40053
40500
|
var WorkspaceGridItem = React24__default.memo(({
|
|
@@ -40056,20 +40503,21 @@ var WorkspaceGridItem = React24__default.memo(({
|
|
|
40056
40503
|
isBottleneck = false,
|
|
40057
40504
|
isLowEfficiency = false,
|
|
40058
40505
|
isVeryLowEfficiency = false,
|
|
40059
|
-
onHoverChange
|
|
40506
|
+
onHoverChange,
|
|
40507
|
+
legend
|
|
40060
40508
|
}) => {
|
|
40061
40509
|
const { navigate } = useNavigation();
|
|
40510
|
+
const effectiveLegend = legend || DEFAULT_EFFICIENCY_LEGEND;
|
|
40062
40511
|
const isInactive = useMemo(() => !data.workspace_id || data.efficiency < 10, [data.workspace_id, data.efficiency]);
|
|
40063
40512
|
const colorClass = useMemo(() => {
|
|
40064
40513
|
const isConveyorEnd = position.size === "conveyor" && position.orientation;
|
|
40514
|
+
const efficiencyColor = getEfficiencyColor(data.efficiency, effectiveLegend);
|
|
40065
40515
|
if (isConveyorEnd) {
|
|
40066
40516
|
if (isInactive) return "bg-gray-300/90";
|
|
40067
|
-
|
|
40068
|
-
if (data.efficiency >= 70) return "bg-gradient-to-r from-[#FFB020]/90 to-[#FFB020]/95";
|
|
40069
|
-
return "bg-gradient-to-r from-[#E34329]/90 to-[#E34329]/95";
|
|
40517
|
+
return getGradientEfficiencyClasses(efficiencyColor);
|
|
40070
40518
|
}
|
|
40071
|
-
return isInactive ? "bg-gray-300/90" :
|
|
40072
|
-
}, [data.efficiency, isInactive, position.size, position.orientation]);
|
|
40519
|
+
return isInactive ? "bg-gray-300/90" : getEfficiencyColorClasses(data.efficiency, effectiveLegend);
|
|
40520
|
+
}, [data.efficiency, effectiveLegend, isInactive, position.size, position.orientation]);
|
|
40073
40521
|
const { arrow, color: arrowColor } = useMemo(() => getTrendArrowAndColor2(data.trend_score), [data.trend_score]);
|
|
40074
40522
|
const workspaceNumber = useMemo(() => getWorkspaceNumber(data.workspace_name), [data.workspace_name]);
|
|
40075
40523
|
const styles2 = useMemo(() => getWorkspaceStyles(position, isInactive), [position, isInactive]);
|
|
@@ -40151,6 +40599,8 @@ var WorkspaceGrid = React24__default.memo(({
|
|
|
40151
40599
|
factoryView = "factory",
|
|
40152
40600
|
line2Uuid = "line-2",
|
|
40153
40601
|
className = "",
|
|
40602
|
+
hasFlowBuffers = false,
|
|
40603
|
+
legend = DEFAULT_EFFICIENCY_LEGEND,
|
|
40154
40604
|
videoSources = {},
|
|
40155
40605
|
displayNames = {},
|
|
40156
40606
|
onWorkspaceHover,
|
|
@@ -40187,7 +40637,7 @@ var WorkspaceGrid = React24__default.memo(({
|
|
|
40187
40637
|
return /* @__PURE__ */ jsxs("div", { className: `relative w-full h-full overflow-hidden ${className}`, children: [
|
|
40188
40638
|
/* @__PURE__ */ jsxs("div", { className: "absolute top-0 left-2 sm:left-4 right-2 sm:right-8 z-20", children: [
|
|
40189
40639
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-row items-center justify-between py-1 sm:py-1.5 gap-2", children: [
|
|
40190
|
-
/* @__PURE__ */ jsx("div", { className: "hidden sm:block", children: /* @__PURE__ */ jsx(Legend6, {}) }),
|
|
40640
|
+
/* @__PURE__ */ jsx("div", { className: "hidden sm:block", children: /* @__PURE__ */ jsx(Legend6, { legend, useBottleneckLabel: hasFlowBuffers }) }),
|
|
40191
40641
|
mapViewEnabled && /* @__PURE__ */ jsx(
|
|
40192
40642
|
"button",
|
|
40193
40643
|
{
|
|
@@ -40204,7 +40654,7 @@ var WorkspaceGrid = React24__default.memo(({
|
|
|
40204
40654
|
}
|
|
40205
40655
|
)
|
|
40206
40656
|
] }),
|
|
40207
|
-
/* @__PURE__ */ jsx("div", { className: "sm:hidden mt-1 mr-32", children: /* @__PURE__ */ jsx(Legend6, {}) })
|
|
40657
|
+
/* @__PURE__ */ jsx("div", { className: "sm:hidden mt-1 mr-32", children: /* @__PURE__ */ jsx(Legend6, { legend, useBottleneckLabel: hasFlowBuffers }) })
|
|
40208
40658
|
] }),
|
|
40209
40659
|
/* @__PURE__ */ jsx("div", { className: "absolute top-14 sm:top-16 left-0 right-0 bottom-0", children: /* @__PURE__ */ jsx(AnimatePresence, { mode: "wait", children: viewMode === "video" ? /* @__PURE__ */ jsx(
|
|
40210
40660
|
motion.div,
|
|
@@ -40220,6 +40670,7 @@ var WorkspaceGrid = React24__default.memo(({
|
|
|
40220
40670
|
workspaces,
|
|
40221
40671
|
videoSources,
|
|
40222
40672
|
displayNames,
|
|
40673
|
+
legend,
|
|
40223
40674
|
onWorkspaceHover,
|
|
40224
40675
|
onWorkspaceHoverEnd
|
|
40225
40676
|
}
|
|
@@ -40239,6 +40690,7 @@ var WorkspaceGrid = React24__default.memo(({
|
|
|
40239
40690
|
{
|
|
40240
40691
|
workspaces,
|
|
40241
40692
|
displayNames,
|
|
40693
|
+
legend,
|
|
40242
40694
|
onWorkspaceHover,
|
|
40243
40695
|
onWorkspaceHoverEnd
|
|
40244
40696
|
}
|
|
@@ -47719,7 +48171,7 @@ var AIAgentView = () => {
|
|
|
47719
48171
|
barRadius: [4, 4, 0, 0]
|
|
47720
48172
|
// Top corners rounded
|
|
47721
48173
|
};
|
|
47722
|
-
const
|
|
48174
|
+
const CustomTooltip4 = ({ active, payload, label }) => {
|
|
47723
48175
|
if (active && payload && payload.length) {
|
|
47724
48176
|
return /* @__PURE__ */ jsxs("div", { className: "bg-white px-4 py-3 shadow-lg rounded-lg border border-gray-200", children: [
|
|
47725
48177
|
/* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-gray-900 mb-1", children: label }),
|
|
@@ -47819,7 +48271,7 @@ var AIAgentView = () => {
|
|
|
47819
48271
|
tickFormatter: (value) => formatNumber(value)
|
|
47820
48272
|
}
|
|
47821
48273
|
),
|
|
47822
|
-
/* @__PURE__ */ jsx(Tooltip, { content: /* @__PURE__ */ jsx(
|
|
48274
|
+
/* @__PURE__ */ jsx(Tooltip, { content: /* @__PURE__ */ jsx(CustomTooltip4, {}), cursor: { fill: "rgba(0, 0, 0, 0.05)" } }),
|
|
47823
48275
|
/* @__PURE__ */ jsx(
|
|
47824
48276
|
Bar,
|
|
47825
48277
|
{
|
|
@@ -47863,7 +48315,7 @@ var AIAgentView = () => {
|
|
|
47863
48315
|
tickFormatter: (value) => formatNumber(value)
|
|
47864
48316
|
}
|
|
47865
48317
|
),
|
|
47866
|
-
/* @__PURE__ */ jsx(Tooltip, { content: /* @__PURE__ */ jsx(
|
|
48318
|
+
/* @__PURE__ */ jsx(Tooltip, { content: /* @__PURE__ */ jsx(CustomTooltip4, {}), cursor: { strokeDasharray: "3 3" } }),
|
|
47867
48319
|
/* @__PURE__ */ jsx(
|
|
47868
48320
|
Line,
|
|
47869
48321
|
{
|
|
@@ -47983,7 +48435,7 @@ var AIAgentView = () => {
|
|
|
47983
48435
|
tickFormatter: (value) => formatNumber(value)
|
|
47984
48436
|
}
|
|
47985
48437
|
),
|
|
47986
|
-
/* @__PURE__ */ jsx(Tooltip, { content: /* @__PURE__ */ jsx(
|
|
48438
|
+
/* @__PURE__ */ jsx(Tooltip, { content: /* @__PURE__ */ jsx(CustomTooltip4, {}), cursor: { strokeDasharray: "3 3" } }),
|
|
47987
48439
|
/* @__PURE__ */ jsx(
|
|
47988
48440
|
Legend,
|
|
47989
48441
|
{
|
|
@@ -48043,7 +48495,7 @@ var AIAgentView = () => {
|
|
|
48043
48495
|
tickFormatter: (value) => formatNumber(value)
|
|
48044
48496
|
}
|
|
48045
48497
|
),
|
|
48046
|
-
/* @__PURE__ */ jsx(Tooltip, { content: /* @__PURE__ */ jsx(
|
|
48498
|
+
/* @__PURE__ */ jsx(Tooltip, { content: /* @__PURE__ */ jsx(CustomTooltip4, {}), cursor: { fill: "rgba(0, 0, 0, 0.05)" } }),
|
|
48047
48499
|
/* @__PURE__ */ jsx(
|
|
48048
48500
|
Legend,
|
|
48049
48501
|
{
|
|
@@ -48207,7 +48659,7 @@ var AIAgentView = () => {
|
|
|
48207
48659
|
Tooltip,
|
|
48208
48660
|
{
|
|
48209
48661
|
cursor: { strokeDasharray: "3 3" },
|
|
48210
|
-
content: /* @__PURE__ */ jsx(
|
|
48662
|
+
content: /* @__PURE__ */ jsx(CustomTooltip4, {})
|
|
48211
48663
|
}
|
|
48212
48664
|
),
|
|
48213
48665
|
/* @__PURE__ */ jsx(
|
|
@@ -48277,7 +48729,7 @@ var AIAgentView = () => {
|
|
|
48277
48729
|
tickFormatter: (value) => formatNumber(value)
|
|
48278
48730
|
}
|
|
48279
48731
|
),
|
|
48280
|
-
/* @__PURE__ */ jsx(Tooltip, { content: /* @__PURE__ */ jsx(
|
|
48732
|
+
/* @__PURE__ */ jsx(Tooltip, { content: /* @__PURE__ */ jsx(CustomTooltip4, {}), cursor: { fill: "rgba(0, 0, 0, 0.05)" } }),
|
|
48281
48733
|
/* @__PURE__ */ jsx(
|
|
48282
48734
|
Legend,
|
|
48283
48735
|
{
|
|
@@ -48351,7 +48803,7 @@ var AIAgentView = () => {
|
|
|
48351
48803
|
tickFormatter: (value) => formatNumber(value)
|
|
48352
48804
|
}
|
|
48353
48805
|
),
|
|
48354
|
-
/* @__PURE__ */ jsx(Tooltip, { content: /* @__PURE__ */ jsx(
|
|
48806
|
+
/* @__PURE__ */ jsx(Tooltip, { content: /* @__PURE__ */ jsx(CustomTooltip4, {}), cursor: { strokeDasharray: "3 3" } }),
|
|
48355
48807
|
/* @__PURE__ */ jsx(
|
|
48356
48808
|
Legend,
|
|
48357
48809
|
{
|
|
@@ -49610,6 +50062,8 @@ function HomeView({
|
|
|
49610
50062
|
const {
|
|
49611
50063
|
workspaceMetrics,
|
|
49612
50064
|
lineMetrics,
|
|
50065
|
+
efficiencyLegend,
|
|
50066
|
+
metadata: metricsMetadata,
|
|
49613
50067
|
isLoading: metricsLoading,
|
|
49614
50068
|
error: metricsError,
|
|
49615
50069
|
refetch: refetchMetrics
|
|
@@ -49618,6 +50072,7 @@ function HomeView({
|
|
|
49618
50072
|
userAccessibleLineIds: allLineIds
|
|
49619
50073
|
// Pass user's accessible lines for supervisor filtering
|
|
49620
50074
|
});
|
|
50075
|
+
const hasFlowBuffers = Boolean(metricsMetadata?.hasFlowBuffers);
|
|
49621
50076
|
const kpis = useMemo(() => {
|
|
49622
50077
|
const lineMetricsRows = lineMetrics || [];
|
|
49623
50078
|
if (selectedLineId === factoryViewId) {
|
|
@@ -50076,8 +50531,10 @@ function HomeView({
|
|
|
50076
50531
|
workspaces: memoizedWorkspaceMetrics,
|
|
50077
50532
|
lineNames,
|
|
50078
50533
|
factoryView: factoryViewId,
|
|
50534
|
+
legend: efficiencyLegend,
|
|
50079
50535
|
videoSources,
|
|
50080
50536
|
displayNames: workspaceDisplayNames,
|
|
50537
|
+
hasFlowBuffers,
|
|
50081
50538
|
className: "h-full",
|
|
50082
50539
|
onWorkspaceHover: handleWorkspaceHover,
|
|
50083
50540
|
onWorkspaceHoverEnd: handleWorkspaceHoverEnd
|
|
@@ -50104,8 +50561,10 @@ function HomeView({
|
|
|
50104
50561
|
// Show empty grid while loading
|
|
50105
50562
|
lineNames,
|
|
50106
50563
|
factoryView: factoryViewId,
|
|
50564
|
+
legend: efficiencyLegend,
|
|
50107
50565
|
videoSources,
|
|
50108
50566
|
displayNames: workspaceDisplayNames,
|
|
50567
|
+
hasFlowBuffers,
|
|
50109
50568
|
className: "h-full",
|
|
50110
50569
|
onWorkspaceHover: handleWorkspaceHover,
|
|
50111
50570
|
onWorkspaceHoverEnd: handleWorkspaceHoverEnd
|
|
@@ -50726,6 +51185,8 @@ var KPIDetailView = ({
|
|
|
50726
51185
|
avg_efficiency: metric.avg_efficiency || 0,
|
|
50727
51186
|
underperforming_workspaces: metric.underperforming_workspaces || 0,
|
|
50728
51187
|
total_workspaces: metric.total_workspaces || 0,
|
|
51188
|
+
output: metric.current_output || 0,
|
|
51189
|
+
idealOutput: metric.ideal_output || metric.line_threshold || 0,
|
|
50729
51190
|
compliance_percentage: 95 + Math.random() * 5,
|
|
50730
51191
|
// Mock data: random value between 95-100%
|
|
50731
51192
|
hasData: true
|
|
@@ -53181,6 +53642,201 @@ var ACTION_NAMES = {
|
|
|
53181
53642
|
QUALITY_CONTROL: "Quality Control"
|
|
53182
53643
|
};
|
|
53183
53644
|
|
|
53645
|
+
// src/lib/services/efficiencyLegendService.ts
|
|
53646
|
+
var EfficiencyLegendService = class {
|
|
53647
|
+
// 5 minutes
|
|
53648
|
+
constructor(supabase) {
|
|
53649
|
+
this.cache = /* @__PURE__ */ new Map();
|
|
53650
|
+
this.cacheExpiry = /* @__PURE__ */ new Map();
|
|
53651
|
+
this.CACHE_DURATION = 5 * 60 * 1e3;
|
|
53652
|
+
this.supabase = supabase;
|
|
53653
|
+
}
|
|
53654
|
+
/**
|
|
53655
|
+
* Get efficiency legend for a company
|
|
53656
|
+
*/
|
|
53657
|
+
async getEfficiencyLegend(companyId) {
|
|
53658
|
+
try {
|
|
53659
|
+
const cached = this.cache.get(companyId);
|
|
53660
|
+
const expiry = this.cacheExpiry.get(companyId);
|
|
53661
|
+
if (cached && expiry && Date.now() < expiry) {
|
|
53662
|
+
return cached;
|
|
53663
|
+
}
|
|
53664
|
+
const params = new URLSearchParams({ company_id: companyId });
|
|
53665
|
+
const response = await fetchBackendJson(
|
|
53666
|
+
this.supabase,
|
|
53667
|
+
`/api/efficiency-legend?${params.toString()}`
|
|
53668
|
+
);
|
|
53669
|
+
const normalized = this.normalizeLegend(response?.legend);
|
|
53670
|
+
this.cache.set(companyId, normalized);
|
|
53671
|
+
this.cacheExpiry.set(companyId, Date.now() + this.CACHE_DURATION);
|
|
53672
|
+
return normalized;
|
|
53673
|
+
} catch (error) {
|
|
53674
|
+
console.error("Error fetching efficiency legend:", error);
|
|
53675
|
+
return DEFAULT_EFFICIENCY_LEGEND;
|
|
53676
|
+
}
|
|
53677
|
+
}
|
|
53678
|
+
/**
|
|
53679
|
+
* Update or create efficiency legend for a company
|
|
53680
|
+
*/
|
|
53681
|
+
async updateEfficiencyLegend(companyId, legend) {
|
|
53682
|
+
try {
|
|
53683
|
+
const normalizedLegend = this.normalizeLegend(legend);
|
|
53684
|
+
const validation = this.validateLegend(normalizedLegend);
|
|
53685
|
+
if (!validation.valid) {
|
|
53686
|
+
return { success: false, error: validation.error };
|
|
53687
|
+
}
|
|
53688
|
+
const params = new URLSearchParams({ company_id: companyId });
|
|
53689
|
+
await fetchBackendJson(
|
|
53690
|
+
this.supabase,
|
|
53691
|
+
`/api/efficiency-legend?${params.toString()}`,
|
|
53692
|
+
{
|
|
53693
|
+
method: "PUT",
|
|
53694
|
+
body: JSON.stringify(normalizedLegend)
|
|
53695
|
+
}
|
|
53696
|
+
);
|
|
53697
|
+
this.cache.delete(companyId);
|
|
53698
|
+
this.cacheExpiry.delete(companyId);
|
|
53699
|
+
return { success: true };
|
|
53700
|
+
} catch (error) {
|
|
53701
|
+
console.error("Error updating efficiency legend:", error);
|
|
53702
|
+
return { success: false, error: error.message || "Failed to update efficiency legend" };
|
|
53703
|
+
}
|
|
53704
|
+
}
|
|
53705
|
+
/**
|
|
53706
|
+
* Clear cache for a specific company
|
|
53707
|
+
*/
|
|
53708
|
+
clearCache(companyId) {
|
|
53709
|
+
this.cache.delete(companyId);
|
|
53710
|
+
this.cacheExpiry.delete(companyId);
|
|
53711
|
+
}
|
|
53712
|
+
/**
|
|
53713
|
+
* Clear all cache
|
|
53714
|
+
*/
|
|
53715
|
+
clearAllCache() {
|
|
53716
|
+
this.cache.clear();
|
|
53717
|
+
this.cacheExpiry.clear();
|
|
53718
|
+
}
|
|
53719
|
+
/**
|
|
53720
|
+
* Validate legend configuration
|
|
53721
|
+
*/
|
|
53722
|
+
validateLegend(legend) {
|
|
53723
|
+
if (legend.green_min < 0 || legend.green_min > 100) {
|
|
53724
|
+
return { valid: false, error: "Green minimum must be between 0 and 100" };
|
|
53725
|
+
}
|
|
53726
|
+
if (legend.green_max < 0 || legend.green_max > 100) {
|
|
53727
|
+
return { valid: false, error: "Green maximum must be between 0 and 100" };
|
|
53728
|
+
}
|
|
53729
|
+
if (legend.yellow_min < 0 || legend.yellow_min > 100) {
|
|
53730
|
+
return { valid: false, error: "Yellow minimum must be between 0 and 100" };
|
|
53731
|
+
}
|
|
53732
|
+
if (legend.yellow_max < 0 || legend.yellow_max > 100) {
|
|
53733
|
+
return { valid: false, error: "Yellow maximum must be between 0 and 100" };
|
|
53734
|
+
}
|
|
53735
|
+
if (legend.red_min < 0 || legend.red_min > 100) {
|
|
53736
|
+
return { valid: false, error: "Red minimum must be between 0 and 100" };
|
|
53737
|
+
}
|
|
53738
|
+
if (legend.red_max < 0 || legend.red_max > 100) {
|
|
53739
|
+
return { valid: false, error: "Red maximum must be between 0 and 100" };
|
|
53740
|
+
}
|
|
53741
|
+
if (legend.critical_threshold < 0 || legend.critical_threshold > 100) {
|
|
53742
|
+
return { valid: false, error: "Critical threshold must be between 0 and 100" };
|
|
53743
|
+
}
|
|
53744
|
+
if (legend.yellow_min >= legend.green_min) {
|
|
53745
|
+
return { valid: false, error: "Yellow minimum must be less than green minimum" };
|
|
53746
|
+
}
|
|
53747
|
+
if (legend.red_max >= legend.yellow_min) {
|
|
53748
|
+
return { valid: false, error: "Red maximum must be less than yellow minimum" };
|
|
53749
|
+
}
|
|
53750
|
+
if (legend.critical_threshold > legend.red_max) {
|
|
53751
|
+
return { valid: false, error: "Critical threshold must be less than or equal to red maximum" };
|
|
53752
|
+
}
|
|
53753
|
+
return { valid: true };
|
|
53754
|
+
}
|
|
53755
|
+
normalizeLegend(legend) {
|
|
53756
|
+
const fallback = DEFAULT_EFFICIENCY_LEGEND;
|
|
53757
|
+
if (!legend) return fallback;
|
|
53758
|
+
const coerce = (value, fallbackValue) => {
|
|
53759
|
+
const num = Number(value);
|
|
53760
|
+
return Number.isFinite(num) ? num : fallbackValue;
|
|
53761
|
+
};
|
|
53762
|
+
return {
|
|
53763
|
+
green_min: coerce(legend.green_min, fallback.green_min),
|
|
53764
|
+
green_max: coerce(legend.green_max, fallback.green_max),
|
|
53765
|
+
yellow_min: coerce(legend.yellow_min, fallback.yellow_min),
|
|
53766
|
+
yellow_max: coerce(legend.yellow_max, fallback.yellow_max),
|
|
53767
|
+
red_min: coerce(legend.red_min, fallback.red_min),
|
|
53768
|
+
red_max: coerce(legend.red_max, fallback.red_max),
|
|
53769
|
+
critical_threshold: coerce(legend.critical_threshold, fallback.critical_threshold)
|
|
53770
|
+
};
|
|
53771
|
+
}
|
|
53772
|
+
};
|
|
53773
|
+
var efficiencyLegendServiceInstance = null;
|
|
53774
|
+
function getEfficiencyLegendService(supabase) {
|
|
53775
|
+
if (!efficiencyLegendServiceInstance) {
|
|
53776
|
+
efficiencyLegendServiceInstance = new EfficiencyLegendService(supabase);
|
|
53777
|
+
}
|
|
53778
|
+
return efficiencyLegendServiceInstance;
|
|
53779
|
+
}
|
|
53780
|
+
|
|
53781
|
+
// src/lib/hooks/useEfficiencyLegend.ts
|
|
53782
|
+
function useEfficiencyLegend(companyId) {
|
|
53783
|
+
const supabase = useSupabase();
|
|
53784
|
+
const config = useDashboardConfig();
|
|
53785
|
+
const [legend, setLegend] = useState(DEFAULT_EFFICIENCY_LEGEND);
|
|
53786
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
53787
|
+
const [error, setError] = useState(null);
|
|
53788
|
+
const effectiveCompanyId = companyId || config.entityConfig?.companyId;
|
|
53789
|
+
const fetchLegend = useCallback(async () => {
|
|
53790
|
+
if (!supabase || !effectiveCompanyId) {
|
|
53791
|
+
setIsLoading(false);
|
|
53792
|
+
return;
|
|
53793
|
+
}
|
|
53794
|
+
try {
|
|
53795
|
+
setIsLoading(true);
|
|
53796
|
+
setError(null);
|
|
53797
|
+
const service = getEfficiencyLegendService(supabase);
|
|
53798
|
+
const fetchedLegend = await service.getEfficiencyLegend(effectiveCompanyId);
|
|
53799
|
+
setLegend(fetchedLegend);
|
|
53800
|
+
} catch (err) {
|
|
53801
|
+
console.error("Error fetching efficiency legend:", err);
|
|
53802
|
+
setError(err.message || "Failed to fetch efficiency legend");
|
|
53803
|
+
setLegend(DEFAULT_EFFICIENCY_LEGEND);
|
|
53804
|
+
} finally {
|
|
53805
|
+
setIsLoading(false);
|
|
53806
|
+
}
|
|
53807
|
+
}, [supabase, effectiveCompanyId]);
|
|
53808
|
+
useEffect(() => {
|
|
53809
|
+
fetchLegend();
|
|
53810
|
+
}, [fetchLegend]);
|
|
53811
|
+
const updateLegend = useCallback(async (newLegend) => {
|
|
53812
|
+
if (!supabase || !effectiveCompanyId) {
|
|
53813
|
+
return { success: false, error: "Supabase client or company ID not available" };
|
|
53814
|
+
}
|
|
53815
|
+
try {
|
|
53816
|
+
const service = getEfficiencyLegendService(supabase);
|
|
53817
|
+
const result = await service.updateEfficiencyLegend(effectiveCompanyId, newLegend);
|
|
53818
|
+
if (result.success) {
|
|
53819
|
+
setLegend(newLegend);
|
|
53820
|
+
setError(null);
|
|
53821
|
+
} else {
|
|
53822
|
+
setError(result.error || "Failed to update efficiency legend");
|
|
53823
|
+
}
|
|
53824
|
+
return result;
|
|
53825
|
+
} catch (err) {
|
|
53826
|
+
const errorMsg = err.message || "Failed to update efficiency legend";
|
|
53827
|
+
setError(errorMsg);
|
|
53828
|
+
return { success: false, error: errorMsg };
|
|
53829
|
+
}
|
|
53830
|
+
}, [supabase, effectiveCompanyId]);
|
|
53831
|
+
return {
|
|
53832
|
+
legend,
|
|
53833
|
+
isLoading,
|
|
53834
|
+
error,
|
|
53835
|
+
updateLegend,
|
|
53836
|
+
refetch: fetchLegend
|
|
53837
|
+
};
|
|
53838
|
+
}
|
|
53839
|
+
|
|
53184
53840
|
// src/views/TargetsView.utils.ts
|
|
53185
53841
|
var calculatePPH = (cycleTime, breaks = [], shiftHours = 0) => {
|
|
53186
53842
|
if (cycleTime === "" || cycleTime === 0) return "";
|
|
@@ -53207,369 +53863,245 @@ var getStoredLineState2 = (lineId) => {
|
|
|
53207
53863
|
return false;
|
|
53208
53864
|
}
|
|
53209
53865
|
};
|
|
53210
|
-
var
|
|
53866
|
+
var ConfigureLegendModal = ({
|
|
53211
53867
|
isOpen,
|
|
53212
53868
|
onClose,
|
|
53213
|
-
lineWorkspaces,
|
|
53214
|
-
lineNames,
|
|
53215
53869
|
onSave,
|
|
53216
|
-
|
|
53870
|
+
legend,
|
|
53871
|
+
canSave = true
|
|
53217
53872
|
}) => {
|
|
53218
|
-
const
|
|
53219
|
-
const [
|
|
53220
|
-
const [
|
|
53221
|
-
const [
|
|
53222
|
-
const [
|
|
53223
|
-
const [targetDayOutput, setTargetDayOutput] = useState("");
|
|
53224
|
-
const [productId, setProductId] = useState("");
|
|
53225
|
-
const [selectedCount, setSelectedCount] = useState(0);
|
|
53226
|
-
const shiftHours = useMemo(() => {
|
|
53227
|
-
if (selectedLine && lineWorkspaces[selectedLine]) {
|
|
53228
|
-
return lineWorkspaces[selectedLine].shiftHours;
|
|
53229
|
-
}
|
|
53230
|
-
return 8;
|
|
53231
|
-
}, [selectedLine, lineWorkspaces]);
|
|
53232
|
-
const selectedLineBreaks = useMemo(() => {
|
|
53233
|
-
if (selectedLine && lineWorkspaces[selectedLine]) {
|
|
53234
|
-
return lineWorkspaces[selectedLine].breaks;
|
|
53235
|
-
}
|
|
53236
|
-
return [];
|
|
53237
|
-
}, [selectedLine, lineWorkspaces]);
|
|
53238
|
-
useEffect(() => {
|
|
53239
|
-
if (!isOpen) {
|
|
53240
|
-
setTimeout(() => {
|
|
53241
|
-
setSelectedLine("");
|
|
53242
|
-
setSelectedWorkspaces([]);
|
|
53243
|
-
setActionType("assembly");
|
|
53244
|
-
setTargetPPH("");
|
|
53245
|
-
setTargetCycleTime("");
|
|
53246
|
-
setTargetDayOutput("");
|
|
53247
|
-
setProductId("");
|
|
53248
|
-
}, 200);
|
|
53249
|
-
}
|
|
53250
|
-
}, [isOpen]);
|
|
53873
|
+
const effectiveLegend = legend || DEFAULT_EFFICIENCY_LEGEND;
|
|
53874
|
+
const [redThreshold, setRedThreshold] = useState(effectiveLegend.yellow_min);
|
|
53875
|
+
const [greenThreshold, setGreenThreshold] = useState(effectiveLegend.green_min);
|
|
53876
|
+
const [isSaving, setIsSaving] = useState(false);
|
|
53877
|
+
const [saveSuccess, setSaveSuccess] = useState(false);
|
|
53251
53878
|
useEffect(() => {
|
|
53252
|
-
if (
|
|
53253
|
-
|
|
53879
|
+
if (isOpen) {
|
|
53880
|
+
setRedThreshold(effectiveLegend.yellow_min);
|
|
53881
|
+
setGreenThreshold(effectiveLegend.green_min);
|
|
53882
|
+
setSaveSuccess(false);
|
|
53254
53883
|
}
|
|
53255
|
-
}, [
|
|
53256
|
-
useEffect(() => {
|
|
53257
|
-
setSelectedCount(selectedWorkspaces.length);
|
|
53258
|
-
}, [selectedWorkspaces]);
|
|
53884
|
+
}, [isOpen, effectiveLegend]);
|
|
53259
53885
|
const handleSave = async () => {
|
|
53260
|
-
if (
|
|
53261
|
-
toast.error("
|
|
53886
|
+
if (!canSave) {
|
|
53887
|
+
toast.error("You do not have permission to update the legend.");
|
|
53262
53888
|
return;
|
|
53263
53889
|
}
|
|
53264
|
-
if (
|
|
53265
|
-
toast.error("Please enter
|
|
53890
|
+
if (redThreshold === "" || greenThreshold === "") {
|
|
53891
|
+
toast.error("Please enter valid threshold values");
|
|
53266
53892
|
return;
|
|
53267
53893
|
}
|
|
53268
|
-
if (
|
|
53269
|
-
toast.error("
|
|
53894
|
+
if (Number(redThreshold) >= Number(greenThreshold)) {
|
|
53895
|
+
toast.error("Red threshold must be lower than Green threshold");
|
|
53270
53896
|
return;
|
|
53271
53897
|
}
|
|
53272
|
-
|
|
53273
|
-
|
|
53274
|
-
|
|
53275
|
-
...targetCycleTime !== "" && { targetCycleTime },
|
|
53276
|
-
...targetDayOutput !== "" && { targetDayOutput }
|
|
53277
|
-
};
|
|
53278
|
-
if (targetCycleTime !== "" && targetPPH === "") {
|
|
53279
|
-
const lineBreaks = lineWorkspaces[selectedLine].breaks || [];
|
|
53280
|
-
const lineShiftHours = lineWorkspaces[selectedLine].shiftHours;
|
|
53281
|
-
const calculatedPPH = calculatePPH(targetCycleTime, lineBreaks, lineShiftHours);
|
|
53282
|
-
if (calculatedPPH !== "") {
|
|
53283
|
-
updates.targetPPH = calculatedPPH;
|
|
53284
|
-
}
|
|
53285
|
-
}
|
|
53286
|
-
if (updates.targetPPH !== void 0 && targetDayOutput === "") {
|
|
53287
|
-
const lineBreaks = lineWorkspaces[selectedLine].breaks || [];
|
|
53288
|
-
const lineShiftHours = lineWorkspaces[selectedLine].shiftHours;
|
|
53289
|
-
const calculatedOutput = calculateDayOutput(updates.targetPPH, lineShiftHours, lineBreaks);
|
|
53290
|
-
if (calculatedOutput !== "") {
|
|
53291
|
-
updates.targetDayOutput = calculatedOutput;
|
|
53292
|
-
}
|
|
53293
|
-
}
|
|
53294
|
-
onSave({
|
|
53295
|
-
lineId: selectedLine,
|
|
53296
|
-
workspaceIds: selectedWorkspaces,
|
|
53297
|
-
productId,
|
|
53298
|
-
updates
|
|
53299
|
-
});
|
|
53300
|
-
onClose();
|
|
53301
|
-
};
|
|
53302
|
-
const toggleAllWorkspaces = (lineId) => {
|
|
53303
|
-
if (!lineWorkspaces[lineId]) return;
|
|
53304
|
-
const allWorkspaceIds = lineWorkspaces[lineId].workspaces.map((w) => w.id);
|
|
53305
|
-
if (selectedWorkspaces.length === allWorkspaceIds.length) {
|
|
53306
|
-
setSelectedWorkspaces([]);
|
|
53307
|
-
} else {
|
|
53308
|
-
setSelectedWorkspaces(allWorkspaceIds);
|
|
53898
|
+
if (Number(redThreshold) < 1 || Number(redThreshold) > 100 || Number(greenThreshold) > 100) {
|
|
53899
|
+
toast.error("Thresholds must be between 1 and 100");
|
|
53900
|
+
return;
|
|
53309
53901
|
}
|
|
53310
|
-
|
|
53311
|
-
|
|
53312
|
-
|
|
53313
|
-
|
|
53314
|
-
|
|
53902
|
+
const redMax = Number(redThreshold) - 1;
|
|
53903
|
+
const yellowMax = Number(greenThreshold) - 1;
|
|
53904
|
+
if (redMax < DEFAULT_EFFICIENCY_LEGEND.critical_threshold) {
|
|
53905
|
+
toast.error("Red threshold must be above 50% while critical alerts are fixed at <50%.");
|
|
53906
|
+
return;
|
|
53907
|
+
}
|
|
53908
|
+
setIsSaving(true);
|
|
53909
|
+
setSaveSuccess(false);
|
|
53910
|
+
try {
|
|
53911
|
+
const result = await onSave({
|
|
53912
|
+
green_min: Number(greenThreshold),
|
|
53913
|
+
green_max: 100,
|
|
53914
|
+
yellow_min: Number(redThreshold),
|
|
53915
|
+
yellow_max: yellowMax,
|
|
53916
|
+
red_min: 0,
|
|
53917
|
+
red_max: redMax,
|
|
53918
|
+
critical_threshold: DEFAULT_EFFICIENCY_LEGEND.critical_threshold
|
|
53919
|
+
});
|
|
53920
|
+
if (result.success) {
|
|
53921
|
+
setSaveSuccess(true);
|
|
53922
|
+
setTimeout(() => setSaveSuccess(false), 3e3);
|
|
53923
|
+
} else {
|
|
53924
|
+
toast.error(result.error || "Failed to update legend");
|
|
53315
53925
|
}
|
|
53316
|
-
}
|
|
53317
|
-
|
|
53318
|
-
|
|
53926
|
+
} catch (error) {
|
|
53927
|
+
console.error("Error saving legend:", error);
|
|
53928
|
+
toast.error("Failed to update legend");
|
|
53929
|
+
} finally {
|
|
53930
|
+
setIsSaving(false);
|
|
53319
53931
|
}
|
|
53320
|
-
|
|
53321
|
-
document.removeEventListener("keydown", handleEscape);
|
|
53322
|
-
};
|
|
53323
|
-
}, [isOpen, onClose]);
|
|
53932
|
+
};
|
|
53324
53933
|
if (!isOpen) return null;
|
|
53325
53934
|
return /* @__PURE__ */ jsx(
|
|
53326
53935
|
"div",
|
|
53327
53936
|
{
|
|
53328
|
-
className: "fixed inset-0 bg-gray-900/
|
|
53937
|
+
className: "fixed inset-0 bg-gray-900/40 backdrop-blur-sm z-50 flex items-center justify-center transition-opacity duration-300",
|
|
53329
53938
|
onClick: (e) => {
|
|
53330
53939
|
if (e.target === e.currentTarget) {
|
|
53331
53940
|
onClose();
|
|
53332
53941
|
}
|
|
53333
53942
|
},
|
|
53334
|
-
children: /* @__PURE__ */ jsxs("div", { className: "bg-white rounded-
|
|
53335
|
-
/* @__PURE__ */ jsxs("div", { className: "px-6 py-
|
|
53943
|
+
children: /* @__PURE__ */ jsxs("div", { className: "bg-white rounded-lg shadow-xl w-full max-w-xl flex flex-col animate-modal-in transform transition-all", children: [
|
|
53944
|
+
/* @__PURE__ */ jsxs("div", { className: "px-6 py-5 border-b border-gray-100 flex items-center justify-between bg-white rounded-t-lg", children: [
|
|
53336
53945
|
/* @__PURE__ */ jsxs("div", { children: [
|
|
53337
|
-
/* @__PURE__ */ jsx("h2", { className: "text-
|
|
53338
|
-
/* @__PURE__ */ jsx("p", { className: "
|
|
53946
|
+
/* @__PURE__ */ jsx("h2", { className: "text-base font-semibold text-gray-900", children: "Performance Thresholds" }),
|
|
53947
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm text-gray-500 mt-0.5", children: "Define acceptance criteria for production metrics." })
|
|
53339
53948
|
] }),
|
|
53340
53949
|
/* @__PURE__ */ jsx(
|
|
53341
53950
|
"button",
|
|
53342
53951
|
{
|
|
53343
53952
|
onClick: onClose,
|
|
53344
|
-
className: "text-gray-400 hover:text-gray-
|
|
53345
|
-
children: /* @__PURE__ */ jsx(X, { className: "w-
|
|
53953
|
+
className: "text-gray-400 hover:text-gray-600 transition-colors p-1.5 hover:bg-gray-50 rounded-md",
|
|
53954
|
+
children: /* @__PURE__ */ jsx(X, { className: "w-4 h-4" })
|
|
53346
53955
|
}
|
|
53347
53956
|
)
|
|
53348
53957
|
] }),
|
|
53349
|
-
/* @__PURE__ */ jsxs("div", { className: "p-
|
|
53350
|
-
/* @__PURE__ */ jsxs("div", { className: "space-y-6", children: [
|
|
53351
|
-
|
|
53352
|
-
|
|
53353
|
-
|
|
53354
|
-
|
|
53355
|
-
|
|
53356
|
-
|
|
53357
|
-
|
|
53358
|
-
|
|
53359
|
-
|
|
53360
|
-
|
|
53361
|
-
|
|
53362
|
-
|
|
53363
|
-
|
|
53364
|
-
|
|
53365
|
-
|
|
53366
|
-
|
|
53367
|
-
|
|
53368
|
-
|
|
53369
|
-
|
|
53370
|
-
|
|
53371
|
-
|
|
53372
|
-
|
|
53373
|
-
|
|
53374
|
-
{
|
|
53375
|
-
|
|
53376
|
-
|
|
53377
|
-
|
|
53378
|
-
|
|
53379
|
-
|
|
53380
|
-
|
|
53381
|
-
|
|
53382
|
-
|
|
53383
|
-
|
|
53384
|
-
|
|
53385
|
-
|
|
53386
|
-
|
|
53387
|
-
|
|
53388
|
-
|
|
53389
|
-
|
|
53390
|
-
|
|
53391
|
-
|
|
53392
|
-
|
|
53393
|
-
|
|
53394
|
-
|
|
53395
|
-
|
|
53396
|
-
|
|
53397
|
-
|
|
53398
|
-
|
|
53399
|
-
|
|
53400
|
-
}
|
|
53401
|
-
|
|
53402
|
-
|
|
53403
|
-
|
|
53404
|
-
|
|
53405
|
-
|
|
53406
|
-
|
|
53407
|
-
children: [
|
|
53408
|
-
/* @__PURE__ */ jsx(
|
|
53409
|
-
"input",
|
|
53410
|
-
{
|
|
53411
|
-
type: "checkbox",
|
|
53412
|
-
checked: selectedWorkspaces.includes(workspace.id),
|
|
53413
|
-
onChange: (e) => {
|
|
53414
|
-
if (e.target.checked) {
|
|
53415
|
-
setSelectedWorkspaces((prev) => [...prev, workspace.id]);
|
|
53416
|
-
} else {
|
|
53417
|
-
setSelectedWorkspaces((prev) => prev.filter((id3) => id3 !== workspace.id));
|
|
53418
|
-
}
|
|
53419
|
-
},
|
|
53420
|
-
className: "rounded border-gray-300 text-blue-600 focus:ring-blue-500"
|
|
53421
|
-
}
|
|
53422
|
-
),
|
|
53423
|
-
/* @__PURE__ */ jsx("span", { className: `text-sm ${selectedWorkspaces.includes(workspace.id) ? "text-blue-900 font-medium" : "text-gray-900"}`, children: formatWorkspaceName(workspace.name, selectedLine) })
|
|
53424
|
-
]
|
|
53425
|
-
},
|
|
53426
|
-
workspace.id
|
|
53427
|
-
)) })
|
|
53428
|
-
] }),
|
|
53429
|
-
/* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
53430
|
-
/* @__PURE__ */ jsx("label", { className: "block text-sm font-medium text-gray-700", children: "Action Type" }),
|
|
53431
|
-
/* @__PURE__ */ jsxs(
|
|
53432
|
-
"select",
|
|
53433
|
-
{
|
|
53434
|
-
value: actionType,
|
|
53435
|
-
onChange: (e) => setActionType(e.target.value),
|
|
53436
|
-
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-blue-400\n appearance-none bg-no-repeat bg-right pr-10\n hover:bg-blue-50/50",
|
|
53437
|
-
children: [
|
|
53438
|
-
/* @__PURE__ */ jsx("option", { value: "assembly", className: "py-2", children: "Assembly" }),
|
|
53439
|
-
/* @__PURE__ */ jsx("option", { value: "packaging", className: "py-2", children: "Packaging" })
|
|
53440
|
-
]
|
|
53441
|
-
}
|
|
53442
|
-
)
|
|
53443
|
-
] })
|
|
53958
|
+
/* @__PURE__ */ jsxs("div", { className: "p-8 space-y-8", children: [
|
|
53959
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-2 pt-6", children: [
|
|
53960
|
+
" ",
|
|
53961
|
+
/* @__PURE__ */ jsxs("div", { className: "h-6 w-full rounded-md bg-gray-100 relative overflow-visible ring-1 ring-black/5 flex mt-2", children: [
|
|
53962
|
+
/* @__PURE__ */ jsx(
|
|
53963
|
+
"div",
|
|
53964
|
+
{
|
|
53965
|
+
className: "h-full bg-red-500 transition-all duration-500 ease-in-out relative group first:rounded-l-md",
|
|
53966
|
+
style: { width: `${Math.min(Number(redThreshold) || 0, 100)}%` },
|
|
53967
|
+
children: /* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-white/0 group-hover:bg-white/10 transition-colors" })
|
|
53968
|
+
}
|
|
53969
|
+
),
|
|
53970
|
+
/* @__PURE__ */ jsx(
|
|
53971
|
+
"div",
|
|
53972
|
+
{
|
|
53973
|
+
className: "h-full bg-yellow-400 transition-all duration-500 ease-in-out relative group",
|
|
53974
|
+
style: { width: `${Math.max(0, Math.min((Number(greenThreshold) || 0) - (Number(redThreshold) || 0), 100 - (Number(redThreshold) || 0)))}%` },
|
|
53975
|
+
children: /* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-white/0 group-hover:bg-white/10 transition-colors" })
|
|
53976
|
+
}
|
|
53977
|
+
),
|
|
53978
|
+
/* @__PURE__ */ jsx(
|
|
53979
|
+
"div",
|
|
53980
|
+
{
|
|
53981
|
+
className: "h-full bg-green-500 transition-all duration-500 ease-in-out relative group last:rounded-r-md",
|
|
53982
|
+
style: { width: `${Math.max(0, 100 - (Number(greenThreshold) || 0))}%` },
|
|
53983
|
+
children: /* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-white/0 group-hover:bg-white/10 transition-colors" })
|
|
53984
|
+
}
|
|
53985
|
+
),
|
|
53986
|
+
/* @__PURE__ */ jsx(
|
|
53987
|
+
"div",
|
|
53988
|
+
{
|
|
53989
|
+
className: "absolute -top-8 transition-all duration-500 ease-in-out z-20",
|
|
53990
|
+
style: { left: `${Math.min(Number(redThreshold) || 0, 100)}%`, transform: "translateX(-50%)" },
|
|
53991
|
+
children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center", children: [
|
|
53992
|
+
/* @__PURE__ */ jsxs("span", { className: "text-xs font-bold text-gray-900 bg-white px-1.5 py-0.5 rounded shadow-sm border border-gray-200 mb-1 whitespace-nowrap", children: [
|
|
53993
|
+
redThreshold,
|
|
53994
|
+
"%"
|
|
53995
|
+
] }),
|
|
53996
|
+
/* @__PURE__ */ jsx("div", { className: "w-px h-3 bg-gray-400/50" })
|
|
53997
|
+
] })
|
|
53998
|
+
}
|
|
53999
|
+
),
|
|
54000
|
+
/* @__PURE__ */ jsx(
|
|
54001
|
+
"div",
|
|
54002
|
+
{
|
|
54003
|
+
className: "absolute -top-8 transition-all duration-500 ease-in-out z-20",
|
|
54004
|
+
style: { left: `${Math.min(Number(greenThreshold) || 0, 100)}%`, transform: "translateX(-50%)" },
|
|
54005
|
+
children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center", children: [
|
|
54006
|
+
/* @__PURE__ */ jsxs("span", { className: "text-xs font-bold text-gray-900 bg-white px-1.5 py-0.5 rounded shadow-sm border border-gray-200 mb-1 whitespace-nowrap", children: [
|
|
54007
|
+
greenThreshold,
|
|
54008
|
+
"%"
|
|
54009
|
+
] }),
|
|
54010
|
+
/* @__PURE__ */ jsx("div", { className: "w-px h-3 bg-gray-400/50" })
|
|
54011
|
+
] })
|
|
54012
|
+
}
|
|
54013
|
+
),
|
|
54014
|
+
/* @__PURE__ */ jsx("div", { className: "absolute top-0 bottom-0 w-px bg-white/50 z-10 pointer-events-none", style: { left: `${Math.min(Number(redThreshold) || 0, 100)}%` } }),
|
|
54015
|
+
/* @__PURE__ */ jsx("div", { className: "absolute top-0 bottom-0 w-px bg-white/50 z-10 pointer-events-none", style: { left: `${Math.min(Number(greenThreshold) || 0, 100)}%` } })
|
|
53444
54016
|
] }),
|
|
53445
|
-
/* @__PURE__ */
|
|
53446
|
-
/* @__PURE__ */
|
|
53447
|
-
|
|
53448
|
-
|
|
53449
|
-
|
|
53450
|
-
|
|
53451
|
-
|
|
54017
|
+
/* @__PURE__ */ jsxs("div", { className: "flex justify-between text-xs font-medium text-gray-400 pt-1", children: [
|
|
54018
|
+
/* @__PURE__ */ jsx("span", { children: "0%" }),
|
|
54019
|
+
/* @__PURE__ */ jsx("span", { children: "100%+" })
|
|
54020
|
+
] })
|
|
54021
|
+
] }),
|
|
54022
|
+
/* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-8 relative", children: [
|
|
54023
|
+
/* @__PURE__ */ jsx("div", { className: "absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 text-gray-300", children: /* @__PURE__ */ jsx(ArrowRight, { className: "w-5 h-5" }) }),
|
|
54024
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
54025
|
+
/* @__PURE__ */ jsx("label", { className: "block text-sm font-medium text-gray-700 mb-2", children: "Critical Limit" }),
|
|
54026
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center", children: [
|
|
54027
|
+
/* @__PURE__ */ jsx("div", { className: "w-2 h-2 rounded-full bg-red-500 mr-2.5" }),
|
|
54028
|
+
/* @__PURE__ */ jsxs("div", { className: "relative w-full", children: [
|
|
53452
54029
|
/* @__PURE__ */ jsx(
|
|
53453
54030
|
"input",
|
|
53454
54031
|
{
|
|
53455
54032
|
type: "number",
|
|
53456
|
-
value:
|
|
54033
|
+
value: redThreshold,
|
|
53457
54034
|
onChange: (e) => {
|
|
53458
|
-
|
|
53459
|
-
|
|
53460
|
-
if (newValue !== "" && newValue > 0) {
|
|
53461
|
-
const pph = calculatePPH(newValue, selectedLineBreaks, shiftHours);
|
|
53462
|
-
setTargetPPH(pph);
|
|
53463
|
-
const dayOutput = calculateDayOutput(pph, shiftHours, selectedLineBreaks);
|
|
53464
|
-
setTargetDayOutput(dayOutput);
|
|
53465
|
-
} else if (newValue === "") {
|
|
53466
|
-
setTargetPPH("");
|
|
53467
|
-
setTargetDayOutput("");
|
|
53468
|
-
}
|
|
54035
|
+
setRedThreshold(e.target.value === "" ? "" : Number(e.target.value));
|
|
54036
|
+
setSaveSuccess(false);
|
|
53469
54037
|
},
|
|
53470
|
-
|
|
53471
|
-
|
|
53472
|
-
|
|
53473
|
-
placeholder: "
|
|
54038
|
+
min: 1,
|
|
54039
|
+
max: 100,
|
|
54040
|
+
className: "block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 sm:text-sm py-2 px-3 bg-white no-spinner",
|
|
54041
|
+
placeholder: "70"
|
|
53474
54042
|
}
|
|
53475
54043
|
),
|
|
53476
|
-
|
|
53477
|
-
"button",
|
|
53478
|
-
{
|
|
53479
|
-
onClick: () => {
|
|
53480
|
-
setTargetCycleTime("");
|
|
53481
|
-
setTargetPPH("");
|
|
53482
|
-
setTargetDayOutput("");
|
|
53483
|
-
},
|
|
53484
|
-
className: "absolute right-2 top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-500",
|
|
53485
|
-
children: /* @__PURE__ */ jsx(X, { className: "w-4 h-4" })
|
|
53486
|
-
}
|
|
53487
|
-
)
|
|
54044
|
+
/* @__PURE__ */ jsx("div", { className: "absolute inset-y-0 right-0 pr-3 flex items-center pointer-events-none", children: /* @__PURE__ */ jsx("span", { className: "text-gray-500 sm:text-sm", children: "%" }) })
|
|
53488
54045
|
] })
|
|
53489
54046
|
] }),
|
|
53490
|
-
/* @__PURE__ */ jsxs("
|
|
53491
|
-
|
|
53492
|
-
|
|
53493
|
-
|
|
54047
|
+
/* @__PURE__ */ jsxs("p", { className: "mt-2 text-xs text-gray-500", children: [
|
|
54048
|
+
"Efficiency below ",
|
|
54049
|
+
/* @__PURE__ */ jsxs("span", { className: "font-medium text-gray-900", children: [
|
|
54050
|
+
redThreshold,
|
|
54051
|
+
"%"
|
|
53494
54052
|
] }),
|
|
53495
|
-
|
|
54053
|
+
" will show in ",
|
|
54054
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium text-red-600", children: "red" }),
|
|
54055
|
+
"."
|
|
54056
|
+
] })
|
|
54057
|
+
] }),
|
|
54058
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
54059
|
+
/* @__PURE__ */ jsx("label", { className: "block text-sm font-medium text-gray-700 mb-2", children: "Target Limit" }),
|
|
54060
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center", children: [
|
|
54061
|
+
/* @__PURE__ */ jsx("div", { className: "w-2 h-2 rounded-full bg-green-500 mr-2.5" }),
|
|
54062
|
+
/* @__PURE__ */ jsxs("div", { className: "relative w-full", children: [
|
|
53496
54063
|
/* @__PURE__ */ jsx(
|
|
53497
54064
|
"input",
|
|
53498
54065
|
{
|
|
53499
54066
|
type: "number",
|
|
53500
|
-
value:
|
|
54067
|
+
value: greenThreshold,
|
|
53501
54068
|
onChange: (e) => {
|
|
53502
|
-
|
|
53503
|
-
|
|
53504
|
-
if (newValue !== "") {
|
|
53505
|
-
const dayOutput = calculateDayOutput(newValue, shiftHours, selectedLineBreaks);
|
|
53506
|
-
setTargetDayOutput(dayOutput);
|
|
53507
|
-
}
|
|
54069
|
+
setGreenThreshold(e.target.value === "" ? "" : Number(e.target.value));
|
|
54070
|
+
setSaveSuccess(false);
|
|
53508
54071
|
},
|
|
53509
|
-
|
|
53510
|
-
|
|
53511
|
-
|
|
53512
|
-
placeholder: "
|
|
54072
|
+
min: 1,
|
|
54073
|
+
max: 100,
|
|
54074
|
+
className: "block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 sm:text-sm py-2 px-3 bg-white no-spinner",
|
|
54075
|
+
placeholder: "80"
|
|
53513
54076
|
}
|
|
53514
54077
|
),
|
|
53515
|
-
|
|
53516
|
-
"button",
|
|
53517
|
-
{
|
|
53518
|
-
onClick: () => {
|
|
53519
|
-
setTargetPPH("");
|
|
53520
|
-
setTargetDayOutput("");
|
|
53521
|
-
},
|
|
53522
|
-
className: "absolute right-2 top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-500",
|
|
53523
|
-
children: /* @__PURE__ */ jsx(X, { className: "w-4 h-4" })
|
|
53524
|
-
}
|
|
53525
|
-
)
|
|
54078
|
+
/* @__PURE__ */ jsx("div", { className: "absolute inset-y-0 right-0 pr-3 flex items-center pointer-events-none", children: /* @__PURE__ */ jsx("span", { className: "text-gray-500 sm:text-sm", children: "%" }) })
|
|
53526
54079
|
] })
|
|
53527
54080
|
] }),
|
|
53528
|
-
/* @__PURE__ */ jsxs("
|
|
53529
|
-
|
|
53530
|
-
|
|
53531
|
-
|
|
54081
|
+
/* @__PURE__ */ jsxs("p", { className: "mt-2 text-xs text-gray-500", children: [
|
|
54082
|
+
"Efficiency above ",
|
|
54083
|
+
/* @__PURE__ */ jsxs("span", { className: "font-medium text-gray-900", children: [
|
|
54084
|
+
greenThreshold,
|
|
54085
|
+
"%"
|
|
53532
54086
|
] }),
|
|
53533
|
-
|
|
53534
|
-
|
|
53535
|
-
|
|
53536
|
-
{
|
|
53537
|
-
type: "number",
|
|
53538
|
-
value: targetDayOutput,
|
|
53539
|
-
onChange: (e) => setTargetDayOutput(e.target.value ? Number(e.target.value) : ""),
|
|
53540
|
-
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",
|
|
53541
|
-
min: "0",
|
|
53542
|
-
step: "1",
|
|
53543
|
-
placeholder: "Enter day output"
|
|
53544
|
-
}
|
|
53545
|
-
),
|
|
53546
|
-
targetDayOutput !== "" && /* @__PURE__ */ jsx(
|
|
53547
|
-
"button",
|
|
53548
|
-
{
|
|
53549
|
-
onClick: () => setTargetDayOutput(""),
|
|
53550
|
-
className: "absolute right-2 top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-500",
|
|
53551
|
-
children: /* @__PURE__ */ jsx(X, { className: "w-4 h-4" })
|
|
53552
|
-
}
|
|
53553
|
-
)
|
|
53554
|
-
] })
|
|
54087
|
+
" will show in ",
|
|
54088
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium text-green-600", children: "green" }),
|
|
54089
|
+
"."
|
|
53555
54090
|
] })
|
|
53556
|
-
] })
|
|
53557
|
-
] })
|
|
53558
|
-
/* @__PURE__ */ jsx("div", { className: "absolute bottom-0 left-0 right-0 h-10 bg-gradient-to-t from-white to-transparent pointer-events-none" })
|
|
54091
|
+
] })
|
|
54092
|
+
] })
|
|
53559
54093
|
] }),
|
|
53560
|
-
/* @__PURE__ */ jsxs("div", { className: "px-6 py-4 bg-gray-50 border-t border-gray-
|
|
53561
|
-
/* @__PURE__ */ jsx("div", { className: "
|
|
53562
|
-
"
|
|
53563
|
-
|
|
53564
|
-
" workspace",
|
|
53565
|
-
selectedCount !== 1 ? "s" : ""
|
|
54094
|
+
/* @__PURE__ */ jsxs("div", { className: "px-6 py-4 bg-gray-50 border-t border-gray-100 flex items-center justify-between gap-3 rounded-b-lg", children: [
|
|
54095
|
+
/* @__PURE__ */ jsx("div", { className: "min-h-[20px]", children: saveSuccess && /* @__PURE__ */ jsxs("span", { className: "text-sm text-green-600 font-medium flex items-center gap-1.5", children: [
|
|
54096
|
+
/* @__PURE__ */ jsx(CheckCircle2, { className: "w-4 h-4" }),
|
|
54097
|
+
"Saved successfully"
|
|
53566
54098
|
] }) }),
|
|
53567
|
-
/* @__PURE__ */ jsxs("div", { className: "flex
|
|
54099
|
+
/* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-3", children: [
|
|
53568
54100
|
/* @__PURE__ */ jsx(
|
|
53569
54101
|
"button",
|
|
53570
54102
|
{
|
|
53571
54103
|
onClick: onClose,
|
|
53572
|
-
className: "px-4 py-2 text-sm font-medium text-gray-700 bg-white border border-gray-300
|
|
54104
|
+
className: "px-4 py-2 text-sm font-medium text-gray-700 bg-white border border-gray-300 rounded-md hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 shadow-sm transition-all",
|
|
53573
54105
|
children: "Cancel"
|
|
53574
54106
|
}
|
|
53575
54107
|
),
|
|
@@ -53577,10 +54109,9 @@ var BulkConfigureModal = ({
|
|
|
53577
54109
|
"button",
|
|
53578
54110
|
{
|
|
53579
54111
|
onClick: handleSave,
|
|
53580
|
-
disabled: !
|
|
53581
|
-
className:
|
|
53582
|
-
|
|
53583
|
-
children: "Apply Changes"
|
|
54112
|
+
disabled: !canSave || isSaving,
|
|
54113
|
+
className: "px-4 py-2 text-sm font-medium text-white bg-blue-600 border border-transparent rounded-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 shadow-sm transition-all disabled:bg-gray-300 disabled:cursor-not-allowed",
|
|
54114
|
+
children: isSaving ? "Saving..." : "Save Changes"
|
|
53584
54115
|
}
|
|
53585
54116
|
)
|
|
53586
54117
|
] })
|
|
@@ -53589,7 +54120,7 @@ var BulkConfigureModal = ({
|
|
|
53589
54120
|
}
|
|
53590
54121
|
);
|
|
53591
54122
|
};
|
|
53592
|
-
var
|
|
54123
|
+
var ConfigureLegendModal_default = ConfigureLegendModal;
|
|
53593
54124
|
var SKUModal = ({
|
|
53594
54125
|
isOpen,
|
|
53595
54126
|
onClose,
|
|
@@ -53990,7 +54521,8 @@ var TargetsViewUI = ({
|
|
|
53990
54521
|
{ id: 0, name: "Day Shift" },
|
|
53991
54522
|
{ id: 1, name: "Night Shift" }
|
|
53992
54523
|
],
|
|
53993
|
-
|
|
54524
|
+
isConfigureLegendOpen,
|
|
54525
|
+
legend,
|
|
53994
54526
|
navItems = [],
|
|
53995
54527
|
currentPathname = "/targets",
|
|
53996
54528
|
canSaveTargets = true,
|
|
@@ -54001,8 +54533,8 @@ var TargetsViewUI = ({
|
|
|
54001
54533
|
onActionTypeChange,
|
|
54002
54534
|
onShiftChange,
|
|
54003
54535
|
onSaveLine,
|
|
54004
|
-
|
|
54005
|
-
|
|
54536
|
+
onToggleConfigureLegend,
|
|
54537
|
+
onSaveLegend,
|
|
54006
54538
|
onUpdateWorkspaceDisplayName,
|
|
54007
54539
|
// SKU props
|
|
54008
54540
|
skuEnabled = false,
|
|
@@ -54028,11 +54560,13 @@ var TargetsViewUI = ({
|
|
|
54028
54560
|
/* @__PURE__ */ jsx("div", { className: "sm:absolute sm:right-0 w-full sm:w-auto", children: /* @__PURE__ */ jsxs(
|
|
54029
54561
|
"button",
|
|
54030
54562
|
{
|
|
54031
|
-
className:
|
|
54032
|
-
onClick:
|
|
54563
|
+
className: `w-full sm:w-auto px-3 sm:px-4 py-1.5 sm:py-2 text-xs sm:text-sm font-medium rounded-lg transition-all duration-200 ${canSaveTargets ? "text-gray-700 bg-white border border-gray-300 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500" : "text-gray-400 bg-gray-100 border border-gray-200 cursor-not-allowed"}`,
|
|
54564
|
+
onClick: onToggleConfigureLegend,
|
|
54565
|
+
disabled: !canSaveTargets,
|
|
54566
|
+
title: !canSaveTargets ? "You do not have permission to update the legend" : "",
|
|
54033
54567
|
children: [
|
|
54034
|
-
/* @__PURE__ */ jsx(
|
|
54035
|
-
"
|
|
54568
|
+
/* @__PURE__ */ jsx(Palette, { className: "w-3 h-3 sm:w-4 sm:h-4 mr-1.5 sm:mr-2 inline-block" }),
|
|
54569
|
+
"Configure Legend"
|
|
54036
54570
|
]
|
|
54037
54571
|
}
|
|
54038
54572
|
) }),
|
|
@@ -54334,14 +54868,13 @@ var TargetsViewUI = ({
|
|
|
54334
54868
|
)) })
|
|
54335
54869
|
] }) }),
|
|
54336
54870
|
/* @__PURE__ */ jsx(
|
|
54337
|
-
|
|
54871
|
+
ConfigureLegendModal_default,
|
|
54338
54872
|
{
|
|
54339
|
-
isOpen:
|
|
54340
|
-
onClose:
|
|
54341
|
-
|
|
54342
|
-
|
|
54343
|
-
|
|
54344
|
-
selectedShift
|
|
54873
|
+
isOpen: isConfigureLegendOpen,
|
|
54874
|
+
onClose: onToggleConfigureLegend,
|
|
54875
|
+
onSave: onSaveLegend,
|
|
54876
|
+
legend,
|
|
54877
|
+
canSave: canSaveTargets
|
|
54345
54878
|
}
|
|
54346
54879
|
)
|
|
54347
54880
|
] });
|
|
@@ -54387,7 +54920,7 @@ var TargetsView = ({
|
|
|
54387
54920
|
() => lineIds.reduce((acc, id3) => ({ ...acc, [id3]: false }), {})
|
|
54388
54921
|
);
|
|
54389
54922
|
const [isLoading, setIsLoading] = useState(true);
|
|
54390
|
-
const [
|
|
54923
|
+
const [isConfigureLegendOpen, setIsConfigureLegendOpen] = useState(false);
|
|
54391
54924
|
const [selectedWorkspaces, setSelectedWorkspaces] = useState([]);
|
|
54392
54925
|
const [selectedShift, setSelectedShift] = useState(0);
|
|
54393
54926
|
const [shiftOptions, setShiftOptions] = useState([]);
|
|
@@ -54404,6 +54937,7 @@ var TargetsView = ({
|
|
|
54404
54937
|
const supabase = useSupabase();
|
|
54405
54938
|
const effectiveUserId = userId || "6bf6f271-1e55-4a95-9b89-1c3820b58739";
|
|
54406
54939
|
const dashboardConfig = useDashboardConfig();
|
|
54940
|
+
const { legend, updateLegend } = useEfficiencyLegend(companyId);
|
|
54407
54941
|
const { skus, isLoading: skusLoading } = useSKUs(companyId);
|
|
54408
54942
|
const skuEnabled = dashboardConfig?.skuConfig?.enabled || false;
|
|
54409
54943
|
useEffect(() => {
|
|
@@ -54839,41 +55373,23 @@ var TargetsView = ({
|
|
|
54839
55373
|
console.log(`[handleSaveLine] Set savingLines to false for ${lineId} in finally block`);
|
|
54840
55374
|
}
|
|
54841
55375
|
}, [canSaveTargets, supabase, lineWorkspaces, selectedShift, lineNames, onSaveChanges, skuEnabled, dashboardConfig]);
|
|
54842
|
-
const
|
|
54843
|
-
if (!
|
|
54844
|
-
|
|
54845
|
-
|
|
54846
|
-
|
|
54847
|
-
|
|
54848
|
-
|
|
54849
|
-
|
|
54850
|
-
|
|
54851
|
-
|
|
55376
|
+
const handleSaveLegend = useCallback(async (nextLegend) => {
|
|
55377
|
+
if (!canSaveTargets) {
|
|
55378
|
+
toast.error("You do not have permission to update the legend.");
|
|
55379
|
+
return { success: false, error: "Permission denied" };
|
|
55380
|
+
}
|
|
55381
|
+
const result = await updateLegend(nextLegend);
|
|
55382
|
+
if (result.success) {
|
|
55383
|
+
toast.success("Efficiency legend updated successfully");
|
|
55384
|
+
} else if (result.error) {
|
|
55385
|
+
toast.error(result.error);
|
|
55386
|
+
} else {
|
|
55387
|
+
toast.error("Failed to update efficiency legend");
|
|
54852
55388
|
}
|
|
54853
|
-
|
|
54854
|
-
|
|
54855
|
-
|
|
54856
|
-
|
|
54857
|
-
workspaces: prev[updates.lineId].workspaces.map((ws) => {
|
|
54858
|
-
if (!updates.workspaceIds.includes(ws.id)) return ws;
|
|
54859
|
-
return {
|
|
54860
|
-
...ws,
|
|
54861
|
-
...updates.updates.actionType && {
|
|
54862
|
-
actionType: updates.updates.actionType,
|
|
54863
|
-
actionId: actionIds[updates.updates.actionType]
|
|
54864
|
-
},
|
|
54865
|
-
...updates.updates.targetPPH !== void 0 && { targetPPH: updates.updates.targetPPH },
|
|
54866
|
-
...updates.updates.targetCycleTime !== void 0 && { targetCycleTime: updates.updates.targetCycleTime },
|
|
54867
|
-
...updates.updates.targetDayOutput !== void 0 && { targetDayOutput: updates.updates.targetDayOutput }
|
|
54868
|
-
};
|
|
54869
|
-
})
|
|
54870
|
-
}
|
|
54871
|
-
}));
|
|
54872
|
-
toast.success(`Updated ${updates.workspaceIds.length} workspaces in ${lineNames[updates.lineId] || updates.lineId}`);
|
|
54873
|
-
setIsBulkConfigureOpen(false);
|
|
54874
|
-
};
|
|
54875
|
-
const handleToggleBulkConfigure = () => {
|
|
54876
|
-
setIsBulkConfigureOpen((prev) => !prev);
|
|
55389
|
+
return result;
|
|
55390
|
+
}, [canSaveTargets, updateLegend]);
|
|
55391
|
+
const handleToggleConfigureLegend = () => {
|
|
55392
|
+
setIsConfigureLegendOpen((prev) => !prev);
|
|
54877
55393
|
};
|
|
54878
55394
|
const handleNavigateBack = () => {
|
|
54879
55395
|
if (router && router.push) {
|
|
@@ -54911,7 +55427,7 @@ var TargetsView = ({
|
|
|
54911
55427
|
saveSuccess,
|
|
54912
55428
|
selectedShift,
|
|
54913
55429
|
shiftOptions,
|
|
54914
|
-
|
|
55430
|
+
isConfigureLegendOpen,
|
|
54915
55431
|
navItems: [],
|
|
54916
55432
|
currentPathname: "/targets",
|
|
54917
55433
|
canSaveTargets,
|
|
@@ -54922,8 +55438,9 @@ var TargetsView = ({
|
|
|
54922
55438
|
onActionTypeChange: handleActionTypeChange,
|
|
54923
55439
|
onShiftChange: handleShiftChange,
|
|
54924
55440
|
onSaveLine: handleSaveLine,
|
|
54925
|
-
|
|
54926
|
-
|
|
55441
|
+
onToggleConfigureLegend: handleToggleConfigureLegend,
|
|
55442
|
+
onSaveLegend: handleSaveLegend,
|
|
55443
|
+
legend,
|
|
54927
55444
|
onUpdateWorkspaceDisplayName: handleUpdateWorkspaceDisplayName,
|
|
54928
55445
|
skuEnabled,
|
|
54929
55446
|
skus,
|
|
@@ -55304,6 +55821,20 @@ var WorkspaceDetailView = ({
|
|
|
55304
55821
|
}, [monthlyData, range]);
|
|
55305
55822
|
const formattedWorkspaceName = displayName || formatWorkspaceName3(workspace?.workspace_name || "", effectiveLineId);
|
|
55306
55823
|
const shouldShowCycleTimeChart = showCycleTimeChart ?? formattedWorkspaceName.startsWith("FINAL ASSY");
|
|
55824
|
+
const idleClipDate = date || workspace?.date || calculatedOperationalDate || getOperationalDate(timezone);
|
|
55825
|
+
const idleClipShiftId = parsedShiftId ?? workspace?.shift_id;
|
|
55826
|
+
const idleClipFetchEnabled = Boolean(
|
|
55827
|
+
workspaceId && idleClipDate && idleClipShiftId !== void 0 && activeTab === "overview" && showIdleTime && !shouldShowCycleTimeChart
|
|
55828
|
+
);
|
|
55829
|
+
const {
|
|
55830
|
+
idleClips: idleTimeClips,
|
|
55831
|
+
clipClassifications: idleTimeClipClassifications
|
|
55832
|
+
} = useIdleTimeClipClassifications({
|
|
55833
|
+
workspaceId,
|
|
55834
|
+
date: idleClipDate,
|
|
55835
|
+
shiftId: idleClipShiftId,
|
|
55836
|
+
enabled: idleClipFetchEnabled
|
|
55837
|
+
});
|
|
55307
55838
|
const handleBackNavigation = () => {
|
|
55308
55839
|
if (returnUrl) {
|
|
55309
55840
|
if (onNavigate) {
|
|
@@ -55690,7 +56221,11 @@ var WorkspaceDetailView = ({
|
|
|
55690
56221
|
shiftStart: workspace.shift_start || "06:00",
|
|
55691
56222
|
shiftEnd: workspace.shift_end,
|
|
55692
56223
|
showIdleTime,
|
|
55693
|
-
idleTimeHourly: workspace.idle_time_hourly
|
|
56224
|
+
idleTimeHourly: workspace.idle_time_hourly,
|
|
56225
|
+
idleTimeClips,
|
|
56226
|
+
idleTimeClipClassifications,
|
|
56227
|
+
shiftDate: idleClipDate,
|
|
56228
|
+
timezone
|
|
55694
56229
|
}
|
|
55695
56230
|
)
|
|
55696
56231
|
}
|
|
@@ -55816,7 +56351,11 @@ var WorkspaceDetailView = ({
|
|
|
55816
56351
|
shiftStart: workspace.shift_start || "06:00",
|
|
55817
56352
|
shiftEnd: workspace.shift_end,
|
|
55818
56353
|
showIdleTime,
|
|
55819
|
-
idleTimeHourly: workspace.idle_time_hourly
|
|
56354
|
+
idleTimeHourly: workspace.idle_time_hourly,
|
|
56355
|
+
idleTimeClips,
|
|
56356
|
+
idleTimeClipClassifications,
|
|
56357
|
+
shiftDate: idleClipDate,
|
|
56358
|
+
timezone
|
|
55820
56359
|
}
|
|
55821
56360
|
)
|
|
55822
56361
|
}
|
|
@@ -58950,7 +59489,12 @@ var ImprovementCenterView = () => {
|
|
|
58950
59489
|
const { user } = useAuth();
|
|
58951
59490
|
const dashboardConfig = useDashboardConfig();
|
|
58952
59491
|
const entityConfig = useEntityConfig();
|
|
58953
|
-
const
|
|
59492
|
+
const timezone = useAppTimezone();
|
|
59493
|
+
const today = new Date((/* @__PURE__ */ new Date()).toLocaleString("en-US", { timeZone: timezone }));
|
|
59494
|
+
const [selectedMonth, setSelectedMonth] = useState(today.getMonth());
|
|
59495
|
+
const [selectedYear, setSelectedYear] = useState(today.getFullYear());
|
|
59496
|
+
const monthBounds = useMemo(() => getMonthKeyBounds(selectedYear, selectedMonth), [selectedYear, selectedMonth]);
|
|
59497
|
+
const [dateRange, setDateRange] = useState(monthBounds);
|
|
58954
59498
|
const [selectedLineId, setSelectedLineId] = useState("all");
|
|
58955
59499
|
const [selectedStatus, setSelectedStatus] = useState("all");
|
|
58956
59500
|
const [selectedShift, setSelectedShift] = useState("all");
|
|
@@ -58961,14 +59505,36 @@ var ImprovementCenterView = () => {
|
|
|
58961
59505
|
const [loadError, setLoadError] = useState(null);
|
|
58962
59506
|
const [teamMembers, setTeamMembers] = useState([]);
|
|
58963
59507
|
const [companyLines, setCompanyLines] = useState([]);
|
|
59508
|
+
const [isFilterOpen, setIsFilterOpen] = useState(false);
|
|
59509
|
+
const filterRef = useRef(null);
|
|
59510
|
+
useEffect(() => {
|
|
59511
|
+
const handleClickOutside = (event) => {
|
|
59512
|
+
if (filterRef.current && !filterRef.current.contains(event.target)) {
|
|
59513
|
+
setIsFilterOpen(false);
|
|
59514
|
+
}
|
|
59515
|
+
};
|
|
59516
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
59517
|
+
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
59518
|
+
}, []);
|
|
58964
59519
|
const computeWeeksOpen = (firstSeenAt) => {
|
|
58965
59520
|
if (!firstSeenAt) return void 0;
|
|
58966
|
-
const firstSeen = new Date(firstSeenAt);
|
|
59521
|
+
const firstSeen = new Date(new Date(firstSeenAt).toLocaleString("en-US", { timeZone: timezone }));
|
|
58967
59522
|
if (Number.isNaN(firstSeen.getTime())) return void 0;
|
|
58968
|
-
const now2 = /* @__PURE__ */ new Date();
|
|
59523
|
+
const now2 = new Date((/* @__PURE__ */ new Date()).toLocaleString("en-US", { timeZone: timezone }));
|
|
58969
59524
|
const diffDays = Math.max(0, Math.floor((now2.getTime() - firstSeen.getTime()) / (1e3 * 60 * 60 * 24)));
|
|
58970
59525
|
return Math.max(1, Math.ceil(diffDays / 7));
|
|
58971
59526
|
};
|
|
59527
|
+
const formatOpenedDate = (firstSeenAt) => {
|
|
59528
|
+
if (!firstSeenAt) return void 0;
|
|
59529
|
+
const raw = new Date(firstSeenAt);
|
|
59530
|
+
if (Number.isNaN(raw.getTime())) return void 0;
|
|
59531
|
+
const zoned = new Date(raw.toLocaleString("en-US", { timeZone: timezone }));
|
|
59532
|
+
const day = zoned.getDate();
|
|
59533
|
+
const month = zoned.toLocaleString("en-US", { month: "short" });
|
|
59534
|
+
const dayMod = day % 100;
|
|
59535
|
+
const suffix = dayMod >= 11 && dayMod <= 13 ? "th" : day % 10 === 1 ? "st" : day % 10 === 2 ? "nd" : day % 10 === 3 ? "rd" : "th";
|
|
59536
|
+
return `${day}${suffix} ${month}`;
|
|
59537
|
+
};
|
|
58972
59538
|
const configuredLines = useMemo(() => {
|
|
58973
59539
|
return entityConfig.lines || entityConfig.lineNames || {};
|
|
58974
59540
|
}, [entityConfig.lines, entityConfig.lineNames]);
|
|
@@ -59077,14 +59643,38 @@ var ImprovementCenterView = () => {
|
|
|
59077
59643
|
cancelled = true;
|
|
59078
59644
|
};
|
|
59079
59645
|
}, [supabase, companyId]);
|
|
59080
|
-
|
|
59081
|
-
|
|
59082
|
-
};
|
|
59083
|
-
const
|
|
59084
|
-
|
|
59646
|
+
useEffect(() => {
|
|
59647
|
+
setDateRange(monthBounds);
|
|
59648
|
+
}, [monthBounds]);
|
|
59649
|
+
const handleRangeChange = (newRange) => {
|
|
59650
|
+
setDateRange(newRange);
|
|
59651
|
+
trackCoreEvent("Improvement Center Date Range Changed", {
|
|
59652
|
+
start_date: newRange.startKey,
|
|
59653
|
+
end_date: newRange.endKey
|
|
59654
|
+
});
|
|
59085
59655
|
};
|
|
59086
|
-
const
|
|
59087
|
-
|
|
59656
|
+
const handleMonthNavigate = (newMonth, newYear) => {
|
|
59657
|
+
let validMonth = newMonth;
|
|
59658
|
+
let validYear = newYear;
|
|
59659
|
+
if (validMonth < 0) {
|
|
59660
|
+
validMonth = 11;
|
|
59661
|
+
validYear -= 1;
|
|
59662
|
+
} else if (validMonth > 11) {
|
|
59663
|
+
validMonth = 0;
|
|
59664
|
+
validYear += 1;
|
|
59665
|
+
}
|
|
59666
|
+
if (validYear < 2023) return;
|
|
59667
|
+
if (validYear > today.getFullYear() || validYear === today.getFullYear() && validMonth > today.getMonth()) {
|
|
59668
|
+
return;
|
|
59669
|
+
}
|
|
59670
|
+
const nextBounds = getMonthKeyBounds(validYear, validMonth);
|
|
59671
|
+
setSelectedMonth(validMonth);
|
|
59672
|
+
setSelectedYear(validYear);
|
|
59673
|
+
setDateRange(nextBounds);
|
|
59674
|
+
trackCoreEvent("Improvement Center Month Changed", {
|
|
59675
|
+
direction: validMonth > selectedMonth || validYear > selectedYear ? "next" : "previous",
|
|
59676
|
+
new_month: `${validYear}-${String(validMonth + 1).padStart(2, "0")}`
|
|
59677
|
+
});
|
|
59088
59678
|
};
|
|
59089
59679
|
useEffect(() => {
|
|
59090
59680
|
let cancelled = false;
|
|
@@ -59102,7 +59692,9 @@ var ImprovementCenterView = () => {
|
|
|
59102
59692
|
status: "all",
|
|
59103
59693
|
limit: "500"
|
|
59104
59694
|
});
|
|
59105
|
-
params.set("month", `${
|
|
59695
|
+
params.set("month", `${selectedYear}-${String(selectedMonth + 1).padStart(2, "0")}`);
|
|
59696
|
+
params.set("start_date", dateRange.startKey);
|
|
59697
|
+
params.set("end_date", dateRange.endKey);
|
|
59106
59698
|
if (scopeLineIds.length > 0) {
|
|
59107
59699
|
params.set("line_ids", scopeLineIds.join(","));
|
|
59108
59700
|
}
|
|
@@ -59133,7 +59725,7 @@ var ImprovementCenterView = () => {
|
|
|
59133
59725
|
return () => {
|
|
59134
59726
|
cancelled = true;
|
|
59135
59727
|
};
|
|
59136
|
-
}, [supabase, companyId, scopeLineIdsKey,
|
|
59728
|
+
}, [supabase, companyId, scopeLineIdsKey, selectedMonth, selectedYear, dateRange.startKey, dateRange.endKey]);
|
|
59137
59729
|
const teamMembersById = useMemo(() => {
|
|
59138
59730
|
return new Map(teamMembers.map((member) => [member.id, member]));
|
|
59139
59731
|
}, [teamMembers]);
|
|
@@ -59175,6 +59767,15 @@ var ImprovementCenterView = () => {
|
|
|
59175
59767
|
};
|
|
59176
59768
|
}, [recommendations, selectedLineId, selectedShift, selectedWeeksRange, selectedMemberId]);
|
|
59177
59769
|
const clearFilters = () => {
|
|
59770
|
+
trackCoreEvent("Improvement Center Filters Cleared", {
|
|
59771
|
+
previous_filters: {
|
|
59772
|
+
line_id: selectedLineId,
|
|
59773
|
+
status: selectedStatus,
|
|
59774
|
+
shift: selectedShift,
|
|
59775
|
+
weeks_range: selectedWeeksRange,
|
|
59776
|
+
member_id: selectedMemberId
|
|
59777
|
+
}
|
|
59778
|
+
});
|
|
59178
59779
|
setSelectedLineId("all");
|
|
59179
59780
|
setSelectedStatus("all");
|
|
59180
59781
|
setSelectedShift("all");
|
|
@@ -59208,8 +59809,60 @@ var ImprovementCenterView = () => {
|
|
|
59208
59809
|
setSelectedLineId("all");
|
|
59209
59810
|
}
|
|
59210
59811
|
}, [scopeLineIds, selectedLineId]);
|
|
59812
|
+
useEffect(() => {
|
|
59813
|
+
trackCoreEvent("Improvement Center Viewed", {
|
|
59814
|
+
company_id: companyId,
|
|
59815
|
+
user_role: user?.role_level,
|
|
59816
|
+
initial_month: `${selectedYear}-${String(selectedMonth + 1).padStart(2, "0")}`,
|
|
59817
|
+
total_scope_lines: scopeLineIds.length
|
|
59818
|
+
});
|
|
59819
|
+
}, []);
|
|
59820
|
+
const handleStatusFilterChange = (status) => {
|
|
59821
|
+
trackCoreEvent("Improvement Center Filter Applied", {
|
|
59822
|
+
filter_type: "status",
|
|
59823
|
+
filter_value: status,
|
|
59824
|
+
previous_value: selectedStatus
|
|
59825
|
+
});
|
|
59826
|
+
setSelectedStatus(status);
|
|
59827
|
+
};
|
|
59828
|
+
const handleShiftFilterChange = (shift) => {
|
|
59829
|
+
trackCoreEvent("Improvement Center Filter Applied", {
|
|
59830
|
+
filter_type: "shift",
|
|
59831
|
+
filter_value: shift,
|
|
59832
|
+
previous_value: selectedShift
|
|
59833
|
+
});
|
|
59834
|
+
setSelectedShift(shift);
|
|
59835
|
+
};
|
|
59836
|
+
const handleWeeksFilterChange = (weeksRange) => {
|
|
59837
|
+
trackCoreEvent("Improvement Center Filter Applied", {
|
|
59838
|
+
filter_type: "weeks_open",
|
|
59839
|
+
filter_value: weeksRange,
|
|
59840
|
+
previous_value: selectedWeeksRange
|
|
59841
|
+
});
|
|
59842
|
+
setSelectedWeeksRange(weeksRange);
|
|
59843
|
+
};
|
|
59844
|
+
const handleMemberFilterChange = (memberId) => {
|
|
59845
|
+
const memberName = memberId === "all" ? "all" : teamMembers.find((m) => m.id === memberId)?.name || memberId;
|
|
59846
|
+
trackCoreEvent("Improvement Center Filter Applied", {
|
|
59847
|
+
filter_type: "member",
|
|
59848
|
+
filter_value: memberName,
|
|
59849
|
+
member_id: memberId,
|
|
59850
|
+
previous_value: selectedMemberId
|
|
59851
|
+
});
|
|
59852
|
+
setSelectedMemberId(memberId);
|
|
59853
|
+
};
|
|
59854
|
+
const handleLineFilterChange = (lineId) => {
|
|
59855
|
+
const lineName = lineId === "all" ? "all" : lineNameById.get(lineId) || lineId;
|
|
59856
|
+
trackCoreEvent("Improvement Center Filter Applied", {
|
|
59857
|
+
filter_type: "line",
|
|
59858
|
+
filter_value: lineName,
|
|
59859
|
+
line_id: lineId,
|
|
59860
|
+
previous_value: selectedLineId
|
|
59861
|
+
});
|
|
59862
|
+
setSelectedLineId(lineId);
|
|
59863
|
+
};
|
|
59211
59864
|
return /* @__PURE__ */ jsxs("div", { className: "min-h-screen bg-gray-50 flex flex-col", children: [
|
|
59212
|
-
/* @__PURE__ */ jsx("header", { className: "sticky top-0 z-
|
|
59865
|
+
/* @__PURE__ */ jsx("header", { className: "sticky top-0 z-30 bg-white border-b border-gray-200 flex-shrink-0", children: /* @__PURE__ */ jsx("div", { className: "px-4 sm:px-6 lg:px-8 py-4", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
|
|
59213
59866
|
/* @__PURE__ */ jsx("div", { className: "flex items-center gap-4 min-w-[120px]", children: /* @__PURE__ */ jsx(
|
|
59214
59867
|
BackButtonMinimal,
|
|
59215
59868
|
{
|
|
@@ -59221,187 +59874,173 @@ var ImprovementCenterView = () => {
|
|
|
59221
59874
|
/* @__PURE__ */ jsx("h1", { className: "text-2xl lg:text-3xl font-semibold text-gray-900 text-center", children: "Improvement Center" }),
|
|
59222
59875
|
/* @__PURE__ */ jsx("p", { className: "text-sm text-gray-500 mt-1 text-center px-4 hidden sm:block", children: "Track and resolve persistent issues across your production lines" })
|
|
59223
59876
|
] }),
|
|
59224
|
-
/* @__PURE__ */ jsx("div", { className: "min-w-[
|
|
59877
|
+
/* @__PURE__ */ jsx("div", { className: "min-w-[180px] flex justify-end", children: /* @__PURE__ */ jsx(
|
|
59878
|
+
MonthlyRangeFilter_default,
|
|
59879
|
+
{
|
|
59880
|
+
month: selectedMonth,
|
|
59881
|
+
year: selectedYear,
|
|
59882
|
+
timezone,
|
|
59883
|
+
value: dateRange,
|
|
59884
|
+
onChange: handleRangeChange,
|
|
59885
|
+
onMonthNavigate: handleMonthNavigate
|
|
59886
|
+
}
|
|
59887
|
+
) })
|
|
59225
59888
|
] }) }) }),
|
|
59226
59889
|
/* @__PURE__ */ jsxs("main", { className: "flex-1 p-4 sm:p-6 max-w-7xl mx-auto w-full", children: [
|
|
59227
|
-
/* @__PURE__ */
|
|
59228
|
-
/* @__PURE__ */ jsx(
|
|
59229
|
-
"
|
|
59230
|
-
{
|
|
59231
|
-
|
|
59232
|
-
|
|
59233
|
-
children: /* @__PURE__ */ jsx(ChevronLeftIcon, { className: "w-5 h-5" })
|
|
59234
|
-
}
|
|
59235
|
-
),
|
|
59236
|
-
/* @__PURE__ */ jsx("span", { className: "text-base font-semibold text-gray-900 min-w-[160px] text-center", children: formatMonth(currentDate) }),
|
|
59237
|
-
/* @__PURE__ */ jsx(
|
|
59890
|
+
/* @__PURE__ */ jsxs("div", { className: "-mx-4 sm:-mx-6 px-4 sm:px-6 py-3 border-b border-gray-200 mb-6 flex flex-col lg:flex-row items-start lg:items-center justify-between gap-4 transition-all", children: [
|
|
59891
|
+
/* @__PURE__ */ jsx("div", { className: "flex p-1 bg-gray-50 border border-gray-200 rounded-lg", children: [
|
|
59892
|
+
{ id: "all", label: "All", count: stats.all },
|
|
59893
|
+
{ id: "resolved", label: "Resolved", count: stats.resolved, icon: CheckCircleIcon },
|
|
59894
|
+
{ id: "unresolved", label: "Unresolved", count: stats.unresolved, icon: XCircleIcon }
|
|
59895
|
+
].map((tab) => /* @__PURE__ */ jsxs(
|
|
59238
59896
|
"button",
|
|
59239
59897
|
{
|
|
59240
|
-
onClick:
|
|
59241
|
-
className:
|
|
59242
|
-
children:
|
|
59243
|
-
|
|
59244
|
-
|
|
59245
|
-
|
|
59246
|
-
|
|
59247
|
-
|
|
59248
|
-
|
|
59249
|
-
|
|
59250
|
-
|
|
59251
|
-
onClick: () => setSelectedStatus("all"),
|
|
59252
|
-
className: `px-4 py-2 rounded-lg text-sm font-medium transition-all cursor-pointer ${selectedStatus === "all" ? "bg-white text-gray-900 shadow-sm ring-1 ring-black/5" : "text-gray-500 hover:text-gray-700 hover:bg-gray-100"}`,
|
|
59253
|
-
children: [
|
|
59254
|
-
"All ",
|
|
59255
|
-
/* @__PURE__ */ jsx("span", { className: "ml-1.5 bg-gray-100 px-2 py-0.5 rounded-full text-xs text-gray-600", children: stats.all })
|
|
59256
|
-
]
|
|
59257
|
-
}
|
|
59258
|
-
),
|
|
59259
|
-
/* @__PURE__ */ jsx("div", { className: "h-4 w-px bg-gray-300 mx-1" }),
|
|
59260
|
-
/* @__PURE__ */ jsxs(
|
|
59261
|
-
"button",
|
|
59262
|
-
{
|
|
59263
|
-
onClick: () => setSelectedStatus("resolved"),
|
|
59264
|
-
className: `flex items-center gap-1.5 px-3 py-2 rounded-lg text-sm transition-all cursor-pointer ${selectedStatus === "resolved" ? "bg-green-50 text-green-700 ring-1 ring-green-200" : "text-gray-600 hover:bg-gray-100"}`,
|
|
59265
|
-
children: [
|
|
59266
|
-
/* @__PURE__ */ jsx(CheckCircleIcon, { className: "w-4 h-4 text-green-500" }),
|
|
59267
|
-
"Resolved ",
|
|
59268
|
-
stats.resolved
|
|
59269
|
-
]
|
|
59270
|
-
}
|
|
59271
|
-
),
|
|
59898
|
+
onClick: () => handleStatusFilterChange(tab.id),
|
|
59899
|
+
className: `flex items-center gap-2 px-3 py-1.5 rounded-md text-sm font-medium transition-all duration-200 ${selectedStatus === tab.id ? "bg-white text-blue-600 shadow-sm ring-1 ring-gray-200" : "text-gray-600 hover:text-gray-900 hover:bg-gray-100"}`,
|
|
59900
|
+
children: [
|
|
59901
|
+
tab.icon && /* @__PURE__ */ jsx(tab.icon, { className: `w-4 h-4 ${selectedStatus === tab.id ? "text-blue-600" : "text-gray-400"}` }),
|
|
59902
|
+
tab.label,
|
|
59903
|
+
/* @__PURE__ */ jsx("span", { className: `text-xs px-1.5 py-0.5 rounded-full ${selectedStatus === tab.id ? "bg-blue-50 text-blue-600" : "bg-gray-200/50 text-gray-500"}`, children: tab.count })
|
|
59904
|
+
]
|
|
59905
|
+
},
|
|
59906
|
+
tab.id
|
|
59907
|
+
)) }),
|
|
59908
|
+
/* @__PURE__ */ jsxs("div", { className: "relative", ref: filterRef, children: [
|
|
59272
59909
|
/* @__PURE__ */ jsxs(
|
|
59273
59910
|
"button",
|
|
59274
59911
|
{
|
|
59275
|
-
onClick: () =>
|
|
59276
|
-
className: `flex items-center gap-
|
|
59277
|
-
children: [
|
|
59278
|
-
/* @__PURE__ */ jsx(XCircleIcon, { className: "w-4 h-4 text-red-500" }),
|
|
59279
|
-
"Unresolved ",
|
|
59280
|
-
stats.unresolved
|
|
59281
|
-
]
|
|
59282
|
-
}
|
|
59283
|
-
)
|
|
59284
|
-
] }),
|
|
59285
|
-
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2 w-full md:w-auto", children: [
|
|
59286
|
-
/* @__PURE__ */ jsxs(
|
|
59287
|
-
"select",
|
|
59288
|
-
{
|
|
59289
|
-
value: selectedShift,
|
|
59290
|
-
onChange: (e) => setSelectedShift(e.target.value),
|
|
59291
|
-
className: "flex-1 md:flex-none appearance-none pl-3 pr-8 py-1.5 text-sm border border-gray-300 rounded-lg bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-blue-500 cursor-pointer text-gray-700 shadow-sm",
|
|
59292
|
-
style: { backgroundImage: `url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e")`, backgroundPosition: `right 0.5rem center`, backgroundRepeat: `no-repeat`, backgroundSize: `1.5em 1.5em` },
|
|
59293
|
-
children: [
|
|
59294
|
-
/* @__PURE__ */ jsx("option", { value: "all", children: "All Shifts" }),
|
|
59295
|
-
shiftOptions.filter((s) => s !== "all").map((shift) => /* @__PURE__ */ jsx("option", { value: shift, children: shift }, shift))
|
|
59296
|
-
]
|
|
59297
|
-
}
|
|
59298
|
-
),
|
|
59299
|
-
/* @__PURE__ */ jsx(
|
|
59300
|
-
"select",
|
|
59301
|
-
{
|
|
59302
|
-
value: selectedWeeksRange,
|
|
59303
|
-
onChange: (e) => setSelectedWeeksRange(e.target.value),
|
|
59304
|
-
className: "flex-1 md:flex-none appearance-none pl-3 pr-8 py-1.5 text-sm border border-gray-300 rounded-lg bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-blue-500 cursor-pointer text-gray-700 shadow-sm",
|
|
59305
|
-
style: { backgroundImage: `url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e")`, backgroundPosition: `right 0.5rem center`, backgroundRepeat: `no-repeat`, backgroundSize: `1.5em 1.5em` },
|
|
59306
|
-
children: weekOptions.map((opt) => /* @__PURE__ */ jsx("option", { value: opt.id, children: opt.label }, opt.id))
|
|
59307
|
-
}
|
|
59308
|
-
),
|
|
59309
|
-
/* @__PURE__ */ jsxs(
|
|
59310
|
-
"select",
|
|
59311
|
-
{
|
|
59312
|
-
value: selectedMemberId,
|
|
59313
|
-
onChange: (e) => setSelectedMemberId(e.target.value),
|
|
59314
|
-
className: "flex-1 md:flex-none appearance-none pl-3 pr-8 py-1.5 text-sm border border-gray-300 rounded-lg bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-blue-500 cursor-pointer text-gray-700 shadow-sm",
|
|
59315
|
-
style: { backgroundImage: `url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e")`, backgroundPosition: `right 0.5rem center`, backgroundRepeat: `no-repeat`, backgroundSize: `1.5em 1.5em` },
|
|
59912
|
+
onClick: () => setIsFilterOpen(!isFilterOpen),
|
|
59913
|
+
className: `flex items-center gap-2 px-3 py-1.5 rounded-lg border text-sm font-medium transition-all shadow-sm ${isFilterOpen || (selectedShift !== "all" || selectedWeeksRange !== "all" || selectedMemberId !== "all" || selectedLineId !== "all") ? "bg-blue-50 border-blue-200 text-blue-700" : "bg-white border-gray-200 text-gray-700 hover:bg-gray-50"}`,
|
|
59316
59914
|
children: [
|
|
59317
|
-
/* @__PURE__ */ jsx(
|
|
59318
|
-
|
|
59915
|
+
/* @__PURE__ */ jsx(FunnelIcon, { className: "w-4 h-4" }),
|
|
59916
|
+
/* @__PURE__ */ jsx("span", { children: "Filters" }),
|
|
59917
|
+
(selectedShift !== "all" || selectedWeeksRange !== "all" || selectedMemberId !== "all" || selectedLineId !== "all") && /* @__PURE__ */ jsx("span", { className: "flex items-center justify-center w-5 h-5 bg-blue-100 text-blue-700 text-xs rounded-full font-bold ml-1", children: [selectedShift, selectedWeeksRange, selectedMemberId, selectedLineId].filter((v) => v !== "all").length }),
|
|
59918
|
+
/* @__PURE__ */ jsx(ChevronDownIcon, { className: `w-3 h-3 ml-1 transition-transform ${isFilterOpen ? "rotate-180" : ""}` })
|
|
59319
59919
|
]
|
|
59320
59920
|
}
|
|
59321
59921
|
),
|
|
59322
|
-
/* @__PURE__ */
|
|
59323
|
-
"
|
|
59324
|
-
|
|
59325
|
-
|
|
59326
|
-
|
|
59327
|
-
|
|
59328
|
-
|
|
59329
|
-
|
|
59330
|
-
|
|
59331
|
-
|
|
59922
|
+
isFilterOpen && /* @__PURE__ */ jsxs("div", { className: "absolute right-0 top-full mt-2 w-72 bg-white rounded-xl shadow-xl border border-gray-100 p-4 z-50 animate-in fade-in zoom-in-95 duration-100", children: [
|
|
59923
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between mb-3", children: [
|
|
59924
|
+
/* @__PURE__ */ jsx("h3", { className: "text-sm font-semibold text-gray-900", children: "Filter View" }),
|
|
59925
|
+
(selectedShift !== "all" || selectedWeeksRange !== "all" || selectedMemberId !== "all" || selectedLineId !== "all") && /* @__PURE__ */ jsx(
|
|
59926
|
+
"button",
|
|
59927
|
+
{
|
|
59928
|
+
onClick: clearFilters,
|
|
59929
|
+
className: "text-xs text-red-600 hover:text-red-700 font-medium",
|
|
59930
|
+
children: "Clear all"
|
|
59931
|
+
}
|
|
59932
|
+
)
|
|
59933
|
+
] }),
|
|
59934
|
+
/* @__PURE__ */ jsx("div", { className: "space-y-3", children: [
|
|
59935
|
+
{ value: selectedShift, onChange: handleShiftFilterChange, options: shiftOptions, label: "Shift" },
|
|
59936
|
+
{ value: selectedWeeksRange, onChange: handleWeeksFilterChange, options: weekOptions.map((o) => o.id), labels: weekOptions, label: "Duration" },
|
|
59937
|
+
{ value: selectedMemberId, onChange: handleMemberFilterChange, options: ["all", ...teamMembers.map((m) => m.id)], labels: teamMembers, label: "Member" },
|
|
59938
|
+
{ value: selectedLineId, onChange: handleLineFilterChange, options: lineOptions.map((o) => o.id), labels: lineOptions, label: "Line" }
|
|
59939
|
+
].map((filter2, idx) => /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
|
|
59940
|
+
/* @__PURE__ */ jsx("label", { className: "text-xs font-medium text-gray-500 uppercase tracking-wide ml-1", children: filter2.label }),
|
|
59941
|
+
/* @__PURE__ */ jsx("div", { className: "relative", children: /* @__PURE__ */ jsx(
|
|
59942
|
+
"select",
|
|
59943
|
+
{
|
|
59944
|
+
value: filter2.value,
|
|
59945
|
+
onChange: (e) => filter2.onChange(e.target.value),
|
|
59946
|
+
className: "w-full appearance-none pl-3 pr-8 py-2 text-sm bg-gray-50 border border-gray-200 hover:border-gray-300 rounded-lg text-gray-900 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:bg-white transition-all cursor-pointer",
|
|
59947
|
+
style: { backgroundImage: `url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e")`, backgroundPosition: `right 0.75rem center`, backgroundRepeat: `no-repeat`, backgroundSize: `1.2em 1.2em` },
|
|
59948
|
+
children: filter2.options.map((opt) => {
|
|
59949
|
+
const val = typeof opt === "string" ? opt : opt.id;
|
|
59950
|
+
let label = val;
|
|
59951
|
+
if (filter2.labels) {
|
|
59952
|
+
const found = filter2.labels.find((l) => (l.id || l.user_id || l) === val);
|
|
59953
|
+
label = found ? found.label || found.name || found : val;
|
|
59954
|
+
}
|
|
59955
|
+
if (val === "all") label = `All ${filter2.label}s`;
|
|
59956
|
+
return /* @__PURE__ */ jsx("option", { value: val, children: label }, val);
|
|
59957
|
+
})
|
|
59958
|
+
}
|
|
59959
|
+
) })
|
|
59960
|
+
] }, idx)) })
|
|
59961
|
+
] })
|
|
59332
59962
|
] })
|
|
59333
59963
|
] }),
|
|
59334
59964
|
/* @__PURE__ */ jsxs("div", { className: "grid gap-6", children: [
|
|
59335
|
-
filteredRecommendations.length > 0 ? filteredRecommendations.map((rec, index) =>
|
|
59336
|
-
|
|
59337
|
-
{
|
|
59338
|
-
|
|
59339
|
-
|
|
59340
|
-
|
|
59341
|
-
|
|
59342
|
-
|
|
59343
|
-
|
|
59344
|
-
|
|
59345
|
-
|
|
59346
|
-
|
|
59347
|
-
|
|
59348
|
-
|
|
59349
|
-
|
|
59350
|
-
/* @__PURE__ */
|
|
59351
|
-
|
|
59352
|
-
|
|
59353
|
-
|
|
59354
|
-
|
|
59355
|
-
|
|
59356
|
-
|
|
59357
|
-
/* @__PURE__ */
|
|
59358
|
-
|
|
59359
|
-
|
|
59360
|
-
|
|
59965
|
+
filteredRecommendations.length > 0 ? filteredRecommendations.map((rec, index) => {
|
|
59966
|
+
const weeksOpen = rec.weeks_open || 1;
|
|
59967
|
+
const openLabel = weeksOpen <= 1 ? "Opened this week" : `Opened for ${weeksOpen} weeks`;
|
|
59968
|
+
const openedOnLabel = formatOpenedDate(rec.first_seen_at);
|
|
59969
|
+
return /* @__PURE__ */ jsx(
|
|
59970
|
+
motion.div,
|
|
59971
|
+
{
|
|
59972
|
+
initial: { opacity: 0, y: 20 },
|
|
59973
|
+
animate: { opacity: 1, y: 0 },
|
|
59974
|
+
transition: { delay: index * 0.1 },
|
|
59975
|
+
className: `bg-white rounded-xl shadow-sm border overflow-hidden ${rec.ticket_status === "solved" ? "border-green-200" : "border-gray-200"}`,
|
|
59976
|
+
children: /* @__PURE__ */ jsx("div", { className: "p-6 relative", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col md:flex-row gap-6", children: [
|
|
59977
|
+
/* @__PURE__ */ jsxs("div", { className: "flex-1 space-y-4", children: [
|
|
59978
|
+
/* @__PURE__ */ jsx("div", { className: "flex items-start justify-between", children: /* @__PURE__ */ jsxs("div", { className: "space-y-3 w-full", children: [
|
|
59979
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-3", children: [
|
|
59980
|
+
/* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1.5 px-2.5 py-0.5 rounded-full text-xs font-semibold text-gray-600 bg-gray-100 border border-gray-200", children: [
|
|
59981
|
+
"#",
|
|
59982
|
+
rec.issue_number ?? index + 1
|
|
59983
|
+
] }),
|
|
59984
|
+
rec.ticket_status === "solved" ? /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1.5 px-2.5 py-0.5 rounded-full text-xs font-medium bg-emerald-50 text-emerald-700 border border-emerald-100", children: [
|
|
59985
|
+
/* @__PURE__ */ jsx(CheckCircleIcon, { className: "w-3.5 h-3.5" }),
|
|
59986
|
+
"Resolved"
|
|
59987
|
+
] }) : /* @__PURE__ */ jsxs("span", { className: `inline-flex items-center gap-1.5 px-2.5 py-0.5 rounded-full text-xs font-medium border ${weeksOpen > 2 ? "bg-red-50 text-red-700 border-red-100" : "bg-amber-50 text-amber-700 border-amber-100"}`, children: [
|
|
59988
|
+
/* @__PURE__ */ jsx(ClockIcon, { className: "w-3.5 h-3.5" }),
|
|
59989
|
+
openLabel
|
|
59990
|
+
] }),
|
|
59991
|
+
openedOnLabel && /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1.5 px-2.5 py-0.5 rounded-full text-xs font-medium text-gray-600 bg-gray-100 border border-gray-200", children: [
|
|
59992
|
+
"Opened on ",
|
|
59993
|
+
openedOnLabel
|
|
59994
|
+
] }),
|
|
59995
|
+
rec.assigned_user_ids && rec.assigned_user_ids.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
59996
|
+
/* @__PURE__ */ jsx("div", { className: "h-3 w-px bg-gray-200" }),
|
|
59997
|
+
/* @__PURE__ */ jsx("div", { className: "flex items-center gap-3", children: rec.assigned_user_ids.map((uid) => {
|
|
59998
|
+
const user2 = teamMembersById.get(uid);
|
|
59999
|
+
if (!user2) {
|
|
60000
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
|
|
60001
|
+
/* @__PURE__ */ jsx("div", { className: "w-5 h-5 rounded-full bg-gray-100 text-gray-500 flex items-center justify-center text-[9px] font-bold border border-gray-200", children: "??" }),
|
|
60002
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-gray-500", children: "Unknown" })
|
|
60003
|
+
] }, uid);
|
|
60004
|
+
}
|
|
59361
60005
|
return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
|
|
59362
|
-
/* @__PURE__ */ jsx("div", { className: "w-5 h-5 rounded-full bg-gray-100 text-gray-
|
|
59363
|
-
/* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-gray-
|
|
59364
|
-
] },
|
|
59365
|
-
}
|
|
59366
|
-
|
|
59367
|
-
|
|
59368
|
-
|
|
59369
|
-
|
|
59370
|
-
|
|
59371
|
-
|
|
59372
|
-
|
|
59373
|
-
|
|
59374
|
-
|
|
59375
|
-
|
|
59376
|
-
|
|
59377
|
-
|
|
59378
|
-
rec.line,
|
|
59379
|
-
(rec.shift_label || rec.shift_id !== void 0) && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
59380
|
-
/* @__PURE__ */ jsx("span", { children: "\u2022" }),
|
|
59381
|
-
/* @__PURE__ */ jsx("span", { className: "uppercase tracking-wide text-xs pt-0.5 text-gray-500 font-medium", children: rec.shift_label || `Shift ${rec.shift_id}` })
|
|
60006
|
+
/* @__PURE__ */ jsx("div", { className: "w-5 h-5 rounded-full bg-gray-100 text-gray-600 flex items-center justify-center text-[9px] font-bold border border-gray-200", children: user2.initials }),
|
|
60007
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-gray-600", children: user2.name })
|
|
60008
|
+
] }, user2.id);
|
|
60009
|
+
}) })
|
|
60010
|
+
] })
|
|
60011
|
+
] }),
|
|
60012
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
60013
|
+
/* @__PURE__ */ jsx("h3", { className: "text-lg font-semibold text-gray-900 pr-12", children: rec.title }),
|
|
60014
|
+
/* @__PURE__ */ jsxs("p", { className: "text-sm font-medium text-gray-500 mt-1 flex items-center gap-2", children: [
|
|
60015
|
+
rec.location,
|
|
60016
|
+
" \u2022 ",
|
|
60017
|
+
rec.line,
|
|
60018
|
+
(rec.shift_label || rec.shift_id !== void 0) && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
60019
|
+
/* @__PURE__ */ jsx("span", { children: "\u2022" }),
|
|
60020
|
+
/* @__PURE__ */ jsx("span", { className: "uppercase tracking-wide text-xs pt-0.5 text-gray-500 font-medium", children: rec.shift_label || `Shift ${rec.shift_id}` })
|
|
60021
|
+
] })
|
|
59382
60022
|
] })
|
|
59383
60023
|
] })
|
|
59384
|
-
] })
|
|
59385
|
-
|
|
59386
|
-
|
|
59387
|
-
|
|
59388
|
-
|
|
59389
|
-
|
|
59390
|
-
|
|
59391
|
-
|
|
59392
|
-
|
|
59393
|
-
|
|
59394
|
-
|
|
59395
|
-
|
|
59396
|
-
|
|
59397
|
-
|
|
59398
|
-
|
|
59399
|
-
|
|
59400
|
-
|
|
59401
|
-
|
|
59402
|
-
|
|
59403
|
-
|
|
59404
|
-
)) : (
|
|
60024
|
+
] }) }),
|
|
60025
|
+
/* @__PURE__ */ jsx("div", { className: "prose prose-sm text-gray-600", children: /* @__PURE__ */ jsx("p", { children: rec.description }) }),
|
|
60026
|
+
rec.resolution_instructions && /* @__PURE__ */ jsx("div", { className: "bg-blue-50 border border-blue-100 rounded-lg p-3", children: /* @__PURE__ */ jsxs("p", { className: "text-sm text-blue-800 font-medium flex items-start gap-2", children: [
|
|
60027
|
+
/* @__PURE__ */ jsx(CheckCircleIcon, { className: "w-5 h-5 flex-shrink-0" }),
|
|
60028
|
+
rec.resolution_instructions
|
|
60029
|
+
] }) })
|
|
60030
|
+
] }),
|
|
60031
|
+
/* @__PURE__ */ jsx("div", { className: "w-full md:w-1/2 lg:w-5/12 bg-gray-50 rounded-lg p-4 border border-gray-100", children: Array.isArray(rec.evidence) && rec.evidence.length > 0 ? /* @__PURE__ */ jsx(
|
|
60032
|
+
EvidenceCarousel,
|
|
60033
|
+
{
|
|
60034
|
+
evidence: rec.evidence,
|
|
60035
|
+
recId: rec.id,
|
|
60036
|
+
clipsService
|
|
60037
|
+
}
|
|
60038
|
+
) : /* @__PURE__ */ jsx("div", { className: "text-xs text-gray-500", children: isLoading ? "Loading evidence\u2026" : loadError ? loadError : "No evidence available" }) })
|
|
60039
|
+
] }) })
|
|
60040
|
+
},
|
|
60041
|
+
rec.id
|
|
60042
|
+
);
|
|
60043
|
+
}) : (
|
|
59405
60044
|
// Success State (Zero Tickets)
|
|
59406
60045
|
/* @__PURE__ */ jsxs("div", { className: "text-center py-16 bg-white rounded-xl border border-gray-200 shadow-sm", children: [
|
|
59407
60046
|
/* @__PURE__ */ jsx("div", { className: "mx-auto flex items-center justify-center w-16 h-16 rounded-full bg-green-50 mb-4", children: /* @__PURE__ */ jsx(CheckCircleIcon, { className: "w-8 h-8 text-green-500" }) }),
|
|
@@ -59878,4 +60517,4 @@ var streamProxyConfig = {
|
|
|
59878
60517
|
}
|
|
59879
60518
|
};
|
|
59880
60519
|
|
|
59881
|
-
export { ACTION_NAMES, AIAgentView_default as AIAgentView, AcceptInvite, AcceptInviteView_default as AcceptInviteView, AdvancedFilterDialog, AdvancedFilterPanel, AudioService, AuthCallback, AuthCallbackView_default as AuthCallbackView, AuthProvider, AuthService, AuthenticatedBottleneckClipsView, AuthenticatedFactoryView, AuthenticatedHelpView, AuthenticatedHomeView, AuthenticatedShiftsView, AuthenticatedTargetsView, AuthenticatedTicketsView, AuthenticatedWorkspaceHealthView, AxelNotificationPopup, AxelOrb, BackButton, BackButtonMinimal, BarChart, BaseHistoryCalendar, BottleneckClipsModal, BottleneckClipsView_default as BottleneckClipsView, BottlenecksContent, BreakNotificationPopup, CachePrefetchStatus, Card2 as Card, CardContent2 as CardContent, CardDescription2 as CardDescription, CardFooter2 as CardFooter, CardHeader2 as CardHeader, CardTitle2 as CardTitle, ChangeRoleDialog, ClipFilterProvider, CompactWorkspaceHealthCard, ConfirmRemoveUserDialog, CongratulationsOverlay, CroppedHlsVideoPlayer, CroppedVideoPlayer, CycleTimeChart, CycleTimeOverTimeChart, DEFAULT_ANALYTICS_CONFIG, DEFAULT_AUTH_CONFIG, DEFAULT_CONFIG, DEFAULT_DATABASE_CONFIG, DEFAULT_DATE_TIME_CONFIG, DEFAULT_ENDPOINTS_CONFIG, DEFAULT_ENTITY_CONFIG, DEFAULT_HOME_VIEW_CONFIG, DEFAULT_MAP_VIEW_CONFIG, DEFAULT_SHIFT_CONFIG, DEFAULT_SHIFT_DATA, DEFAULT_THEME_CONFIG, DEFAULT_VIDEO_CONFIG, DEFAULT_WORKSPACE_CONFIG, DEFAULT_WORKSPACE_POSITIONS, DashboardHeader, DashboardLayout, DashboardOverridesProvider, DashboardProvider, DateDisplay_default as DateDisplay, DateTimeDisplay, DebugAuth, DebugAuthView_default as DebugAuthView, DetailedHealthStatus, DiagnosisVideoModal, EmptyStateMessage, EncouragementOverlay, FactoryAssignmentDropdown, FactoryView_default as FactoryView, FileManagerFilters, FilterDialogTrigger, FirstTimeLoginDebug, FirstTimeLoginHandler, GaugeChart, GridComponentsPlaceholder, HamburgerButton, Header, HealthDateShiftSelector, HealthStatusGrid, HealthStatusIndicator, HelpView_default as HelpView, HlsVideoPlayer, HomeView_default as HomeView, HourlyOutputChart2 as HourlyOutputChart, ISTTimer_default as ISTTimer, ImprovementCenterView_default as ImprovementCenterView, InlineEditableText, InteractiveOnboardingTour, InvitationService, InvitationsTable, InviteUserDialog, 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, LineAssignmentDropdown, LineChart, LineHistoryCalendar, LineMonthlyHistory, LineMonthlyPdfGenerator, LinePdfExportButton, LinePdfGenerator, LineWhatsAppShareButton, LinesService, LiveTimer, LoadingInline, LoadingOverlay_default as LoadingOverlay, LoadingPage_default as LoadingPage, LoadingSkeleton, LoadingState, LoginPage, LoginView_default as LoginView, Logo, MainLayout, MapGridView, MetricCard_default as MetricCard, MinimalOnboardingPopup, NewClipsNotification, NoWorkspaceData, OnboardingDemo, OnboardingTour, OptifyeAgentClient, OptifyeLogoLoader_default as OptifyeLogoLoader, OutputProgressChart, PageHeader, PieChart4 as PieChart, PlayPauseIndicator, PrefetchConfigurationError, PrefetchError, PrefetchEvents, PrefetchStatus, PrefetchTimeoutError, ProfileView_default as ProfileView, RegistryProvider, RoleBadge, S3ClipsSupabaseService as S3ClipsService, S3Service, SKUManagementView, SOPComplianceChart, SSEChatClient, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, SessionTracker, SessionTrackingContext, SessionTrackingProvider, ShiftDisplay_default as ShiftDisplay, ShiftsView_default as ShiftsView, SideNavBar, SignupWithInvitation, SilentErrorBoundary, SimpleOnboardingPopup, SingleVideoStream_default as SingleVideoStream, Skeleton, SubscriptionManager, SubscriptionManagerProvider, SupabaseProvider, SupervisorDropdown_default as SupervisorDropdown, SupervisorManagementView_default as SupervisorManagementView, SupervisorService, TargetWorkspaceGrid, TargetsView_default as TargetsView, TeamManagementView_default as TeamManagementView, TeamUsagePdfGenerator, ThreadSidebar, TicketHistory_default as TicketHistory, TicketHistoryService, TicketsView_default as TicketsView, TimeDisplay_default as TimeDisplay, TimePickerDropdown, Timer_default as Timer, TimezoneProvider, TimezoneService, UserManagementService, UserManagementTable, UserService, UserUsageDetailModal, UserUsageStats, VideoCard, VideoGridView, VideoPlayer, VideoPreloader, WORKSPACE_POSITIONS, WhatsAppShareButton, WorkspaceCard, WorkspaceDetailView_default as WorkspaceDetailView, WorkspaceDisplayNameExample, WorkspaceGrid, WorkspaceGridItem, WorkspaceHealthCard, WorkspaceHealthView_default as WorkspaceHealthView, WorkspaceHistoryCalendar, WorkspaceMetricCards, WorkspaceMetricCardsImpl, WorkspaceMonthlyDataFetcher, WorkspaceMonthlyHistory, WorkspaceMonthlyPdfGenerator, WorkspacePdfExportButton, WorkspacePdfGenerator, WorkspaceWhatsAppShareButton, actionService, aggregateKPIsFromLineMetricsRows, apiUtils, areAllLinesOnSameShift, authCoreService, authOTPService, authRateLimitService, buildDateKey, buildKPIsFromLineMetricsRow, checkRateLimit2 as checkRateLimit, clearAllRateLimits2 as clearAllRateLimits, clearRateLimit2 as clearRateLimit, clearS3VideoCache, clearS3VideoFromCache, clearWorkspaceDisplayNamesCache, cn, createDefaultKPIs, createInvitationService, createLinesService, createSessionTracker, createStreamProxyHandler, createSupabaseClient, createSupervisorService, createThrottledReload, createUserManagementService, createUserService, dashboardService, deleteThread, fetchIdleTimeReasons, filterDataByDateKeyRange, forceRefreshWorkspaceDisplayNames, formatDateInZone, formatDateKeyForDisplay, formatDateTimeInZone, formatDuration, formatISTDate, formatIdleTime, formatRangeLabel, formatReasonLabel, formatRelativeTime, formatTimeInZone, fromUrlFriendlyName, getAllLineDisplayNames, getAllThreadMessages, getAllWorkspaceDisplayNamesAsync, getAllWorkspaceDisplayNamesSnapshot, getAnonClient, getAvailableShiftIds, getBrowserName, getCameraNumber, getCompanyMetricsTableName, getConfigurableShortWorkspaceDisplayName, getConfigurableWorkspaceDisplayName, getConfiguredLineIds, getCoreSessionRecordingProperties, getCoreSessionReplayUrl, getCurrentShift, getCurrentShiftForLine, getCurrentTimeInZone, getDashboardHeaderTimeInZone, getDateKeyFromDate, getDaysDifferenceInZone, getDefaultCameraStreamUrl, getDefaultLineId, getDefaultTabForWorkspace, getLineDisplayName, getManufacturingInsights, getMetricsTablePrefix, getMonthKeyBounds, getMonthWeekRanges, getNextUpdateInterval, getOperationalDate, getReasonColor, getS3SignedUrl, getS3VideoSrc, getShiftData, getShiftNameById, getShortShiftName, getShortWorkspaceDisplayName, getShortWorkspaceDisplayNameAsync, getStoredWorkspaceMappings, getSubscriptionManager, getThreadMessages, getUniformShiftGroup, getUserThreads, getUserThreadsPaginated, getWorkspaceDisplayName, getWorkspaceDisplayNameAsync, getWorkspaceDisplayNamesMap, getWorkspaceFromUrl, getWorkspaceNavigationParams, groupLinesByShift, hasAnyShiftData, identifyCoreUser, initializeCoreMixpanel, isFullMonthRange, isLegacyConfiguration, isPrefetchError, isSafari, isTransitionPeriod, isUrlPermanentlyFailed, isValidFactoryViewConfiguration, isValidLineInfoPayload, isValidPrefetchParams, isValidPrefetchStatus, isValidWorkspaceDetailedMetricsPayload, isValidWorkspaceMetricsPayload, isWorkspaceDisplayNamesLoaded, isWorkspaceDisplayNamesLoading, linesService, mergeWithDefaultConfig, migrateLegacyConfiguration, normalizeDateKeyRange, optifyeAgentClient, parseDateKeyToDate, parseS3Uri, preInitializeWorkspaceDisplayNames, preloadS3Video, preloadS3VideoUrl, preloadS3VideosUrl, preloadVideoUrl, preloadVideosUrl, qualityService, realtimeService, refreshWorkspaceDisplayNames, resetCoreMixpanel, resetFailedUrl, resetSubscriptionManager, s3VideoPreloader, shuffleArray, simulateApiDelay, skuService, startCoreSessionRecording, stopCoreSessionRecording, storeWorkspaceMapping, streamProxyConfig, subscribeWorkspaceDisplayNames, throttledReloadDashboard, toUrlFriendlyName, trackCoreEvent, trackCorePageView, transformToChartData, updateThreadTitle, upsertWorkspaceDisplayNameInCache, useAccessControl, useActiveBreaks, useActiveLineId, useAllWorkspaceMetrics, useAnalyticsConfig, useAppTimezone, useAudioService, useAuth, useAuthConfig, useAxelNotifications, useCanSaveTargets, useClipFilter, useClipTypes, useClipTypesWithCounts, useCompanyUsersUsage, useComponentOverride, useCustomConfig, useDashboardConfig, useDashboardMetrics, useDatabaseConfig, useDateFormatter, useDateTimeConfig, useDynamicShiftConfig, useEndpointsConfig, useEntityConfig, useFactoryOverviewMetrics, useFeatureFlags, useFormatNumber, useHasLineAccess, useHistoricWorkspaceMetrics, useHlsStream, useHlsStreamWithCropping, useHookOverride, useHourEndTimer, useHourlyTargetAchievements, useHourlyTargetMisses, useIdleTimeReasons, useLeaderboardMetrics, useLineDetailedMetrics, useLineKPIs, useLineMetrics, useLineShiftConfig, useLineSupervisor, useLineWorkspaceMetrics, useLines, useMessages, useMetrics, useMultiLineShiftConfigs, useNavigation, useOverrides, usePageOverride, usePrefetchClipCounts, useRealtimeLineMetrics, useRegistry, useSKUs, useSessionKeepAlive, useSessionTracking, useSessionTrackingContext, useShiftConfig, useShifts, useSubscriptionManager, useSubscriptionManagerSafe, useSupabase, useSupabaseClient, useSupervisorsByLineIds, useTargets, useTeamManagementPermissions, useTheme, useThemeConfig, useThreads, useTicketHistory, useTimezoneContext, useUserLineAccess, useUserUsage, useVideoConfig, useWorkspaceConfig, useWorkspaceDetailedMetrics, useWorkspaceDisplayName, useWorkspaceDisplayNames, useWorkspaceDisplayNamesMap, useWorkspaceHealthById, useWorkspaceHealthStatus, useWorkspaceMetrics, useWorkspaceNavigation, useWorkspaceOperators, useWorkspaceUptimeTimeline, userService, videoPrefetchManager, videoPreloader, whatsappService, withAccessControl, withAuth, withRegistry, withTimezone, workspaceHealthService, workspaceService };
|
|
60520
|
+
export { ACTION_NAMES, AIAgentView_default as AIAgentView, AcceptInvite, AcceptInviteView_default as AcceptInviteView, AdvancedFilterDialog, AdvancedFilterPanel, AudioService, AuthCallback, AuthCallbackView_default as AuthCallbackView, AuthProvider, AuthService, AuthenticatedBottleneckClipsView, AuthenticatedFactoryView, AuthenticatedHelpView, AuthenticatedHomeView, AuthenticatedShiftsView, AuthenticatedTargetsView, AuthenticatedTicketsView, AuthenticatedWorkspaceHealthView, AxelNotificationPopup, AxelOrb, BackButton, BackButtonMinimal, BarChart, BaseHistoryCalendar, BottleneckClipsModal, BottleneckClipsView_default as BottleneckClipsView, BottlenecksContent, BreakNotificationPopup, CachePrefetchStatus, Card2 as Card, CardContent2 as CardContent, CardDescription2 as CardDescription, CardFooter2 as CardFooter, CardHeader2 as CardHeader, CardTitle2 as CardTitle, ChangeRoleDialog, ClipFilterProvider, CompactWorkspaceHealthCard, ConfirmRemoveUserDialog, CongratulationsOverlay, CroppedHlsVideoPlayer, CroppedVideoPlayer, CycleTimeChart, CycleTimeOverTimeChart, DEFAULT_ANALYTICS_CONFIG, DEFAULT_AUTH_CONFIG, DEFAULT_CONFIG, DEFAULT_DATABASE_CONFIG, DEFAULT_DATE_TIME_CONFIG, DEFAULT_ENDPOINTS_CONFIG, DEFAULT_ENTITY_CONFIG, DEFAULT_HOME_VIEW_CONFIG, DEFAULT_MAP_VIEW_CONFIG, DEFAULT_SHIFT_CONFIG, DEFAULT_SHIFT_DATA, DEFAULT_THEME_CONFIG, DEFAULT_VIDEO_CONFIG, DEFAULT_WORKSPACE_CONFIG, DEFAULT_WORKSPACE_POSITIONS, DashboardHeader, DashboardLayout, DashboardOverridesProvider, DashboardProvider, DateDisplay_default as DateDisplay, DateTimeDisplay, DebugAuth, DebugAuthView_default as DebugAuthView, DetailedHealthStatus, DiagnosisVideoModal, EmptyStateMessage, EncouragementOverlay, FactoryAssignmentDropdown, FactoryView_default as FactoryView, FileManagerFilters, FilterDialogTrigger, FirstTimeLoginDebug, FirstTimeLoginHandler, GaugeChart, GridComponentsPlaceholder, HamburgerButton, Header, HealthDateShiftSelector, HealthStatusGrid, HealthStatusIndicator, HelpView_default as HelpView, HlsVideoPlayer, HomeView_default as HomeView, HourlyOutputChart2 as HourlyOutputChart, ISTTimer_default as ISTTimer, ImprovementCenterView_default as ImprovementCenterView, InlineEditableText, InteractiveOnboardingTour, InvitationService, InvitationsTable, InviteUserDialog, 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, LineAssignmentDropdown, LineChart, LineHistoryCalendar, LineMonthlyHistory, LineMonthlyPdfGenerator, LinePdfExportButton, LinePdfGenerator, LineWhatsAppShareButton, LinesService, LiveTimer, LoadingInline, LoadingOverlay_default as LoadingOverlay, LoadingPage_default as LoadingPage, LoadingSkeleton, LoadingState, LoginPage, LoginView_default as LoginView, Logo, MainLayout, MapGridView, MetricCard_default as MetricCard, MinimalOnboardingPopup, NewClipsNotification, NoWorkspaceData, OnboardingDemo, OnboardingTour, OptifyeAgentClient, OptifyeLogoLoader_default as OptifyeLogoLoader, OutputProgressChart, PageHeader, PieChart4 as PieChart, PlayPauseIndicator, PrefetchConfigurationError, PrefetchError, PrefetchEvents, PrefetchStatus, PrefetchTimeoutError, ProfileView_default as ProfileView, RegistryProvider, RoleBadge, S3ClipsSupabaseService as S3ClipsService, S3Service, SKUManagementView, SOPComplianceChart, SSEChatClient, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, SessionTracker, SessionTrackingContext, SessionTrackingProvider, ShiftDisplay_default as ShiftDisplay, ShiftsView_default as ShiftsView, SideNavBar, SignupWithInvitation, SilentErrorBoundary, SimpleOnboardingPopup, SingleVideoStream_default as SingleVideoStream, Skeleton, SubscriptionManager, SubscriptionManagerProvider, SupabaseProvider, SupervisorDropdown_default as SupervisorDropdown, SupervisorManagementView_default as SupervisorManagementView, SupervisorService, TargetWorkspaceGrid, TargetsView_default as TargetsView, TeamManagementView_default as TeamManagementView, TeamUsagePdfGenerator, ThreadSidebar, TicketHistory_default as TicketHistory, TicketHistoryService, TicketsView_default as TicketsView, TimeDisplay_default as TimeDisplay, TimePickerDropdown, Timer_default as Timer, TimezoneProvider, TimezoneService, UserManagementService, UserManagementTable, UserService, UserUsageDetailModal, UserUsageStats, VideoCard, VideoGridView, VideoPlayer, VideoPreloader, WORKSPACE_POSITIONS, WhatsAppShareButton, WorkspaceCard, WorkspaceDetailView_default as WorkspaceDetailView, WorkspaceDisplayNameExample, WorkspaceGrid, WorkspaceGridItem, WorkspaceHealthCard, WorkspaceHealthView_default as WorkspaceHealthView, WorkspaceHistoryCalendar, WorkspaceMetricCards, WorkspaceMetricCardsImpl, WorkspaceMonthlyDataFetcher, WorkspaceMonthlyHistory, WorkspaceMonthlyPdfGenerator, WorkspacePdfExportButton, WorkspacePdfGenerator, WorkspaceWhatsAppShareButton, actionService, aggregateKPIsFromLineMetricsRows, apiUtils, areAllLinesOnSameShift, authCoreService, authOTPService, authRateLimitService, buildDateKey, buildKPIsFromLineMetricsRow, checkRateLimit2 as checkRateLimit, clearAllRateLimits2 as clearAllRateLimits, clearRateLimit2 as clearRateLimit, clearS3VideoCache, clearS3VideoFromCache, clearWorkspaceDisplayNamesCache, cn, createDefaultKPIs, createInvitationService, createLinesService, createSessionTracker, createStreamProxyHandler, createSupabaseClient, createSupervisorService, createThrottledReload, createUserManagementService, createUserService, dashboardService, deleteThread, fetchIdleTimeReasons, filterDataByDateKeyRange, forceRefreshWorkspaceDisplayNames, formatDateInZone, formatDateKeyForDisplay, formatDateTimeInZone, formatDuration, formatISTDate, formatIdleTime, formatRangeLabel, formatReasonLabel, formatRelativeTime, formatTimeInZone, fromUrlFriendlyName, getAllLineDisplayNames, getAllThreadMessages, getAllWorkspaceDisplayNamesAsync, getAllWorkspaceDisplayNamesSnapshot, getAnonClient, getAvailableShiftIds, getBrowserName, getCameraNumber, getCompanyMetricsTableName, getConfigurableShortWorkspaceDisplayName, getConfigurableWorkspaceDisplayName, getConfiguredLineIds, getCoreSessionRecordingProperties, getCoreSessionReplayUrl, getCurrentShift, getCurrentShiftForLine, getCurrentTimeInZone, getDashboardHeaderTimeInZone, getDateKeyFromDate, getDaysDifferenceInZone, getDefaultCameraStreamUrl, getDefaultLineId, getDefaultTabForWorkspace, getLineDisplayName, getManufacturingInsights, getMetricsTablePrefix, getMonthKeyBounds, getMonthWeekRanges, getNextUpdateInterval, getOperationalDate, getReasonColor, getS3SignedUrl, getS3VideoSrc, getShiftData, getShiftNameById, getShortShiftName, getShortWorkspaceDisplayName, getShortWorkspaceDisplayNameAsync, getStoredWorkspaceMappings, getSubscriptionManager, getThreadMessages, getUniformShiftGroup, getUserThreads, getUserThreadsPaginated, getWorkspaceDisplayName, getWorkspaceDisplayNameAsync, getWorkspaceDisplayNamesMap, getWorkspaceFromUrl, getWorkspaceNavigationParams, groupLinesByShift, hasAnyShiftData, identifyCoreUser, initializeCoreMixpanel, isFullMonthRange, isLegacyConfiguration, isPrefetchError, isSafari, isTransitionPeriod, isUrlPermanentlyFailed, isValidFactoryViewConfiguration, isValidLineInfoPayload, isValidPrefetchParams, isValidPrefetchStatus, isValidWorkspaceDetailedMetricsPayload, isValidWorkspaceMetricsPayload, isWorkspaceDisplayNamesLoaded, isWorkspaceDisplayNamesLoading, linesService, mergeWithDefaultConfig, migrateLegacyConfiguration, normalizeDateKeyRange, optifyeAgentClient, parseDateKeyToDate, parseS3Uri, preInitializeWorkspaceDisplayNames, preloadS3Video, preloadS3VideoUrl, preloadS3VideosUrl, preloadVideoUrl, preloadVideosUrl, qualityService, realtimeService, refreshWorkspaceDisplayNames, resetCoreMixpanel, resetFailedUrl, resetSubscriptionManager, s3VideoPreloader, shuffleArray, simulateApiDelay, skuService, startCoreSessionRecording, stopCoreSessionRecording, storeWorkspaceMapping, streamProxyConfig, subscribeWorkspaceDisplayNames, throttledReloadDashboard, toUrlFriendlyName, trackCoreEvent, trackCorePageView, transformToChartData, updateThreadTitle, upsertWorkspaceDisplayNameInCache, useAccessControl, useActiveBreaks, useActiveLineId, useAllWorkspaceMetrics, useAnalyticsConfig, useAppTimezone, useAudioService, useAuth, useAuthConfig, useAxelNotifications, useCanSaveTargets, useClipFilter, useClipTypes, useClipTypesWithCounts, useCompanyUsersUsage, useComponentOverride, useCustomConfig, useDashboardConfig, useDashboardMetrics, useDatabaseConfig, useDateFormatter, useDateTimeConfig, useDynamicShiftConfig, useEndpointsConfig, useEntityConfig, useFactoryOverviewMetrics, useFeatureFlags, useFormatNumber, useHasLineAccess, useHistoricWorkspaceMetrics, useHlsStream, useHlsStreamWithCropping, useHookOverride, useHourEndTimer, useHourlyTargetAchievements, useHourlyTargetMisses, useIdleTimeClipClassifications, useIdleTimeReasons, useLeaderboardMetrics, useLineDetailedMetrics, useLineKPIs, useLineMetrics, useLineShiftConfig, useLineSupervisor, useLineWorkspaceMetrics, useLines, useMessages, useMetrics, useMultiLineShiftConfigs, useNavigation, useOverrides, usePageOverride, usePrefetchClipCounts, useRealtimeLineMetrics, useRegistry, useSKUs, useSessionKeepAlive, useSessionTracking, useSessionTrackingContext, useShiftConfig, useShifts, useSubscriptionManager, useSubscriptionManagerSafe, useSupabase, useSupabaseClient, useSupervisorsByLineIds, useTargets, useTeamManagementPermissions, useTheme, useThemeConfig, useThreads, useTicketHistory, useTimezoneContext, useUserLineAccess, useUserUsage, useVideoConfig, useWorkspaceConfig, useWorkspaceDetailedMetrics, useWorkspaceDisplayName, useWorkspaceDisplayNames, useWorkspaceDisplayNamesMap, useWorkspaceHealthById, useWorkspaceHealthStatus, useWorkspaceMetrics, useWorkspaceNavigation, useWorkspaceOperators, useWorkspaceUptimeTimeline, userService, videoPrefetchManager, videoPreloader, whatsappService, withAccessControl, withAuth, withRegistry, withTimezone, workspaceHealthService, workspaceService };
|