@optifye/dashboard-core 6.10.53 → 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 +65 -17
- package/dist/index.d.ts +65 -17
- package/dist/index.js +3942 -2420
- package/dist/index.mjs +2055 -535
- 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
|
|
@@ -6931,6 +7133,9 @@ var InvitationService = class {
|
|
|
6931
7133
|
if (existingUser) {
|
|
6932
7134
|
throw new Error("A user with this email address already exists in the system.");
|
|
6933
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
|
+
}
|
|
6934
7139
|
const invitationData = {
|
|
6935
7140
|
email: input.email.toLowerCase().trim(),
|
|
6936
7141
|
company_id: input.company_id,
|
|
@@ -6941,7 +7146,7 @@ var InvitationService = class {
|
|
|
6941
7146
|
if (input.role_level === "supervisor" && input.line_ids && input.line_ids.length > 0) {
|
|
6942
7147
|
invitationData.line_ids = input.line_ids;
|
|
6943
7148
|
}
|
|
6944
|
-
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) {
|
|
6945
7150
|
invitationData.factory_ids = input.factory_ids;
|
|
6946
7151
|
}
|
|
6947
7152
|
console.log("[InvitationService] Final invitationData being inserted:", invitationData);
|
|
@@ -7651,6 +7856,8 @@ async function fetchIdleTimeReasons(params) {
|
|
|
7651
7856
|
data: {
|
|
7652
7857
|
total_idle_time_seconds: 0,
|
|
7653
7858
|
total_clips_analyzed: 0,
|
|
7859
|
+
scope_work_seconds: null,
|
|
7860
|
+
scope_workspace_count: 0,
|
|
7654
7861
|
reasons: []
|
|
7655
7862
|
},
|
|
7656
7863
|
error: "Request failed"
|
|
@@ -7668,6 +7875,8 @@ async function fetchIdleTimeReasons(params) {
|
|
|
7668
7875
|
return {
|
|
7669
7876
|
total_idle_time_seconds: 0,
|
|
7670
7877
|
total_clips_analyzed: 0,
|
|
7878
|
+
scope_work_seconds: null,
|
|
7879
|
+
scope_workspace_count: 0,
|
|
7671
7880
|
reasons: []
|
|
7672
7881
|
};
|
|
7673
7882
|
}
|
|
@@ -7675,7 +7884,9 @@ async function fetchIdleTimeReasons(params) {
|
|
|
7675
7884
|
function transformToChartData(data) {
|
|
7676
7885
|
return data.reasons.map((reason) => ({
|
|
7677
7886
|
name: formatReasonLabel(reason.reason),
|
|
7678
|
-
value: reason.percentage
|
|
7887
|
+
value: reason.percentage,
|
|
7888
|
+
totalDurationSeconds: reason.total_duration_seconds,
|
|
7889
|
+
efficiencyLossPercentage: reason.efficiency_loss_percentage ?? null
|
|
7679
7890
|
}));
|
|
7680
7891
|
}
|
|
7681
7892
|
function formatReasonLabel(reason) {
|
|
@@ -8083,6 +8294,18 @@ var lineLeaderboardService = {
|
|
|
8083
8294
|
return data?.entries ?? [];
|
|
8084
8295
|
}
|
|
8085
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
|
+
};
|
|
8086
8309
|
var SupabaseContext = createContext(void 0);
|
|
8087
8310
|
var SupabaseProvider = ({ client, children }) => {
|
|
8088
8311
|
_setSupabaseInstance(client);
|
|
@@ -8858,7 +9081,7 @@ var useMobileMenu = () => {
|
|
|
8858
9081
|
};
|
|
8859
9082
|
var useHideMobileHeader = (shouldHide = true) => {
|
|
8860
9083
|
const context = useMobileMenu();
|
|
8861
|
-
|
|
9084
|
+
React141__default.useEffect(() => {
|
|
8862
9085
|
if (context && shouldHide) {
|
|
8863
9086
|
context.setHideMobileHeader(true);
|
|
8864
9087
|
return () => {
|
|
@@ -14861,10 +15084,7 @@ var useSKUs = (companyId) => {
|
|
|
14861
15084
|
// src/lib/hooks/useCanSaveTargets.ts
|
|
14862
15085
|
var useCanSaveTargets = () => {
|
|
14863
15086
|
const { user } = useAuth();
|
|
14864
|
-
|
|
14865
|
-
return true;
|
|
14866
|
-
}
|
|
14867
|
-
return user?.role_level === "owner" || user?.role_level === "plant_head";
|
|
15087
|
+
return canRoleManageTargets(user?.role_level);
|
|
14868
15088
|
};
|
|
14869
15089
|
function useTicketHistory(companyId) {
|
|
14870
15090
|
const [tickets, setTickets] = useState([]);
|
|
@@ -16166,12 +16386,7 @@ var useFormatNumber = () => {
|
|
|
16166
16386
|
function useAccessControl() {
|
|
16167
16387
|
const { user } = useAuth();
|
|
16168
16388
|
const userRole = useMemo(() => {
|
|
16169
|
-
|
|
16170
|
-
const roleLevel = user.role_level;
|
|
16171
|
-
if (roleLevel === "owner" || roleLevel === "it" || roleLevel === "plant_head" || roleLevel === "supervisor" || roleLevel === "optifye") {
|
|
16172
|
-
return roleLevel;
|
|
16173
|
-
}
|
|
16174
|
-
return "supervisor";
|
|
16389
|
+
return normalizeRoleLevel(user?.role_level) || null;
|
|
16175
16390
|
}, [user?.role_level]);
|
|
16176
16391
|
const assignedLineIds = useMemo(() => {
|
|
16177
16392
|
if (!user) return [];
|
|
@@ -16183,89 +16398,15 @@ function useAccessControl() {
|
|
|
16183
16398
|
}, [user]);
|
|
16184
16399
|
const assignedFactoryIds = useMemo(() => {
|
|
16185
16400
|
if (!user) return [];
|
|
16186
|
-
if (user.role_level
|
|
16401
|
+
if (isFactoryScopedRole(user.role_level)) {
|
|
16187
16402
|
const factories = user.properties?.factory_id || user.properties?.factory_ids || [];
|
|
16188
16403
|
return Array.isArray(factories) ? factories : [];
|
|
16189
16404
|
}
|
|
16190
16405
|
return [];
|
|
16191
16406
|
}, [user]);
|
|
16192
|
-
const roleAccessMap = {
|
|
16193
|
-
optifye: [
|
|
16194
|
-
"/",
|
|
16195
|
-
"/leaderboard",
|
|
16196
|
-
"/kpis",
|
|
16197
|
-
"/targets",
|
|
16198
|
-
"/shifts",
|
|
16199
|
-
"/supervisor-management",
|
|
16200
|
-
"/skus",
|
|
16201
|
-
"/help",
|
|
16202
|
-
"/health",
|
|
16203
|
-
"/profile",
|
|
16204
|
-
"/workspace",
|
|
16205
|
-
"/factory-view",
|
|
16206
|
-
"/team-management"
|
|
16207
|
-
],
|
|
16208
|
-
owner: [
|
|
16209
|
-
"/",
|
|
16210
|
-
"/leaderboard",
|
|
16211
|
-
"/kpis",
|
|
16212
|
-
"/targets",
|
|
16213
|
-
"/shifts",
|
|
16214
|
-
"/supervisor-management",
|
|
16215
|
-
"/skus",
|
|
16216
|
-
"/help",
|
|
16217
|
-
"/health",
|
|
16218
|
-
"/profile",
|
|
16219
|
-
"/workspace",
|
|
16220
|
-
"/factory-view",
|
|
16221
|
-
"/team-management"
|
|
16222
|
-
],
|
|
16223
|
-
it: [
|
|
16224
|
-
"/",
|
|
16225
|
-
"/leaderboard",
|
|
16226
|
-
"/kpis",
|
|
16227
|
-
"/targets",
|
|
16228
|
-
"/shifts",
|
|
16229
|
-
"/supervisor-management",
|
|
16230
|
-
"/skus",
|
|
16231
|
-
"/help",
|
|
16232
|
-
"/health",
|
|
16233
|
-
"/profile",
|
|
16234
|
-
"/workspace",
|
|
16235
|
-
"/factory-view",
|
|
16236
|
-
"/team-management"
|
|
16237
|
-
],
|
|
16238
|
-
plant_head: [
|
|
16239
|
-
"/",
|
|
16240
|
-
"/leaderboard",
|
|
16241
|
-
"/kpis",
|
|
16242
|
-
"/targets",
|
|
16243
|
-
"/shifts",
|
|
16244
|
-
"/supervisor-management",
|
|
16245
|
-
"/skus",
|
|
16246
|
-
"/help",
|
|
16247
|
-
"/health",
|
|
16248
|
-
"/profile",
|
|
16249
|
-
"/workspace",
|
|
16250
|
-
"/factory-view",
|
|
16251
|
-
"/team-management"
|
|
16252
|
-
],
|
|
16253
|
-
supervisor: [
|
|
16254
|
-
"/",
|
|
16255
|
-
"/leaderboard",
|
|
16256
|
-
"/kpis",
|
|
16257
|
-
"/targets",
|
|
16258
|
-
"/shifts",
|
|
16259
|
-
"/skus",
|
|
16260
|
-
"/help",
|
|
16261
|
-
"/health",
|
|
16262
|
-
"/profile",
|
|
16263
|
-
"/workspace"
|
|
16264
|
-
]
|
|
16265
|
-
};
|
|
16266
16407
|
const accessiblePages = useMemo(() => {
|
|
16267
16408
|
if (!userRole) return [];
|
|
16268
|
-
return
|
|
16409
|
+
return getRoleNavPaths(userRole);
|
|
16269
16410
|
}, [userRole]);
|
|
16270
16411
|
const hasAccess = useMemo(() => {
|
|
16271
16412
|
return (path) => {
|
|
@@ -16315,111 +16456,50 @@ function useTeamManagementPermissions() {
|
|
|
16315
16456
|
* Can the current user assign lines to this user?
|
|
16316
16457
|
*/
|
|
16317
16458
|
canAssignLines: (targetUser) => {
|
|
16318
|
-
|
|
16319
|
-
if (currentRole === "optifye") return true;
|
|
16320
|
-
if ((currentRole === "owner" || currentRole === "it") && targetUser.role_level === "supervisor") {
|
|
16321
|
-
return true;
|
|
16322
|
-
}
|
|
16323
|
-
if (currentRole === "plant_head" && targetUser.role_level === "supervisor") {
|
|
16324
|
-
return true;
|
|
16325
|
-
}
|
|
16326
|
-
return false;
|
|
16459
|
+
return canRoleAssignLines(currentRole, targetUser.role_level);
|
|
16327
16460
|
},
|
|
16328
16461
|
/**
|
|
16329
16462
|
* Can the current user assign factories to this user?
|
|
16330
16463
|
*/
|
|
16331
16464
|
canAssignFactories: (targetUser) => {
|
|
16332
|
-
|
|
16333
|
-
if (currentRole === "optifye") return true;
|
|
16334
|
-
if ((currentRole === "owner" || currentRole === "it") && targetUser.role_level === "plant_head") {
|
|
16335
|
-
return true;
|
|
16336
|
-
}
|
|
16337
|
-
return false;
|
|
16465
|
+
return canRoleAssignFactories(currentRole, targetUser.role_level);
|
|
16338
16466
|
},
|
|
16339
16467
|
/**
|
|
16340
16468
|
* Can the current user change this user's role?
|
|
16341
16469
|
*/
|
|
16342
16470
|
canChangeRole: (targetUser) => {
|
|
16343
|
-
|
|
16344
|
-
if (currentRole === "optifye") return true;
|
|
16345
|
-
if (currentRole === "owner" || currentRole === "it") {
|
|
16346
|
-
return ["plant_head", "supervisor"].includes(targetUser.role_level);
|
|
16347
|
-
}
|
|
16348
|
-
return false;
|
|
16471
|
+
return canRoleChangeRole(currentRole, targetUser.role_level, { isSuperAdminOptifye });
|
|
16349
16472
|
},
|
|
16350
16473
|
/**
|
|
16351
16474
|
* Can the current user remove this user?
|
|
16352
16475
|
*/
|
|
16353
16476
|
canRemoveUser: (targetUser) => {
|
|
16354
|
-
|
|
16355
|
-
if (currentRole === "optifye") return true;
|
|
16356
|
-
if (currentRole === "owner" || currentRole === "it") {
|
|
16357
|
-
return ["plant_head", "supervisor"].includes(targetUser.role_level);
|
|
16358
|
-
}
|
|
16359
|
-
return false;
|
|
16477
|
+
return canRoleRemoveUser(currentRole, targetUser.role_level, { isSuperAdminOptifye });
|
|
16360
16478
|
},
|
|
16361
16479
|
/**
|
|
16362
16480
|
* Get list of roles the current user can assign
|
|
16363
16481
|
* NOTE: Optifye role can ONLY be assigned from database directly, never from frontend
|
|
16364
16482
|
*/
|
|
16365
16483
|
availableRolesToAssign: () => {
|
|
16366
|
-
|
|
16367
|
-
if (currentRole === "optifye") {
|
|
16368
|
-
if (isSuperAdminOptifye) {
|
|
16369
|
-
return ["owner", "it", "plant_head", "supervisor"];
|
|
16370
|
-
}
|
|
16371
|
-
return ["it", "plant_head", "supervisor"];
|
|
16372
|
-
}
|
|
16373
|
-
if (currentRole === "owner") {
|
|
16374
|
-
return ["it", "plant_head", "supervisor"];
|
|
16375
|
-
}
|
|
16376
|
-
if (currentRole === "it") {
|
|
16377
|
-
return ["plant_head", "supervisor"];
|
|
16378
|
-
}
|
|
16379
|
-
if (currentRole === "plant_head") {
|
|
16380
|
-
return ["supervisor"];
|
|
16381
|
-
}
|
|
16382
|
-
return [];
|
|
16484
|
+
return getAssignableRoles(currentRole, { isSuperAdminOptifye });
|
|
16383
16485
|
},
|
|
16384
16486
|
/**
|
|
16385
16487
|
* Can the current user invite someone with this role?
|
|
16386
16488
|
*/
|
|
16387
16489
|
canInviteRole: (role) => {
|
|
16388
|
-
|
|
16389
|
-
if (currentRole === "optifye") {
|
|
16390
|
-
if (role === "owner") {
|
|
16391
|
-
return isSuperAdminOptifye;
|
|
16392
|
-
}
|
|
16393
|
-
return true;
|
|
16394
|
-
}
|
|
16395
|
-
if (currentRole === "owner") {
|
|
16396
|
-
return ["it", "plant_head", "supervisor"].includes(role);
|
|
16397
|
-
}
|
|
16398
|
-
if (currentRole === "it") {
|
|
16399
|
-
return ["plant_head", "supervisor"].includes(role);
|
|
16400
|
-
}
|
|
16401
|
-
if (currentRole === "plant_head") {
|
|
16402
|
-
return role === "supervisor";
|
|
16403
|
-
}
|
|
16404
|
-
return false;
|
|
16490
|
+
return canRoleInviteRole(currentRole, role, { isSuperAdminOptifye });
|
|
16405
16491
|
},
|
|
16406
16492
|
/**
|
|
16407
16493
|
* Get the name of the assignment column for a user
|
|
16408
16494
|
*/
|
|
16409
16495
|
getAssignmentColumnName: (targetUser) => {
|
|
16410
|
-
|
|
16411
|
-
return "Factories";
|
|
16412
|
-
}
|
|
16413
|
-
if (targetUser.role_level === "supervisor") {
|
|
16414
|
-
return "Lines";
|
|
16415
|
-
}
|
|
16416
|
-
return "Assignments";
|
|
16496
|
+
return getAssignmentColumnLabel(targetUser.role_level);
|
|
16417
16497
|
},
|
|
16418
16498
|
/**
|
|
16419
16499
|
* Should the assignment column be shown?
|
|
16420
16500
|
*/
|
|
16421
16501
|
showAssignmentColumn: () => {
|
|
16422
|
-
return !!currentRole &&
|
|
16502
|
+
return !!currentRole && (currentRole === "optifye" || currentRole === "owner" || currentRole === "it" || isFactoryScopedRole(currentRole));
|
|
16423
16503
|
}
|
|
16424
16504
|
};
|
|
16425
16505
|
}
|
|
@@ -20274,7 +20354,7 @@ var getStoredWorkspaceMappings = () => {
|
|
|
20274
20354
|
var getDefaultTabForWorkspace = (workspaceId, displayName) => {
|
|
20275
20355
|
return "overview";
|
|
20276
20356
|
};
|
|
20277
|
-
var getWorkspaceNavigationParams = (workspaceId, displayName, lineId) => {
|
|
20357
|
+
var getWorkspaceNavigationParams = (workspaceId, displayName, lineId, returnTo) => {
|
|
20278
20358
|
const defaultTab = getDefaultTabForWorkspace();
|
|
20279
20359
|
const params = new URLSearchParams();
|
|
20280
20360
|
params.set("displayName", displayName);
|
|
@@ -20282,6 +20362,9 @@ var getWorkspaceNavigationParams = (workspaceId, displayName, lineId) => {
|
|
|
20282
20362
|
if (lineId) {
|
|
20283
20363
|
params.set("lineId", lineId);
|
|
20284
20364
|
}
|
|
20365
|
+
if (returnTo) {
|
|
20366
|
+
params.set("returnTo", returnTo);
|
|
20367
|
+
}
|
|
20285
20368
|
return `?${params.toString()}`;
|
|
20286
20369
|
};
|
|
20287
20370
|
|
|
@@ -20577,14 +20660,18 @@ var formatIdleTime = (idleTimeInSeconds) => {
|
|
|
20577
20660
|
if (!idleTimeInSeconds || idleTimeInSeconds <= 0) {
|
|
20578
20661
|
return "0s";
|
|
20579
20662
|
}
|
|
20580
|
-
const
|
|
20663
|
+
const days = Math.floor(idleTimeInSeconds / 86400);
|
|
20664
|
+
const hours = Math.floor(idleTimeInSeconds % 86400 / 3600);
|
|
20581
20665
|
const minutes = Math.floor(idleTimeInSeconds % 3600 / 60);
|
|
20582
20666
|
const seconds = Math.floor(idleTimeInSeconds % 60);
|
|
20583
20667
|
const parts = [];
|
|
20668
|
+
if (days > 0) {
|
|
20669
|
+
parts.push(`${days}d`);
|
|
20670
|
+
}
|
|
20584
20671
|
if (hours > 0) {
|
|
20585
20672
|
parts.push(`${hours}h`);
|
|
20586
20673
|
}
|
|
20587
|
-
if (minutes > 0 || hours > 0) {
|
|
20674
|
+
if (minutes > 0 || hours > 0 || days > 0) {
|
|
20588
20675
|
parts.push(`${minutes}m`);
|
|
20589
20676
|
}
|
|
20590
20677
|
parts.push(`${seconds}s`);
|
|
@@ -20631,7 +20718,7 @@ var MotionConfigContext = createContext({
|
|
|
20631
20718
|
});
|
|
20632
20719
|
|
|
20633
20720
|
// ../../node_modules/framer-motion/dist/es/components/AnimatePresence/PopChild.mjs
|
|
20634
|
-
var PopChildMeasure = class extends
|
|
20721
|
+
var PopChildMeasure = class extends React141.Component {
|
|
20635
20722
|
getSnapshotBeforeUpdate(prevProps) {
|
|
20636
20723
|
const element = this.props.childRef.current;
|
|
20637
20724
|
if (element && prevProps.isPresent && !this.props.isPresent) {
|
|
@@ -20686,7 +20773,7 @@ function PopChild({ children, isPresent }) {
|
|
|
20686
20773
|
document.head.removeChild(style);
|
|
20687
20774
|
};
|
|
20688
20775
|
}, [isPresent]);
|
|
20689
|
-
return jsx(PopChildMeasure, { isPresent, childRef: ref, sizeRef: size, children:
|
|
20776
|
+
return jsx(PopChildMeasure, { isPresent, childRef: ref, sizeRef: size, children: React141.cloneElement(children, { ref }) });
|
|
20690
20777
|
}
|
|
20691
20778
|
|
|
20692
20779
|
// ../../node_modules/framer-motion/dist/es/components/AnimatePresence/PresenceChild.mjs
|
|
@@ -20723,7 +20810,7 @@ var PresenceChild = ({ children, initial, isPresent, onExitComplete, custom, pre
|
|
|
20723
20810
|
useMemo(() => {
|
|
20724
20811
|
presenceChildren.forEach((_, key) => presenceChildren.set(key, false));
|
|
20725
20812
|
}, [isPresent]);
|
|
20726
|
-
|
|
20813
|
+
React141.useEffect(() => {
|
|
20727
20814
|
!isPresent && !presenceChildren.size && onExitComplete && onExitComplete();
|
|
20728
20815
|
}, [isPresent]);
|
|
20729
20816
|
if (mode === "popLayout") {
|
|
@@ -28557,12 +28644,12 @@ var withAuth = (WrappedComponent2, options) => {
|
|
|
28557
28644
|
requireAuth: true,
|
|
28558
28645
|
...options
|
|
28559
28646
|
};
|
|
28560
|
-
const WithAuthComponent =
|
|
28647
|
+
const WithAuthComponent = React141.memo(function WithAuthComponent2(props) {
|
|
28561
28648
|
const { session, loading, error } = useAuth();
|
|
28562
28649
|
const router = useRouter();
|
|
28563
|
-
const [localLoading, setLocalLoading] =
|
|
28564
|
-
const [loadingTimeoutReached, setLoadingTimeoutReached] =
|
|
28565
|
-
|
|
28650
|
+
const [localLoading, setLocalLoading] = React141.useState(loading);
|
|
28651
|
+
const [loadingTimeoutReached, setLoadingTimeoutReached] = React141.useState(false);
|
|
28652
|
+
React141.useEffect(() => {
|
|
28566
28653
|
if (process.env.NODE_ENV === "development" && process.env.DEBUG_AUTH === "true") {
|
|
28567
28654
|
console.log("withAuth state:", {
|
|
28568
28655
|
loading,
|
|
@@ -28572,7 +28659,7 @@ var withAuth = (WrappedComponent2, options) => {
|
|
|
28572
28659
|
});
|
|
28573
28660
|
}
|
|
28574
28661
|
}, [session, loading, error]);
|
|
28575
|
-
const handleLoadingTimeout =
|
|
28662
|
+
const handleLoadingTimeout = React141.useCallback(() => {
|
|
28576
28663
|
console.warn("[withAuth] Loading timeout reached");
|
|
28577
28664
|
setLoadingTimeoutReached(true);
|
|
28578
28665
|
if (typeof window !== "undefined" && localStorage.getItem("sb-zmzewpwerpaupoaoeqhh-auth-token")) {
|
|
@@ -28583,13 +28670,13 @@ var withAuth = (WrappedComponent2, options) => {
|
|
|
28583
28670
|
router.replace(defaultOptions.redirectTo);
|
|
28584
28671
|
}
|
|
28585
28672
|
}, [router]);
|
|
28586
|
-
|
|
28673
|
+
React141.useEffect(() => {
|
|
28587
28674
|
if (!loading && defaultOptions.requireAuth && !session && !error) {
|
|
28588
28675
|
console.log("[withAuth] No session found, redirecting to login");
|
|
28589
28676
|
router.replace(defaultOptions.redirectTo);
|
|
28590
28677
|
}
|
|
28591
28678
|
}, [session, loading, router, error]);
|
|
28592
|
-
|
|
28679
|
+
React141.useEffect(() => {
|
|
28593
28680
|
setLocalLoading(loading);
|
|
28594
28681
|
}, [loading]);
|
|
28595
28682
|
if (loading || localLoading) {
|
|
@@ -28652,18 +28739,11 @@ function withAccessControl(WrappedComponent2, options = {}) {
|
|
|
28652
28739
|
if (keyIndex >= 0 && keyIndex < segments.length - 1) return segments[keyIndex + 1];
|
|
28653
28740
|
return null;
|
|
28654
28741
|
};
|
|
28655
|
-
const roleAccessMap = {
|
|
28656
|
-
optifye: ["/", "/leaderboard", "/kpis", "/targets", "/shifts", "/supervisor-management", "/skus", "/help", "/health", "/profile", "/workspace", "/factory-view", "/team-management", "/improvement-center", "/tickets"],
|
|
28657
|
-
owner: ["/", "/leaderboard", "/kpis", "/targets", "/shifts", "/supervisor-management", "/skus", "/help", "/health", "/profile", "/workspace", "/factory-view", "/team-management", "/improvement-center", "/tickets"],
|
|
28658
|
-
it: ["/", "/leaderboard", "/kpis", "/targets", "/shifts", "/supervisor-management", "/skus", "/help", "/health", "/profile", "/workspace", "/factory-view", "/team-management", "/improvement-center", "/tickets"],
|
|
28659
|
-
plant_head: ["/", "/leaderboard", "/kpis", "/targets", "/shifts", "/supervisor-management", "/skus", "/help", "/health", "/profile", "/workspace", "/factory-view", "/team-management", "/improvement-center", "/tickets"],
|
|
28660
|
-
supervisor: ["/", "/leaderboard", "/kpis", "/targets", "/shifts", "/skus", "/help", "/health", "/profile", "/workspace", "/improvement-center", "/tickets"]
|
|
28661
|
-
};
|
|
28662
28742
|
const canAccessPath = (path) => {
|
|
28663
28743
|
if (!user || !role) return false;
|
|
28664
28744
|
if (isSuperAdmin) return true;
|
|
28665
28745
|
const basePath = getBasePath(path);
|
|
28666
|
-
const allowed =
|
|
28746
|
+
const allowed = getRoleNavPaths(role);
|
|
28667
28747
|
if (!allowed.includes(basePath)) {
|
|
28668
28748
|
return false;
|
|
28669
28749
|
}
|
|
@@ -29064,8 +29144,8 @@ function getRoleConfig(role) {
|
|
|
29064
29144
|
switch (role) {
|
|
29065
29145
|
case "optifye":
|
|
29066
29146
|
return {
|
|
29067
|
-
label:
|
|
29068
|
-
description:
|
|
29147
|
+
label: getRoleLabel(role),
|
|
29148
|
+
description: getRoleDescription(role),
|
|
29069
29149
|
icon: Star,
|
|
29070
29150
|
bgColor: "bg-gradient-to-r from-purple-50 to-pink-50",
|
|
29071
29151
|
textColor: "text-purple-700",
|
|
@@ -29073,8 +29153,8 @@ function getRoleConfig(role) {
|
|
|
29073
29153
|
};
|
|
29074
29154
|
case "owner":
|
|
29075
29155
|
return {
|
|
29076
|
-
label:
|
|
29077
|
-
description:
|
|
29156
|
+
label: getRoleLabel(role),
|
|
29157
|
+
description: getRoleDescription(role),
|
|
29078
29158
|
icon: Shield,
|
|
29079
29159
|
bgColor: "bg-blue-50",
|
|
29080
29160
|
textColor: "text-blue-700",
|
|
@@ -29082,8 +29162,8 @@ function getRoleConfig(role) {
|
|
|
29082
29162
|
};
|
|
29083
29163
|
case "it":
|
|
29084
29164
|
return {
|
|
29085
|
-
label:
|
|
29086
|
-
description:
|
|
29165
|
+
label: getRoleLabel(role),
|
|
29166
|
+
description: getRoleDescription(role),
|
|
29087
29167
|
icon: Wrench,
|
|
29088
29168
|
bgColor: "bg-teal-50",
|
|
29089
29169
|
textColor: "text-teal-700",
|
|
@@ -29091,17 +29171,26 @@ function getRoleConfig(role) {
|
|
|
29091
29171
|
};
|
|
29092
29172
|
case "plant_head":
|
|
29093
29173
|
return {
|
|
29094
|
-
label:
|
|
29095
|
-
description:
|
|
29174
|
+
label: getRoleLabel(role),
|
|
29175
|
+
description: getRoleDescription(role),
|
|
29096
29176
|
icon: Users,
|
|
29097
29177
|
bgColor: "bg-blue-50",
|
|
29098
29178
|
textColor: "text-blue-700",
|
|
29099
29179
|
borderColor: "border-blue-200"
|
|
29100
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
|
+
};
|
|
29101
29190
|
case "supervisor":
|
|
29102
29191
|
return {
|
|
29103
|
-
label:
|
|
29104
|
-
description:
|
|
29192
|
+
label: getRoleLabel(role),
|
|
29193
|
+
description: getRoleDescription(role),
|
|
29105
29194
|
icon: User,
|
|
29106
29195
|
bgColor: "bg-blue-50",
|
|
29107
29196
|
textColor: "text-blue-700",
|
|
@@ -29209,7 +29298,7 @@ var SignupWithInvitation = ({
|
|
|
29209
29298
|
if (invitation.line_ids && invitation.line_ids.length > 0) {
|
|
29210
29299
|
properties.line_id = invitation.line_ids;
|
|
29211
29300
|
}
|
|
29212
|
-
} else if (invitation.role_level === "plant_head") {
|
|
29301
|
+
} else if (invitation.role_level === "plant_head" || invitation.role_level === "industrial_engineer") {
|
|
29213
29302
|
properties.access_level = "factory";
|
|
29214
29303
|
if (invitation.factory_ids && invitation.factory_ids.length > 0) {
|
|
29215
29304
|
properties.factory_ids = invitation.factory_ids;
|
|
@@ -29300,7 +29389,7 @@ var SignupWithInvitation = ({
|
|
|
29300
29389
|
] })
|
|
29301
29390
|
] })
|
|
29302
29391
|
] }),
|
|
29303
|
-
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: [
|
|
29304
29393
|
/* @__PURE__ */ jsx("p", { className: "text-sm text-gray-600 mb-1", children: "Assigned Factories" }),
|
|
29305
29394
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
29306
29395
|
/* @__PURE__ */ jsx(Building2, { className: "w-4 h-4 text-indigo-600" }),
|
|
@@ -29522,11 +29611,11 @@ var BarChartComponent = ({
|
|
|
29522
29611
|
aspect = 2,
|
|
29523
29612
|
...restOfChartProps
|
|
29524
29613
|
}) => {
|
|
29525
|
-
const containerRef =
|
|
29526
|
-
const [containerReady, setContainerReady] =
|
|
29614
|
+
const containerRef = React141__default.useRef(null);
|
|
29615
|
+
const [containerReady, setContainerReady] = React141__default.useState(false);
|
|
29527
29616
|
const themeConfig = useThemeConfig();
|
|
29528
29617
|
const { formatNumber } = useFormatNumber();
|
|
29529
|
-
|
|
29618
|
+
React141__default.useEffect(() => {
|
|
29530
29619
|
const checkContainerDimensions = () => {
|
|
29531
29620
|
if (containerRef.current) {
|
|
29532
29621
|
const rect = containerRef.current.getBoundingClientRect();
|
|
@@ -29640,7 +29729,7 @@ var BarChartComponent = ({
|
|
|
29640
29729
|
}
|
|
29641
29730
|
return /* @__PURE__ */ jsx("div", { className: clsx("w-full", className), children: chartContent });
|
|
29642
29731
|
};
|
|
29643
|
-
var BarChart =
|
|
29732
|
+
var BarChart = React141__default.memo(BarChartComponent, (prevProps, nextProps) => {
|
|
29644
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) {
|
|
29645
29734
|
return false;
|
|
29646
29735
|
}
|
|
@@ -29686,13 +29775,14 @@ var LineChartComponent = ({
|
|
|
29686
29775
|
showTooltip = true,
|
|
29687
29776
|
responsive = true,
|
|
29688
29777
|
aspect = 2,
|
|
29778
|
+
fillContainer = false,
|
|
29689
29779
|
...restOfChartProps
|
|
29690
29780
|
}) => {
|
|
29691
|
-
const containerRef =
|
|
29692
|
-
const [containerReady, setContainerReady] =
|
|
29781
|
+
const containerRef = React141__default.useRef(null);
|
|
29782
|
+
const [containerReady, setContainerReady] = React141__default.useState(false);
|
|
29693
29783
|
const themeConfig = useThemeConfig();
|
|
29694
29784
|
const { formatNumber } = useFormatNumber();
|
|
29695
|
-
|
|
29785
|
+
React141__default.useEffect(() => {
|
|
29696
29786
|
const checkContainerDimensions = () => {
|
|
29697
29787
|
if (containerRef.current) {
|
|
29698
29788
|
const rect = containerRef.current.getBoundingClientRect();
|
|
@@ -29720,8 +29810,8 @@ var LineChartComponent = ({
|
|
|
29720
29810
|
const defaultTooltipFormatter = (value, name, props) => {
|
|
29721
29811
|
const formattedValue = typeof value === "number" ? formatNumber(value) : value;
|
|
29722
29812
|
return [
|
|
29723
|
-
/* @__PURE__ */ jsx("span", { children: `${formattedValue}${yAxisUnit || ""}` }, `tt-val-${name}-${value}`),
|
|
29724
|
-
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}`)
|
|
29725
29815
|
];
|
|
29726
29816
|
};
|
|
29727
29817
|
const defaultColors = [
|
|
@@ -29757,7 +29847,7 @@ var LineChartComponent = ({
|
|
|
29757
29847
|
stroke: axisStrokeColor
|
|
29758
29848
|
}
|
|
29759
29849
|
),
|
|
29760
|
-
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" } }),
|
|
29761
29851
|
showLegend && /* @__PURE__ */ jsx(Legend, { payload: legendPayload }),
|
|
29762
29852
|
lines.map((lineConfig, index) => {
|
|
29763
29853
|
const lineProps = {
|
|
@@ -29783,15 +29873,15 @@ var LineChartComponent = ({
|
|
|
29783
29873
|
"div",
|
|
29784
29874
|
{
|
|
29785
29875
|
ref: containerRef,
|
|
29786
|
-
className: clsx("w-full h-auto", className),
|
|
29787
|
-
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" },
|
|
29788
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..." }) })
|
|
29789
29879
|
}
|
|
29790
29880
|
);
|
|
29791
29881
|
}
|
|
29792
29882
|
return /* @__PURE__ */ jsx("div", { className: clsx("w-full", className), children: chartContent });
|
|
29793
29883
|
};
|
|
29794
|
-
var LineChart =
|
|
29884
|
+
var LineChart = React141__default.memo(LineChartComponent, (prevProps, nextProps) => {
|
|
29795
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)) {
|
|
29796
29886
|
return false;
|
|
29797
29887
|
}
|
|
@@ -29885,7 +29975,7 @@ var OutputProgressChartComponent = ({
|
|
|
29885
29975
|
] }) })
|
|
29886
29976
|
] }) });
|
|
29887
29977
|
};
|
|
29888
|
-
var OutputProgressChart =
|
|
29978
|
+
var OutputProgressChart = React141__default.memo(OutputProgressChartComponent);
|
|
29889
29979
|
OutputProgressChart.displayName = "OutputProgressChart";
|
|
29890
29980
|
var LargeOutputProgressChart = ({
|
|
29891
29981
|
currentOutput,
|
|
@@ -30025,7 +30115,7 @@ var CycleTimeChartComponent = ({
|
|
|
30025
30115
|
}
|
|
30026
30116
|
) }) });
|
|
30027
30117
|
};
|
|
30028
|
-
var CycleTimeChart =
|
|
30118
|
+
var CycleTimeChart = React141__default.memo(CycleTimeChartComponent, (prevProps, nextProps) => {
|
|
30029
30119
|
if (prevProps.className !== nextProps.className) {
|
|
30030
30120
|
return false;
|
|
30031
30121
|
}
|
|
@@ -30051,8 +30141,8 @@ var CycleTimeOverTimeChart = ({
|
|
|
30051
30141
|
className = ""
|
|
30052
30142
|
}) => {
|
|
30053
30143
|
const MAX_DATA_POINTS = 40;
|
|
30054
|
-
const containerRef =
|
|
30055
|
-
const [containerReady, setContainerReady] =
|
|
30144
|
+
const containerRef = React141__default.useRef(null);
|
|
30145
|
+
const [containerReady, setContainerReady] = React141__default.useState(false);
|
|
30056
30146
|
const getHourFromTimeString = (timeStr) => {
|
|
30057
30147
|
const [hours, minutes] = timeStr.split(":");
|
|
30058
30148
|
return parseInt(hours);
|
|
@@ -30063,10 +30153,10 @@ var CycleTimeOverTimeChart = ({
|
|
|
30063
30153
|
};
|
|
30064
30154
|
const displayData = getDisplayData(data);
|
|
30065
30155
|
const DURATION = displayData.length;
|
|
30066
|
-
const [animatedData, setAnimatedData] =
|
|
30067
|
-
const prevDataRef =
|
|
30068
|
-
const animationFrameRef =
|
|
30069
|
-
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) => {
|
|
30070
30160
|
const startData = [...prevDataRef.current];
|
|
30071
30161
|
const startTime = performance.now();
|
|
30072
30162
|
const duration = 1200;
|
|
@@ -30096,7 +30186,7 @@ var CycleTimeOverTimeChart = ({
|
|
|
30096
30186
|
}
|
|
30097
30187
|
animationFrameRef.current = requestAnimationFrame(animate);
|
|
30098
30188
|
}, []);
|
|
30099
|
-
|
|
30189
|
+
React141__default.useEffect(() => {
|
|
30100
30190
|
if (JSON.stringify(data) !== JSON.stringify(prevDataRef.current)) {
|
|
30101
30191
|
const processedData = getDisplayData(data);
|
|
30102
30192
|
animateToNewData(processedData);
|
|
@@ -30107,7 +30197,7 @@ var CycleTimeOverTimeChart = ({
|
|
|
30107
30197
|
}
|
|
30108
30198
|
};
|
|
30109
30199
|
}, [data, animateToNewData]);
|
|
30110
|
-
|
|
30200
|
+
React141__default.useEffect(() => {
|
|
30111
30201
|
const checkContainerDimensions = () => {
|
|
30112
30202
|
if (containerRef.current) {
|
|
30113
30203
|
const rect = containerRef.current.getBoundingClientRect();
|
|
@@ -30350,7 +30440,7 @@ var CycleTimeOverTimeChart = ({
|
|
|
30350
30440
|
}
|
|
30351
30441
|
);
|
|
30352
30442
|
};
|
|
30353
|
-
var Card =
|
|
30443
|
+
var Card = React141.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
30354
30444
|
"div",
|
|
30355
30445
|
{
|
|
30356
30446
|
ref,
|
|
@@ -30362,7 +30452,7 @@ var Card = React26.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */
|
|
|
30362
30452
|
}
|
|
30363
30453
|
));
|
|
30364
30454
|
Card.displayName = "Card";
|
|
30365
|
-
var CardHeader =
|
|
30455
|
+
var CardHeader = React141.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
30366
30456
|
"div",
|
|
30367
30457
|
{
|
|
30368
30458
|
ref,
|
|
@@ -30371,7 +30461,7 @@ var CardHeader = React26.forwardRef(({ className, ...props }, ref) => /* @__PURE
|
|
|
30371
30461
|
}
|
|
30372
30462
|
));
|
|
30373
30463
|
CardHeader.displayName = "CardHeader";
|
|
30374
|
-
var CardTitle =
|
|
30464
|
+
var CardTitle = React141.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
30375
30465
|
"h3",
|
|
30376
30466
|
{
|
|
30377
30467
|
ref,
|
|
@@ -30383,7 +30473,7 @@ var CardTitle = React26.forwardRef(({ className, ...props }, ref) => /* @__PURE_
|
|
|
30383
30473
|
}
|
|
30384
30474
|
));
|
|
30385
30475
|
CardTitle.displayName = "CardTitle";
|
|
30386
|
-
var CardDescription =
|
|
30476
|
+
var CardDescription = React141.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
30387
30477
|
"p",
|
|
30388
30478
|
{
|
|
30389
30479
|
ref,
|
|
@@ -30392,9 +30482,9 @@ var CardDescription = React26.forwardRef(({ className, ...props }, ref) => /* @_
|
|
|
30392
30482
|
}
|
|
30393
30483
|
));
|
|
30394
30484
|
CardDescription.displayName = "CardDescription";
|
|
30395
|
-
var CardContent =
|
|
30485
|
+
var CardContent = React141.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("p-6 pt-0", className), ...props }));
|
|
30396
30486
|
CardContent.displayName = "CardContent";
|
|
30397
|
-
var CardFooter =
|
|
30487
|
+
var CardFooter = React141.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
30398
30488
|
"div",
|
|
30399
30489
|
{
|
|
30400
30490
|
ref,
|
|
@@ -30470,7 +30560,7 @@ var buttonVariants = cva(
|
|
|
30470
30560
|
}
|
|
30471
30561
|
}
|
|
30472
30562
|
);
|
|
30473
|
-
var Button =
|
|
30563
|
+
var Button = React141.forwardRef(
|
|
30474
30564
|
({ className, variant, size, asChild = false, ...props }, ref) => {
|
|
30475
30565
|
const Comp = asChild ? Slot : "button";
|
|
30476
30566
|
return /* @__PURE__ */ jsx(
|
|
@@ -30497,9 +30587,9 @@ var HourlyOutputChartComponent = ({
|
|
|
30497
30587
|
timezone,
|
|
30498
30588
|
className = ""
|
|
30499
30589
|
}) => {
|
|
30500
|
-
const containerRef =
|
|
30501
|
-
const [containerReady, setContainerReady] =
|
|
30502
|
-
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);
|
|
30503
30593
|
const getTimeFromTimeString2 = (timeStr) => {
|
|
30504
30594
|
const [hours, minutes] = timeStr.split(":");
|
|
30505
30595
|
const hour = parseInt(hours);
|
|
@@ -30508,13 +30598,13 @@ var HourlyOutputChartComponent = ({
|
|
|
30508
30598
|
return { hour, minute, decimalHour };
|
|
30509
30599
|
};
|
|
30510
30600
|
const shiftStartTime = getTimeFromTimeString2(shiftStart);
|
|
30511
|
-
|
|
30601
|
+
React141__default.useMemo(() => {
|
|
30512
30602
|
if (!shiftDate || !timezone) return null;
|
|
30513
30603
|
const hour = shiftStartTime.hour.toString().padStart(2, "0");
|
|
30514
30604
|
const minute = shiftStartTime.minute.toString().padStart(2, "0");
|
|
30515
30605
|
return fromZonedTime(`${shiftDate}T${hour}:${minute}:00`, timezone);
|
|
30516
30606
|
}, [shiftDate, timezone, shiftStartTime.hour, shiftStartTime.minute]);
|
|
30517
|
-
const idleClipRanges =
|
|
30607
|
+
const idleClipRanges = React141__default.useMemo(() => {
|
|
30518
30608
|
if (!idleTimeClips || idleTimeClips.length === 0) return [];
|
|
30519
30609
|
return idleTimeClips.map((clip) => ({
|
|
30520
30610
|
id: clip.id,
|
|
@@ -30522,7 +30612,7 @@ var HourlyOutputChartComponent = ({
|
|
|
30522
30612
|
end: clip.idle_end_time ? new Date(clip.idle_end_time) : null
|
|
30523
30613
|
})).filter((clip) => clip.start && clip.end);
|
|
30524
30614
|
}, [idleTimeClips]);
|
|
30525
|
-
|
|
30615
|
+
React141__default.useCallback((rangeStart, rangeEnd) => {
|
|
30526
30616
|
if (!rangeStart || !rangeEnd || idleClipRanges.length === 0) {
|
|
30527
30617
|
return "Reason unavailable";
|
|
30528
30618
|
}
|
|
@@ -30539,7 +30629,7 @@ var HourlyOutputChartComponent = ({
|
|
|
30539
30629
|
}
|
|
30540
30630
|
return classification.label.replace(/_/g, " ");
|
|
30541
30631
|
}, [idleClipRanges, idleTimeClipClassifications]);
|
|
30542
|
-
const { shiftDuration, shiftEndTime, hasPartialLastHour } =
|
|
30632
|
+
const { shiftDuration, shiftEndTime, hasPartialLastHour } = React141__default.useMemo(() => {
|
|
30543
30633
|
console.log("[HourlyOutputChart] Calculating shift duration with:", {
|
|
30544
30634
|
shiftStart,
|
|
30545
30635
|
shiftEnd,
|
|
@@ -30574,12 +30664,12 @@ var HourlyOutputChartComponent = ({
|
|
|
30574
30664
|
}, [shiftEnd, shiftStartTime.decimalHour]);
|
|
30575
30665
|
const SHIFT_DURATION = shiftDuration;
|
|
30576
30666
|
shiftEndTime ? shiftEndTime.hour : (shiftStartTime.hour + SHIFT_DURATION) % 24;
|
|
30577
|
-
const [animatedData, setAnimatedData] =
|
|
30667
|
+
const [animatedData, setAnimatedData] = React141__default.useState(
|
|
30578
30668
|
() => Array(SHIFT_DURATION).fill(0)
|
|
30579
30669
|
);
|
|
30580
|
-
const prevDataRef =
|
|
30581
|
-
const animationFrameRef =
|
|
30582
|
-
|
|
30670
|
+
const prevDataRef = React141__default.useRef(Array(SHIFT_DURATION).fill(0));
|
|
30671
|
+
const animationFrameRef = React141__default.useRef(null);
|
|
30672
|
+
React141__default.useEffect(() => {
|
|
30583
30673
|
setAnimatedData((prev) => {
|
|
30584
30674
|
if (prev.length !== SHIFT_DURATION) {
|
|
30585
30675
|
return Array(SHIFT_DURATION).fill(0);
|
|
@@ -30588,14 +30678,14 @@ var HourlyOutputChartComponent = ({
|
|
|
30588
30678
|
});
|
|
30589
30679
|
prevDataRef.current = Array(SHIFT_DURATION).fill(0);
|
|
30590
30680
|
}, [SHIFT_DURATION]);
|
|
30591
|
-
const [idleBarState, setIdleBarState] =
|
|
30681
|
+
const [idleBarState, setIdleBarState] = React141__default.useState({
|
|
30592
30682
|
visible: showIdleTime,
|
|
30593
30683
|
key: 0,
|
|
30594
30684
|
shouldAnimate: false
|
|
30595
30685
|
});
|
|
30596
|
-
const prevShowIdleTimeRef =
|
|
30597
|
-
const stateUpdateTimeoutRef =
|
|
30598
|
-
|
|
30686
|
+
const prevShowIdleTimeRef = React141__default.useRef(showIdleTime);
|
|
30687
|
+
const stateUpdateTimeoutRef = React141__default.useRef(null);
|
|
30688
|
+
React141__default.useEffect(() => {
|
|
30599
30689
|
if (stateUpdateTimeoutRef.current) {
|
|
30600
30690
|
clearTimeout(stateUpdateTimeoutRef.current);
|
|
30601
30691
|
}
|
|
@@ -30620,7 +30710,7 @@ var HourlyOutputChartComponent = ({
|
|
|
30620
30710
|
}
|
|
30621
30711
|
};
|
|
30622
30712
|
}, [showIdleTime]);
|
|
30623
|
-
const animateToNewData =
|
|
30713
|
+
const animateToNewData = React141__default.useCallback((targetData) => {
|
|
30624
30714
|
const startData = [...prevDataRef.current];
|
|
30625
30715
|
const startTime = performance.now();
|
|
30626
30716
|
const duration = 1200;
|
|
@@ -30650,7 +30740,7 @@ var HourlyOutputChartComponent = ({
|
|
|
30650
30740
|
}
|
|
30651
30741
|
animationFrameRef.current = requestAnimationFrame(animate);
|
|
30652
30742
|
}, []);
|
|
30653
|
-
|
|
30743
|
+
React141__default.useEffect(() => {
|
|
30654
30744
|
if (JSON.stringify(data) !== JSON.stringify(prevDataRef.current)) {
|
|
30655
30745
|
const shiftData = data.slice(0, SHIFT_DURATION);
|
|
30656
30746
|
animateToNewData(shiftData);
|
|
@@ -30661,7 +30751,7 @@ var HourlyOutputChartComponent = ({
|
|
|
30661
30751
|
}
|
|
30662
30752
|
};
|
|
30663
30753
|
}, [data, animateToNewData]);
|
|
30664
|
-
|
|
30754
|
+
React141__default.useEffect(() => {
|
|
30665
30755
|
const checkContainerDimensions = () => {
|
|
30666
30756
|
if (containerRef.current) {
|
|
30667
30757
|
const rect = containerRef.current.getBoundingClientRect();
|
|
@@ -30687,7 +30777,7 @@ var HourlyOutputChartComponent = ({
|
|
|
30687
30777
|
clearTimeout(fallbackTimeout);
|
|
30688
30778
|
};
|
|
30689
30779
|
}, []);
|
|
30690
|
-
const xAxisConfig =
|
|
30780
|
+
const xAxisConfig = React141__default.useMemo(() => {
|
|
30691
30781
|
if (containerWidth >= 960) {
|
|
30692
30782
|
return { interval: 0, angle: -45, height: 92, tickFont: 10, tickMargin: 12 };
|
|
30693
30783
|
}
|
|
@@ -30696,7 +30786,7 @@ var HourlyOutputChartComponent = ({
|
|
|
30696
30786
|
}
|
|
30697
30787
|
return { interval: 0, angle: -30, height: 64, tickFont: 9, tickMargin: 6 };
|
|
30698
30788
|
}, [containerWidth]);
|
|
30699
|
-
const formatHour =
|
|
30789
|
+
const formatHour = React141__default.useCallback((hourIndex) => {
|
|
30700
30790
|
const isLastHour = hourIndex === SHIFT_DURATION - 1;
|
|
30701
30791
|
const startDecimalHour = shiftStartTime.decimalHour + hourIndex;
|
|
30702
30792
|
const startHour = Math.floor(startDecimalHour) % 24;
|
|
@@ -30720,7 +30810,7 @@ var HourlyOutputChartComponent = ({
|
|
|
30720
30810
|
};
|
|
30721
30811
|
return `${formatTime5(startHour, startMinute)}-${formatTime5(endHour, endMinute)}`;
|
|
30722
30812
|
}, [shiftStartTime.decimalHour, SHIFT_DURATION, shiftEndTime]);
|
|
30723
|
-
const formatTimeRange2 =
|
|
30813
|
+
const formatTimeRange2 = React141__default.useCallback((hourIndex) => {
|
|
30724
30814
|
const isLastHour = hourIndex === SHIFT_DURATION - 1;
|
|
30725
30815
|
const startDecimalHour = shiftStartTime.decimalHour + hourIndex;
|
|
30726
30816
|
const startHour = Math.floor(startDecimalHour) % 24;
|
|
@@ -30741,7 +30831,7 @@ var HourlyOutputChartComponent = ({
|
|
|
30741
30831
|
};
|
|
30742
30832
|
return `${formatTime5(startHour, startMinute)} - ${formatTime5(endHour, endMinute)}`;
|
|
30743
30833
|
}, [shiftStartTime.decimalHour, SHIFT_DURATION, shiftEndTime]);
|
|
30744
|
-
const chartData =
|
|
30834
|
+
const chartData = React141__default.useMemo(() => {
|
|
30745
30835
|
return Array.from({ length: SHIFT_DURATION }, (_, i) => {
|
|
30746
30836
|
const actualHour = (shiftStartTime.hour + i) % 24;
|
|
30747
30837
|
const startMinute = shiftStartTime.minute;
|
|
@@ -30811,7 +30901,7 @@ var HourlyOutputChartComponent = ({
|
|
|
30811
30901
|
};
|
|
30812
30902
|
});
|
|
30813
30903
|
}, [animatedData, data, pphThreshold, idleTimeHourly, shiftStartTime.hour, shiftStartTime.minute, shiftEndTime, formatHour, formatTimeRange2, SHIFT_DURATION]);
|
|
30814
|
-
const IdleBar =
|
|
30904
|
+
const IdleBar = React141__default.useMemo(() => {
|
|
30815
30905
|
if (!idleBarState.visible) return null;
|
|
30816
30906
|
return /* @__PURE__ */ jsx(
|
|
30817
30907
|
Bar,
|
|
@@ -31139,7 +31229,7 @@ var HourlyOutputChartComponent = ({
|
|
|
31139
31229
|
}
|
|
31140
31230
|
);
|
|
31141
31231
|
};
|
|
31142
|
-
var HourlyOutputChart =
|
|
31232
|
+
var HourlyOutputChart = React141__default.memo(HourlyOutputChartComponent, (prevProps, nextProps) => {
|
|
31143
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) {
|
|
31144
31234
|
return false;
|
|
31145
31235
|
}
|
|
@@ -31202,7 +31292,7 @@ function getTrendArrowAndColor(trend) {
|
|
|
31202
31292
|
return { arrow: "\u2192", color: "text-gray-400" };
|
|
31203
31293
|
}
|
|
31204
31294
|
}
|
|
31205
|
-
var VideoCard =
|
|
31295
|
+
var VideoCard = React141__default.memo(({
|
|
31206
31296
|
workspace,
|
|
31207
31297
|
hlsUrl,
|
|
31208
31298
|
shouldPlay,
|
|
@@ -31382,7 +31472,7 @@ var logDebug2 = (...args) => {
|
|
|
31382
31472
|
if (!DEBUG_DASHBOARD_LOGS2) return;
|
|
31383
31473
|
console.log(...args);
|
|
31384
31474
|
};
|
|
31385
|
-
var VideoGridView =
|
|
31475
|
+
var VideoGridView = React141__default.memo(({
|
|
31386
31476
|
workspaces,
|
|
31387
31477
|
selectedLine,
|
|
31388
31478
|
className = "",
|
|
@@ -31619,7 +31709,8 @@ var VideoGridView = React26__default.memo(({
|
|
|
31619
31709
|
action_count: workspace.action_count
|
|
31620
31710
|
});
|
|
31621
31711
|
const displayName = getWorkspaceDisplayName(workspace.workspace_name, workspace.line_id);
|
|
31622
|
-
const
|
|
31712
|
+
const currentPath = (router.asPath || "/").split("#")[0];
|
|
31713
|
+
const navParams = getWorkspaceNavigationParams(workspaceId, displayName, workspace.line_id, currentPath);
|
|
31623
31714
|
router.push(`/workspace/${workspaceId}${navParams}`);
|
|
31624
31715
|
}, [router, prewarmClipsInit]);
|
|
31625
31716
|
const handleStreamError = useCallback((workspaceId, options) => {
|
|
@@ -31751,7 +31842,7 @@ var VideoGridView = React26__default.memo(({
|
|
|
31751
31842
|
) }) });
|
|
31752
31843
|
});
|
|
31753
31844
|
VideoGridView.displayName = "VideoGridView";
|
|
31754
|
-
var MapGridView =
|
|
31845
|
+
var MapGridView = React141__default.memo(({
|
|
31755
31846
|
workspaces,
|
|
31756
31847
|
className = "",
|
|
31757
31848
|
displayNames = {},
|
|
@@ -31826,7 +31917,8 @@ var MapGridView = React26__default.memo(({
|
|
|
31826
31917
|
});
|
|
31827
31918
|
const displayName = displayNames[`${workspace.line_id}_${workspace.workspace_name}`] || // Always pass line_id to fallback to ensure correct mapping per line
|
|
31828
31919
|
getWorkspaceDisplayName(workspace.workspace_name, workspace.line_id);
|
|
31829
|
-
const
|
|
31920
|
+
const currentPath = (router.asPath || "/").split("#")[0];
|
|
31921
|
+
const navParams = getWorkspaceNavigationParams(workspaceId, displayName, workspace.line_id, currentPath);
|
|
31830
31922
|
router.push(`/workspace/${workspaceId}${navParams}`);
|
|
31831
31923
|
}, [router, displayNames, prewarmClipsInit]);
|
|
31832
31924
|
const activePositions = useMemo(() => {
|
|
@@ -32572,7 +32664,7 @@ var UptimeLineChartComponent = ({ points, className = "" }) => {
|
|
|
32572
32664
|
)
|
|
32573
32665
|
] }) }) });
|
|
32574
32666
|
};
|
|
32575
|
-
var UptimeLineChart =
|
|
32667
|
+
var UptimeLineChart = React141__default.memo(UptimeLineChartComponent);
|
|
32576
32668
|
var padTime = (value) => value.toString().padStart(2, "0");
|
|
32577
32669
|
var parseTime = (timeValue) => {
|
|
32578
32670
|
if (!timeValue) return null;
|
|
@@ -32781,10 +32873,10 @@ var HourlyUptimeChartComponent = ({
|
|
|
32781
32873
|
elapsedMinutes,
|
|
32782
32874
|
className = ""
|
|
32783
32875
|
}) => {
|
|
32784
|
-
const containerRef =
|
|
32785
|
-
const [containerReady, setContainerReady] =
|
|
32786
|
-
const [containerWidth, setContainerWidth] =
|
|
32787
|
-
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({
|
|
32788
32880
|
idleTimeHourly,
|
|
32789
32881
|
shiftStart,
|
|
32790
32882
|
shiftEnd,
|
|
@@ -32793,11 +32885,11 @@ var HourlyUptimeChartComponent = ({
|
|
|
32793
32885
|
elapsedMinutes
|
|
32794
32886
|
}), [idleTimeHourly, shiftStart, shiftEnd, shiftDate, timezone, elapsedMinutes]);
|
|
32795
32887
|
const hasAggregateData = Boolean(hourlyAggregates && hourlyAggregates.length > 0);
|
|
32796
|
-
const shiftStartTime =
|
|
32888
|
+
const shiftStartTime = React141__default.useMemo(
|
|
32797
32889
|
() => getTimeFromTimeString(shiftStart),
|
|
32798
32890
|
[shiftStart]
|
|
32799
32891
|
);
|
|
32800
|
-
const { shiftDuration, shiftEndTime } =
|
|
32892
|
+
const { shiftDuration, shiftEndTime } = React141__default.useMemo(() => {
|
|
32801
32893
|
if (!shiftEnd) {
|
|
32802
32894
|
const fallbackHours = uptimeSeries.shiftMinutes > 0 ? Math.ceil(uptimeSeries.shiftMinutes / 60) : 0;
|
|
32803
32895
|
return { shiftDuration: fallbackHours, shiftEndTime: null };
|
|
@@ -32811,7 +32903,7 @@ var HourlyUptimeChartComponent = ({
|
|
|
32811
32903
|
const hourCount = hasPartial ? Math.ceil(duration) : Math.round(duration);
|
|
32812
32904
|
return { shiftDuration: hourCount, shiftEndTime: endTime };
|
|
32813
32905
|
}, [shiftEnd, shiftStartTime.decimalHour, uptimeSeries.shiftMinutes]);
|
|
32814
|
-
const formatHour =
|
|
32906
|
+
const formatHour = React141__default.useCallback((hourIndex) => {
|
|
32815
32907
|
const isLastHour = hourIndex === shiftDuration - 1;
|
|
32816
32908
|
const startDecimalHour = shiftStartTime.decimalHour + hourIndex;
|
|
32817
32909
|
const startHour = Math.floor(startDecimalHour) % 24;
|
|
@@ -32836,7 +32928,7 @@ var HourlyUptimeChartComponent = ({
|
|
|
32836
32928
|
};
|
|
32837
32929
|
return `${formatTime5(startHour, startMinute)}-${formatTime5(endHour, endMinute)}`;
|
|
32838
32930
|
}, [shiftDuration, shiftStartTime.decimalHour, shiftEndTime]);
|
|
32839
|
-
const formatTimeRange2 =
|
|
32931
|
+
const formatTimeRange2 = React141__default.useCallback((hourIndex) => {
|
|
32840
32932
|
const isLastHour = hourIndex === shiftDuration - 1;
|
|
32841
32933
|
const startDecimalHour = shiftStartTime.decimalHour + hourIndex;
|
|
32842
32934
|
const startHour = Math.floor(startDecimalHour) % 24;
|
|
@@ -32858,7 +32950,7 @@ var HourlyUptimeChartComponent = ({
|
|
|
32858
32950
|
};
|
|
32859
32951
|
return `${formatTime5(startHour, startMinute)} - ${formatTime5(endHour, endMinute)}`;
|
|
32860
32952
|
}, [shiftDuration, shiftStartTime.decimalHour, shiftEndTime]);
|
|
32861
|
-
const chartData =
|
|
32953
|
+
const chartData = React141__default.useMemo(() => {
|
|
32862
32954
|
if (shiftDuration <= 0) return [];
|
|
32863
32955
|
if (hasAggregateData) {
|
|
32864
32956
|
return hourlyAggregates.map((entry, hourIndex) => ({
|
|
@@ -32900,7 +32992,7 @@ var HourlyUptimeChartComponent = ({
|
|
|
32900
32992
|
}, [hasAggregateData, hourlyAggregates, uptimeSeries.points, uptimeSeries.elapsedMinutes, uptimeSeries.shiftMinutes, shiftDuration, formatHour, formatTimeRange2]);
|
|
32901
32993
|
const maxYValue = 100;
|
|
32902
32994
|
const yAxisTicks = [0, 25, 50, 75, 100];
|
|
32903
|
-
|
|
32995
|
+
React141__default.useEffect(() => {
|
|
32904
32996
|
const checkContainerDimensions = () => {
|
|
32905
32997
|
if (containerRef.current) {
|
|
32906
32998
|
const rect = containerRef.current.getBoundingClientRect();
|
|
@@ -32926,7 +33018,7 @@ var HourlyUptimeChartComponent = ({
|
|
|
32926
33018
|
clearTimeout(fallbackTimeout);
|
|
32927
33019
|
};
|
|
32928
33020
|
}, []);
|
|
32929
|
-
const xAxisConfig =
|
|
33021
|
+
const xAxisConfig = React141__default.useMemo(() => {
|
|
32930
33022
|
if (containerWidth >= 960) {
|
|
32931
33023
|
return { interval: 0, angle: -45, height: 92, tickFont: 10, tickMargin: 12, labelMode: "full" };
|
|
32932
33024
|
}
|
|
@@ -32935,7 +33027,7 @@ var HourlyUptimeChartComponent = ({
|
|
|
32935
33027
|
}
|
|
32936
33028
|
return { interval: 0, angle: -30, height: 64, tickFont: 9, tickMargin: 6, labelMode: "start" };
|
|
32937
33029
|
}, [containerWidth]);
|
|
32938
|
-
const formatXAxisTick =
|
|
33030
|
+
const formatXAxisTick = React141__default.useCallback((raw) => {
|
|
32939
33031
|
const label = typeof raw === "string" ? raw : String(raw);
|
|
32940
33032
|
if (xAxisConfig.labelMode === "full") return label;
|
|
32941
33033
|
const parts = label.split("-");
|
|
@@ -33141,7 +33233,7 @@ var HourlyUptimeChartComponent = ({
|
|
|
33141
33233
|
}
|
|
33142
33234
|
);
|
|
33143
33235
|
};
|
|
33144
|
-
var HourlyUptimeChart =
|
|
33236
|
+
var HourlyUptimeChart = React141__default.memo(HourlyUptimeChartComponent);
|
|
33145
33237
|
var DEFAULT_COLORS2 = ["#00AB45", "#ef4444"];
|
|
33146
33238
|
var UptimeDonutChartComponent = ({
|
|
33147
33239
|
data,
|
|
@@ -33211,7 +33303,7 @@ var UptimeDonutChartComponent = ({
|
|
|
33211
33303
|
] }) })
|
|
33212
33304
|
] }) });
|
|
33213
33305
|
};
|
|
33214
|
-
var UptimeDonutChart =
|
|
33306
|
+
var UptimeDonutChart = React141__default.memo(UptimeDonutChartComponent);
|
|
33215
33307
|
UptimeDonutChart.displayName = "UptimeDonutChart";
|
|
33216
33308
|
var TrendIcon = ({ trend }) => {
|
|
33217
33309
|
if (trend === "up") {
|
|
@@ -33330,7 +33422,7 @@ var EmptyStateMessage = ({
|
|
|
33330
33422
|
iconClassName
|
|
33331
33423
|
}) => {
|
|
33332
33424
|
let IconContent = null;
|
|
33333
|
-
if (
|
|
33425
|
+
if (React141__default.isValidElement(iconType)) {
|
|
33334
33426
|
IconContent = iconType;
|
|
33335
33427
|
} else if (typeof iconType === "string") {
|
|
33336
33428
|
const MappedIcon = IconMap[iconType];
|
|
@@ -35615,7 +35707,7 @@ function Skeleton({ className, ...props }) {
|
|
|
35615
35707
|
var Select = SelectPrimitive.Root;
|
|
35616
35708
|
var SelectGroup = SelectPrimitive.Group;
|
|
35617
35709
|
var SelectValue = SelectPrimitive.Value;
|
|
35618
|
-
var SelectTrigger =
|
|
35710
|
+
var SelectTrigger = React141.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(
|
|
35619
35711
|
SelectPrimitive.Trigger,
|
|
35620
35712
|
{
|
|
35621
35713
|
ref,
|
|
@@ -35631,7 +35723,7 @@ var SelectTrigger = React26.forwardRef(({ className, children, ...props }, ref)
|
|
|
35631
35723
|
}
|
|
35632
35724
|
));
|
|
35633
35725
|
SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
|
|
35634
|
-
var SelectScrollUpButton =
|
|
35726
|
+
var SelectScrollUpButton = React141.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
35635
35727
|
SelectPrimitive.ScrollUpButton,
|
|
35636
35728
|
{
|
|
35637
35729
|
ref,
|
|
@@ -35641,7 +35733,7 @@ var SelectScrollUpButton = React26.forwardRef(({ className, ...props }, ref) =>
|
|
|
35641
35733
|
}
|
|
35642
35734
|
));
|
|
35643
35735
|
SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName;
|
|
35644
|
-
var SelectScrollDownButton =
|
|
35736
|
+
var SelectScrollDownButton = React141.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
35645
35737
|
SelectPrimitive.ScrollDownButton,
|
|
35646
35738
|
{
|
|
35647
35739
|
ref,
|
|
@@ -35651,7 +35743,7 @@ var SelectScrollDownButton = React26.forwardRef(({ className, ...props }, ref) =
|
|
|
35651
35743
|
}
|
|
35652
35744
|
));
|
|
35653
35745
|
SelectScrollDownButton.displayName = SelectPrimitive.ScrollDownButton.displayName;
|
|
35654
|
-
var SelectContent =
|
|
35746
|
+
var SelectContent = React141.forwardRef(({ className, children, position = "popper", ...props }, ref) => /* @__PURE__ */ jsx(SelectPrimitive.Portal, { children: /* @__PURE__ */ jsxs(
|
|
35655
35747
|
SelectPrimitive.Content,
|
|
35656
35748
|
{
|
|
35657
35749
|
ref,
|
|
@@ -35679,7 +35771,7 @@ var SelectContent = React26.forwardRef(({ className, children, position = "poppe
|
|
|
35679
35771
|
}
|
|
35680
35772
|
) }));
|
|
35681
35773
|
SelectContent.displayName = SelectPrimitive.Content.displayName;
|
|
35682
|
-
var SelectLabel =
|
|
35774
|
+
var SelectLabel = React141.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
35683
35775
|
SelectPrimitive.Label,
|
|
35684
35776
|
{
|
|
35685
35777
|
ref,
|
|
@@ -35688,7 +35780,7 @@ var SelectLabel = React26.forwardRef(({ className, ...props }, ref) => /* @__PUR
|
|
|
35688
35780
|
}
|
|
35689
35781
|
));
|
|
35690
35782
|
SelectLabel.displayName = SelectPrimitive.Label.displayName;
|
|
35691
|
-
var SelectItem =
|
|
35783
|
+
var SelectItem = React141.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(
|
|
35692
35784
|
SelectPrimitive.Item,
|
|
35693
35785
|
{
|
|
35694
35786
|
ref,
|
|
@@ -35704,7 +35796,7 @@ var SelectItem = React26.forwardRef(({ className, children, ...props }, ref) =>
|
|
|
35704
35796
|
}
|
|
35705
35797
|
));
|
|
35706
35798
|
SelectItem.displayName = SelectPrimitive.Item.displayName;
|
|
35707
|
-
var SelectSeparator =
|
|
35799
|
+
var SelectSeparator = React141.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
35708
35800
|
SelectPrimitive.Separator,
|
|
35709
35801
|
{
|
|
35710
35802
|
ref,
|
|
@@ -36003,7 +36095,7 @@ var TimePickerDropdown = ({
|
|
|
36003
36095
|
] })
|
|
36004
36096
|
] });
|
|
36005
36097
|
};
|
|
36006
|
-
var SilentErrorBoundary = class extends
|
|
36098
|
+
var SilentErrorBoundary = class extends React141__default.Component {
|
|
36007
36099
|
constructor(props) {
|
|
36008
36100
|
super(props);
|
|
36009
36101
|
this.handleClearAndReload = () => {
|
|
@@ -42517,6 +42609,32 @@ var STATIC_COLORS = {
|
|
|
42517
42609
|
};
|
|
42518
42610
|
var PRODUCTIVE_COLOR = "#00AB45";
|
|
42519
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
|
+
};
|
|
42520
42638
|
var getColorForEntry = (name, index) => {
|
|
42521
42639
|
const normalized = name.trim().toLowerCase();
|
|
42522
42640
|
if (normalized === "productive" || normalized === "productive time") {
|
|
@@ -42531,11 +42649,37 @@ var getColorForEntry = (name, index) => {
|
|
|
42531
42649
|
const snakeCaseName = name.replace(/ /g, "_");
|
|
42532
42650
|
return getReasonColor(snakeCaseName, index);
|
|
42533
42651
|
};
|
|
42534
|
-
var CustomTooltip = ({ active, payload }) => {
|
|
42652
|
+
var CustomTooltip = ({ active, payload, hideTotalDuration }) => {
|
|
42535
42653
|
if (active && payload && payload.length) {
|
|
42536
|
-
|
|
42537
|
-
|
|
42538
|
-
|
|
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
|
|
42539
42683
|
] });
|
|
42540
42684
|
}
|
|
42541
42685
|
return null;
|
|
@@ -42572,10 +42716,11 @@ var ErrorState = ({ error }) => /* @__PURE__ */ jsx("div", { className: "w-full
|
|
|
42572
42716
|
var IdleTimeReasonChartComponent = ({
|
|
42573
42717
|
data,
|
|
42574
42718
|
isLoading = false,
|
|
42575
|
-
error = null
|
|
42719
|
+
error = null,
|
|
42720
|
+
hideTotalDuration = false
|
|
42576
42721
|
}) => {
|
|
42577
|
-
const [activeData, setActiveData] =
|
|
42578
|
-
|
|
42722
|
+
const [activeData, setActiveData] = React141__default.useState([]);
|
|
42723
|
+
React141__default.useEffect(() => {
|
|
42579
42724
|
if (activeData.length > 0) {
|
|
42580
42725
|
setActiveData([]);
|
|
42581
42726
|
}
|
|
@@ -42590,7 +42735,7 @@ var IdleTimeReasonChartComponent = ({
|
|
|
42590
42735
|
setActiveData([]);
|
|
42591
42736
|
}
|
|
42592
42737
|
}, [data]);
|
|
42593
|
-
|
|
42738
|
+
React141__default.useEffect(() => {
|
|
42594
42739
|
if (!data || data.length === 0) return;
|
|
42595
42740
|
data.forEach((entry, index) => {
|
|
42596
42741
|
if (entry.name.toLowerCase().includes("other")) {
|
|
@@ -42598,7 +42743,7 @@ var IdleTimeReasonChartComponent = ({
|
|
|
42598
42743
|
}
|
|
42599
42744
|
});
|
|
42600
42745
|
}, [data]);
|
|
42601
|
-
const pieKey =
|
|
42746
|
+
const pieKey = React141__default.useMemo(() => {
|
|
42602
42747
|
return activeData.map((d) => `${d.name}-${d.value}`).join("|");
|
|
42603
42748
|
}, [activeData]);
|
|
42604
42749
|
if (isLoading) {
|
|
@@ -42625,19 +42770,29 @@ var IdleTimeReasonChartComponent = ({
|
|
|
42625
42770
|
}
|
|
42626
42771
|
.recharts-wrapper {
|
|
42627
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;
|
|
42628
42783
|
}
|
|
42629
42784
|
` }),
|
|
42630
42785
|
/* @__PURE__ */ jsxs(
|
|
42631
42786
|
"div",
|
|
42632
42787
|
{
|
|
42633
|
-
className: "w-full h-full flex items-center overflow-
|
|
42788
|
+
className: "w-full h-full flex items-center overflow-visible focus:outline-none",
|
|
42634
42789
|
tabIndex: -1,
|
|
42635
42790
|
onFocus: (e) => e.currentTarget.blur(),
|
|
42636
42791
|
children: [
|
|
42637
42792
|
/* @__PURE__ */ jsx(
|
|
42638
42793
|
"div",
|
|
42639
42794
|
{
|
|
42640
|
-
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",
|
|
42641
42796
|
tabIndex: -1,
|
|
42642
42797
|
onFocus: (e) => e.currentTarget.blur(),
|
|
42643
42798
|
children: /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxs(PieChart, { margin: { top: 0, right: 0, bottom: 0, left: 0 }, children: [
|
|
@@ -42669,11 +42824,11 @@ var IdleTimeReasonChartComponent = ({
|
|
|
42669
42824
|
},
|
|
42670
42825
|
pieKey
|
|
42671
42826
|
),
|
|
42672
|
-
/* @__PURE__ */ jsx(Tooltip, { content: /* @__PURE__ */ jsx(CustomTooltip, {}) })
|
|
42827
|
+
/* @__PURE__ */ jsx(Tooltip, { content: /* @__PURE__ */ jsx(CustomTooltip, { hideTotalDuration }) })
|
|
42673
42828
|
] }) })
|
|
42674
42829
|
}
|
|
42675
42830
|
),
|
|
42676
|
-
/* @__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: [
|
|
42677
42832
|
/* @__PURE__ */ jsx(
|
|
42678
42833
|
"span",
|
|
42679
42834
|
{
|
|
@@ -42681,14 +42836,14 @@ var IdleTimeReasonChartComponent = ({
|
|
|
42681
42836
|
style: { backgroundColor: getColorForEntry(entry.name, index) }
|
|
42682
42837
|
}
|
|
42683
42838
|
),
|
|
42684
|
-
/* @__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, " ") })
|
|
42685
42840
|
] }, `item-${index}`)) }) })
|
|
42686
42841
|
]
|
|
42687
42842
|
}
|
|
42688
42843
|
)
|
|
42689
42844
|
] });
|
|
42690
42845
|
};
|
|
42691
|
-
var IdleTimeReasonChart =
|
|
42846
|
+
var IdleTimeReasonChart = React141__default.memo(IdleTimeReasonChartComponent);
|
|
42692
42847
|
IdleTimeReasonChart.displayName = "IdleTimeReasonChart";
|
|
42693
42848
|
var IdleTimeReasonChart_default = IdleTimeReasonChart;
|
|
42694
42849
|
var DEFAULT_PERFORMANCE_DATA = {
|
|
@@ -46910,11 +47065,11 @@ var getWorkspaceStyles = (position, isPlaceholder = false) => {
|
|
|
46910
47065
|
${isPlaceholder ? "cursor-default" : ""}`;
|
|
46911
47066
|
};
|
|
46912
47067
|
var formatPercentRange = (min, max) => {
|
|
46913
|
-
const
|
|
47068
|
+
const format8 = (value) => Number.isInteger(value) ? `${value}` : value.toFixed(1);
|
|
46914
47069
|
if (min >= 100 || max >= 100) {
|
|
46915
|
-
return `${
|
|
47070
|
+
return `${format8(min)}+%`;
|
|
46916
47071
|
}
|
|
46917
|
-
return `${
|
|
47072
|
+
return `${format8(min)}-${format8(max)}%`;
|
|
46918
47073
|
};
|
|
46919
47074
|
var Legend6 = ({ useBottleneckLabel = false, legend }) => {
|
|
46920
47075
|
const effectiveLegend = legend || DEFAULT_EFFICIENCY_LEGEND;
|
|
@@ -46948,7 +47103,7 @@ var arePropsEqual = (prevProps, nextProps) => {
|
|
|
46948
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
|
|
46949
47104
|
prevProps.position.id === nextProps.position.id;
|
|
46950
47105
|
};
|
|
46951
|
-
var WorkspaceGridItem =
|
|
47106
|
+
var WorkspaceGridItem = React141__default.memo(({
|
|
46952
47107
|
data,
|
|
46953
47108
|
position,
|
|
46954
47109
|
isBottleneck = false,
|
|
@@ -46977,7 +47132,8 @@ var WorkspaceGridItem = React26__default.memo(({
|
|
|
46977
47132
|
e.preventDefault();
|
|
46978
47133
|
if (isInactive) return;
|
|
46979
47134
|
const displayName = getWorkspaceDisplayName(data.workspace_name, data.line_id);
|
|
46980
|
-
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);
|
|
46981
47137
|
navigate(`/workspace/${data.workspace_id}${navParams}`, {
|
|
46982
47138
|
trackingEvent: {
|
|
46983
47139
|
name: "Workspace Detail Clicked",
|
|
@@ -47042,7 +47198,7 @@ var WorkspaceGridItem = React26__default.memo(({
|
|
|
47042
47198
|
);
|
|
47043
47199
|
}, arePropsEqual);
|
|
47044
47200
|
WorkspaceGridItem.displayName = "WorkspaceGridItem";
|
|
47045
|
-
var WorkspaceGrid =
|
|
47201
|
+
var WorkspaceGrid = React141__default.memo(({
|
|
47046
47202
|
workspaces,
|
|
47047
47203
|
isPdfMode = false,
|
|
47048
47204
|
customWorkspacePositions,
|
|
@@ -47297,7 +47453,7 @@ var KPICard = ({
|
|
|
47297
47453
|
}) => {
|
|
47298
47454
|
useThemeConfig();
|
|
47299
47455
|
const { formatNumber } = useFormatNumber();
|
|
47300
|
-
const trendInfo =
|
|
47456
|
+
const trendInfo = React141__default.useMemo(() => {
|
|
47301
47457
|
let trendValue = trend || "neutral";
|
|
47302
47458
|
if (change !== void 0 && trend === void 0) {
|
|
47303
47459
|
trendValue = change > 0 ? "up" : change < 0 ? "down" : "neutral";
|
|
@@ -47324,7 +47480,7 @@ var KPICard = ({
|
|
|
47324
47480
|
const shouldShowTrend = !(change === 0 && trend === void 0);
|
|
47325
47481
|
return { trendValue, Icon: Icon2, colorClass, bgClass, shouldShowTrend };
|
|
47326
47482
|
}, [trend, change]);
|
|
47327
|
-
const formattedValue =
|
|
47483
|
+
const formattedValue = React141__default.useMemo(() => {
|
|
47328
47484
|
if (title === "Quality Compliance" && typeof value === "number") {
|
|
47329
47485
|
return value.toFixed(1);
|
|
47330
47486
|
}
|
|
@@ -47338,7 +47494,7 @@ var KPICard = ({
|
|
|
47338
47494
|
}
|
|
47339
47495
|
return value;
|
|
47340
47496
|
}, [value, title]);
|
|
47341
|
-
const formattedChange =
|
|
47497
|
+
const formattedChange = React141__default.useMemo(() => {
|
|
47342
47498
|
if (change === void 0 || change === 0 && !showZeroChange) return null;
|
|
47343
47499
|
const absChange = Math.abs(change);
|
|
47344
47500
|
return formatNumber(absChange, { minimumFractionDigits: 0, maximumFractionDigits: 1 });
|
|
@@ -47776,7 +47932,7 @@ var WorkspaceHealthCard = ({
|
|
|
47776
47932
|
onClick(workspace);
|
|
47777
47933
|
}
|
|
47778
47934
|
};
|
|
47779
|
-
const
|
|
47935
|
+
const formatDuration5 = (minutes) => {
|
|
47780
47936
|
if (!minutes || minutes <= 0) return "0 min";
|
|
47781
47937
|
const rounded = Math.max(Math.round(minutes), 0);
|
|
47782
47938
|
const days = Math.floor(rounded / 1440);
|
|
@@ -47842,7 +47998,7 @@ var WorkspaceHealthCard = ({
|
|
|
47842
47998
|
};
|
|
47843
47999
|
}
|
|
47844
48000
|
return {
|
|
47845
|
-
text: `${
|
|
48001
|
+
text: `${formatDuration5(downtimeMinutes)}`,
|
|
47846
48002
|
className: downtimeMinutes > 60 ? "text-rose-600 dark:text-rose-400" : "text-amber-600 dark:text-amber-400",
|
|
47847
48003
|
label: "Total Downtime"
|
|
47848
48004
|
};
|
|
@@ -48818,7 +48974,7 @@ var Breadcrumbs = ({ items }) => {
|
|
|
48818
48974
|
}
|
|
48819
48975
|
}
|
|
48820
48976
|
};
|
|
48821
|
-
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: [
|
|
48822
48978
|
index > 0 && /* @__PURE__ */ jsx(ChevronRight, { className: "h-3 w-3 text-gray-400 dark:text-gray-500" }),
|
|
48823
48979
|
/* @__PURE__ */ jsxs(
|
|
48824
48980
|
"span",
|
|
@@ -48880,29 +49036,27 @@ var UserProfileDropdown = ({ config }) => {
|
|
|
48880
49036
|
}
|
|
48881
49037
|
}
|
|
48882
49038
|
};
|
|
48883
|
-
const
|
|
49039
|
+
const fullName = user?.user_metadata?.full_name;
|
|
49040
|
+
const triggerLabel = config.showName !== false ? fullName || user.email || "Account" : "Account";
|
|
48884
49041
|
return /* @__PURE__ */ jsxs("div", { className: "relative", ref: dropdownRef, children: [
|
|
48885
|
-
/* @__PURE__ */
|
|
49042
|
+
/* @__PURE__ */ jsx(
|
|
48886
49043
|
"button",
|
|
48887
49044
|
{
|
|
48888
49045
|
type: "button",
|
|
48889
|
-
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",
|
|
48890
49047
|
onClick: () => setIsOpen(!isOpen),
|
|
48891
49048
|
"aria-haspopup": "true",
|
|
48892
49049
|
"aria-expanded": isOpen,
|
|
48893
49050
|
"aria-label": "User menu",
|
|
48894
|
-
children: [
|
|
48895
|
-
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,
|
|
48896
|
-
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 })
|
|
48897
|
-
]
|
|
49051
|
+
children: /* @__PURE__ */ jsx("span", { className: "truncate max-w-[180px]", children: triggerLabel })
|
|
48898
49052
|
}
|
|
48899
49053
|
),
|
|
48900
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: [
|
|
48901
|
-
config.showName !== false &&
|
|
48902
|
-
/* @__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 }),
|
|
48903
49057
|
user.email && /* @__PURE__ */ jsx("p", { className: "text-xs text-gray-500 dark:text-gray-400 truncate", children: user.email })
|
|
48904
49058
|
] }),
|
|
48905
|
-
|
|
49059
|
+
fullName && /* @__PURE__ */ jsx("div", { className: "md:hidden h-px bg-gray-200 dark:bg-gray-700 my-1" }),
|
|
48906
49060
|
menuItems.map(
|
|
48907
49061
|
(item) => item.isDivider ? /* @__PURE__ */ jsx("div", { className: "h-px bg-gray-200 dark:bg-gray-700 my-1" }, item.key) : /* @__PURE__ */ jsxs(
|
|
48908
49062
|
"button",
|
|
@@ -49144,6 +49298,211 @@ var SettingsPopup = ({
|
|
|
49144
49298
|
document.body
|
|
49145
49299
|
);
|
|
49146
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
|
+
};
|
|
49147
49506
|
var SideNavBar = memo$1(({
|
|
49148
49507
|
// These props are accepted but not used in this implementation
|
|
49149
49508
|
navItems = [],
|
|
@@ -49157,17 +49516,13 @@ var SideNavBar = memo$1(({
|
|
|
49157
49516
|
const router = useRouter();
|
|
49158
49517
|
const { navigate } = useNavigation();
|
|
49159
49518
|
const { signOut, user } = useAuth();
|
|
49519
|
+
const supabase = useSupabase();
|
|
49160
49520
|
const entityConfig = useEntityConfig();
|
|
49161
49521
|
const dashboardConfig = useDashboardConfig();
|
|
49162
49522
|
const isSuperAdmin = user?.scope_mode === "SUPER_ADMIN" || !!user?.access_scope?.is_super_admin;
|
|
49163
49523
|
const role = user?.role_level;
|
|
49164
|
-
const
|
|
49165
|
-
|
|
49166
|
-
owner: ["/", "/leaderboard", "/kpis", "/targets", "/shifts", "/supervisor-management", "/skus", "/help", "/health", "/profile", "/workspace", "/factory-view", "/team-management", "/tickets", "/improvement-center"],
|
|
49167
|
-
it: ["/", "/leaderboard", "/kpis", "/targets", "/shifts", "/supervisor-management", "/skus", "/help", "/health", "/profile", "/workspace", "/factory-view", "/team-management", "/tickets", "/improvement-center"],
|
|
49168
|
-
plant_head: ["/", "/leaderboard", "/kpis", "/targets", "/shifts", "/supervisor-management", "/skus", "/help", "/health", "/profile", "/workspace", "/factory-view", "/team-management", "/tickets", "/improvement-center"],
|
|
49169
|
-
supervisor: ["/", "/leaderboard", "/kpis", "/targets", "/shifts", "/skus", "/help", "/health", "/profile", "/workspace", "/tickets", "/improvement-center"]
|
|
49170
|
-
};
|
|
49524
|
+
const roleNavPaths = useMemo(() => getRoleNavPaths(role), [role]);
|
|
49525
|
+
const showLiveMonitorLink = roleNavPaths.includes("/live-monitor");
|
|
49171
49526
|
const getBasePath = useCallback((path) => {
|
|
49172
49527
|
const firstSegment = path.split("?")[0].split("/").filter(Boolean)[0];
|
|
49173
49528
|
return firstSegment ? `/${firstSegment}` : "/";
|
|
@@ -49176,9 +49531,8 @@ var SideNavBar = memo$1(({
|
|
|
49176
49531
|
if (!role) return false;
|
|
49177
49532
|
if (isSuperAdmin) return true;
|
|
49178
49533
|
const basePath = getBasePath(path);
|
|
49179
|
-
|
|
49180
|
-
|
|
49181
|
-
}, [role, isSuperAdmin, getBasePath]);
|
|
49534
|
+
return roleNavPaths.includes(basePath);
|
|
49535
|
+
}, [role, isSuperAdmin, getBasePath, roleNavPaths]);
|
|
49182
49536
|
const lineId = entityConfig.defaultLineId || LINE_1_UUID;
|
|
49183
49537
|
const skuEnabled = dashboardConfig?.skuConfig?.enabled || false;
|
|
49184
49538
|
dashboardConfig?.supervisorConfig?.enabled || false;
|
|
@@ -49219,6 +49573,17 @@ var SideNavBar = memo$1(({
|
|
|
49219
49573
|
});
|
|
49220
49574
|
onMobileMenuClose?.();
|
|
49221
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]);
|
|
49222
49587
|
const handleKPIsClick = useCallback(() => {
|
|
49223
49588
|
navigate(`/kpis`, {
|
|
49224
49589
|
trackingEvent: {
|
|
@@ -49354,6 +49719,37 @@ var SideNavBar = memo$1(({
|
|
|
49354
49719
|
}, [navigate, onMobileMenuClose]);
|
|
49355
49720
|
const [isSettingsOpen, setIsSettingsOpen] = useState(false);
|
|
49356
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]);
|
|
49357
49753
|
const settingsItems = useMemo(() => {
|
|
49358
49754
|
const items = [
|
|
49359
49755
|
...canAccessPath("/targets") ? [{
|
|
@@ -49448,6 +49844,7 @@ var SideNavBar = memo$1(({
|
|
|
49448
49844
|
onMobileMenuClose?.();
|
|
49449
49845
|
}, [navigate, onMobileMenuClose]);
|
|
49450
49846
|
const homeButtonClasses = useMemo(() => getButtonClasses("/"), [getButtonClasses, pathname]);
|
|
49847
|
+
const liveButtonClasses = useMemo(() => getButtonClasses("/live-monitor"), [getButtonClasses, pathname]);
|
|
49451
49848
|
const leaderboardButtonClasses = useMemo(() => getButtonClasses("/leaderboard"), [getButtonClasses, pathname]);
|
|
49452
49849
|
const kpisButtonClasses = useMemo(() => getButtonClasses("/kpis"), [getButtonClasses, pathname]);
|
|
49453
49850
|
const improvementButtonClasses = useMemo(() => getButtonClasses("/improvement-center"), [getButtonClasses, pathname]);
|
|
@@ -49461,6 +49858,12 @@ var SideNavBar = memo$1(({
|
|
|
49461
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"}
|
|
49462
49859
|
transition-all duration-200 ease-out focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2`;
|
|
49463
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]);
|
|
49464
49867
|
const NavigationContent = () => /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
49465
49868
|
/* @__PURE__ */ jsx("div", { className: "w-full py-6 px-4 flex-shrink-0", children: /* @__PURE__ */ jsx(
|
|
49466
49869
|
"button",
|
|
@@ -49472,21 +49875,38 @@ var SideNavBar = memo$1(({
|
|
|
49472
49875
|
}
|
|
49473
49876
|
) }),
|
|
49474
49877
|
/* @__PURE__ */ jsxs("div", { className: "flex-1 w-full py-6 px-4 overflow-y-auto", children: [
|
|
49475
|
-
/* @__PURE__ */
|
|
49476
|
-
"
|
|
49477
|
-
|
|
49478
|
-
|
|
49479
|
-
|
|
49480
|
-
|
|
49481
|
-
|
|
49482
|
-
|
|
49483
|
-
|
|
49484
|
-
|
|
49485
|
-
|
|
49486
|
-
|
|
49487
|
-
|
|
49488
|
-
|
|
49489
|
-
|
|
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
|
+
] }),
|
|
49490
49910
|
/* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
|
|
49491
49911
|
canAccessPath("/leaderboard") && /* @__PURE__ */ jsxs(
|
|
49492
49912
|
"button",
|
|
@@ -49566,22 +49986,55 @@ var SideNavBar = memo$1(({
|
|
|
49566
49986
|
)
|
|
49567
49987
|
] })
|
|
49568
49988
|
] }),
|
|
49569
|
-
|
|
49570
|
-
|
|
49571
|
-
|
|
49572
|
-
|
|
49573
|
-
|
|
49574
|
-
|
|
49575
|
-
|
|
49576
|
-
|
|
49577
|
-
|
|
49578
|
-
|
|
49579
|
-
|
|
49580
|
-
|
|
49581
|
-
|
|
49582
|
-
|
|
49583
|
-
|
|
49584
|
-
|
|
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
|
+
] })
|
|
49585
50038
|
] });
|
|
49586
50039
|
const MobileNavigationContent = () => {
|
|
49587
50040
|
const isActive = (path) => {
|
|
@@ -49616,6 +50069,18 @@ var SideNavBar = memo$1(({
|
|
|
49616
50069
|
]
|
|
49617
50070
|
}
|
|
49618
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
|
+
),
|
|
49619
50084
|
/* @__PURE__ */ jsxs("div", { className: "mt-6 space-y-2", children: [
|
|
49620
50085
|
canAccessPath("/leaderboard") && /* @__PURE__ */ jsxs(
|
|
49621
50086
|
"button",
|
|
@@ -49679,9 +50144,31 @@ var SideNavBar = memo$1(({
|
|
|
49679
50144
|
}
|
|
49680
50145
|
)
|
|
49681
50146
|
] }),
|
|
49682
|
-
|
|
50147
|
+
/* @__PURE__ */ jsxs("div", { className: "mt-8 pt-6 border-t border-gray-100", children: [
|
|
49683
50148
|
/* @__PURE__ */ jsx("h3", { className: "px-5 mb-3 text-[10px] font-bold text-gray-400 uppercase tracking-widest", children: "Settings & Support" }),
|
|
49684
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
|
+
),
|
|
49685
50172
|
canAccessPath("/targets") && /* @__PURE__ */ jsxs(
|
|
49686
50173
|
"button",
|
|
49687
50174
|
{
|
|
@@ -49796,7 +50283,18 @@ var SideNavBar = memo$1(({
|
|
|
49796
50283
|
] }),
|
|
49797
50284
|
/* @__PURE__ */ jsx("div", { className: "flex-1 overflow-y-auto", children: /* @__PURE__ */ jsx(MobileNavigationContent, {}) })
|
|
49798
50285
|
] })
|
|
49799
|
-
] })
|
|
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
|
+
)
|
|
49800
50298
|
] });
|
|
49801
50299
|
});
|
|
49802
50300
|
SideNavBar.displayName = "SideNavBar";
|
|
@@ -49973,7 +50471,7 @@ var AwardBadge = ({
|
|
|
49973
50471
|
}) => {
|
|
49974
50472
|
const styles2 = getBadgeStyles(type);
|
|
49975
50473
|
const Icon2 = CustomIcon || getDefaultIcon(type);
|
|
49976
|
-
const randomDelay =
|
|
50474
|
+
const randomDelay = React141__default.useMemo(() => Math.random() * 2, []);
|
|
49977
50475
|
const floatingAnimation = {
|
|
49978
50476
|
animate: {
|
|
49979
50477
|
y: [0, -10, 0],
|
|
@@ -52003,18 +52501,20 @@ var InviteUserDialog = ({
|
|
|
52003
52501
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
52004
52502
|
const [error, setError] = useState(null);
|
|
52005
52503
|
const isSuperAdminOptifye = user?.role_level === "optifye" && (user?.scope_mode === "SUPER_ADMIN" || !!user?.access_scope?.is_super_admin);
|
|
52006
|
-
const canInviteOwner = isSuperAdminOptifye;
|
|
52007
|
-
const canInviteIT = user?.role_level
|
|
52008
|
-
const canInvitePlantHead = user?.role_level
|
|
52009
|
-
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 });
|
|
52010
52509
|
const invitableRoles = useMemo(() => {
|
|
52011
52510
|
const roles = [];
|
|
52012
52511
|
if (canInviteOwner) roles.push("owner");
|
|
52013
52512
|
if (canInviteIT) roles.push("it");
|
|
52014
52513
|
if (canInvitePlantHead) roles.push("plant_head");
|
|
52514
|
+
if (canInviteIndustrialEngineer) roles.push("industrial_engineer");
|
|
52015
52515
|
if (canInviteSupervisor) roles.push("supervisor");
|
|
52016
52516
|
return roles;
|
|
52017
|
-
}, [canInviteOwner, canInviteIT, canInvitePlantHead, canInviteSupervisor]);
|
|
52517
|
+
}, [canInviteOwner, canInviteIT, canInvitePlantHead, canInviteIndustrialEngineer, canInviteSupervisor]);
|
|
52018
52518
|
const filteredLines = useMemo(() => {
|
|
52019
52519
|
const search = lineSearch.trim().toLowerCase();
|
|
52020
52520
|
if (!search) return availableLines;
|
|
@@ -52091,6 +52591,10 @@ var InviteUserDialog = ({
|
|
|
52091
52591
|
setError("Only super-admin Optifye users can create owner users.");
|
|
52092
52592
|
return;
|
|
52093
52593
|
}
|
|
52594
|
+
if (selectedRole === "industrial_engineer" && selectedFactories.length === 0) {
|
|
52595
|
+
setError("Select at least one factory for an industrial engineer.");
|
|
52596
|
+
return;
|
|
52597
|
+
}
|
|
52094
52598
|
const companyId = entityConfig?.companyId || user?.properties?.company_id;
|
|
52095
52599
|
if (!companyId) {
|
|
52096
52600
|
setError("Company ID not found. Please refresh and try again.");
|
|
@@ -52114,7 +52618,7 @@ var InviteUserDialog = ({
|
|
|
52114
52618
|
role_level: selectedRole,
|
|
52115
52619
|
company_id: companyId,
|
|
52116
52620
|
line_ids: selectedRole === "supervisor" ? selectedLines : void 0,
|
|
52117
|
-
factory_ids: selectedRole
|
|
52621
|
+
factory_ids: isFactoryScopedRole(selectedRole) ? selectedFactories : void 0,
|
|
52118
52622
|
created_by: user?.id
|
|
52119
52623
|
}
|
|
52120
52624
|
});
|
|
@@ -52352,6 +52856,33 @@ var InviteUserDialog = ({
|
|
|
52352
52856
|
]
|
|
52353
52857
|
}
|
|
52354
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
|
+
),
|
|
52355
52886
|
canInviteSupervisor && /* @__PURE__ */ jsxs(
|
|
52356
52887
|
"label",
|
|
52357
52888
|
{
|
|
@@ -52381,14 +52912,18 @@ var InviteUserDialog = ({
|
|
|
52381
52912
|
)
|
|
52382
52913
|
] })
|
|
52383
52914
|
] }),
|
|
52384
|
-
selectedRole
|
|
52915
|
+
isFactoryScopedRole(selectedRole) && /* @__PURE__ */ jsxs("div", { className: "rounded-xl border border-slate-200 bg-slate-50 p-4 space-y-3", children: [
|
|
52385
52916
|
/* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-3", children: [
|
|
52386
52917
|
/* @__PURE__ */ jsxs("div", { children: [
|
|
52387
52918
|
/* @__PURE__ */ jsxs("p", { className: "text-sm font-medium text-gray-800 flex items-center gap-1.5", children: [
|
|
52388
52919
|
/* @__PURE__ */ jsx(Building2, { className: "w-4 h-4 text-blue-600" }),
|
|
52389
52920
|
"Factory Access"
|
|
52390
52921
|
] }),
|
|
52391
|
-
/* @__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
|
+
] })
|
|
52392
52927
|
] }),
|
|
52393
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: [
|
|
52394
52929
|
selectedFactories.length,
|
|
@@ -52613,16 +53148,6 @@ var InviteUserDialog = ({
|
|
|
52613
53148
|
}
|
|
52614
53149
|
);
|
|
52615
53150
|
};
|
|
52616
|
-
var getRoleLabel = (role) => {
|
|
52617
|
-
const labels = {
|
|
52618
|
-
"supervisor": "Supervisor",
|
|
52619
|
-
"plant_head": "Plant Head",
|
|
52620
|
-
"it": "IT",
|
|
52621
|
-
"owner": "Owner",
|
|
52622
|
-
"optifye": "Optifye Admin"
|
|
52623
|
-
};
|
|
52624
|
-
return labels[role] || role;
|
|
52625
|
-
};
|
|
52626
53151
|
var ChangeRoleDialog = ({
|
|
52627
53152
|
user,
|
|
52628
53153
|
availableRoles,
|
|
@@ -53574,7 +54099,7 @@ var FactoryAssignmentDropdown = ({
|
|
|
53574
54099
|
)
|
|
53575
54100
|
] });
|
|
53576
54101
|
};
|
|
53577
|
-
function
|
|
54102
|
+
function formatDuration2(ms) {
|
|
53578
54103
|
if (ms === void 0 || ms === null) return "No data";
|
|
53579
54104
|
if (ms === 0) return "0m";
|
|
53580
54105
|
const hours = Math.floor(ms / (1e3 * 60 * 60));
|
|
@@ -53618,7 +54143,7 @@ var UserUsageStats = ({
|
|
|
53618
54143
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
|
|
53619
54144
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 text-sm", children: [
|
|
53620
54145
|
/* @__PURE__ */ jsx(Clock, { className: "w-3.5 h-3.5 text-gray-400" }),
|
|
53621
|
-
/* @__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) })
|
|
53622
54147
|
] }),
|
|
53623
54148
|
showViewButton && onViewDetails && /* @__PURE__ */ jsx(
|
|
53624
54149
|
"button",
|
|
@@ -53634,14 +54159,14 @@ var UserUsageStats = ({
|
|
|
53634
54159
|
/* @__PURE__ */ jsx(Activity, { className: "w-3 h-3 text-green-500" }),
|
|
53635
54160
|
/* @__PURE__ */ jsxs("span", { children: [
|
|
53636
54161
|
"Active: ",
|
|
53637
|
-
|
|
54162
|
+
formatDuration2(todayUsage?.active_ms)
|
|
53638
54163
|
] })
|
|
53639
54164
|
] }),
|
|
53640
54165
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
|
|
53641
54166
|
/* @__PURE__ */ jsx(Eye, { className: "w-3 h-3 text-amber-500" }),
|
|
53642
54167
|
/* @__PURE__ */ jsxs("span", { children: [
|
|
53643
54168
|
"Passive: ",
|
|
53644
|
-
|
|
54169
|
+
formatDuration2(todayUsage?.passive_ms)
|
|
53645
54170
|
] })
|
|
53646
54171
|
] })
|
|
53647
54172
|
] })
|
|
@@ -53836,7 +54361,7 @@ function DailyBarChart({
|
|
|
53836
54361
|
/* @__PURE__ */ jsx("div", { className: "w-2 h-2 rounded-full bg-gray-300" }),
|
|
53837
54362
|
/* @__PURE__ */ jsxs("span", { className: "text-sm font-medium text-gray-600", children: [
|
|
53838
54363
|
"Average Daily usage: ",
|
|
53839
|
-
/* @__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" })
|
|
53840
54365
|
] })
|
|
53841
54366
|
] }),
|
|
53842
54367
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-6 text-xs font-medium text-gray-500", children: [
|
|
@@ -53929,7 +54454,7 @@ function DailyBarChart({
|
|
|
53929
54454
|
hasData ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
53930
54455
|
/* @__PURE__ */ jsxs("div", { className: "flex justify-between items-center mb-2", children: [
|
|
53931
54456
|
/* @__PURE__ */ jsx("span", { className: "text-gray-500 text-xs", children: "Total" }),
|
|
53932
|
-
/* @__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) })
|
|
53933
54458
|
] }),
|
|
53934
54459
|
/* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
|
|
53935
54460
|
/* @__PURE__ */ jsxs("div", { className: "flex justify-between items-center text-xs", children: [
|
|
@@ -53937,14 +54462,14 @@ function DailyBarChart({
|
|
|
53937
54462
|
/* @__PURE__ */ jsx("div", { className: "w-1.5 h-1.5 bg-green-500 rounded-full" }),
|
|
53938
54463
|
"Active"
|
|
53939
54464
|
] }),
|
|
53940
|
-
/* @__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) })
|
|
53941
54466
|
] }),
|
|
53942
54467
|
/* @__PURE__ */ jsxs("div", { className: "flex justify-between items-center text-xs", children: [
|
|
53943
54468
|
/* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1.5 text-gray-500", children: [
|
|
53944
54469
|
/* @__PURE__ */ jsx("div", { className: "w-1.5 h-1.5 bg-amber-400 rounded-full" }),
|
|
53945
54470
|
"Passive"
|
|
53946
54471
|
] }),
|
|
53947
|
-
/* @__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) })
|
|
53948
54473
|
] })
|
|
53949
54474
|
] })
|
|
53950
54475
|
] }) : /* @__PURE__ */ jsx("div", { className: "text-gray-400 text-xs italic", children: "No data recorded" })
|
|
@@ -54075,15 +54600,7 @@ var UserManagementTable = ({
|
|
|
54075
54600
|
const permissions = useTeamManagementPermissions();
|
|
54076
54601
|
const { user: currentUser } = useAuth();
|
|
54077
54602
|
const availableRoles = useMemo(() => {
|
|
54078
|
-
|
|
54079
|
-
const roleHierarchy = {
|
|
54080
|
-
"optifye": ["optifye", "owner", "it", "plant_head", "supervisor"],
|
|
54081
|
-
"owner": ["owner", "it", "plant_head", "supervisor"],
|
|
54082
|
-
"it": ["it", "plant_head", "supervisor"],
|
|
54083
|
-
"plant_head": ["plant_head", "supervisor"],
|
|
54084
|
-
"supervisor": ["supervisor"]
|
|
54085
|
-
};
|
|
54086
|
-
return roleHierarchy[currentRole] || ["supervisor"];
|
|
54603
|
+
return getVisibleRolesForCurrentUser(currentUser?.role_level);
|
|
54087
54604
|
}, [currentUser]);
|
|
54088
54605
|
const [searchTerm, setSearchTerm] = useState("");
|
|
54089
54606
|
const [roleFilter, setRoleFilter] = useState("all");
|
|
@@ -54180,10 +54697,48 @@ var UserManagementTable = ({
|
|
|
54180
54697
|
}
|
|
54181
54698
|
return [];
|
|
54182
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
|
+
};
|
|
54183
54738
|
const formatAssignments = (user) => {
|
|
54184
54739
|
if (user.role_level === "owner" || user.role_level === "it") return "Company-wide";
|
|
54185
54740
|
if (user.role_level === "optifye") return "All companies";
|
|
54186
|
-
if (user.role_level
|
|
54741
|
+
if (isFactoryScopedRole(user.role_level)) {
|
|
54187
54742
|
if (user.assigned_factories && user.assigned_factories.length > 0) {
|
|
54188
54743
|
return user.assigned_factories.join(", ");
|
|
54189
54744
|
}
|
|
@@ -54264,11 +54819,12 @@ var UserManagementTable = ({
|
|
|
54264
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",
|
|
54265
54820
|
children: [
|
|
54266
54821
|
/* @__PURE__ */ jsx("option", { value: "all", children: "All Roles" }),
|
|
54267
|
-
availableRoles.includes("optifye") && /* @__PURE__ */ jsx("option", { value: "optifye", children: "
|
|
54268
|
-
availableRoles.includes("owner") && /* @__PURE__ */ jsx("option", { value: "owner", children: "
|
|
54269
|
-
availableRoles.includes("it") && /* @__PURE__ */ jsx("option", { value: "it", children: "
|
|
54270
|
-
availableRoles.includes("plant_head") && /* @__PURE__ */ jsx("option", { value: "plant_head", children: "
|
|
54271
|
-
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") })
|
|
54272
54828
|
]
|
|
54273
54829
|
}
|
|
54274
54830
|
)
|
|
@@ -54386,7 +54942,7 @@ var UserManagementTable = ({
|
|
|
54386
54942
|
onUpdate: onLineAssignmentUpdate || (async () => {
|
|
54387
54943
|
})
|
|
54388
54944
|
}
|
|
54389
|
-
) : user.role_level
|
|
54945
|
+
) : isFactoryScopedRole(user.role_level) ? (() => {
|
|
54390
54946
|
const canEditFactoryAssignments = permissions.canAssignFactories(user) && !!onFactoryAssignmentUpdate;
|
|
54391
54947
|
if (!canEditFactoryAssignments) {
|
|
54392
54948
|
return /* @__PURE__ */ jsx("p", { className: "text-sm text-gray-900", children: formatAssignments(user) });
|
|
@@ -54416,7 +54972,7 @@ var UserManagementTable = ({
|
|
|
54416
54972
|
setShowUsageDetailModal(true);
|
|
54417
54973
|
},
|
|
54418
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",
|
|
54419
|
-
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) })
|
|
54420
54976
|
}
|
|
54421
54977
|
) : /* @__PURE__ */ jsx("span", { className: "text-sm text-gray-400", children: "-" }) }),
|
|
54422
54978
|
/* @__PURE__ */ jsx("td", { className: "px-6 py-4 whitespace-nowrap text-right", children: hasActions && /* @__PURE__ */ jsx("div", { className: "relative", children: /* @__PURE__ */ jsx(
|
|
@@ -54566,7 +55122,7 @@ var UserManagementTable = ({
|
|
|
54566
55122
|
ChangeRoleDialog,
|
|
54567
55123
|
{
|
|
54568
55124
|
user: selectedUser,
|
|
54569
|
-
availableRoles:
|
|
55125
|
+
availableRoles: getAvailableRolesForUser(selectedUser),
|
|
54570
55126
|
onConfirm: handleRoleChangeConfirm,
|
|
54571
55127
|
onClose: () => {
|
|
54572
55128
|
setShowChangeRoleDialog(false);
|
|
@@ -56305,7 +56861,7 @@ function HomeView({
|
|
|
56305
56861
|
animate: { opacity: 1, scale: 1 },
|
|
56306
56862
|
transition: { duration: 0.3 },
|
|
56307
56863
|
className: "h-full",
|
|
56308
|
-
children:
|
|
56864
|
+
children: React141__default.createElement(WorkspaceGrid, {
|
|
56309
56865
|
workspaces: workspaceMetrics,
|
|
56310
56866
|
lineNames,
|
|
56311
56867
|
factoryView: factoryViewId,
|
|
@@ -56336,7 +56892,7 @@ function HomeView({
|
|
|
56336
56892
|
animate: { opacity: 1, scale: 1 },
|
|
56337
56893
|
transition: { duration: 0.3 },
|
|
56338
56894
|
className: "h-full",
|
|
56339
|
-
children:
|
|
56895
|
+
children: React141__default.createElement(WorkspaceGrid, {
|
|
56340
56896
|
workspaces: [],
|
|
56341
56897
|
// Show empty grid while loading
|
|
56342
56898
|
lineNames,
|
|
@@ -56403,7 +56959,7 @@ function HomeView({
|
|
|
56403
56959
|
}
|
|
56404
56960
|
);
|
|
56405
56961
|
}
|
|
56406
|
-
var AuthenticatedHomeView = withAuth(
|
|
56962
|
+
var AuthenticatedHomeView = withAuth(React141__default.memo(HomeView));
|
|
56407
56963
|
var HomeView_default = HomeView;
|
|
56408
56964
|
function withWorkspaceDisplayNames(Component3, options = {}) {
|
|
56409
56965
|
const {
|
|
@@ -56813,7 +57369,7 @@ var MonthlyRangeFilter = ({
|
|
|
56813
57369
|
label: "This Month",
|
|
56814
57370
|
getValue: () => ({
|
|
56815
57371
|
start: startOfMonth(/* @__PURE__ */ new Date()),
|
|
56816
|
-
end:
|
|
57372
|
+
end: endOfDay(/* @__PURE__ */ new Date())
|
|
56817
57373
|
})
|
|
56818
57374
|
}
|
|
56819
57375
|
];
|
|
@@ -56837,6 +57393,7 @@ var MonthlyRangeFilter = ({
|
|
|
56837
57393
|
const [rangeEnd, setRangeEnd] = useState(parseDateKeyToDate(normalizedRange.endKey));
|
|
56838
57394
|
const [selecting, setSelecting] = useState(false);
|
|
56839
57395
|
const [activePreset, setActivePreset] = useState(null);
|
|
57396
|
+
const today = useMemo(() => endOfDay(/* @__PURE__ */ new Date()), []);
|
|
56840
57397
|
useEffect(() => {
|
|
56841
57398
|
setCalendarMonth(month);
|
|
56842
57399
|
setCalendarYear(year);
|
|
@@ -56867,6 +57424,9 @@ var MonthlyRangeFilter = ({
|
|
|
56867
57424
|
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
56868
57425
|
}, []);
|
|
56869
57426
|
const handleDayClick = (day) => {
|
|
57427
|
+
if (startOfDay(day) > startOfDay(today)) {
|
|
57428
|
+
return;
|
|
57429
|
+
}
|
|
56870
57430
|
setActivePreset("Custom");
|
|
56871
57431
|
if (!selecting || !rangeStart) {
|
|
56872
57432
|
setRangeStart(day);
|
|
@@ -56899,9 +57459,13 @@ var MonthlyRangeFilter = ({
|
|
|
56899
57459
|
};
|
|
56900
57460
|
const handleApply = () => {
|
|
56901
57461
|
if (rangeStart) {
|
|
56902
|
-
const
|
|
56903
|
-
const
|
|
56904
|
-
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");
|
|
56905
57469
|
onChange({ startKey, endKey });
|
|
56906
57470
|
setIsOpen(false);
|
|
56907
57471
|
}
|
|
@@ -57082,6 +57646,7 @@ var MonthlyRangeFilter = ({
|
|
|
57082
57646
|
const isEnd = isRangeEnd(day);
|
|
57083
57647
|
const isSingleDaySelection = isStart && (!rangeEnd || rangeEnd && isSameDay(rangeStart, rangeEnd));
|
|
57084
57648
|
const dayNum = day.getDate();
|
|
57649
|
+
const isFutureDay = startOfDay(day) > startOfDay(today);
|
|
57085
57650
|
return /* @__PURE__ */ jsxs("div", { className: "relative", children: [
|
|
57086
57651
|
inRange && !isStart && !isEnd && /* @__PURE__ */ jsx("div", { className: "absolute inset-y-0 -inset-x-0.5 bg-[#EEF2FF] z-0" }),
|
|
57087
57652
|
inRange && isStart && !isSingleDaySelection && /* @__PURE__ */ jsx("div", { className: "absolute inset-y-0 right-0 left-1/2 bg-[#EEF2FF] z-0" }),
|
|
@@ -57091,10 +57656,12 @@ var MonthlyRangeFilter = ({
|
|
|
57091
57656
|
{
|
|
57092
57657
|
type: "button",
|
|
57093
57658
|
onClick: () => handleDayClick(day),
|
|
57659
|
+
disabled: isFutureDay,
|
|
57094
57660
|
className: clsx(
|
|
57095
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",
|
|
57096
57663
|
// Not in range
|
|
57097
|
-
!inRange && "text-gray-700 hover:bg-gray-50 rounded-lg",
|
|
57664
|
+
!isFutureDay && !inRange && "text-gray-700 hover:bg-gray-50 rounded-lg",
|
|
57098
57665
|
// Middle of range
|
|
57099
57666
|
inRange && !isStart && !isEnd && "text-[#4F46E5]",
|
|
57100
57667
|
// Start/End of range or Single selection
|
|
@@ -57132,7 +57699,7 @@ var MetricCards = memo$1(({
|
|
|
57132
57699
|
variants: containerVariants,
|
|
57133
57700
|
initial: "initial",
|
|
57134
57701
|
animate: "animate",
|
|
57135
|
-
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]`,
|
|
57136
57703
|
children: [
|
|
57137
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: [
|
|
57138
57705
|
/* @__PURE__ */ jsx("h2", { className: "text-sm sm:text-base font-bold text-gray-700 mb-2 text-center", children: "Line Output" }),
|
|
@@ -57181,7 +57748,23 @@ var MetricCards = memo$1(({
|
|
|
57181
57748
|
if (prevProps.efficiencyLegend !== nextProps.efficiencyLegend) return false;
|
|
57182
57749
|
const prevMetrics = prevProps.lineInfo.metrics;
|
|
57183
57750
|
const nextMetrics = nextProps.lineInfo.metrics;
|
|
57184
|
-
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;
|
|
57185
57768
|
if (idleTimeChanged) return false;
|
|
57186
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;
|
|
57187
57770
|
});
|
|
@@ -57200,7 +57783,7 @@ var LineUptimeMetricCards = memo$1(({
|
|
|
57200
57783
|
variants: containerVariants,
|
|
57201
57784
|
initial: "initial",
|
|
57202
57785
|
animate: "animate",
|
|
57203
|
-
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]`,
|
|
57204
57787
|
children: [
|
|
57205
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: [
|
|
57206
57789
|
/* @__PURE__ */ jsx("h2", { className: "text-sm sm:text-base font-bold text-gray-700 mb-2 text-center", children: "Utilization" }),
|
|
@@ -57268,7 +57851,7 @@ var BottomSection = memo$1(({
|
|
|
57268
57851
|
variants: containerVariants,
|
|
57269
57852
|
initial: "initial",
|
|
57270
57853
|
animate: "animate",
|
|
57271
|
-
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]",
|
|
57272
57855
|
children: [
|
|
57273
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: [
|
|
57274
57857
|
/* @__PURE__ */ jsxs("div", { className: "flex justify-between items-center mb-2", children: [
|
|
@@ -57435,7 +58018,7 @@ var UptimeBottomSection = memo$1(({
|
|
|
57435
58018
|
variants: containerVariants,
|
|
57436
58019
|
initial: "initial",
|
|
57437
58020
|
animate: "animate",
|
|
57438
|
-
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]",
|
|
57439
58022
|
children: [
|
|
57440
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: [
|
|
57441
58024
|
/* @__PURE__ */ jsxs("div", { className: "flex justify-between items-center mb-2", children: [
|
|
@@ -58673,7 +59256,7 @@ var KPIDetailView = ({
|
|
|
58673
59256
|
initial: "initial",
|
|
58674
59257
|
animate: "animate",
|
|
58675
59258
|
exit: "exit",
|
|
58676
|
-
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",
|
|
58677
59260
|
children: resolvedLineInfo && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
58678
59261
|
isUptimeMode ? /* @__PURE__ */ jsx(
|
|
58679
59262
|
LineUptimeMetricCards,
|
|
@@ -58770,7 +59353,7 @@ var KPIDetailView = ({
|
|
|
58770
59353
|
initial: "initial",
|
|
58771
59354
|
animate: "animate",
|
|
58772
59355
|
exit: "exit",
|
|
58773
|
-
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",
|
|
58774
59357
|
children: resolvedLineInfo && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
58775
59358
|
isUptimeMode ? /* @__PURE__ */ jsx(
|
|
58776
59359
|
LineUptimeMetricCards,
|
|
@@ -58865,7 +59448,7 @@ var getMonthDateInfo = (timezone) => {
|
|
|
58865
59448
|
const monthEndDate = fromZonedTime(`${monthEndKey}T23:59:59`, timezone);
|
|
58866
59449
|
return { startDate, endDate, monthEndDate };
|
|
58867
59450
|
};
|
|
58868
|
-
var LeaderboardCountdown = ({ targetDate, format:
|
|
59451
|
+
var LeaderboardCountdown = ({ targetDate, format: format8, finishedLabel = "Finished", placeholder = "--", onFinished }) => {
|
|
58869
59452
|
const [time2, setTime] = useState("");
|
|
58870
59453
|
const hasFinishedRef = useRef(false);
|
|
58871
59454
|
useEffect(() => {
|
|
@@ -58887,7 +59470,7 @@ var LeaderboardCountdown = ({ targetDate, format: format7, finishedLabel = "Fini
|
|
|
58887
59470
|
}
|
|
58888
59471
|
return;
|
|
58889
59472
|
}
|
|
58890
|
-
if (
|
|
59473
|
+
if (format8 === "days") {
|
|
58891
59474
|
const days = Math.floor(diff / (1e3 * 60 * 60 * 24));
|
|
58892
59475
|
const hours = Math.floor(diff % (1e3 * 60 * 60 * 24) / (1e3 * 60 * 60));
|
|
58893
59476
|
setTime(`${days} days ${hours} hours`);
|
|
@@ -58902,7 +59485,7 @@ var LeaderboardCountdown = ({ targetDate, format: format7, finishedLabel = "Fini
|
|
|
58902
59485
|
tick();
|
|
58903
59486
|
const interval = setInterval(tick, 1e3);
|
|
58904
59487
|
return () => clearInterval(interval);
|
|
58905
|
-
}, [targetDate,
|
|
59488
|
+
}, [targetDate, format8, finishedLabel, placeholder, onFinished]);
|
|
58906
59489
|
return /* @__PURE__ */ jsx(Fragment, { children: time2 });
|
|
58907
59490
|
};
|
|
58908
59491
|
var LinesLeaderboard = ({
|
|
@@ -58923,18 +59506,18 @@ var LinesLeaderboard = ({
|
|
|
58923
59506
|
setViewType
|
|
58924
59507
|
}) => {
|
|
58925
59508
|
const formatEfficiency = (value) => typeof value === "number" && Number.isFinite(value) ? `${value.toFixed(1)}%` : "--";
|
|
58926
|
-
const assignedLineIdSet =
|
|
59509
|
+
const assignedLineIdSet = React141__default.useMemo(
|
|
58927
59510
|
() => new Set(assignedLineIds || []),
|
|
58928
59511
|
[assignedLineIds]
|
|
58929
59512
|
);
|
|
58930
|
-
const canClickLine =
|
|
59513
|
+
const canClickLine = React141__default.useCallback(
|
|
58931
59514
|
(lineId) => {
|
|
58932
59515
|
if (!assignedLineIds) return true;
|
|
58933
59516
|
return assignedLineIdSet.has(lineId);
|
|
58934
59517
|
},
|
|
58935
59518
|
[assignedLineIds, assignedLineIdSet]
|
|
58936
59519
|
);
|
|
58937
|
-
const handleTimeRangeChange =
|
|
59520
|
+
const handleTimeRangeChange = React141__default.useCallback((newRange) => {
|
|
58938
59521
|
if (newRange === timeRange) return;
|
|
58939
59522
|
trackCoreEvent("Leaderboard Time Range Changed", {
|
|
58940
59523
|
from_range: timeRange,
|
|
@@ -58945,7 +59528,7 @@ var LinesLeaderboard = ({
|
|
|
58945
59528
|
});
|
|
58946
59529
|
setTimeRange(newRange);
|
|
58947
59530
|
}, [timeRange, lines.length, monthlyEfficiencyByLineId, setTimeRange]);
|
|
58948
|
-
const handleLeaderboardLineClick =
|
|
59531
|
+
const handleLeaderboardLineClick = React141__default.useCallback((item, clickSource) => {
|
|
58949
59532
|
if (!canClickLine(item.line.id)) return;
|
|
58950
59533
|
trackCoreEvent("Leaderboard Line Clicked", {
|
|
58951
59534
|
line_id: item.line.id,
|
|
@@ -58959,8 +59542,8 @@ var LinesLeaderboard = ({
|
|
|
58959
59542
|
});
|
|
58960
59543
|
onLineClick(item.line);
|
|
58961
59544
|
}, [canClickLine, onLineClick, timeRange]);
|
|
58962
|
-
const viewLoadedTrackedRef =
|
|
58963
|
-
const leaderboardData =
|
|
59545
|
+
const viewLoadedTrackedRef = React141__default.useRef(null);
|
|
59546
|
+
const leaderboardData = React141__default.useMemo(() => {
|
|
58964
59547
|
const loading = timeRange === "today" ? isLoadingToday : isLoadingMonthly;
|
|
58965
59548
|
const efficiencyMap = timeRange === "today" ? todayEfficiencyByLineId : monthlyEfficiencyByLineId;
|
|
58966
59549
|
return lines.map((line) => {
|
|
@@ -58991,7 +59574,7 @@ var LinesLeaderboard = ({
|
|
|
58991
59574
|
isLoadingToday,
|
|
58992
59575
|
isLoadingMonthly
|
|
58993
59576
|
]);
|
|
58994
|
-
|
|
59577
|
+
React141__default.useEffect(() => {
|
|
58995
59578
|
const isLoading = timeRange === "today" ? isLoadingToday : isLoadingMonthly;
|
|
58996
59579
|
const trackingKey = `${timeRange}-${leaderboardData.length}`;
|
|
58997
59580
|
if (leaderboardData.length > 0 && !isLoading && viewLoadedTrackedRef.current !== trackingKey) {
|
|
@@ -59017,7 +59600,7 @@ var LinesLeaderboard = ({
|
|
|
59017
59600
|
const countdownTarget = timeRange === "monthly" ? monthEndDate : shiftEndDate;
|
|
59018
59601
|
const countdownFormat = timeRange === "monthly" ? "days" : "clock";
|
|
59019
59602
|
const countdownFinishedLabel = timeRange === "monthly" ? "Finished" : "Shift Ended";
|
|
59020
|
-
const handleCountdownFinished =
|
|
59603
|
+
const handleCountdownFinished = React141__default.useCallback(() => {
|
|
59021
59604
|
trackCoreEvent("Leaderboard Countdown Finished", {
|
|
59022
59605
|
countdown_type: timeRange === "monthly" ? "month_end" : "shift_end",
|
|
59023
59606
|
time_range: timeRange,
|
|
@@ -59044,7 +59627,7 @@ var LinesLeaderboard = ({
|
|
|
59044
59627
|
return "bg-white border-gray-100";
|
|
59045
59628
|
}
|
|
59046
59629
|
};
|
|
59047
|
-
|
|
59630
|
+
React141__default.useEffect(() => {
|
|
59048
59631
|
const style = document.createElement("style");
|
|
59049
59632
|
style.innerHTML = `
|
|
59050
59633
|
@keyframes float {
|
|
@@ -59231,7 +59814,7 @@ var LineCard = ({
|
|
|
59231
59814
|
supervisors
|
|
59232
59815
|
}) => {
|
|
59233
59816
|
const isUptimeLine = (line.monitoring_mode ?? "output") === "uptime";
|
|
59234
|
-
const isOnTrack =
|
|
59817
|
+
const isOnTrack = React141__default.useMemo(() => {
|
|
59235
59818
|
if (!kpis) return null;
|
|
59236
59819
|
return isEfficiencyOnTrack(kpis.efficiency.value);
|
|
59237
59820
|
}, [kpis]);
|
|
@@ -59422,46 +60005,46 @@ var KPIsOverviewView = ({
|
|
|
59422
60005
|
const configuredTimezone = dbTimezone || dateTimeConfig.defaultTimezone || "UTC";
|
|
59423
60006
|
const { startDate: monthStartDate, endDate: monthEndDateKey, monthEndDate } = getMonthDateInfo(configuredTimezone);
|
|
59424
60007
|
const isSuperAdmin = user?.scope_mode === "SUPER_ADMIN" || !!user?.access_scope?.is_super_admin;
|
|
59425
|
-
const scopedLineIds =
|
|
60008
|
+
const scopedLineIds = React141__default.useMemo(
|
|
59426
60009
|
() => Array.isArray(user?.access_scope?.line_ids) ? user.access_scope.line_ids.filter((lineId) => typeof lineId === "string" && lineId.length > 0) : [],
|
|
59427
60010
|
[user?.access_scope?.line_ids]
|
|
59428
60011
|
);
|
|
59429
60012
|
const hasCanonicalScope = !!user?.scope_mode || !!user?.access_scope;
|
|
59430
60013
|
const scopeRole = (user?.role_level || user?.role || "").toLowerCase();
|
|
59431
|
-
const isStrictLineScopedRole = scopeRole === "supervisor" || scopeRole
|
|
59432
|
-
const resolvedAssignedLineIds =
|
|
60014
|
+
const isStrictLineScopedRole = scopeRole === "supervisor" || isFactoryScopedRole(scopeRole);
|
|
60015
|
+
const resolvedAssignedLineIds = React141__default.useMemo(() => {
|
|
59433
60016
|
if (isSuperAdmin) return [];
|
|
59434
60017
|
if (scopedLineIds.length > 0) return scopedLineIds;
|
|
59435
60018
|
if (lineIds && lineIds.length > 0) return lineIds;
|
|
59436
60019
|
if (isStrictLineScopedRole && hasCanonicalScope) return [];
|
|
59437
60020
|
return [];
|
|
59438
60021
|
}, [isSuperAdmin, scopedLineIds, lineIds, isStrictLineScopedRole, hasCanonicalScope]);
|
|
59439
|
-
const assignedLineIdSet =
|
|
60022
|
+
const assignedLineIdSet = React141__default.useMemo(
|
|
59440
60023
|
() => new Set(resolvedAssignedLineIds),
|
|
59441
60024
|
[resolvedAssignedLineIds]
|
|
59442
60025
|
);
|
|
59443
|
-
const metricsLineIds =
|
|
60026
|
+
const metricsLineIds = React141__default.useMemo(() => {
|
|
59444
60027
|
if (isSuperAdmin) {
|
|
59445
60028
|
return lineIds ?? [];
|
|
59446
60029
|
}
|
|
59447
60030
|
return resolvedAssignedLineIds;
|
|
59448
60031
|
}, [isSuperAdmin, lineIds, resolvedAssignedLineIds]);
|
|
59449
60032
|
const assignedLineIdsForLeaderboard = isSuperAdmin ? void 0 : resolvedAssignedLineIds;
|
|
59450
|
-
const leaderboardLinesForView =
|
|
60033
|
+
const leaderboardLinesForView = React141__default.useMemo(() => {
|
|
59451
60034
|
const targetMode = viewType === "machine" ? "uptime" : "output";
|
|
59452
60035
|
return leaderboardLines.filter((line) => (line.monitoring_mode ?? "output") === targetMode);
|
|
59453
60036
|
}, [leaderboardLines, viewType]);
|
|
59454
|
-
const linesForView =
|
|
60037
|
+
const linesForView = React141__default.useMemo(() => {
|
|
59455
60038
|
const targetMode = viewType === "machine" ? "uptime" : "output";
|
|
59456
60039
|
return lines.filter((line) => (line.monitoring_mode ?? "output") === targetMode);
|
|
59457
60040
|
}, [lines, viewType]);
|
|
59458
|
-
const relevantLinesForMode =
|
|
60041
|
+
const relevantLinesForMode = React141__default.useMemo(() => {
|
|
59459
60042
|
if (activeTab === "leaderboard") {
|
|
59460
60043
|
return leaderboardLines.length > 0 ? leaderboardLines : lines;
|
|
59461
60044
|
}
|
|
59462
60045
|
return lines;
|
|
59463
60046
|
}, [activeTab, leaderboardLines, lines]);
|
|
59464
|
-
const { hasUptime, hasOutput } =
|
|
60047
|
+
const { hasUptime, hasOutput } = React141__default.useMemo(() => {
|
|
59465
60048
|
let uptime = false;
|
|
59466
60049
|
let output = false;
|
|
59467
60050
|
for (const line of relevantLinesForMode) {
|
|
@@ -59486,7 +60069,7 @@ var KPIsOverviewView = ({
|
|
|
59486
60069
|
const currentShiftDetails = getCurrentShift(configuredTimezone, shiftConfig);
|
|
59487
60070
|
const currentShiftDate = currentShiftDetails.date;
|
|
59488
60071
|
const currentShiftId = currentShiftDetails.shiftId;
|
|
59489
|
-
const shiftEndDate =
|
|
60072
|
+
const shiftEndDate = React141__default.useMemo(
|
|
59490
60073
|
() => getShiftEndDate(currentShiftDetails, configuredTimezone),
|
|
59491
60074
|
[currentShiftDetails, configuredTimezone]
|
|
59492
60075
|
);
|
|
@@ -59500,15 +60083,15 @@ var KPIsOverviewView = ({
|
|
|
59500
60083
|
lineId: factoryViewId,
|
|
59501
60084
|
userAccessibleLineIds: metricsLineIds
|
|
59502
60085
|
});
|
|
59503
|
-
const defaultKPIs =
|
|
59504
|
-
const kpisByLineId =
|
|
60086
|
+
const defaultKPIs = React141__default.useMemo(() => createDefaultKPIs(), []);
|
|
60087
|
+
const kpisByLineId = React141__default.useMemo(() => {
|
|
59505
60088
|
const map = /* @__PURE__ */ new Map();
|
|
59506
60089
|
lineMetrics.forEach((row) => {
|
|
59507
60090
|
if (row?.line_id) map.set(row.line_id, buildKPIsFromLineMetricsRow(row));
|
|
59508
60091
|
});
|
|
59509
60092
|
return map;
|
|
59510
60093
|
}, [lineMetrics]);
|
|
59511
|
-
const supervisorLineIds =
|
|
60094
|
+
const supervisorLineIds = React141__default.useMemo(
|
|
59512
60095
|
() => (leaderboardLines.length > 0 ? leaderboardLines : lines).map((l) => l.id),
|
|
59513
60096
|
[leaderboardLines, lines]
|
|
59514
60097
|
);
|
|
@@ -60470,7 +61053,7 @@ var LeaderboardDetailView = memo$1(({
|
|
|
60470
61053
|
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
60471
61054
|
}, []);
|
|
60472
61055
|
const [isMobile, setIsMobile] = useState(false);
|
|
60473
|
-
|
|
61056
|
+
React141__default.useEffect(() => {
|
|
60474
61057
|
const checkMobile = () => setIsMobile(window.innerWidth < 640);
|
|
60475
61058
|
checkMobile();
|
|
60476
61059
|
window.addEventListener("resize", checkMobile);
|
|
@@ -62729,7 +63312,7 @@ var ShiftsView = ({
|
|
|
62729
63312
|
] })
|
|
62730
63313
|
] });
|
|
62731
63314
|
};
|
|
62732
|
-
var AuthenticatedShiftsView = withAuth(
|
|
63315
|
+
var AuthenticatedShiftsView = withAuth(React141__default.memo(ShiftsView));
|
|
62733
63316
|
var ShiftsView_default = ShiftsView;
|
|
62734
63317
|
|
|
62735
63318
|
// src/views/TargetsView.utils.ts
|
|
@@ -64419,7 +65002,7 @@ var TargetsView = ({
|
|
|
64419
65002
|
};
|
|
64420
65003
|
var TargetsViewWithDisplayNames = withAllWorkspaceDisplayNames(TargetsView);
|
|
64421
65004
|
var TargetsView_default = TargetsViewWithDisplayNames;
|
|
64422
|
-
var AuthenticatedTargetsView = withAuth(
|
|
65005
|
+
var AuthenticatedTargetsView = withAuth(React141__default.memo(TargetsViewWithDisplayNames));
|
|
64423
65006
|
|
|
64424
65007
|
// src/views/workspace-detail-view.utils.ts
|
|
64425
65008
|
var formatDateInTimezone = (date = /* @__PURE__ */ new Date(), timezone, options) => {
|
|
@@ -64473,25 +65056,6 @@ var getInitialTab = (sourceType, defaultTab, fromMonthly, urlDate) => {
|
|
|
64473
65056
|
return "overview";
|
|
64474
65057
|
};
|
|
64475
65058
|
var DEBUG_DASHBOARD2 = process.env.NEXT_PUBLIC_DEBUG_DASHBOARD === "true";
|
|
64476
|
-
var SHORT_DESKTOP_QUERY = "(min-width: 1024px) and (max-height: 850px)";
|
|
64477
|
-
var useMediaQuery = (query) => {
|
|
64478
|
-
const [matches, setMatches] = useState(false);
|
|
64479
|
-
useEffect(() => {
|
|
64480
|
-
if (typeof window === "undefined" || !window.matchMedia) {
|
|
64481
|
-
return;
|
|
64482
|
-
}
|
|
64483
|
-
const mediaQueryList = window.matchMedia(query);
|
|
64484
|
-
const onChange = () => setMatches(mediaQueryList.matches);
|
|
64485
|
-
onChange();
|
|
64486
|
-
if (typeof mediaQueryList.addEventListener === "function") {
|
|
64487
|
-
mediaQueryList.addEventListener("change", onChange);
|
|
64488
|
-
return () => mediaQueryList.removeEventListener("change", onChange);
|
|
64489
|
-
}
|
|
64490
|
-
mediaQueryList.addListener(onChange);
|
|
64491
|
-
return () => mediaQueryList.removeListener(onChange);
|
|
64492
|
-
}, [query]);
|
|
64493
|
-
return matches;
|
|
64494
|
-
};
|
|
64495
65059
|
var chartCardVariants = {
|
|
64496
65060
|
initial: { opacity: 0, y: 10 },
|
|
64497
65061
|
animate: {
|
|
@@ -64569,9 +65133,8 @@ var WorkspaceDetailView = ({
|
|
|
64569
65133
|
const [usingFallbackData, setUsingFallbackData] = useState(false);
|
|
64570
65134
|
const { isIdleTimeVlmEnabled } = useIdleTimeVlmConfig();
|
|
64571
65135
|
const [showChartIdleTime, setShowChartIdleTime] = useState(false);
|
|
64572
|
-
const
|
|
64573
|
-
const
|
|
64574
|
-
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";
|
|
64575
65138
|
const dashboardConfig = useDashboardConfig();
|
|
64576
65139
|
const { legend: efficiencyLegend } = useEfficiencyLegend();
|
|
64577
65140
|
const prewarmedClipsRef = useRef(/* @__PURE__ */ new Set());
|
|
@@ -65159,19 +65722,13 @@ var WorkspaceDetailView = ({
|
|
|
65159
65722
|
shiftId: idleClipShiftId,
|
|
65160
65723
|
enabled: idleClipFetchEnabled
|
|
65161
65724
|
});
|
|
65162
|
-
const
|
|
65725
|
+
const fallbackReturnUrl = returnUrl || "/";
|
|
65726
|
+
const appendReturnUrl = useCallback((params) => {
|
|
65163
65727
|
if (returnUrl) {
|
|
65164
|
-
|
|
65165
|
-
onNavigate(returnUrl);
|
|
65166
|
-
}
|
|
65167
|
-
return;
|
|
65168
|
-
}
|
|
65169
|
-
if (activeTab === "monthly_history") {
|
|
65170
|
-
if (onNavigate) {
|
|
65171
|
-
onNavigate("/");
|
|
65172
|
-
}
|
|
65173
|
-
return;
|
|
65728
|
+
params.set("returnTo", returnUrl);
|
|
65174
65729
|
}
|
|
65730
|
+
}, [returnUrl]);
|
|
65731
|
+
const handleBackNavigation = () => {
|
|
65175
65732
|
if (date || shift) {
|
|
65176
65733
|
setActiveTab("monthly_history");
|
|
65177
65734
|
if (onNavigate) {
|
|
@@ -65185,8 +65742,22 @@ var WorkspaceDetailView = ({
|
|
|
65185
65742
|
if (effectiveLineId) {
|
|
65186
65743
|
params.set("lineId", effectiveLineId);
|
|
65187
65744
|
}
|
|
65745
|
+
appendReturnUrl(params);
|
|
65188
65746
|
onNavigate(`/workspace/${workspaceId}?${params.toString()}`);
|
|
65189
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;
|
|
65190
65761
|
} else {
|
|
65191
65762
|
if (previousView === "line_monthly_history") {
|
|
65192
65763
|
setActiveTab("monthly_history");
|
|
@@ -65201,11 +65772,12 @@ var WorkspaceDetailView = ({
|
|
|
65201
65772
|
if (effectiveLineId) {
|
|
65202
65773
|
params.set("lineId", effectiveLineId);
|
|
65203
65774
|
}
|
|
65775
|
+
appendReturnUrl(params);
|
|
65204
65776
|
onNavigate(`/workspace/${workspaceId}?${params.toString()}`);
|
|
65205
65777
|
}
|
|
65206
65778
|
} else {
|
|
65207
65779
|
if (onNavigate) {
|
|
65208
|
-
onNavigate(
|
|
65780
|
+
onNavigate(fallbackReturnUrl);
|
|
65209
65781
|
}
|
|
65210
65782
|
}
|
|
65211
65783
|
}
|
|
@@ -65264,7 +65836,7 @@ var WorkspaceDetailView = ({
|
|
|
65264
65836
|
/* @__PURE__ */ jsx(
|
|
65265
65837
|
BackButton,
|
|
65266
65838
|
{
|
|
65267
|
-
onClick: () => onNavigate && onNavigate(
|
|
65839
|
+
onClick: () => onNavigate && onNavigate(fallbackReturnUrl),
|
|
65268
65840
|
text: "Return to Dashboard",
|
|
65269
65841
|
size: "default",
|
|
65270
65842
|
"aria-label": "Return to dashboard"
|
|
@@ -65278,7 +65850,7 @@ var WorkspaceDetailView = ({
|
|
|
65278
65850
|
/* @__PURE__ */ jsx(
|
|
65279
65851
|
BackButton,
|
|
65280
65852
|
{
|
|
65281
|
-
onClick: () => onNavigate && onNavigate(
|
|
65853
|
+
onClick: () => onNavigate && onNavigate(fallbackReturnUrl),
|
|
65282
65854
|
text: "Return to Dashboard",
|
|
65283
65855
|
size: "default",
|
|
65284
65856
|
"aria-label": "Return to dashboard"
|
|
@@ -65549,7 +66121,7 @@ var WorkspaceDetailView = ({
|
|
|
65549
66121
|
] })
|
|
65550
66122
|
] }),
|
|
65551
66123
|
/* @__PURE__ */ jsxs("div", { className: "flex-grow p-1.5 sm:p-2 lg:p-4", children: [
|
|
65552
|
-
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: [
|
|
65553
66125
|
/* @__PURE__ */ jsxs("div", { className: "block lg:hidden space-y-6 pb-6", children: [
|
|
65554
66126
|
!shouldShowCycleTimeChart && !isUptimeMode && /* @__PURE__ */ jsxs(
|
|
65555
66127
|
motion.div,
|
|
@@ -65891,6 +66463,7 @@ var WorkspaceDetailView = ({
|
|
|
65891
66463
|
if (effectiveLineId) {
|
|
65892
66464
|
params.set("lineId", effectiveLineId);
|
|
65893
66465
|
}
|
|
66466
|
+
appendReturnUrl(params);
|
|
65894
66467
|
onNavigate(`/workspace/${workspaceId}?${params.toString()}`);
|
|
65895
66468
|
}
|
|
65896
66469
|
},
|
|
@@ -66251,7 +66824,7 @@ var formatTime4 = (date, timezone) => new Intl.DateTimeFormat("en-IN", {
|
|
|
66251
66824
|
hour12: true,
|
|
66252
66825
|
timeZone: timezone
|
|
66253
66826
|
}).format(date);
|
|
66254
|
-
var
|
|
66827
|
+
var formatDuration3 = (minutes) => {
|
|
66255
66828
|
if (minutes < 1) return "<1 min";
|
|
66256
66829
|
if (minutes < 60) return `${minutes} min`;
|
|
66257
66830
|
const hours = Math.floor(minutes / 60);
|
|
@@ -66364,7 +66937,7 @@ var UptimeTimelineStrip = ({
|
|
|
66364
66937
|
if (segment.length > 1) {
|
|
66365
66938
|
endDate.setMinutes(endDate.getMinutes() + 1);
|
|
66366
66939
|
}
|
|
66367
|
-
const tooltip = `${STATUS_TITLES[segment.status]} \u2022 ${
|
|
66940
|
+
const tooltip = `${STATUS_TITLES[segment.status]} \u2022 ${formatDuration3(segment.length)} (${formatTime4(
|
|
66368
66941
|
startDate,
|
|
66369
66942
|
timezone
|
|
66370
66943
|
)} - ${formatTime4(endDate, timezone)})`;
|
|
@@ -66397,7 +66970,7 @@ var UptimeTimelineStrip = ({
|
|
|
66397
66970
|
};
|
|
66398
66971
|
var UptimeTimelineStrip_default = UptimeTimelineStrip;
|
|
66399
66972
|
var SHORT_INTERRUPT_THRESHOLD_MINUTES = 3;
|
|
66400
|
-
var
|
|
66973
|
+
var formatDuration4 = (minutes) => {
|
|
66401
66974
|
if (!minutes || minutes <= 0) return "0 min";
|
|
66402
66975
|
const rounded = Math.max(Math.round(minutes), 0);
|
|
66403
66976
|
const days = Math.floor(rounded / 1440);
|
|
@@ -66416,7 +66989,7 @@ var formatDowntimeLabel2 = (minutes, includeSuffix = true) => {
|
|
|
66416
66989
|
if (!minutes || minutes <= 0) {
|
|
66417
66990
|
return includeSuffix ? "No downtime" : "0 min";
|
|
66418
66991
|
}
|
|
66419
|
-
const label =
|
|
66992
|
+
const label = formatDuration4(minutes);
|
|
66420
66993
|
return includeSuffix ? `${label} down` : label;
|
|
66421
66994
|
};
|
|
66422
66995
|
var formatTimeRange = (start, end, timezone) => {
|
|
@@ -67172,6 +67745,7 @@ var TeamManagementView = ({
|
|
|
67172
67745
|
owners: 0,
|
|
67173
67746
|
it: 0,
|
|
67174
67747
|
plantHeads: 0,
|
|
67748
|
+
industrialEngineers: 0,
|
|
67175
67749
|
supervisors: 0,
|
|
67176
67750
|
optifye: 0
|
|
67177
67751
|
});
|
|
@@ -67185,8 +67759,8 @@ var TeamManagementView = ({
|
|
|
67185
67759
|
}
|
|
67186
67760
|
return [];
|
|
67187
67761
|
}, []);
|
|
67188
|
-
const
|
|
67189
|
-
if (user?.role_level
|
|
67762
|
+
const factoryScopedRoleFactoryIds = useMemo(() => {
|
|
67763
|
+
if (!isFactoryScopedRole(user?.role_level)) return [];
|
|
67190
67764
|
const scopedFactoryIds = normalizeIds(user?.access_scope?.factory_ids);
|
|
67191
67765
|
if (scopedFactoryIds.length > 0) {
|
|
67192
67766
|
return Array.from(new Set(scopedFactoryIds));
|
|
@@ -67204,8 +67778,8 @@ var TeamManagementView = ({
|
|
|
67204
67778
|
window.dispatchEvent(new Event("rbac:refresh-scope"));
|
|
67205
67779
|
}
|
|
67206
67780
|
}, []);
|
|
67207
|
-
const canAddUsers = user?.role_level
|
|
67208
|
-
const canViewUsageStats = user?.role_level
|
|
67781
|
+
const canAddUsers = canRoleManageUsers(user?.role_level);
|
|
67782
|
+
const canViewUsageStats = canRoleViewUsageStats(user?.role_level);
|
|
67209
67783
|
const pageCompanyId = entityConfig?.companyId || user?.properties?.company_id;
|
|
67210
67784
|
const companyIdForUsage = pageCompanyId;
|
|
67211
67785
|
const usageDateRange = useMemo(() => {
|
|
@@ -67239,8 +67813,8 @@ var TeamManagementView = ({
|
|
|
67239
67813
|
}, {});
|
|
67240
67814
|
}, [usageData, usageDateRange.daysElapsed]);
|
|
67241
67815
|
const pageTitle = "Team Management";
|
|
67242
|
-
const pageDescription =
|
|
67243
|
-
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;
|
|
67244
67818
|
const loadData = useCallback(async () => {
|
|
67245
67819
|
if (!supabase) {
|
|
67246
67820
|
setError("Supabase client not available. Please refresh the page.");
|
|
@@ -67287,8 +67861,8 @@ var TeamManagementView = ({
|
|
|
67287
67861
|
setAvailableFactories(factories || []);
|
|
67288
67862
|
setAvailableLines(lines);
|
|
67289
67863
|
console.log("[TeamManagementView] Company-scoped team view - Company:", companyId, "Loaded factories:", factories?.length, "lines:", lines?.length);
|
|
67290
|
-
} else if (user?.role_level
|
|
67291
|
-
if (
|
|
67864
|
+
} else if (isFactoryScopedRole(user?.role_level)) {
|
|
67865
|
+
if (factoryScopedRoleFactoryIds.length > 0) {
|
|
67292
67866
|
if (companyId) {
|
|
67293
67867
|
const linesResponse = await fetch(`${backendUrl}/api/lines?company_id=${companyId}`, {
|
|
67294
67868
|
headers: {
|
|
@@ -67301,9 +67875,9 @@ var TeamManagementView = ({
|
|
|
67301
67875
|
}
|
|
67302
67876
|
const linesData = await linesResponse.json();
|
|
67303
67877
|
const allLines = linesData.lines || [];
|
|
67304
|
-
const lines = allLines.filter((line) =>
|
|
67878
|
+
const lines = allLines.filter((line) => factoryScopedRoleFactoryIds.includes(line.factory_id));
|
|
67305
67879
|
setAvailableLines(lines);
|
|
67306
|
-
console.log("[TeamManagementView]
|
|
67880
|
+
console.log("[TeamManagementView] Factory-scoped team view - Factories:", factoryScopedRoleFactoryIds, "Loaded lines:", lines?.length);
|
|
67307
67881
|
}
|
|
67308
67882
|
} else if (entityConfig?.factoryId) {
|
|
67309
67883
|
const linesResponse = await fetch(`${backendUrl}/api/lines?factory_id=${entityConfig.factoryId}`, {
|
|
@@ -67340,12 +67914,12 @@ var TeamManagementView = ({
|
|
|
67340
67914
|
setAvailableFactories([]);
|
|
67341
67915
|
console.log("[TeamManagementView] Fallback - Company:", companyId, "Loaded lines:", lines?.length);
|
|
67342
67916
|
}
|
|
67343
|
-
const usersPromise = user?.role_level
|
|
67344
|
-
if (
|
|
67917
|
+
const usersPromise = isFactoryScopedRole(user?.role_level) ? (async () => {
|
|
67918
|
+
if (factoryScopedRoleFactoryIds.length === 0) {
|
|
67345
67919
|
return [];
|
|
67346
67920
|
}
|
|
67347
67921
|
const results = await Promise.allSettled(
|
|
67348
|
-
|
|
67922
|
+
factoryScopedRoleFactoryIds.map((factoryId) => userManagementService.getFactoryUsers(factoryId))
|
|
67349
67923
|
);
|
|
67350
67924
|
const successful = results.filter(
|
|
67351
67925
|
(result) => result.status === "fulfilled"
|
|
@@ -67377,6 +67951,7 @@ var TeamManagementView = ({
|
|
|
67377
67951
|
owners: userStats.owners,
|
|
67378
67952
|
it: userStats.it,
|
|
67379
67953
|
plantHeads: userStats.plant_heads,
|
|
67954
|
+
industrialEngineers: userStats.industrial_engineers,
|
|
67380
67955
|
supervisors: userStats.supervisors,
|
|
67381
67956
|
optifye: 0
|
|
67382
67957
|
});
|
|
@@ -67387,7 +67962,7 @@ var TeamManagementView = ({
|
|
|
67387
67962
|
} finally {
|
|
67388
67963
|
setIsLoading(false);
|
|
67389
67964
|
}
|
|
67390
|
-
}, [supabase, user, pageCompanyId, entityConfig?.factoryId,
|
|
67965
|
+
}, [supabase, user, pageCompanyId, entityConfig?.factoryId, factoryScopedRoleFactoryIds]);
|
|
67391
67966
|
useEffect(() => {
|
|
67392
67967
|
const companyId = pageCompanyId;
|
|
67393
67968
|
const canLoad = hasAccess && user && !!companyId;
|
|
@@ -67493,7 +68068,7 @@ var TeamManagementView = ({
|
|
|
67493
68068
|
{
|
|
67494
68069
|
iconType: AlertCircle,
|
|
67495
68070
|
title: "Access Denied",
|
|
67496
|
-
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.`
|
|
67497
68072
|
}
|
|
67498
68073
|
) });
|
|
67499
68074
|
}
|
|
@@ -67660,7 +68235,7 @@ function BottleneckClipsView({
|
|
|
67660
68235
|
) })
|
|
67661
68236
|
] }) });
|
|
67662
68237
|
}
|
|
67663
|
-
var AuthenticatedBottleneckClipsView = withAuth(
|
|
68238
|
+
var AuthenticatedBottleneckClipsView = withAuth(React141__default.memo(BottleneckClipsView));
|
|
67664
68239
|
var BottleneckClipsView_default = BottleneckClipsView;
|
|
67665
68240
|
|
|
67666
68241
|
// src/lib/services/ticketService.ts
|
|
@@ -68491,7 +69066,7 @@ Please ensure:
|
|
|
68491
69066
|
)
|
|
68492
69067
|
] });
|
|
68493
69068
|
}
|
|
68494
|
-
var AuthenticatedTicketsView = withAuth(
|
|
69069
|
+
var AuthenticatedTicketsView = withAuth(React141__default.memo(TicketsView));
|
|
68495
69070
|
var TicketsView_default = TicketsView;
|
|
68496
69071
|
|
|
68497
69072
|
// src/lib/api/s3-clips-parser.ts
|
|
@@ -68671,6 +69246,74 @@ var buildInitials = (name) => {
|
|
|
68671
69246
|
const second = parts.length > 1 ? parts[1]?.[0] || "" : "";
|
|
68672
69247
|
return `${first}${second}`.toUpperCase();
|
|
68673
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
|
+
};
|
|
68674
69317
|
var ClipVideoCarousel = ({ clips, clipsService }) => {
|
|
68675
69318
|
const [currentIndex, setCurrentIndex] = useState(0);
|
|
68676
69319
|
const [videos, setVideos] = useState([]);
|
|
@@ -69093,12 +69736,12 @@ var ImprovementCenterView = () => {
|
|
|
69093
69736
|
}, [user]);
|
|
69094
69737
|
const assignedFactoryIds = useMemo(() => {
|
|
69095
69738
|
if (!user) return [];
|
|
69096
|
-
if (user.role_level
|
|
69739
|
+
if (!isFactoryScopedRole(user.role_level)) return [];
|
|
69097
69740
|
const factories = user.properties?.factory_id || user.properties?.factory_ids || [];
|
|
69098
69741
|
return Array.isArray(factories) ? factories : [];
|
|
69099
69742
|
}, [user]);
|
|
69100
69743
|
const plantHeadLineIds = useMemo(() => {
|
|
69101
|
-
if (user?.role_level
|
|
69744
|
+
if (!isFactoryScopedRole(user?.role_level) || companyLines.length === 0) return [];
|
|
69102
69745
|
const factorySet = new Set(assignedFactoryIds);
|
|
69103
69746
|
return companyLines.filter((line) => line.factoryId === void 0 || line.factoryId === null || factorySet.has(line.factoryId)).map((line) => line.id);
|
|
69104
69747
|
}, [assignedFactoryIds, companyLines, user?.role_level]);
|
|
@@ -69106,7 +69749,7 @@ var ImprovementCenterView = () => {
|
|
|
69106
69749
|
if (user?.role_level === "supervisor") {
|
|
69107
69750
|
return assignedLineIds;
|
|
69108
69751
|
}
|
|
69109
|
-
if (user?.role_level
|
|
69752
|
+
if (isFactoryScopedRole(user?.role_level)) {
|
|
69110
69753
|
if (plantHeadLineIds.length > 0) return plantHeadLineIds;
|
|
69111
69754
|
return companyLineIds.length > 0 ? companyLineIds : configuredLineIds;
|
|
69112
69755
|
}
|
|
@@ -69129,6 +69772,21 @@ var ImprovementCenterView = () => {
|
|
|
69129
69772
|
return map;
|
|
69130
69773
|
}, [companyLines, configuredLines]);
|
|
69131
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]);
|
|
69132
69790
|
const clipsService = useMemo(() => {
|
|
69133
69791
|
try {
|
|
69134
69792
|
return new S3ClipsSupabaseService(dashboardConfig);
|
|
@@ -69142,24 +69800,42 @@ var ImprovementCenterView = () => {
|
|
|
69142
69800
|
if (!supabase || !companyId) return;
|
|
69143
69801
|
try {
|
|
69144
69802
|
const userService2 = createUserManagementService(supabase);
|
|
69145
|
-
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
|
+
);
|
|
69146
69818
|
if (cancelled) return;
|
|
69147
|
-
const
|
|
69819
|
+
const membersById = /* @__PURE__ */ new Map();
|
|
69820
|
+
users.forEach((user2) => {
|
|
69148
69821
|
const rawName = user2.first_name ? `${user2.first_name}${user2.last_name ? " " + user2.last_name : ""}` : user2.properties?.full_name || user2.email?.split("@")[0] || "Unknown";
|
|
69149
|
-
|
|
69150
|
-
|
|
69151
|
-
|
|
69152
|
-
|
|
69153
|
-
|
|
69154
|
-
|
|
69155
|
-
|
|
69156
|
-
|
|
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
|
+
}
|
|
69157
69832
|
});
|
|
69833
|
+
const members = Array.from(membersById.values());
|
|
69158
69834
|
members.sort((a, b) => a.name.localeCompare(b.name));
|
|
69159
69835
|
setTeamMembers(members);
|
|
69160
69836
|
} catch (error) {
|
|
69161
69837
|
if (!cancelled) {
|
|
69162
|
-
console.error("[ImprovementCenterView] Failed to load
|
|
69838
|
+
console.error("[ImprovementCenterView] Failed to load assignee members", error);
|
|
69163
69839
|
setTeamMembers([]);
|
|
69164
69840
|
}
|
|
69165
69841
|
}
|
|
@@ -69222,7 +69898,12 @@ var ImprovementCenterView = () => {
|
|
|
69222
69898
|
};
|
|
69223
69899
|
});
|
|
69224
69900
|
const allowed = new Set(scopeLineIds);
|
|
69225
|
-
|
|
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
|
+
]);
|
|
69226
69907
|
} catch (err) {
|
|
69227
69908
|
if (cancelled) return;
|
|
69228
69909
|
setLoadError(err?.message || "Failed to load recommendations");
|
|
@@ -69235,10 +69916,10 @@ var ImprovementCenterView = () => {
|
|
|
69235
69916
|
return () => {
|
|
69236
69917
|
cancelled = true;
|
|
69237
69918
|
};
|
|
69238
|
-
}, [supabase, companyId, scopeLineIdsKey]);
|
|
69919
|
+
}, [supabase, companyId, scopeLineIdsKey, lineNameById]);
|
|
69239
69920
|
const teamMembersById = useMemo(() => {
|
|
69240
|
-
return new Map(
|
|
69241
|
-
}, [
|
|
69921
|
+
return new Map(teamMembersWithIETeam.map((member) => [member.id, member]));
|
|
69922
|
+
}, [teamMembersWithIETeam]);
|
|
69242
69923
|
const filteredRecommendations = useMemo(() => {
|
|
69243
69924
|
return recommendations.filter((rec) => {
|
|
69244
69925
|
if (selectedLineId !== "all" && rec.line_id !== selectedLineId) return false;
|
|
@@ -69253,7 +69934,12 @@ var ImprovementCenterView = () => {
|
|
|
69253
69934
|
}
|
|
69254
69935
|
if (selectedMemberId !== "all" && !(rec.assigned_user_ids?.includes(selectedMemberId) || rec.assigned_to_user_id === selectedMemberId)) return false;
|
|
69255
69936
|
return true;
|
|
69256
|
-
}).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
|
+
});
|
|
69257
69943
|
}, [recommendations, selectedLineId, selectedStatus, selectedShift, selectedWeeksRange, selectedMemberId]);
|
|
69258
69944
|
const stats = useMemo(() => {
|
|
69259
69945
|
const baseFiltered = recommendations.filter((rec) => {
|
|
@@ -69351,7 +70037,7 @@ var ImprovementCenterView = () => {
|
|
|
69351
70037
|
setSelectedWeeksRange(weeksRange);
|
|
69352
70038
|
};
|
|
69353
70039
|
const handleMemberFilterChange = (memberId) => {
|
|
69354
|
-
const memberName = memberId === "all" ? "all" :
|
|
70040
|
+
const memberName = memberId === "all" ? "all" : teamMembersWithIETeam.find((member) => member.id === memberId)?.name || memberId;
|
|
69355
70041
|
trackCoreEvent("Improvement Center Filter Applied", {
|
|
69356
70042
|
filter_type: "member",
|
|
69357
70043
|
filter_value: memberName,
|
|
@@ -69433,7 +70119,7 @@ var ImprovementCenterView = () => {
|
|
|
69433
70119
|
/* @__PURE__ */ jsx("div", { className: "space-y-3", children: [
|
|
69434
70120
|
{ value: selectedShift, onChange: handleShiftFilterChange, options: shiftOptions, label: "Shift" },
|
|
69435
70121
|
{ value: selectedWeeksRange, onChange: handleWeeksFilterChange, options: weekOptions.map((o) => o.id), labels: weekOptions, label: "Duration" },
|
|
69436
|
-
{ value: selectedMemberId, onChange: handleMemberFilterChange, options: ["all", ...
|
|
70122
|
+
{ value: selectedMemberId, onChange: handleMemberFilterChange, options: ["all", ...teamMembersWithIETeam.map((m) => m.id)], labels: teamMembersWithIETeam, label: "Member" },
|
|
69437
70123
|
{ value: selectedLineId, onChange: handleLineFilterChange, options: lineOptions.map((o) => o.id), labels: lineOptions, label: "Line" }
|
|
69438
70124
|
].map((filter2, idx) => /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
|
|
69439
70125
|
/* @__PURE__ */ jsx("label", { className: "text-xs font-medium text-gray-500 uppercase tracking-wide ml-1", children: filter2.label }),
|
|
@@ -69650,7 +70336,7 @@ var ThreadSidebar = ({
|
|
|
69650
70336
|
] }) })
|
|
69651
70337
|
] });
|
|
69652
70338
|
};
|
|
69653
|
-
var ProfilePicture =
|
|
70339
|
+
var ProfilePicture = React141__default.memo(({
|
|
69654
70340
|
alt = "Axel",
|
|
69655
70341
|
className = "",
|
|
69656
70342
|
size = "md",
|
|
@@ -71621,6 +72307,840 @@ var AIAgentView = () => {
|
|
|
71621
72307
|
] });
|
|
71622
72308
|
};
|
|
71623
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;
|
|
71624
73144
|
var S3Service = class {
|
|
71625
73145
|
constructor(config) {
|
|
71626
73146
|
this.s3Client = null;
|
|
@@ -72097,4 +73617,4 @@ var streamProxyConfig = {
|
|
|
72097
73617
|
}
|
|
72098
73618
|
};
|
|
72099
73619
|
|
|
72100
|
-
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 };
|