@optifye/dashboard-core 6.10.52 → 6.11.0
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 +178 -17
- package/dist/index.d.mts +66 -17
- package/dist/index.d.ts +66 -17
- package/dist/index.js +3993 -2435
- package/dist/index.mjs +2106 -550
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
import * as
|
|
2
|
-
import
|
|
1
|
+
import * as React141 from 'react';
|
|
2
|
+
import React141__default, { createContext, useRef, useCallback, useState, useMemo, useEffect, forwardRef, useImperativeHandle, useLayoutEffect, memo as memo$1, 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
5
|
import { fromZonedTime, formatInTimeZone, toZonedTime } from 'date-fns-tz';
|
|
6
|
-
import { endOfDay, startOfDay,
|
|
6
|
+
import { endOfDay, startOfDay, startOfMonth, isSameDay, endOfMonth, eachDayOfInterval, getDay, isWithinInterval, format, addDays, differenceInMinutes, addMinutes, subDays, subMonths, addMonths, parseISO, isValid, formatDistanceToNow, isToday, isFuture, isBefore } 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';
|
|
10
10
|
import Hls, { Events, ErrorTypes } from 'hls.js';
|
|
11
11
|
import useSWR from 'swr';
|
|
12
12
|
import { memo, noop, warning, invariant, progress, secondsToMilliseconds, millisecondsToSeconds } from 'motion-utils';
|
|
13
|
-
import { Camera, AlertTriangle, ChevronDown, ChevronUp, Check, Map as Map$1, Video, ShieldCheck, Star, Award, Filter, X, Coffee, Plus, ArrowLeft, Clock, Calendar, Save, AlertCircle, Loader2, Minus, ArrowDown, ArrowUp, ChevronLeft, ChevronRight, TrendingUp, Sparkles, Pause, Play, Wrench, XCircle, Package, UserX, Zap, HelpCircle, Tag, Palette, CheckCircle2, RefreshCw, TrendingDown, FolderOpen, Folder, Sliders, Activity, Layers, Search, Edit2, ArrowRight, CheckCircle, User, Users, Shield, Building2, Mail, Lock, Info, Share2, Trophy, Target, Download, Sun, Moon, MousePointer, UserPlus, UserCog, Trash2, Eye, MoreVertical, BarChart3, Pencil, UserCheck, LogOut, Film, MessageSquare, Menu, Send, Copy, Settings, LifeBuoy, EyeOff,
|
|
13
|
+
import { Camera, AlertTriangle, ChevronDown, ChevronUp, Check, Map as Map$1, Video, ShieldCheck, Star, Award, Filter, X, Coffee, Plus, ArrowLeft, Clock, Calendar, Save, AlertCircle, Loader2, Minus, ArrowDown, ArrowUp, ChevronLeft, ChevronRight, TrendingUp, Sparkles, Pause, Play, Wrench, XCircle, Package, UserX, Zap, HelpCircle, Tag, Palette, CheckCircle2, RefreshCw, TrendingDown, FolderOpen, Folder, Sliders, Activity, Layers, Search, Edit2, ArrowRight, CheckCircle, User, Users, Shield, Building2, Mail, Lock, Info, Share2, Trophy, Target, Download, Sun, Moon, MousePointer, UserPlus, UserCog, Trash2, Eye, MoreVertical, BarChart3, Pencil, UserCheck, LogOut, Film, MessageSquare, Menu, Send, Copy, Bell, ArrowUpRight, Settings, LifeBuoy, EyeOff, Flame, Crown, Medal } from 'lucide-react';
|
|
14
14
|
import { toast } from 'sonner';
|
|
15
15
|
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';
|
|
16
16
|
import { Slot } from '@radix-ui/react-slot';
|
|
17
17
|
import * as SelectPrimitive from '@radix-ui/react-select';
|
|
18
18
|
import { DayPicker, useNavigation as useNavigation$1 } from 'react-day-picker';
|
|
19
|
-
import { AdjustmentsHorizontalIcon, ClockIcon, UsersIcon, UserCircleIcon, TicketIcon, CurrencyDollarIcon, QuestionMarkCircleIcon, XMarkIcon, ArrowRightIcon, Bars3Icon, HomeIcon, TrophyIcon, ChartBarIcon, LightBulbIcon, CubeIcon, HeartIcon, Cog6ToothIcon, ChevronRightIcon, ArrowRightStartOnRectangleIcon, CalendarIcon, ChevronDownIcon, ChevronLeftIcon,
|
|
19
|
+
import { AdjustmentsHorizontalIcon, ClockIcon, UsersIcon, UserCircleIcon, TicketIcon, CurrencyDollarIcon, QuestionMarkCircleIcon, XMarkIcon, ArrowRightIcon, Bars3Icon, HomeIcon, VideoCameraIcon, TrophyIcon, ChartBarIcon, LightBulbIcon, CubeIcon, HeartIcon, BellIcon, Cog6ToothIcon, ChevronRightIcon, ArrowRightStartOnRectangleIcon, ExclamationCircleIcon, ExclamationTriangleIcon, CalendarIcon, ChevronDownIcon, ChevronLeftIcon, EnvelopeIcon, DocumentTextIcon, ChevronUpIcon, ArrowDownTrayIcon, CheckCircleIcon, ChatBubbleLeftRightIcon, XCircleIcon, FunnelIcon, EyeIcon, InformationCircleIcon, ArrowLeftIcon, PlayCircleIcon } from '@heroicons/react/24/outline';
|
|
20
20
|
import { CheckIcon } from '@heroicons/react/24/solid';
|
|
21
21
|
import html2canvas from 'html2canvas';
|
|
22
22
|
import jsPDF, { jsPDF as jsPDF$1 } from 'jspdf';
|
|
@@ -400,14 +400,14 @@ var useIdleTimeVlmConfig = () => {
|
|
|
400
400
|
}
|
|
401
401
|
return context;
|
|
402
402
|
};
|
|
403
|
-
var DashboardConfigContext =
|
|
403
|
+
var DashboardConfigContext = React141.createContext(void 0);
|
|
404
404
|
var DashboardProvider = ({ config: userProvidedConfig, children }) => {
|
|
405
|
-
const fullConfig =
|
|
405
|
+
const fullConfig = React141.useMemo(() => mergeWithDefaultConfig(userProvidedConfig), [userProvidedConfig]);
|
|
406
406
|
_setDashboardConfigInstance(fullConfig);
|
|
407
|
-
|
|
407
|
+
React141.useEffect(() => {
|
|
408
408
|
_setDashboardConfigInstance(fullConfig);
|
|
409
409
|
}, [fullConfig]);
|
|
410
|
-
|
|
410
|
+
React141.useEffect(() => {
|
|
411
411
|
if (!fullConfig.theme) return;
|
|
412
412
|
const styleId = "dashboard-core-theme-vars";
|
|
413
413
|
let styleEl = document.getElementById(styleId);
|
|
@@ -433,7 +433,7 @@ var DashboardProvider = ({ config: userProvidedConfig, children }) => {
|
|
|
433
433
|
return /* @__PURE__ */ jsx(DashboardConfigContext.Provider, { value: fullConfig, children: /* @__PURE__ */ jsx(IdleTimeVlmConfigProvider, { children }) });
|
|
434
434
|
};
|
|
435
435
|
var useDashboardConfig = () => {
|
|
436
|
-
const ctx =
|
|
436
|
+
const ctx = React141.useContext(DashboardConfigContext);
|
|
437
437
|
if (!ctx) throw new Error("useDashboardConfig must be used within a DashboardProvider");
|
|
438
438
|
return ctx;
|
|
439
439
|
};
|
|
@@ -3857,6 +3857,208 @@ var ApiClient = class {
|
|
|
3857
3857
|
};
|
|
3858
3858
|
ApiClient.DEFAULT_TIMEOUT = 3e5;
|
|
3859
3859
|
|
|
3860
|
+
// src/lib/utils/roleMetadata.ts
|
|
3861
|
+
var FACTORY_SCOPED_ROLE_SET = /* @__PURE__ */ new Set(["plant_head", "industrial_engineer"]);
|
|
3862
|
+
var ROLE_ORDER = [
|
|
3863
|
+
"optifye",
|
|
3864
|
+
"owner",
|
|
3865
|
+
"it",
|
|
3866
|
+
"plant_head",
|
|
3867
|
+
"industrial_engineer",
|
|
3868
|
+
"supervisor"
|
|
3869
|
+
];
|
|
3870
|
+
var FULL_DASHBOARD_PATHS = [
|
|
3871
|
+
"/",
|
|
3872
|
+
"/leaderboard",
|
|
3873
|
+
"/kpis",
|
|
3874
|
+
"/targets",
|
|
3875
|
+
"/shifts",
|
|
3876
|
+
"/supervisor-management",
|
|
3877
|
+
"/skus",
|
|
3878
|
+
"/help",
|
|
3879
|
+
"/health",
|
|
3880
|
+
"/profile",
|
|
3881
|
+
"/workspace",
|
|
3882
|
+
"/factory-view",
|
|
3883
|
+
"/team-management",
|
|
3884
|
+
"/tickets",
|
|
3885
|
+
"/improvement-center"
|
|
3886
|
+
];
|
|
3887
|
+
var LIVE_MONITOR_DASHBOARD_PATHS = [
|
|
3888
|
+
"/",
|
|
3889
|
+
"/live-monitor",
|
|
3890
|
+
...FULL_DASHBOARD_PATHS.filter((path) => path !== "/")
|
|
3891
|
+
];
|
|
3892
|
+
var SUPERVISOR_PATHS = [
|
|
3893
|
+
"/",
|
|
3894
|
+
"/leaderboard",
|
|
3895
|
+
"/kpis",
|
|
3896
|
+
"/targets",
|
|
3897
|
+
"/shifts",
|
|
3898
|
+
"/skus",
|
|
3899
|
+
"/help",
|
|
3900
|
+
"/health",
|
|
3901
|
+
"/profile",
|
|
3902
|
+
"/workspace",
|
|
3903
|
+
"/tickets",
|
|
3904
|
+
"/improvement-center"
|
|
3905
|
+
];
|
|
3906
|
+
var ROLE_METADATA = {
|
|
3907
|
+
optifye: {
|
|
3908
|
+
label: "Optifye",
|
|
3909
|
+
description: "Full platform access - Optifye team member",
|
|
3910
|
+
assignmentKind: "global",
|
|
3911
|
+
navPaths: LIVE_MONITOR_DASHBOARD_PATHS
|
|
3912
|
+
},
|
|
3913
|
+
owner: {
|
|
3914
|
+
label: "Owner",
|
|
3915
|
+
description: "Company-wide access - Can manage all users and settings",
|
|
3916
|
+
assignmentKind: "company",
|
|
3917
|
+
navPaths: LIVE_MONITOR_DASHBOARD_PATHS
|
|
3918
|
+
},
|
|
3919
|
+
it: {
|
|
3920
|
+
label: "IT",
|
|
3921
|
+
description: "Company-wide access - IT personnel with full company access",
|
|
3922
|
+
assignmentKind: "company",
|
|
3923
|
+
navPaths: FULL_DASHBOARD_PATHS
|
|
3924
|
+
},
|
|
3925
|
+
plant_head: {
|
|
3926
|
+
label: "Plant Head",
|
|
3927
|
+
description: "Factory-level access - Can manage supervisors and factory settings",
|
|
3928
|
+
assignmentKind: "factory",
|
|
3929
|
+
navPaths: LIVE_MONITOR_DASHBOARD_PATHS
|
|
3930
|
+
},
|
|
3931
|
+
industrial_engineer: {
|
|
3932
|
+
label: "Industrial Engineer",
|
|
3933
|
+
description: "Factory-level access - Can manage supervisors and factory performance scope",
|
|
3934
|
+
assignmentKind: "factory",
|
|
3935
|
+
navPaths: FULL_DASHBOARD_PATHS
|
|
3936
|
+
},
|
|
3937
|
+
supervisor: {
|
|
3938
|
+
label: "Supervisor",
|
|
3939
|
+
description: "Line-level access - Can monitor assigned production lines",
|
|
3940
|
+
assignmentKind: "line",
|
|
3941
|
+
navPaths: SUPERVISOR_PATHS
|
|
3942
|
+
}
|
|
3943
|
+
};
|
|
3944
|
+
var normalizeRoleLevel = (role) => {
|
|
3945
|
+
if (!role) return null;
|
|
3946
|
+
return Object.prototype.hasOwnProperty.call(ROLE_METADATA, role) ? role : null;
|
|
3947
|
+
};
|
|
3948
|
+
var getRoleMetadata = (role) => {
|
|
3949
|
+
const normalizedRole = normalizeRoleLevel(role);
|
|
3950
|
+
return normalizedRole ? ROLE_METADATA[normalizedRole] : null;
|
|
3951
|
+
};
|
|
3952
|
+
var getRoleLabel = (role) => {
|
|
3953
|
+
return getRoleMetadata(role)?.label || (role || "Unknown");
|
|
3954
|
+
};
|
|
3955
|
+
var getRoleDescription = (role) => {
|
|
3956
|
+
return getRoleMetadata(role)?.description || "";
|
|
3957
|
+
};
|
|
3958
|
+
var isFactoryScopedRole = (role) => {
|
|
3959
|
+
const normalizedRole = normalizeRoleLevel(role);
|
|
3960
|
+
return normalizedRole ? FACTORY_SCOPED_ROLE_SET.has(normalizedRole) : false;
|
|
3961
|
+
};
|
|
3962
|
+
var isSupervisorRole = (role) => normalizeRoleLevel(role) === "supervisor";
|
|
3963
|
+
var canRoleManageUsers = (role) => {
|
|
3964
|
+
const normalizedRole = normalizeRoleLevel(role);
|
|
3965
|
+
return normalizedRole === "optifye" || normalizedRole === "owner" || normalizedRole === "it" || isFactoryScopedRole(normalizedRole);
|
|
3966
|
+
};
|
|
3967
|
+
var canRoleManageTargets = (role) => {
|
|
3968
|
+
const normalizedRole = normalizeRoleLevel(role);
|
|
3969
|
+
return normalizedRole === "optifye" || normalizedRole === "owner" || normalizedRole === "it" || isFactoryScopedRole(normalizedRole);
|
|
3970
|
+
};
|
|
3971
|
+
var canRoleViewUsageStats = (role) => {
|
|
3972
|
+
const normalizedRole = normalizeRoleLevel(role);
|
|
3973
|
+
return normalizedRole === "optifye" || normalizedRole === "owner" || normalizedRole === "it";
|
|
3974
|
+
};
|
|
3975
|
+
var canRoleAccessTeamManagement = (role) => {
|
|
3976
|
+
return canRoleManageUsers(role);
|
|
3977
|
+
};
|
|
3978
|
+
var getRoleNavPaths = (role) => {
|
|
3979
|
+
return getRoleMetadata(role)?.navPaths || [];
|
|
3980
|
+
};
|
|
3981
|
+
var getVisibleRolesForCurrentUser = (currentRole) => {
|
|
3982
|
+
const normalizedRole = normalizeRoleLevel(currentRole);
|
|
3983
|
+
const visibleRolesByCurrentRole = {
|
|
3984
|
+
optifye: ROLE_ORDER,
|
|
3985
|
+
owner: ["owner", "it", "plant_head", "industrial_engineer", "supervisor"],
|
|
3986
|
+
it: ["it", "plant_head", "industrial_engineer", "supervisor"],
|
|
3987
|
+
plant_head: ["plant_head", "supervisor"],
|
|
3988
|
+
industrial_engineer: ["industrial_engineer", "supervisor"],
|
|
3989
|
+
supervisor: ["supervisor"]
|
|
3990
|
+
};
|
|
3991
|
+
return normalizedRole ? visibleRolesByCurrentRole[normalizedRole] : ["supervisor"];
|
|
3992
|
+
};
|
|
3993
|
+
var getAssignableRoles = (currentRole, options = {}) => {
|
|
3994
|
+
const normalizedRole = normalizeRoleLevel(currentRole);
|
|
3995
|
+
const isSuperAdminOptifye = !!options.isSuperAdminOptifye;
|
|
3996
|
+
if (!normalizedRole) return [];
|
|
3997
|
+
if (normalizedRole === "optifye") {
|
|
3998
|
+
return isSuperAdminOptifye ? ["owner", "it", "plant_head", "industrial_engineer", "supervisor"] : ["it", "plant_head", "industrial_engineer", "supervisor"];
|
|
3999
|
+
}
|
|
4000
|
+
if (normalizedRole === "owner") {
|
|
4001
|
+
return ["it", "plant_head", "industrial_engineer", "supervisor"];
|
|
4002
|
+
}
|
|
4003
|
+
if (normalizedRole === "it") {
|
|
4004
|
+
return ["plant_head", "industrial_engineer", "supervisor"];
|
|
4005
|
+
}
|
|
4006
|
+
if (isFactoryScopedRole(normalizedRole)) {
|
|
4007
|
+
return ["supervisor"];
|
|
4008
|
+
}
|
|
4009
|
+
return [];
|
|
4010
|
+
};
|
|
4011
|
+
var canRoleInviteRole = (currentRole, targetRole, options = {}) => {
|
|
4012
|
+
const normalizedTargetRole = normalizeRoleLevel(targetRole);
|
|
4013
|
+
if (!normalizedTargetRole) return false;
|
|
4014
|
+
return getAssignableRoles(currentRole, options).includes(normalizedTargetRole);
|
|
4015
|
+
};
|
|
4016
|
+
var canRoleAssignLines = (currentRole, targetRole) => {
|
|
4017
|
+
const normalizedCurrentRole = normalizeRoleLevel(currentRole);
|
|
4018
|
+
const normalizedTargetRole = normalizeRoleLevel(targetRole);
|
|
4019
|
+
if (normalizedTargetRole !== "supervisor") return false;
|
|
4020
|
+
return normalizedCurrentRole === "optifye" || normalizedCurrentRole === "owner" || normalizedCurrentRole === "it" || isFactoryScopedRole(normalizedCurrentRole);
|
|
4021
|
+
};
|
|
4022
|
+
var canRoleAssignFactories = (currentRole, targetRole) => {
|
|
4023
|
+
const normalizedCurrentRole = normalizeRoleLevel(currentRole);
|
|
4024
|
+
const normalizedTargetRole = normalizeRoleLevel(targetRole);
|
|
4025
|
+
if (!normalizedTargetRole || !isFactoryScopedRole(normalizedTargetRole)) return false;
|
|
4026
|
+
return normalizedCurrentRole === "optifye" || normalizedCurrentRole === "owner" || normalizedCurrentRole === "it";
|
|
4027
|
+
};
|
|
4028
|
+
var canRoleChangeRole = (currentRole, targetRole, options = {}) => {
|
|
4029
|
+
const normalizedCurrentRole = normalizeRoleLevel(currentRole);
|
|
4030
|
+
const normalizedTargetRole = normalizeRoleLevel(targetRole);
|
|
4031
|
+
const isSuperAdminOptifye = !!options.isSuperAdminOptifye;
|
|
4032
|
+
if (!normalizedCurrentRole || !normalizedTargetRole) return false;
|
|
4033
|
+
if (normalizedCurrentRole === "optifye") {
|
|
4034
|
+
if (isSuperAdminOptifye) return true;
|
|
4035
|
+
return ["it", "plant_head", "industrial_engineer", "supervisor"].includes(normalizedTargetRole);
|
|
4036
|
+
}
|
|
4037
|
+
if (normalizedCurrentRole === "owner") {
|
|
4038
|
+
return ["plant_head", "industrial_engineer", "supervisor"].includes(normalizedTargetRole);
|
|
4039
|
+
}
|
|
4040
|
+
if (normalizedCurrentRole === "it") {
|
|
4041
|
+
return ["plant_head", "industrial_engineer", "supervisor"].includes(normalizedTargetRole);
|
|
4042
|
+
}
|
|
4043
|
+
return false;
|
|
4044
|
+
};
|
|
4045
|
+
var canRoleRemoveUser = (currentRole, targetRole, options = {}) => {
|
|
4046
|
+
const normalizedCurrentRole = normalizeRoleLevel(currentRole);
|
|
4047
|
+
const normalizedTargetRole = normalizeRoleLevel(targetRole);
|
|
4048
|
+
const isSuperAdminOptifye = !!options.isSuperAdminOptifye;
|
|
4049
|
+
if (!normalizedCurrentRole || !normalizedTargetRole) return false;
|
|
4050
|
+
if (normalizedCurrentRole === "optifye") return isSuperAdminOptifye;
|
|
4051
|
+
if (normalizedCurrentRole === "owner" || normalizedCurrentRole === "it") {
|
|
4052
|
+
return ["plant_head", "industrial_engineer", "supervisor"].includes(normalizedTargetRole);
|
|
4053
|
+
}
|
|
4054
|
+
return false;
|
|
4055
|
+
};
|
|
4056
|
+
var getAssignmentColumnLabel = (role) => {
|
|
4057
|
+
if (isFactoryScopedRole(role)) return "Factories";
|
|
4058
|
+
if (isSupervisorRole(role)) return "Lines";
|
|
4059
|
+
return "Assignments";
|
|
4060
|
+
};
|
|
4061
|
+
|
|
3860
4062
|
// src/lib/services/authService.ts
|
|
3861
4063
|
var AuthService = class {
|
|
3862
4064
|
/**
|
|
@@ -3976,7 +4178,7 @@ var AuthService = class {
|
|
|
3976
4178
|
first_login_completed: enrichedUser.profile.first_login_completed,
|
|
3977
4179
|
properties: {
|
|
3978
4180
|
company_id: enrichedUser.company_id,
|
|
3979
|
-
access_level: enrichedUser.permissions.is_owner || enrichedUser.permissions.is_optifye_admin ? "company" : enrichedUser.
|
|
4181
|
+
access_level: enrichedUser.permissions.is_owner || enrichedUser.permissions.is_optifye_admin ? "company" : isFactoryScopedRole(enrichedUser.role) ? "factory" : "line",
|
|
3980
4182
|
line_ids: line_ids.length > 0 ? line_ids : void 0,
|
|
3981
4183
|
factory_ids: factory_ids.length > 0 ? factory_ids : void 0,
|
|
3982
4184
|
// Include permissions for easy access
|
|
@@ -5561,6 +5763,25 @@ var CLIP_COUNTS_CACHE_TTL = 30 * 1e3;
|
|
|
5561
5763
|
var CLIP_BY_ID_CACHE_TTL = 2 * 60 * 1e3;
|
|
5562
5764
|
var CLIP_BY_ID_CACHE_MAX = 200;
|
|
5563
5765
|
var CLIPS_INIT_CACHE_TTL = 30 * 1e3;
|
|
5766
|
+
var parseFiniteNumber = (value) => {
|
|
5767
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
5768
|
+
return value;
|
|
5769
|
+
}
|
|
5770
|
+
if (typeof value === "string" && value.trim().length > 0) {
|
|
5771
|
+
const parsed = Number(value);
|
|
5772
|
+
if (Number.isFinite(parsed)) {
|
|
5773
|
+
return parsed;
|
|
5774
|
+
}
|
|
5775
|
+
}
|
|
5776
|
+
return void 0;
|
|
5777
|
+
};
|
|
5778
|
+
var getClipCycleTimeFrames = (metadata) => {
|
|
5779
|
+
const flattenedCycleTime = parseFiniteNumber(metadata?.cycle_time);
|
|
5780
|
+
if (flattenedCycleTime !== void 0) {
|
|
5781
|
+
return flattenedCycleTime;
|
|
5782
|
+
}
|
|
5783
|
+
return parseFiniteNumber(metadata?.request?.metadata?.cycle_time);
|
|
5784
|
+
};
|
|
5564
5785
|
var getSupabaseClient = () => {
|
|
5565
5786
|
const existing = _getSupabaseInstanceOptional();
|
|
5566
5787
|
if (existing) {
|
|
@@ -6070,20 +6291,31 @@ var S3ClipsSupabaseService = class {
|
|
|
6070
6291
|
limit
|
|
6071
6292
|
});
|
|
6072
6293
|
console.log(`[S3ClipsSupabase] Fetched ${response.clips?.length || 0} ${type} clips`);
|
|
6073
|
-
const transformedClips = (response.clips || []).map((clip) =>
|
|
6074
|
-
id
|
|
6075
|
-
|
|
6076
|
-
|
|
6077
|
-
|
|
6078
|
-
|
|
6079
|
-
|
|
6080
|
-
|
|
6081
|
-
|
|
6082
|
-
|
|
6083
|
-
|
|
6084
|
-
|
|
6085
|
-
|
|
6086
|
-
|
|
6294
|
+
const transformedClips = (response.clips || []).map((clip) => {
|
|
6295
|
+
const clipId = clip.id ?? clip.clip_id;
|
|
6296
|
+
const clipType = clip.type ?? clip.clip_type_name;
|
|
6297
|
+
const cycleTimeSeconds = parseFiniteNumber(clip.cycle_time_seconds) ?? (() => {
|
|
6298
|
+
const cycleTimeFrames = getClipCycleTimeFrames(clip.metadata);
|
|
6299
|
+
return cycleTimeFrames !== void 0 ? cycleTimeFrames / (clip.metadata?.playlist?.fps || 20) : void 0;
|
|
6300
|
+
})();
|
|
6301
|
+
return {
|
|
6302
|
+
id: clipId,
|
|
6303
|
+
src: clip.src ?? clip.playlist,
|
|
6304
|
+
// Current API returns src; keep playlist fallback for legacy responses
|
|
6305
|
+
timestamp: clip.timestamp,
|
|
6306
|
+
// Use pre-formatted timestamp from API (already in 12-hour format with seconds)
|
|
6307
|
+
severity: clip.severity ?? this.getSeverityFromClipType(clipType),
|
|
6308
|
+
description: clip.description ?? this.getDescriptionFromClipType(clipType),
|
|
6309
|
+
type: clipType,
|
|
6310
|
+
originalUri: clip.originalUri ?? `clips:${clipId}`,
|
|
6311
|
+
cycle_time_seconds: cycleTimeSeconds,
|
|
6312
|
+
creation_timestamp: clip.creation_timestamp ?? clip.created_at,
|
|
6313
|
+
percentile: clip.percentile ?? clip.cycle_time_percentile ?? clip.idle_time_percentile,
|
|
6314
|
+
duration: clip.duration,
|
|
6315
|
+
idle_start_time: clip.idle_start_time,
|
|
6316
|
+
idle_end_time: clip.idle_end_time
|
|
6317
|
+
};
|
|
6318
|
+
});
|
|
6087
6319
|
return {
|
|
6088
6320
|
clips: transformedClips,
|
|
6089
6321
|
total: response.total || transformedClips.length,
|
|
@@ -6113,10 +6345,13 @@ var S3ClipsSupabaseService = class {
|
|
|
6113
6345
|
*/
|
|
6114
6346
|
getSeverityFromClipType(clipType) {
|
|
6115
6347
|
switch (clipType) {
|
|
6348
|
+
case "long_cycle_time":
|
|
6349
|
+
case "worst_cycle_time":
|
|
6116
6350
|
case "sop_deviations":
|
|
6117
6351
|
return "high";
|
|
6118
6352
|
case "idle_time":
|
|
6119
6353
|
return "medium";
|
|
6354
|
+
case "best_cycle_time":
|
|
6120
6355
|
case "cycle_completion":
|
|
6121
6356
|
default:
|
|
6122
6357
|
return "low";
|
|
@@ -6128,11 +6363,14 @@ var S3ClipsSupabaseService = class {
|
|
|
6128
6363
|
*/
|
|
6129
6364
|
getDescriptionFromClipType(clipType) {
|
|
6130
6365
|
const descriptions = {
|
|
6366
|
+
"long_cycle_time": "Long Cycle Time Detected",
|
|
6131
6367
|
"idle_time": "Idle Time Detected",
|
|
6368
|
+
"best_cycle_time": "Best Cycle Time Performance",
|
|
6369
|
+
"worst_cycle_time": "Worst Cycle Time Performance",
|
|
6132
6370
|
"sop_deviations": "SOP Deviations",
|
|
6133
6371
|
"cycle_completion": "Cycle Completion"
|
|
6134
6372
|
};
|
|
6135
|
-
return descriptions[clipType] || "Analysis Clip";
|
|
6373
|
+
return clipType ? descriptions[clipType] || "Analysis Clip" : "Analysis Clip";
|
|
6136
6374
|
}
|
|
6137
6375
|
};
|
|
6138
6376
|
|
|
@@ -6895,6 +7133,9 @@ var InvitationService = class {
|
|
|
6895
7133
|
if (existingUser) {
|
|
6896
7134
|
throw new Error("A user with this email address already exists in the system.");
|
|
6897
7135
|
}
|
|
7136
|
+
if (input.role_level === "industrial_engineer" && (!input.factory_ids || input.factory_ids.length === 0)) {
|
|
7137
|
+
throw new Error("Industrial Engineer invitations require at least one factory assignment.");
|
|
7138
|
+
}
|
|
6898
7139
|
const invitationData = {
|
|
6899
7140
|
email: input.email.toLowerCase().trim(),
|
|
6900
7141
|
company_id: input.company_id,
|
|
@@ -6905,7 +7146,7 @@ var InvitationService = class {
|
|
|
6905
7146
|
if (input.role_level === "supervisor" && input.line_ids && input.line_ids.length > 0) {
|
|
6906
7147
|
invitationData.line_ids = input.line_ids;
|
|
6907
7148
|
}
|
|
6908
|
-
if (input.role_level === "plant_head" && input.factory_ids && input.factory_ids.length > 0) {
|
|
7149
|
+
if ((input.role_level === "plant_head" || input.role_level === "industrial_engineer") && input.factory_ids && input.factory_ids.length > 0) {
|
|
6909
7150
|
invitationData.factory_ids = input.factory_ids;
|
|
6910
7151
|
}
|
|
6911
7152
|
console.log("[InvitationService] Final invitationData being inserted:", invitationData);
|
|
@@ -7615,6 +7856,8 @@ async function fetchIdleTimeReasons(params) {
|
|
|
7615
7856
|
data: {
|
|
7616
7857
|
total_idle_time_seconds: 0,
|
|
7617
7858
|
total_clips_analyzed: 0,
|
|
7859
|
+
scope_work_seconds: null,
|
|
7860
|
+
scope_workspace_count: 0,
|
|
7618
7861
|
reasons: []
|
|
7619
7862
|
},
|
|
7620
7863
|
error: "Request failed"
|
|
@@ -7632,6 +7875,8 @@ async function fetchIdleTimeReasons(params) {
|
|
|
7632
7875
|
return {
|
|
7633
7876
|
total_idle_time_seconds: 0,
|
|
7634
7877
|
total_clips_analyzed: 0,
|
|
7878
|
+
scope_work_seconds: null,
|
|
7879
|
+
scope_workspace_count: 0,
|
|
7635
7880
|
reasons: []
|
|
7636
7881
|
};
|
|
7637
7882
|
}
|
|
@@ -7639,7 +7884,9 @@ async function fetchIdleTimeReasons(params) {
|
|
|
7639
7884
|
function transformToChartData(data) {
|
|
7640
7885
|
return data.reasons.map((reason) => ({
|
|
7641
7886
|
name: formatReasonLabel(reason.reason),
|
|
7642
|
-
value: reason.percentage
|
|
7887
|
+
value: reason.percentage,
|
|
7888
|
+
totalDurationSeconds: reason.total_duration_seconds,
|
|
7889
|
+
efficiencyLossPercentage: reason.efficiency_loss_percentage ?? null
|
|
7643
7890
|
}));
|
|
7644
7891
|
}
|
|
7645
7892
|
function formatReasonLabel(reason) {
|
|
@@ -8047,6 +8294,18 @@ var lineLeaderboardService = {
|
|
|
8047
8294
|
return data?.entries ?? [];
|
|
8048
8295
|
}
|
|
8049
8296
|
};
|
|
8297
|
+
|
|
8298
|
+
// src/lib/services/alertsService.ts
|
|
8299
|
+
var alertsService = {
|
|
8300
|
+
async getCurrentAlerts(supabase, companyId) {
|
|
8301
|
+
const query = `?company_id=${encodeURIComponent(companyId)}`;
|
|
8302
|
+
return fetchBackendJson(supabase, `/api/alerts/current${query}`);
|
|
8303
|
+
},
|
|
8304
|
+
async getSummary(supabase, companyId) {
|
|
8305
|
+
const query = `?company_id=${encodeURIComponent(companyId)}`;
|
|
8306
|
+
return fetchBackendJson(supabase, `/api/alerts/summary${query}`);
|
|
8307
|
+
}
|
|
8308
|
+
};
|
|
8050
8309
|
var SupabaseContext = createContext(void 0);
|
|
8051
8310
|
var SupabaseProvider = ({ client, children }) => {
|
|
8052
8311
|
_setSupabaseInstance(client);
|
|
@@ -8822,7 +9081,7 @@ var useMobileMenu = () => {
|
|
|
8822
9081
|
};
|
|
8823
9082
|
var useHideMobileHeader = (shouldHide = true) => {
|
|
8824
9083
|
const context = useMobileMenu();
|
|
8825
|
-
|
|
9084
|
+
React141__default.useEffect(() => {
|
|
8826
9085
|
if (context && shouldHide) {
|
|
8827
9086
|
context.setHideMobileHeader(true);
|
|
8828
9087
|
return () => {
|
|
@@ -14825,10 +15084,7 @@ var useSKUs = (companyId) => {
|
|
|
14825
15084
|
// src/lib/hooks/useCanSaveTargets.ts
|
|
14826
15085
|
var useCanSaveTargets = () => {
|
|
14827
15086
|
const { user } = useAuth();
|
|
14828
|
-
|
|
14829
|
-
return true;
|
|
14830
|
-
}
|
|
14831
|
-
return user?.role_level === "owner" || user?.role_level === "plant_head";
|
|
15087
|
+
return canRoleManageTargets(user?.role_level);
|
|
14832
15088
|
};
|
|
14833
15089
|
function useTicketHistory(companyId) {
|
|
14834
15090
|
const [tickets, setTickets] = useState([]);
|
|
@@ -16130,12 +16386,7 @@ var useFormatNumber = () => {
|
|
|
16130
16386
|
function useAccessControl() {
|
|
16131
16387
|
const { user } = useAuth();
|
|
16132
16388
|
const userRole = useMemo(() => {
|
|
16133
|
-
|
|
16134
|
-
const roleLevel = user.role_level;
|
|
16135
|
-
if (roleLevel === "owner" || roleLevel === "it" || roleLevel === "plant_head" || roleLevel === "supervisor" || roleLevel === "optifye") {
|
|
16136
|
-
return roleLevel;
|
|
16137
|
-
}
|
|
16138
|
-
return "supervisor";
|
|
16389
|
+
return normalizeRoleLevel(user?.role_level) || null;
|
|
16139
16390
|
}, [user?.role_level]);
|
|
16140
16391
|
const assignedLineIds = useMemo(() => {
|
|
16141
16392
|
if (!user) return [];
|
|
@@ -16147,89 +16398,15 @@ function useAccessControl() {
|
|
|
16147
16398
|
}, [user]);
|
|
16148
16399
|
const assignedFactoryIds = useMemo(() => {
|
|
16149
16400
|
if (!user) return [];
|
|
16150
|
-
if (user.role_level
|
|
16401
|
+
if (isFactoryScopedRole(user.role_level)) {
|
|
16151
16402
|
const factories = user.properties?.factory_id || user.properties?.factory_ids || [];
|
|
16152
16403
|
return Array.isArray(factories) ? factories : [];
|
|
16153
16404
|
}
|
|
16154
16405
|
return [];
|
|
16155
16406
|
}, [user]);
|
|
16156
|
-
const roleAccessMap = {
|
|
16157
|
-
optifye: [
|
|
16158
|
-
"/",
|
|
16159
|
-
"/leaderboard",
|
|
16160
|
-
"/kpis",
|
|
16161
|
-
"/targets",
|
|
16162
|
-
"/shifts",
|
|
16163
|
-
"/supervisor-management",
|
|
16164
|
-
"/skus",
|
|
16165
|
-
"/help",
|
|
16166
|
-
"/health",
|
|
16167
|
-
"/profile",
|
|
16168
|
-
"/workspace",
|
|
16169
|
-
"/factory-view",
|
|
16170
|
-
"/team-management"
|
|
16171
|
-
],
|
|
16172
|
-
owner: [
|
|
16173
|
-
"/",
|
|
16174
|
-
"/leaderboard",
|
|
16175
|
-
"/kpis",
|
|
16176
|
-
"/targets",
|
|
16177
|
-
"/shifts",
|
|
16178
|
-
"/supervisor-management",
|
|
16179
|
-
"/skus",
|
|
16180
|
-
"/help",
|
|
16181
|
-
"/health",
|
|
16182
|
-
"/profile",
|
|
16183
|
-
"/workspace",
|
|
16184
|
-
"/factory-view",
|
|
16185
|
-
"/team-management"
|
|
16186
|
-
],
|
|
16187
|
-
it: [
|
|
16188
|
-
"/",
|
|
16189
|
-
"/leaderboard",
|
|
16190
|
-
"/kpis",
|
|
16191
|
-
"/targets",
|
|
16192
|
-
"/shifts",
|
|
16193
|
-
"/supervisor-management",
|
|
16194
|
-
"/skus",
|
|
16195
|
-
"/help",
|
|
16196
|
-
"/health",
|
|
16197
|
-
"/profile",
|
|
16198
|
-
"/workspace",
|
|
16199
|
-
"/factory-view",
|
|
16200
|
-
"/team-management"
|
|
16201
|
-
],
|
|
16202
|
-
plant_head: [
|
|
16203
|
-
"/",
|
|
16204
|
-
"/leaderboard",
|
|
16205
|
-
"/kpis",
|
|
16206
|
-
"/targets",
|
|
16207
|
-
"/shifts",
|
|
16208
|
-
"/supervisor-management",
|
|
16209
|
-
"/skus",
|
|
16210
|
-
"/help",
|
|
16211
|
-
"/health",
|
|
16212
|
-
"/profile",
|
|
16213
|
-
"/workspace",
|
|
16214
|
-
"/factory-view",
|
|
16215
|
-
"/team-management"
|
|
16216
|
-
],
|
|
16217
|
-
supervisor: [
|
|
16218
|
-
"/",
|
|
16219
|
-
"/leaderboard",
|
|
16220
|
-
"/kpis",
|
|
16221
|
-
"/targets",
|
|
16222
|
-
"/shifts",
|
|
16223
|
-
"/skus",
|
|
16224
|
-
"/help",
|
|
16225
|
-
"/health",
|
|
16226
|
-
"/profile",
|
|
16227
|
-
"/workspace"
|
|
16228
|
-
]
|
|
16229
|
-
};
|
|
16230
16407
|
const accessiblePages = useMemo(() => {
|
|
16231
16408
|
if (!userRole) return [];
|
|
16232
|
-
return
|
|
16409
|
+
return getRoleNavPaths(userRole);
|
|
16233
16410
|
}, [userRole]);
|
|
16234
16411
|
const hasAccess = useMemo(() => {
|
|
16235
16412
|
return (path) => {
|
|
@@ -16279,111 +16456,50 @@ function useTeamManagementPermissions() {
|
|
|
16279
16456
|
* Can the current user assign lines to this user?
|
|
16280
16457
|
*/
|
|
16281
16458
|
canAssignLines: (targetUser) => {
|
|
16282
|
-
|
|
16283
|
-
if (currentRole === "optifye") return true;
|
|
16284
|
-
if ((currentRole === "owner" || currentRole === "it") && targetUser.role_level === "supervisor") {
|
|
16285
|
-
return true;
|
|
16286
|
-
}
|
|
16287
|
-
if (currentRole === "plant_head" && targetUser.role_level === "supervisor") {
|
|
16288
|
-
return true;
|
|
16289
|
-
}
|
|
16290
|
-
return false;
|
|
16459
|
+
return canRoleAssignLines(currentRole, targetUser.role_level);
|
|
16291
16460
|
},
|
|
16292
16461
|
/**
|
|
16293
16462
|
* Can the current user assign factories to this user?
|
|
16294
16463
|
*/
|
|
16295
16464
|
canAssignFactories: (targetUser) => {
|
|
16296
|
-
|
|
16297
|
-
if (currentRole === "optifye") return true;
|
|
16298
|
-
if ((currentRole === "owner" || currentRole === "it") && targetUser.role_level === "plant_head") {
|
|
16299
|
-
return true;
|
|
16300
|
-
}
|
|
16301
|
-
return false;
|
|
16465
|
+
return canRoleAssignFactories(currentRole, targetUser.role_level);
|
|
16302
16466
|
},
|
|
16303
16467
|
/**
|
|
16304
16468
|
* Can the current user change this user's role?
|
|
16305
16469
|
*/
|
|
16306
16470
|
canChangeRole: (targetUser) => {
|
|
16307
|
-
|
|
16308
|
-
if (currentRole === "optifye") return true;
|
|
16309
|
-
if (currentRole === "owner" || currentRole === "it") {
|
|
16310
|
-
return ["plant_head", "supervisor"].includes(targetUser.role_level);
|
|
16311
|
-
}
|
|
16312
|
-
return false;
|
|
16471
|
+
return canRoleChangeRole(currentRole, targetUser.role_level, { isSuperAdminOptifye });
|
|
16313
16472
|
},
|
|
16314
16473
|
/**
|
|
16315
16474
|
* Can the current user remove this user?
|
|
16316
16475
|
*/
|
|
16317
16476
|
canRemoveUser: (targetUser) => {
|
|
16318
|
-
|
|
16319
|
-
if (currentRole === "optifye") return true;
|
|
16320
|
-
if (currentRole === "owner" || currentRole === "it") {
|
|
16321
|
-
return ["plant_head", "supervisor"].includes(targetUser.role_level);
|
|
16322
|
-
}
|
|
16323
|
-
return false;
|
|
16477
|
+
return canRoleRemoveUser(currentRole, targetUser.role_level, { isSuperAdminOptifye });
|
|
16324
16478
|
},
|
|
16325
16479
|
/**
|
|
16326
16480
|
* Get list of roles the current user can assign
|
|
16327
16481
|
* NOTE: Optifye role can ONLY be assigned from database directly, never from frontend
|
|
16328
16482
|
*/
|
|
16329
16483
|
availableRolesToAssign: () => {
|
|
16330
|
-
|
|
16331
|
-
if (currentRole === "optifye") {
|
|
16332
|
-
if (isSuperAdminOptifye) {
|
|
16333
|
-
return ["owner", "it", "plant_head", "supervisor"];
|
|
16334
|
-
}
|
|
16335
|
-
return ["it", "plant_head", "supervisor"];
|
|
16336
|
-
}
|
|
16337
|
-
if (currentRole === "owner") {
|
|
16338
|
-
return ["it", "plant_head", "supervisor"];
|
|
16339
|
-
}
|
|
16340
|
-
if (currentRole === "it") {
|
|
16341
|
-
return ["plant_head", "supervisor"];
|
|
16342
|
-
}
|
|
16343
|
-
if (currentRole === "plant_head") {
|
|
16344
|
-
return ["supervisor"];
|
|
16345
|
-
}
|
|
16346
|
-
return [];
|
|
16484
|
+
return getAssignableRoles(currentRole, { isSuperAdminOptifye });
|
|
16347
16485
|
},
|
|
16348
16486
|
/**
|
|
16349
16487
|
* Can the current user invite someone with this role?
|
|
16350
16488
|
*/
|
|
16351
16489
|
canInviteRole: (role) => {
|
|
16352
|
-
|
|
16353
|
-
if (currentRole === "optifye") {
|
|
16354
|
-
if (role === "owner") {
|
|
16355
|
-
return isSuperAdminOptifye;
|
|
16356
|
-
}
|
|
16357
|
-
return true;
|
|
16358
|
-
}
|
|
16359
|
-
if (currentRole === "owner") {
|
|
16360
|
-
return ["it", "plant_head", "supervisor"].includes(role);
|
|
16361
|
-
}
|
|
16362
|
-
if (currentRole === "it") {
|
|
16363
|
-
return ["plant_head", "supervisor"].includes(role);
|
|
16364
|
-
}
|
|
16365
|
-
if (currentRole === "plant_head") {
|
|
16366
|
-
return role === "supervisor";
|
|
16367
|
-
}
|
|
16368
|
-
return false;
|
|
16490
|
+
return canRoleInviteRole(currentRole, role, { isSuperAdminOptifye });
|
|
16369
16491
|
},
|
|
16370
16492
|
/**
|
|
16371
16493
|
* Get the name of the assignment column for a user
|
|
16372
16494
|
*/
|
|
16373
16495
|
getAssignmentColumnName: (targetUser) => {
|
|
16374
|
-
|
|
16375
|
-
return "Factories";
|
|
16376
|
-
}
|
|
16377
|
-
if (targetUser.role_level === "supervisor") {
|
|
16378
|
-
return "Lines";
|
|
16379
|
-
}
|
|
16380
|
-
return "Assignments";
|
|
16496
|
+
return getAssignmentColumnLabel(targetUser.role_level);
|
|
16381
16497
|
},
|
|
16382
16498
|
/**
|
|
16383
16499
|
* Should the assignment column be shown?
|
|
16384
16500
|
*/
|
|
16385
16501
|
showAssignmentColumn: () => {
|
|
16386
|
-
return !!currentRole &&
|
|
16502
|
+
return !!currentRole && (currentRole === "optifye" || currentRole === "owner" || currentRole === "it" || isFactoryScopedRole(currentRole));
|
|
16387
16503
|
}
|
|
16388
16504
|
};
|
|
16389
16505
|
}
|
|
@@ -20238,7 +20354,7 @@ var getStoredWorkspaceMappings = () => {
|
|
|
20238
20354
|
var getDefaultTabForWorkspace = (workspaceId, displayName) => {
|
|
20239
20355
|
return "overview";
|
|
20240
20356
|
};
|
|
20241
|
-
var getWorkspaceNavigationParams = (workspaceId, displayName, lineId) => {
|
|
20357
|
+
var getWorkspaceNavigationParams = (workspaceId, displayName, lineId, returnTo) => {
|
|
20242
20358
|
const defaultTab = getDefaultTabForWorkspace();
|
|
20243
20359
|
const params = new URLSearchParams();
|
|
20244
20360
|
params.set("displayName", displayName);
|
|
@@ -20246,6 +20362,9 @@ var getWorkspaceNavigationParams = (workspaceId, displayName, lineId) => {
|
|
|
20246
20362
|
if (lineId) {
|
|
20247
20363
|
params.set("lineId", lineId);
|
|
20248
20364
|
}
|
|
20365
|
+
if (returnTo) {
|
|
20366
|
+
params.set("returnTo", returnTo);
|
|
20367
|
+
}
|
|
20249
20368
|
return `?${params.toString()}`;
|
|
20250
20369
|
};
|
|
20251
20370
|
|
|
@@ -20541,14 +20660,18 @@ var formatIdleTime = (idleTimeInSeconds) => {
|
|
|
20541
20660
|
if (!idleTimeInSeconds || idleTimeInSeconds <= 0) {
|
|
20542
20661
|
return "0s";
|
|
20543
20662
|
}
|
|
20544
|
-
const
|
|
20663
|
+
const days = Math.floor(idleTimeInSeconds / 86400);
|
|
20664
|
+
const hours = Math.floor(idleTimeInSeconds % 86400 / 3600);
|
|
20545
20665
|
const minutes = Math.floor(idleTimeInSeconds % 3600 / 60);
|
|
20546
20666
|
const seconds = Math.floor(idleTimeInSeconds % 60);
|
|
20547
20667
|
const parts = [];
|
|
20668
|
+
if (days > 0) {
|
|
20669
|
+
parts.push(`${days}d`);
|
|
20670
|
+
}
|
|
20548
20671
|
if (hours > 0) {
|
|
20549
20672
|
parts.push(`${hours}h`);
|
|
20550
20673
|
}
|
|
20551
|
-
if (minutes > 0 || hours > 0) {
|
|
20674
|
+
if (minutes > 0 || hours > 0 || days > 0) {
|
|
20552
20675
|
parts.push(`${minutes}m`);
|
|
20553
20676
|
}
|
|
20554
20677
|
parts.push(`${seconds}s`);
|
|
@@ -20595,7 +20718,7 @@ var MotionConfigContext = createContext({
|
|
|
20595
20718
|
});
|
|
20596
20719
|
|
|
20597
20720
|
// ../../node_modules/framer-motion/dist/es/components/AnimatePresence/PopChild.mjs
|
|
20598
|
-
var PopChildMeasure = class extends
|
|
20721
|
+
var PopChildMeasure = class extends React141.Component {
|
|
20599
20722
|
getSnapshotBeforeUpdate(prevProps) {
|
|
20600
20723
|
const element = this.props.childRef.current;
|
|
20601
20724
|
if (element && prevProps.isPresent && !this.props.isPresent) {
|
|
@@ -20650,7 +20773,7 @@ function PopChild({ children, isPresent }) {
|
|
|
20650
20773
|
document.head.removeChild(style);
|
|
20651
20774
|
};
|
|
20652
20775
|
}, [isPresent]);
|
|
20653
|
-
return jsx(PopChildMeasure, { isPresent, childRef: ref, sizeRef: size, children:
|
|
20776
|
+
return jsx(PopChildMeasure, { isPresent, childRef: ref, sizeRef: size, children: React141.cloneElement(children, { ref }) });
|
|
20654
20777
|
}
|
|
20655
20778
|
|
|
20656
20779
|
// ../../node_modules/framer-motion/dist/es/components/AnimatePresence/PresenceChild.mjs
|
|
@@ -20687,7 +20810,7 @@ var PresenceChild = ({ children, initial, isPresent, onExitComplete, custom, pre
|
|
|
20687
20810
|
useMemo(() => {
|
|
20688
20811
|
presenceChildren.forEach((_, key) => presenceChildren.set(key, false));
|
|
20689
20812
|
}, [isPresent]);
|
|
20690
|
-
|
|
20813
|
+
React141.useEffect(() => {
|
|
20691
20814
|
!isPresent && !presenceChildren.size && onExitComplete && onExitComplete();
|
|
20692
20815
|
}, [isPresent]);
|
|
20693
20816
|
if (mode === "popLayout") {
|
|
@@ -28521,12 +28644,12 @@ var withAuth = (WrappedComponent2, options) => {
|
|
|
28521
28644
|
requireAuth: true,
|
|
28522
28645
|
...options
|
|
28523
28646
|
};
|
|
28524
|
-
const WithAuthComponent =
|
|
28647
|
+
const WithAuthComponent = React141.memo(function WithAuthComponent2(props) {
|
|
28525
28648
|
const { session, loading, error } = useAuth();
|
|
28526
28649
|
const router = useRouter();
|
|
28527
|
-
const [localLoading, setLocalLoading] =
|
|
28528
|
-
const [loadingTimeoutReached, setLoadingTimeoutReached] =
|
|
28529
|
-
|
|
28650
|
+
const [localLoading, setLocalLoading] = React141.useState(loading);
|
|
28651
|
+
const [loadingTimeoutReached, setLoadingTimeoutReached] = React141.useState(false);
|
|
28652
|
+
React141.useEffect(() => {
|
|
28530
28653
|
if (process.env.NODE_ENV === "development" && process.env.DEBUG_AUTH === "true") {
|
|
28531
28654
|
console.log("withAuth state:", {
|
|
28532
28655
|
loading,
|
|
@@ -28536,7 +28659,7 @@ var withAuth = (WrappedComponent2, options) => {
|
|
|
28536
28659
|
});
|
|
28537
28660
|
}
|
|
28538
28661
|
}, [session, loading, error]);
|
|
28539
|
-
const handleLoadingTimeout =
|
|
28662
|
+
const handleLoadingTimeout = React141.useCallback(() => {
|
|
28540
28663
|
console.warn("[withAuth] Loading timeout reached");
|
|
28541
28664
|
setLoadingTimeoutReached(true);
|
|
28542
28665
|
if (typeof window !== "undefined" && localStorage.getItem("sb-zmzewpwerpaupoaoeqhh-auth-token")) {
|
|
@@ -28547,13 +28670,13 @@ var withAuth = (WrappedComponent2, options) => {
|
|
|
28547
28670
|
router.replace(defaultOptions.redirectTo);
|
|
28548
28671
|
}
|
|
28549
28672
|
}, [router]);
|
|
28550
|
-
|
|
28673
|
+
React141.useEffect(() => {
|
|
28551
28674
|
if (!loading && defaultOptions.requireAuth && !session && !error) {
|
|
28552
28675
|
console.log("[withAuth] No session found, redirecting to login");
|
|
28553
28676
|
router.replace(defaultOptions.redirectTo);
|
|
28554
28677
|
}
|
|
28555
28678
|
}, [session, loading, router, error]);
|
|
28556
|
-
|
|
28679
|
+
React141.useEffect(() => {
|
|
28557
28680
|
setLocalLoading(loading);
|
|
28558
28681
|
}, [loading]);
|
|
28559
28682
|
if (loading || localLoading) {
|
|
@@ -28616,18 +28739,11 @@ function withAccessControl(WrappedComponent2, options = {}) {
|
|
|
28616
28739
|
if (keyIndex >= 0 && keyIndex < segments.length - 1) return segments[keyIndex + 1];
|
|
28617
28740
|
return null;
|
|
28618
28741
|
};
|
|
28619
|
-
const roleAccessMap = {
|
|
28620
|
-
optifye: ["/", "/leaderboard", "/kpis", "/targets", "/shifts", "/supervisor-management", "/skus", "/help", "/health", "/profile", "/workspace", "/factory-view", "/team-management", "/improvement-center", "/tickets"],
|
|
28621
|
-
owner: ["/", "/leaderboard", "/kpis", "/targets", "/shifts", "/supervisor-management", "/skus", "/help", "/health", "/profile", "/workspace", "/factory-view", "/team-management", "/improvement-center", "/tickets"],
|
|
28622
|
-
it: ["/", "/leaderboard", "/kpis", "/targets", "/shifts", "/supervisor-management", "/skus", "/help", "/health", "/profile", "/workspace", "/factory-view", "/team-management", "/improvement-center", "/tickets"],
|
|
28623
|
-
plant_head: ["/", "/leaderboard", "/kpis", "/targets", "/shifts", "/supervisor-management", "/skus", "/help", "/health", "/profile", "/workspace", "/factory-view", "/team-management", "/improvement-center", "/tickets"],
|
|
28624
|
-
supervisor: ["/", "/leaderboard", "/kpis", "/targets", "/shifts", "/skus", "/help", "/health", "/profile", "/workspace", "/improvement-center", "/tickets"]
|
|
28625
|
-
};
|
|
28626
28742
|
const canAccessPath = (path) => {
|
|
28627
28743
|
if (!user || !role) return false;
|
|
28628
28744
|
if (isSuperAdmin) return true;
|
|
28629
28745
|
const basePath = getBasePath(path);
|
|
28630
|
-
const allowed =
|
|
28746
|
+
const allowed = getRoleNavPaths(role);
|
|
28631
28747
|
if (!allowed.includes(basePath)) {
|
|
28632
28748
|
return false;
|
|
28633
28749
|
}
|
|
@@ -29028,8 +29144,8 @@ function getRoleConfig(role) {
|
|
|
29028
29144
|
switch (role) {
|
|
29029
29145
|
case "optifye":
|
|
29030
29146
|
return {
|
|
29031
|
-
label:
|
|
29032
|
-
description:
|
|
29147
|
+
label: getRoleLabel(role),
|
|
29148
|
+
description: getRoleDescription(role),
|
|
29033
29149
|
icon: Star,
|
|
29034
29150
|
bgColor: "bg-gradient-to-r from-purple-50 to-pink-50",
|
|
29035
29151
|
textColor: "text-purple-700",
|
|
@@ -29037,8 +29153,8 @@ function getRoleConfig(role) {
|
|
|
29037
29153
|
};
|
|
29038
29154
|
case "owner":
|
|
29039
29155
|
return {
|
|
29040
|
-
label:
|
|
29041
|
-
description:
|
|
29156
|
+
label: getRoleLabel(role),
|
|
29157
|
+
description: getRoleDescription(role),
|
|
29042
29158
|
icon: Shield,
|
|
29043
29159
|
bgColor: "bg-blue-50",
|
|
29044
29160
|
textColor: "text-blue-700",
|
|
@@ -29046,8 +29162,8 @@ function getRoleConfig(role) {
|
|
|
29046
29162
|
};
|
|
29047
29163
|
case "it":
|
|
29048
29164
|
return {
|
|
29049
|
-
label:
|
|
29050
|
-
description:
|
|
29165
|
+
label: getRoleLabel(role),
|
|
29166
|
+
description: getRoleDescription(role),
|
|
29051
29167
|
icon: Wrench,
|
|
29052
29168
|
bgColor: "bg-teal-50",
|
|
29053
29169
|
textColor: "text-teal-700",
|
|
@@ -29055,17 +29171,26 @@ function getRoleConfig(role) {
|
|
|
29055
29171
|
};
|
|
29056
29172
|
case "plant_head":
|
|
29057
29173
|
return {
|
|
29058
|
-
label:
|
|
29059
|
-
description:
|
|
29174
|
+
label: getRoleLabel(role),
|
|
29175
|
+
description: getRoleDescription(role),
|
|
29060
29176
|
icon: Users,
|
|
29061
29177
|
bgColor: "bg-blue-50",
|
|
29062
29178
|
textColor: "text-blue-700",
|
|
29063
29179
|
borderColor: "border-blue-200"
|
|
29064
29180
|
};
|
|
29181
|
+
case "industrial_engineer":
|
|
29182
|
+
return {
|
|
29183
|
+
label: getRoleLabel(role),
|
|
29184
|
+
description: getRoleDescription(role),
|
|
29185
|
+
icon: Users,
|
|
29186
|
+
bgColor: "bg-amber-50",
|
|
29187
|
+
textColor: "text-amber-700",
|
|
29188
|
+
borderColor: "border-amber-200"
|
|
29189
|
+
};
|
|
29065
29190
|
case "supervisor":
|
|
29066
29191
|
return {
|
|
29067
|
-
label:
|
|
29068
|
-
description:
|
|
29192
|
+
label: getRoleLabel(role),
|
|
29193
|
+
description: getRoleDescription(role),
|
|
29069
29194
|
icon: User,
|
|
29070
29195
|
bgColor: "bg-blue-50",
|
|
29071
29196
|
textColor: "text-blue-700",
|
|
@@ -29173,7 +29298,7 @@ var SignupWithInvitation = ({
|
|
|
29173
29298
|
if (invitation.line_ids && invitation.line_ids.length > 0) {
|
|
29174
29299
|
properties.line_id = invitation.line_ids;
|
|
29175
29300
|
}
|
|
29176
|
-
} else if (invitation.role_level === "plant_head") {
|
|
29301
|
+
} else if (invitation.role_level === "plant_head" || invitation.role_level === "industrial_engineer") {
|
|
29177
29302
|
properties.access_level = "factory";
|
|
29178
29303
|
if (invitation.factory_ids && invitation.factory_ids.length > 0) {
|
|
29179
29304
|
properties.factory_ids = invitation.factory_ids;
|
|
@@ -29264,7 +29389,7 @@ var SignupWithInvitation = ({
|
|
|
29264
29389
|
] })
|
|
29265
29390
|
] })
|
|
29266
29391
|
] }),
|
|
29267
|
-
invitation.role_level === "plant_head" && invitation.factory_ids && invitation.factory_ids.length > 0 && /* @__PURE__ */ jsxs("div", { className: "md:col-span-2", children: [
|
|
29392
|
+
(invitation.role_level === "plant_head" || invitation.role_level === "industrial_engineer") && invitation.factory_ids && invitation.factory_ids.length > 0 && /* @__PURE__ */ jsxs("div", { className: "md:col-span-2", children: [
|
|
29268
29393
|
/* @__PURE__ */ jsx("p", { className: "text-sm text-gray-600 mb-1", children: "Assigned Factories" }),
|
|
29269
29394
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
29270
29395
|
/* @__PURE__ */ jsx(Building2, { className: "w-4 h-4 text-indigo-600" }),
|
|
@@ -29486,11 +29611,11 @@ var BarChartComponent = ({
|
|
|
29486
29611
|
aspect = 2,
|
|
29487
29612
|
...restOfChartProps
|
|
29488
29613
|
}) => {
|
|
29489
|
-
const containerRef =
|
|
29490
|
-
const [containerReady, setContainerReady] =
|
|
29614
|
+
const containerRef = React141__default.useRef(null);
|
|
29615
|
+
const [containerReady, setContainerReady] = React141__default.useState(false);
|
|
29491
29616
|
const themeConfig = useThemeConfig();
|
|
29492
29617
|
const { formatNumber } = useFormatNumber();
|
|
29493
|
-
|
|
29618
|
+
React141__default.useEffect(() => {
|
|
29494
29619
|
const checkContainerDimensions = () => {
|
|
29495
29620
|
if (containerRef.current) {
|
|
29496
29621
|
const rect = containerRef.current.getBoundingClientRect();
|
|
@@ -29604,7 +29729,7 @@ var BarChartComponent = ({
|
|
|
29604
29729
|
}
|
|
29605
29730
|
return /* @__PURE__ */ jsx("div", { className: clsx("w-full", className), children: chartContent });
|
|
29606
29731
|
};
|
|
29607
|
-
var BarChart =
|
|
29732
|
+
var BarChart = React141__default.memo(BarChartComponent, (prevProps, nextProps) => {
|
|
29608
29733
|
if (prevProps.xAxisDataKey !== nextProps.xAxisDataKey || prevProps.xAxisLabel !== nextProps.xAxisLabel || prevProps.yAxisLabel !== nextProps.yAxisLabel || prevProps.yAxisUnit !== nextProps.yAxisUnit || JSON.stringify(prevProps.referenceLines || []) !== JSON.stringify(nextProps.referenceLines || []) || prevProps.layout !== nextProps.layout || prevProps.className !== nextProps.className || prevProps.showGrid !== nextProps.showGrid || prevProps.showLegend !== nextProps.showLegend || prevProps.showTooltip !== nextProps.showTooltip || prevProps.responsive !== nextProps.responsive || prevProps.aspect !== nextProps.aspect) {
|
|
29609
29734
|
return false;
|
|
29610
29735
|
}
|
|
@@ -29650,13 +29775,14 @@ var LineChartComponent = ({
|
|
|
29650
29775
|
showTooltip = true,
|
|
29651
29776
|
responsive = true,
|
|
29652
29777
|
aspect = 2,
|
|
29778
|
+
fillContainer = false,
|
|
29653
29779
|
...restOfChartProps
|
|
29654
29780
|
}) => {
|
|
29655
|
-
const containerRef =
|
|
29656
|
-
const [containerReady, setContainerReady] =
|
|
29781
|
+
const containerRef = React141__default.useRef(null);
|
|
29782
|
+
const [containerReady, setContainerReady] = React141__default.useState(false);
|
|
29657
29783
|
const themeConfig = useThemeConfig();
|
|
29658
29784
|
const { formatNumber } = useFormatNumber();
|
|
29659
|
-
|
|
29785
|
+
React141__default.useEffect(() => {
|
|
29660
29786
|
const checkContainerDimensions = () => {
|
|
29661
29787
|
if (containerRef.current) {
|
|
29662
29788
|
const rect = containerRef.current.getBoundingClientRect();
|
|
@@ -29684,8 +29810,8 @@ var LineChartComponent = ({
|
|
|
29684
29810
|
const defaultTooltipFormatter = (value, name, props) => {
|
|
29685
29811
|
const formattedValue = typeof value === "number" ? formatNumber(value) : value;
|
|
29686
29812
|
return [
|
|
29687
|
-
/* @__PURE__ */ jsx("span", { children: `${formattedValue}${yAxisUnit || ""}` }, `tt-val-${name}-${value}`),
|
|
29688
|
-
name
|
|
29813
|
+
/* @__PURE__ */ jsx("span", { className: "text-gray-900", children: `${formattedValue}${yAxisUnit || ""}` }, `tt-val-${name}-${value}`),
|
|
29814
|
+
/* @__PURE__ */ jsx("span", { className: "text-gray-500", children: name }, `tt-name-${name}`)
|
|
29689
29815
|
];
|
|
29690
29816
|
};
|
|
29691
29817
|
const defaultColors = [
|
|
@@ -29721,7 +29847,7 @@ var LineChartComponent = ({
|
|
|
29721
29847
|
stroke: axisStrokeColor
|
|
29722
29848
|
}
|
|
29723
29849
|
),
|
|
29724
|
-
showTooltip && /* @__PURE__ */ jsx(Tooltip, { formatter: tooltipFormatter || defaultTooltipFormatter, cursor: { strokeDasharray: "3 3" } }),
|
|
29850
|
+
showTooltip && /* @__PURE__ */ jsx(Tooltip, { formatter: tooltipFormatter || defaultTooltipFormatter, itemStyle: { color: "#111827" }, cursor: { strokeDasharray: "3 3" } }),
|
|
29725
29851
|
showLegend && /* @__PURE__ */ jsx(Legend, { payload: legendPayload }),
|
|
29726
29852
|
lines.map((lineConfig, index) => {
|
|
29727
29853
|
const lineProps = {
|
|
@@ -29747,15 +29873,15 @@ var LineChartComponent = ({
|
|
|
29747
29873
|
"div",
|
|
29748
29874
|
{
|
|
29749
29875
|
ref: containerRef,
|
|
29750
|
-
className: clsx("w-full h-auto", className),
|
|
29751
|
-
style: { aspectRatio: `${aspect}/1`, minHeight: "50px", minWidth: "100px" },
|
|
29876
|
+
className: clsx(fillContainer ? "w-full h-full" : "w-full h-auto", className),
|
|
29877
|
+
style: fillContainer ? { height: "100%", minHeight: "50px", minWidth: "100px" } : { aspectRatio: `${aspect}/1`, minHeight: "50px", minWidth: "100px" },
|
|
29752
29878
|
children: containerReady ? /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: chartContent }) : /* @__PURE__ */ jsx("div", { className: "w-full h-full flex items-center justify-center bg-gray-50 rounded-lg", children: /* @__PURE__ */ jsx("div", { className: "text-gray-500 text-sm", children: "Loading chart..." }) })
|
|
29753
29879
|
}
|
|
29754
29880
|
);
|
|
29755
29881
|
}
|
|
29756
29882
|
return /* @__PURE__ */ jsx("div", { className: clsx("w-full", className), children: chartContent });
|
|
29757
29883
|
};
|
|
29758
|
-
var LineChart =
|
|
29884
|
+
var LineChart = React141__default.memo(LineChartComponent, (prevProps, nextProps) => {
|
|
29759
29885
|
if (prevProps.xAxisDataKey !== nextProps.xAxisDataKey || prevProps.xAxisLabel !== nextProps.xAxisLabel || prevProps.yAxisLabel !== nextProps.yAxisLabel || prevProps.yAxisUnit !== nextProps.yAxisUnit || prevProps.className !== nextProps.className || prevProps.showGrid !== nextProps.showGrid || prevProps.showLegend !== nextProps.showLegend || prevProps.showTooltip !== nextProps.showTooltip || prevProps.responsive !== nextProps.responsive || prevProps.aspect !== nextProps.aspect || JSON.stringify(prevProps.yAxisDomain) !== JSON.stringify(nextProps.yAxisDomain)) {
|
|
29760
29886
|
return false;
|
|
29761
29887
|
}
|
|
@@ -29849,7 +29975,7 @@ var OutputProgressChartComponent = ({
|
|
|
29849
29975
|
] }) })
|
|
29850
29976
|
] }) });
|
|
29851
29977
|
};
|
|
29852
|
-
var OutputProgressChart =
|
|
29978
|
+
var OutputProgressChart = React141__default.memo(OutputProgressChartComponent);
|
|
29853
29979
|
OutputProgressChart.displayName = "OutputProgressChart";
|
|
29854
29980
|
var LargeOutputProgressChart = ({
|
|
29855
29981
|
currentOutput,
|
|
@@ -29989,7 +30115,7 @@ var CycleTimeChartComponent = ({
|
|
|
29989
30115
|
}
|
|
29990
30116
|
) }) });
|
|
29991
30117
|
};
|
|
29992
|
-
var CycleTimeChart =
|
|
30118
|
+
var CycleTimeChart = React141__default.memo(CycleTimeChartComponent, (prevProps, nextProps) => {
|
|
29993
30119
|
if (prevProps.className !== nextProps.className) {
|
|
29994
30120
|
return false;
|
|
29995
30121
|
}
|
|
@@ -30015,8 +30141,8 @@ var CycleTimeOverTimeChart = ({
|
|
|
30015
30141
|
className = ""
|
|
30016
30142
|
}) => {
|
|
30017
30143
|
const MAX_DATA_POINTS = 40;
|
|
30018
|
-
const containerRef =
|
|
30019
|
-
const [containerReady, setContainerReady] =
|
|
30144
|
+
const containerRef = React141__default.useRef(null);
|
|
30145
|
+
const [containerReady, setContainerReady] = React141__default.useState(false);
|
|
30020
30146
|
const getHourFromTimeString = (timeStr) => {
|
|
30021
30147
|
const [hours, minutes] = timeStr.split(":");
|
|
30022
30148
|
return parseInt(hours);
|
|
@@ -30027,10 +30153,10 @@ var CycleTimeOverTimeChart = ({
|
|
|
30027
30153
|
};
|
|
30028
30154
|
const displayData = getDisplayData(data);
|
|
30029
30155
|
const DURATION = displayData.length;
|
|
30030
|
-
const [animatedData, setAnimatedData] =
|
|
30031
|
-
const prevDataRef =
|
|
30032
|
-
const animationFrameRef =
|
|
30033
|
-
const animateToNewData =
|
|
30156
|
+
const [animatedData, setAnimatedData] = React141__default.useState(Array(DURATION).fill(0));
|
|
30157
|
+
const prevDataRef = React141__default.useRef(Array(DURATION).fill(0));
|
|
30158
|
+
const animationFrameRef = React141__default.useRef(null);
|
|
30159
|
+
const animateToNewData = React141__default.useCallback((targetData) => {
|
|
30034
30160
|
const startData = [...prevDataRef.current];
|
|
30035
30161
|
const startTime = performance.now();
|
|
30036
30162
|
const duration = 1200;
|
|
@@ -30060,7 +30186,7 @@ var CycleTimeOverTimeChart = ({
|
|
|
30060
30186
|
}
|
|
30061
30187
|
animationFrameRef.current = requestAnimationFrame(animate);
|
|
30062
30188
|
}, []);
|
|
30063
|
-
|
|
30189
|
+
React141__default.useEffect(() => {
|
|
30064
30190
|
if (JSON.stringify(data) !== JSON.stringify(prevDataRef.current)) {
|
|
30065
30191
|
const processedData = getDisplayData(data);
|
|
30066
30192
|
animateToNewData(processedData);
|
|
@@ -30071,7 +30197,7 @@ var CycleTimeOverTimeChart = ({
|
|
|
30071
30197
|
}
|
|
30072
30198
|
};
|
|
30073
30199
|
}, [data, animateToNewData]);
|
|
30074
|
-
|
|
30200
|
+
React141__default.useEffect(() => {
|
|
30075
30201
|
const checkContainerDimensions = () => {
|
|
30076
30202
|
if (containerRef.current) {
|
|
30077
30203
|
const rect = containerRef.current.getBoundingClientRect();
|
|
@@ -30314,7 +30440,7 @@ var CycleTimeOverTimeChart = ({
|
|
|
30314
30440
|
}
|
|
30315
30441
|
);
|
|
30316
30442
|
};
|
|
30317
|
-
var Card =
|
|
30443
|
+
var Card = React141.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
30318
30444
|
"div",
|
|
30319
30445
|
{
|
|
30320
30446
|
ref,
|
|
@@ -30326,7 +30452,7 @@ var Card = React26.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */
|
|
|
30326
30452
|
}
|
|
30327
30453
|
));
|
|
30328
30454
|
Card.displayName = "Card";
|
|
30329
|
-
var CardHeader =
|
|
30455
|
+
var CardHeader = React141.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
30330
30456
|
"div",
|
|
30331
30457
|
{
|
|
30332
30458
|
ref,
|
|
@@ -30335,7 +30461,7 @@ var CardHeader = React26.forwardRef(({ className, ...props }, ref) => /* @__PURE
|
|
|
30335
30461
|
}
|
|
30336
30462
|
));
|
|
30337
30463
|
CardHeader.displayName = "CardHeader";
|
|
30338
|
-
var CardTitle =
|
|
30464
|
+
var CardTitle = React141.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
30339
30465
|
"h3",
|
|
30340
30466
|
{
|
|
30341
30467
|
ref,
|
|
@@ -30347,7 +30473,7 @@ var CardTitle = React26.forwardRef(({ className, ...props }, ref) => /* @__PURE_
|
|
|
30347
30473
|
}
|
|
30348
30474
|
));
|
|
30349
30475
|
CardTitle.displayName = "CardTitle";
|
|
30350
|
-
var CardDescription =
|
|
30476
|
+
var CardDescription = React141.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
30351
30477
|
"p",
|
|
30352
30478
|
{
|
|
30353
30479
|
ref,
|
|
@@ -30356,9 +30482,9 @@ var CardDescription = React26.forwardRef(({ className, ...props }, ref) => /* @_
|
|
|
30356
30482
|
}
|
|
30357
30483
|
));
|
|
30358
30484
|
CardDescription.displayName = "CardDescription";
|
|
30359
|
-
var CardContent =
|
|
30485
|
+
var CardContent = React141.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("p-6 pt-0", className), ...props }));
|
|
30360
30486
|
CardContent.displayName = "CardContent";
|
|
30361
|
-
var CardFooter =
|
|
30487
|
+
var CardFooter = React141.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
30362
30488
|
"div",
|
|
30363
30489
|
{
|
|
30364
30490
|
ref,
|
|
@@ -30434,7 +30560,7 @@ var buttonVariants = cva(
|
|
|
30434
30560
|
}
|
|
30435
30561
|
}
|
|
30436
30562
|
);
|
|
30437
|
-
var Button =
|
|
30563
|
+
var Button = React141.forwardRef(
|
|
30438
30564
|
({ className, variant, size, asChild = false, ...props }, ref) => {
|
|
30439
30565
|
const Comp = asChild ? Slot : "button";
|
|
30440
30566
|
return /* @__PURE__ */ jsx(
|
|
@@ -30461,9 +30587,9 @@ var HourlyOutputChartComponent = ({
|
|
|
30461
30587
|
timezone,
|
|
30462
30588
|
className = ""
|
|
30463
30589
|
}) => {
|
|
30464
|
-
const containerRef =
|
|
30465
|
-
const [containerReady, setContainerReady] =
|
|
30466
|
-
const [containerWidth, setContainerWidth] =
|
|
30590
|
+
const containerRef = React141__default.useRef(null);
|
|
30591
|
+
const [containerReady, setContainerReady] = React141__default.useState(false);
|
|
30592
|
+
const [containerWidth, setContainerWidth] = React141__default.useState(0);
|
|
30467
30593
|
const getTimeFromTimeString2 = (timeStr) => {
|
|
30468
30594
|
const [hours, minutes] = timeStr.split(":");
|
|
30469
30595
|
const hour = parseInt(hours);
|
|
@@ -30472,13 +30598,13 @@ var HourlyOutputChartComponent = ({
|
|
|
30472
30598
|
return { hour, minute, decimalHour };
|
|
30473
30599
|
};
|
|
30474
30600
|
const shiftStartTime = getTimeFromTimeString2(shiftStart);
|
|
30475
|
-
|
|
30601
|
+
React141__default.useMemo(() => {
|
|
30476
30602
|
if (!shiftDate || !timezone) return null;
|
|
30477
30603
|
const hour = shiftStartTime.hour.toString().padStart(2, "0");
|
|
30478
30604
|
const minute = shiftStartTime.minute.toString().padStart(2, "0");
|
|
30479
30605
|
return fromZonedTime(`${shiftDate}T${hour}:${minute}:00`, timezone);
|
|
30480
30606
|
}, [shiftDate, timezone, shiftStartTime.hour, shiftStartTime.minute]);
|
|
30481
|
-
const idleClipRanges =
|
|
30607
|
+
const idleClipRanges = React141__default.useMemo(() => {
|
|
30482
30608
|
if (!idleTimeClips || idleTimeClips.length === 0) return [];
|
|
30483
30609
|
return idleTimeClips.map((clip) => ({
|
|
30484
30610
|
id: clip.id,
|
|
@@ -30486,7 +30612,7 @@ var HourlyOutputChartComponent = ({
|
|
|
30486
30612
|
end: clip.idle_end_time ? new Date(clip.idle_end_time) : null
|
|
30487
30613
|
})).filter((clip) => clip.start && clip.end);
|
|
30488
30614
|
}, [idleTimeClips]);
|
|
30489
|
-
|
|
30615
|
+
React141__default.useCallback((rangeStart, rangeEnd) => {
|
|
30490
30616
|
if (!rangeStart || !rangeEnd || idleClipRanges.length === 0) {
|
|
30491
30617
|
return "Reason unavailable";
|
|
30492
30618
|
}
|
|
@@ -30503,7 +30629,7 @@ var HourlyOutputChartComponent = ({
|
|
|
30503
30629
|
}
|
|
30504
30630
|
return classification.label.replace(/_/g, " ");
|
|
30505
30631
|
}, [idleClipRanges, idleTimeClipClassifications]);
|
|
30506
|
-
const { shiftDuration, shiftEndTime, hasPartialLastHour } =
|
|
30632
|
+
const { shiftDuration, shiftEndTime, hasPartialLastHour } = React141__default.useMemo(() => {
|
|
30507
30633
|
console.log("[HourlyOutputChart] Calculating shift duration with:", {
|
|
30508
30634
|
shiftStart,
|
|
30509
30635
|
shiftEnd,
|
|
@@ -30538,12 +30664,12 @@ var HourlyOutputChartComponent = ({
|
|
|
30538
30664
|
}, [shiftEnd, shiftStartTime.decimalHour]);
|
|
30539
30665
|
const SHIFT_DURATION = shiftDuration;
|
|
30540
30666
|
shiftEndTime ? shiftEndTime.hour : (shiftStartTime.hour + SHIFT_DURATION) % 24;
|
|
30541
|
-
const [animatedData, setAnimatedData] =
|
|
30667
|
+
const [animatedData, setAnimatedData] = React141__default.useState(
|
|
30542
30668
|
() => Array(SHIFT_DURATION).fill(0)
|
|
30543
30669
|
);
|
|
30544
|
-
const prevDataRef =
|
|
30545
|
-
const animationFrameRef =
|
|
30546
|
-
|
|
30670
|
+
const prevDataRef = React141__default.useRef(Array(SHIFT_DURATION).fill(0));
|
|
30671
|
+
const animationFrameRef = React141__default.useRef(null);
|
|
30672
|
+
React141__default.useEffect(() => {
|
|
30547
30673
|
setAnimatedData((prev) => {
|
|
30548
30674
|
if (prev.length !== SHIFT_DURATION) {
|
|
30549
30675
|
return Array(SHIFT_DURATION).fill(0);
|
|
@@ -30552,14 +30678,14 @@ var HourlyOutputChartComponent = ({
|
|
|
30552
30678
|
});
|
|
30553
30679
|
prevDataRef.current = Array(SHIFT_DURATION).fill(0);
|
|
30554
30680
|
}, [SHIFT_DURATION]);
|
|
30555
|
-
const [idleBarState, setIdleBarState] =
|
|
30681
|
+
const [idleBarState, setIdleBarState] = React141__default.useState({
|
|
30556
30682
|
visible: showIdleTime,
|
|
30557
30683
|
key: 0,
|
|
30558
30684
|
shouldAnimate: false
|
|
30559
30685
|
});
|
|
30560
|
-
const prevShowIdleTimeRef =
|
|
30561
|
-
const stateUpdateTimeoutRef =
|
|
30562
|
-
|
|
30686
|
+
const prevShowIdleTimeRef = React141__default.useRef(showIdleTime);
|
|
30687
|
+
const stateUpdateTimeoutRef = React141__default.useRef(null);
|
|
30688
|
+
React141__default.useEffect(() => {
|
|
30563
30689
|
if (stateUpdateTimeoutRef.current) {
|
|
30564
30690
|
clearTimeout(stateUpdateTimeoutRef.current);
|
|
30565
30691
|
}
|
|
@@ -30584,7 +30710,7 @@ var HourlyOutputChartComponent = ({
|
|
|
30584
30710
|
}
|
|
30585
30711
|
};
|
|
30586
30712
|
}, [showIdleTime]);
|
|
30587
|
-
const animateToNewData =
|
|
30713
|
+
const animateToNewData = React141__default.useCallback((targetData) => {
|
|
30588
30714
|
const startData = [...prevDataRef.current];
|
|
30589
30715
|
const startTime = performance.now();
|
|
30590
30716
|
const duration = 1200;
|
|
@@ -30614,7 +30740,7 @@ var HourlyOutputChartComponent = ({
|
|
|
30614
30740
|
}
|
|
30615
30741
|
animationFrameRef.current = requestAnimationFrame(animate);
|
|
30616
30742
|
}, []);
|
|
30617
|
-
|
|
30743
|
+
React141__default.useEffect(() => {
|
|
30618
30744
|
if (JSON.stringify(data) !== JSON.stringify(prevDataRef.current)) {
|
|
30619
30745
|
const shiftData = data.slice(0, SHIFT_DURATION);
|
|
30620
30746
|
animateToNewData(shiftData);
|
|
@@ -30625,7 +30751,7 @@ var HourlyOutputChartComponent = ({
|
|
|
30625
30751
|
}
|
|
30626
30752
|
};
|
|
30627
30753
|
}, [data, animateToNewData]);
|
|
30628
|
-
|
|
30754
|
+
React141__default.useEffect(() => {
|
|
30629
30755
|
const checkContainerDimensions = () => {
|
|
30630
30756
|
if (containerRef.current) {
|
|
30631
30757
|
const rect = containerRef.current.getBoundingClientRect();
|
|
@@ -30651,7 +30777,7 @@ var HourlyOutputChartComponent = ({
|
|
|
30651
30777
|
clearTimeout(fallbackTimeout);
|
|
30652
30778
|
};
|
|
30653
30779
|
}, []);
|
|
30654
|
-
const xAxisConfig =
|
|
30780
|
+
const xAxisConfig = React141__default.useMemo(() => {
|
|
30655
30781
|
if (containerWidth >= 960) {
|
|
30656
30782
|
return { interval: 0, angle: -45, height: 92, tickFont: 10, tickMargin: 12 };
|
|
30657
30783
|
}
|
|
@@ -30660,7 +30786,7 @@ var HourlyOutputChartComponent = ({
|
|
|
30660
30786
|
}
|
|
30661
30787
|
return { interval: 0, angle: -30, height: 64, tickFont: 9, tickMargin: 6 };
|
|
30662
30788
|
}, [containerWidth]);
|
|
30663
|
-
const formatHour =
|
|
30789
|
+
const formatHour = React141__default.useCallback((hourIndex) => {
|
|
30664
30790
|
const isLastHour = hourIndex === SHIFT_DURATION - 1;
|
|
30665
30791
|
const startDecimalHour = shiftStartTime.decimalHour + hourIndex;
|
|
30666
30792
|
const startHour = Math.floor(startDecimalHour) % 24;
|
|
@@ -30684,7 +30810,7 @@ var HourlyOutputChartComponent = ({
|
|
|
30684
30810
|
};
|
|
30685
30811
|
return `${formatTime5(startHour, startMinute)}-${formatTime5(endHour, endMinute)}`;
|
|
30686
30812
|
}, [shiftStartTime.decimalHour, SHIFT_DURATION, shiftEndTime]);
|
|
30687
|
-
const formatTimeRange2 =
|
|
30813
|
+
const formatTimeRange2 = React141__default.useCallback((hourIndex) => {
|
|
30688
30814
|
const isLastHour = hourIndex === SHIFT_DURATION - 1;
|
|
30689
30815
|
const startDecimalHour = shiftStartTime.decimalHour + hourIndex;
|
|
30690
30816
|
const startHour = Math.floor(startDecimalHour) % 24;
|
|
@@ -30705,7 +30831,7 @@ var HourlyOutputChartComponent = ({
|
|
|
30705
30831
|
};
|
|
30706
30832
|
return `${formatTime5(startHour, startMinute)} - ${formatTime5(endHour, endMinute)}`;
|
|
30707
30833
|
}, [shiftStartTime.decimalHour, SHIFT_DURATION, shiftEndTime]);
|
|
30708
|
-
const chartData =
|
|
30834
|
+
const chartData = React141__default.useMemo(() => {
|
|
30709
30835
|
return Array.from({ length: SHIFT_DURATION }, (_, i) => {
|
|
30710
30836
|
const actualHour = (shiftStartTime.hour + i) % 24;
|
|
30711
30837
|
const startMinute = shiftStartTime.minute;
|
|
@@ -30775,7 +30901,7 @@ var HourlyOutputChartComponent = ({
|
|
|
30775
30901
|
};
|
|
30776
30902
|
});
|
|
30777
30903
|
}, [animatedData, data, pphThreshold, idleTimeHourly, shiftStartTime.hour, shiftStartTime.minute, shiftEndTime, formatHour, formatTimeRange2, SHIFT_DURATION]);
|
|
30778
|
-
const IdleBar =
|
|
30904
|
+
const IdleBar = React141__default.useMemo(() => {
|
|
30779
30905
|
if (!idleBarState.visible) return null;
|
|
30780
30906
|
return /* @__PURE__ */ jsx(
|
|
30781
30907
|
Bar,
|
|
@@ -31103,7 +31229,7 @@ var HourlyOutputChartComponent = ({
|
|
|
31103
31229
|
}
|
|
31104
31230
|
);
|
|
31105
31231
|
};
|
|
31106
|
-
var HourlyOutputChart =
|
|
31232
|
+
var HourlyOutputChart = React141__default.memo(HourlyOutputChartComponent, (prevProps, nextProps) => {
|
|
31107
31233
|
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) {
|
|
31108
31234
|
return false;
|
|
31109
31235
|
}
|
|
@@ -31166,7 +31292,7 @@ function getTrendArrowAndColor(trend) {
|
|
|
31166
31292
|
return { arrow: "\u2192", color: "text-gray-400" };
|
|
31167
31293
|
}
|
|
31168
31294
|
}
|
|
31169
|
-
var VideoCard =
|
|
31295
|
+
var VideoCard = React141__default.memo(({
|
|
31170
31296
|
workspace,
|
|
31171
31297
|
hlsUrl,
|
|
31172
31298
|
shouldPlay,
|
|
@@ -31346,7 +31472,7 @@ var logDebug2 = (...args) => {
|
|
|
31346
31472
|
if (!DEBUG_DASHBOARD_LOGS2) return;
|
|
31347
31473
|
console.log(...args);
|
|
31348
31474
|
};
|
|
31349
|
-
var VideoGridView =
|
|
31475
|
+
var VideoGridView = React141__default.memo(({
|
|
31350
31476
|
workspaces,
|
|
31351
31477
|
selectedLine,
|
|
31352
31478
|
className = "",
|
|
@@ -31583,7 +31709,8 @@ var VideoGridView = React26__default.memo(({
|
|
|
31583
31709
|
action_count: workspace.action_count
|
|
31584
31710
|
});
|
|
31585
31711
|
const displayName = getWorkspaceDisplayName(workspace.workspace_name, workspace.line_id);
|
|
31586
|
-
const
|
|
31712
|
+
const currentPath = (router.asPath || "/").split("#")[0];
|
|
31713
|
+
const navParams = getWorkspaceNavigationParams(workspaceId, displayName, workspace.line_id, currentPath);
|
|
31587
31714
|
router.push(`/workspace/${workspaceId}${navParams}`);
|
|
31588
31715
|
}, [router, prewarmClipsInit]);
|
|
31589
31716
|
const handleStreamError = useCallback((workspaceId, options) => {
|
|
@@ -31715,7 +31842,7 @@ var VideoGridView = React26__default.memo(({
|
|
|
31715
31842
|
) }) });
|
|
31716
31843
|
});
|
|
31717
31844
|
VideoGridView.displayName = "VideoGridView";
|
|
31718
|
-
var MapGridView =
|
|
31845
|
+
var MapGridView = React141__default.memo(({
|
|
31719
31846
|
workspaces,
|
|
31720
31847
|
className = "",
|
|
31721
31848
|
displayNames = {},
|
|
@@ -31790,7 +31917,8 @@ var MapGridView = React26__default.memo(({
|
|
|
31790
31917
|
});
|
|
31791
31918
|
const displayName = displayNames[`${workspace.line_id}_${workspace.workspace_name}`] || // Always pass line_id to fallback to ensure correct mapping per line
|
|
31792
31919
|
getWorkspaceDisplayName(workspace.workspace_name, workspace.line_id);
|
|
31793
|
-
const
|
|
31920
|
+
const currentPath = (router.asPath || "/").split("#")[0];
|
|
31921
|
+
const navParams = getWorkspaceNavigationParams(workspaceId, displayName, workspace.line_id, currentPath);
|
|
31794
31922
|
router.push(`/workspace/${workspaceId}${navParams}`);
|
|
31795
31923
|
}, [router, displayNames, prewarmClipsInit]);
|
|
31796
31924
|
const activePositions = useMemo(() => {
|
|
@@ -32536,7 +32664,7 @@ var UptimeLineChartComponent = ({ points, className = "" }) => {
|
|
|
32536
32664
|
)
|
|
32537
32665
|
] }) }) });
|
|
32538
32666
|
};
|
|
32539
|
-
var UptimeLineChart =
|
|
32667
|
+
var UptimeLineChart = React141__default.memo(UptimeLineChartComponent);
|
|
32540
32668
|
var padTime = (value) => value.toString().padStart(2, "0");
|
|
32541
32669
|
var parseTime = (timeValue) => {
|
|
32542
32670
|
if (!timeValue) return null;
|
|
@@ -32745,10 +32873,10 @@ var HourlyUptimeChartComponent = ({
|
|
|
32745
32873
|
elapsedMinutes,
|
|
32746
32874
|
className = ""
|
|
32747
32875
|
}) => {
|
|
32748
|
-
const containerRef =
|
|
32749
|
-
const [containerReady, setContainerReady] =
|
|
32750
|
-
const [containerWidth, setContainerWidth] =
|
|
32751
|
-
const uptimeSeries =
|
|
32876
|
+
const containerRef = React141__default.useRef(null);
|
|
32877
|
+
const [containerReady, setContainerReady] = React141__default.useState(false);
|
|
32878
|
+
const [containerWidth, setContainerWidth] = React141__default.useState(0);
|
|
32879
|
+
const uptimeSeries = React141__default.useMemo(() => buildUptimeSeries({
|
|
32752
32880
|
idleTimeHourly,
|
|
32753
32881
|
shiftStart,
|
|
32754
32882
|
shiftEnd,
|
|
@@ -32757,11 +32885,11 @@ var HourlyUptimeChartComponent = ({
|
|
|
32757
32885
|
elapsedMinutes
|
|
32758
32886
|
}), [idleTimeHourly, shiftStart, shiftEnd, shiftDate, timezone, elapsedMinutes]);
|
|
32759
32887
|
const hasAggregateData = Boolean(hourlyAggregates && hourlyAggregates.length > 0);
|
|
32760
|
-
const shiftStartTime =
|
|
32888
|
+
const shiftStartTime = React141__default.useMemo(
|
|
32761
32889
|
() => getTimeFromTimeString(shiftStart),
|
|
32762
32890
|
[shiftStart]
|
|
32763
32891
|
);
|
|
32764
|
-
const { shiftDuration, shiftEndTime } =
|
|
32892
|
+
const { shiftDuration, shiftEndTime } = React141__default.useMemo(() => {
|
|
32765
32893
|
if (!shiftEnd) {
|
|
32766
32894
|
const fallbackHours = uptimeSeries.shiftMinutes > 0 ? Math.ceil(uptimeSeries.shiftMinutes / 60) : 0;
|
|
32767
32895
|
return { shiftDuration: fallbackHours, shiftEndTime: null };
|
|
@@ -32775,7 +32903,7 @@ var HourlyUptimeChartComponent = ({
|
|
|
32775
32903
|
const hourCount = hasPartial ? Math.ceil(duration) : Math.round(duration);
|
|
32776
32904
|
return { shiftDuration: hourCount, shiftEndTime: endTime };
|
|
32777
32905
|
}, [shiftEnd, shiftStartTime.decimalHour, uptimeSeries.shiftMinutes]);
|
|
32778
|
-
const formatHour =
|
|
32906
|
+
const formatHour = React141__default.useCallback((hourIndex) => {
|
|
32779
32907
|
const isLastHour = hourIndex === shiftDuration - 1;
|
|
32780
32908
|
const startDecimalHour = shiftStartTime.decimalHour + hourIndex;
|
|
32781
32909
|
const startHour = Math.floor(startDecimalHour) % 24;
|
|
@@ -32800,7 +32928,7 @@ var HourlyUptimeChartComponent = ({
|
|
|
32800
32928
|
};
|
|
32801
32929
|
return `${formatTime5(startHour, startMinute)}-${formatTime5(endHour, endMinute)}`;
|
|
32802
32930
|
}, [shiftDuration, shiftStartTime.decimalHour, shiftEndTime]);
|
|
32803
|
-
const formatTimeRange2 =
|
|
32931
|
+
const formatTimeRange2 = React141__default.useCallback((hourIndex) => {
|
|
32804
32932
|
const isLastHour = hourIndex === shiftDuration - 1;
|
|
32805
32933
|
const startDecimalHour = shiftStartTime.decimalHour + hourIndex;
|
|
32806
32934
|
const startHour = Math.floor(startDecimalHour) % 24;
|
|
@@ -32822,7 +32950,7 @@ var HourlyUptimeChartComponent = ({
|
|
|
32822
32950
|
};
|
|
32823
32951
|
return `${formatTime5(startHour, startMinute)} - ${formatTime5(endHour, endMinute)}`;
|
|
32824
32952
|
}, [shiftDuration, shiftStartTime.decimalHour, shiftEndTime]);
|
|
32825
|
-
const chartData =
|
|
32953
|
+
const chartData = React141__default.useMemo(() => {
|
|
32826
32954
|
if (shiftDuration <= 0) return [];
|
|
32827
32955
|
if (hasAggregateData) {
|
|
32828
32956
|
return hourlyAggregates.map((entry, hourIndex) => ({
|
|
@@ -32864,7 +32992,7 @@ var HourlyUptimeChartComponent = ({
|
|
|
32864
32992
|
}, [hasAggregateData, hourlyAggregates, uptimeSeries.points, uptimeSeries.elapsedMinutes, uptimeSeries.shiftMinutes, shiftDuration, formatHour, formatTimeRange2]);
|
|
32865
32993
|
const maxYValue = 100;
|
|
32866
32994
|
const yAxisTicks = [0, 25, 50, 75, 100];
|
|
32867
|
-
|
|
32995
|
+
React141__default.useEffect(() => {
|
|
32868
32996
|
const checkContainerDimensions = () => {
|
|
32869
32997
|
if (containerRef.current) {
|
|
32870
32998
|
const rect = containerRef.current.getBoundingClientRect();
|
|
@@ -32890,7 +33018,7 @@ var HourlyUptimeChartComponent = ({
|
|
|
32890
33018
|
clearTimeout(fallbackTimeout);
|
|
32891
33019
|
};
|
|
32892
33020
|
}, []);
|
|
32893
|
-
const xAxisConfig =
|
|
33021
|
+
const xAxisConfig = React141__default.useMemo(() => {
|
|
32894
33022
|
if (containerWidth >= 960) {
|
|
32895
33023
|
return { interval: 0, angle: -45, height: 92, tickFont: 10, tickMargin: 12, labelMode: "full" };
|
|
32896
33024
|
}
|
|
@@ -32899,7 +33027,7 @@ var HourlyUptimeChartComponent = ({
|
|
|
32899
33027
|
}
|
|
32900
33028
|
return { interval: 0, angle: -30, height: 64, tickFont: 9, tickMargin: 6, labelMode: "start" };
|
|
32901
33029
|
}, [containerWidth]);
|
|
32902
|
-
const formatXAxisTick =
|
|
33030
|
+
const formatXAxisTick = React141__default.useCallback((raw) => {
|
|
32903
33031
|
const label = typeof raw === "string" ? raw : String(raw);
|
|
32904
33032
|
if (xAxisConfig.labelMode === "full") return label;
|
|
32905
33033
|
const parts = label.split("-");
|
|
@@ -33105,7 +33233,7 @@ var HourlyUptimeChartComponent = ({
|
|
|
33105
33233
|
}
|
|
33106
33234
|
);
|
|
33107
33235
|
};
|
|
33108
|
-
var HourlyUptimeChart =
|
|
33236
|
+
var HourlyUptimeChart = React141__default.memo(HourlyUptimeChartComponent);
|
|
33109
33237
|
var DEFAULT_COLORS2 = ["#00AB45", "#ef4444"];
|
|
33110
33238
|
var UptimeDonutChartComponent = ({
|
|
33111
33239
|
data,
|
|
@@ -33175,7 +33303,7 @@ var UptimeDonutChartComponent = ({
|
|
|
33175
33303
|
] }) })
|
|
33176
33304
|
] }) });
|
|
33177
33305
|
};
|
|
33178
|
-
var UptimeDonutChart =
|
|
33306
|
+
var UptimeDonutChart = React141__default.memo(UptimeDonutChartComponent);
|
|
33179
33307
|
UptimeDonutChart.displayName = "UptimeDonutChart";
|
|
33180
33308
|
var TrendIcon = ({ trend }) => {
|
|
33181
33309
|
if (trend === "up") {
|
|
@@ -33294,7 +33422,7 @@ var EmptyStateMessage = ({
|
|
|
33294
33422
|
iconClassName
|
|
33295
33423
|
}) => {
|
|
33296
33424
|
let IconContent = null;
|
|
33297
|
-
if (
|
|
33425
|
+
if (React141__default.isValidElement(iconType)) {
|
|
33298
33426
|
IconContent = iconType;
|
|
33299
33427
|
} else if (typeof iconType === "string") {
|
|
33300
33428
|
const MappedIcon = IconMap[iconType];
|
|
@@ -35579,7 +35707,7 @@ function Skeleton({ className, ...props }) {
|
|
|
35579
35707
|
var Select = SelectPrimitive.Root;
|
|
35580
35708
|
var SelectGroup = SelectPrimitive.Group;
|
|
35581
35709
|
var SelectValue = SelectPrimitive.Value;
|
|
35582
|
-
var SelectTrigger =
|
|
35710
|
+
var SelectTrigger = React141.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(
|
|
35583
35711
|
SelectPrimitive.Trigger,
|
|
35584
35712
|
{
|
|
35585
35713
|
ref,
|
|
@@ -35595,7 +35723,7 @@ var SelectTrigger = React26.forwardRef(({ className, children, ...props }, ref)
|
|
|
35595
35723
|
}
|
|
35596
35724
|
));
|
|
35597
35725
|
SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
|
|
35598
|
-
var SelectScrollUpButton =
|
|
35726
|
+
var SelectScrollUpButton = React141.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
35599
35727
|
SelectPrimitive.ScrollUpButton,
|
|
35600
35728
|
{
|
|
35601
35729
|
ref,
|
|
@@ -35605,7 +35733,7 @@ var SelectScrollUpButton = React26.forwardRef(({ className, ...props }, ref) =>
|
|
|
35605
35733
|
}
|
|
35606
35734
|
));
|
|
35607
35735
|
SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName;
|
|
35608
|
-
var SelectScrollDownButton =
|
|
35736
|
+
var SelectScrollDownButton = React141.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
35609
35737
|
SelectPrimitive.ScrollDownButton,
|
|
35610
35738
|
{
|
|
35611
35739
|
ref,
|
|
@@ -35615,7 +35743,7 @@ var SelectScrollDownButton = React26.forwardRef(({ className, ...props }, ref) =
|
|
|
35615
35743
|
}
|
|
35616
35744
|
));
|
|
35617
35745
|
SelectScrollDownButton.displayName = SelectPrimitive.ScrollDownButton.displayName;
|
|
35618
|
-
var SelectContent =
|
|
35746
|
+
var SelectContent = React141.forwardRef(({ className, children, position = "popper", ...props }, ref) => /* @__PURE__ */ jsx(SelectPrimitive.Portal, { children: /* @__PURE__ */ jsxs(
|
|
35619
35747
|
SelectPrimitive.Content,
|
|
35620
35748
|
{
|
|
35621
35749
|
ref,
|
|
@@ -35643,7 +35771,7 @@ var SelectContent = React26.forwardRef(({ className, children, position = "poppe
|
|
|
35643
35771
|
}
|
|
35644
35772
|
) }));
|
|
35645
35773
|
SelectContent.displayName = SelectPrimitive.Content.displayName;
|
|
35646
|
-
var SelectLabel =
|
|
35774
|
+
var SelectLabel = React141.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
35647
35775
|
SelectPrimitive.Label,
|
|
35648
35776
|
{
|
|
35649
35777
|
ref,
|
|
@@ -35652,7 +35780,7 @@ var SelectLabel = React26.forwardRef(({ className, ...props }, ref) => /* @__PUR
|
|
|
35652
35780
|
}
|
|
35653
35781
|
));
|
|
35654
35782
|
SelectLabel.displayName = SelectPrimitive.Label.displayName;
|
|
35655
|
-
var SelectItem =
|
|
35783
|
+
var SelectItem = React141.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(
|
|
35656
35784
|
SelectPrimitive.Item,
|
|
35657
35785
|
{
|
|
35658
35786
|
ref,
|
|
@@ -35668,7 +35796,7 @@ var SelectItem = React26.forwardRef(({ className, children, ...props }, ref) =>
|
|
|
35668
35796
|
}
|
|
35669
35797
|
));
|
|
35670
35798
|
SelectItem.displayName = SelectPrimitive.Item.displayName;
|
|
35671
|
-
var SelectSeparator =
|
|
35799
|
+
var SelectSeparator = React141.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
35672
35800
|
SelectPrimitive.Separator,
|
|
35673
35801
|
{
|
|
35674
35802
|
ref,
|
|
@@ -35967,7 +36095,7 @@ var TimePickerDropdown = ({
|
|
|
35967
36095
|
] })
|
|
35968
36096
|
] });
|
|
35969
36097
|
};
|
|
35970
|
-
var SilentErrorBoundary = class extends
|
|
36098
|
+
var SilentErrorBoundary = class extends React141__default.Component {
|
|
35971
36099
|
constructor(props) {
|
|
35972
36100
|
super(props);
|
|
35973
36101
|
this.handleClearAndReload = () => {
|
|
@@ -42481,6 +42609,32 @@ var STATIC_COLORS = {
|
|
|
42481
42609
|
};
|
|
42482
42610
|
var PRODUCTIVE_COLOR = "#00AB45";
|
|
42483
42611
|
var IDLE_COLOR = "#e5e7eb";
|
|
42612
|
+
var formatDuration = (seconds) => {
|
|
42613
|
+
if (seconds === null || seconds === void 0 || !Number.isFinite(seconds)) {
|
|
42614
|
+
return "--";
|
|
42615
|
+
}
|
|
42616
|
+
const wholeSeconds = Math.max(0, Math.round(seconds));
|
|
42617
|
+
const days = Math.floor(wholeSeconds / 86400);
|
|
42618
|
+
const hours = Math.floor(wholeSeconds % 86400 / 3600);
|
|
42619
|
+
const minutes = Math.floor(wholeSeconds % 3600 / 60);
|
|
42620
|
+
const remainingSeconds = wholeSeconds % 60;
|
|
42621
|
+
if (days > 0) {
|
|
42622
|
+
return `${days}d ${hours}h ${minutes}m ${remainingSeconds}s`;
|
|
42623
|
+
}
|
|
42624
|
+
if (hours > 0) {
|
|
42625
|
+
return `${hours}h ${minutes}m ${remainingSeconds}s`;
|
|
42626
|
+
}
|
|
42627
|
+
if (minutes > 0) {
|
|
42628
|
+
return `${minutes}m ${remainingSeconds}s`;
|
|
42629
|
+
}
|
|
42630
|
+
return `${remainingSeconds}s`;
|
|
42631
|
+
};
|
|
42632
|
+
var formatPercentage = (value) => {
|
|
42633
|
+
if (value === null || value === void 0 || !Number.isFinite(value)) {
|
|
42634
|
+
return "--";
|
|
42635
|
+
}
|
|
42636
|
+
return `${value.toFixed(1)}%`;
|
|
42637
|
+
};
|
|
42484
42638
|
var getColorForEntry = (name, index) => {
|
|
42485
42639
|
const normalized = name.trim().toLowerCase();
|
|
42486
42640
|
if (normalized === "productive" || normalized === "productive time") {
|
|
@@ -42495,11 +42649,37 @@ var getColorForEntry = (name, index) => {
|
|
|
42495
42649
|
const snakeCaseName = name.replace(/ /g, "_");
|
|
42496
42650
|
return getReasonColor(snakeCaseName, index);
|
|
42497
42651
|
};
|
|
42498
|
-
var CustomTooltip = ({ active, payload }) => {
|
|
42652
|
+
var CustomTooltip = ({ active, payload, hideTotalDuration }) => {
|
|
42499
42653
|
if (active && payload && payload.length) {
|
|
42500
|
-
|
|
42501
|
-
|
|
42502
|
-
|
|
42654
|
+
const datum = payload[0]?.payload;
|
|
42655
|
+
const contributors = datum?.contributors || [];
|
|
42656
|
+
const fill = payload[0]?.payload?.fill || payload[0]?.fill || getColorForEntry(payload[0].name, 0);
|
|
42657
|
+
return /* @__PURE__ */ jsxs("div", { className: "bg-white/95 backdrop-blur-sm p-3 border border-gray-200 shadow-xl rounded-lg z-50 min-w-[200px]", children: [
|
|
42658
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 mb-2 pb-1 border-b border-gray-100", children: [
|
|
42659
|
+
/* @__PURE__ */ jsx("div", { className: "w-2.5 h-2.5 rounded-full flex-shrink-0", style: { backgroundColor: fill } }),
|
|
42660
|
+
/* @__PURE__ */ jsx("span", { className: "font-semibold text-slate-800 text-sm", children: payload[0].name.replace(/_/g, " ") })
|
|
42661
|
+
] }),
|
|
42662
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1 text-xs", children: [
|
|
42663
|
+
/* @__PURE__ */ jsxs("div", { className: "flex justify-between items-center gap-3", children: [
|
|
42664
|
+
/* @__PURE__ */ jsx("span", { className: "text-slate-500", children: "Share of idle time" }),
|
|
42665
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium text-slate-800", children: `${payload[0].value.toFixed(1)}%` })
|
|
42666
|
+
] }),
|
|
42667
|
+
!hideTotalDuration && datum?.totalDurationSeconds !== void 0 ? /* @__PURE__ */ jsxs("div", { className: "flex justify-between items-center gap-3", children: [
|
|
42668
|
+
/* @__PURE__ */ jsx("span", { className: "text-slate-500", children: "Total Duration" }),
|
|
42669
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium text-slate-800", children: formatDuration(datum.totalDurationSeconds) })
|
|
42670
|
+
] }) : null,
|
|
42671
|
+
/* @__PURE__ */ jsxs("div", { className: "flex justify-between items-center gap-3", children: [
|
|
42672
|
+
/* @__PURE__ */ jsx("span", { className: "text-slate-500", children: "Efficiency Loss" }),
|
|
42673
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium text-slate-800", children: formatPercentage(datum?.efficiencyLossPercentage) })
|
|
42674
|
+
] })
|
|
42675
|
+
] }),
|
|
42676
|
+
contributors.length > 0 ? /* @__PURE__ */ jsxs("div", { className: "mt-2 pt-2 border-t border-gray-100", children: [
|
|
42677
|
+
/* @__PURE__ */ jsx("p", { className: "text-[9px] font-semibold uppercase tracking-wider text-slate-400 mb-1.5", children: "Top Workstations" }),
|
|
42678
|
+
/* @__PURE__ */ jsx("div", { className: "space-y-1", children: contributors.slice(0, 3).map((contributor) => /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-2 text-[10px]", children: [
|
|
42679
|
+
/* @__PURE__ */ jsx("span", { className: "text-slate-700 truncate max-w-[120px]", children: contributor.workspaceName }),
|
|
42680
|
+
/* @__PURE__ */ jsx("span", { className: "text-slate-500 text-right whitespace-nowrap", children: `${formatDuration(contributor.totalDurationSeconds)} \u2022 ${Number(contributor.percentageWithinReason || 0).toFixed(1)}%` })
|
|
42681
|
+
] }, `${payload[0].name}-${contributor.workspaceId}`)) })
|
|
42682
|
+
] }) : null
|
|
42503
42683
|
] });
|
|
42504
42684
|
}
|
|
42505
42685
|
return null;
|
|
@@ -42536,10 +42716,11 @@ var ErrorState = ({ error }) => /* @__PURE__ */ jsx("div", { className: "w-full
|
|
|
42536
42716
|
var IdleTimeReasonChartComponent = ({
|
|
42537
42717
|
data,
|
|
42538
42718
|
isLoading = false,
|
|
42539
|
-
error = null
|
|
42719
|
+
error = null,
|
|
42720
|
+
hideTotalDuration = false
|
|
42540
42721
|
}) => {
|
|
42541
|
-
const [activeData, setActiveData] =
|
|
42542
|
-
|
|
42722
|
+
const [activeData, setActiveData] = React141__default.useState([]);
|
|
42723
|
+
React141__default.useEffect(() => {
|
|
42543
42724
|
if (activeData.length > 0) {
|
|
42544
42725
|
setActiveData([]);
|
|
42545
42726
|
}
|
|
@@ -42554,7 +42735,7 @@ var IdleTimeReasonChartComponent = ({
|
|
|
42554
42735
|
setActiveData([]);
|
|
42555
42736
|
}
|
|
42556
42737
|
}, [data]);
|
|
42557
|
-
|
|
42738
|
+
React141__default.useEffect(() => {
|
|
42558
42739
|
if (!data || data.length === 0) return;
|
|
42559
42740
|
data.forEach((entry, index) => {
|
|
42560
42741
|
if (entry.name.toLowerCase().includes("other")) {
|
|
@@ -42562,7 +42743,7 @@ var IdleTimeReasonChartComponent = ({
|
|
|
42562
42743
|
}
|
|
42563
42744
|
});
|
|
42564
42745
|
}, [data]);
|
|
42565
|
-
const pieKey =
|
|
42746
|
+
const pieKey = React141__default.useMemo(() => {
|
|
42566
42747
|
return activeData.map((d) => `${d.name}-${d.value}`).join("|");
|
|
42567
42748
|
}, [activeData]);
|
|
42568
42749
|
if (isLoading) {
|
|
@@ -42589,19 +42770,29 @@ var IdleTimeReasonChartComponent = ({
|
|
|
42589
42770
|
}
|
|
42590
42771
|
.recharts-wrapper {
|
|
42591
42772
|
outline: none !important;
|
|
42773
|
+
overflow: visible !important;
|
|
42774
|
+
}
|
|
42775
|
+
.recharts-tooltip-wrapper {
|
|
42776
|
+
z-index: 1000 !important;
|
|
42777
|
+
}
|
|
42778
|
+
.recharts-responsive-container {
|
|
42779
|
+
overflow: visible !important;
|
|
42780
|
+
}
|
|
42781
|
+
.recharts-surface {
|
|
42782
|
+
overflow: visible !important;
|
|
42592
42783
|
}
|
|
42593
42784
|
` }),
|
|
42594
42785
|
/* @__PURE__ */ jsxs(
|
|
42595
42786
|
"div",
|
|
42596
42787
|
{
|
|
42597
|
-
className: "w-full h-full flex items-center overflow-
|
|
42788
|
+
className: "w-full h-full flex items-center overflow-visible focus:outline-none",
|
|
42598
42789
|
tabIndex: -1,
|
|
42599
42790
|
onFocus: (e) => e.currentTarget.blur(),
|
|
42600
42791
|
children: [
|
|
42601
42792
|
/* @__PURE__ */ jsx(
|
|
42602
42793
|
"div",
|
|
42603
42794
|
{
|
|
42604
|
-
className: "flex-1 h-full min-w-0 relative focus:outline-none",
|
|
42795
|
+
className: "flex-1 h-full min-w-0 relative focus:outline-none overflow-visible",
|
|
42605
42796
|
tabIndex: -1,
|
|
42606
42797
|
onFocus: (e) => e.currentTarget.blur(),
|
|
42607
42798
|
children: /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxs(PieChart, { margin: { top: 0, right: 0, bottom: 0, left: 0 }, children: [
|
|
@@ -42633,11 +42824,11 @@ var IdleTimeReasonChartComponent = ({
|
|
|
42633
42824
|
},
|
|
42634
42825
|
pieKey
|
|
42635
42826
|
),
|
|
42636
|
-
/* @__PURE__ */ jsx(Tooltip, { content: /* @__PURE__ */ jsx(CustomTooltip, {}) })
|
|
42827
|
+
/* @__PURE__ */ jsx(Tooltip, { content: /* @__PURE__ */ jsx(CustomTooltip, { hideTotalDuration }) })
|
|
42637
42828
|
] }) })
|
|
42638
42829
|
}
|
|
42639
42830
|
),
|
|
42640
|
-
/* @__PURE__ */ jsx("div", { className: "w-[
|
|
42831
|
+
/* @__PURE__ */ jsx("div", { className: "w-[50%] max-w-[200px] pl-1 pr-1 flex flex-col justify-center h-full overflow-y-auto", children: /* @__PURE__ */ jsx("ul", { className: "text-xs space-y-1.5", children: data.map((entry, index) => /* @__PURE__ */ jsxs("li", { className: "flex items-start", children: [
|
|
42641
42832
|
/* @__PURE__ */ jsx(
|
|
42642
42833
|
"span",
|
|
42643
42834
|
{
|
|
@@ -42645,14 +42836,14 @@ var IdleTimeReasonChartComponent = ({
|
|
|
42645
42836
|
style: { backgroundColor: getColorForEntry(entry.name, index) }
|
|
42646
42837
|
}
|
|
42647
42838
|
),
|
|
42648
|
-
/* @__PURE__ */ jsx("span", { className: "text-gray-600 leading-tight text-[
|
|
42839
|
+
/* @__PURE__ */ jsx("span", { className: "text-gray-600 leading-tight text-[11px] sm:text-xs break-words", children: entry.name.replace(/_/g, " ") })
|
|
42649
42840
|
] }, `item-${index}`)) }) })
|
|
42650
42841
|
]
|
|
42651
42842
|
}
|
|
42652
42843
|
)
|
|
42653
42844
|
] });
|
|
42654
42845
|
};
|
|
42655
|
-
var IdleTimeReasonChart =
|
|
42846
|
+
var IdleTimeReasonChart = React141__default.memo(IdleTimeReasonChartComponent);
|
|
42656
42847
|
IdleTimeReasonChart.displayName = "IdleTimeReasonChart";
|
|
42657
42848
|
var IdleTimeReasonChart_default = IdleTimeReasonChart;
|
|
42658
42849
|
var DEFAULT_PERFORMANCE_DATA = {
|
|
@@ -46874,11 +47065,11 @@ var getWorkspaceStyles = (position, isPlaceholder = false) => {
|
|
|
46874
47065
|
${isPlaceholder ? "cursor-default" : ""}`;
|
|
46875
47066
|
};
|
|
46876
47067
|
var formatPercentRange = (min, max) => {
|
|
46877
|
-
const
|
|
47068
|
+
const format8 = (value) => Number.isInteger(value) ? `${value}` : value.toFixed(1);
|
|
46878
47069
|
if (min >= 100 || max >= 100) {
|
|
46879
|
-
return `${
|
|
47070
|
+
return `${format8(min)}+%`;
|
|
46880
47071
|
}
|
|
46881
|
-
return `${
|
|
47072
|
+
return `${format8(min)}-${format8(max)}%`;
|
|
46882
47073
|
};
|
|
46883
47074
|
var Legend6 = ({ useBottleneckLabel = false, legend }) => {
|
|
46884
47075
|
const effectiveLegend = legend || DEFAULT_EFFICIENCY_LEGEND;
|
|
@@ -46912,7 +47103,7 @@ var arePropsEqual = (prevProps, nextProps) => {
|
|
|
46912
47103
|
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
|
|
46913
47104
|
prevProps.position.id === nextProps.position.id;
|
|
46914
47105
|
};
|
|
46915
|
-
var WorkspaceGridItem =
|
|
47106
|
+
var WorkspaceGridItem = React141__default.memo(({
|
|
46916
47107
|
data,
|
|
46917
47108
|
position,
|
|
46918
47109
|
isBottleneck = false,
|
|
@@ -46941,7 +47132,8 @@ var WorkspaceGridItem = React26__default.memo(({
|
|
|
46941
47132
|
e.preventDefault();
|
|
46942
47133
|
if (isInactive) return;
|
|
46943
47134
|
const displayName = getWorkspaceDisplayName(data.workspace_name, data.line_id);
|
|
46944
|
-
const
|
|
47135
|
+
const currentPath = typeof window !== "undefined" ? `${window.location.pathname}${window.location.search}` : "/";
|
|
47136
|
+
const navParams = getWorkspaceNavigationParams(data.workspace_id, displayName, data.line_id, currentPath);
|
|
46945
47137
|
navigate(`/workspace/${data.workspace_id}${navParams}`, {
|
|
46946
47138
|
trackingEvent: {
|
|
46947
47139
|
name: "Workspace Detail Clicked",
|
|
@@ -47006,7 +47198,7 @@ var WorkspaceGridItem = React26__default.memo(({
|
|
|
47006
47198
|
);
|
|
47007
47199
|
}, arePropsEqual);
|
|
47008
47200
|
WorkspaceGridItem.displayName = "WorkspaceGridItem";
|
|
47009
|
-
var WorkspaceGrid =
|
|
47201
|
+
var WorkspaceGrid = React141__default.memo(({
|
|
47010
47202
|
workspaces,
|
|
47011
47203
|
isPdfMode = false,
|
|
47012
47204
|
customWorkspacePositions,
|
|
@@ -47261,7 +47453,7 @@ var KPICard = ({
|
|
|
47261
47453
|
}) => {
|
|
47262
47454
|
useThemeConfig();
|
|
47263
47455
|
const { formatNumber } = useFormatNumber();
|
|
47264
|
-
const trendInfo =
|
|
47456
|
+
const trendInfo = React141__default.useMemo(() => {
|
|
47265
47457
|
let trendValue = trend || "neutral";
|
|
47266
47458
|
if (change !== void 0 && trend === void 0) {
|
|
47267
47459
|
trendValue = change > 0 ? "up" : change < 0 ? "down" : "neutral";
|
|
@@ -47288,7 +47480,7 @@ var KPICard = ({
|
|
|
47288
47480
|
const shouldShowTrend = !(change === 0 && trend === void 0);
|
|
47289
47481
|
return { trendValue, Icon: Icon2, colorClass, bgClass, shouldShowTrend };
|
|
47290
47482
|
}, [trend, change]);
|
|
47291
|
-
const formattedValue =
|
|
47483
|
+
const formattedValue = React141__default.useMemo(() => {
|
|
47292
47484
|
if (title === "Quality Compliance" && typeof value === "number") {
|
|
47293
47485
|
return value.toFixed(1);
|
|
47294
47486
|
}
|
|
@@ -47302,7 +47494,7 @@ var KPICard = ({
|
|
|
47302
47494
|
}
|
|
47303
47495
|
return value;
|
|
47304
47496
|
}, [value, title]);
|
|
47305
|
-
const formattedChange =
|
|
47497
|
+
const formattedChange = React141__default.useMemo(() => {
|
|
47306
47498
|
if (change === void 0 || change === 0 && !showZeroChange) return null;
|
|
47307
47499
|
const absChange = Math.abs(change);
|
|
47308
47500
|
return formatNumber(absChange, { minimumFractionDigits: 0, maximumFractionDigits: 1 });
|
|
@@ -47740,7 +47932,7 @@ var WorkspaceHealthCard = ({
|
|
|
47740
47932
|
onClick(workspace);
|
|
47741
47933
|
}
|
|
47742
47934
|
};
|
|
47743
|
-
const
|
|
47935
|
+
const formatDuration5 = (minutes) => {
|
|
47744
47936
|
if (!minutes || minutes <= 0) return "0 min";
|
|
47745
47937
|
const rounded = Math.max(Math.round(minutes), 0);
|
|
47746
47938
|
const days = Math.floor(rounded / 1440);
|
|
@@ -47806,7 +47998,7 @@ var WorkspaceHealthCard = ({
|
|
|
47806
47998
|
};
|
|
47807
47999
|
}
|
|
47808
48000
|
return {
|
|
47809
|
-
text: `${
|
|
48001
|
+
text: `${formatDuration5(downtimeMinutes)}`,
|
|
47810
48002
|
className: downtimeMinutes > 60 ? "text-rose-600 dark:text-rose-400" : "text-amber-600 dark:text-amber-400",
|
|
47811
48003
|
label: "Total Downtime"
|
|
47812
48004
|
};
|
|
@@ -48782,7 +48974,7 @@ var Breadcrumbs = ({ items }) => {
|
|
|
48782
48974
|
}
|
|
48783
48975
|
}
|
|
48784
48976
|
};
|
|
48785
|
-
return /* @__PURE__ */ jsx("nav", { "aria-label": "Breadcrumb", className: "mb-1 flex items-center space-x-1 text-xs font-medium text-gray-500 dark:text-gray-400", children: items.map((item, index) => /* @__PURE__ */ jsxs(
|
|
48977
|
+
return /* @__PURE__ */ jsx("nav", { "aria-label": "Breadcrumb", className: "mb-1 flex items-center space-x-1 text-xs font-medium text-gray-500 dark:text-gray-400", children: items.map((item, index) => /* @__PURE__ */ jsxs(React141__default.Fragment, { children: [
|
|
48786
48978
|
index > 0 && /* @__PURE__ */ jsx(ChevronRight, { className: "h-3 w-3 text-gray-400 dark:text-gray-500" }),
|
|
48787
48979
|
/* @__PURE__ */ jsxs(
|
|
48788
48980
|
"span",
|
|
@@ -48844,29 +49036,27 @@ var UserProfileDropdown = ({ config }) => {
|
|
|
48844
49036
|
}
|
|
48845
49037
|
}
|
|
48846
49038
|
};
|
|
48847
|
-
const
|
|
49039
|
+
const fullName = user?.user_metadata?.full_name;
|
|
49040
|
+
const triggerLabel = config.showName !== false ? fullName || user.email || "Account" : "Account";
|
|
48848
49041
|
return /* @__PURE__ */ jsxs("div", { className: "relative", ref: dropdownRef, children: [
|
|
48849
|
-
/* @__PURE__ */
|
|
49042
|
+
/* @__PURE__ */ jsx(
|
|
48850
49043
|
"button",
|
|
48851
49044
|
{
|
|
48852
49045
|
type: "button",
|
|
48853
|
-
className: "flex items-center
|
|
49046
|
+
className: "flex items-center rounded-md px-2 py-1.5 text-sm font-medium text-gray-700 hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 dark:text-gray-200 dark:hover:bg-gray-800 dark:focus:ring-offset-gray-800",
|
|
48854
49047
|
onClick: () => setIsOpen(!isOpen),
|
|
48855
49048
|
"aria-haspopup": "true",
|
|
48856
49049
|
"aria-expanded": isOpen,
|
|
48857
49050
|
"aria-label": "User menu",
|
|
48858
|
-
children: [
|
|
48859
|
-
config.customAvatar ? config.customAvatar : config.showAvatar !== false && user?.user_metadata?.avatar_url ? /* @__PURE__ */ jsx("img", { className: "h-8 w-8 rounded-full", src: user.user_metadata.avatar_url, alt: "User avatar" }) : defaultAvatar,
|
|
48860
|
-
config.showName !== false && user?.user_metadata?.full_name && /* @__PURE__ */ jsx("span", { className: "hidden md:block text-sm font-medium text-gray-700 dark:text-gray-200", children: user.user_metadata.full_name })
|
|
48861
|
-
]
|
|
49051
|
+
children: /* @__PURE__ */ jsx("span", { className: "truncate max-w-[180px]", children: triggerLabel })
|
|
48862
49052
|
}
|
|
48863
49053
|
),
|
|
48864
49054
|
isOpen && /* @__PURE__ */ jsxs("div", { className: "origin-top-right absolute right-0 mt-2 w-48 rounded-md shadow-lg py-1 bg-white dark:bg-gray-800 ring-1 ring-black ring-opacity-5 dark:ring-gray-700 focus:outline-none z-50", children: [
|
|
48865
|
-
config.showName !== false &&
|
|
48866
|
-
/* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-gray-900 dark:text-white truncate", children:
|
|
49055
|
+
config.showName !== false && fullName && /* @__PURE__ */ jsxs("div", { className: "px-4 py-2 md:hidden", children: [
|
|
49056
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-gray-900 dark:text-white truncate", children: fullName }),
|
|
48867
49057
|
user.email && /* @__PURE__ */ jsx("p", { className: "text-xs text-gray-500 dark:text-gray-400 truncate", children: user.email })
|
|
48868
49058
|
] }),
|
|
48869
|
-
|
|
49059
|
+
fullName && /* @__PURE__ */ jsx("div", { className: "md:hidden h-px bg-gray-200 dark:bg-gray-700 my-1" }),
|
|
48870
49060
|
menuItems.map(
|
|
48871
49061
|
(item) => item.isDivider ? /* @__PURE__ */ jsx("div", { className: "h-px bg-gray-200 dark:bg-gray-700 my-1" }, item.key) : /* @__PURE__ */ jsxs(
|
|
48872
49062
|
"button",
|
|
@@ -49108,6 +49298,211 @@ var SettingsPopup = ({
|
|
|
49108
49298
|
document.body
|
|
49109
49299
|
);
|
|
49110
49300
|
};
|
|
49301
|
+
var formatPercent = (value) => typeof value === "number" && Number.isFinite(value) ? `${value.toFixed(1)}%` : "N/A";
|
|
49302
|
+
var formatRelativeTime2 = (value) => {
|
|
49303
|
+
const parsed = new Date(value);
|
|
49304
|
+
if (Number.isNaN(parsed.getTime())) return "Just now";
|
|
49305
|
+
const diffMs = parsed.getTime() - Date.now();
|
|
49306
|
+
const absSeconds = Math.round(Math.abs(diffMs) / 1e3);
|
|
49307
|
+
const rtf = new Intl.RelativeTimeFormat("en", { numeric: "auto" });
|
|
49308
|
+
if (absSeconds < 60) return rtf.format(Math.round(diffMs / 1e3), "second");
|
|
49309
|
+
if (absSeconds < 3600) return rtf.format(Math.round(diffMs / 6e4), "minute");
|
|
49310
|
+
if (absSeconds < 86400) return rtf.format(Math.round(diffMs / 36e5), "hour");
|
|
49311
|
+
return rtf.format(Math.round(diffMs / 864e5), "day");
|
|
49312
|
+
};
|
|
49313
|
+
var AlertsPopup = ({
|
|
49314
|
+
isOpen,
|
|
49315
|
+
onClose,
|
|
49316
|
+
triggerRef,
|
|
49317
|
+
companyId,
|
|
49318
|
+
alertsCount = 0,
|
|
49319
|
+
onAlertsLoaded
|
|
49320
|
+
}) => {
|
|
49321
|
+
const supabase = useSupabase();
|
|
49322
|
+
const popupRef = useRef(null);
|
|
49323
|
+
const [position, setPosition] = useState({ top: 0, left: 90, width: 360 });
|
|
49324
|
+
const [mounted, setMounted] = useState(false);
|
|
49325
|
+
const [alerts, setAlerts] = useState([]);
|
|
49326
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
49327
|
+
const [error, setError] = useState(null);
|
|
49328
|
+
const loadAlerts = useCallback(async () => {
|
|
49329
|
+
if (!supabase || !companyId) {
|
|
49330
|
+
setAlerts([]);
|
|
49331
|
+
onAlertsLoaded?.(0);
|
|
49332
|
+
return;
|
|
49333
|
+
}
|
|
49334
|
+
try {
|
|
49335
|
+
setIsLoading(true);
|
|
49336
|
+
setError(null);
|
|
49337
|
+
const response = await alertsService.getCurrentAlerts(supabase, companyId);
|
|
49338
|
+
const nextAlerts = response?.alerts || [];
|
|
49339
|
+
setAlerts(nextAlerts);
|
|
49340
|
+
onAlertsLoaded?.(response?.total ?? nextAlerts.length);
|
|
49341
|
+
} catch (err) {
|
|
49342
|
+
const message = err instanceof Error ? err.message : "Failed to load alerts";
|
|
49343
|
+
setAlerts([]);
|
|
49344
|
+
setError(message);
|
|
49345
|
+
onAlertsLoaded?.(0);
|
|
49346
|
+
} finally {
|
|
49347
|
+
setIsLoading(false);
|
|
49348
|
+
}
|
|
49349
|
+
}, [companyId, onAlertsLoaded, supabase]);
|
|
49350
|
+
useEffect(() => {
|
|
49351
|
+
setMounted(true);
|
|
49352
|
+
}, []);
|
|
49353
|
+
useEffect(() => {
|
|
49354
|
+
if (!isOpen) return;
|
|
49355
|
+
void loadAlerts();
|
|
49356
|
+
}, [isOpen, loadAlerts]);
|
|
49357
|
+
const updatePosition = useCallback(() => {
|
|
49358
|
+
const viewportHeight = window.innerHeight;
|
|
49359
|
+
const viewportWidth = window.innerWidth;
|
|
49360
|
+
if (viewportWidth < 768) {
|
|
49361
|
+
const mobileWidth = Math.max(240, Math.min(360, viewportWidth - 32));
|
|
49362
|
+
setPosition({
|
|
49363
|
+
top: Math.max(16, (viewportHeight - 280) / 2),
|
|
49364
|
+
left: Math.max(16, (viewportWidth - mobileWidth) / 2),
|
|
49365
|
+
width: mobileWidth
|
|
49366
|
+
});
|
|
49367
|
+
return;
|
|
49368
|
+
}
|
|
49369
|
+
if (!triggerRef.current) return;
|
|
49370
|
+
const rect = triggerRef.current.getBoundingClientRect();
|
|
49371
|
+
const popupHeight = 280;
|
|
49372
|
+
let top = rect.bottom - popupHeight + 40;
|
|
49373
|
+
if (top < 16) top = 16;
|
|
49374
|
+
if (top + popupHeight > viewportHeight - 16) {
|
|
49375
|
+
top = viewportHeight - popupHeight - 16;
|
|
49376
|
+
}
|
|
49377
|
+
setPosition({
|
|
49378
|
+
top,
|
|
49379
|
+
left: 88,
|
|
49380
|
+
// Sidebar width (80px) + gap (8px)
|
|
49381
|
+
width: 360
|
|
49382
|
+
});
|
|
49383
|
+
}, [triggerRef]);
|
|
49384
|
+
useEffect(() => {
|
|
49385
|
+
if (isOpen) {
|
|
49386
|
+
updatePosition();
|
|
49387
|
+
window.addEventListener("resize", updatePosition);
|
|
49388
|
+
window.addEventListener("scroll", updatePosition);
|
|
49389
|
+
}
|
|
49390
|
+
return () => {
|
|
49391
|
+
window.removeEventListener("resize", updatePosition);
|
|
49392
|
+
window.removeEventListener("scroll", updatePosition);
|
|
49393
|
+
};
|
|
49394
|
+
}, [isOpen, updatePosition]);
|
|
49395
|
+
useEffect(() => {
|
|
49396
|
+
const handleClickOutside = (event) => {
|
|
49397
|
+
const target = event.target;
|
|
49398
|
+
const clickedTrigger = triggerRef.current?.contains(target) ?? false;
|
|
49399
|
+
if (popupRef.current && !popupRef.current.contains(target) && !clickedTrigger) {
|
|
49400
|
+
onClose();
|
|
49401
|
+
}
|
|
49402
|
+
};
|
|
49403
|
+
const handleEscape = (event) => {
|
|
49404
|
+
if (event.key === "Escape") {
|
|
49405
|
+
onClose();
|
|
49406
|
+
}
|
|
49407
|
+
};
|
|
49408
|
+
if (isOpen) {
|
|
49409
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
49410
|
+
document.addEventListener("keydown", handleEscape);
|
|
49411
|
+
}
|
|
49412
|
+
return () => {
|
|
49413
|
+
document.removeEventListener("mousedown", handleClickOutside);
|
|
49414
|
+
document.removeEventListener("keydown", handleEscape);
|
|
49415
|
+
};
|
|
49416
|
+
}, [isOpen, onClose, triggerRef]);
|
|
49417
|
+
if (!mounted) return null;
|
|
49418
|
+
return createPortal(
|
|
49419
|
+
/* @__PURE__ */ jsx(AnimatePresence, { children: isOpen && /* @__PURE__ */ jsxs(
|
|
49420
|
+
motion.div,
|
|
49421
|
+
{
|
|
49422
|
+
ref: popupRef,
|
|
49423
|
+
initial: { opacity: 0, x: -12, scale: 0.95 },
|
|
49424
|
+
animate: { opacity: 1, x: 0, scale: 1 },
|
|
49425
|
+
exit: { opacity: 0, x: -12, scale: 0.95 },
|
|
49426
|
+
transition: {
|
|
49427
|
+
duration: 0.2,
|
|
49428
|
+
ease: [0.16, 1, 0.3, 1]
|
|
49429
|
+
},
|
|
49430
|
+
style: {
|
|
49431
|
+
position: "fixed",
|
|
49432
|
+
top: position.top,
|
|
49433
|
+
left: position.left,
|
|
49434
|
+
width: position.width,
|
|
49435
|
+
zIndex: 2147483647
|
|
49436
|
+
},
|
|
49437
|
+
className: "bg-white rounded-[16px] shadow-xl border border-gray-100 max-w-[calc(100vw-32px)] overflow-hidden flex flex-col",
|
|
49438
|
+
children: [
|
|
49439
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-5 py-4 border-b border-gray-50 bg-[#fafafa]", children: [
|
|
49440
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
|
|
49441
|
+
/* @__PURE__ */ jsx("h3", { className: "text-[14px] font-bold text-[#111827] uppercase tracking-wide", children: "Recent Alerts" }),
|
|
49442
|
+
alertsCount > 0 && /* @__PURE__ */ jsxs("span", { className: "bg-[#eff6ff] text-[#2563eb] text-[11px] font-bold px-2 py-0.5 rounded-full", children: [
|
|
49443
|
+
alertsCount,
|
|
49444
|
+
" Active"
|
|
49445
|
+
] })
|
|
49446
|
+
] }),
|
|
49447
|
+
/* @__PURE__ */ jsx(
|
|
49448
|
+
"button",
|
|
49449
|
+
{
|
|
49450
|
+
onClick: onClose,
|
|
49451
|
+
className: "text-gray-400 hover:text-gray-600 focus:outline-none p-1.5 -mr-1.5 rounded-lg hover:bg-gray-100 transition-colors",
|
|
49452
|
+
children: /* @__PURE__ */ jsx(XMarkIcon, { className: "w-[18px] h-[18px]", strokeWidth: 2 })
|
|
49453
|
+
}
|
|
49454
|
+
)
|
|
49455
|
+
] }),
|
|
49456
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col max-h-[380px] overflow-y-auto", children: [
|
|
49457
|
+
isLoading && /* @__PURE__ */ jsx("div", { className: "px-5 py-10 text-sm text-gray-500", children: "Loading current shift alerts..." }),
|
|
49458
|
+
!isLoading && error && /* @__PURE__ */ jsx("div", { className: "px-5 py-10 text-sm text-red-600", children: error }),
|
|
49459
|
+
!isLoading && !error && alerts.length === 0 && /* @__PURE__ */ jsx("div", { className: "px-5 py-10 text-sm text-gray-500", children: "No active alerts for the current shift." }),
|
|
49460
|
+
!isLoading && !error && alerts.map((alert2, index) => {
|
|
49461
|
+
const isCritical = typeof alert2.delta_efficiency === "number" && alert2.delta_efficiency <= -10;
|
|
49462
|
+
const description = `${alert2.monitoring_mode === "uptime" ? "Uptime" : "Output"} efficiency is ${formatPercent(alert2.current_efficiency)} vs last week's ${formatPercent(alert2.baseline_efficiency)} average.`;
|
|
49463
|
+
return /* @__PURE__ */ jsx(
|
|
49464
|
+
motion.div,
|
|
49465
|
+
{
|
|
49466
|
+
initial: { opacity: 0, y: 10 },
|
|
49467
|
+
animate: { opacity: 1, y: 0 },
|
|
49468
|
+
transition: {
|
|
49469
|
+
duration: 0.2,
|
|
49470
|
+
delay: index * 0.05 + 0.1,
|
|
49471
|
+
ease: [0.16, 1, 0.3, 1]
|
|
49472
|
+
},
|
|
49473
|
+
className: "px-5 py-5 border-b border-gray-50 hover:bg-[#f8fafc] transition-colors",
|
|
49474
|
+
children: /* @__PURE__ */ jsxs("div", { className: "flex gap-4", children: [
|
|
49475
|
+
/* @__PURE__ */ jsx("div", { className: `shrink-0 flex items-start pt-0.5 ${isCritical ? "text-[#ef4444]" : "text-[#f59e0b]"}`, children: isCritical ? /* @__PURE__ */ jsx(ExclamationCircleIcon, { className: "w-5 h-5", strokeWidth: 1.5 }) : /* @__PURE__ */ jsx(ExclamationTriangleIcon, { className: "w-5 h-5", strokeWidth: 1.5 }) }),
|
|
49476
|
+
/* @__PURE__ */ jsxs("div", { className: "flex-1", children: [
|
|
49477
|
+
/* @__PURE__ */ jsxs("div", { className: "flex justify-between items-start mb-1.5", children: [
|
|
49478
|
+
/* @__PURE__ */ jsx("h4", { className: "text-sm font-semibold text-[#111827]", children: alert2.line_name }),
|
|
49479
|
+
/* @__PURE__ */ jsx("span", { className: "text-[12px] text-[#94a3b8] font-medium whitespace-nowrap ml-3", children: formatRelativeTime2(alert2.evaluated_at) })
|
|
49480
|
+
] }),
|
|
49481
|
+
/* @__PURE__ */ jsxs("p", { className: "text-[12px] font-medium text-[#475569] uppercase tracking-wide", children: [
|
|
49482
|
+
alert2.monitoring_mode === "uptime" ? "Uptime" : "Output",
|
|
49483
|
+
" regression"
|
|
49484
|
+
] }),
|
|
49485
|
+
/* @__PURE__ */ jsx("p", { className: "text-[13.5px] text-[#64748b] leading-[1.45] mt-1", children: description }),
|
|
49486
|
+
/* @__PURE__ */ jsxs("p", { className: "text-[12px] text-[#94a3b8] mt-2", children: [
|
|
49487
|
+
"Delta ",
|
|
49488
|
+
formatPercent(alert2.delta_efficiency),
|
|
49489
|
+
" across ",
|
|
49490
|
+
alert2.baseline_sample_size,
|
|
49491
|
+
" historical shifts"
|
|
49492
|
+
] })
|
|
49493
|
+
] })
|
|
49494
|
+
] })
|
|
49495
|
+
},
|
|
49496
|
+
alert2.id
|
|
49497
|
+
);
|
|
49498
|
+
})
|
|
49499
|
+
] })
|
|
49500
|
+
]
|
|
49501
|
+
}
|
|
49502
|
+
) }),
|
|
49503
|
+
document.body
|
|
49504
|
+
);
|
|
49505
|
+
};
|
|
49111
49506
|
var SideNavBar = memo$1(({
|
|
49112
49507
|
// These props are accepted but not used in this implementation
|
|
49113
49508
|
navItems = [],
|
|
@@ -49121,17 +49516,13 @@ var SideNavBar = memo$1(({
|
|
|
49121
49516
|
const router = useRouter();
|
|
49122
49517
|
const { navigate } = useNavigation();
|
|
49123
49518
|
const { signOut, user } = useAuth();
|
|
49519
|
+
const supabase = useSupabase();
|
|
49124
49520
|
const entityConfig = useEntityConfig();
|
|
49125
49521
|
const dashboardConfig = useDashboardConfig();
|
|
49126
49522
|
const isSuperAdmin = user?.scope_mode === "SUPER_ADMIN" || !!user?.access_scope?.is_super_admin;
|
|
49127
49523
|
const role = user?.role_level;
|
|
49128
|
-
const
|
|
49129
|
-
|
|
49130
|
-
owner: ["/", "/leaderboard", "/kpis", "/targets", "/shifts", "/supervisor-management", "/skus", "/help", "/health", "/profile", "/workspace", "/factory-view", "/team-management", "/tickets", "/improvement-center"],
|
|
49131
|
-
it: ["/", "/leaderboard", "/kpis", "/targets", "/shifts", "/supervisor-management", "/skus", "/help", "/health", "/profile", "/workspace", "/factory-view", "/team-management", "/tickets", "/improvement-center"],
|
|
49132
|
-
plant_head: ["/", "/leaderboard", "/kpis", "/targets", "/shifts", "/supervisor-management", "/skus", "/help", "/health", "/profile", "/workspace", "/factory-view", "/team-management", "/tickets", "/improvement-center"],
|
|
49133
|
-
supervisor: ["/", "/leaderboard", "/kpis", "/targets", "/shifts", "/skus", "/help", "/health", "/profile", "/workspace", "/tickets", "/improvement-center"]
|
|
49134
|
-
};
|
|
49524
|
+
const roleNavPaths = useMemo(() => getRoleNavPaths(role), [role]);
|
|
49525
|
+
const showLiveMonitorLink = roleNavPaths.includes("/live-monitor");
|
|
49135
49526
|
const getBasePath = useCallback((path) => {
|
|
49136
49527
|
const firstSegment = path.split("?")[0].split("/").filter(Boolean)[0];
|
|
49137
49528
|
return firstSegment ? `/${firstSegment}` : "/";
|
|
@@ -49140,9 +49531,8 @@ var SideNavBar = memo$1(({
|
|
|
49140
49531
|
if (!role) return false;
|
|
49141
49532
|
if (isSuperAdmin) return true;
|
|
49142
49533
|
const basePath = getBasePath(path);
|
|
49143
|
-
|
|
49144
|
-
|
|
49145
|
-
}, [role, isSuperAdmin, getBasePath]);
|
|
49534
|
+
return roleNavPaths.includes(basePath);
|
|
49535
|
+
}, [role, isSuperAdmin, getBasePath, roleNavPaths]);
|
|
49146
49536
|
const lineId = entityConfig.defaultLineId || LINE_1_UUID;
|
|
49147
49537
|
const skuEnabled = dashboardConfig?.skuConfig?.enabled || false;
|
|
49148
49538
|
dashboardConfig?.supervisorConfig?.enabled || false;
|
|
@@ -49183,6 +49573,17 @@ var SideNavBar = memo$1(({
|
|
|
49183
49573
|
});
|
|
49184
49574
|
onMobileMenuClose?.();
|
|
49185
49575
|
}, [navigate, onMobileMenuClose]);
|
|
49576
|
+
const handleLiveClick = useCallback(() => {
|
|
49577
|
+
navigate("/live-monitor", {
|
|
49578
|
+
trackingEvent: {
|
|
49579
|
+
name: "Live Monitor Clicked",
|
|
49580
|
+
properties: {
|
|
49581
|
+
source: "side_nav"
|
|
49582
|
+
}
|
|
49583
|
+
}
|
|
49584
|
+
});
|
|
49585
|
+
onMobileMenuClose?.();
|
|
49586
|
+
}, [navigate, onMobileMenuClose]);
|
|
49186
49587
|
const handleKPIsClick = useCallback(() => {
|
|
49187
49588
|
navigate(`/kpis`, {
|
|
49188
49589
|
trackingEvent: {
|
|
@@ -49318,6 +49719,37 @@ var SideNavBar = memo$1(({
|
|
|
49318
49719
|
}, [navigate, onMobileMenuClose]);
|
|
49319
49720
|
const [isSettingsOpen, setIsSettingsOpen] = useState(false);
|
|
49320
49721
|
const settingsTriggerRef = useRef(null);
|
|
49722
|
+
const [isAlertsOpen, setIsAlertsOpen] = useState(false);
|
|
49723
|
+
const [alertsCount, setAlertsCount] = useState(0);
|
|
49724
|
+
const alertsTriggerRef = useRef(null);
|
|
49725
|
+
const alertsCompanyId = entityConfig.companyId || user?.company_id;
|
|
49726
|
+
const showAlertsButton = (role === "supervisor" || role === "optifye") && !!alertsCompanyId && !!supabase;
|
|
49727
|
+
const refreshAlertsSummary = useCallback(async () => {
|
|
49728
|
+
if (!showAlertsButton || !supabase || !alertsCompanyId) {
|
|
49729
|
+
setAlertsCount(0);
|
|
49730
|
+
return;
|
|
49731
|
+
}
|
|
49732
|
+
try {
|
|
49733
|
+
const summary = await alertsService.getSummary(supabase, alertsCompanyId);
|
|
49734
|
+
setAlertsCount(summary?.total_current_alerts || 0);
|
|
49735
|
+
} catch (error) {
|
|
49736
|
+
console.error("Failed to fetch alerts summary:", error);
|
|
49737
|
+
setAlertsCount(0);
|
|
49738
|
+
}
|
|
49739
|
+
}, [alertsCompanyId, showAlertsButton, supabase]);
|
|
49740
|
+
useEffect(() => {
|
|
49741
|
+
if (!showAlertsButton) {
|
|
49742
|
+
setAlertsCount(0);
|
|
49743
|
+
return;
|
|
49744
|
+
}
|
|
49745
|
+
void refreshAlertsSummary();
|
|
49746
|
+
const intervalId = window.setInterval(() => {
|
|
49747
|
+
void refreshAlertsSummary();
|
|
49748
|
+
}, 5 * 60 * 1e3);
|
|
49749
|
+
return () => {
|
|
49750
|
+
window.clearInterval(intervalId);
|
|
49751
|
+
};
|
|
49752
|
+
}, [refreshAlertsSummary, showAlertsButton]);
|
|
49321
49753
|
const settingsItems = useMemo(() => {
|
|
49322
49754
|
const items = [
|
|
49323
49755
|
...canAccessPath("/targets") ? [{
|
|
@@ -49412,6 +49844,7 @@ var SideNavBar = memo$1(({
|
|
|
49412
49844
|
onMobileMenuClose?.();
|
|
49413
49845
|
}, [navigate, onMobileMenuClose]);
|
|
49414
49846
|
const homeButtonClasses = useMemo(() => getButtonClasses("/"), [getButtonClasses, pathname]);
|
|
49847
|
+
const liveButtonClasses = useMemo(() => getButtonClasses("/live-monitor"), [getButtonClasses, pathname]);
|
|
49415
49848
|
const leaderboardButtonClasses = useMemo(() => getButtonClasses("/leaderboard"), [getButtonClasses, pathname]);
|
|
49416
49849
|
const kpisButtonClasses = useMemo(() => getButtonClasses("/kpis"), [getButtonClasses, pathname]);
|
|
49417
49850
|
const improvementButtonClasses = useMemo(() => getButtonClasses("/improvement-center"), [getButtonClasses, pathname]);
|
|
@@ -49425,6 +49858,12 @@ var SideNavBar = memo$1(({
|
|
|
49425
49858
|
${isActive ? "bg-blue-50/80 text-blue-600 font-medium" : "hover:bg-gray-50 text-gray-500 hover:text-gray-700 font-medium active:bg-gray-100"}
|
|
49426
49859
|
transition-all duration-200 ease-out focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2`;
|
|
49427
49860
|
}, [isSettingsOpen, settingsItems]);
|
|
49861
|
+
const alertsButtonClasses = useMemo(() => {
|
|
49862
|
+
const isActive = isAlertsOpen;
|
|
49863
|
+
return `w-full flex flex-col items-center justify-center py-4 sm:py-3 px-2 sm:px-1 rounded-lg relative group min-h-[44px] sm:min-h-0
|
|
49864
|
+
${isActive ? "bg-blue-50/80 text-blue-600 font-medium" : "hover:bg-gray-50 text-gray-500 hover:text-gray-700 font-medium active:bg-gray-100"}
|
|
49865
|
+
transition-all duration-200 ease-out focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2`;
|
|
49866
|
+
}, [isAlertsOpen]);
|
|
49428
49867
|
const NavigationContent = () => /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
49429
49868
|
/* @__PURE__ */ jsx("div", { className: "w-full py-6 px-4 flex-shrink-0", children: /* @__PURE__ */ jsx(
|
|
49430
49869
|
"button",
|
|
@@ -49436,21 +49875,38 @@ var SideNavBar = memo$1(({
|
|
|
49436
49875
|
}
|
|
49437
49876
|
) }),
|
|
49438
49877
|
/* @__PURE__ */ jsxs("div", { className: "flex-1 w-full py-6 px-4 overflow-y-auto", children: [
|
|
49439
|
-
/* @__PURE__ */
|
|
49440
|
-
"
|
|
49441
|
-
|
|
49442
|
-
|
|
49443
|
-
|
|
49444
|
-
|
|
49445
|
-
|
|
49446
|
-
|
|
49447
|
-
|
|
49448
|
-
|
|
49449
|
-
|
|
49450
|
-
|
|
49451
|
-
|
|
49452
|
-
|
|
49453
|
-
|
|
49878
|
+
/* @__PURE__ */ jsxs("div", { className: "mb-6", children: [
|
|
49879
|
+
canAccessPath("/") && /* @__PURE__ */ jsxs(
|
|
49880
|
+
"button",
|
|
49881
|
+
{
|
|
49882
|
+
onClick: handleHomeClick,
|
|
49883
|
+
className: homeButtonClasses,
|
|
49884
|
+
"aria-label": "Home",
|
|
49885
|
+
tabIndex: 0,
|
|
49886
|
+
role: "tab",
|
|
49887
|
+
"aria-selected": pathname === "/" || pathname.startsWith("//"),
|
|
49888
|
+
children: [
|
|
49889
|
+
/* @__PURE__ */ jsx(HomeIcon, { className: "w-5 h-5 mb-1" }),
|
|
49890
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs sm:text-[10px] font-medium leading-tight", children: "Home" })
|
|
49891
|
+
]
|
|
49892
|
+
}
|
|
49893
|
+
),
|
|
49894
|
+
showLiveMonitorLink && canAccessPath("/live-monitor") && /* @__PURE__ */ jsxs(
|
|
49895
|
+
"button",
|
|
49896
|
+
{
|
|
49897
|
+
onClick: handleLiveClick,
|
|
49898
|
+
className: `${liveButtonClasses} mt-3`,
|
|
49899
|
+
"aria-label": "Monitor",
|
|
49900
|
+
tabIndex: 0,
|
|
49901
|
+
role: "tab",
|
|
49902
|
+
"aria-selected": pathname === "/live-monitor" || pathname.startsWith("/live-monitor/"),
|
|
49903
|
+
children: [
|
|
49904
|
+
/* @__PURE__ */ jsx(VideoCameraIcon, { className: "w-5 h-5 mb-1" }),
|
|
49905
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs sm:text-[10px] font-medium leading-tight", children: "Monitor" })
|
|
49906
|
+
]
|
|
49907
|
+
}
|
|
49908
|
+
)
|
|
49909
|
+
] }),
|
|
49454
49910
|
/* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
|
|
49455
49911
|
canAccessPath("/leaderboard") && /* @__PURE__ */ jsxs(
|
|
49456
49912
|
"button",
|
|
@@ -49530,22 +49986,55 @@ var SideNavBar = memo$1(({
|
|
|
49530
49986
|
)
|
|
49531
49987
|
] })
|
|
49532
49988
|
] }),
|
|
49533
|
-
|
|
49534
|
-
|
|
49535
|
-
|
|
49536
|
-
|
|
49537
|
-
|
|
49538
|
-
|
|
49539
|
-
|
|
49540
|
-
|
|
49541
|
-
|
|
49542
|
-
|
|
49543
|
-
|
|
49544
|
-
|
|
49545
|
-
|
|
49546
|
-
|
|
49547
|
-
|
|
49548
|
-
|
|
49989
|
+
/* @__PURE__ */ jsxs("div", { className: "w-full py-4 px-4 border-t border-gray-100 flex-shrink-0 flex flex-col gap-2", children: [
|
|
49990
|
+
showAlertsButton && /* @__PURE__ */ jsxs(
|
|
49991
|
+
"button",
|
|
49992
|
+
{
|
|
49993
|
+
ref: alertsTriggerRef,
|
|
49994
|
+
onClick: () => {
|
|
49995
|
+
setIsAlertsOpen(!isAlertsOpen);
|
|
49996
|
+
setIsSettingsOpen(false);
|
|
49997
|
+
if (!isAlertsOpen) {
|
|
49998
|
+
void refreshAlertsSummary();
|
|
49999
|
+
}
|
|
50000
|
+
},
|
|
50001
|
+
className: alertsButtonClasses,
|
|
50002
|
+
"aria-label": "Alerts",
|
|
50003
|
+
tabIndex: 0,
|
|
50004
|
+
role: "tab",
|
|
50005
|
+
"aria-selected": isAlertsOpen,
|
|
50006
|
+
children: [
|
|
50007
|
+
/* @__PURE__ */ jsxs("div", { className: "relative", children: [
|
|
50008
|
+
/* @__PURE__ */ jsx(BellIcon, { className: "w-5 h-5 mb-1" }),
|
|
50009
|
+
alertsCount > 0 && /* @__PURE__ */ jsxs("span", { className: "absolute -top-1 -right-1 flex h-2.5 w-2.5", children: [
|
|
50010
|
+
/* @__PURE__ */ jsx("span", { className: "animate-ping absolute inline-flex h-full w-full rounded-full bg-red-400 opacity-75" }),
|
|
50011
|
+
/* @__PURE__ */ jsx("span", { className: "relative inline-flex rounded-full h-2.5 w-2.5 bg-red-500" })
|
|
50012
|
+
] })
|
|
50013
|
+
] }),
|
|
50014
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs sm:text-[10px] font-medium leading-tight mt-1", children: "Alerts" })
|
|
50015
|
+
]
|
|
50016
|
+
}
|
|
50017
|
+
),
|
|
50018
|
+
settingsItems.length > 0 && /* @__PURE__ */ jsxs(
|
|
50019
|
+
"button",
|
|
50020
|
+
{
|
|
50021
|
+
ref: settingsTriggerRef,
|
|
50022
|
+
onClick: () => {
|
|
50023
|
+
setIsSettingsOpen(!isSettingsOpen);
|
|
50024
|
+
setIsAlertsOpen(false);
|
|
50025
|
+
},
|
|
50026
|
+
className: settingsButtonClasses,
|
|
50027
|
+
"aria-label": "Settings",
|
|
50028
|
+
tabIndex: 0,
|
|
50029
|
+
role: "tab",
|
|
50030
|
+
"aria-selected": isSettingsOpen || settingsItems.some((item) => item.isActive),
|
|
50031
|
+
children: [
|
|
50032
|
+
/* @__PURE__ */ jsx(Cog6ToothIcon, { className: "w-5 h-5 mb-1" }),
|
|
50033
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs sm:text-[10px] font-medium leading-tight", children: "Settings" })
|
|
50034
|
+
]
|
|
50035
|
+
}
|
|
50036
|
+
)
|
|
50037
|
+
] })
|
|
49549
50038
|
] });
|
|
49550
50039
|
const MobileNavigationContent = () => {
|
|
49551
50040
|
const isActive = (path) => {
|
|
@@ -49580,6 +50069,18 @@ var SideNavBar = memo$1(({
|
|
|
49580
50069
|
]
|
|
49581
50070
|
}
|
|
49582
50071
|
),
|
|
50072
|
+
showLiveMonitorLink && canAccessPath("/live-monitor") && /* @__PURE__ */ jsxs(
|
|
50073
|
+
"button",
|
|
50074
|
+
{
|
|
50075
|
+
onClick: handleMobileNavClick(handleLiveClick),
|
|
50076
|
+
className: `${getMobileButtonClass("/live-monitor")} mt-2`,
|
|
50077
|
+
"aria-label": "Monitor",
|
|
50078
|
+
children: [
|
|
50079
|
+
/* @__PURE__ */ jsx(VideoCameraIcon, { className: getIconClass("/live-monitor") }),
|
|
50080
|
+
/* @__PURE__ */ jsx("span", { className: "text-base font-medium", children: "Monitor" })
|
|
50081
|
+
]
|
|
50082
|
+
}
|
|
50083
|
+
),
|
|
49583
50084
|
/* @__PURE__ */ jsxs("div", { className: "mt-6 space-y-2", children: [
|
|
49584
50085
|
canAccessPath("/leaderboard") && /* @__PURE__ */ jsxs(
|
|
49585
50086
|
"button",
|
|
@@ -49643,9 +50144,31 @@ var SideNavBar = memo$1(({
|
|
|
49643
50144
|
}
|
|
49644
50145
|
)
|
|
49645
50146
|
] }),
|
|
49646
|
-
|
|
50147
|
+
/* @__PURE__ */ jsxs("div", { className: "mt-8 pt-6 border-t border-gray-100", children: [
|
|
49647
50148
|
/* @__PURE__ */ jsx("h3", { className: "px-5 mb-3 text-[10px] font-bold text-gray-400 uppercase tracking-widest", children: "Settings & Support" }),
|
|
49648
50149
|
/* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
|
|
50150
|
+
showAlertsButton && /* @__PURE__ */ jsxs(
|
|
50151
|
+
"button",
|
|
50152
|
+
{
|
|
50153
|
+
onClick: () => {
|
|
50154
|
+
setIsAlertsOpen(true);
|
|
50155
|
+
void refreshAlertsSummary();
|
|
50156
|
+
onMobileMenuClose?.();
|
|
50157
|
+
},
|
|
50158
|
+
className: getMobileButtonClass("/alerts"),
|
|
50159
|
+
"aria-label": "Alerts",
|
|
50160
|
+
children: [
|
|
50161
|
+
/* @__PURE__ */ jsxs("div", { className: "relative", children: [
|
|
50162
|
+
/* @__PURE__ */ jsx(BellIcon, { className: getIconClass("/alerts") }),
|
|
50163
|
+
alertsCount > 0 && /* @__PURE__ */ jsxs("span", { className: "absolute -top-1 -right-1 flex h-2.5 w-2.5", children: [
|
|
50164
|
+
/* @__PURE__ */ jsx("span", { className: "animate-ping absolute inline-flex h-full w-full rounded-full bg-red-400 opacity-75" }),
|
|
50165
|
+
/* @__PURE__ */ jsx("span", { className: "relative inline-flex rounded-full h-2.5 w-2.5 bg-red-500" })
|
|
50166
|
+
] })
|
|
50167
|
+
] }),
|
|
50168
|
+
/* @__PURE__ */ jsx("span", { className: "text-base font-medium ml-3", children: "Alerts" })
|
|
50169
|
+
]
|
|
50170
|
+
}
|
|
50171
|
+
),
|
|
49649
50172
|
canAccessPath("/targets") && /* @__PURE__ */ jsxs(
|
|
49650
50173
|
"button",
|
|
49651
50174
|
{
|
|
@@ -49760,7 +50283,18 @@ var SideNavBar = memo$1(({
|
|
|
49760
50283
|
] }),
|
|
49761
50284
|
/* @__PURE__ */ jsx("div", { className: "flex-1 overflow-y-auto", children: /* @__PURE__ */ jsx(MobileNavigationContent, {}) })
|
|
49762
50285
|
] })
|
|
49763
|
-
] })
|
|
50286
|
+
] }),
|
|
50287
|
+
/* @__PURE__ */ jsx(
|
|
50288
|
+
AlertsPopup,
|
|
50289
|
+
{
|
|
50290
|
+
isOpen: isAlertsOpen,
|
|
50291
|
+
onClose: () => setIsAlertsOpen(false),
|
|
50292
|
+
triggerRef: alertsTriggerRef,
|
|
50293
|
+
companyId: alertsCompanyId,
|
|
50294
|
+
alertsCount,
|
|
50295
|
+
onAlertsLoaded: setAlertsCount
|
|
50296
|
+
}
|
|
50297
|
+
)
|
|
49764
50298
|
] });
|
|
49765
50299
|
});
|
|
49766
50300
|
SideNavBar.displayName = "SideNavBar";
|
|
@@ -49937,7 +50471,7 @@ var AwardBadge = ({
|
|
|
49937
50471
|
}) => {
|
|
49938
50472
|
const styles2 = getBadgeStyles(type);
|
|
49939
50473
|
const Icon2 = CustomIcon || getDefaultIcon(type);
|
|
49940
|
-
const randomDelay =
|
|
50474
|
+
const randomDelay = React141__default.useMemo(() => Math.random() * 2, []);
|
|
49941
50475
|
const floatingAnimation = {
|
|
49942
50476
|
animate: {
|
|
49943
50477
|
y: [0, -10, 0],
|
|
@@ -51967,18 +52501,20 @@ var InviteUserDialog = ({
|
|
|
51967
52501
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
51968
52502
|
const [error, setError] = useState(null);
|
|
51969
52503
|
const isSuperAdminOptifye = user?.role_level === "optifye" && (user?.scope_mode === "SUPER_ADMIN" || !!user?.access_scope?.is_super_admin);
|
|
51970
|
-
const canInviteOwner = isSuperAdminOptifye;
|
|
51971
|
-
const canInviteIT = user?.role_level
|
|
51972
|
-
const canInvitePlantHead = user?.role_level
|
|
51973
|
-
const
|
|
52504
|
+
const canInviteOwner = canRoleInviteRole(user?.role_level, "owner", { isSuperAdminOptifye });
|
|
52505
|
+
const canInviteIT = canRoleInviteRole(user?.role_level, "it", { isSuperAdminOptifye });
|
|
52506
|
+
const canInvitePlantHead = canRoleInviteRole(user?.role_level, "plant_head", { isSuperAdminOptifye });
|
|
52507
|
+
const canInviteIndustrialEngineer = canRoleInviteRole(user?.role_level, "industrial_engineer", { isSuperAdminOptifye });
|
|
52508
|
+
const canInviteSupervisor = canRoleInviteRole(user?.role_level, "supervisor", { isSuperAdminOptifye });
|
|
51974
52509
|
const invitableRoles = useMemo(() => {
|
|
51975
52510
|
const roles = [];
|
|
51976
52511
|
if (canInviteOwner) roles.push("owner");
|
|
51977
52512
|
if (canInviteIT) roles.push("it");
|
|
51978
52513
|
if (canInvitePlantHead) roles.push("plant_head");
|
|
52514
|
+
if (canInviteIndustrialEngineer) roles.push("industrial_engineer");
|
|
51979
52515
|
if (canInviteSupervisor) roles.push("supervisor");
|
|
51980
52516
|
return roles;
|
|
51981
|
-
}, [canInviteOwner, canInviteIT, canInvitePlantHead, canInviteSupervisor]);
|
|
52517
|
+
}, [canInviteOwner, canInviteIT, canInvitePlantHead, canInviteIndustrialEngineer, canInviteSupervisor]);
|
|
51982
52518
|
const filteredLines = useMemo(() => {
|
|
51983
52519
|
const search = lineSearch.trim().toLowerCase();
|
|
51984
52520
|
if (!search) return availableLines;
|
|
@@ -52055,6 +52591,10 @@ var InviteUserDialog = ({
|
|
|
52055
52591
|
setError("Only super-admin Optifye users can create owner users.");
|
|
52056
52592
|
return;
|
|
52057
52593
|
}
|
|
52594
|
+
if (selectedRole === "industrial_engineer" && selectedFactories.length === 0) {
|
|
52595
|
+
setError("Select at least one factory for an industrial engineer.");
|
|
52596
|
+
return;
|
|
52597
|
+
}
|
|
52058
52598
|
const companyId = entityConfig?.companyId || user?.properties?.company_id;
|
|
52059
52599
|
if (!companyId) {
|
|
52060
52600
|
setError("Company ID not found. Please refresh and try again.");
|
|
@@ -52078,7 +52618,7 @@ var InviteUserDialog = ({
|
|
|
52078
52618
|
role_level: selectedRole,
|
|
52079
52619
|
company_id: companyId,
|
|
52080
52620
|
line_ids: selectedRole === "supervisor" ? selectedLines : void 0,
|
|
52081
|
-
factory_ids: selectedRole
|
|
52621
|
+
factory_ids: isFactoryScopedRole(selectedRole) ? selectedFactories : void 0,
|
|
52082
52622
|
created_by: user?.id
|
|
52083
52623
|
}
|
|
52084
52624
|
});
|
|
@@ -52316,6 +52856,33 @@ var InviteUserDialog = ({
|
|
|
52316
52856
|
]
|
|
52317
52857
|
}
|
|
52318
52858
|
),
|
|
52859
|
+
canInviteIndustrialEngineer && /* @__PURE__ */ jsxs(
|
|
52860
|
+
"label",
|
|
52861
|
+
{
|
|
52862
|
+
className: cn(
|
|
52863
|
+
"flex items-start gap-3 p-4 border-2 rounded-lg cursor-pointer transition-all duration-200",
|
|
52864
|
+
selectedRole === "industrial_engineer" ? "border-amber-500 bg-amber-50" : "border-gray-200 hover:border-gray-300 hover:bg-gray-50"
|
|
52865
|
+
),
|
|
52866
|
+
children: [
|
|
52867
|
+
/* @__PURE__ */ jsx(
|
|
52868
|
+
"input",
|
|
52869
|
+
{
|
|
52870
|
+
type: "radio",
|
|
52871
|
+
name: "role",
|
|
52872
|
+
value: "industrial_engineer",
|
|
52873
|
+
checked: selectedRole === "industrial_engineer",
|
|
52874
|
+
onChange: (e) => setSelectedRole(e.target.value),
|
|
52875
|
+
className: "mt-1",
|
|
52876
|
+
disabled: isSubmitting
|
|
52877
|
+
}
|
|
52878
|
+
),
|
|
52879
|
+
/* @__PURE__ */ jsxs("div", { className: "flex-1", children: [
|
|
52880
|
+
/* @__PURE__ */ jsx("div", { className: "flex items-center gap-2 mb-1", children: /* @__PURE__ */ jsx(RoleBadge_default, { role: "industrial_engineer", size: "sm" }) }),
|
|
52881
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm text-gray-600", children: "Factory-level access. Can manage supervisors and factory performance scope." })
|
|
52882
|
+
] })
|
|
52883
|
+
]
|
|
52884
|
+
}
|
|
52885
|
+
),
|
|
52319
52886
|
canInviteSupervisor && /* @__PURE__ */ jsxs(
|
|
52320
52887
|
"label",
|
|
52321
52888
|
{
|
|
@@ -52345,14 +52912,18 @@ var InviteUserDialog = ({
|
|
|
52345
52912
|
)
|
|
52346
52913
|
] })
|
|
52347
52914
|
] }),
|
|
52348
|
-
selectedRole
|
|
52915
|
+
isFactoryScopedRole(selectedRole) && /* @__PURE__ */ jsxs("div", { className: "rounded-xl border border-slate-200 bg-slate-50 p-4 space-y-3", children: [
|
|
52349
52916
|
/* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-3", children: [
|
|
52350
52917
|
/* @__PURE__ */ jsxs("div", { children: [
|
|
52351
52918
|
/* @__PURE__ */ jsxs("p", { className: "text-sm font-medium text-gray-800 flex items-center gap-1.5", children: [
|
|
52352
52919
|
/* @__PURE__ */ jsx(Building2, { className: "w-4 h-4 text-blue-600" }),
|
|
52353
52920
|
"Factory Access"
|
|
52354
52921
|
] }),
|
|
52355
|
-
/* @__PURE__ */
|
|
52922
|
+
/* @__PURE__ */ jsxs("p", { className: "text-xs text-gray-500 mt-1", children: [
|
|
52923
|
+
"Choose the factories this ",
|
|
52924
|
+
selectedRole === "industrial_engineer" ? "industrial engineer" : "plant head",
|
|
52925
|
+
" will manage."
|
|
52926
|
+
] })
|
|
52356
52927
|
] }),
|
|
52357
52928
|
/* @__PURE__ */ jsxs("span", { className: "text-xs font-medium bg-white border border-gray-200 text-gray-600 rounded-full px-2 py-1", children: [
|
|
52358
52929
|
selectedFactories.length,
|
|
@@ -52577,16 +53148,6 @@ var InviteUserDialog = ({
|
|
|
52577
53148
|
}
|
|
52578
53149
|
);
|
|
52579
53150
|
};
|
|
52580
|
-
var getRoleLabel = (role) => {
|
|
52581
|
-
const labels = {
|
|
52582
|
-
"supervisor": "Supervisor",
|
|
52583
|
-
"plant_head": "Plant Head",
|
|
52584
|
-
"it": "IT",
|
|
52585
|
-
"owner": "Owner",
|
|
52586
|
-
"optifye": "Optifye Admin"
|
|
52587
|
-
};
|
|
52588
|
-
return labels[role] || role;
|
|
52589
|
-
};
|
|
52590
53151
|
var ChangeRoleDialog = ({
|
|
52591
53152
|
user,
|
|
52592
53153
|
availableRoles,
|
|
@@ -53538,7 +54099,7 @@ var FactoryAssignmentDropdown = ({
|
|
|
53538
54099
|
)
|
|
53539
54100
|
] });
|
|
53540
54101
|
};
|
|
53541
|
-
function
|
|
54102
|
+
function formatDuration2(ms) {
|
|
53542
54103
|
if (ms === void 0 || ms === null) return "No data";
|
|
53543
54104
|
if (ms === 0) return "0m";
|
|
53544
54105
|
const hours = Math.floor(ms / (1e3 * 60 * 60));
|
|
@@ -53582,7 +54143,7 @@ var UserUsageStats = ({
|
|
|
53582
54143
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
|
|
53583
54144
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 text-sm", children: [
|
|
53584
54145
|
/* @__PURE__ */ jsx(Clock, { className: "w-3.5 h-3.5 text-gray-400" }),
|
|
53585
|
-
/* @__PURE__ */ jsx("span", { className: hasUsage ? getUsageColorClass(todayUsage.total_ms) : "text-gray-400", children:
|
|
54146
|
+
/* @__PURE__ */ jsx("span", { className: hasUsage ? getUsageColorClass(todayUsage.total_ms) : "text-gray-400", children: formatDuration2(todayUsage?.total_ms) })
|
|
53586
54147
|
] }),
|
|
53587
54148
|
showViewButton && onViewDetails && /* @__PURE__ */ jsx(
|
|
53588
54149
|
"button",
|
|
@@ -53598,14 +54159,14 @@ var UserUsageStats = ({
|
|
|
53598
54159
|
/* @__PURE__ */ jsx(Activity, { className: "w-3 h-3 text-green-500" }),
|
|
53599
54160
|
/* @__PURE__ */ jsxs("span", { children: [
|
|
53600
54161
|
"Active: ",
|
|
53601
|
-
|
|
54162
|
+
formatDuration2(todayUsage?.active_ms)
|
|
53602
54163
|
] })
|
|
53603
54164
|
] }),
|
|
53604
54165
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
|
|
53605
54166
|
/* @__PURE__ */ jsx(Eye, { className: "w-3 h-3 text-amber-500" }),
|
|
53606
54167
|
/* @__PURE__ */ jsxs("span", { children: [
|
|
53607
54168
|
"Passive: ",
|
|
53608
|
-
|
|
54169
|
+
formatDuration2(todayUsage?.passive_ms)
|
|
53609
54170
|
] })
|
|
53610
54171
|
] })
|
|
53611
54172
|
] })
|
|
@@ -53800,7 +54361,7 @@ function DailyBarChart({
|
|
|
53800
54361
|
/* @__PURE__ */ jsx("div", { className: "w-2 h-2 rounded-full bg-gray-300" }),
|
|
53801
54362
|
/* @__PURE__ */ jsxs("span", { className: "text-sm font-medium text-gray-600", children: [
|
|
53802
54363
|
"Average Daily usage: ",
|
|
53803
|
-
/* @__PURE__ */ jsx("span", { className: "text-gray-900 font-semibold", children: avgDailyMs > 0 ?
|
|
54364
|
+
/* @__PURE__ */ jsx("span", { className: "text-gray-900 font-semibold", children: avgDailyMs > 0 ? formatDuration2(avgDailyMs) : "0m" })
|
|
53804
54365
|
] })
|
|
53805
54366
|
] }),
|
|
53806
54367
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-6 text-xs font-medium text-gray-500", children: [
|
|
@@ -53893,7 +54454,7 @@ function DailyBarChart({
|
|
|
53893
54454
|
hasData ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
53894
54455
|
/* @__PURE__ */ jsxs("div", { className: "flex justify-between items-center mb-2", children: [
|
|
53895
54456
|
/* @__PURE__ */ jsx("span", { className: "text-gray-500 text-xs", children: "Total" }),
|
|
53896
|
-
/* @__PURE__ */ jsx("span", { className: "font-medium text-gray-900 text-sm", children:
|
|
54457
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium text-gray-900 text-sm", children: formatDuration2(data.total_duration_ms) })
|
|
53897
54458
|
] }),
|
|
53898
54459
|
/* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
|
|
53899
54460
|
/* @__PURE__ */ jsxs("div", { className: "flex justify-between items-center text-xs", children: [
|
|
@@ -53901,14 +54462,14 @@ function DailyBarChart({
|
|
|
53901
54462
|
/* @__PURE__ */ jsx("div", { className: "w-1.5 h-1.5 bg-green-500 rounded-full" }),
|
|
53902
54463
|
"Active"
|
|
53903
54464
|
] }),
|
|
53904
|
-
/* @__PURE__ */ jsx("span", { className: "font-medium text-gray-700", children:
|
|
54465
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium text-gray-700", children: formatDuration2(data.active_duration_ms) })
|
|
53905
54466
|
] }),
|
|
53906
54467
|
/* @__PURE__ */ jsxs("div", { className: "flex justify-between items-center text-xs", children: [
|
|
53907
54468
|
/* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1.5 text-gray-500", children: [
|
|
53908
54469
|
/* @__PURE__ */ jsx("div", { className: "w-1.5 h-1.5 bg-amber-400 rounded-full" }),
|
|
53909
54470
|
"Passive"
|
|
53910
54471
|
] }),
|
|
53911
|
-
/* @__PURE__ */ jsx("span", { className: "font-medium text-gray-700", children:
|
|
54472
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium text-gray-700", children: formatDuration2(data.passive_duration_ms) })
|
|
53912
54473
|
] })
|
|
53913
54474
|
] })
|
|
53914
54475
|
] }) : /* @__PURE__ */ jsx("div", { className: "text-gray-400 text-xs italic", children: "No data recorded" })
|
|
@@ -54039,15 +54600,7 @@ var UserManagementTable = ({
|
|
|
54039
54600
|
const permissions = useTeamManagementPermissions();
|
|
54040
54601
|
const { user: currentUser } = useAuth();
|
|
54041
54602
|
const availableRoles = useMemo(() => {
|
|
54042
|
-
|
|
54043
|
-
const roleHierarchy = {
|
|
54044
|
-
"optifye": ["optifye", "owner", "it", "plant_head", "supervisor"],
|
|
54045
|
-
"owner": ["owner", "it", "plant_head", "supervisor"],
|
|
54046
|
-
"it": ["it", "plant_head", "supervisor"],
|
|
54047
|
-
"plant_head": ["plant_head", "supervisor"],
|
|
54048
|
-
"supervisor": ["supervisor"]
|
|
54049
|
-
};
|
|
54050
|
-
return roleHierarchy[currentRole] || ["supervisor"];
|
|
54603
|
+
return getVisibleRolesForCurrentUser(currentUser?.role_level);
|
|
54051
54604
|
}, [currentUser]);
|
|
54052
54605
|
const [searchTerm, setSearchTerm] = useState("");
|
|
54053
54606
|
const [roleFilter, setRoleFilter] = useState("all");
|
|
@@ -54144,10 +54697,48 @@ var UserManagementTable = ({
|
|
|
54144
54697
|
}
|
|
54145
54698
|
return [];
|
|
54146
54699
|
};
|
|
54700
|
+
const getLineIdsFromUser = (user) => {
|
|
54701
|
+
const properties = user.properties || {};
|
|
54702
|
+
const rawLineIds = properties.line_ids ?? properties.line_id;
|
|
54703
|
+
if (Array.isArray(rawLineIds)) {
|
|
54704
|
+
return rawLineIds.filter((lineId) => typeof lineId === "string" && lineId.length > 0);
|
|
54705
|
+
}
|
|
54706
|
+
if (typeof rawLineIds === "string" && rawLineIds.length > 0) {
|
|
54707
|
+
return [rawLineIds];
|
|
54708
|
+
}
|
|
54709
|
+
return [];
|
|
54710
|
+
};
|
|
54711
|
+
const canOfferIndustrialEngineerRole = (user) => {
|
|
54712
|
+
if (getFactoryIdsFromUser(user).length > 0) {
|
|
54713
|
+
return true;
|
|
54714
|
+
}
|
|
54715
|
+
const lineIds = getLineIdsFromUser(user);
|
|
54716
|
+
if (lineIds.length === 0) {
|
|
54717
|
+
return false;
|
|
54718
|
+
}
|
|
54719
|
+
const lineFactoryById = new Map(
|
|
54720
|
+
availableLines.map((line) => [line.id, line.factory_id])
|
|
54721
|
+
);
|
|
54722
|
+
return lineIds.some((lineId) => {
|
|
54723
|
+
const factoryId = lineFactoryById.get(lineId);
|
|
54724
|
+
return typeof factoryId === "string" && factoryId.length > 0;
|
|
54725
|
+
});
|
|
54726
|
+
};
|
|
54727
|
+
const getAvailableRolesForUser = (user) => {
|
|
54728
|
+
const baseRoles = permissions.availableRolesToAssign();
|
|
54729
|
+
let filteredRoles = baseRoles;
|
|
54730
|
+
if (baseRoles.includes("industrial_engineer") && !canOfferIndustrialEngineerRole(user)) {
|
|
54731
|
+
filteredRoles = baseRoles.filter((role) => role !== "industrial_engineer");
|
|
54732
|
+
}
|
|
54733
|
+
if (!filteredRoles.includes(user.role_level)) {
|
|
54734
|
+
return [user.role_level, ...filteredRoles];
|
|
54735
|
+
}
|
|
54736
|
+
return filteredRoles;
|
|
54737
|
+
};
|
|
54147
54738
|
const formatAssignments = (user) => {
|
|
54148
54739
|
if (user.role_level === "owner" || user.role_level === "it") return "Company-wide";
|
|
54149
54740
|
if (user.role_level === "optifye") return "All companies";
|
|
54150
|
-
if (user.role_level
|
|
54741
|
+
if (isFactoryScopedRole(user.role_level)) {
|
|
54151
54742
|
if (user.assigned_factories && user.assigned_factories.length > 0) {
|
|
54152
54743
|
return user.assigned_factories.join(", ");
|
|
54153
54744
|
}
|
|
@@ -54228,11 +54819,12 @@ var UserManagementTable = ({
|
|
|
54228
54819
|
className: "px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent bg-white",
|
|
54229
54820
|
children: [
|
|
54230
54821
|
/* @__PURE__ */ jsx("option", { value: "all", children: "All Roles" }),
|
|
54231
|
-
availableRoles.includes("optifye") && /* @__PURE__ */ jsx("option", { value: "optifye", children: "
|
|
54232
|
-
availableRoles.includes("owner") && /* @__PURE__ */ jsx("option", { value: "owner", children: "
|
|
54233
|
-
availableRoles.includes("it") && /* @__PURE__ */ jsx("option", { value: "it", children: "
|
|
54234
|
-
availableRoles.includes("plant_head") && /* @__PURE__ */ jsx("option", { value: "plant_head", children: "
|
|
54235
|
-
availableRoles.includes("
|
|
54822
|
+
availableRoles.includes("optifye") && /* @__PURE__ */ jsx("option", { value: "optifye", children: getRoleLabel("optifye") }),
|
|
54823
|
+
availableRoles.includes("owner") && /* @__PURE__ */ jsx("option", { value: "owner", children: getRoleLabel("owner") }),
|
|
54824
|
+
availableRoles.includes("it") && /* @__PURE__ */ jsx("option", { value: "it", children: getRoleLabel("it") }),
|
|
54825
|
+
availableRoles.includes("plant_head") && /* @__PURE__ */ jsx("option", { value: "plant_head", children: getRoleLabel("plant_head") }),
|
|
54826
|
+
availableRoles.includes("industrial_engineer") && /* @__PURE__ */ jsx("option", { value: "industrial_engineer", children: getRoleLabel("industrial_engineer") }),
|
|
54827
|
+
availableRoles.includes("supervisor") && /* @__PURE__ */ jsx("option", { value: "supervisor", children: getRoleLabel("supervisor") })
|
|
54236
54828
|
]
|
|
54237
54829
|
}
|
|
54238
54830
|
)
|
|
@@ -54350,7 +54942,7 @@ var UserManagementTable = ({
|
|
|
54350
54942
|
onUpdate: onLineAssignmentUpdate || (async () => {
|
|
54351
54943
|
})
|
|
54352
54944
|
}
|
|
54353
|
-
) : user.role_level
|
|
54945
|
+
) : isFactoryScopedRole(user.role_level) ? (() => {
|
|
54354
54946
|
const canEditFactoryAssignments = permissions.canAssignFactories(user) && !!onFactoryAssignmentUpdate;
|
|
54355
54947
|
if (!canEditFactoryAssignments) {
|
|
54356
54948
|
return /* @__PURE__ */ jsx("p", { className: "text-sm text-gray-900", children: formatAssignments(user) });
|
|
@@ -54380,7 +54972,7 @@ var UserManagementTable = ({
|
|
|
54380
54972
|
setShowUsageDetailModal(true);
|
|
54381
54973
|
},
|
|
54382
54974
|
className: "group flex items-center gap-3 hover:bg-gray-50 -mx-2 px-2 py-1.5 rounded-lg transition-all duration-200",
|
|
54383
|
-
children: isUsageLoading ? /* @__PURE__ */ jsx("div", { className: "animate-pulse bg-gray-200 h-5 w-20 rounded" }) : /* @__PURE__ */ jsx("span", { className: `text-base font-semibold ${avgDailyUsage?.[user.user_id] && avgDailyUsage[user.user_id] > 0 ? "text-gray-900 group-hover:text-blue-600" : "text-gray-400"} transition-colors`, children:
|
|
54975
|
+
children: isUsageLoading ? /* @__PURE__ */ jsx("div", { className: "animate-pulse bg-gray-200 h-5 w-20 rounded" }) : /* @__PURE__ */ jsx("span", { className: `text-base font-semibold ${avgDailyUsage?.[user.user_id] && avgDailyUsage[user.user_id] > 0 ? "text-gray-900 group-hover:text-blue-600" : "text-gray-400"} transition-colors`, children: formatDuration2(avgDailyUsage?.[user.user_id] || 0) })
|
|
54384
54976
|
}
|
|
54385
54977
|
) : /* @__PURE__ */ jsx("span", { className: "text-sm text-gray-400", children: "-" }) }),
|
|
54386
54978
|
/* @__PURE__ */ jsx("td", { className: "px-6 py-4 whitespace-nowrap text-right", children: hasActions && /* @__PURE__ */ jsx("div", { className: "relative", children: /* @__PURE__ */ jsx(
|
|
@@ -54530,7 +55122,7 @@ var UserManagementTable = ({
|
|
|
54530
55122
|
ChangeRoleDialog,
|
|
54531
55123
|
{
|
|
54532
55124
|
user: selectedUser,
|
|
54533
|
-
availableRoles:
|
|
55125
|
+
availableRoles: getAvailableRolesForUser(selectedUser),
|
|
54534
55126
|
onConfirm: handleRoleChangeConfirm,
|
|
54535
55127
|
onClose: () => {
|
|
54536
55128
|
setShowChangeRoleDialog(false);
|
|
@@ -56269,7 +56861,7 @@ function HomeView({
|
|
|
56269
56861
|
animate: { opacity: 1, scale: 1 },
|
|
56270
56862
|
transition: { duration: 0.3 },
|
|
56271
56863
|
className: "h-full",
|
|
56272
|
-
children:
|
|
56864
|
+
children: React141__default.createElement(WorkspaceGrid, {
|
|
56273
56865
|
workspaces: workspaceMetrics,
|
|
56274
56866
|
lineNames,
|
|
56275
56867
|
factoryView: factoryViewId,
|
|
@@ -56300,7 +56892,7 @@ function HomeView({
|
|
|
56300
56892
|
animate: { opacity: 1, scale: 1 },
|
|
56301
56893
|
transition: { duration: 0.3 },
|
|
56302
56894
|
className: "h-full",
|
|
56303
|
-
children:
|
|
56895
|
+
children: React141__default.createElement(WorkspaceGrid, {
|
|
56304
56896
|
workspaces: [],
|
|
56305
56897
|
// Show empty grid while loading
|
|
56306
56898
|
lineNames,
|
|
@@ -56367,7 +56959,7 @@ function HomeView({
|
|
|
56367
56959
|
}
|
|
56368
56960
|
);
|
|
56369
56961
|
}
|
|
56370
|
-
var AuthenticatedHomeView = withAuth(
|
|
56962
|
+
var AuthenticatedHomeView = withAuth(React141__default.memo(HomeView));
|
|
56371
56963
|
var HomeView_default = HomeView;
|
|
56372
56964
|
function withWorkspaceDisplayNames(Component3, options = {}) {
|
|
56373
56965
|
const {
|
|
@@ -56777,7 +57369,7 @@ var MonthlyRangeFilter = ({
|
|
|
56777
57369
|
label: "This Month",
|
|
56778
57370
|
getValue: () => ({
|
|
56779
57371
|
start: startOfMonth(/* @__PURE__ */ new Date()),
|
|
56780
|
-
end:
|
|
57372
|
+
end: endOfDay(/* @__PURE__ */ new Date())
|
|
56781
57373
|
})
|
|
56782
57374
|
}
|
|
56783
57375
|
];
|
|
@@ -56801,6 +57393,7 @@ var MonthlyRangeFilter = ({
|
|
|
56801
57393
|
const [rangeEnd, setRangeEnd] = useState(parseDateKeyToDate(normalizedRange.endKey));
|
|
56802
57394
|
const [selecting, setSelecting] = useState(false);
|
|
56803
57395
|
const [activePreset, setActivePreset] = useState(null);
|
|
57396
|
+
const today = useMemo(() => endOfDay(/* @__PURE__ */ new Date()), []);
|
|
56804
57397
|
useEffect(() => {
|
|
56805
57398
|
setCalendarMonth(month);
|
|
56806
57399
|
setCalendarYear(year);
|
|
@@ -56831,6 +57424,9 @@ var MonthlyRangeFilter = ({
|
|
|
56831
57424
|
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
56832
57425
|
}, []);
|
|
56833
57426
|
const handleDayClick = (day) => {
|
|
57427
|
+
if (startOfDay(day) > startOfDay(today)) {
|
|
57428
|
+
return;
|
|
57429
|
+
}
|
|
56834
57430
|
setActivePreset("Custom");
|
|
56835
57431
|
if (!selecting || !rangeStart) {
|
|
56836
57432
|
setRangeStart(day);
|
|
@@ -56863,9 +57459,13 @@ var MonthlyRangeFilter = ({
|
|
|
56863
57459
|
};
|
|
56864
57460
|
const handleApply = () => {
|
|
56865
57461
|
if (rangeStart) {
|
|
56866
|
-
const
|
|
56867
|
-
const
|
|
56868
|
-
const
|
|
57462
|
+
const boundedStart = startOfDay(rangeStart) > startOfDay(today) ? startOfDay(today) : startOfDay(rangeStart);
|
|
57463
|
+
const candidateEnd = rangeEnd || rangeStart;
|
|
57464
|
+
const boundedEnd = startOfDay(candidateEnd) > startOfDay(today) ? startOfDay(today) : startOfDay(candidateEnd);
|
|
57465
|
+
const start = boundedStart <= boundedEnd ? boundedStart : boundedEnd;
|
|
57466
|
+
const end = boundedStart <= boundedEnd ? boundedEnd : boundedStart;
|
|
57467
|
+
const startKey = format(start, "yyyy-MM-dd");
|
|
57468
|
+
const endKey = format(end, "yyyy-MM-dd");
|
|
56869
57469
|
onChange({ startKey, endKey });
|
|
56870
57470
|
setIsOpen(false);
|
|
56871
57471
|
}
|
|
@@ -57046,6 +57646,7 @@ var MonthlyRangeFilter = ({
|
|
|
57046
57646
|
const isEnd = isRangeEnd(day);
|
|
57047
57647
|
const isSingleDaySelection = isStart && (!rangeEnd || rangeEnd && isSameDay(rangeStart, rangeEnd));
|
|
57048
57648
|
const dayNum = day.getDate();
|
|
57649
|
+
const isFutureDay = startOfDay(day) > startOfDay(today);
|
|
57049
57650
|
return /* @__PURE__ */ jsxs("div", { className: "relative", children: [
|
|
57050
57651
|
inRange && !isStart && !isEnd && /* @__PURE__ */ jsx("div", { className: "absolute inset-y-0 -inset-x-0.5 bg-[#EEF2FF] z-0" }),
|
|
57051
57652
|
inRange && isStart && !isSingleDaySelection && /* @__PURE__ */ jsx("div", { className: "absolute inset-y-0 right-0 left-1/2 bg-[#EEF2FF] z-0" }),
|
|
@@ -57055,10 +57656,12 @@ var MonthlyRangeFilter = ({
|
|
|
57055
57656
|
{
|
|
57056
57657
|
type: "button",
|
|
57057
57658
|
onClick: () => handleDayClick(day),
|
|
57659
|
+
disabled: isFutureDay,
|
|
57058
57660
|
className: clsx(
|
|
57059
57661
|
"h-10 w-full flex items-center justify-center text-sm font-semibold transition-all duration-150 relative z-10",
|
|
57662
|
+
isFutureDay && "text-gray-200 cursor-not-allowed",
|
|
57060
57663
|
// Not in range
|
|
57061
|
-
!inRange && "text-gray-700 hover:bg-gray-50 rounded-lg",
|
|
57664
|
+
!isFutureDay && !inRange && "text-gray-700 hover:bg-gray-50 rounded-lg",
|
|
57062
57665
|
// Middle of range
|
|
57063
57666
|
inRange && !isStart && !isEnd && "text-[#4F46E5]",
|
|
57064
57667
|
// Start/End of range or Single selection
|
|
@@ -57096,7 +57699,7 @@ var MetricCards = memo$1(({
|
|
|
57096
57699
|
variants: containerVariants,
|
|
57097
57700
|
initial: "initial",
|
|
57098
57701
|
animate: "animate",
|
|
57099
|
-
className: `grid grid-cols-1 sm:grid-cols-2 ${showIdleTime ? "lg:grid-cols-4" : "lg:grid-cols-3"} gap-3 sm:gap-4 mb-2
|
|
57702
|
+
className: `grid grid-cols-1 sm:grid-cols-2 ${showIdleTime ? "lg:grid-cols-4" : "lg:grid-cols-3"} gap-3 sm:gap-4 mb-2 h-auto lg:flex-[2] lg:min-h-[250px]`,
|
|
57100
57703
|
children: [
|
|
57101
57704
|
/* @__PURE__ */ jsxs(motion.div, { variants: itemVariants, className: "bg-white rounded-xl shadow-sm p-3 sm:p-4 overflow-hidden h-[240px] sm:h-[260px] md:h-auto", children: [
|
|
57102
57705
|
/* @__PURE__ */ jsx("h2", { className: "text-sm sm:text-base font-bold text-gray-700 mb-2 text-center", children: "Line Output" }),
|
|
@@ -57145,7 +57748,23 @@ var MetricCards = memo$1(({
|
|
|
57145
57748
|
if (prevProps.efficiencyLegend !== nextProps.efficiencyLegend) return false;
|
|
57146
57749
|
const prevMetrics = prevProps.lineInfo.metrics;
|
|
57147
57750
|
const nextMetrics = nextProps.lineInfo.metrics;
|
|
57148
|
-
const
|
|
57751
|
+
const prevIdleChartSignature = JSON.stringify(
|
|
57752
|
+
(prevProps.idleTimeData?.chartData || []).map((entry) => ({
|
|
57753
|
+
name: entry.name,
|
|
57754
|
+
value: entry.value,
|
|
57755
|
+
totalDurationSeconds: entry.totalDurationSeconds ?? null,
|
|
57756
|
+
efficiencyLossPercentage: entry.efficiencyLossPercentage ?? null
|
|
57757
|
+
}))
|
|
57758
|
+
);
|
|
57759
|
+
const nextIdleChartSignature = JSON.stringify(
|
|
57760
|
+
(nextProps.idleTimeData?.chartData || []).map((entry) => ({
|
|
57761
|
+
name: entry.name,
|
|
57762
|
+
value: entry.value,
|
|
57763
|
+
totalDurationSeconds: entry.totalDurationSeconds ?? null,
|
|
57764
|
+
efficiencyLossPercentage: entry.efficiencyLossPercentage ?? null
|
|
57765
|
+
}))
|
|
57766
|
+
);
|
|
57767
|
+
const idleTimeChanged = prevProps.idleTimeData?.isLoading !== nextProps.idleTimeData?.isLoading || prevProps.idleTimeData?.error !== nextProps.idleTimeData?.error || prevIdleChartSignature !== nextIdleChartSignature || prevProps.idleTimeData?.data?.total_idle_time_seconds !== nextProps.idleTimeData?.data?.total_idle_time_seconds || prevProps.idleTimeData?.data?.scope_work_seconds !== nextProps.idleTimeData?.data?.scope_work_seconds;
|
|
57149
57768
|
if (idleTimeChanged) return false;
|
|
57150
57769
|
return prevMetrics.current_output === nextMetrics.current_output && prevMetrics.line_threshold === nextMetrics.line_threshold && prevMetrics.underperforming_workspaces === nextMetrics.underperforming_workspaces && prevMetrics.total_workspaces === nextMetrics.total_workspaces && prevMetrics.avg_efficiency === nextMetrics.avg_efficiency;
|
|
57151
57770
|
});
|
|
@@ -57164,7 +57783,7 @@ var LineUptimeMetricCards = memo$1(({
|
|
|
57164
57783
|
variants: containerVariants,
|
|
57165
57784
|
initial: "initial",
|
|
57166
57785
|
animate: "animate",
|
|
57167
|
-
className: `grid grid-cols-1 sm:grid-cols-2 ${showIdleTime ? "lg:grid-cols-4" : "lg:grid-cols-3"} gap-3 sm:gap-4 mb-2
|
|
57786
|
+
className: `grid grid-cols-1 sm:grid-cols-2 ${showIdleTime ? "lg:grid-cols-4" : "lg:grid-cols-3"} gap-3 sm:gap-4 mb-2 h-auto lg:flex-[2] lg:min-h-[250px]`,
|
|
57168
57787
|
children: [
|
|
57169
57788
|
/* @__PURE__ */ jsxs(motion.div, { variants: itemVariants, className: "bg-white rounded-xl shadow-sm p-3 sm:p-4 overflow-hidden h-[240px] sm:h-[260px] md:h-auto", children: [
|
|
57170
57789
|
/* @__PURE__ */ jsx("h2", { className: "text-sm sm:text-base font-bold text-gray-700 mb-2 text-center", children: "Utilization" }),
|
|
@@ -57232,7 +57851,7 @@ var BottomSection = memo$1(({
|
|
|
57232
57851
|
variants: containerVariants,
|
|
57233
57852
|
initial: "initial",
|
|
57234
57853
|
animate: "animate",
|
|
57235
|
-
className: "grid grid-cols-1 lg:grid-cols-5 gap-3 sm:gap-4
|
|
57854
|
+
className: "grid grid-cols-1 lg:grid-cols-5 gap-3 sm:gap-4 h-auto mt-4 lg:mt-0 lg:flex-[3] lg:min-h-[300px]",
|
|
57236
57855
|
children: [
|
|
57237
57856
|
/* @__PURE__ */ jsxs(motion.div, { variants: itemVariants, className: "lg:col-span-2 bg-white rounded-xl shadow-sm p-3 sm:p-4 flex flex-col overflow-hidden h-[350px] sm:h-[400px] md:h-auto", children: [
|
|
57238
57857
|
/* @__PURE__ */ jsxs("div", { className: "flex justify-between items-center mb-2", children: [
|
|
@@ -57399,7 +58018,7 @@ var UptimeBottomSection = memo$1(({
|
|
|
57399
58018
|
variants: containerVariants,
|
|
57400
58019
|
initial: "initial",
|
|
57401
58020
|
animate: "animate",
|
|
57402
|
-
className: "grid grid-cols-1 lg:grid-cols-5 gap-3 sm:gap-4
|
|
58021
|
+
className: "grid grid-cols-1 lg:grid-cols-5 gap-3 sm:gap-4 h-auto mt-4 lg:mt-0 lg:flex-[3] lg:min-h-[300px]",
|
|
57403
58022
|
children: [
|
|
57404
58023
|
/* @__PURE__ */ jsxs(motion.div, { variants: itemVariants, className: "lg:col-span-2 bg-white rounded-xl shadow-sm p-3 sm:p-4 flex flex-col overflow-hidden h-[350px] sm:h-[400px] md:h-auto", children: [
|
|
57405
58024
|
/* @__PURE__ */ jsxs("div", { className: "flex justify-between items-center mb-2", children: [
|
|
@@ -58637,7 +59256,7 @@ var KPIDetailView = ({
|
|
|
58637
59256
|
initial: "initial",
|
|
58638
59257
|
animate: "animate",
|
|
58639
59258
|
exit: "exit",
|
|
58640
|
-
className: "space-y-6 md:space-y-0",
|
|
59259
|
+
className: "space-y-6 md:space-y-0 lg:h-[calc(100vh-12rem)] lg:min-h-0 lg:flex lg:flex-col lg:gap-3",
|
|
58641
59260
|
children: resolvedLineInfo && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
58642
59261
|
isUptimeMode ? /* @__PURE__ */ jsx(
|
|
58643
59262
|
LineUptimeMetricCards,
|
|
@@ -58734,7 +59353,7 @@ var KPIDetailView = ({
|
|
|
58734
59353
|
initial: "initial",
|
|
58735
59354
|
animate: "animate",
|
|
58736
59355
|
exit: "exit",
|
|
58737
|
-
className: "space-y-6 md:space-y-0",
|
|
59356
|
+
className: "space-y-6 md:space-y-0 lg:h-[calc(100vh-12rem)] lg:min-h-0 lg:flex lg:flex-col lg:gap-3",
|
|
58738
59357
|
children: resolvedLineInfo && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
58739
59358
|
isUptimeMode ? /* @__PURE__ */ jsx(
|
|
58740
59359
|
LineUptimeMetricCards,
|
|
@@ -58829,7 +59448,7 @@ var getMonthDateInfo = (timezone) => {
|
|
|
58829
59448
|
const monthEndDate = fromZonedTime(`${monthEndKey}T23:59:59`, timezone);
|
|
58830
59449
|
return { startDate, endDate, monthEndDate };
|
|
58831
59450
|
};
|
|
58832
|
-
var LeaderboardCountdown = ({ targetDate, format:
|
|
59451
|
+
var LeaderboardCountdown = ({ targetDate, format: format8, finishedLabel = "Finished", placeholder = "--", onFinished }) => {
|
|
58833
59452
|
const [time2, setTime] = useState("");
|
|
58834
59453
|
const hasFinishedRef = useRef(false);
|
|
58835
59454
|
useEffect(() => {
|
|
@@ -58851,7 +59470,7 @@ var LeaderboardCountdown = ({ targetDate, format: format7, finishedLabel = "Fini
|
|
|
58851
59470
|
}
|
|
58852
59471
|
return;
|
|
58853
59472
|
}
|
|
58854
|
-
if (
|
|
59473
|
+
if (format8 === "days") {
|
|
58855
59474
|
const days = Math.floor(diff / (1e3 * 60 * 60 * 24));
|
|
58856
59475
|
const hours = Math.floor(diff % (1e3 * 60 * 60 * 24) / (1e3 * 60 * 60));
|
|
58857
59476
|
setTime(`${days} days ${hours} hours`);
|
|
@@ -58866,7 +59485,7 @@ var LeaderboardCountdown = ({ targetDate, format: format7, finishedLabel = "Fini
|
|
|
58866
59485
|
tick();
|
|
58867
59486
|
const interval = setInterval(tick, 1e3);
|
|
58868
59487
|
return () => clearInterval(interval);
|
|
58869
|
-
}, [targetDate,
|
|
59488
|
+
}, [targetDate, format8, finishedLabel, placeholder, onFinished]);
|
|
58870
59489
|
return /* @__PURE__ */ jsx(Fragment, { children: time2 });
|
|
58871
59490
|
};
|
|
58872
59491
|
var LinesLeaderboard = ({
|
|
@@ -58887,18 +59506,18 @@ var LinesLeaderboard = ({
|
|
|
58887
59506
|
setViewType
|
|
58888
59507
|
}) => {
|
|
58889
59508
|
const formatEfficiency = (value) => typeof value === "number" && Number.isFinite(value) ? `${value.toFixed(1)}%` : "--";
|
|
58890
|
-
const assignedLineIdSet =
|
|
59509
|
+
const assignedLineIdSet = React141__default.useMemo(
|
|
58891
59510
|
() => new Set(assignedLineIds || []),
|
|
58892
59511
|
[assignedLineIds]
|
|
58893
59512
|
);
|
|
58894
|
-
const canClickLine =
|
|
59513
|
+
const canClickLine = React141__default.useCallback(
|
|
58895
59514
|
(lineId) => {
|
|
58896
59515
|
if (!assignedLineIds) return true;
|
|
58897
59516
|
return assignedLineIdSet.has(lineId);
|
|
58898
59517
|
},
|
|
58899
59518
|
[assignedLineIds, assignedLineIdSet]
|
|
58900
59519
|
);
|
|
58901
|
-
const handleTimeRangeChange =
|
|
59520
|
+
const handleTimeRangeChange = React141__default.useCallback((newRange) => {
|
|
58902
59521
|
if (newRange === timeRange) return;
|
|
58903
59522
|
trackCoreEvent("Leaderboard Time Range Changed", {
|
|
58904
59523
|
from_range: timeRange,
|
|
@@ -58909,7 +59528,7 @@ var LinesLeaderboard = ({
|
|
|
58909
59528
|
});
|
|
58910
59529
|
setTimeRange(newRange);
|
|
58911
59530
|
}, [timeRange, lines.length, monthlyEfficiencyByLineId, setTimeRange]);
|
|
58912
|
-
const handleLeaderboardLineClick =
|
|
59531
|
+
const handleLeaderboardLineClick = React141__default.useCallback((item, clickSource) => {
|
|
58913
59532
|
if (!canClickLine(item.line.id)) return;
|
|
58914
59533
|
trackCoreEvent("Leaderboard Line Clicked", {
|
|
58915
59534
|
line_id: item.line.id,
|
|
@@ -58923,8 +59542,8 @@ var LinesLeaderboard = ({
|
|
|
58923
59542
|
});
|
|
58924
59543
|
onLineClick(item.line);
|
|
58925
59544
|
}, [canClickLine, onLineClick, timeRange]);
|
|
58926
|
-
const viewLoadedTrackedRef =
|
|
58927
|
-
const leaderboardData =
|
|
59545
|
+
const viewLoadedTrackedRef = React141__default.useRef(null);
|
|
59546
|
+
const leaderboardData = React141__default.useMemo(() => {
|
|
58928
59547
|
const loading = timeRange === "today" ? isLoadingToday : isLoadingMonthly;
|
|
58929
59548
|
const efficiencyMap = timeRange === "today" ? todayEfficiencyByLineId : monthlyEfficiencyByLineId;
|
|
58930
59549
|
return lines.map((line) => {
|
|
@@ -58955,7 +59574,7 @@ var LinesLeaderboard = ({
|
|
|
58955
59574
|
isLoadingToday,
|
|
58956
59575
|
isLoadingMonthly
|
|
58957
59576
|
]);
|
|
58958
|
-
|
|
59577
|
+
React141__default.useEffect(() => {
|
|
58959
59578
|
const isLoading = timeRange === "today" ? isLoadingToday : isLoadingMonthly;
|
|
58960
59579
|
const trackingKey = `${timeRange}-${leaderboardData.length}`;
|
|
58961
59580
|
if (leaderboardData.length > 0 && !isLoading && viewLoadedTrackedRef.current !== trackingKey) {
|
|
@@ -58981,7 +59600,7 @@ var LinesLeaderboard = ({
|
|
|
58981
59600
|
const countdownTarget = timeRange === "monthly" ? monthEndDate : shiftEndDate;
|
|
58982
59601
|
const countdownFormat = timeRange === "monthly" ? "days" : "clock";
|
|
58983
59602
|
const countdownFinishedLabel = timeRange === "monthly" ? "Finished" : "Shift Ended";
|
|
58984
|
-
const handleCountdownFinished =
|
|
59603
|
+
const handleCountdownFinished = React141__default.useCallback(() => {
|
|
58985
59604
|
trackCoreEvent("Leaderboard Countdown Finished", {
|
|
58986
59605
|
countdown_type: timeRange === "monthly" ? "month_end" : "shift_end",
|
|
58987
59606
|
time_range: timeRange,
|
|
@@ -59008,7 +59627,7 @@ var LinesLeaderboard = ({
|
|
|
59008
59627
|
return "bg-white border-gray-100";
|
|
59009
59628
|
}
|
|
59010
59629
|
};
|
|
59011
|
-
|
|
59630
|
+
React141__default.useEffect(() => {
|
|
59012
59631
|
const style = document.createElement("style");
|
|
59013
59632
|
style.innerHTML = `
|
|
59014
59633
|
@keyframes float {
|
|
@@ -59195,7 +59814,7 @@ var LineCard = ({
|
|
|
59195
59814
|
supervisors
|
|
59196
59815
|
}) => {
|
|
59197
59816
|
const isUptimeLine = (line.monitoring_mode ?? "output") === "uptime";
|
|
59198
|
-
const isOnTrack =
|
|
59817
|
+
const isOnTrack = React141__default.useMemo(() => {
|
|
59199
59818
|
if (!kpis) return null;
|
|
59200
59819
|
return isEfficiencyOnTrack(kpis.efficiency.value);
|
|
59201
59820
|
}, [kpis]);
|
|
@@ -59386,46 +60005,46 @@ var KPIsOverviewView = ({
|
|
|
59386
60005
|
const configuredTimezone = dbTimezone || dateTimeConfig.defaultTimezone || "UTC";
|
|
59387
60006
|
const { startDate: monthStartDate, endDate: monthEndDateKey, monthEndDate } = getMonthDateInfo(configuredTimezone);
|
|
59388
60007
|
const isSuperAdmin = user?.scope_mode === "SUPER_ADMIN" || !!user?.access_scope?.is_super_admin;
|
|
59389
|
-
const scopedLineIds =
|
|
60008
|
+
const scopedLineIds = React141__default.useMemo(
|
|
59390
60009
|
() => Array.isArray(user?.access_scope?.line_ids) ? user.access_scope.line_ids.filter((lineId) => typeof lineId === "string" && lineId.length > 0) : [],
|
|
59391
60010
|
[user?.access_scope?.line_ids]
|
|
59392
60011
|
);
|
|
59393
60012
|
const hasCanonicalScope = !!user?.scope_mode || !!user?.access_scope;
|
|
59394
60013
|
const scopeRole = (user?.role_level || user?.role || "").toLowerCase();
|
|
59395
|
-
const isStrictLineScopedRole = scopeRole === "supervisor" || scopeRole
|
|
59396
|
-
const resolvedAssignedLineIds =
|
|
60014
|
+
const isStrictLineScopedRole = scopeRole === "supervisor" || isFactoryScopedRole(scopeRole);
|
|
60015
|
+
const resolvedAssignedLineIds = React141__default.useMemo(() => {
|
|
59397
60016
|
if (isSuperAdmin) return [];
|
|
59398
60017
|
if (scopedLineIds.length > 0) return scopedLineIds;
|
|
59399
60018
|
if (lineIds && lineIds.length > 0) return lineIds;
|
|
59400
60019
|
if (isStrictLineScopedRole && hasCanonicalScope) return [];
|
|
59401
60020
|
return [];
|
|
59402
60021
|
}, [isSuperAdmin, scopedLineIds, lineIds, isStrictLineScopedRole, hasCanonicalScope]);
|
|
59403
|
-
const assignedLineIdSet =
|
|
60022
|
+
const assignedLineIdSet = React141__default.useMemo(
|
|
59404
60023
|
() => new Set(resolvedAssignedLineIds),
|
|
59405
60024
|
[resolvedAssignedLineIds]
|
|
59406
60025
|
);
|
|
59407
|
-
const metricsLineIds =
|
|
60026
|
+
const metricsLineIds = React141__default.useMemo(() => {
|
|
59408
60027
|
if (isSuperAdmin) {
|
|
59409
60028
|
return lineIds ?? [];
|
|
59410
60029
|
}
|
|
59411
60030
|
return resolvedAssignedLineIds;
|
|
59412
60031
|
}, [isSuperAdmin, lineIds, resolvedAssignedLineIds]);
|
|
59413
60032
|
const assignedLineIdsForLeaderboard = isSuperAdmin ? void 0 : resolvedAssignedLineIds;
|
|
59414
|
-
const leaderboardLinesForView =
|
|
60033
|
+
const leaderboardLinesForView = React141__default.useMemo(() => {
|
|
59415
60034
|
const targetMode = viewType === "machine" ? "uptime" : "output";
|
|
59416
60035
|
return leaderboardLines.filter((line) => (line.monitoring_mode ?? "output") === targetMode);
|
|
59417
60036
|
}, [leaderboardLines, viewType]);
|
|
59418
|
-
const linesForView =
|
|
60037
|
+
const linesForView = React141__default.useMemo(() => {
|
|
59419
60038
|
const targetMode = viewType === "machine" ? "uptime" : "output";
|
|
59420
60039
|
return lines.filter((line) => (line.monitoring_mode ?? "output") === targetMode);
|
|
59421
60040
|
}, [lines, viewType]);
|
|
59422
|
-
const relevantLinesForMode =
|
|
60041
|
+
const relevantLinesForMode = React141__default.useMemo(() => {
|
|
59423
60042
|
if (activeTab === "leaderboard") {
|
|
59424
60043
|
return leaderboardLines.length > 0 ? leaderboardLines : lines;
|
|
59425
60044
|
}
|
|
59426
60045
|
return lines;
|
|
59427
60046
|
}, [activeTab, leaderboardLines, lines]);
|
|
59428
|
-
const { hasUptime, hasOutput } =
|
|
60047
|
+
const { hasUptime, hasOutput } = React141__default.useMemo(() => {
|
|
59429
60048
|
let uptime = false;
|
|
59430
60049
|
let output = false;
|
|
59431
60050
|
for (const line of relevantLinesForMode) {
|
|
@@ -59450,7 +60069,7 @@ var KPIsOverviewView = ({
|
|
|
59450
60069
|
const currentShiftDetails = getCurrentShift(configuredTimezone, shiftConfig);
|
|
59451
60070
|
const currentShiftDate = currentShiftDetails.date;
|
|
59452
60071
|
const currentShiftId = currentShiftDetails.shiftId;
|
|
59453
|
-
const shiftEndDate =
|
|
60072
|
+
const shiftEndDate = React141__default.useMemo(
|
|
59454
60073
|
() => getShiftEndDate(currentShiftDetails, configuredTimezone),
|
|
59455
60074
|
[currentShiftDetails, configuredTimezone]
|
|
59456
60075
|
);
|
|
@@ -59464,15 +60083,15 @@ var KPIsOverviewView = ({
|
|
|
59464
60083
|
lineId: factoryViewId,
|
|
59465
60084
|
userAccessibleLineIds: metricsLineIds
|
|
59466
60085
|
});
|
|
59467
|
-
const defaultKPIs =
|
|
59468
|
-
const kpisByLineId =
|
|
60086
|
+
const defaultKPIs = React141__default.useMemo(() => createDefaultKPIs(), []);
|
|
60087
|
+
const kpisByLineId = React141__default.useMemo(() => {
|
|
59469
60088
|
const map = /* @__PURE__ */ new Map();
|
|
59470
60089
|
lineMetrics.forEach((row) => {
|
|
59471
60090
|
if (row?.line_id) map.set(row.line_id, buildKPIsFromLineMetricsRow(row));
|
|
59472
60091
|
});
|
|
59473
60092
|
return map;
|
|
59474
60093
|
}, [lineMetrics]);
|
|
59475
|
-
const supervisorLineIds =
|
|
60094
|
+
const supervisorLineIds = React141__default.useMemo(
|
|
59476
60095
|
() => (leaderboardLines.length > 0 ? leaderboardLines : lines).map((l) => l.id),
|
|
59477
60096
|
[leaderboardLines, lines]
|
|
59478
60097
|
);
|
|
@@ -60434,7 +61053,7 @@ var LeaderboardDetailView = memo$1(({
|
|
|
60434
61053
|
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
60435
61054
|
}, []);
|
|
60436
61055
|
const [isMobile, setIsMobile] = useState(false);
|
|
60437
|
-
|
|
61056
|
+
React141__default.useEffect(() => {
|
|
60438
61057
|
const checkMobile = () => setIsMobile(window.innerWidth < 640);
|
|
60439
61058
|
checkMobile();
|
|
60440
61059
|
window.addEventListener("resize", checkMobile);
|
|
@@ -62693,7 +63312,7 @@ var ShiftsView = ({
|
|
|
62693
63312
|
] })
|
|
62694
63313
|
] });
|
|
62695
63314
|
};
|
|
62696
|
-
var AuthenticatedShiftsView = withAuth(
|
|
63315
|
+
var AuthenticatedShiftsView = withAuth(React141__default.memo(ShiftsView));
|
|
62697
63316
|
var ShiftsView_default = ShiftsView;
|
|
62698
63317
|
|
|
62699
63318
|
// src/views/TargetsView.utils.ts
|
|
@@ -64383,7 +65002,7 @@ var TargetsView = ({
|
|
|
64383
65002
|
};
|
|
64384
65003
|
var TargetsViewWithDisplayNames = withAllWorkspaceDisplayNames(TargetsView);
|
|
64385
65004
|
var TargetsView_default = TargetsViewWithDisplayNames;
|
|
64386
|
-
var AuthenticatedTargetsView = withAuth(
|
|
65005
|
+
var AuthenticatedTargetsView = withAuth(React141__default.memo(TargetsViewWithDisplayNames));
|
|
64387
65006
|
|
|
64388
65007
|
// src/views/workspace-detail-view.utils.ts
|
|
64389
65008
|
var formatDateInTimezone = (date = /* @__PURE__ */ new Date(), timezone, options) => {
|
|
@@ -64437,25 +65056,6 @@ var getInitialTab = (sourceType, defaultTab, fromMonthly, urlDate) => {
|
|
|
64437
65056
|
return "overview";
|
|
64438
65057
|
};
|
|
64439
65058
|
var DEBUG_DASHBOARD2 = process.env.NEXT_PUBLIC_DEBUG_DASHBOARD === "true";
|
|
64440
|
-
var SHORT_DESKTOP_QUERY = "(min-width: 1024px) and (max-height: 850px)";
|
|
64441
|
-
var useMediaQuery = (query) => {
|
|
64442
|
-
const [matches, setMatches] = useState(false);
|
|
64443
|
-
useEffect(() => {
|
|
64444
|
-
if (typeof window === "undefined" || !window.matchMedia) {
|
|
64445
|
-
return;
|
|
64446
|
-
}
|
|
64447
|
-
const mediaQueryList = window.matchMedia(query);
|
|
64448
|
-
const onChange = () => setMatches(mediaQueryList.matches);
|
|
64449
|
-
onChange();
|
|
64450
|
-
if (typeof mediaQueryList.addEventListener === "function") {
|
|
64451
|
-
mediaQueryList.addEventListener("change", onChange);
|
|
64452
|
-
return () => mediaQueryList.removeEventListener("change", onChange);
|
|
64453
|
-
}
|
|
64454
|
-
mediaQueryList.addListener(onChange);
|
|
64455
|
-
return () => mediaQueryList.removeListener(onChange);
|
|
64456
|
-
}, [query]);
|
|
64457
|
-
return matches;
|
|
64458
|
-
};
|
|
64459
65059
|
var chartCardVariants = {
|
|
64460
65060
|
initial: { opacity: 0, y: 10 },
|
|
64461
65061
|
animate: {
|
|
@@ -64533,9 +65133,8 @@ var WorkspaceDetailView = ({
|
|
|
64533
65133
|
const [usingFallbackData, setUsingFallbackData] = useState(false);
|
|
64534
65134
|
const { isIdleTimeVlmEnabled } = useIdleTimeVlmConfig();
|
|
64535
65135
|
const [showChartIdleTime, setShowChartIdleTime] = useState(false);
|
|
64536
|
-
const
|
|
64537
|
-
const
|
|
64538
|
-
const desktopBottomSectionClass = isShortDesktop ? "flex-none min-h-[300px]" : "flex-[2] min-h-0";
|
|
65136
|
+
const desktopTopSectionClass = "flex-[3] min-h-0";
|
|
65137
|
+
const desktopBottomSectionClass = "flex-[2] min-h-0";
|
|
64539
65138
|
const dashboardConfig = useDashboardConfig();
|
|
64540
65139
|
const { legend: efficiencyLegend } = useEfficiencyLegend();
|
|
64541
65140
|
const prewarmedClipsRef = useRef(/* @__PURE__ */ new Set());
|
|
@@ -65123,19 +65722,13 @@ var WorkspaceDetailView = ({
|
|
|
65123
65722
|
shiftId: idleClipShiftId,
|
|
65124
65723
|
enabled: idleClipFetchEnabled
|
|
65125
65724
|
});
|
|
65126
|
-
const
|
|
65725
|
+
const fallbackReturnUrl = returnUrl || "/";
|
|
65726
|
+
const appendReturnUrl = useCallback((params) => {
|
|
65127
65727
|
if (returnUrl) {
|
|
65128
|
-
|
|
65129
|
-
onNavigate(returnUrl);
|
|
65130
|
-
}
|
|
65131
|
-
return;
|
|
65132
|
-
}
|
|
65133
|
-
if (activeTab === "monthly_history") {
|
|
65134
|
-
if (onNavigate) {
|
|
65135
|
-
onNavigate("/");
|
|
65136
|
-
}
|
|
65137
|
-
return;
|
|
65728
|
+
params.set("returnTo", returnUrl);
|
|
65138
65729
|
}
|
|
65730
|
+
}, [returnUrl]);
|
|
65731
|
+
const handleBackNavigation = () => {
|
|
65139
65732
|
if (date || shift) {
|
|
65140
65733
|
setActiveTab("monthly_history");
|
|
65141
65734
|
if (onNavigate) {
|
|
@@ -65149,8 +65742,22 @@ var WorkspaceDetailView = ({
|
|
|
65149
65742
|
if (effectiveLineId) {
|
|
65150
65743
|
params.set("lineId", effectiveLineId);
|
|
65151
65744
|
}
|
|
65745
|
+
appendReturnUrl(params);
|
|
65152
65746
|
onNavigate(`/workspace/${workspaceId}?${params.toString()}`);
|
|
65153
65747
|
}
|
|
65748
|
+
return;
|
|
65749
|
+
}
|
|
65750
|
+
if (activeTab === "monthly_history") {
|
|
65751
|
+
if (onNavigate) {
|
|
65752
|
+
onNavigate(fallbackReturnUrl);
|
|
65753
|
+
}
|
|
65754
|
+
return;
|
|
65755
|
+
}
|
|
65756
|
+
if (returnUrl) {
|
|
65757
|
+
if (onNavigate) {
|
|
65758
|
+
onNavigate(returnUrl);
|
|
65759
|
+
}
|
|
65760
|
+
return;
|
|
65154
65761
|
} else {
|
|
65155
65762
|
if (previousView === "line_monthly_history") {
|
|
65156
65763
|
setActiveTab("monthly_history");
|
|
@@ -65165,11 +65772,12 @@ var WorkspaceDetailView = ({
|
|
|
65165
65772
|
if (effectiveLineId) {
|
|
65166
65773
|
params.set("lineId", effectiveLineId);
|
|
65167
65774
|
}
|
|
65775
|
+
appendReturnUrl(params);
|
|
65168
65776
|
onNavigate(`/workspace/${workspaceId}?${params.toString()}`);
|
|
65169
65777
|
}
|
|
65170
65778
|
} else {
|
|
65171
65779
|
if (onNavigate) {
|
|
65172
|
-
onNavigate(
|
|
65780
|
+
onNavigate(fallbackReturnUrl);
|
|
65173
65781
|
}
|
|
65174
65782
|
}
|
|
65175
65783
|
}
|
|
@@ -65228,7 +65836,7 @@ var WorkspaceDetailView = ({
|
|
|
65228
65836
|
/* @__PURE__ */ jsx(
|
|
65229
65837
|
BackButton,
|
|
65230
65838
|
{
|
|
65231
|
-
onClick: () => onNavigate && onNavigate(
|
|
65839
|
+
onClick: () => onNavigate && onNavigate(fallbackReturnUrl),
|
|
65232
65840
|
text: "Return to Dashboard",
|
|
65233
65841
|
size: "default",
|
|
65234
65842
|
"aria-label": "Return to dashboard"
|
|
@@ -65242,7 +65850,7 @@ var WorkspaceDetailView = ({
|
|
|
65242
65850
|
/* @__PURE__ */ jsx(
|
|
65243
65851
|
BackButton,
|
|
65244
65852
|
{
|
|
65245
|
-
onClick: () => onNavigate && onNavigate(
|
|
65853
|
+
onClick: () => onNavigate && onNavigate(fallbackReturnUrl),
|
|
65246
65854
|
text: "Return to Dashboard",
|
|
65247
65855
|
size: "default",
|
|
65248
65856
|
"aria-label": "Return to dashboard"
|
|
@@ -65513,7 +66121,7 @@ var WorkspaceDetailView = ({
|
|
|
65513
66121
|
] })
|
|
65514
66122
|
] }),
|
|
65515
66123
|
/* @__PURE__ */ jsxs("div", { className: "flex-grow p-1.5 sm:p-2 lg:p-4", children: [
|
|
65516
|
-
activeTab === "overview" && /* @__PURE__ */ jsxs("div", { className: "flex flex-col h-full lg:h-[calc(100vh-
|
|
66124
|
+
activeTab === "overview" && /* @__PURE__ */ jsxs("div", { className: "flex flex-col h-full lg:h-[calc(100vh-12rem)] overflow-y-auto lg:min-h-0 pb-4", children: [
|
|
65517
66125
|
/* @__PURE__ */ jsxs("div", { className: "block lg:hidden space-y-6 pb-6", children: [
|
|
65518
66126
|
!shouldShowCycleTimeChart && !isUptimeMode && /* @__PURE__ */ jsxs(
|
|
65519
66127
|
motion.div,
|
|
@@ -65855,6 +66463,7 @@ var WorkspaceDetailView = ({
|
|
|
65855
66463
|
if (effectiveLineId) {
|
|
65856
66464
|
params.set("lineId", effectiveLineId);
|
|
65857
66465
|
}
|
|
66466
|
+
appendReturnUrl(params);
|
|
65858
66467
|
onNavigate(`/workspace/${workspaceId}?${params.toString()}`);
|
|
65859
66468
|
}
|
|
65860
66469
|
},
|
|
@@ -66215,7 +66824,7 @@ var formatTime4 = (date, timezone) => new Intl.DateTimeFormat("en-IN", {
|
|
|
66215
66824
|
hour12: true,
|
|
66216
66825
|
timeZone: timezone
|
|
66217
66826
|
}).format(date);
|
|
66218
|
-
var
|
|
66827
|
+
var formatDuration3 = (minutes) => {
|
|
66219
66828
|
if (minutes < 1) return "<1 min";
|
|
66220
66829
|
if (minutes < 60) return `${minutes} min`;
|
|
66221
66830
|
const hours = Math.floor(minutes / 60);
|
|
@@ -66328,7 +66937,7 @@ var UptimeTimelineStrip = ({
|
|
|
66328
66937
|
if (segment.length > 1) {
|
|
66329
66938
|
endDate.setMinutes(endDate.getMinutes() + 1);
|
|
66330
66939
|
}
|
|
66331
|
-
const tooltip = `${STATUS_TITLES[segment.status]} \u2022 ${
|
|
66940
|
+
const tooltip = `${STATUS_TITLES[segment.status]} \u2022 ${formatDuration3(segment.length)} (${formatTime4(
|
|
66332
66941
|
startDate,
|
|
66333
66942
|
timezone
|
|
66334
66943
|
)} - ${formatTime4(endDate, timezone)})`;
|
|
@@ -66361,7 +66970,7 @@ var UptimeTimelineStrip = ({
|
|
|
66361
66970
|
};
|
|
66362
66971
|
var UptimeTimelineStrip_default = UptimeTimelineStrip;
|
|
66363
66972
|
var SHORT_INTERRUPT_THRESHOLD_MINUTES = 3;
|
|
66364
|
-
var
|
|
66973
|
+
var formatDuration4 = (minutes) => {
|
|
66365
66974
|
if (!minutes || minutes <= 0) return "0 min";
|
|
66366
66975
|
const rounded = Math.max(Math.round(minutes), 0);
|
|
66367
66976
|
const days = Math.floor(rounded / 1440);
|
|
@@ -66380,7 +66989,7 @@ var formatDowntimeLabel2 = (minutes, includeSuffix = true) => {
|
|
|
66380
66989
|
if (!minutes || minutes <= 0) {
|
|
66381
66990
|
return includeSuffix ? "No downtime" : "0 min";
|
|
66382
66991
|
}
|
|
66383
|
-
const label =
|
|
66992
|
+
const label = formatDuration4(minutes);
|
|
66384
66993
|
return includeSuffix ? `${label} down` : label;
|
|
66385
66994
|
};
|
|
66386
66995
|
var formatTimeRange = (start, end, timezone) => {
|
|
@@ -67136,6 +67745,7 @@ var TeamManagementView = ({
|
|
|
67136
67745
|
owners: 0,
|
|
67137
67746
|
it: 0,
|
|
67138
67747
|
plantHeads: 0,
|
|
67748
|
+
industrialEngineers: 0,
|
|
67139
67749
|
supervisors: 0,
|
|
67140
67750
|
optifye: 0
|
|
67141
67751
|
});
|
|
@@ -67149,8 +67759,8 @@ var TeamManagementView = ({
|
|
|
67149
67759
|
}
|
|
67150
67760
|
return [];
|
|
67151
67761
|
}, []);
|
|
67152
|
-
const
|
|
67153
|
-
if (user?.role_level
|
|
67762
|
+
const factoryScopedRoleFactoryIds = useMemo(() => {
|
|
67763
|
+
if (!isFactoryScopedRole(user?.role_level)) return [];
|
|
67154
67764
|
const scopedFactoryIds = normalizeIds(user?.access_scope?.factory_ids);
|
|
67155
67765
|
if (scopedFactoryIds.length > 0) {
|
|
67156
67766
|
return Array.from(new Set(scopedFactoryIds));
|
|
@@ -67168,8 +67778,8 @@ var TeamManagementView = ({
|
|
|
67168
67778
|
window.dispatchEvent(new Event("rbac:refresh-scope"));
|
|
67169
67779
|
}
|
|
67170
67780
|
}, []);
|
|
67171
|
-
const canAddUsers = user?.role_level
|
|
67172
|
-
const canViewUsageStats = user?.role_level
|
|
67781
|
+
const canAddUsers = canRoleManageUsers(user?.role_level);
|
|
67782
|
+
const canViewUsageStats = canRoleViewUsageStats(user?.role_level);
|
|
67173
67783
|
const pageCompanyId = entityConfig?.companyId || user?.properties?.company_id;
|
|
67174
67784
|
const companyIdForUsage = pageCompanyId;
|
|
67175
67785
|
const usageDateRange = useMemo(() => {
|
|
@@ -67203,8 +67813,8 @@ var TeamManagementView = ({
|
|
|
67203
67813
|
}, {});
|
|
67204
67814
|
}, [usageData, usageDateRange.daysElapsed]);
|
|
67205
67815
|
const pageTitle = "Team Management";
|
|
67206
|
-
const pageDescription =
|
|
67207
|
-
const hasAccess = user ? user.role_level === void 0 ||
|
|
67816
|
+
const pageDescription = canViewUsageStats ? "Manage team members and view their daily usage" : "Manage supervisors in your factory";
|
|
67817
|
+
const hasAccess = user ? user.role_level === void 0 || canRoleAccessTeamManagement(user.role_level) : false;
|
|
67208
67818
|
const loadData = useCallback(async () => {
|
|
67209
67819
|
if (!supabase) {
|
|
67210
67820
|
setError("Supabase client not available. Please refresh the page.");
|
|
@@ -67251,8 +67861,8 @@ var TeamManagementView = ({
|
|
|
67251
67861
|
setAvailableFactories(factories || []);
|
|
67252
67862
|
setAvailableLines(lines);
|
|
67253
67863
|
console.log("[TeamManagementView] Company-scoped team view - Company:", companyId, "Loaded factories:", factories?.length, "lines:", lines?.length);
|
|
67254
|
-
} else if (user?.role_level
|
|
67255
|
-
if (
|
|
67864
|
+
} else if (isFactoryScopedRole(user?.role_level)) {
|
|
67865
|
+
if (factoryScopedRoleFactoryIds.length > 0) {
|
|
67256
67866
|
if (companyId) {
|
|
67257
67867
|
const linesResponse = await fetch(`${backendUrl}/api/lines?company_id=${companyId}`, {
|
|
67258
67868
|
headers: {
|
|
@@ -67265,9 +67875,9 @@ var TeamManagementView = ({
|
|
|
67265
67875
|
}
|
|
67266
67876
|
const linesData = await linesResponse.json();
|
|
67267
67877
|
const allLines = linesData.lines || [];
|
|
67268
|
-
const lines = allLines.filter((line) =>
|
|
67878
|
+
const lines = allLines.filter((line) => factoryScopedRoleFactoryIds.includes(line.factory_id));
|
|
67269
67879
|
setAvailableLines(lines);
|
|
67270
|
-
console.log("[TeamManagementView]
|
|
67880
|
+
console.log("[TeamManagementView] Factory-scoped team view - Factories:", factoryScopedRoleFactoryIds, "Loaded lines:", lines?.length);
|
|
67271
67881
|
}
|
|
67272
67882
|
} else if (entityConfig?.factoryId) {
|
|
67273
67883
|
const linesResponse = await fetch(`${backendUrl}/api/lines?factory_id=${entityConfig.factoryId}`, {
|
|
@@ -67304,12 +67914,12 @@ var TeamManagementView = ({
|
|
|
67304
67914
|
setAvailableFactories([]);
|
|
67305
67915
|
console.log("[TeamManagementView] Fallback - Company:", companyId, "Loaded lines:", lines?.length);
|
|
67306
67916
|
}
|
|
67307
|
-
const usersPromise = user?.role_level
|
|
67308
|
-
if (
|
|
67917
|
+
const usersPromise = isFactoryScopedRole(user?.role_level) ? (async () => {
|
|
67918
|
+
if (factoryScopedRoleFactoryIds.length === 0) {
|
|
67309
67919
|
return [];
|
|
67310
67920
|
}
|
|
67311
67921
|
const results = await Promise.allSettled(
|
|
67312
|
-
|
|
67922
|
+
factoryScopedRoleFactoryIds.map((factoryId) => userManagementService.getFactoryUsers(factoryId))
|
|
67313
67923
|
);
|
|
67314
67924
|
const successful = results.filter(
|
|
67315
67925
|
(result) => result.status === "fulfilled"
|
|
@@ -67341,6 +67951,7 @@ var TeamManagementView = ({
|
|
|
67341
67951
|
owners: userStats.owners,
|
|
67342
67952
|
it: userStats.it,
|
|
67343
67953
|
plantHeads: userStats.plant_heads,
|
|
67954
|
+
industrialEngineers: userStats.industrial_engineers,
|
|
67344
67955
|
supervisors: userStats.supervisors,
|
|
67345
67956
|
optifye: 0
|
|
67346
67957
|
});
|
|
@@ -67351,7 +67962,7 @@ var TeamManagementView = ({
|
|
|
67351
67962
|
} finally {
|
|
67352
67963
|
setIsLoading(false);
|
|
67353
67964
|
}
|
|
67354
|
-
}, [supabase, user, pageCompanyId, entityConfig?.factoryId,
|
|
67965
|
+
}, [supabase, user, pageCompanyId, entityConfig?.factoryId, factoryScopedRoleFactoryIds]);
|
|
67355
67966
|
useEffect(() => {
|
|
67356
67967
|
const companyId = pageCompanyId;
|
|
67357
67968
|
const canLoad = hasAccess && user && !!companyId;
|
|
@@ -67457,7 +68068,7 @@ var TeamManagementView = ({
|
|
|
67457
68068
|
{
|
|
67458
68069
|
iconType: AlertCircle,
|
|
67459
68070
|
title: "Access Denied",
|
|
67460
|
-
message:
|
|
68071
|
+
message: `You don't have permission to view this page. Only ${getRoleLabel("owner")}, ${getRoleLabel("it")}, ${getRoleLabel("plant_head")}, ${getRoleLabel("industrial_engineer")}, and ${getRoleLabel("optifye")} users can access team management.`
|
|
67461
68072
|
}
|
|
67462
68073
|
) });
|
|
67463
68074
|
}
|
|
@@ -67624,7 +68235,7 @@ function BottleneckClipsView({
|
|
|
67624
68235
|
) })
|
|
67625
68236
|
] }) });
|
|
67626
68237
|
}
|
|
67627
|
-
var AuthenticatedBottleneckClipsView = withAuth(
|
|
68238
|
+
var AuthenticatedBottleneckClipsView = withAuth(React141__default.memo(BottleneckClipsView));
|
|
67628
68239
|
var BottleneckClipsView_default = BottleneckClipsView;
|
|
67629
68240
|
|
|
67630
68241
|
// src/lib/services/ticketService.ts
|
|
@@ -68455,7 +69066,7 @@ Please ensure:
|
|
|
68455
69066
|
)
|
|
68456
69067
|
] });
|
|
68457
69068
|
}
|
|
68458
|
-
var AuthenticatedTicketsView = withAuth(
|
|
69069
|
+
var AuthenticatedTicketsView = withAuth(React141__default.memo(TicketsView));
|
|
68459
69070
|
var TicketsView_default = TicketsView;
|
|
68460
69071
|
|
|
68461
69072
|
// src/lib/api/s3-clips-parser.ts
|
|
@@ -68635,6 +69246,74 @@ var buildInitials = (name) => {
|
|
|
68635
69246
|
const second = parts.length > 1 ? parts[1]?.[0] || "" : "";
|
|
68636
69247
|
return `${first}${second}`.toUpperCase();
|
|
68637
69248
|
};
|
|
69249
|
+
var MOCK_IE_TEAM_USER_ID = "mock-industrial-engineering-team";
|
|
69250
|
+
var MOCK_IE_TICKET_ID = "mock-ie-rack-too-far-away";
|
|
69251
|
+
var getRandomVideoGalleryClips = (recommendations, maxClips = 3) => {
|
|
69252
|
+
const seen = /* @__PURE__ */ new Set();
|
|
69253
|
+
const candidates = [];
|
|
69254
|
+
recommendations.forEach((rec) => {
|
|
69255
|
+
if (!Array.isArray(rec.evidence)) return;
|
|
69256
|
+
rec.evidence.forEach((evidenceItem) => {
|
|
69257
|
+
if (evidenceItem.type !== "video_gallery" || !Array.isArray(evidenceItem.clips)) return;
|
|
69258
|
+
evidenceItem.clips.forEach((rawClip) => {
|
|
69259
|
+
if (!rawClip || typeof rawClip.clip_id !== "string") return;
|
|
69260
|
+
const key = `${rawClip.clip_id}:${rawClip.workspace_id || ""}`;
|
|
69261
|
+
if (seen.has(key)) return;
|
|
69262
|
+
seen.add(key);
|
|
69263
|
+
candidates.push({
|
|
69264
|
+
clip_id: rawClip.clip_id,
|
|
69265
|
+
workspace_id: typeof rawClip.workspace_id === "string" ? rawClip.workspace_id : void 0,
|
|
69266
|
+
cycle_time_seconds: typeof rawClip.cycle_time_seconds === "number" ? rawClip.cycle_time_seconds : void 0,
|
|
69267
|
+
cycle_sec: typeof rawClip.cycle_sec === "number" ? rawClip.cycle_sec : void 0
|
|
69268
|
+
});
|
|
69269
|
+
});
|
|
69270
|
+
});
|
|
69271
|
+
});
|
|
69272
|
+
for (let i = candidates.length - 1; i > 0; i -= 1) {
|
|
69273
|
+
const j = Math.floor(Math.random() * (i + 1));
|
|
69274
|
+
[candidates[i], candidates[j]] = [candidates[j], candidates[i]];
|
|
69275
|
+
}
|
|
69276
|
+
return candidates.slice(0, Math.max(1, maxClips));
|
|
69277
|
+
};
|
|
69278
|
+
var buildIEMockRecommendation = (recommendations, lineNameById) => {
|
|
69279
|
+
const now4 = /* @__PURE__ */ new Date();
|
|
69280
|
+
const firstSeen = new Date(now4.getTime() - 3 * 24 * 60 * 60 * 1e3).toISOString();
|
|
69281
|
+
const sampleRec = recommendations.find((rec) => !!rec.line_id) || recommendations[0];
|
|
69282
|
+
const lineId = sampleRec?.line_id;
|
|
69283
|
+
const line = lineId ? lineNameById.get(lineId) || sampleRec?.line || "Line 1" : sampleRec?.line || "Line 1";
|
|
69284
|
+
const shiftLabel = sampleRec?.shift_label;
|
|
69285
|
+
const shiftId = sampleRec?.shift_id;
|
|
69286
|
+
const randomClips = getRandomVideoGalleryClips(recommendations, 3);
|
|
69287
|
+
return {
|
|
69288
|
+
id: MOCK_IE_TICKET_ID,
|
|
69289
|
+
issue_id: MOCK_IE_TICKET_ID,
|
|
69290
|
+
issue_number: 0,
|
|
69291
|
+
issue_status: "open",
|
|
69292
|
+
template_code: "ie_rack_too_far_away_mock",
|
|
69293
|
+
type: "cycle_time",
|
|
69294
|
+
title: "Rack too far away",
|
|
69295
|
+
location: "Industrial Engineering Review",
|
|
69296
|
+
line,
|
|
69297
|
+
line_id: lineId,
|
|
69298
|
+
description: "We analyzed 30 slow clips and saw that the top reason was the operator having to reach for the desk.",
|
|
69299
|
+
resolution_instructions: "Completion condition: Move the rack 3 inches closer to the operator for better ergonomic posture.",
|
|
69300
|
+
shift_id: shiftId,
|
|
69301
|
+
shift_label: shiftLabel,
|
|
69302
|
+
first_seen_at: firstSeen,
|
|
69303
|
+
visible_since: firstSeen,
|
|
69304
|
+
weeks_open: 1,
|
|
69305
|
+
ticket_status: "active",
|
|
69306
|
+
assigned_to_user_id: MOCK_IE_TEAM_USER_ID,
|
|
69307
|
+
assigned_user_ids: [MOCK_IE_TEAM_USER_ID],
|
|
69308
|
+
evidence: randomClips.length > 0 ? [
|
|
69309
|
+
{
|
|
69310
|
+
type: "video_gallery",
|
|
69311
|
+
title: "Slow clips analyzed",
|
|
69312
|
+
clips: randomClips
|
|
69313
|
+
}
|
|
69314
|
+
] : []
|
|
69315
|
+
};
|
|
69316
|
+
};
|
|
68638
69317
|
var ClipVideoCarousel = ({ clips, clipsService }) => {
|
|
68639
69318
|
const [currentIndex, setCurrentIndex] = useState(0);
|
|
68640
69319
|
const [videos, setVideos] = useState([]);
|
|
@@ -69057,12 +69736,12 @@ var ImprovementCenterView = () => {
|
|
|
69057
69736
|
}, [user]);
|
|
69058
69737
|
const assignedFactoryIds = useMemo(() => {
|
|
69059
69738
|
if (!user) return [];
|
|
69060
|
-
if (user.role_level
|
|
69739
|
+
if (!isFactoryScopedRole(user.role_level)) return [];
|
|
69061
69740
|
const factories = user.properties?.factory_id || user.properties?.factory_ids || [];
|
|
69062
69741
|
return Array.isArray(factories) ? factories : [];
|
|
69063
69742
|
}, [user]);
|
|
69064
69743
|
const plantHeadLineIds = useMemo(() => {
|
|
69065
|
-
if (user?.role_level
|
|
69744
|
+
if (!isFactoryScopedRole(user?.role_level) || companyLines.length === 0) return [];
|
|
69066
69745
|
const factorySet = new Set(assignedFactoryIds);
|
|
69067
69746
|
return companyLines.filter((line) => line.factoryId === void 0 || line.factoryId === null || factorySet.has(line.factoryId)).map((line) => line.id);
|
|
69068
69747
|
}, [assignedFactoryIds, companyLines, user?.role_level]);
|
|
@@ -69070,7 +69749,7 @@ var ImprovementCenterView = () => {
|
|
|
69070
69749
|
if (user?.role_level === "supervisor") {
|
|
69071
69750
|
return assignedLineIds;
|
|
69072
69751
|
}
|
|
69073
|
-
if (user?.role_level
|
|
69752
|
+
if (isFactoryScopedRole(user?.role_level)) {
|
|
69074
69753
|
if (plantHeadLineIds.length > 0) return plantHeadLineIds;
|
|
69075
69754
|
return companyLineIds.length > 0 ? companyLineIds : configuredLineIds;
|
|
69076
69755
|
}
|
|
@@ -69093,6 +69772,21 @@ var ImprovementCenterView = () => {
|
|
|
69093
69772
|
return map;
|
|
69094
69773
|
}, [companyLines, configuredLines]);
|
|
69095
69774
|
const companyId = user?.company_id || entityConfig.companyId;
|
|
69775
|
+
const industrialEngineeringTeamMember = useMemo(
|
|
69776
|
+
() => ({
|
|
69777
|
+
id: MOCK_IE_TEAM_USER_ID,
|
|
69778
|
+
name: "Industrial Engineering Team",
|
|
69779
|
+
role: "industrial_engineering",
|
|
69780
|
+
initials: "IE"
|
|
69781
|
+
}),
|
|
69782
|
+
[]
|
|
69783
|
+
);
|
|
69784
|
+
const teamMembersWithIETeam = useMemo(() => {
|
|
69785
|
+
if (teamMembers.some((member) => member.id === MOCK_IE_TEAM_USER_ID)) {
|
|
69786
|
+
return teamMembers;
|
|
69787
|
+
}
|
|
69788
|
+
return [...teamMembers, industrialEngineeringTeamMember];
|
|
69789
|
+
}, [teamMembers, industrialEngineeringTeamMember]);
|
|
69096
69790
|
const clipsService = useMemo(() => {
|
|
69097
69791
|
try {
|
|
69098
69792
|
return new S3ClipsSupabaseService(dashboardConfig);
|
|
@@ -69106,24 +69800,42 @@ var ImprovementCenterView = () => {
|
|
|
69106
69800
|
if (!supabase || !companyId) return;
|
|
69107
69801
|
try {
|
|
69108
69802
|
const userService2 = createUserManagementService(supabase);
|
|
69109
|
-
const
|
|
69803
|
+
const roleFilters = ["supervisor", "owner", "industrial_engineer"];
|
|
69804
|
+
const roleResults = await Promise.allSettled(
|
|
69805
|
+
roleFilters.map((role) => userService2.getCompanyUsers(companyId, role))
|
|
69806
|
+
);
|
|
69807
|
+
roleResults.forEach((result, index) => {
|
|
69808
|
+
if (result.status === "rejected") {
|
|
69809
|
+
console.warn(
|
|
69810
|
+
`[ImprovementCenterView] Failed to load ${roleFilters[index]} users`,
|
|
69811
|
+
result.reason
|
|
69812
|
+
);
|
|
69813
|
+
}
|
|
69814
|
+
});
|
|
69815
|
+
const users = roleResults.flatMap(
|
|
69816
|
+
(result) => result.status === "fulfilled" ? result.value : []
|
|
69817
|
+
);
|
|
69110
69818
|
if (cancelled) return;
|
|
69111
|
-
const
|
|
69819
|
+
const membersById = /* @__PURE__ */ new Map();
|
|
69820
|
+
users.forEach((user2) => {
|
|
69112
69821
|
const rawName = user2.first_name ? `${user2.first_name}${user2.last_name ? " " + user2.last_name : ""}` : user2.properties?.full_name || user2.email?.split("@")[0] || "Unknown";
|
|
69113
|
-
|
|
69114
|
-
|
|
69115
|
-
|
|
69116
|
-
|
|
69117
|
-
|
|
69118
|
-
|
|
69119
|
-
|
|
69120
|
-
|
|
69822
|
+
if (!membersById.has(user2.user_id)) {
|
|
69823
|
+
membersById.set(user2.user_id, {
|
|
69824
|
+
id: user2.user_id,
|
|
69825
|
+
name: rawName,
|
|
69826
|
+
role: user2.role_level,
|
|
69827
|
+
initials: buildInitials(rawName),
|
|
69828
|
+
email: user2.email,
|
|
69829
|
+
profilePhotoUrl: user2.profile_photo_url
|
|
69830
|
+
});
|
|
69831
|
+
}
|
|
69121
69832
|
});
|
|
69833
|
+
const members = Array.from(membersById.values());
|
|
69122
69834
|
members.sort((a, b) => a.name.localeCompare(b.name));
|
|
69123
69835
|
setTeamMembers(members);
|
|
69124
69836
|
} catch (error) {
|
|
69125
69837
|
if (!cancelled) {
|
|
69126
|
-
console.error("[ImprovementCenterView] Failed to load
|
|
69838
|
+
console.error("[ImprovementCenterView] Failed to load assignee members", error);
|
|
69127
69839
|
setTeamMembers([]);
|
|
69128
69840
|
}
|
|
69129
69841
|
}
|
|
@@ -69186,7 +69898,12 @@ var ImprovementCenterView = () => {
|
|
|
69186
69898
|
};
|
|
69187
69899
|
});
|
|
69188
69900
|
const allowed = new Set(scopeLineIds);
|
|
69189
|
-
|
|
69901
|
+
const scopedRecommendations = recs.filter((r2) => !r2.line_id || allowed.has(r2.line_id));
|
|
69902
|
+
const mockRecommendation = buildIEMockRecommendation(scopedRecommendations, lineNameById);
|
|
69903
|
+
setRecommendations([
|
|
69904
|
+
mockRecommendation,
|
|
69905
|
+
...scopedRecommendations.filter((recommendation) => recommendation.id !== MOCK_IE_TICKET_ID)
|
|
69906
|
+
]);
|
|
69190
69907
|
} catch (err) {
|
|
69191
69908
|
if (cancelled) return;
|
|
69192
69909
|
setLoadError(err?.message || "Failed to load recommendations");
|
|
@@ -69199,10 +69916,10 @@ var ImprovementCenterView = () => {
|
|
|
69199
69916
|
return () => {
|
|
69200
69917
|
cancelled = true;
|
|
69201
69918
|
};
|
|
69202
|
-
}, [supabase, companyId, scopeLineIdsKey]);
|
|
69919
|
+
}, [supabase, companyId, scopeLineIdsKey, lineNameById]);
|
|
69203
69920
|
const teamMembersById = useMemo(() => {
|
|
69204
|
-
return new Map(
|
|
69205
|
-
}, [
|
|
69921
|
+
return new Map(teamMembersWithIETeam.map((member) => [member.id, member]));
|
|
69922
|
+
}, [teamMembersWithIETeam]);
|
|
69206
69923
|
const filteredRecommendations = useMemo(() => {
|
|
69207
69924
|
return recommendations.filter((rec) => {
|
|
69208
69925
|
if (selectedLineId !== "all" && rec.line_id !== selectedLineId) return false;
|
|
@@ -69217,7 +69934,12 @@ var ImprovementCenterView = () => {
|
|
|
69217
69934
|
}
|
|
69218
69935
|
if (selectedMemberId !== "all" && !(rec.assigned_user_ids?.includes(selectedMemberId) || rec.assigned_to_user_id === selectedMemberId)) return false;
|
|
69219
69936
|
return true;
|
|
69220
|
-
}).sort((a, b) =>
|
|
69937
|
+
}).sort((a, b) => {
|
|
69938
|
+
const aIndustrial = a.industrial_eng_bottleneck ? 1 : 0;
|
|
69939
|
+
const bIndustrial = b.industrial_eng_bottleneck ? 1 : 0;
|
|
69940
|
+
if (aIndustrial !== bIndustrial) return bIndustrial - aIndustrial;
|
|
69941
|
+
return (a.issue_number || 0) - (b.issue_number || 0);
|
|
69942
|
+
});
|
|
69221
69943
|
}, [recommendations, selectedLineId, selectedStatus, selectedShift, selectedWeeksRange, selectedMemberId]);
|
|
69222
69944
|
const stats = useMemo(() => {
|
|
69223
69945
|
const baseFiltered = recommendations.filter((rec) => {
|
|
@@ -69315,7 +70037,7 @@ var ImprovementCenterView = () => {
|
|
|
69315
70037
|
setSelectedWeeksRange(weeksRange);
|
|
69316
70038
|
};
|
|
69317
70039
|
const handleMemberFilterChange = (memberId) => {
|
|
69318
|
-
const memberName = memberId === "all" ? "all" :
|
|
70040
|
+
const memberName = memberId === "all" ? "all" : teamMembersWithIETeam.find((member) => member.id === memberId)?.name || memberId;
|
|
69319
70041
|
trackCoreEvent("Improvement Center Filter Applied", {
|
|
69320
70042
|
filter_type: "member",
|
|
69321
70043
|
filter_value: memberName,
|
|
@@ -69397,7 +70119,7 @@ var ImprovementCenterView = () => {
|
|
|
69397
70119
|
/* @__PURE__ */ jsx("div", { className: "space-y-3", children: [
|
|
69398
70120
|
{ value: selectedShift, onChange: handleShiftFilterChange, options: shiftOptions, label: "Shift" },
|
|
69399
70121
|
{ value: selectedWeeksRange, onChange: handleWeeksFilterChange, options: weekOptions.map((o) => o.id), labels: weekOptions, label: "Duration" },
|
|
69400
|
-
{ value: selectedMemberId, onChange: handleMemberFilterChange, options: ["all", ...
|
|
70122
|
+
{ value: selectedMemberId, onChange: handleMemberFilterChange, options: ["all", ...teamMembersWithIETeam.map((m) => m.id)], labels: teamMembersWithIETeam, label: "Member" },
|
|
69401
70123
|
{ value: selectedLineId, onChange: handleLineFilterChange, options: lineOptions.map((o) => o.id), labels: lineOptions, label: "Line" }
|
|
69402
70124
|
].map((filter2, idx) => /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
|
|
69403
70125
|
/* @__PURE__ */ jsx("label", { className: "text-xs font-medium text-gray-500 uppercase tracking-wide ml-1", children: filter2.label }),
|
|
@@ -69614,7 +70336,7 @@ var ThreadSidebar = ({
|
|
|
69614
70336
|
] }) })
|
|
69615
70337
|
] });
|
|
69616
70338
|
};
|
|
69617
|
-
var ProfilePicture =
|
|
70339
|
+
var ProfilePicture = React141__default.memo(({
|
|
69618
70340
|
alt = "Axel",
|
|
69619
70341
|
className = "",
|
|
69620
70342
|
size = "md",
|
|
@@ -71585,6 +72307,840 @@ var AIAgentView = () => {
|
|
|
71585
72307
|
] });
|
|
71586
72308
|
};
|
|
71587
72309
|
var AIAgentView_default = AIAgentView;
|
|
72310
|
+
var EMPTY_OVERVIEW = {
|
|
72311
|
+
scope: {
|
|
72312
|
+
current_range: { day_count: null },
|
|
72313
|
+
previous_range: { day_count: null },
|
|
72314
|
+
available_line_modes: { has_output: false, has_uptime: false }
|
|
72315
|
+
},
|
|
72316
|
+
summary: {
|
|
72317
|
+
plant_efficiency: { current: null, previous: null, delta_pp: null },
|
|
72318
|
+
avg_idle_per_workstation: { current_seconds: null, previous_seconds: null, delta_seconds: null }
|
|
72319
|
+
},
|
|
72320
|
+
poorest_lines: { output: [], uptime: [] },
|
|
72321
|
+
trend: { shift_mode: "all", points: [] },
|
|
72322
|
+
idle_reason_breakdown: []
|
|
72323
|
+
};
|
|
72324
|
+
var efficiencyLineConfig = [
|
|
72325
|
+
{
|
|
72326
|
+
dataKey: "efficiency",
|
|
72327
|
+
name: "Efficiency",
|
|
72328
|
+
stroke: "#00AB45",
|
|
72329
|
+
strokeWidth: 3,
|
|
72330
|
+
type: "monotone",
|
|
72331
|
+
dot: { r: 4, fill: "#00AB45", strokeWidth: 2, stroke: "#fff" },
|
|
72332
|
+
activeDot: { r: 6, strokeWidth: 0, fill: "#00AB45" }
|
|
72333
|
+
}
|
|
72334
|
+
];
|
|
72335
|
+
var toNumber3 = (value) => {
|
|
72336
|
+
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
72337
|
+
if (typeof value === "string" && value.trim().length > 0) {
|
|
72338
|
+
const parsed = Number(value);
|
|
72339
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
72340
|
+
}
|
|
72341
|
+
return null;
|
|
72342
|
+
};
|
|
72343
|
+
var roundOne = (value) => Math.round(value * 10) / 10;
|
|
72344
|
+
var getLastSevenDayRange = (timezone) => {
|
|
72345
|
+
const todayKey = formatInTimeZone(/* @__PURE__ */ new Date(), timezone || "UTC", "yyyy-MM-dd");
|
|
72346
|
+
const endDate = parseISO(`${todayKey}T00:00:00`);
|
|
72347
|
+
const startDate = subDays(endDate, 6);
|
|
72348
|
+
return {
|
|
72349
|
+
startKey: format(startDate, "yyyy-MM-dd"),
|
|
72350
|
+
endKey: format(endDate, "yyyy-MM-dd")
|
|
72351
|
+
};
|
|
72352
|
+
};
|
|
72353
|
+
var formatIdleDuration = (seconds) => {
|
|
72354
|
+
if (seconds === null || seconds === void 0 || !Number.isFinite(seconds)) {
|
|
72355
|
+
return "--";
|
|
72356
|
+
}
|
|
72357
|
+
const wholeSeconds = Math.max(0, Math.round(seconds));
|
|
72358
|
+
const minutes = Math.floor(wholeSeconds / 60);
|
|
72359
|
+
const remainingSeconds = wholeSeconds % 60;
|
|
72360
|
+
if (minutes > 0) {
|
|
72361
|
+
return `${minutes}m ${remainingSeconds}s`;
|
|
72362
|
+
}
|
|
72363
|
+
return `${remainingSeconds}s`;
|
|
72364
|
+
};
|
|
72365
|
+
var formatSignedIdleDuration = (seconds) => {
|
|
72366
|
+
const sign = seconds > 0 ? "+" : "-";
|
|
72367
|
+
return `${sign}${formatIdleDuration(Math.abs(seconds))}`;
|
|
72368
|
+
};
|
|
72369
|
+
var formatComparisonWindow = (dayCount) => {
|
|
72370
|
+
if (!dayCount || !Number.isFinite(dayCount)) return "previous range";
|
|
72371
|
+
return `previous ${dayCount} ${dayCount === 1 ? "day" : "days"}`;
|
|
72372
|
+
};
|
|
72373
|
+
var shuffle = (items) => {
|
|
72374
|
+
const next = [...items];
|
|
72375
|
+
for (let i = next.length - 1; i > 0; i -= 1) {
|
|
72376
|
+
const swapIndex = Math.floor(Math.random() * (i + 1));
|
|
72377
|
+
[next[i], next[swapIndex]] = [next[swapIndex], next[i]];
|
|
72378
|
+
}
|
|
72379
|
+
return next;
|
|
72380
|
+
};
|
|
72381
|
+
var buildImprovementMetric = (recommendation) => {
|
|
72382
|
+
const metrics2 = recommendation.metrics || {};
|
|
72383
|
+
const efficiencyGain = toNumber3(metrics2.efficiency_gain_pct);
|
|
72384
|
+
if (efficiencyGain !== null) {
|
|
72385
|
+
return `+${roundOne(efficiencyGain)}% Efficiency`;
|
|
72386
|
+
}
|
|
72387
|
+
const outputGain = toNumber3(metrics2.output_gain);
|
|
72388
|
+
if (outputGain !== null) {
|
|
72389
|
+
return `+${Math.round(outputGain)} Units`;
|
|
72390
|
+
}
|
|
72391
|
+
const idleMinutes = toNumber3(metrics2.idle_minutes);
|
|
72392
|
+
if (idleMinutes !== null) {
|
|
72393
|
+
return `-${Math.round(idleMinutes)}m Idle`;
|
|
72394
|
+
}
|
|
72395
|
+
const impactText = recommendation.impact?.trim();
|
|
72396
|
+
if (impactText) {
|
|
72397
|
+
return impactText.length > 22 ? `${impactText.slice(0, 22).trim()}...` : impactText;
|
|
72398
|
+
}
|
|
72399
|
+
return "Review Issue";
|
|
72400
|
+
};
|
|
72401
|
+
var buildImprovementImpact = (recommendation) => {
|
|
72402
|
+
if (recommendation.issue_severity !== void 0 && recommendation.issue_severity !== null) {
|
|
72403
|
+
if (recommendation.issue_severity >= 3) return "High";
|
|
72404
|
+
if (recommendation.issue_severity >= 2) return "Medium";
|
|
72405
|
+
return "Low";
|
|
72406
|
+
}
|
|
72407
|
+
return "Medium";
|
|
72408
|
+
};
|
|
72409
|
+
var buildDeltaBadge = (delta, options) => {
|
|
72410
|
+
if (delta === null || delta === void 0 || !Number.isFinite(delta)) {
|
|
72411
|
+
return {
|
|
72412
|
+
icon: null,
|
|
72413
|
+
className: "bg-slate-100 text-slate-500",
|
|
72414
|
+
text: `No ${options.comparisonLabel} baseline`
|
|
72415
|
+
};
|
|
72416
|
+
}
|
|
72417
|
+
const direction = delta >= 0 ? "up" : "down";
|
|
72418
|
+
const isGood = options.positiveIsGood ? delta >= 0 : delta <= 0;
|
|
72419
|
+
return {
|
|
72420
|
+
icon: direction,
|
|
72421
|
+
className: isGood ? "bg-[#ecfdf5] text-[#059669]" : "bg-[#FEF2F2] text-[#DC2626]",
|
|
72422
|
+
text: `${options.formatter(delta)} vs ${options.comparisonLabel}`
|
|
72423
|
+
};
|
|
72424
|
+
};
|
|
72425
|
+
var buildLineDeltaTone = (delta, comparisonLabel) => {
|
|
72426
|
+
if (delta === null || delta === void 0 || !Number.isFinite(delta)) {
|
|
72427
|
+
return {
|
|
72428
|
+
className: "text-slate-400",
|
|
72429
|
+
text: `No ${comparisonLabel} baseline`
|
|
72430
|
+
};
|
|
72431
|
+
}
|
|
72432
|
+
return {
|
|
72433
|
+
className: delta >= 0 ? "text-[#059669]" : "text-[#DC2626]",
|
|
72434
|
+
text: `${delta >= 0 ? "+" : ""}${roundOne(delta)}% vs ${comparisonLabel}`
|
|
72435
|
+
};
|
|
72436
|
+
};
|
|
72437
|
+
var SectionPulse = ({ className }) => /* @__PURE__ */ jsx("div", { className: `animate-pulse rounded-md bg-slate-200/70 ${className || ""}` });
|
|
72438
|
+
var OverviewMetricCardSkeleton = () => /* @__PURE__ */ jsxs("div", { className: "mt-2 space-y-3", children: [
|
|
72439
|
+
/* @__PURE__ */ jsx(SectionPulse, { className: "h-8 w-32" }),
|
|
72440
|
+
/* @__PURE__ */ jsx(SectionPulse, { className: "h-6 w-44 rounded-full" })
|
|
72441
|
+
] });
|
|
72442
|
+
var OverviewListSkeleton = ({ rows = 3 }) => /* @__PURE__ */ jsx("div", { className: "space-y-4 py-3", children: Array.from({ length: rows }).map((_, index) => /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-4", children: [
|
|
72443
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 min-w-0", children: [
|
|
72444
|
+
/* @__PURE__ */ jsx(SectionPulse, { className: "h-8 w-8 rounded-full" }),
|
|
72445
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
72446
|
+
/* @__PURE__ */ jsx(SectionPulse, { className: "h-3 w-28" }),
|
|
72447
|
+
/* @__PURE__ */ jsx(SectionPulse, { className: "h-2.5 w-20" })
|
|
72448
|
+
] })
|
|
72449
|
+
] }),
|
|
72450
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
72451
|
+
/* @__PURE__ */ jsx(SectionPulse, { className: "h-4 w-12" }),
|
|
72452
|
+
/* @__PURE__ */ jsx(SectionPulse, { className: "h-6 w-10 rounded-full" })
|
|
72453
|
+
] })
|
|
72454
|
+
] }, index)) });
|
|
72455
|
+
var OverviewChartSkeleton = () => /* @__PURE__ */ jsx("div", { className: "w-full h-full animate-pulse", children: /* @__PURE__ */ jsx("div", { className: "h-full rounded-xl bg-gradient-to-b from-slate-100 to-slate-50 p-4", children: /* @__PURE__ */ jsx("div", { className: "h-full rounded-lg border border-dashed border-slate-200 bg-white/70 px-3 py-4", children: /* @__PURE__ */ jsx("div", { className: "flex h-full items-end gap-3", children: Array.from({ length: 7 }).map((_, index) => /* @__PURE__ */ jsxs("div", { className: "flex h-full flex-1 flex-col justify-end gap-2", children: [
|
|
72456
|
+
/* @__PURE__ */ jsx(SectionPulse, { className: `w-full rounded-md ${index % 3 === 0 ? "h-24" : index % 3 === 1 ? "h-32" : "h-20"}` }),
|
|
72457
|
+
/* @__PURE__ */ jsx(SectionPulse, { className: "h-2.5 w-8 self-center" })
|
|
72458
|
+
] }, index)) }) }) }) });
|
|
72459
|
+
var OverviewIdleBreakdownSkeleton = () => /* @__PURE__ */ jsxs("div", { className: "w-full h-full flex items-center overflow-hidden animate-pulse", children: [
|
|
72460
|
+
/* @__PURE__ */ jsx("div", { className: "flex-1 h-full min-w-0 relative flex items-center justify-center", children: /* @__PURE__ */ jsx("div", { className: "w-32 h-32 rounded-full bg-slate-200" }) }),
|
|
72461
|
+
/* @__PURE__ */ jsx("div", { className: "w-[50%] max-w-[200px] pl-2 flex flex-col justify-center h-full space-y-2", children: [1, 2, 3, 4].map((i) => /* @__PURE__ */ jsxs("div", { className: "flex items-center", children: [
|
|
72462
|
+
/* @__PURE__ */ jsx("div", { className: "w-2.5 h-2.5 rounded-full bg-slate-200 mr-1.5" }),
|
|
72463
|
+
/* @__PURE__ */ jsx("div", { className: "h-3 bg-slate-200 rounded w-20" })
|
|
72464
|
+
] }, i)) })
|
|
72465
|
+
] });
|
|
72466
|
+
var OverviewImprovementsSkeleton = () => /* @__PURE__ */ jsx("div", { className: "space-y-4 py-3", children: Array.from({ length: 3 }).map((_, index) => /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
|
|
72467
|
+
/* @__PURE__ */ jsx(SectionPulse, { className: "h-4 w-4 rounded-full" }),
|
|
72468
|
+
/* @__PURE__ */ jsxs("div", { className: "flex-1 space-y-2", children: [
|
|
72469
|
+
/* @__PURE__ */ jsx(SectionPulse, { className: "h-3 w-40" }),
|
|
72470
|
+
/* @__PURE__ */ jsx(SectionPulse, { className: "h-2.5 w-24" })
|
|
72471
|
+
] })
|
|
72472
|
+
] }, index)) });
|
|
72473
|
+
var PlantHeadView = () => {
|
|
72474
|
+
const supabase = useSupabase();
|
|
72475
|
+
const entityConfig = useEntityConfig();
|
|
72476
|
+
const appTimezone = useAppTimezone() || "UTC";
|
|
72477
|
+
const { navigate } = useNavigation();
|
|
72478
|
+
const { accessibleLineIds } = useUserLineAccess();
|
|
72479
|
+
const mobileMenuContext = useMobileMenu();
|
|
72480
|
+
useHideMobileHeader(!!mobileMenuContext);
|
|
72481
|
+
const [dateRange, setDateRange] = React141__default.useState(() => getLastSevenDayRange("UTC"));
|
|
72482
|
+
const [trendMode, setTrendMode] = React141__default.useState("all");
|
|
72483
|
+
const [poorestLineMode, setPoorestLineMode] = React141__default.useState("output");
|
|
72484
|
+
const [overview, setOverview] = React141__default.useState(EMPTY_OVERVIEW);
|
|
72485
|
+
const [isSnapshotLoading, setIsSnapshotLoading] = React141__default.useState(false);
|
|
72486
|
+
const [isTrendLoading, setIsTrendLoading] = React141__default.useState(false);
|
|
72487
|
+
const [trendFetchNonce, setTrendFetchNonce] = React141__default.useState(0);
|
|
72488
|
+
const [trendViewOpenNonce] = React141__default.useState(() => Date.now());
|
|
72489
|
+
const [idleReasonBreakdown, setIdleReasonBreakdown] = React141__default.useState([]);
|
|
72490
|
+
const [isIdleReasonBreakdownLoading, setIsIdleReasonBreakdownLoading] = React141__default.useState(false);
|
|
72491
|
+
const [improvements, setImprovements] = React141__default.useState([]);
|
|
72492
|
+
const [isImprovementsLoading, setIsImprovementsLoading] = React141__default.useState(false);
|
|
72493
|
+
const [isFilterOpen, setIsFilterOpen] = React141__default.useState(false);
|
|
72494
|
+
const filterRef = React141__default.useRef(null);
|
|
72495
|
+
const filterButtonRef = React141__default.useRef(null);
|
|
72496
|
+
const mobileFilterButtonRef = React141__default.useRef(null);
|
|
72497
|
+
React141__default.useEffect(() => {
|
|
72498
|
+
function handleClickOutside(event) {
|
|
72499
|
+
if (filterRef.current && !filterRef.current.contains(event.target) && filterButtonRef.current && !filterButtonRef.current.contains(event.target) && mobileFilterButtonRef.current && !mobileFilterButtonRef.current.contains(event.target)) {
|
|
72500
|
+
setIsFilterOpen(false);
|
|
72501
|
+
}
|
|
72502
|
+
}
|
|
72503
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
72504
|
+
return () => {
|
|
72505
|
+
document.removeEventListener("mousedown", handleClickOutside);
|
|
72506
|
+
};
|
|
72507
|
+
}, []);
|
|
72508
|
+
const hasInitializedRangeRef = React141__default.useRef(false);
|
|
72509
|
+
React141__default.useEffect(() => {
|
|
72510
|
+
if (hasInitializedRangeRef.current) return;
|
|
72511
|
+
setDateRange(getLastSevenDayRange(appTimezone));
|
|
72512
|
+
hasInitializedRangeRef.current = true;
|
|
72513
|
+
}, [appTimezone]);
|
|
72514
|
+
const companyId = entityConfig.companyId;
|
|
72515
|
+
const scopedLineIds = React141__default.useMemo(
|
|
72516
|
+
() => Array.from(new Set((accessibleLineIds || []).filter(Boolean))),
|
|
72517
|
+
[accessibleLineIds]
|
|
72518
|
+
);
|
|
72519
|
+
const lineIdsKey = React141__default.useMemo(
|
|
72520
|
+
() => scopedLineIds.slice().sort().join(","),
|
|
72521
|
+
[scopedLineIds]
|
|
72522
|
+
);
|
|
72523
|
+
const { supervisorsByLineId } = useSupervisorsByLineIds(scopedLineIds, {
|
|
72524
|
+
enabled: !!companyId && scopedLineIds.length > 0,
|
|
72525
|
+
companyId,
|
|
72526
|
+
useBackend: true
|
|
72527
|
+
});
|
|
72528
|
+
React141__default.useEffect(() => {
|
|
72529
|
+
if (!supabase || !companyId) return void 0;
|
|
72530
|
+
if (scopedLineIds.length === 0) {
|
|
72531
|
+
setOverview(EMPTY_OVERVIEW);
|
|
72532
|
+
setIdleReasonBreakdown([]);
|
|
72533
|
+
setIsSnapshotLoading(false);
|
|
72534
|
+
return void 0;
|
|
72535
|
+
}
|
|
72536
|
+
let cancelled = false;
|
|
72537
|
+
setOverview((prev) => ({
|
|
72538
|
+
...prev,
|
|
72539
|
+
scope: EMPTY_OVERVIEW.scope,
|
|
72540
|
+
summary: EMPTY_OVERVIEW.summary,
|
|
72541
|
+
poorest_lines: EMPTY_OVERVIEW.poorest_lines
|
|
72542
|
+
}));
|
|
72543
|
+
setIsSnapshotLoading(true);
|
|
72544
|
+
const fetchOverviewSnapshot = async () => {
|
|
72545
|
+
const params = new URLSearchParams({
|
|
72546
|
+
company_id: companyId,
|
|
72547
|
+
start_date: dateRange.startKey,
|
|
72548
|
+
end_date: dateRange.endKey,
|
|
72549
|
+
trend_shift_mode: trendMode,
|
|
72550
|
+
line_ids: scopedLineIds.join(",")
|
|
72551
|
+
});
|
|
72552
|
+
const response = await fetchBackendJson(
|
|
72553
|
+
supabase,
|
|
72554
|
+
`/api/dashboard/operations-overview/snapshot?${params.toString()}`
|
|
72555
|
+
);
|
|
72556
|
+
if (!cancelled) {
|
|
72557
|
+
setOverview((prev) => ({
|
|
72558
|
+
...prev,
|
|
72559
|
+
scope: response.scope || EMPTY_OVERVIEW.scope,
|
|
72560
|
+
summary: response.summary || EMPTY_OVERVIEW.summary,
|
|
72561
|
+
poorest_lines: response.poorest_lines || EMPTY_OVERVIEW.poorest_lines
|
|
72562
|
+
}));
|
|
72563
|
+
}
|
|
72564
|
+
};
|
|
72565
|
+
fetchOverviewSnapshot().catch((error) => {
|
|
72566
|
+
console.error("[PlantHeadView] Failed to fetch operations overview snapshot", error);
|
|
72567
|
+
if (!cancelled) {
|
|
72568
|
+
setOverview((prev) => ({
|
|
72569
|
+
...prev,
|
|
72570
|
+
scope: EMPTY_OVERVIEW.scope,
|
|
72571
|
+
summary: EMPTY_OVERVIEW.summary,
|
|
72572
|
+
poorest_lines: EMPTY_OVERVIEW.poorest_lines
|
|
72573
|
+
}));
|
|
72574
|
+
}
|
|
72575
|
+
}).finally(() => {
|
|
72576
|
+
if (!cancelled) {
|
|
72577
|
+
setIsSnapshotLoading(false);
|
|
72578
|
+
}
|
|
72579
|
+
});
|
|
72580
|
+
return () => {
|
|
72581
|
+
cancelled = true;
|
|
72582
|
+
};
|
|
72583
|
+
}, [
|
|
72584
|
+
companyId,
|
|
72585
|
+
dateRange.endKey,
|
|
72586
|
+
dateRange.startKey,
|
|
72587
|
+
lineIdsKey,
|
|
72588
|
+
scopedLineIds,
|
|
72589
|
+
supabase,
|
|
72590
|
+
trendMode
|
|
72591
|
+
]);
|
|
72592
|
+
React141__default.useEffect(() => {
|
|
72593
|
+
if (!supabase || !companyId) return void 0;
|
|
72594
|
+
if (scopedLineIds.length === 0) {
|
|
72595
|
+
setOverview((prev) => ({
|
|
72596
|
+
...prev,
|
|
72597
|
+
trend: EMPTY_OVERVIEW.trend
|
|
72598
|
+
}));
|
|
72599
|
+
setIsTrendLoading(false);
|
|
72600
|
+
return void 0;
|
|
72601
|
+
}
|
|
72602
|
+
let cancelled = false;
|
|
72603
|
+
setIsTrendLoading(true);
|
|
72604
|
+
const fetchOverviewTrend = async () => {
|
|
72605
|
+
const params = new URLSearchParams({
|
|
72606
|
+
company_id: companyId,
|
|
72607
|
+
start_date: dateRange.startKey,
|
|
72608
|
+
end_date: dateRange.endKey,
|
|
72609
|
+
trend_shift_mode: trendMode,
|
|
72610
|
+
line_ids: scopedLineIds.join(",")
|
|
72611
|
+
});
|
|
72612
|
+
const response = await fetchBackendJson(
|
|
72613
|
+
supabase,
|
|
72614
|
+
`/api/dashboard/operations-overview/trend?${params.toString()}`
|
|
72615
|
+
);
|
|
72616
|
+
if (!cancelled) {
|
|
72617
|
+
setOverview((prev) => ({
|
|
72618
|
+
...prev,
|
|
72619
|
+
trend: response.trend || EMPTY_OVERVIEW.trend
|
|
72620
|
+
}));
|
|
72621
|
+
setTrendFetchNonce((prev) => prev + 1);
|
|
72622
|
+
}
|
|
72623
|
+
};
|
|
72624
|
+
fetchOverviewTrend().catch((error) => {
|
|
72625
|
+
console.error("[PlantHeadView] Failed to fetch operations overview trend", error);
|
|
72626
|
+
}).finally(() => {
|
|
72627
|
+
if (!cancelled) {
|
|
72628
|
+
setIsTrendLoading(false);
|
|
72629
|
+
}
|
|
72630
|
+
});
|
|
72631
|
+
return () => {
|
|
72632
|
+
cancelled = true;
|
|
72633
|
+
};
|
|
72634
|
+
}, [
|
|
72635
|
+
companyId,
|
|
72636
|
+
dateRange.endKey,
|
|
72637
|
+
dateRange.startKey,
|
|
72638
|
+
lineIdsKey,
|
|
72639
|
+
scopedLineIds,
|
|
72640
|
+
supabase,
|
|
72641
|
+
trendMode
|
|
72642
|
+
]);
|
|
72643
|
+
React141__default.useEffect(() => {
|
|
72644
|
+
if (!supabase || !companyId) return void 0;
|
|
72645
|
+
if (scopedLineIds.length === 0) {
|
|
72646
|
+
setIdleReasonBreakdown([]);
|
|
72647
|
+
setIsIdleReasonBreakdownLoading(false);
|
|
72648
|
+
return void 0;
|
|
72649
|
+
}
|
|
72650
|
+
let cancelled = false;
|
|
72651
|
+
setIdleReasonBreakdown([]);
|
|
72652
|
+
setIsIdleReasonBreakdownLoading(true);
|
|
72653
|
+
const fetchIdleReasonBreakdown = async () => {
|
|
72654
|
+
const params = new URLSearchParams({
|
|
72655
|
+
company_id: companyId,
|
|
72656
|
+
start_date: dateRange.startKey,
|
|
72657
|
+
end_date: dateRange.endKey,
|
|
72658
|
+
trend_shift_mode: trendMode,
|
|
72659
|
+
line_ids: scopedLineIds.join(",")
|
|
72660
|
+
});
|
|
72661
|
+
const response = await fetchBackendJson(
|
|
72662
|
+
supabase,
|
|
72663
|
+
`/api/dashboard/operations-overview/idle-reason-breakdown?${params.toString()}`
|
|
72664
|
+
);
|
|
72665
|
+
if (!cancelled) {
|
|
72666
|
+
setIdleReasonBreakdown(response.idle_reason_breakdown || []);
|
|
72667
|
+
}
|
|
72668
|
+
};
|
|
72669
|
+
fetchIdleReasonBreakdown().catch((error) => {
|
|
72670
|
+
console.error("[PlantHeadView] Failed to fetch idle reason breakdown", error);
|
|
72671
|
+
if (!cancelled) {
|
|
72672
|
+
setIdleReasonBreakdown([]);
|
|
72673
|
+
}
|
|
72674
|
+
}).finally(() => {
|
|
72675
|
+
if (!cancelled) {
|
|
72676
|
+
setIsIdleReasonBreakdownLoading(false);
|
|
72677
|
+
}
|
|
72678
|
+
});
|
|
72679
|
+
return () => {
|
|
72680
|
+
cancelled = true;
|
|
72681
|
+
};
|
|
72682
|
+
}, [
|
|
72683
|
+
companyId,
|
|
72684
|
+
dateRange.endKey,
|
|
72685
|
+
dateRange.startKey,
|
|
72686
|
+
lineIdsKey,
|
|
72687
|
+
scopedLineIds,
|
|
72688
|
+
supabase,
|
|
72689
|
+
trendMode
|
|
72690
|
+
]);
|
|
72691
|
+
React141__default.useEffect(() => {
|
|
72692
|
+
if (!supabase || !companyId) return void 0;
|
|
72693
|
+
if (scopedLineIds.length === 0) {
|
|
72694
|
+
setImprovements([]);
|
|
72695
|
+
setIsImprovementsLoading(false);
|
|
72696
|
+
return void 0;
|
|
72697
|
+
}
|
|
72698
|
+
let cancelled = false;
|
|
72699
|
+
setIsImprovementsLoading(true);
|
|
72700
|
+
const fetchImprovements = async () => {
|
|
72701
|
+
const params = new URLSearchParams({
|
|
72702
|
+
company_id: companyId,
|
|
72703
|
+
status: "open",
|
|
72704
|
+
limit: "200",
|
|
72705
|
+
line_ids: scopedLineIds.join(",")
|
|
72706
|
+
});
|
|
72707
|
+
const response = await fetchBackendJson(
|
|
72708
|
+
supabase,
|
|
72709
|
+
`/api/improvement-center/recommendations?${params.toString()}`
|
|
72710
|
+
);
|
|
72711
|
+
if (cancelled) return;
|
|
72712
|
+
const allowedLineIds = new Set(scopedLineIds);
|
|
72713
|
+
const scopedRecommendations = (response.recommendations || []).filter((recommendation) => {
|
|
72714
|
+
return !recommendation.line_id || allowedLineIds.has(recommendation.line_id);
|
|
72715
|
+
});
|
|
72716
|
+
const nextImprovements = shuffle(scopedRecommendations).slice(0, 3).map((recommendation) => ({
|
|
72717
|
+
id: recommendation.id,
|
|
72718
|
+
title: recommendation.title?.trim() || "Untitled issue",
|
|
72719
|
+
impact: buildImprovementImpact(recommendation),
|
|
72720
|
+
metric: buildImprovementMetric(recommendation)
|
|
72721
|
+
}));
|
|
72722
|
+
setImprovements(nextImprovements);
|
|
72723
|
+
};
|
|
72724
|
+
fetchImprovements().catch((error) => {
|
|
72725
|
+
console.error("[PlantHeadView] Failed to fetch improvements", error);
|
|
72726
|
+
if (!cancelled) {
|
|
72727
|
+
setImprovements([]);
|
|
72728
|
+
}
|
|
72729
|
+
}).finally(() => {
|
|
72730
|
+
if (!cancelled) {
|
|
72731
|
+
setIsImprovementsLoading(false);
|
|
72732
|
+
}
|
|
72733
|
+
});
|
|
72734
|
+
return () => {
|
|
72735
|
+
cancelled = true;
|
|
72736
|
+
};
|
|
72737
|
+
}, [companyId, lineIdsKey, scopedLineIds, supabase]);
|
|
72738
|
+
const availableLineModes = overview.scope?.available_line_modes;
|
|
72739
|
+
React141__default.useEffect(() => {
|
|
72740
|
+
const hasOutput = !!availableLineModes?.has_output;
|
|
72741
|
+
const hasUptime = !!availableLineModes?.has_uptime;
|
|
72742
|
+
if (hasOutput && !hasUptime && poorestLineMode !== "output") {
|
|
72743
|
+
setPoorestLineMode("output");
|
|
72744
|
+
} else if (hasUptime && !hasOutput && poorestLineMode !== "uptime") {
|
|
72745
|
+
setPoorestLineMode("uptime");
|
|
72746
|
+
}
|
|
72747
|
+
}, [availableLineModes?.has_output, availableLineModes?.has_uptime, poorestLineMode]);
|
|
72748
|
+
const comparisonLabel = React141__default.useMemo(
|
|
72749
|
+
() => formatComparisonWindow(overview.scope?.current_range?.day_count ?? null),
|
|
72750
|
+
[overview.scope?.current_range?.day_count]
|
|
72751
|
+
);
|
|
72752
|
+
const plantEfficiencyBadge = React141__default.useMemo(() => {
|
|
72753
|
+
return buildDeltaBadge(overview.summary?.plant_efficiency?.delta_pp, {
|
|
72754
|
+
positiveIsGood: true,
|
|
72755
|
+
formatter: (value) => `${value >= 0 ? "+" : ""}${roundOne(value)}%`,
|
|
72756
|
+
comparisonLabel
|
|
72757
|
+
});
|
|
72758
|
+
}, [comparisonLabel, overview.summary?.plant_efficiency?.delta_pp]);
|
|
72759
|
+
const idleBadge = React141__default.useMemo(() => {
|
|
72760
|
+
return buildDeltaBadge(overview.summary?.avg_idle_per_workstation?.delta_seconds, {
|
|
72761
|
+
positiveIsGood: false,
|
|
72762
|
+
formatter: (value) => formatSignedIdleDuration(value),
|
|
72763
|
+
comparisonLabel
|
|
72764
|
+
});
|
|
72765
|
+
}, [comparisonLabel, overview.summary?.avg_idle_per_workstation?.delta_seconds]);
|
|
72766
|
+
const trendData = React141__default.useMemo(() => {
|
|
72767
|
+
return (overview.trend?.points || []).map((point) => ({
|
|
72768
|
+
name: point.date ? format(parseDateKeyToDate(point.date), "MMM d") : "",
|
|
72769
|
+
efficiency: (() => {
|
|
72770
|
+
const value = toNumber3(point.avg_efficiency);
|
|
72771
|
+
return value === null ? void 0 : value;
|
|
72772
|
+
})()
|
|
72773
|
+
}));
|
|
72774
|
+
}, [overview.trend?.points]);
|
|
72775
|
+
const trendPlayKey = React141__default.useMemo(() => {
|
|
72776
|
+
return `${trendViewOpenNonce}:${trendFetchNonce}`;
|
|
72777
|
+
}, [trendFetchNonce, trendViewOpenNonce]);
|
|
72778
|
+
const idleBreakdown = React141__default.useMemo(() => {
|
|
72779
|
+
return idleReasonBreakdown.map((item) => ({
|
|
72780
|
+
name: item.reason?.trim() || "Unknown",
|
|
72781
|
+
value: toNumber3(item.percentage) || 0,
|
|
72782
|
+
totalDurationSeconds: toNumber3(item.total_duration_seconds),
|
|
72783
|
+
efficiencyLossPercentage: toNumber3(item.efficiency_loss_percentage),
|
|
72784
|
+
contributors: (item.contributors || []).map((contributor) => ({
|
|
72785
|
+
workspaceId: contributor.workspace_id || "",
|
|
72786
|
+
workspaceName: contributor.workspace_name?.trim() || "Unknown",
|
|
72787
|
+
totalDurationSeconds: toNumber3(contributor.total_duration_seconds),
|
|
72788
|
+
percentageWithinReason: toNumber3(contributor.percentage_within_reason)
|
|
72789
|
+
}))
|
|
72790
|
+
})).filter((item) => item.value > 0);
|
|
72791
|
+
}, [idleReasonBreakdown]);
|
|
72792
|
+
const mergedPoorestLines = React141__default.useMemo(() => {
|
|
72793
|
+
const rows = overview.poorest_lines?.[poorestLineMode] || [];
|
|
72794
|
+
return rows.slice(0, 3).map((line) => {
|
|
72795
|
+
const lineId = line.line_id || "";
|
|
72796
|
+
const supervisors = supervisorsByLineId.get(lineId) || [];
|
|
72797
|
+
const supervisor = supervisors[0];
|
|
72798
|
+
return {
|
|
72799
|
+
id: lineId,
|
|
72800
|
+
name: line.line_name?.trim() || "Unknown Line",
|
|
72801
|
+
efficiency: roundOne(toNumber3(line.avg_efficiency) || 0),
|
|
72802
|
+
previousEfficiency: toNumber3(line.previous_avg_efficiency),
|
|
72803
|
+
delta: toNumber3(line.delta_pp),
|
|
72804
|
+
supervisor: supervisor?.displayName || "Unassigned",
|
|
72805
|
+
supervisorImage: supervisor?.profilePhotoUrl ?? null
|
|
72806
|
+
};
|
|
72807
|
+
});
|
|
72808
|
+
}, [overview.poorest_lines, poorestLineMode, supervisorsByLineId]);
|
|
72809
|
+
const showPoorestModeToggle = !!availableLineModes?.has_output && !!availableLineModes?.has_uptime;
|
|
72810
|
+
availableLineModes?.has_uptime && !availableLineModes?.has_output ? "Uptime" : "Output";
|
|
72811
|
+
const poorestMetricLabel = poorestLineMode === "uptime" ? "Uptime" : "Efficiency";
|
|
72812
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col min-h-screen bg-slate-50 w-full font-sans", children: [
|
|
72813
|
+
/* @__PURE__ */ jsx("header", { className: "sticky top-0 z-10 bg-white border-b flex-shrink-0 shadow-sm", children: /* @__PURE__ */ jsxs("div", { className: "px-3 sm:px-4 md:px-6 py-2 sm:py-3 relative", children: [
|
|
72814
|
+
/* @__PURE__ */ jsx("div", { className: "sm:hidden", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center", children: [
|
|
72815
|
+
mobileMenuContext ? /* @__PURE__ */ jsx(
|
|
72816
|
+
HamburgerButton,
|
|
72817
|
+
{
|
|
72818
|
+
onClick: mobileMenuContext.onMobileMenuOpen,
|
|
72819
|
+
className: "flex-shrink-0 -ml-1"
|
|
72820
|
+
}
|
|
72821
|
+
) : /* @__PURE__ */ jsx("div", { className: "w-8 flex-shrink-0" }),
|
|
72822
|
+
/* @__PURE__ */ jsxs("div", { className: "flex-1 flex flex-col items-center justify-center", children: [
|
|
72823
|
+
/* @__PURE__ */ jsx("h1", { className: "text-lg font-semibold text-gray-900 text-center px-1 truncate max-w-[200px]", children: "Operations Overview" }),
|
|
72824
|
+
/* @__PURE__ */ jsxs("span", { className: "text-[10px] font-medium text-slate-500 text-center mt-0.5", children: [
|
|
72825
|
+
format(parseDateKeyToDate(dateRange.startKey), "do MMM"),
|
|
72826
|
+
" - ",
|
|
72827
|
+
format(parseDateKeyToDate(dateRange.endKey), "do MMM, yyyy")
|
|
72828
|
+
] })
|
|
72829
|
+
] }),
|
|
72830
|
+
/* @__PURE__ */ jsxs("div", { className: "flex-shrink-0 flex items-center gap-1.5", children: [
|
|
72831
|
+
/* @__PURE__ */ jsx(
|
|
72832
|
+
MonthlyRangeFilter_default,
|
|
72833
|
+
{
|
|
72834
|
+
month: parseDateKeyToDate(dateRange.startKey).getMonth(),
|
|
72835
|
+
year: parseDateKeyToDate(dateRange.startKey).getFullYear(),
|
|
72836
|
+
timezone: appTimezone,
|
|
72837
|
+
value: dateRange,
|
|
72838
|
+
onChange: setDateRange,
|
|
72839
|
+
showLabel: false
|
|
72840
|
+
}
|
|
72841
|
+
),
|
|
72842
|
+
/* @__PURE__ */ jsxs(
|
|
72843
|
+
"button",
|
|
72844
|
+
{
|
|
72845
|
+
ref: mobileFilterButtonRef,
|
|
72846
|
+
onClick: () => setIsFilterOpen(!isFilterOpen),
|
|
72847
|
+
className: `p-2 rounded-full transition-colors relative ${isFilterOpen || trendMode !== "all" ? "bg-blue-50" : "active:bg-gray-100"}`,
|
|
72848
|
+
"aria-label": "Open filters",
|
|
72849
|
+
children: [
|
|
72850
|
+
/* @__PURE__ */ jsx(Filter, { className: `w-5 h-5 ${trendMode !== "all" ? "text-blue-600" : "text-gray-700"}` }),
|
|
72851
|
+
trendMode !== "all" && /* @__PURE__ */ jsx("span", { className: "absolute -top-1 -right-1 flex items-center justify-center w-4 h-4 bg-blue-600 text-white text-[10px] rounded-full font-bold", children: "1" })
|
|
72852
|
+
]
|
|
72853
|
+
}
|
|
72854
|
+
)
|
|
72855
|
+
] })
|
|
72856
|
+
] }) }),
|
|
72857
|
+
/* @__PURE__ */ jsx("div", { className: "hidden sm:block", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-center relative min-h-[56px]", children: [
|
|
72858
|
+
/* @__PURE__ */ jsxs("div", { className: "absolute left-1/2 -translate-x-1/2 flex flex-col items-center pointer-events-none", children: [
|
|
72859
|
+
/* @__PURE__ */ jsx("h1", { className: "text-2xl md:text-3xl lg:text-4xl font-semibold text-gray-900 tracking-tight text-center pointer-events-auto leading-tight mb-0.5", children: "Operations Overview" }),
|
|
72860
|
+
/* @__PURE__ */ jsxs("span", { className: "text-xs sm:text-sm font-medium text-slate-500 text-center pointer-events-auto", children: [
|
|
72861
|
+
format(parseDateKeyToDate(dateRange.startKey), "do MMMM, yyyy"),
|
|
72862
|
+
" - ",
|
|
72863
|
+
format(parseDateKeyToDate(dateRange.endKey), "do MMMM, yyyy")
|
|
72864
|
+
] })
|
|
72865
|
+
] }),
|
|
72866
|
+
/* @__PURE__ */ jsxs("div", { className: "absolute right-0 flex items-center gap-3", children: [
|
|
72867
|
+
/* @__PURE__ */ jsx("div", { className: "flex items-center", children: /* @__PURE__ */ jsx(
|
|
72868
|
+
MonthlyRangeFilter_default,
|
|
72869
|
+
{
|
|
72870
|
+
month: parseDateKeyToDate(dateRange.startKey).getMonth(),
|
|
72871
|
+
year: parseDateKeyToDate(dateRange.startKey).getFullYear(),
|
|
72872
|
+
timezone: appTimezone,
|
|
72873
|
+
value: dateRange,
|
|
72874
|
+
onChange: setDateRange,
|
|
72875
|
+
showLabel: false
|
|
72876
|
+
}
|
|
72877
|
+
) }),
|
|
72878
|
+
/* @__PURE__ */ jsxs(
|
|
72879
|
+
"button",
|
|
72880
|
+
{
|
|
72881
|
+
ref: filterButtonRef,
|
|
72882
|
+
onClick: () => setIsFilterOpen(!isFilterOpen),
|
|
72883
|
+
className: `flex items-center gap-2 px-3 py-1.5 rounded-lg border text-sm font-medium transition-all shadow-sm ${isFilterOpen || trendMode !== "all" ? "border-blue-500 bg-blue-50 text-blue-700 ring-1 ring-blue-500" : "border-slate-200 bg-white text-slate-700 hover:bg-slate-50"}`,
|
|
72884
|
+
"aria-label": "Open filters",
|
|
72885
|
+
children: [
|
|
72886
|
+
/* @__PURE__ */ jsx(Filter, { className: `w-[18px] h-[18px] ${trendMode !== "all" ? "text-blue-600" : "text-slate-500"}` }),
|
|
72887
|
+
"Filters",
|
|
72888
|
+
/* @__PURE__ */ jsx(ChevronDown, { className: `w-4 h-4 ml-0.5 transition-transform duration-200 ${isFilterOpen ? "rotate-180" : ""}` })
|
|
72889
|
+
]
|
|
72890
|
+
}
|
|
72891
|
+
)
|
|
72892
|
+
] })
|
|
72893
|
+
] }) }),
|
|
72894
|
+
isFilterOpen && /* @__PURE__ */ jsxs("div", { ref: filterRef, className: "absolute right-3 sm:right-4 md:right-5 lg:right-6 top-full mt-2 w-72 bg-white rounded-xl shadow-xl border border-gray-100 p-4 z-50", children: [
|
|
72895
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between mb-3", children: [
|
|
72896
|
+
/* @__PURE__ */ jsx("h3", { className: "text-sm font-semibold text-gray-900", children: "Filter View" }),
|
|
72897
|
+
trendMode !== "all" && /* @__PURE__ */ jsx(
|
|
72898
|
+
"button",
|
|
72899
|
+
{
|
|
72900
|
+
onClick: () => {
|
|
72901
|
+
setTrendMode("all");
|
|
72902
|
+
setIsFilterOpen(false);
|
|
72903
|
+
},
|
|
72904
|
+
className: "text-xs text-red-600 hover:text-red-700 font-medium",
|
|
72905
|
+
children: "Clear all"
|
|
72906
|
+
}
|
|
72907
|
+
)
|
|
72908
|
+
] }),
|
|
72909
|
+
/* @__PURE__ */ jsx("div", { className: "space-y-3", children: /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
|
|
72910
|
+
/* @__PURE__ */ jsx("label", { className: "text-xs font-medium text-gray-500 uppercase tracking-wide ml-1", children: "Shift" }),
|
|
72911
|
+
/* @__PURE__ */ jsx("div", { className: "relative", children: /* @__PURE__ */ jsxs(
|
|
72912
|
+
"select",
|
|
72913
|
+
{
|
|
72914
|
+
value: trendMode,
|
|
72915
|
+
onChange: (e) => setTrendMode(e.target.value),
|
|
72916
|
+
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",
|
|
72917
|
+
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` },
|
|
72918
|
+
children: [
|
|
72919
|
+
/* @__PURE__ */ jsx("option", { value: "all", children: "All Shifts" }),
|
|
72920
|
+
/* @__PURE__ */ jsx("option", { value: "day", children: "Day Shift" }),
|
|
72921
|
+
/* @__PURE__ */ jsx("option", { value: "night", children: "Night Shift" })
|
|
72922
|
+
]
|
|
72923
|
+
}
|
|
72924
|
+
) })
|
|
72925
|
+
] }) })
|
|
72926
|
+
] })
|
|
72927
|
+
] }) }),
|
|
72928
|
+
/* @__PURE__ */ jsxs("div", { className: "p-4 sm:p-6 pb-6 max-w-[1800px] mx-auto w-full flex-1 min-h-0 overflow-y-auto flex flex-col gap-5", children: [
|
|
72929
|
+
/* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 lg:grid-cols-2 gap-5", children: [
|
|
72930
|
+
/* @__PURE__ */ jsxs(
|
|
72931
|
+
"div",
|
|
72932
|
+
{
|
|
72933
|
+
className: "bg-white rounded-xl shadow-sm border border-slate-100 p-4 md:p-5 flex flex-col justify-center min-h-[100px] text-left",
|
|
72934
|
+
children: [
|
|
72935
|
+
/* @__PURE__ */ jsx("div", { className: "flex justify-between items-center mb-1", children: /* @__PURE__ */ jsx("h2", { className: "text-lg font-semibold text-gray-700", children: "Overall Efficiency" }) }),
|
|
72936
|
+
isSnapshotLoading ? /* @__PURE__ */ jsx(OverviewMetricCardSkeleton, {}) : overview.summary?.plant_efficiency?.current !== null && overview.summary?.plant_efficiency?.current !== void 0 ? /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2 sm:gap-3 mt-1", children: [
|
|
72937
|
+
/* @__PURE__ */ jsxs("span", { className: "text-2xl sm:text-3xl font-bold text-slate-800 tracking-tight", children: [
|
|
72938
|
+
roundOne(overview.summary.plant_efficiency.current),
|
|
72939
|
+
"%"
|
|
72940
|
+
] }),
|
|
72941
|
+
/* @__PURE__ */ jsxs("div", { className: `flex items-center gap-1 px-2.5 py-1 rounded-full ${plantEfficiencyBadge.className}`, children: [
|
|
72942
|
+
plantEfficiencyBadge.icon === "up" ? /* @__PURE__ */ jsx(ArrowUp, { className: "w-3.5 h-3.5", strokeWidth: 2.5 }) : plantEfficiencyBadge.icon === "down" ? /* @__PURE__ */ jsx(ArrowDown, { className: "w-3.5 h-3.5", strokeWidth: 2.5 }) : null,
|
|
72943
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs sm:text-sm font-medium", children: plantEfficiencyBadge.text })
|
|
72944
|
+
] })
|
|
72945
|
+
] }) : /* @__PURE__ */ jsx("div", { className: "mt-2 text-sm text-slate-400", children: "No efficiency data available" })
|
|
72946
|
+
]
|
|
72947
|
+
}
|
|
72948
|
+
),
|
|
72949
|
+
/* @__PURE__ */ jsxs(
|
|
72950
|
+
"div",
|
|
72951
|
+
{
|
|
72952
|
+
className: "bg-white rounded-xl shadow-sm border border-slate-100 p-4 md:p-5 flex flex-col justify-center min-h-[100px] text-left",
|
|
72953
|
+
children: [
|
|
72954
|
+
/* @__PURE__ */ jsx("div", { className: "flex justify-between items-center mb-1", children: /* @__PURE__ */ jsx("h2", { className: "text-lg font-semibold text-gray-700", children: "Idle Time per Workstation" }) }),
|
|
72955
|
+
isSnapshotLoading ? /* @__PURE__ */ jsx(OverviewMetricCardSkeleton, {}) : overview.summary?.avg_idle_per_workstation?.current_seconds !== null && overview.summary?.avg_idle_per_workstation?.current_seconds !== void 0 ? /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2 sm:gap-3 mt-1", children: [
|
|
72956
|
+
/* @__PURE__ */ jsx("span", { className: "text-2xl sm:text-3xl font-bold text-slate-800 tracking-tight", children: formatIdleDuration(overview.summary.avg_idle_per_workstation.current_seconds) }),
|
|
72957
|
+
/* @__PURE__ */ jsxs("div", { className: `flex items-center gap-1 px-2.5 py-1 rounded-full ${idleBadge.className}`, children: [
|
|
72958
|
+
idleBadge.icon === "up" ? /* @__PURE__ */ jsx(ArrowUp, { className: "w-3.5 h-3.5", strokeWidth: 2.5 }) : idleBadge.icon === "down" ? /* @__PURE__ */ jsx(ArrowDown, { className: "w-3.5 h-3.5", strokeWidth: 2.5 }) : null,
|
|
72959
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs sm:text-sm font-medium", children: idleBadge.text })
|
|
72960
|
+
] })
|
|
72961
|
+
] }) : /* @__PURE__ */ jsx("div", { className: "mt-2 text-sm text-slate-400", children: "No idle time data available" })
|
|
72962
|
+
]
|
|
72963
|
+
}
|
|
72964
|
+
)
|
|
72965
|
+
] }),
|
|
72966
|
+
/* @__PURE__ */ jsxs("div", { className: "flex-1 min-h-0 grid grid-cols-1 xl:grid-cols-2 gap-5 auto-rows-fr", children: [
|
|
72967
|
+
/* @__PURE__ */ jsxs("div", { className: "grid grid-rows-1 xl:grid-rows-2 gap-5 min-h-0", children: [
|
|
72968
|
+
/* @__PURE__ */ jsxs("div", { className: "bg-white rounded-xl shadow-sm border border-slate-100 flex flex-col overflow-hidden", children: [
|
|
72969
|
+
/* @__PURE__ */ jsxs("div", { className: "px-5 py-4 border-b border-slate-50 flex justify-between items-center gap-3 flex-wrap", children: [
|
|
72970
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 flex-wrap", children: [
|
|
72971
|
+
/* @__PURE__ */ jsx("h2", { className: "text-lg font-semibold text-gray-700", children: "Poorest Performers" }),
|
|
72972
|
+
showPoorestModeToggle && /* @__PURE__ */ jsxs("div", { className: "flex bg-slate-100 p-0.5 rounded-lg", children: [
|
|
72973
|
+
/* @__PURE__ */ jsx(
|
|
72974
|
+
"button",
|
|
72975
|
+
{
|
|
72976
|
+
type: "button",
|
|
72977
|
+
onClick: () => setPoorestLineMode("output"),
|
|
72978
|
+
className: `px-3 py-1 text-[11px] font-bold rounded-md ${poorestLineMode === "output" ? "bg-white text-slate-800 shadow-sm" : "text-slate-500 hover:text-slate-800"}`,
|
|
72979
|
+
children: "Output"
|
|
72980
|
+
}
|
|
72981
|
+
),
|
|
72982
|
+
/* @__PURE__ */ jsx(
|
|
72983
|
+
"button",
|
|
72984
|
+
{
|
|
72985
|
+
type: "button",
|
|
72986
|
+
onClick: () => setPoorestLineMode("uptime"),
|
|
72987
|
+
className: `px-3 py-1 text-[11px] font-bold rounded-md ${poorestLineMode === "uptime" ? "bg-white text-slate-800 shadow-sm" : "text-slate-500 hover:text-slate-800"}`,
|
|
72988
|
+
children: "Uptime"
|
|
72989
|
+
}
|
|
72990
|
+
)
|
|
72991
|
+
] })
|
|
72992
|
+
] }),
|
|
72993
|
+
/* @__PURE__ */ jsx(
|
|
72994
|
+
"button",
|
|
72995
|
+
{
|
|
72996
|
+
type: "button",
|
|
72997
|
+
onClick: () => navigate("/kpis"),
|
|
72998
|
+
className: "text-[11px] font-bold text-slate-500 hover:text-slate-800 transition-colors",
|
|
72999
|
+
children: "View All"
|
|
73000
|
+
}
|
|
73001
|
+
)
|
|
73002
|
+
] }),
|
|
73003
|
+
/* @__PURE__ */ jsx("div", { className: "flex-1 flex flex-col p-0 overflow-auto", children: /* @__PURE__ */ jsxs("div", { className: "divide-y divide-slate-50 flex-1 px-5", children: [
|
|
73004
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between py-2", children: [
|
|
73005
|
+
/* @__PURE__ */ jsx("div", { className: "font-semibold text-slate-400 text-[10px] uppercase tracking-wider min-w-[120px]", children: "Line" }),
|
|
73006
|
+
/* @__PURE__ */ jsx("div", { className: "font-semibold text-slate-400 text-[10px] uppercase tracking-wider text-left shrink-0 min-w-[110px] flex items-center gap-2", children: poorestMetricLabel })
|
|
73007
|
+
] }),
|
|
73008
|
+
isSnapshotLoading ? /* @__PURE__ */ jsx(OverviewListSkeleton, {}) : mergedPoorestLines.length > 0 ? mergedPoorestLines.map((line) => {
|
|
73009
|
+
const lineDelta = buildLineDeltaTone(line.delta, comparisonLabel);
|
|
73010
|
+
return /* @__PURE__ */ jsx(
|
|
73011
|
+
"div",
|
|
73012
|
+
{
|
|
73013
|
+
onClick: () => navigate(`/kpis/${line.id}`),
|
|
73014
|
+
className: "block py-3 hover:bg-slate-50/50 transition-colors cursor-pointer group relative",
|
|
73015
|
+
children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-4", children: [
|
|
73016
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 min-w-0", children: [
|
|
73017
|
+
/* @__PURE__ */ jsx("div", { className: "w-8 h-8 rounded-full bg-slate-100 border border-slate-200 overflow-hidden flex-shrink-0", children: line.supervisorImage ? /* @__PURE__ */ jsx(
|
|
73018
|
+
"img",
|
|
73019
|
+
{
|
|
73020
|
+
src: line.supervisorImage,
|
|
73021
|
+
alt: line.supervisor,
|
|
73022
|
+
className: "w-full h-full object-cover"
|
|
73023
|
+
}
|
|
73024
|
+
) : /* @__PURE__ */ jsx("div", { className: "w-full h-full flex items-center justify-center text-[10px] font-bold text-slate-500", children: line.supervisor.split(" ").map((part) => part[0]).join("").slice(0, 2) }) }),
|
|
73025
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
|
|
73026
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
73027
|
+
/* @__PURE__ */ jsx("div", { className: "font-bold text-slate-800 text-[13px] truncate group-hover:text-indigo-600 transition-colors", children: line.name }),
|
|
73028
|
+
/* @__PURE__ */ jsxs(
|
|
73029
|
+
"button",
|
|
73030
|
+
{
|
|
73031
|
+
type: "button",
|
|
73032
|
+
onClick: (event) => {
|
|
73033
|
+
event.stopPropagation();
|
|
73034
|
+
console.log(`Notify ${line.supervisor}`);
|
|
73035
|
+
},
|
|
73036
|
+
className: "flex items-center gap-1 text-[9px] font-bold text-slate-500 bg-slate-100 px-1.5 py-0.5 rounded transition-colors hover:bg-slate-200 hover:text-slate-700",
|
|
73037
|
+
children: [
|
|
73038
|
+
/* @__PURE__ */ jsx(Bell, { className: "w-2.5 h-2.5" }),
|
|
73039
|
+
"Notify"
|
|
73040
|
+
]
|
|
73041
|
+
}
|
|
73042
|
+
)
|
|
73043
|
+
] }),
|
|
73044
|
+
/* @__PURE__ */ jsx("div", { className: "flex items-center gap-2 mt-0.5 flex-wrap", children: /* @__PURE__ */ jsx("span", { className: "text-[10px] text-slate-400 font-medium", children: line.supervisor }) })
|
|
73045
|
+
] })
|
|
73046
|
+
] }),
|
|
73047
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 shrink-0 justify-start min-w-[110px]", children: [
|
|
73048
|
+
/* @__PURE__ */ jsxs("div", { className: "text-[15px] font-bold text-slate-800", children: [
|
|
73049
|
+
line.efficiency,
|
|
73050
|
+
"%"
|
|
73051
|
+
] }),
|
|
73052
|
+
line.delta !== null && line.delta !== void 0 && Number.isFinite(line.delta) ? /* @__PURE__ */ jsxs("div", { className: `flex items-center gap-0.5 px-2 py-0.5 rounded-full ${line.delta >= 0 ? "bg-[#ecfdf5] text-[#059669]" : "bg-[#FEF2F2] text-[#DC2626]"}`, children: [
|
|
73053
|
+
line.delta >= 0 ? /* @__PURE__ */ jsx(ArrowUp, { className: "w-3 h-3", strokeWidth: 2.5 }) : /* @__PURE__ */ jsx(ArrowDown, { className: "w-3 h-3", strokeWidth: 2.5 }),
|
|
73054
|
+
/* @__PURE__ */ jsx("span", { className: "text-[11px] font-bold", children: lineDelta.text.split(" vs ")[0].replace("+", "") })
|
|
73055
|
+
] }) : /* @__PURE__ */ jsx("div", { className: "flex items-center gap-0.5 px-2 py-0.5 rounded-full bg-slate-50 text-slate-400", children: /* @__PURE__ */ jsx("span", { className: "text-[11px] font-bold", children: "\u2014" }) })
|
|
73056
|
+
] })
|
|
73057
|
+
] })
|
|
73058
|
+
},
|
|
73059
|
+
line.id
|
|
73060
|
+
);
|
|
73061
|
+
}) : /* @__PURE__ */ jsx("div", { className: "py-8 text-center text-sm text-slate-400", children: `No ${poorestLineMode} line data available` })
|
|
73062
|
+
] }) })
|
|
73063
|
+
] }),
|
|
73064
|
+
/* @__PURE__ */ jsxs(
|
|
73065
|
+
"div",
|
|
73066
|
+
{
|
|
73067
|
+
className: "bg-white rounded-xl shadow-sm border border-slate-100 flex flex-col overflow-hidden text-left",
|
|
73068
|
+
children: [
|
|
73069
|
+
/* @__PURE__ */ jsx("div", { className: "px-5 py-4 flex-none flex justify-between items-center border-b border-slate-50/50 relative", children: /* @__PURE__ */ jsx("h2", { className: "text-lg font-semibold text-gray-700", children: "Idle Time Breakdown" }) }),
|
|
73070
|
+
/* @__PURE__ */ jsx("div", { className: "flex-1 min-h-0 p-4 pt-2 relative", children: isIdleReasonBreakdownLoading ? /* @__PURE__ */ jsx(OverviewIdleBreakdownSkeleton, {}) : /* @__PURE__ */ jsx(
|
|
73071
|
+
IdleTimeReasonChart,
|
|
73072
|
+
{
|
|
73073
|
+
data: idleBreakdown,
|
|
73074
|
+
isLoading: false,
|
|
73075
|
+
hideTotalDuration: true
|
|
73076
|
+
}
|
|
73077
|
+
) })
|
|
73078
|
+
]
|
|
73079
|
+
}
|
|
73080
|
+
)
|
|
73081
|
+
] }),
|
|
73082
|
+
/* @__PURE__ */ jsxs("div", { className: "grid grid-rows-1 xl:grid-rows-2 gap-5 min-h-0", children: [
|
|
73083
|
+
/* @__PURE__ */ jsxs(
|
|
73084
|
+
"div",
|
|
73085
|
+
{
|
|
73086
|
+
className: "bg-white rounded-xl shadow-[0_2px_10px_-3px_rgba(6,81,237,0.1)] border border-slate-100 flex flex-col overflow-hidden text-left",
|
|
73087
|
+
children: [
|
|
73088
|
+
/* @__PURE__ */ jsx("div", { className: "px-6 py-5 flex-none flex justify-between items-center border-b border-slate-50/50", children: /* @__PURE__ */ jsx("h2", { className: "text-lg font-semibold text-gray-700", children: "Efficiency Trend" }) }),
|
|
73089
|
+
/* @__PURE__ */ jsx("div", { className: "flex-1 min-h-0 w-full p-4 pt-4 relative", children: isTrendLoading ? /* @__PURE__ */ jsx(OverviewChartSkeleton, {}) : /* @__PURE__ */ jsx("div", { className: "absolute inset-0 pb-2 pr-4 pl-1", children: /* @__PURE__ */ jsx(
|
|
73090
|
+
LineChart,
|
|
73091
|
+
{
|
|
73092
|
+
data: trendData,
|
|
73093
|
+
lines: efficiencyLineConfig,
|
|
73094
|
+
xAxisDataKey: "name",
|
|
73095
|
+
yAxisUnit: "%",
|
|
73096
|
+
yAxisDomain: [0, 100],
|
|
73097
|
+
showLegend: false,
|
|
73098
|
+
showGrid: true,
|
|
73099
|
+
fillContainer: true
|
|
73100
|
+
},
|
|
73101
|
+
trendPlayKey
|
|
73102
|
+
) }) })
|
|
73103
|
+
]
|
|
73104
|
+
}
|
|
73105
|
+
),
|
|
73106
|
+
/* @__PURE__ */ jsxs("div", { className: "bg-white rounded-xl shadow-sm border border-slate-100 flex flex-col overflow-hidden", children: [
|
|
73107
|
+
/* @__PURE__ */ jsxs("div", { className: "px-5 py-4 flex-none flex justify-between items-center border-b border-slate-50/50", children: [
|
|
73108
|
+
/* @__PURE__ */ jsx("h2", { className: "text-lg font-semibold text-gray-700", children: "Improvements" }),
|
|
73109
|
+
/* @__PURE__ */ jsx(
|
|
73110
|
+
"button",
|
|
73111
|
+
{
|
|
73112
|
+
type: "button",
|
|
73113
|
+
onClick: () => navigate("/improvement-center"),
|
|
73114
|
+
className: "text-[11px] font-bold text-slate-500 hover:text-slate-800 transition-colors",
|
|
73115
|
+
children: "View All"
|
|
73116
|
+
}
|
|
73117
|
+
)
|
|
73118
|
+
] }),
|
|
73119
|
+
/* @__PURE__ */ jsx("div", { className: "flex-1 p-0 flex flex-col px-5 py-2 justify-start overflow-auto", children: isImprovementsLoading ? /* @__PURE__ */ jsx(OverviewImprovementsSkeleton, {}) : improvements.length > 0 ? improvements.map((item) => /* @__PURE__ */ jsx(
|
|
73120
|
+
"div",
|
|
73121
|
+
{
|
|
73122
|
+
onClick: () => navigate("/improvement-center"),
|
|
73123
|
+
className: "flex items-center justify-between py-3 border-b border-slate-50 last:border-0 group cursor-pointer",
|
|
73124
|
+
children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 flex-1 min-w-0 pr-4", children: [
|
|
73125
|
+
/* @__PURE__ */ jsx("div", { className: "flex items-center justify-center flex-shrink-0", children: /* @__PURE__ */ jsx(ArrowUpRight, { className: "w-4 h-4 text-slate-400 group-hover:text-indigo-500 transition-colors" }) }),
|
|
73126
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
73127
|
+
/* @__PURE__ */ jsx("h4", { className: "text-[13px] font-semibold text-slate-800 truncate transition-colors group-hover:text-indigo-600 mb-0.5", children: item.title }),
|
|
73128
|
+
/* @__PURE__ */ jsxs("p", { className: "text-[10px] font-medium text-slate-400", children: [
|
|
73129
|
+
"Impact: ",
|
|
73130
|
+
/* @__PURE__ */ jsx("span", { className: "text-slate-500 font-semibold", children: item.impact })
|
|
73131
|
+
] })
|
|
73132
|
+
] })
|
|
73133
|
+
] })
|
|
73134
|
+
},
|
|
73135
|
+
item.id
|
|
73136
|
+
)) : /* @__PURE__ */ jsx("div", { className: "py-8 text-center text-sm text-slate-400", children: "No open improvement issues" }) })
|
|
73137
|
+
] })
|
|
73138
|
+
] })
|
|
73139
|
+
] })
|
|
73140
|
+
] })
|
|
73141
|
+
] });
|
|
73142
|
+
};
|
|
73143
|
+
var PlantHeadView_default = PlantHeadView;
|
|
71588
73144
|
var S3Service = class {
|
|
71589
73145
|
constructor(config) {
|
|
71590
73146
|
this.s3Client = null;
|
|
@@ -72061,4 +73617,4 @@ var streamProxyConfig = {
|
|
|
72061
73617
|
}
|
|
72062
73618
|
};
|
|
72063
73619
|
|
|
72064
|
-
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, AvatarUpload, 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, ClipsCostView_default as ClipsCostView, 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, EFFICIENCY_ON_TRACK_THRESHOLD, EmptyStateMessage, EncouragementOverlay, FactoryAssignmentDropdown, FactoryView_default as FactoryView, FileManagerFilters, FilterDialogTrigger, FirstTimeLoginDebug, FirstTimeLoginHandler, FittingTitle, GaugeChart, GridComponentsPlaceholder, HamburgerButton, Header, HealthDateShiftSelector, HealthStatusGrid, HealthStatusIndicator, HelpView_default as HelpView, HlsVideoPlayer, HomeView_default as HomeView, HourlyOutputChart2 as HourlyOutputChart, HourlyUptimeChart, ISTTimer_default as ISTTimer, IdleTimeVlmConfigProvider, 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, MobileMenuProvider, 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, SettingsPopup, ShiftDisplay_default as ShiftDisplay, ShiftsView_default as ShiftsView, SideNavBar, SignupWithInvitation, SilentErrorBoundary, SimpleOnboardingPopup, SingleVideoStream_default as SingleVideoStream, Skeleton, SubscriptionManager, SubscriptionManagerProvider, SupabaseProvider, SupervisorDropdown_default as SupervisorDropdown, SupervisorManagementView_default as SupervisorManagementView, SupervisorService, TargetWorkspaceGrid, TargetsView_default as TargetsView, TeamManagementView_default as TeamManagementView, ThreadSidebar, TicketHistory_default as TicketHistory, TicketHistoryService, TicketsView_default as TicketsView, TimeDisplay_default as TimeDisplay, TimePickerDropdown, Timer_default as Timer, TimezoneProvider, TimezoneService, UptimeDonutChart, UptimeLineChart, UptimeMetricCards, UserAvatar, 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, awardsService, buildDateKey, buildKPIsFromLineMetricsRow, buildShiftGroupsKey, captureSentryException, captureSentryMessage, checkRateLimit2 as checkRateLimit, clearAllRateLimits2 as clearAllRateLimits, clearRateLimit2 as clearRateLimit, clearS3VideoCache, clearS3VideoFromCache, clearSentryContext, clearWorkspaceDisplayNamesCache, cn, createDefaultKPIs, createInvitationService, createLinesService, createSessionTracker, createStorageService, createStreamProxyHandler, createSupabaseClient, createSupervisorService, createThrottledReload, createUserManagementService, createUserService, dashboardService, deleteThread, fetchIdleTimeReasons, filterDataByDateKeyRange, forceRefreshWorkspaceDisplayNames, formatAwardMonth, formatDateInZone, formatDateKeyForDisplay, formatDateTimeInZone, formatDuration, formatISTDate, formatIdleTime, formatRangeLabel, formatReasonLabel, formatRelativeTime, formatTimeInZone, fromUrlFriendlyName, getAllLineDisplayNames, getAllThreadMessages, getAllWorkspaceDisplayNamesAsync, getAllWorkspaceDisplayNamesSnapshot, getAnonClient, getAvailableShiftIds, getAwardBadgeType, getAwardDescription, getAwardTitle, getBrowserName, getCameraNumber, getCompanyMetricsTableName, getConfigurableShortWorkspaceDisplayName, getConfigurableWorkspaceDisplayName, getConfiguredLineIds, getCoreSessionRecordingProperties, getCoreSessionReplayUrl, getCurrentShift, getCurrentShiftForLine, getCurrentTimeInZone, getDashboardHeaderTimeInZone, getDateKeyFromDate, getDaysDifferenceInZone, getDefaultCameraStreamUrl, getDefaultLineId, getDefaultTabForWorkspace, getInitials, getLineDisplayName, getManufacturingInsights, getMetricsTablePrefix, getMonthKeyBounds, getMonthWeekRanges, getNextUpdateInterval, getOperationalDate, getReasonColor, getS3SignedUrl, getS3VideoSrc, getShiftData, getShiftNameById, getShiftWorkDurationSeconds, getShortShiftName, getShortWorkspaceDisplayName, getShortWorkspaceDisplayNameAsync, getStoredWorkspaceMappings, getSubscriptionManager, getThreadMessages, getUniformShiftGroup, getUserThreads, getUserThreadsPaginated, getWorkspaceDisplayName, getWorkspaceDisplayNameAsync, getWorkspaceDisplayNamesMap, getWorkspaceFromUrl, getWorkspaceNavigationParams, groupLinesByShift, hasAnyShiftData, identifyCoreUser, initializeCoreMixpanel, isEfficiencyOnTrack, isFullMonthRange, isLegacyConfiguration, isPrefetchError, isSafari, isTransitionPeriod, isUrlPermanentlyFailed, isValidFactoryViewConfiguration, isValidLineInfoPayload, isValidPrefetchParams, isValidPrefetchStatus, isValidWorkspaceDetailedMetricsPayload, isValidWorkspaceMetricsPayload, isWorkspaceDisplayNamesLoaded, isWorkspaceDisplayNamesLoading, lineLeaderboardService, linesService, mergeWithDefaultConfig, migrateLegacyConfiguration, normalizeDateKeyRange, optifyeAgentClient, parseDateKeyToDate, parseS3Uri, preInitializeWorkspaceDisplayNames, preloadS3Video, preloadS3VideoUrl, preloadS3VideosUrl, preloadVideoUrl, preloadVideosUrl, qualityService, realtimeService, refreshWorkspaceDisplayNames, resetCoreMixpanel, resetFailedUrl, resetSubscriptionManager, s3VideoPreloader, setSentryUserContext, setSentryWorkspaceContext, 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, useClipsInit, useCompanyClipsCost, useCompanyUsersUsage, useComponentOverride, useCustomConfig, useDashboardConfig, useDashboardMetrics, useDatabaseConfig, useDateFormatter, useDateTimeConfig, useDynamicShiftConfig, useEndpointsConfig, useEntityConfig, useFactoryOverviewMetrics, useFeatureFlags, useFormatNumber, useHasLineAccess, useHideMobileHeader, useHistoricWorkspaceMetrics, useHlsStream, useHlsStreamWithCropping, useHookOverride, useHourEndTimer, useHourlyTargetAchievements, useHourlyTargetMisses, useIdleTimeClipClassifications, useIdleTimeReasons, useIdleTimeVlmConfig, useKpiTrends, useLeaderboardMetrics, useLineDetailedMetrics, useLineKPIs, useLineMetrics, useLineShiftConfig, useLineSupervisor, useLineWorkspaceMetrics, useLines, useMessages, useMetrics, useMobileMenu, useMonthlyTrend, useMultiLineShiftConfigs, useNavigation, useOperationalShiftKey, useOptionalSupabase, useOverrides, usePageOverride, usePrefetchClipCounts, useRealtimeLineMetrics, useRegistry, useSKUs, useSessionKeepAlive, useSessionTracking, useSessionTrackingContext, useShiftConfig, useShiftGroups, useShifts, useSubscriptionManager, useSubscriptionManagerSafe, useSupabase, useSupabaseClient, useSupervisorsByLineIds, useTargets, useTeamManagementPermissions, useTheme, useThemeConfig, useThreads, useTicketHistory, useTimezoneContext, useUserLineAccess, useUserUsage, useVideoConfig, useWorkspaceConfig, useWorkspaceDetailedMetrics, useWorkspaceDisplayName, useWorkspaceDisplayNames, useWorkspaceDisplayNamesMap, useWorkspaceHealthById, useWorkspaceHealthLastSeen, useWorkspaceHealthStatus, useWorkspaceMetrics, useWorkspaceNavigation, useWorkspaceOperators, useWorkspaceUptimeTimeline, useWorkspaceVideoStreams, userService, videoPrefetchManager, videoPreloader, weeklyTopPerformerService, whatsappService, withAccessControl, withAuth, withRegistry, withTimezone, workspaceHealthService, workspaceService };
|
|
73620
|
+
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, AvatarUpload, 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, ClipsCostView_default as ClipsCostView, 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, EFFICIENCY_ON_TRACK_THRESHOLD, EmptyStateMessage, EncouragementOverlay, FactoryAssignmentDropdown, FactoryView_default as FactoryView, FileManagerFilters, FilterDialogTrigger, FirstTimeLoginDebug, FirstTimeLoginHandler, FittingTitle, GaugeChart, GridComponentsPlaceholder, HamburgerButton, Header, HealthDateShiftSelector, HealthStatusGrid, HealthStatusIndicator, HelpView_default as HelpView, HlsVideoPlayer, HomeView_default as HomeView, HourlyOutputChart2 as HourlyOutputChart, HourlyUptimeChart, ISTTimer_default as ISTTimer, IdleTimeVlmConfigProvider, 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, MobileMenuProvider, NewClipsNotification, NoWorkspaceData, OnboardingDemo, OnboardingTour, OptifyeAgentClient, OptifyeLogoLoader_default as OptifyeLogoLoader, OutputProgressChart, PageHeader, PieChart4 as PieChart, PlantHeadView_default as PlantHeadView, 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, SettingsPopup, ShiftDisplay_default as ShiftDisplay, ShiftsView_default as ShiftsView, SideNavBar, SignupWithInvitation, SilentErrorBoundary, SimpleOnboardingPopup, SingleVideoStream_default as SingleVideoStream, Skeleton, SubscriptionManager, SubscriptionManagerProvider, SupabaseProvider, SupervisorDropdown_default as SupervisorDropdown, SupervisorManagementView_default as SupervisorManagementView, SupervisorService, TargetWorkspaceGrid, TargetsView_default as TargetsView, TeamManagementView_default as TeamManagementView, ThreadSidebar, TicketHistory_default as TicketHistory, TicketHistoryService, TicketsView_default as TicketsView, TimeDisplay_default as TimeDisplay, TimePickerDropdown, Timer_default as Timer, TimezoneProvider, TimezoneService, UptimeDonutChart, UptimeLineChart, UptimeMetricCards, UserAvatar, 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, alertsService, apiUtils, areAllLinesOnSameShift, authCoreService, authOTPService, authRateLimitService, awardsService, buildDateKey, buildKPIsFromLineMetricsRow, buildShiftGroupsKey, captureSentryException, captureSentryMessage, checkRateLimit2 as checkRateLimit, clearAllRateLimits2 as clearAllRateLimits, clearRateLimit2 as clearRateLimit, clearS3VideoCache, clearS3VideoFromCache, clearSentryContext, clearWorkspaceDisplayNamesCache, cn, createDefaultKPIs, createInvitationService, createLinesService, createSessionTracker, createStorageService, createStreamProxyHandler, createSupabaseClient, createSupervisorService, createThrottledReload, createUserManagementService, createUserService, dashboardService, deleteThread, fetchIdleTimeReasons, filterDataByDateKeyRange, forceRefreshWorkspaceDisplayNames, formatAwardMonth, formatDateInZone, formatDateKeyForDisplay, formatDateTimeInZone, formatDuration2 as formatDuration, formatISTDate, formatIdleTime, formatRangeLabel, formatReasonLabel, formatRelativeTime, formatTimeInZone, fromUrlFriendlyName, getAllLineDisplayNames, getAllThreadMessages, getAllWorkspaceDisplayNamesAsync, getAllWorkspaceDisplayNamesSnapshot, getAnonClient, getAvailableShiftIds, getAwardBadgeType, getAwardDescription, getAwardTitle, getBrowserName, getCameraNumber, getCompanyMetricsTableName, getConfigurableShortWorkspaceDisplayName, getConfigurableWorkspaceDisplayName, getConfiguredLineIds, getCoreSessionRecordingProperties, getCoreSessionReplayUrl, getCurrentShift, getCurrentShiftForLine, getCurrentTimeInZone, getDashboardHeaderTimeInZone, getDateKeyFromDate, getDaysDifferenceInZone, getDefaultCameraStreamUrl, getDefaultLineId, getDefaultTabForWorkspace, getInitials, getLineDisplayName, getManufacturingInsights, getMetricsTablePrefix, getMonthKeyBounds, getMonthWeekRanges, getNextUpdateInterval, getOperationalDate, getReasonColor, getS3SignedUrl, getS3VideoSrc, getShiftData, getShiftNameById, getShiftWorkDurationSeconds, getShortShiftName, getShortWorkspaceDisplayName, getShortWorkspaceDisplayNameAsync, getStoredWorkspaceMappings, getSubscriptionManager, getThreadMessages, getUniformShiftGroup, getUserThreads, getUserThreadsPaginated, getWorkspaceDisplayName, getWorkspaceDisplayNameAsync, getWorkspaceDisplayNamesMap, getWorkspaceFromUrl, getWorkspaceNavigationParams, groupLinesByShift, hasAnyShiftData, identifyCoreUser, initializeCoreMixpanel, isEfficiencyOnTrack, isFullMonthRange, isLegacyConfiguration, isPrefetchError, isSafari, isTransitionPeriod, isUrlPermanentlyFailed, isValidFactoryViewConfiguration, isValidLineInfoPayload, isValidPrefetchParams, isValidPrefetchStatus, isValidWorkspaceDetailedMetricsPayload, isValidWorkspaceMetricsPayload, isWorkspaceDisplayNamesLoaded, isWorkspaceDisplayNamesLoading, lineLeaderboardService, linesService, mergeWithDefaultConfig, migrateLegacyConfiguration, normalizeDateKeyRange, optifyeAgentClient, parseDateKeyToDate, parseS3Uri, preInitializeWorkspaceDisplayNames, preloadS3Video, preloadS3VideoUrl, preloadS3VideosUrl, preloadVideoUrl, preloadVideosUrl, qualityService, realtimeService, refreshWorkspaceDisplayNames, resetCoreMixpanel, resetFailedUrl, resetSubscriptionManager, s3VideoPreloader, setSentryUserContext, setSentryWorkspaceContext, 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, useClipsInit, useCompanyClipsCost, useCompanyUsersUsage, useComponentOverride, useCustomConfig, useDashboardConfig, useDashboardMetrics, useDatabaseConfig, useDateFormatter, useDateTimeConfig, useDynamicShiftConfig, useEndpointsConfig, useEntityConfig, useFactoryOverviewMetrics, useFeatureFlags, useFormatNumber, useHasLineAccess, useHideMobileHeader, useHistoricWorkspaceMetrics, useHlsStream, useHlsStreamWithCropping, useHookOverride, useHourEndTimer, useHourlyTargetAchievements, useHourlyTargetMisses, useIdleTimeClipClassifications, useIdleTimeReasons, useIdleTimeVlmConfig, useKpiTrends, useLeaderboardMetrics, useLineDetailedMetrics, useLineKPIs, useLineMetrics, useLineShiftConfig, useLineSupervisor, useLineWorkspaceMetrics, useLines, useMessages, useMetrics, useMobileMenu, useMonthlyTrend, useMultiLineShiftConfigs, useNavigation, useOperationalShiftKey, useOptionalSupabase, useOverrides, usePageOverride, usePrefetchClipCounts, useRealtimeLineMetrics, useRegistry, useSKUs, useSessionKeepAlive, useSessionTracking, useSessionTrackingContext, useShiftConfig, useShiftGroups, useShifts, useSubscriptionManager, useSubscriptionManagerSafe, useSupabase, useSupabaseClient, useSupervisorsByLineIds, useTargets, useTeamManagementPermissions, useTheme, useThemeConfig, useThreads, useTicketHistory, useTimezoneContext, useUserLineAccess, useUserUsage, useVideoConfig, useWorkspaceConfig, useWorkspaceDetailedMetrics, useWorkspaceDisplayName, useWorkspaceDisplayNames, useWorkspaceDisplayNamesMap, useWorkspaceHealthById, useWorkspaceHealthLastSeen, useWorkspaceHealthStatus, useWorkspaceMetrics, useWorkspaceNavigation, useWorkspaceOperators, useWorkspaceUptimeTimeline, useWorkspaceVideoStreams, userService, videoPrefetchManager, videoPreloader, weeklyTopPerformerService, whatsappService, withAccessControl, withAuth, withRegistry, withTimezone, workspaceHealthService, workspaceService };
|