@optifye/dashboard-core 6.11.15 → 6.11.16
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 +26 -3
- package/dist/index.d.mts +28 -2
- package/dist/index.d.ts +28 -2
- package/dist/index.js +1115 -534
- package/dist/index.mjs +1115 -536
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -12864,6 +12864,7 @@ var useShiftGroups = ({
|
|
|
12864
12864
|
}) => {
|
|
12865
12865
|
const [shiftGroups, setShiftGroups] = React141.useState([]);
|
|
12866
12866
|
const [shiftGroupsKey, setShiftGroupsKey] = React141.useState("");
|
|
12867
|
+
const [hasComputed, setHasComputed] = React141.useState(false);
|
|
12867
12868
|
const lastKeyRef = React141.useRef("");
|
|
12868
12869
|
const mapRef = React141.useRef(shiftConfigMap);
|
|
12869
12870
|
React141.useEffect(() => {
|
|
@@ -12874,6 +12875,7 @@ var useShiftGroups = ({
|
|
|
12874
12875
|
lastKeyRef.current = "";
|
|
12875
12876
|
setShiftGroups([]);
|
|
12876
12877
|
setShiftGroupsKey("");
|
|
12878
|
+
setHasComputed(false);
|
|
12877
12879
|
return;
|
|
12878
12880
|
}
|
|
12879
12881
|
let isMounted = true;
|
|
@@ -12886,6 +12888,7 @@ var useShiftGroups = ({
|
|
|
12886
12888
|
setShiftGroups(groups);
|
|
12887
12889
|
setShiftGroupsKey(key);
|
|
12888
12890
|
}
|
|
12891
|
+
setHasComputed(true);
|
|
12889
12892
|
};
|
|
12890
12893
|
compute();
|
|
12891
12894
|
const intervalId = setInterval(compute, pollIntervalMs);
|
|
@@ -12894,7 +12897,7 @@ var useShiftGroups = ({
|
|
|
12894
12897
|
clearInterval(intervalId);
|
|
12895
12898
|
};
|
|
12896
12899
|
}, [enabled, shiftConfigMap.size, timezone, pollIntervalMs]);
|
|
12897
|
-
return { shiftGroups, shiftGroupsKey };
|
|
12900
|
+
return { shiftGroups, shiftGroupsKey, hasComputed };
|
|
12898
12901
|
};
|
|
12899
12902
|
|
|
12900
12903
|
// src/lib/types/efficiencyLegend.ts
|
|
@@ -12956,52 +12959,6 @@ function getEfficiencyTextColorClasses(efficiency, legend = DEFAULT_EFFICIENCY_L
|
|
|
12956
12959
|
}
|
|
12957
12960
|
}
|
|
12958
12961
|
|
|
12959
|
-
// src/lib/hooks/useDashboardMetrics.recentFlow.ts
|
|
12960
|
-
var isFiniteNumber = (value) => typeof value === "number" && Number.isFinite(value);
|
|
12961
|
-
var getWorkspaceRecentFlowCacheKey = (workspace) => {
|
|
12962
|
-
const workspaceKey = workspace.workspace_uuid || workspace.workspace_name || "unknown";
|
|
12963
|
-
return `${workspaceKey}|${workspace.date}|${workspace.shift_id}`;
|
|
12964
|
-
};
|
|
12965
|
-
var toRecentFlowSnapshot = (workspace) => {
|
|
12966
|
-
if (!isFiniteNumber(workspace.recent_flow_percent)) {
|
|
12967
|
-
return null;
|
|
12968
|
-
}
|
|
12969
|
-
return {
|
|
12970
|
-
recent_flow_percent: workspace.recent_flow_percent,
|
|
12971
|
-
recent_flow_actual_rate_pph: workspace.recent_flow_actual_rate_pph ?? null,
|
|
12972
|
-
recent_flow_healthy_rate_pph: workspace.recent_flow_healthy_rate_pph ?? null,
|
|
12973
|
-
recent_flow_window_minutes: workspace.recent_flow_window_minutes ?? null,
|
|
12974
|
-
recent_flow_effective_end_at: workspace.recent_flow_effective_end_at ?? null
|
|
12975
|
-
};
|
|
12976
|
-
};
|
|
12977
|
-
var mergeWorkspaceRecentFlowMetrics = (workspaces, previousCache) => {
|
|
12978
|
-
const nextCache = /* @__PURE__ */ new Map();
|
|
12979
|
-
const mergedWorkspaces = workspaces.map((workspace) => {
|
|
12980
|
-
const cacheKey = getWorkspaceRecentFlowCacheKey(workspace);
|
|
12981
|
-
const currentSnapshot = toRecentFlowSnapshot(workspace);
|
|
12982
|
-
if (workspace.recent_flow_mode === "computed" && currentSnapshot) {
|
|
12983
|
-
nextCache.set(cacheKey, currentSnapshot);
|
|
12984
|
-
return workspace;
|
|
12985
|
-
}
|
|
12986
|
-
if (workspace.recent_flow_mode === "hold") {
|
|
12987
|
-
const cachedSnapshot = previousCache.get(cacheKey);
|
|
12988
|
-
if (cachedSnapshot) {
|
|
12989
|
-
nextCache.set(cacheKey, cachedSnapshot);
|
|
12990
|
-
return {
|
|
12991
|
-
...workspace,
|
|
12992
|
-
...cachedSnapshot,
|
|
12993
|
-
recent_flow_mode: "hold"
|
|
12994
|
-
};
|
|
12995
|
-
}
|
|
12996
|
-
}
|
|
12997
|
-
return workspace;
|
|
12998
|
-
});
|
|
12999
|
-
return {
|
|
13000
|
-
workspaces: mergedWorkspaces,
|
|
13001
|
-
cache: nextCache
|
|
13002
|
-
};
|
|
13003
|
-
};
|
|
13004
|
-
|
|
13005
12962
|
// src/lib/hooks/useDashboardMetrics.ts
|
|
13006
12963
|
var DEBUG_DASHBOARD_LOGS = process.env.NEXT_PUBLIC_DEBUG_DASHBOARD === "true";
|
|
13007
12964
|
var logDebug = (...args) => {
|
|
@@ -13090,7 +13047,6 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId, userAccessibleLineIds
|
|
|
13090
13047
|
const abortControllerRef = React141.useRef(null);
|
|
13091
13048
|
const lastFetchKeyRef = React141.useRef(null);
|
|
13092
13049
|
const inFlightFetchKeyRef = React141.useRef(null);
|
|
13093
|
-
const recentFlowCacheRef = React141.useRef(/* @__PURE__ */ new Map());
|
|
13094
13050
|
const updateQueueRef = React141.useRef(false);
|
|
13095
13051
|
const onLineMetricsUpdateRef = React141.useRef(onLineMetricsUpdate);
|
|
13096
13052
|
const shiftGroupsRef = React141.useRef(shiftGroups);
|
|
@@ -13124,7 +13080,6 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId, userAccessibleLineIds
|
|
|
13124
13080
|
setError(null);
|
|
13125
13081
|
lastFetchKeyRef.current = null;
|
|
13126
13082
|
inFlightFetchKeyRef.current = null;
|
|
13127
|
-
recentFlowCacheRef.current = /* @__PURE__ */ new Map();
|
|
13128
13083
|
}, [lineId]);
|
|
13129
13084
|
const fetchAllMetrics = React141.useCallback(async (options = {}) => {
|
|
13130
13085
|
const { force = false } = options;
|
|
@@ -13399,12 +13354,9 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId, userAccessibleLineIds
|
|
|
13399
13354
|
actionType: item.action_type,
|
|
13400
13355
|
actionName: item.action_name
|
|
13401
13356
|
}),
|
|
13402
|
-
recent_flow_mode: item.recent_flow_mode ?? void 0,
|
|
13403
13357
|
recent_flow_percent: item.recent_flow_percent ?? null,
|
|
13404
|
-
recent_flow_actual_rate_pph: item.recent_flow_actual_rate_pph ?? null,
|
|
13405
|
-
recent_flow_healthy_rate_pph: item.recent_flow_healthy_rate_pph ?? null,
|
|
13406
|
-
recent_flow_window_minutes: item.recent_flow_window_minutes ?? null,
|
|
13407
13358
|
recent_flow_effective_end_at: item.recent_flow_effective_end_at ?? null,
|
|
13359
|
+
recent_flow_computed_at: item.recent_flow_computed_at ?? null,
|
|
13408
13360
|
incoming_wip_current: item.incoming_wip_current ?? null,
|
|
13409
13361
|
incoming_wip_effective_at: item.incoming_wip_effective_at ?? null,
|
|
13410
13362
|
incoming_wip_buffer_name: item.incoming_wip_buffer_name ?? null
|
|
@@ -13415,16 +13367,11 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId, userAccessibleLineIds
|
|
|
13415
13367
|
const wsNumB = parseInt(b.workspace_name?.replace(/[^0-9]/g, "") || "0");
|
|
13416
13368
|
return wsNumA - wsNumB;
|
|
13417
13369
|
});
|
|
13418
|
-
|
|
13419
|
-
workspaces: mergedWorkspaceData,
|
|
13420
|
-
cache: nextRecentFlowCache
|
|
13421
|
-
} = mergeWorkspaceRecentFlowMetrics(transformedWorkspaceData, recentFlowCacheRef.current);
|
|
13422
|
-
recentFlowCacheRef.current = nextRecentFlowCache;
|
|
13423
|
-
mergedWorkspaceData.forEach((metric) => {
|
|
13370
|
+
transformedWorkspaceData.forEach((metric) => {
|
|
13424
13371
|
workspaceMetricsStore.setOverview(metric);
|
|
13425
13372
|
});
|
|
13426
13373
|
const newMetricsState = {
|
|
13427
|
-
workspaceMetrics:
|
|
13374
|
+
workspaceMetrics: transformedWorkspaceData,
|
|
13428
13375
|
lineMetrics: allLineMetrics || [],
|
|
13429
13376
|
metadata: { hasFlowBuffers, idleTimeVlmByLine },
|
|
13430
13377
|
efficiencyLegend: efficiencyLegend ?? DEFAULT_EFFICIENCY_LEGEND
|
|
@@ -16849,7 +16796,7 @@ var useActiveBreaks = (lineIds) => {
|
|
|
16849
16796
|
const [isLoading, setIsLoading] = React141.useState(true);
|
|
16850
16797
|
const [error, setError] = React141.useState(null);
|
|
16851
16798
|
const supabase = useSupabase();
|
|
16852
|
-
const
|
|
16799
|
+
const parseTimeToMinutes4 = (timeStr) => {
|
|
16853
16800
|
const [hours, minutes] = timeStr.split(":").map(Number);
|
|
16854
16801
|
return hours * 60 + minutes;
|
|
16855
16802
|
};
|
|
@@ -16858,8 +16805,8 @@ var useActiveBreaks = (lineIds) => {
|
|
|
16858
16805
|
return now4.getHours() * 60 + now4.getMinutes();
|
|
16859
16806
|
};
|
|
16860
16807
|
const isTimeInBreak = (breakStart, breakEnd, currentMinutes) => {
|
|
16861
|
-
const startMinutes =
|
|
16862
|
-
const endMinutes =
|
|
16808
|
+
const startMinutes = parseTimeToMinutes4(breakStart);
|
|
16809
|
+
const endMinutes = parseTimeToMinutes4(breakEnd);
|
|
16863
16810
|
if (endMinutes < startMinutes) {
|
|
16864
16811
|
return currentMinutes >= startMinutes || currentMinutes < endMinutes;
|
|
16865
16812
|
} else {
|
|
@@ -16867,8 +16814,8 @@ var useActiveBreaks = (lineIds) => {
|
|
|
16867
16814
|
}
|
|
16868
16815
|
};
|
|
16869
16816
|
const calculateBreakProgress = (breakStart, breakEnd, currentMinutes) => {
|
|
16870
|
-
const startMinutes =
|
|
16871
|
-
const endMinutes =
|
|
16817
|
+
const startMinutes = parseTimeToMinutes4(breakStart);
|
|
16818
|
+
const endMinutes = parseTimeToMinutes4(breakEnd);
|
|
16872
16819
|
let elapsedMinutes = 0;
|
|
16873
16820
|
let remainingMinutes = 0;
|
|
16874
16821
|
if (endMinutes < startMinutes) {
|
|
@@ -16886,8 +16833,8 @@ var useActiveBreaks = (lineIds) => {
|
|
|
16886
16833
|
return { elapsedMinutes, remainingMinutes };
|
|
16887
16834
|
};
|
|
16888
16835
|
const isTimeInShift = (startTime, endTime, currentMinutes) => {
|
|
16889
|
-
const startMinutes =
|
|
16890
|
-
const endMinutes =
|
|
16836
|
+
const startMinutes = parseTimeToMinutes4(startTime);
|
|
16837
|
+
const endMinutes = parseTimeToMinutes4(endTime);
|
|
16891
16838
|
if (endMinutes < startMinutes) {
|
|
16892
16839
|
return currentMinutes >= startMinutes || currentMinutes < endMinutes;
|
|
16893
16840
|
} else {
|
|
@@ -16947,8 +16894,8 @@ var useActiveBreaks = (lineIds) => {
|
|
|
16947
16894
|
const endTime = breakItem.end || breakItem.endTime || "00:00";
|
|
16948
16895
|
let duration = breakItem.duration || 0;
|
|
16949
16896
|
if (!duration || duration === 0) {
|
|
16950
|
-
const startMinutes =
|
|
16951
|
-
const endMinutes =
|
|
16897
|
+
const startMinutes = parseTimeToMinutes4(startTime);
|
|
16898
|
+
const endMinutes = parseTimeToMinutes4(endTime);
|
|
16952
16899
|
duration = endMinutes < startMinutes ? endMinutes + 24 * 60 - startMinutes : endMinutes - startMinutes;
|
|
16953
16900
|
}
|
|
16954
16901
|
return {
|
|
@@ -16964,8 +16911,8 @@ var useActiveBreaks = (lineIds) => {
|
|
|
16964
16911
|
const endTime = breakItem.end || breakItem.endTime || "00:00";
|
|
16965
16912
|
let duration = breakItem.duration || 0;
|
|
16966
16913
|
if (!duration || duration === 0) {
|
|
16967
|
-
const startMinutes =
|
|
16968
|
-
const endMinutes =
|
|
16914
|
+
const startMinutes = parseTimeToMinutes4(startTime);
|
|
16915
|
+
const endMinutes = parseTimeToMinutes4(endTime);
|
|
16969
16916
|
duration = endMinutes < startMinutes ? endMinutes + 24 * 60 - startMinutes : endMinutes - startMinutes;
|
|
16970
16917
|
}
|
|
16971
16918
|
return {
|
|
@@ -23046,6 +22993,16 @@ var createThrottledReload = (interval = 5e3, maxReloads = 3) => {
|
|
|
23046
22993
|
};
|
|
23047
22994
|
var throttledReloadDashboard = createThrottledReload(5e3, 3);
|
|
23048
22995
|
|
|
22996
|
+
// src/lib/utils/dev/localDevTestLogin.ts
|
|
22997
|
+
var isLoopbackHostname = (hostname) => {
|
|
22998
|
+
const normalized = String(hostname || "").trim().toLowerCase();
|
|
22999
|
+
return normalized === "localhost" || normalized === "127.0.0.1" || normalized === "::1";
|
|
23000
|
+
};
|
|
23001
|
+
var shouldEnableLocalDevTestLogin = ({
|
|
23002
|
+
enabledFlag,
|
|
23003
|
+
hostname
|
|
23004
|
+
}) => enabledFlag && isLoopbackHostname(hostname);
|
|
23005
|
+
|
|
23049
23006
|
// src/lib/utils/index.ts
|
|
23050
23007
|
var formatIdleTime = (idleTimeInSeconds) => {
|
|
23051
23008
|
if (!idleTimeInSeconds || idleTimeInSeconds <= 0) {
|
|
@@ -31230,12 +31187,16 @@ var LoginPage = ({
|
|
|
31230
31187
|
onRateLimitCheck,
|
|
31231
31188
|
logoSrc = optifye_logo_default,
|
|
31232
31189
|
logoAlt = "Optifye",
|
|
31233
|
-
brandName = "Optifye"
|
|
31190
|
+
brandName = "Optifye",
|
|
31191
|
+
showDevTestLogin = false,
|
|
31192
|
+
devTestLoginLabel = "Sign in as Test User",
|
|
31193
|
+
onDevTestLogin
|
|
31234
31194
|
}) => {
|
|
31235
31195
|
const [email, setEmail] = React141.useState("");
|
|
31236
31196
|
const [otp, setOtp] = React141.useState("");
|
|
31237
31197
|
const [step, setStep] = React141.useState("email");
|
|
31238
31198
|
const [loading, setLoading] = React141.useState(false);
|
|
31199
|
+
const [devLoginLoading, setDevLoginLoading] = React141.useState(false);
|
|
31239
31200
|
const [error, setError] = React141.useState(null);
|
|
31240
31201
|
const [countdown, setCountdown] = React141.useState(0);
|
|
31241
31202
|
const supabase = useSupabase();
|
|
@@ -31299,6 +31260,25 @@ var LoginPage = ({
|
|
|
31299
31260
|
startCountdown();
|
|
31300
31261
|
}
|
|
31301
31262
|
};
|
|
31263
|
+
const handleDevTestLogin = async () => {
|
|
31264
|
+
if (!onDevTestLogin) {
|
|
31265
|
+
return;
|
|
31266
|
+
}
|
|
31267
|
+
setDevLoginLoading(true);
|
|
31268
|
+
setError(null);
|
|
31269
|
+
try {
|
|
31270
|
+
const result = await onDevTestLogin();
|
|
31271
|
+
const nextError = typeof result === "object" && result !== null && "error" in result ? result.error : null;
|
|
31272
|
+
if (typeof nextError === "string" && nextError.trim()) {
|
|
31273
|
+
setError(nextError);
|
|
31274
|
+
}
|
|
31275
|
+
} catch (err) {
|
|
31276
|
+
console.error("Dev test login failed:", err);
|
|
31277
|
+
setError("Dev test login unavailable.");
|
|
31278
|
+
} finally {
|
|
31279
|
+
setDevLoginLoading(false);
|
|
31280
|
+
}
|
|
31281
|
+
};
|
|
31302
31282
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-h-screen flex items-center justify-center bg-gradient-to-br from-slate-50 to-slate-100", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "max-w-md w-full mx-4", children: [
|
|
31303
31283
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-white rounded-2xl shadow-xl border border-slate-200 p-8", children: [
|
|
31304
31284
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center mb-8", children: [
|
|
@@ -31339,7 +31319,7 @@ var LoginPage = ({
|
|
|
31339
31319
|
"button",
|
|
31340
31320
|
{
|
|
31341
31321
|
type: "submit",
|
|
31342
|
-
disabled: loading,
|
|
31322
|
+
disabled: loading || devLoginLoading,
|
|
31343
31323
|
className: "w-full py-3 px-4 bg-slate-900 hover:bg-slate-800 focus:ring-2 focus:ring-slate-600 focus:ring-offset-2 text-white font-medium rounded-xl transition-all duration-200 disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center",
|
|
31344
31324
|
children: loading ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
31345
31325
|
/* @__PURE__ */ jsxRuntime.jsxs("svg", { className: "animate-spin -ml-1 mr-3 h-4 w-4 text-white", xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", children: [
|
|
@@ -31349,7 +31329,31 @@ var LoginPage = ({
|
|
|
31349
31329
|
"Sending..."
|
|
31350
31330
|
] }) : "Continue with Email"
|
|
31351
31331
|
}
|
|
31352
|
-
)
|
|
31332
|
+
),
|
|
31333
|
+
showDevTestLogin && onDevTestLogin ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3", children: [
|
|
31334
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
|
|
31335
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-px flex-1 bg-slate-200" }),
|
|
31336
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium uppercase tracking-[0.2em] text-slate-400", children: "Local Dev" }),
|
|
31337
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-px flex-1 bg-slate-200" })
|
|
31338
|
+
] }),
|
|
31339
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
31340
|
+
"button",
|
|
31341
|
+
{
|
|
31342
|
+
type: "button",
|
|
31343
|
+
disabled: loading || devLoginLoading,
|
|
31344
|
+
onClick: () => void handleDevTestLogin(),
|
|
31345
|
+
className: "w-full py-3 px-4 bg-white hover:bg-slate-50 focus:ring-2 focus:ring-slate-400 focus:ring-offset-2 text-slate-700 font-medium rounded-xl border border-slate-200 transition-all duration-200 disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center",
|
|
31346
|
+
children: devLoginLoading ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
31347
|
+
/* @__PURE__ */ jsxRuntime.jsxs("svg", { className: "animate-spin -ml-1 mr-3 h-4 w-4 text-slate-700", xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", children: [
|
|
31348
|
+
/* @__PURE__ */ jsxRuntime.jsx("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }),
|
|
31349
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { className: "opacity-75", fill: "currentColor", d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" })
|
|
31350
|
+
] }),
|
|
31351
|
+
"Signing In..."
|
|
31352
|
+
] }) : devTestLoginLabel
|
|
31353
|
+
}
|
|
31354
|
+
),
|
|
31355
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-center text-xs text-slate-500", children: "Localhost-only convenience login for the shared test account." })
|
|
31356
|
+
] }) : null
|
|
31353
31357
|
] }) : /* @__PURE__ */ jsxRuntime.jsxs("form", { className: "space-y-6", onSubmit: handleVerifyOTP, children: [
|
|
31354
31358
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
31355
31359
|
/* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: "otp", className: "block text-sm font-medium text-slate-700 mb-2 text-center", children: "Enter the 6-digit code sent to" }),
|
|
@@ -31374,7 +31378,7 @@ var LoginPage = ({
|
|
|
31374
31378
|
"button",
|
|
31375
31379
|
{
|
|
31376
31380
|
type: "submit",
|
|
31377
|
-
disabled: loading || otp.length !== 6,
|
|
31381
|
+
disabled: loading || devLoginLoading || otp.length !== 6,
|
|
31378
31382
|
className: "w-full py-3 px-4 bg-slate-900 hover:bg-slate-800 focus:ring-2 focus:ring-slate-600 focus:ring-offset-2 text-white font-medium rounded-xl transition-all duration-200 disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center",
|
|
31379
31383
|
children: loading ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
31380
31384
|
/* @__PURE__ */ jsxRuntime.jsxs("svg", { className: "animate-spin -ml-1 mr-3 h-4 w-4 text-white", xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", children: [
|
|
@@ -32215,31 +32219,35 @@ var LineChartComponent = ({
|
|
|
32215
32219
|
...restOfChartProps
|
|
32216
32220
|
}) => {
|
|
32217
32221
|
const containerRef = React141__namespace.default.useRef(null);
|
|
32218
|
-
const [
|
|
32219
|
-
const
|
|
32220
|
-
const { formatNumber } = useFormatNumber();
|
|
32222
|
+
const [dimensions, setDimensions] = React141__namespace.default.useState({ width: 0, height: 0 });
|
|
32223
|
+
const [hasValidData, setHasValidData] = React141__namespace.default.useState(false);
|
|
32221
32224
|
React141__namespace.default.useEffect(() => {
|
|
32222
|
-
const
|
|
32223
|
-
|
|
32224
|
-
const
|
|
32225
|
-
|
|
32226
|
-
|
|
32227
|
-
|
|
32228
|
-
|
|
32229
|
-
|
|
32230
|
-
checkContainerDimensions();
|
|
32231
|
-
const resizeObserver = new ResizeObserver(checkContainerDimensions);
|
|
32232
|
-
if (containerRef.current) {
|
|
32233
|
-
resizeObserver.observe(containerRef.current);
|
|
32225
|
+
const currentHasValidData = data && lines && lines.length > 0 && data.some(
|
|
32226
|
+
(item) => lines.some((line) => {
|
|
32227
|
+
const val = item[line.dataKey];
|
|
32228
|
+
return typeof val === "number" && val > 0;
|
|
32229
|
+
})
|
|
32230
|
+
);
|
|
32231
|
+
if (currentHasValidData && !hasValidData) {
|
|
32232
|
+
setHasValidData(true);
|
|
32234
32233
|
}
|
|
32235
|
-
|
|
32236
|
-
|
|
32237
|
-
|
|
32238
|
-
|
|
32239
|
-
|
|
32240
|
-
|
|
32241
|
-
|
|
32234
|
+
}, [data, lines, hasValidData]);
|
|
32235
|
+
React141__namespace.default.useEffect(() => {
|
|
32236
|
+
if (!containerRef.current) return;
|
|
32237
|
+
const observer = new ResizeObserver((entries) => {
|
|
32238
|
+
const entry = entries[0];
|
|
32239
|
+
if (entry) {
|
|
32240
|
+
setDimensions({
|
|
32241
|
+
width: entry.contentRect.width,
|
|
32242
|
+
height: entry.contentRect.height
|
|
32243
|
+
});
|
|
32244
|
+
}
|
|
32245
|
+
});
|
|
32246
|
+
observer.observe(containerRef.current);
|
|
32247
|
+
return () => observer.disconnect();
|
|
32242
32248
|
}, []);
|
|
32249
|
+
const themeConfig = useThemeConfig();
|
|
32250
|
+
const { formatNumber } = useFormatNumber();
|
|
32243
32251
|
const yAxisTickFormatter = (value) => {
|
|
32244
32252
|
return `${formatNumber(value)}${yAxisUnit || ""}`;
|
|
32245
32253
|
};
|
|
@@ -32261,57 +32269,71 @@ var LineChartComponent = ({
|
|
|
32261
32269
|
const gridStrokeColor = themeConfig?.gray?.["300"] || "#ccc";
|
|
32262
32270
|
const axisTickFillColor = themeConfig?.gray?.["600"] || "#666";
|
|
32263
32271
|
const axisStrokeColor = themeConfig?.gray?.["400"] || "#999";
|
|
32264
|
-
const
|
|
32265
|
-
|
|
32266
|
-
|
|
32267
|
-
|
|
32268
|
-
|
|
32269
|
-
|
|
32270
|
-
|
|
32271
|
-
|
|
32272
|
-
|
|
32273
|
-
stroke:
|
|
32274
|
-
|
|
32275
|
-
|
|
32276
|
-
|
|
32277
|
-
|
|
32278
|
-
|
|
32279
|
-
|
|
32280
|
-
|
|
32281
|
-
|
|
32282
|
-
|
|
32283
|
-
|
|
32284
|
-
|
|
32285
|
-
|
|
32286
|
-
|
|
32287
|
-
|
|
32288
|
-
|
|
32289
|
-
|
|
32290
|
-
|
|
32291
|
-
|
|
32292
|
-
|
|
32293
|
-
|
|
32294
|
-
|
|
32295
|
-
|
|
32296
|
-
|
|
32297
|
-
|
|
32298
|
-
|
|
32299
|
-
|
|
32300
|
-
|
|
32301
|
-
|
|
32302
|
-
|
|
32303
|
-
|
|
32304
|
-
|
|
32305
|
-
|
|
32306
|
-
|
|
32307
|
-
|
|
32308
|
-
|
|
32309
|
-
|
|
32310
|
-
|
|
32311
|
-
|
|
32312
|
-
|
|
32313
|
-
|
|
32314
|
-
|
|
32272
|
+
const renderChartContent = (chartWidth, chartHeight) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
32273
|
+
recharts.LineChart,
|
|
32274
|
+
{
|
|
32275
|
+
width: chartWidth,
|
|
32276
|
+
height: chartHeight,
|
|
32277
|
+
data,
|
|
32278
|
+
margin: { top: 5, right: 30, left: 20, bottom: 20 },
|
|
32279
|
+
...restOfChartProps,
|
|
32280
|
+
children: [
|
|
32281
|
+
showGrid && /* @__PURE__ */ jsxRuntime.jsx(recharts.CartesianGrid, { strokeDasharray: "3 3", stroke: gridStrokeColor }),
|
|
32282
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
32283
|
+
recharts.XAxis,
|
|
32284
|
+
{
|
|
32285
|
+
dataKey: xAxisDataKey,
|
|
32286
|
+
label: xAxisLabel ? { value: xAxisLabel, position: "insideBottom", offset: -10 } : void 0,
|
|
32287
|
+
tickFormatter: xAxisTickFormatter,
|
|
32288
|
+
tick: { fontSize: 12, fill: axisTickFillColor },
|
|
32289
|
+
stroke: axisStrokeColor
|
|
32290
|
+
}
|
|
32291
|
+
),
|
|
32292
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
32293
|
+
recharts.YAxis,
|
|
32294
|
+
{
|
|
32295
|
+
label: yAxisLabel ? { value: yAxisLabel, angle: -90, position: "insideLeft" } : void 0,
|
|
32296
|
+
tickFormatter: yAxisTickFormatter,
|
|
32297
|
+
domain: yAxisDomain,
|
|
32298
|
+
tick: { fontSize: 12, fill: axisTickFillColor },
|
|
32299
|
+
stroke: axisStrokeColor
|
|
32300
|
+
}
|
|
32301
|
+
),
|
|
32302
|
+
showTooltip && /* @__PURE__ */ jsxRuntime.jsx(
|
|
32303
|
+
recharts.Tooltip,
|
|
32304
|
+
{
|
|
32305
|
+
formatter: tooltipFormatter || defaultTooltipFormatter,
|
|
32306
|
+
labelFormatter: tooltipLabelFormatter,
|
|
32307
|
+
itemStyle: { color: "#111827" },
|
|
32308
|
+
cursor: { strokeDasharray: "3 3" }
|
|
32309
|
+
}
|
|
32310
|
+
),
|
|
32311
|
+
showLegend && /* @__PURE__ */ jsxRuntime.jsx(recharts.Legend, { payload: legendPayload }),
|
|
32312
|
+
lines.map((lineConfig, index) => {
|
|
32313
|
+
const lineProps = {
|
|
32314
|
+
...lineConfig,
|
|
32315
|
+
key: lineConfig.dataKey,
|
|
32316
|
+
type: lineConfig.type || "monotone",
|
|
32317
|
+
stroke: lineConfig.stroke || defaultColors[index % defaultColors.length],
|
|
32318
|
+
activeDot: lineConfig.activeDot !== void 0 ? lineConfig.activeDot : { r: 6 },
|
|
32319
|
+
isAnimationActive: true,
|
|
32320
|
+
animationDuration: 1500,
|
|
32321
|
+
animationBegin: 300
|
|
32322
|
+
};
|
|
32323
|
+
return /* @__PURE__ */ jsxRuntime.jsx(recharts.Line, { ...lineProps, children: lineConfig.labelList && /* @__PURE__ */ jsxRuntime.jsx(
|
|
32324
|
+
recharts.LabelList,
|
|
32325
|
+
{
|
|
32326
|
+
dataKey: lineConfig.dataKey,
|
|
32327
|
+
position: "top",
|
|
32328
|
+
formatter: (value) => formatNumber(value),
|
|
32329
|
+
...typeof lineConfig.labelList === "object" ? lineConfig.labelList : {}
|
|
32330
|
+
}
|
|
32331
|
+
) });
|
|
32332
|
+
})
|
|
32333
|
+
]
|
|
32334
|
+
},
|
|
32335
|
+
hasValidData ? "valid" : "empty"
|
|
32336
|
+
);
|
|
32315
32337
|
if (responsive) {
|
|
32316
32338
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
32317
32339
|
"div",
|
|
@@ -32319,11 +32341,20 @@ var LineChartComponent = ({
|
|
|
32319
32341
|
ref: containerRef,
|
|
32320
32342
|
className: clsx(fillContainer ? "w-full h-full" : "w-full h-auto", className),
|
|
32321
32343
|
style: fillContainer ? { height: "100%", minHeight: "50px", minWidth: "100px" } : { aspectRatio: `${aspect}/1`, minHeight: "50px", minWidth: "100px" },
|
|
32322
|
-
children:
|
|
32344
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
32345
|
+
motion.div,
|
|
32346
|
+
{
|
|
32347
|
+
initial: { opacity: 0 },
|
|
32348
|
+
animate: { opacity: 1 },
|
|
32349
|
+
transition: { duration: 0.5 },
|
|
32350
|
+
className: "w-full h-full",
|
|
32351
|
+
children: dimensions.width > 0 && dimensions.height > 0 && renderChartContent(dimensions.width, dimensions.height)
|
|
32352
|
+
}
|
|
32353
|
+
)
|
|
32323
32354
|
}
|
|
32324
32355
|
);
|
|
32325
32356
|
}
|
|
32326
|
-
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: clsx("w-full", className), children:
|
|
32357
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: clsx("w-full", className), children: renderChartContent(restOfChartProps.width, restOfChartProps.height) });
|
|
32327
32358
|
};
|
|
32328
32359
|
var LineChart = React141__namespace.default.memo(LineChartComponent, (prevProps, nextProps) => {
|
|
32329
32360
|
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)) {
|
|
@@ -32591,14 +32622,35 @@ var CycleTimeOverTimeChart = ({
|
|
|
32591
32622
|
}) => {
|
|
32592
32623
|
const MAX_DATA_POINTS = 40;
|
|
32593
32624
|
const containerRef = React141__namespace.default.useRef(null);
|
|
32594
|
-
const [
|
|
32595
|
-
const
|
|
32625
|
+
const [dimensions, setDimensions] = React141__namespace.default.useState({ width: 0, height: 0 });
|
|
32626
|
+
const [hasValidData, setHasValidData] = React141__namespace.default.useState(false);
|
|
32627
|
+
React141__namespace.default.useEffect(() => {
|
|
32628
|
+
const currentHasValidData = data && data.some((val) => val !== null && val > 0);
|
|
32629
|
+
if (currentHasValidData && !hasValidData) {
|
|
32630
|
+
setHasValidData(true);
|
|
32631
|
+
}
|
|
32632
|
+
}, [data, hasValidData]);
|
|
32633
|
+
React141__namespace.default.useEffect(() => {
|
|
32634
|
+
if (!containerRef.current) return;
|
|
32635
|
+
const observer = new ResizeObserver((entries) => {
|
|
32636
|
+
const entry = entries[0];
|
|
32637
|
+
if (entry) {
|
|
32638
|
+
setDimensions({
|
|
32639
|
+
width: entry.contentRect.width,
|
|
32640
|
+
height: entry.contentRect.height
|
|
32641
|
+
});
|
|
32642
|
+
}
|
|
32643
|
+
});
|
|
32644
|
+
observer.observe(containerRef.current);
|
|
32645
|
+
return () => observer.disconnect();
|
|
32646
|
+
}, []);
|
|
32647
|
+
const parseTimeToMinutes4 = (value) => {
|
|
32596
32648
|
const [hours, minutes] = value.split(":").map(Number);
|
|
32597
32649
|
if (!Number.isFinite(hours) || !Number.isFinite(minutes)) return 0;
|
|
32598
32650
|
return hours * 60 + minutes;
|
|
32599
32651
|
};
|
|
32600
32652
|
const formatHourLabel = (slotIndex) => {
|
|
32601
|
-
const baseMinutes =
|
|
32653
|
+
const baseMinutes = parseTimeToMinutes4(shiftStart);
|
|
32602
32654
|
const absoluteMinutes = baseMinutes + slotIndex * 60;
|
|
32603
32655
|
const hour24 = Math.floor(absoluteMinutes % (24 * 60) / 60);
|
|
32604
32656
|
const ampm = hour24 >= 12 ? "PM" : "AM";
|
|
@@ -32617,52 +32669,7 @@ var CycleTimeOverTimeChart = ({
|
|
|
32617
32669
|
const displayData = getDisplayData(data);
|
|
32618
32670
|
const DURATION = displayData.length;
|
|
32619
32671
|
const effectiveDatasetKey = datasetKey || `cycle-time:${xAxisMode}`;
|
|
32620
|
-
const [animatedDatasetKey, setAnimatedDatasetKey] = React141__namespace.default.useState(null);
|
|
32621
|
-
const shouldAnimate = animatedDatasetKey !== effectiveDatasetKey;
|
|
32622
|
-
const handleAnimationEnd = React141__namespace.default.useCallback(() => {
|
|
32623
|
-
setAnimatedDatasetKey((currentValue) => currentValue === effectiveDatasetKey ? currentValue : effectiveDatasetKey);
|
|
32624
|
-
}, [effectiveDatasetKey]);
|
|
32625
32672
|
const finalData = displayData;
|
|
32626
|
-
React141__namespace.default.useEffect(() => {
|
|
32627
|
-
const containerNode = containerRef.current;
|
|
32628
|
-
if (!containerNode) {
|
|
32629
|
-
setContainerReady(true);
|
|
32630
|
-
return void 0;
|
|
32631
|
-
}
|
|
32632
|
-
let frameId = null;
|
|
32633
|
-
let resizeObserver = null;
|
|
32634
|
-
const checkContainerDimensions = () => {
|
|
32635
|
-
const rect = containerNode.getBoundingClientRect();
|
|
32636
|
-
const isReady = rect.width > 0 && rect.height > 0;
|
|
32637
|
-
if (isReady) {
|
|
32638
|
-
setContainerReady(true);
|
|
32639
|
-
}
|
|
32640
|
-
return isReady;
|
|
32641
|
-
};
|
|
32642
|
-
if (checkContainerDimensions()) {
|
|
32643
|
-
return void 0;
|
|
32644
|
-
}
|
|
32645
|
-
frameId = window.requestAnimationFrame(() => {
|
|
32646
|
-
checkContainerDimensions();
|
|
32647
|
-
});
|
|
32648
|
-
if (typeof ResizeObserver !== "undefined") {
|
|
32649
|
-
resizeObserver = new ResizeObserver(() => {
|
|
32650
|
-
if (checkContainerDimensions() && resizeObserver) {
|
|
32651
|
-
resizeObserver.disconnect();
|
|
32652
|
-
resizeObserver = null;
|
|
32653
|
-
}
|
|
32654
|
-
});
|
|
32655
|
-
resizeObserver.observe(containerNode);
|
|
32656
|
-
} else {
|
|
32657
|
-
setContainerReady(true);
|
|
32658
|
-
}
|
|
32659
|
-
return () => {
|
|
32660
|
-
if (frameId !== null) {
|
|
32661
|
-
window.cancelAnimationFrame(frameId);
|
|
32662
|
-
}
|
|
32663
|
-
resizeObserver?.disconnect();
|
|
32664
|
-
};
|
|
32665
|
-
}, []);
|
|
32666
32673
|
const labelInterval = React141__namespace.default.useMemo(() => {
|
|
32667
32674
|
if (xAxisMode === "hourly") {
|
|
32668
32675
|
return Math.max(1, Math.ceil(DURATION / 8));
|
|
@@ -32870,144 +32877,154 @@ var CycleTimeOverTimeChart = ({
|
|
|
32870
32877
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
32871
32878
|
"div",
|
|
32872
32879
|
{
|
|
32873
|
-
ref: containerRef,
|
|
32874
32880
|
className: `w-full h-full min-w-0 flex flex-col relative pb-2 ${className}`,
|
|
32875
32881
|
style: { minHeight: "200px", minWidth: 0 },
|
|
32876
32882
|
children: [
|
|
32877
32883
|
renderLegend(),
|
|
32878
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 min-h-0 w-full",
|
|
32879
|
-
|
|
32884
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 min-h-0 w-full", ref: containerRef, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
32885
|
+
motion.div,
|
|
32880
32886
|
{
|
|
32881
|
-
|
|
32882
|
-
|
|
32883
|
-
|
|
32884
|
-
|
|
32885
|
-
|
|
32886
|
-
|
|
32887
|
-
|
|
32888
|
-
|
|
32889
|
-
|
|
32890
|
-
|
|
32891
|
-
|
|
32892
|
-
|
|
32893
|
-
|
|
32894
|
-
|
|
32895
|
-
|
|
32896
|
-
angle: xAxisMode === "hourly" ? 0 : -30,
|
|
32897
|
-
textAnchor: xAxisMode === "hourly" ? "middle" : "end",
|
|
32898
|
-
tickMargin: xAxisMode === "hourly" ? 8 : 15,
|
|
32899
|
-
height: xAxisMode === "hourly" ? 40 : 60
|
|
32900
|
-
}
|
|
32901
|
-
),
|
|
32902
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
32903
|
-
recharts.YAxis,
|
|
32904
|
-
{
|
|
32905
|
-
tickMargin: 8,
|
|
32906
|
-
width: 45,
|
|
32907
|
-
yAxisId: "cycle",
|
|
32908
|
-
domain: ["auto", "auto"],
|
|
32909
|
-
ticks: [0, idealCycleTime, ...Array.from({ length: 4 }, (_, i) => (i + 1) * Math.ceil(idealCycleTime / 2))].sort((a, b) => a - b),
|
|
32910
|
-
tickFormatter: (value) => String(value),
|
|
32911
|
-
tick: (props) => {
|
|
32912
|
-
const { x, y, payload } = props;
|
|
32913
|
-
const displayValue = typeof payload.value === "number" ? payload.value.toFixed(1) : String(payload.value);
|
|
32914
|
-
return /* @__PURE__ */ jsxRuntime.jsx("g", { transform: `translate(${x},${y})`, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
32915
|
-
"text",
|
|
32916
|
-
{
|
|
32917
|
-
x: 0,
|
|
32918
|
-
y: 0,
|
|
32919
|
-
dy: 4,
|
|
32920
|
-
textAnchor: "end",
|
|
32921
|
-
fill: payload.value === idealCycleTime ? "#E34329" : "#666",
|
|
32922
|
-
fontSize: 12,
|
|
32923
|
-
fontWeight: payload.value === idealCycleTime ? "bold" : "normal",
|
|
32924
|
-
children: displayValue
|
|
32925
|
-
},
|
|
32926
|
-
`tick-${payload.value}-${x}-${y}`
|
|
32927
|
-
) });
|
|
32928
|
-
}
|
|
32929
|
-
}
|
|
32930
|
-
),
|
|
32931
|
-
showIdleTime && /* @__PURE__ */ jsxRuntime.jsx(
|
|
32932
|
-
recharts.YAxis,
|
|
32933
|
-
{
|
|
32934
|
-
yAxisId: "idle",
|
|
32935
|
-
orientation: "right",
|
|
32936
|
-
tickMargin: 8,
|
|
32937
|
-
width: 35,
|
|
32938
|
-
domain: [0, 60],
|
|
32939
|
-
tickFormatter: (value) => `${value}m`,
|
|
32940
|
-
tick: { fontSize: 11, fill: "#f59e0b" },
|
|
32941
|
-
axisLine: false,
|
|
32942
|
-
tickLine: false
|
|
32943
|
-
}
|
|
32944
|
-
),
|
|
32945
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
32946
|
-
recharts.Tooltip,
|
|
32947
|
-
{
|
|
32948
|
-
cursor: { stroke: "#E5E7EB", strokeWidth: 1 },
|
|
32949
|
-
content: renderChartTooltip,
|
|
32950
|
-
animationDuration: 200
|
|
32951
|
-
}
|
|
32952
|
-
),
|
|
32953
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
32954
|
-
recharts.ReferenceLine,
|
|
32955
|
-
{
|
|
32956
|
-
y: idealCycleTime,
|
|
32957
|
-
yAxisId: "cycle",
|
|
32958
|
-
stroke: "#E34329",
|
|
32959
|
-
strokeDasharray: "3 3",
|
|
32960
|
-
strokeWidth: 2,
|
|
32961
|
-
label: {
|
|
32962
|
-
position: "right",
|
|
32963
|
-
value: `${idealCycleTime.toFixed(1)}s`,
|
|
32964
|
-
fill: "#E34329",
|
|
32965
|
-
fontSize: 12,
|
|
32966
|
-
fontWeight: 500
|
|
32967
|
-
}
|
|
32968
|
-
}
|
|
32969
|
-
),
|
|
32970
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
32971
|
-
recharts.Line,
|
|
32972
|
-
{
|
|
32973
|
-
type: "monotone",
|
|
32974
|
-
yAxisId: "cycle",
|
|
32975
|
-
dataKey: "cycleTime",
|
|
32976
|
-
stroke: "#3B82F6",
|
|
32977
|
-
strokeWidth: 2,
|
|
32978
|
-
connectNulls: false,
|
|
32979
|
-
dot: renderCycleDot,
|
|
32980
|
-
activeDot: renderCycleActiveDot,
|
|
32981
|
-
isAnimationActive: shouldAnimate,
|
|
32982
|
-
animationBegin: 0,
|
|
32983
|
-
animationDuration: 1200,
|
|
32984
|
-
animationEasing: "ease-out",
|
|
32985
|
-
onAnimationEnd: handleAnimationEnd
|
|
32986
|
-
},
|
|
32987
|
-
`${effectiveDatasetKey}:cycle`
|
|
32988
|
-
),
|
|
32989
|
-
showIdleTime && /* @__PURE__ */ jsxRuntime.jsx(
|
|
32990
|
-
recharts.Line,
|
|
32991
|
-
{
|
|
32992
|
-
type: "monotone",
|
|
32993
|
-
yAxisId: "idle",
|
|
32994
|
-
dataKey: "idleMinutes",
|
|
32995
|
-
stroke: "#f59e0b",
|
|
32996
|
-
strokeWidth: 2,
|
|
32997
|
-
strokeDasharray: "4 4",
|
|
32998
|
-
connectNulls: false,
|
|
32999
|
-
dot: renderIdleDot,
|
|
33000
|
-
activeDot: renderIdleActiveDot,
|
|
33001
|
-
isAnimationActive: shouldAnimate,
|
|
33002
|
-
animationBegin: 0,
|
|
33003
|
-
animationDuration: 1200,
|
|
33004
|
-
animationEasing: "ease-out"
|
|
32887
|
+
initial: { opacity: 0 },
|
|
32888
|
+
animate: { opacity: 1 },
|
|
32889
|
+
transition: { duration: 0.5 },
|
|
32890
|
+
className: "w-full h-full",
|
|
32891
|
+
children: dimensions.width > 0 && dimensions.height > 0 && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
32892
|
+
recharts.LineChart,
|
|
32893
|
+
{
|
|
32894
|
+
width: dimensions.width,
|
|
32895
|
+
height: dimensions.height,
|
|
32896
|
+
data: chartData,
|
|
32897
|
+
margin: {
|
|
32898
|
+
top: 5,
|
|
32899
|
+
right: 30,
|
|
32900
|
+
bottom: 25,
|
|
32901
|
+
left: 10
|
|
33005
32902
|
},
|
|
33006
|
-
|
|
33007
|
-
|
|
33008
|
-
|
|
32903
|
+
children: [
|
|
32904
|
+
/* @__PURE__ */ jsxRuntime.jsx(recharts.CartesianGrid, { strokeDasharray: "3 3", vertical: false }),
|
|
32905
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
32906
|
+
recharts.XAxis,
|
|
32907
|
+
{
|
|
32908
|
+
dataKey: "label",
|
|
32909
|
+
tick: { fontSize: 11 },
|
|
32910
|
+
interval: 0,
|
|
32911
|
+
angle: xAxisMode === "hourly" ? 0 : -30,
|
|
32912
|
+
textAnchor: xAxisMode === "hourly" ? "middle" : "end",
|
|
32913
|
+
tickMargin: xAxisMode === "hourly" ? 8 : 15,
|
|
32914
|
+
height: xAxisMode === "hourly" ? 40 : 60
|
|
32915
|
+
}
|
|
32916
|
+
),
|
|
32917
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
32918
|
+
recharts.YAxis,
|
|
32919
|
+
{
|
|
32920
|
+
tickMargin: 8,
|
|
32921
|
+
width: 45,
|
|
32922
|
+
yAxisId: "cycle",
|
|
32923
|
+
domain: ["auto", "auto"],
|
|
32924
|
+
ticks: [0, idealCycleTime, ...Array.from({ length: 4 }, (_, i) => (i + 1) * Math.ceil(idealCycleTime / 2))].sort((a, b) => a - b),
|
|
32925
|
+
tickFormatter: (value) => String(value),
|
|
32926
|
+
tick: (props) => {
|
|
32927
|
+
const { x, y, payload } = props;
|
|
32928
|
+
const displayValue = typeof payload.value === "number" ? payload.value.toFixed(1) : String(payload.value);
|
|
32929
|
+
return /* @__PURE__ */ jsxRuntime.jsx("g", { transform: `translate(${x},${y})`, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
32930
|
+
"text",
|
|
32931
|
+
{
|
|
32932
|
+
x: 0,
|
|
32933
|
+
y: 0,
|
|
32934
|
+
dy: 4,
|
|
32935
|
+
textAnchor: "end",
|
|
32936
|
+
fill: payload.value === idealCycleTime ? "#E34329" : "#666",
|
|
32937
|
+
fontSize: 12,
|
|
32938
|
+
fontWeight: payload.value === idealCycleTime ? "bold" : "normal",
|
|
32939
|
+
children: displayValue
|
|
32940
|
+
},
|
|
32941
|
+
`tick-${payload.value}-${x}-${y}`
|
|
32942
|
+
) });
|
|
32943
|
+
}
|
|
32944
|
+
}
|
|
32945
|
+
),
|
|
32946
|
+
showIdleTime && /* @__PURE__ */ jsxRuntime.jsx(
|
|
32947
|
+
recharts.YAxis,
|
|
32948
|
+
{
|
|
32949
|
+
yAxisId: "idle",
|
|
32950
|
+
orientation: "right",
|
|
32951
|
+
tickMargin: 8,
|
|
32952
|
+
width: 35,
|
|
32953
|
+
domain: [0, 60],
|
|
32954
|
+
tickFormatter: (value) => `${value}m`,
|
|
32955
|
+
tick: { fontSize: 11, fill: "#f59e0b" },
|
|
32956
|
+
axisLine: false,
|
|
32957
|
+
tickLine: false
|
|
32958
|
+
}
|
|
32959
|
+
),
|
|
32960
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
32961
|
+
recharts.Tooltip,
|
|
32962
|
+
{
|
|
32963
|
+
cursor: { stroke: "#E5E7EB", strokeWidth: 1 },
|
|
32964
|
+
content: renderChartTooltip,
|
|
32965
|
+
animationDuration: 200
|
|
32966
|
+
}
|
|
32967
|
+
),
|
|
32968
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
32969
|
+
recharts.ReferenceLine,
|
|
32970
|
+
{
|
|
32971
|
+
y: idealCycleTime,
|
|
32972
|
+
yAxisId: "cycle",
|
|
32973
|
+
stroke: "#E34329",
|
|
32974
|
+
strokeDasharray: "3 3",
|
|
32975
|
+
strokeWidth: 2,
|
|
32976
|
+
label: {
|
|
32977
|
+
position: "right",
|
|
32978
|
+
value: `${idealCycleTime.toFixed(1)}s`,
|
|
32979
|
+
fill: "#E34329",
|
|
32980
|
+
fontSize: 12,
|
|
32981
|
+
fontWeight: 500
|
|
32982
|
+
}
|
|
32983
|
+
}
|
|
32984
|
+
),
|
|
32985
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
32986
|
+
recharts.Line,
|
|
32987
|
+
{
|
|
32988
|
+
type: "monotone",
|
|
32989
|
+
yAxisId: "cycle",
|
|
32990
|
+
dataKey: "cycleTime",
|
|
32991
|
+
stroke: "#3B82F6",
|
|
32992
|
+
strokeWidth: 2,
|
|
32993
|
+
connectNulls: false,
|
|
32994
|
+
dot: renderCycleDot,
|
|
32995
|
+
activeDot: renderCycleActiveDot,
|
|
32996
|
+
isAnimationActive: true,
|
|
32997
|
+
animationBegin: 300,
|
|
32998
|
+
animationDuration: 1500,
|
|
32999
|
+
animationEasing: "ease-out"
|
|
33000
|
+
},
|
|
33001
|
+
`${effectiveDatasetKey}:cycle`
|
|
33002
|
+
),
|
|
33003
|
+
showIdleTime && /* @__PURE__ */ jsxRuntime.jsx(
|
|
33004
|
+
recharts.Line,
|
|
33005
|
+
{
|
|
33006
|
+
type: "monotone",
|
|
33007
|
+
yAxisId: "idle",
|
|
33008
|
+
dataKey: "idleMinutes",
|
|
33009
|
+
stroke: "#f59e0b",
|
|
33010
|
+
strokeWidth: 2,
|
|
33011
|
+
strokeDasharray: "4 4",
|
|
33012
|
+
connectNulls: false,
|
|
33013
|
+
dot: renderIdleDot,
|
|
33014
|
+
activeDot: renderIdleActiveDot,
|
|
33015
|
+
isAnimationActive: true,
|
|
33016
|
+
animationBegin: 300,
|
|
33017
|
+
animationDuration: 1500,
|
|
33018
|
+
animationEasing: "ease-out"
|
|
33019
|
+
},
|
|
33020
|
+
`${effectiveDatasetKey}:idle`
|
|
33021
|
+
)
|
|
33022
|
+
]
|
|
33023
|
+
},
|
|
33024
|
+
hasValidData ? "valid" : "empty"
|
|
33025
|
+
)
|
|
33009
33026
|
}
|
|
33010
|
-
) })
|
|
33027
|
+
) })
|
|
33011
33028
|
]
|
|
33012
33029
|
}
|
|
33013
33030
|
);
|
|
@@ -33857,10 +33874,10 @@ var HourlyOutputChart = React141__namespace.default.memo(HourlyOutputChartCompon
|
|
|
33857
33874
|
HourlyOutputChart.displayName = "HourlyOutputChart";
|
|
33858
33875
|
|
|
33859
33876
|
// src/components/dashboard/grid/videoGridMetricUtils.ts
|
|
33860
|
-
var VIDEO_GRID_LEGEND_LABEL = "
|
|
33877
|
+
var VIDEO_GRID_LEGEND_LABEL = "7 Minute Efficiency";
|
|
33861
33878
|
var MAP_GRID_LEGEND_LABEL = "Efficiency";
|
|
33862
|
-
var MIXED_VIDEO_GRID_LEGEND_LABEL = "
|
|
33863
|
-
var
|
|
33879
|
+
var MIXED_VIDEO_GRID_LEGEND_LABEL = "Efficiency";
|
|
33880
|
+
var isFiniteNumber = (value) => typeof value === "number" && Number.isFinite(value);
|
|
33864
33881
|
var isVideoGridRecentFlowEnabled = (workspace) => isRecentFlowVideoGridMetricMode(
|
|
33865
33882
|
workspace.video_grid_metric_mode,
|
|
33866
33883
|
workspace.assembly_enabled === true
|
|
@@ -33869,11 +33886,11 @@ var isVideoGridWipGated = (workspace) => isWipGatedVideoGridMetricMode(
|
|
|
33869
33886
|
workspace.video_grid_metric_mode,
|
|
33870
33887
|
workspace.assembly_enabled === true
|
|
33871
33888
|
);
|
|
33872
|
-
var hasVideoGridRecentFlow = (workspace) => isVideoGridRecentFlowEnabled(workspace) &&
|
|
33889
|
+
var hasVideoGridRecentFlow = (workspace) => isVideoGridRecentFlowEnabled(workspace) && isFiniteNumber(workspace.recent_flow_percent);
|
|
33873
33890
|
var isVideoGridRecentFlowUnavailable = (workspace) => isVideoGridRecentFlowEnabled(workspace) && !hasVideoGridRecentFlow(workspace);
|
|
33874
33891
|
var getVideoGridMetricValue = (workspace) => {
|
|
33875
33892
|
const recentFlowPercent = workspace.recent_flow_percent;
|
|
33876
|
-
if (hasVideoGridRecentFlow(workspace) &&
|
|
33893
|
+
if (hasVideoGridRecentFlow(workspace) && isFiniteNumber(recentFlowPercent)) {
|
|
33877
33894
|
return recentFlowPercent;
|
|
33878
33895
|
}
|
|
33879
33896
|
if (isVideoGridRecentFlowUnavailable(workspace)) {
|
|
@@ -33884,7 +33901,7 @@ var getVideoGridMetricValue = (workspace) => {
|
|
|
33884
33901
|
var hasIncomingWipMapping = (workspace) => Boolean(workspace.incoming_wip_buffer_name);
|
|
33885
33902
|
var getVideoGridBaseColorState = (workspace, legend = DEFAULT_EFFICIENCY_LEGEND) => {
|
|
33886
33903
|
const metricValue = getVideoGridMetricValue(workspace);
|
|
33887
|
-
if (!
|
|
33904
|
+
if (!isFiniteNumber(metricValue)) {
|
|
33888
33905
|
return "neutral";
|
|
33889
33906
|
}
|
|
33890
33907
|
return getEfficiencyColor(metricValue, legend);
|
|
@@ -33899,7 +33916,7 @@ var isLowWipGreenOverride = (workspace, legend = DEFAULT_EFFICIENCY_LEGEND) => {
|
|
|
33899
33916
|
if (!hasIncomingWipMapping(workspace)) {
|
|
33900
33917
|
return false;
|
|
33901
33918
|
}
|
|
33902
|
-
return
|
|
33919
|
+
return isFiniteNumber(workspace.incoming_wip_current) && workspace.incoming_wip_current <= 1;
|
|
33903
33920
|
};
|
|
33904
33921
|
var toMinuteBucket = (minuteBucket) => Number.isFinite(minuteBucket) ? Math.floor(minuteBucket) : Math.floor(Date.now() / 6e4);
|
|
33905
33922
|
var getEffectiveFlowMinuteBucket = (workspace) => {
|
|
@@ -33941,7 +33958,7 @@ var getVideoGridColorState = (workspace, legend = DEFAULT_EFFICIENCY_LEGEND) =>
|
|
|
33941
33958
|
if (!hasIncomingWipMapping(workspace)) {
|
|
33942
33959
|
return baseColor;
|
|
33943
33960
|
}
|
|
33944
|
-
if (!
|
|
33961
|
+
if (!isFiniteNumber(workspace.incoming_wip_current)) {
|
|
33945
33962
|
return "neutral";
|
|
33946
33963
|
}
|
|
33947
33964
|
if (isLowWipGreenOverride(workspace, legend)) {
|
|
@@ -34133,7 +34150,7 @@ var VideoCard = React141__namespace.default.memo(({
|
|
|
34133
34150
|
}
|
|
34134
34151
|
);
|
|
34135
34152
|
}, (prevProps, nextProps) => {
|
|
34136
|
-
if (prevProps.workspace.efficiency !== nextProps.workspace.efficiency || prevProps.workspace.assembly_enabled !== nextProps.workspace.assembly_enabled || prevProps.workspace.video_grid_metric_mode !== nextProps.workspace.video_grid_metric_mode || prevProps.workspace.
|
|
34153
|
+
if (prevProps.workspace.efficiency !== nextProps.workspace.efficiency || prevProps.workspace.assembly_enabled !== nextProps.workspace.assembly_enabled || prevProps.workspace.video_grid_metric_mode !== nextProps.workspace.video_grid_metric_mode || prevProps.workspace.recent_flow_percent !== nextProps.workspace.recent_flow_percent || prevProps.workspace.recent_flow_effective_end_at !== nextProps.workspace.recent_flow_effective_end_at || prevProps.workspace.incoming_wip_current !== nextProps.workspace.incoming_wip_current || prevProps.workspace.incoming_wip_buffer_name !== nextProps.workspace.incoming_wip_buffer_name || prevProps.workspace.trend !== nextProps.workspace.trend || prevProps.workspace.performance_score !== nextProps.workspace.performance_score || prevProps.workspace.pph !== nextProps.workspace.pph) {
|
|
34137
34154
|
return false;
|
|
34138
34155
|
}
|
|
34139
34156
|
if (prevProps.workspace.workspace_uuid !== nextProps.workspace.workspace_uuid || prevProps.workspace.workspace_name !== nextProps.workspace.workspace_name || prevProps.workspace.line_id !== nextProps.workspace.line_id) {
|
|
@@ -44601,7 +44618,7 @@ var ShiftDisplay = React141.memo(({ className, variant = "default", lineId }) =>
|
|
|
44601
44618
|
return null;
|
|
44602
44619
|
}
|
|
44603
44620
|
};
|
|
44604
|
-
const
|
|
44621
|
+
const getShiftIcon2 = (shift) => {
|
|
44605
44622
|
if (shift === "Day") {
|
|
44606
44623
|
return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ jsxRuntime.jsx("path", { fillRule: "evenodd", d: "M10 2a1 1 0 011 1v1a1 1 0 11-2 0V3a1 1 0 011-1zm4 8a4 4 0 11-8 0 4 4 0 018 0zm-.464 4.95l.707.707a1 1 0 001.414-1.414l-.707-.707a1 1 0 00-1.414 1.414zm2.12-10.607a1 1 0 010 1.414l-.706.707a1 1 0 11-1.414-1.414l.707-.707a1 1 0 011.414 0zM17 11a1 1 0 100-2h-1a1 1 0 100 2h1zm-7 4a1 1 0 011 1v1a1 1 0 11-2 0v-1a1 1 0 011-1zM5.05 6.464A1 1 0 106.465 5.05l-.708-.707a1 1 0 00-1.414 1.414l.707.707zm1.414 8.486l-.707.707a1 1 0 01-1.414-1.414l.707-.707a1 1 0 011.414 1.414zM4 11a1 1 0 100-2H3a1 1 0 000 2h1z", clipRule: "evenodd" }) });
|
|
44607
44624
|
} else {
|
|
@@ -44627,7 +44644,7 @@ var ShiftDisplay = React141.memo(({ className, variant = "default", lineId }) =>
|
|
|
44627
44644
|
}
|
|
44628
44645
|
if (variant === "enhanced") {
|
|
44629
44646
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `inline-flex items-center gap-2 bg-blue-50 rounded-lg px-3 py-1.5 ${className ?? ""}`, children: [
|
|
44630
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-blue-800", children:
|
|
44647
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-blue-800", children: getShiftIcon2(currentShiftText) }),
|
|
44631
44648
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-base font-medium text-blue-800", children: [
|
|
44632
44649
|
currentShiftText,
|
|
44633
44650
|
" Shift"
|
|
@@ -44635,7 +44652,7 @@ var ShiftDisplay = React141.memo(({ className, variant = "default", lineId }) =>
|
|
|
44635
44652
|
] });
|
|
44636
44653
|
}
|
|
44637
44654
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `inline-flex items-center gap-2 bg-blue-50 rounded-lg px-3 py-1.5 ${className ?? ""}`, children: [
|
|
44638
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-blue-800", children:
|
|
44655
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-blue-800", children: getShiftIcon2(currentShiftText) }),
|
|
44639
44656
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-base font-medium text-blue-800", children: [
|
|
44640
44657
|
currentShiftText,
|
|
44641
44658
|
" Shift"
|
|
@@ -47272,7 +47289,7 @@ var LinePdfGenerator = ({
|
|
|
47272
47289
|
doc.setLineWidth(0.8);
|
|
47273
47290
|
doc.line(20, 123, 190, 123);
|
|
47274
47291
|
const hourlyOverviewStartY = 128;
|
|
47275
|
-
const
|
|
47292
|
+
const parseTimeToMinutes4 = (timeStr) => {
|
|
47276
47293
|
const [hours, minutes] = timeStr.split(":");
|
|
47277
47294
|
const hour = parseInt(hours, 10);
|
|
47278
47295
|
const minute = parseInt(minutes || "0", 10);
|
|
@@ -47305,7 +47322,7 @@ var LinePdfGenerator = ({
|
|
|
47305
47322
|
};
|
|
47306
47323
|
};
|
|
47307
47324
|
const getHourlyTimeRanges = (startTimeStr, endTimeStr) => {
|
|
47308
|
-
const startMinutes =
|
|
47325
|
+
const startMinutes = parseTimeToMinutes4(startTimeStr);
|
|
47309
47326
|
if (Number.isNaN(startMinutes)) {
|
|
47310
47327
|
return [];
|
|
47311
47328
|
}
|
|
@@ -47313,7 +47330,7 @@ var LinePdfGenerator = ({
|
|
|
47313
47330
|
const defaultHours = 11;
|
|
47314
47331
|
return Array.from({ length: defaultHours }, (_, i) => buildRange(startMinutes + i * 60, 60));
|
|
47315
47332
|
}
|
|
47316
|
-
const endMinutes =
|
|
47333
|
+
const endMinutes = parseTimeToMinutes4(endTimeStr);
|
|
47317
47334
|
if (Number.isNaN(endMinutes)) {
|
|
47318
47335
|
const fallbackHours = 11;
|
|
47319
47336
|
return Array.from({ length: fallbackHours }, (_, i) => buildRange(startMinutes + i * 60, 60));
|
|
@@ -49082,7 +49099,7 @@ var WorkspacePdfGenerator = ({ workspace, className, idleTimeReasons, efficiency
|
|
|
49082
49099
|
minute: "2-digit",
|
|
49083
49100
|
hour12: true
|
|
49084
49101
|
});
|
|
49085
|
-
const
|
|
49102
|
+
const parseTimeToMinutes4 = (timeValue) => {
|
|
49086
49103
|
const [hourPart, minutePart] = timeValue.split(":").map(Number);
|
|
49087
49104
|
const hour = Number.isFinite(hourPart) ? hourPart : 0;
|
|
49088
49105
|
const minute = Number.isFinite(minutePart) ? minutePart : 0;
|
|
@@ -49099,8 +49116,8 @@ var WorkspacePdfGenerator = ({ workspace, className, idleTimeReasons, efficiency
|
|
|
49099
49116
|
const IST_OFFSET_MINUTES = 330;
|
|
49100
49117
|
return Date.UTC(year, month - 1, day, hour, minute) - IST_OFFSET_MINUTES * 60 * 1e3;
|
|
49101
49118
|
};
|
|
49102
|
-
const shiftStartMinutes =
|
|
49103
|
-
const shiftEndMinutes =
|
|
49119
|
+
const shiftStartMinutes = parseTimeToMinutes4(workspace.shift_start);
|
|
49120
|
+
const shiftEndMinutes = parseTimeToMinutes4(workspace.shift_end);
|
|
49104
49121
|
const wrapsMidnight = shiftEndMinutes <= shiftStartMinutes;
|
|
49105
49122
|
const shiftStartUtcMs = toShiftUtcMs(workspace.date, workspace.shift_start);
|
|
49106
49123
|
const shiftEndUtcMs = toShiftUtcMs(workspace.date, workspace.shift_end) + (wrapsMidnight ? 24 * 60 * 60 * 1e3 : 0);
|
|
@@ -51407,7 +51424,7 @@ var DashboardHeader = React141.memo(({ lineTitle, className = "", headerControls
|
|
|
51407
51424
|
const rawName = currentShift.shiftName || "Day";
|
|
51408
51425
|
return rawName.toLowerCase().includes("shift") ? rawName : `${rawName} Shift`;
|
|
51409
51426
|
};
|
|
51410
|
-
const
|
|
51427
|
+
const getShiftIcon2 = () => {
|
|
51411
51428
|
const currentShift = getCurrentShift(timezone, shiftConfig);
|
|
51412
51429
|
const shiftName = (currentShift.shiftName || "").toLowerCase();
|
|
51413
51430
|
if (shiftName.includes("day") || shiftName.includes("morning") || currentShift.shiftId === 0) {
|
|
@@ -51441,7 +51458,7 @@ var DashboardHeader = React141.memo(({ lineTitle, className = "", headerControls
|
|
|
51441
51458
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: /* @__PURE__ */ jsxRuntime.jsx(Timer2, {}) }),
|
|
51442
51459
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-gray-300", children: "|" }),
|
|
51443
51460
|
isShiftConfigLoading ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-3.5 w-16 bg-gray-200 rounded animate-pulse" }) : /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1 font-medium", children: [
|
|
51444
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "opacity-75", children:
|
|
51461
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "opacity-75", children: getShiftIcon2() }),
|
|
51445
51462
|
getShiftName()
|
|
51446
51463
|
] })
|
|
51447
51464
|
] })
|
|
@@ -51458,7 +51475,7 @@ var DashboardHeader = React141.memo(({ lineTitle, className = "", headerControls
|
|
|
51458
51475
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-2 inline-flex flex-wrap items-center gap-3", children: [
|
|
51459
51476
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs md:text-sm font-medium text-gray-600 whitespace-nowrap", children: /* @__PURE__ */ jsxRuntime.jsx(Timer2, {}) }),
|
|
51460
51477
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "inline-flex items-center gap-1", children: isShiftConfigLoading ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-4 w-20 bg-gray-200 rounded animate-pulse" }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
51461
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-gray-600", children:
|
|
51478
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-gray-600", children: getShiftIcon2() }),
|
|
51462
51479
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs md:text-sm font-medium text-gray-600 whitespace-nowrap", children: getShiftName() })
|
|
51463
51480
|
] }) })
|
|
51464
51481
|
] })
|
|
@@ -58429,7 +58446,7 @@ var FactoryView = ({
|
|
|
58429
58446
|
const currentShift = getCurrentShiftInfo();
|
|
58430
58447
|
return (currentShift.shiftName || "Day").replace(/ Shift$/i, "");
|
|
58431
58448
|
};
|
|
58432
|
-
const
|
|
58449
|
+
const getShiftIcon2 = () => {
|
|
58433
58450
|
const currentShift = getCurrentShiftInfo();
|
|
58434
58451
|
const shiftNameLower = (currentShift.shiftName || "").toLowerCase();
|
|
58435
58452
|
if (shiftNameLower.includes("day") || shiftNameLower.includes("morning") || currentShift.shiftId === 0) {
|
|
@@ -58475,7 +58492,7 @@ var FactoryView = ({
|
|
|
58475
58492
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-2 flex items-center justify-center gap-2", children: [
|
|
58476
58493
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "inline-flex items-center px-2.5 py-1 bg-gray-100 rounded-full", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-gray-700", children: /* @__PURE__ */ jsxRuntime.jsx(ISTTimer_default, {}) }) }),
|
|
58477
58494
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "inline-flex items-center gap-1 px-2.5 py-1 bg-gray-100 rounded-full", children: [
|
|
58478
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-gray-700 scale-90", children:
|
|
58495
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-gray-700 scale-90", children: getShiftIcon2() }),
|
|
58479
58496
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs font-medium text-gray-700", children: [
|
|
58480
58497
|
getShiftName(),
|
|
58481
58498
|
" Shift"
|
|
@@ -58494,7 +58511,7 @@ var FactoryView = ({
|
|
|
58494
58511
|
" IST"
|
|
58495
58512
|
] }),
|
|
58496
58513
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "inline-flex items-center gap-1", children: [
|
|
58497
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-gray-600", children:
|
|
58514
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-gray-600", children: getShiftIcon2() }),
|
|
58498
58515
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-sm font-medium text-gray-600", children: [
|
|
58499
58516
|
getShiftName(),
|
|
58500
58517
|
" Shift"
|
|
@@ -61206,7 +61223,7 @@ var KPIDetailView = ({
|
|
|
61206
61223
|
const getShiftName = React141.useCallback((shiftId) => {
|
|
61207
61224
|
return getShiftNameById(shiftId, configuredTimezone, shiftConfig);
|
|
61208
61225
|
}, [configuredTimezone, shiftConfig]);
|
|
61209
|
-
const
|
|
61226
|
+
const getShiftIcon2 = React141.useCallback((shiftId) => {
|
|
61210
61227
|
if (shiftId === 0) {
|
|
61211
61228
|
return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" }) });
|
|
61212
61229
|
}
|
|
@@ -62086,7 +62103,7 @@ var KPIDetailView = ({
|
|
|
62086
62103
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "sm:hidden mt-3 flex items-center justify-center gap-2", children: [
|
|
62087
62104
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "inline-flex items-center px-2.5 py-1 bg-gray-100 rounded-full", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-gray-700", children: chartMetrics && formatLocalDate(new Date(chartMetrics.date)) }) }),
|
|
62088
62105
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "inline-flex items-center gap-1 px-2.5 py-1 bg-gray-100 rounded-full", children: [
|
|
62089
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-gray-700 scale-90", children:
|
|
62106
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-gray-700 scale-90", children: getShiftIcon2(chartMetrics.shift_id ?? 0) }),
|
|
62090
62107
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs font-medium text-gray-700", children: [
|
|
62091
62108
|
getShiftName(chartMetrics.shift_id ?? 0).replace(/ Shift$/i, ""),
|
|
62092
62109
|
" Shift"
|
|
@@ -62112,7 +62129,7 @@ var KPIDetailView = ({
|
|
|
62112
62129
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-px h-4 bg-blue-200" })
|
|
62113
62130
|
] }),
|
|
62114
62131
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-blue-600", children: [
|
|
62115
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "opacity-70", children:
|
|
62132
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "opacity-70", children: getShiftIcon2(chartMetrics.shift_id ?? 0) }),
|
|
62116
62133
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-sm md:text-base font-semibold uppercase tracking-wider", children: [
|
|
62117
62134
|
getShiftName(chartMetrics.shift_id ?? 0).replace(/ Shift$/i, ""),
|
|
62118
62135
|
" Shift"
|
|
@@ -62130,7 +62147,7 @@ var KPIDetailView = ({
|
|
|
62130
62147
|
return `${startDate.toLocaleDateString("en-US", { month: "short", day: "numeric" })} - ${endDate.toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" })}`;
|
|
62131
62148
|
})() }) }),
|
|
62132
62149
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "inline-flex items-center gap-1 px-2.5 py-1 bg-gray-100 rounded-full", children: [
|
|
62133
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-gray-700 scale-90", children:
|
|
62150
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-gray-700 scale-90", children: getShiftIcon2(selectedShiftId) }),
|
|
62134
62151
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-gray-700", children: getShiftName(selectedShiftId) })
|
|
62135
62152
|
] })
|
|
62136
62153
|
] }),
|
|
@@ -62147,7 +62164,7 @@ var KPIDetailView = ({
|
|
|
62147
62164
|
] }),
|
|
62148
62165
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-px h-4 bg-blue-200" }),
|
|
62149
62166
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-blue-600", children: [
|
|
62150
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "opacity-70", children:
|
|
62167
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "opacity-70", children: getShiftIcon2(selectedShiftId) }),
|
|
62151
62168
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-sm md:text-base font-semibold uppercase tracking-wider", children: [
|
|
62152
62169
|
getShiftName(selectedShiftId).replace(/ Shift$/i, ""),
|
|
62153
62170
|
" Shift"
|
|
@@ -63523,7 +63540,7 @@ var KPIsOverviewView = ({
|
|
|
63523
63540
|
const headerShiftId = showHistoricalLeaderboardHeader ? effectiveLeaderboardShiftId : currentShiftDetails.shiftId;
|
|
63524
63541
|
const headerShiftName = getShiftNameById(headerShiftId, configuredTimezone, shiftConfig).replace(/ Shift$/i, "");
|
|
63525
63542
|
const headerDateLabel = isMonthlyMode ? getMonthRange() : formatLocalDate2(headerDateKey);
|
|
63526
|
-
const
|
|
63543
|
+
const getShiftIcon2 = (shiftId) => {
|
|
63527
63544
|
const shiftNameLower = getShiftNameById(shiftId, configuredTimezone, shiftConfig).toLowerCase();
|
|
63528
63545
|
if (shiftNameLower.includes("day") || shiftNameLower.includes("morning") || shiftId === 0) {
|
|
63529
63546
|
return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" }) });
|
|
@@ -63640,7 +63657,7 @@ var KPIsOverviewView = ({
|
|
|
63640
63657
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: `inline-flex items-center bg-gray-100 rounded-full ${isMonthlyMode ? "px-4 py-1.5 ring-1 ring-gray-200 shadow-sm" : "px-2.5 py-1"}`, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: `font-medium text-gray-700 ${isMonthlyMode ? "text-sm" : "text-xs"}`, children: headerDateLabel }) }),
|
|
63641
63658
|
!isMonthlyMode && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
63642
63659
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "inline-flex items-center gap-1 px-2.5 py-1 bg-gray-100 rounded-full", children: [
|
|
63643
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-gray-700 scale-90", children:
|
|
63660
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-gray-700 scale-90", children: getShiftIcon2(headerShiftId) }),
|
|
63644
63661
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-gray-700", children: headerShiftName })
|
|
63645
63662
|
] }),
|
|
63646
63663
|
showHistoricalLeaderboardHeader ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "inline-flex items-center gap-1 px-2.5 py-1 bg-amber-50 text-amber-700 rounded-full", children: [
|
|
@@ -63836,7 +63853,7 @@ var KPIsOverviewView = ({
|
|
|
63836
63853
|
!isMonthlyMode && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
63837
63854
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-px h-4 bg-blue-200" }),
|
|
63838
63855
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-blue-600", children: [
|
|
63839
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "opacity-70", children:
|
|
63856
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "opacity-70", children: getShiftIcon2(headerShiftId) }),
|
|
63840
63857
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-sm font-semibold uppercase tracking-wider", children: [
|
|
63841
63858
|
headerShiftName,
|
|
63842
63859
|
" Shift"
|
|
@@ -63980,6 +63997,52 @@ var KPIsOverviewView = ({
|
|
|
63980
63997
|
] });
|
|
63981
63998
|
};
|
|
63982
63999
|
var KPIsOverviewView_default = KPIsOverviewView;
|
|
64000
|
+
var toFiniteNumber = (value) => {
|
|
64001
|
+
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
64002
|
+
if (typeof value === "string" && value.trim() !== "") {
|
|
64003
|
+
const parsed = Number(value);
|
|
64004
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
64005
|
+
}
|
|
64006
|
+
return null;
|
|
64007
|
+
};
|
|
64008
|
+
var getCycleRatio = (workspace) => {
|
|
64009
|
+
const idealCycleTime = toFiniteNumber(workspace.ideal_cycle_time);
|
|
64010
|
+
const avgCycleTime = toFiniteNumber(workspace.avg_cycle_time);
|
|
64011
|
+
if (idealCycleTime === null || avgCycleTime === null || idealCycleTime <= 0 || avgCycleTime <= 0) {
|
|
64012
|
+
return null;
|
|
64013
|
+
}
|
|
64014
|
+
return idealCycleTime / avgCycleTime;
|
|
64015
|
+
};
|
|
64016
|
+
var formatCycleTimeValue = (value) => {
|
|
64017
|
+
const numericValue = toFiniteNumber(value);
|
|
64018
|
+
if (numericValue === null || numericValue <= 0) return "--";
|
|
64019
|
+
return `${numericValue.toFixed(1)}s`;
|
|
64020
|
+
};
|
|
64021
|
+
var CycleTimeComparison = React141.memo(({
|
|
64022
|
+
workspace,
|
|
64023
|
+
variant = "table"
|
|
64024
|
+
}) => {
|
|
64025
|
+
const averageValue = formatCycleTimeValue(workspace.avg_cycle_time);
|
|
64026
|
+
const standardValue = formatCycleTimeValue(workspace.ideal_cycle_time);
|
|
64027
|
+
if (variant === "mobile") {
|
|
64028
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-2 flex items-center justify-between py-2 border-t border-gray-100", children: [
|
|
64029
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-gray-500 uppercase tracking-wider", children: "Standard Cycle Time" }),
|
|
64030
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-medium tabular-nums text-gray-500", children: standardValue })
|
|
64031
|
+
] });
|
|
64032
|
+
}
|
|
64033
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
|
|
64034
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col", children: [
|
|
64035
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] font-medium uppercase tracking-wider text-gray-500", children: "Average" }),
|
|
64036
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-semibold tabular-nums text-gray-900", children: averageValue })
|
|
64037
|
+
] }),
|
|
64038
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-6 w-px bg-gray-200" }),
|
|
64039
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col", children: [
|
|
64040
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] font-medium uppercase tracking-wider text-gray-500", children: "Standard" }),
|
|
64041
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-medium tabular-nums text-gray-500", children: standardValue })
|
|
64042
|
+
] })
|
|
64043
|
+
] });
|
|
64044
|
+
}, (prevProps, nextProps) => prevProps.variant === nextProps.variant && prevProps.workspace.avg_cycle_time === nextProps.workspace.avg_cycle_time && prevProps.workspace.ideal_cycle_time === nextProps.workspace.ideal_cycle_time);
|
|
64045
|
+
CycleTimeComparison.displayName = "CycleTimeComparison";
|
|
63983
64046
|
var IsolatedTimer = React141.memo(() => {
|
|
63984
64047
|
return /* @__PURE__ */ jsxRuntime.jsx(ISTTimer_default, {});
|
|
63985
64048
|
});
|
|
@@ -63997,11 +64060,11 @@ var HeaderRibbon = React141.memo(({
|
|
|
63997
64060
|
currentDate,
|
|
63998
64061
|
currentMobileDate,
|
|
63999
64062
|
shiftId,
|
|
64000
|
-
getShiftIcon,
|
|
64063
|
+
getShiftIcon: getShiftIcon2,
|
|
64001
64064
|
getShiftName,
|
|
64002
64065
|
showTimer = true
|
|
64003
64066
|
}) => {
|
|
64004
|
-
const shiftIcon = React141.useMemo(() =>
|
|
64067
|
+
const shiftIcon = React141.useMemo(() => getShiftIcon2(shiftId), [getShiftIcon2, shiftId]);
|
|
64005
64068
|
const shiftName = React141.useMemo(() => getShiftName(shiftId), [getShiftName, shiftId]);
|
|
64006
64069
|
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
64007
64070
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "sm:hidden mt-3 flex items-center justify-center gap-2", children: [
|
|
@@ -64043,8 +64106,9 @@ var MobileWorkspaceCard = React141.memo(({
|
|
|
64043
64106
|
isClickable,
|
|
64044
64107
|
onWorkspaceClick,
|
|
64045
64108
|
getMedalIcon,
|
|
64046
|
-
|
|
64047
|
-
|
|
64109
|
+
metricLabel,
|
|
64110
|
+
isAssemblyMode
|
|
64111
|
+
}) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
64048
64112
|
motion.div,
|
|
64049
64113
|
{
|
|
64050
64114
|
layout: true,
|
|
@@ -64055,28 +64119,31 @@ var MobileWorkspaceCard = React141.memo(({
|
|
|
64055
64119
|
},
|
|
64056
64120
|
onClick: isClickable ? () => onWorkspaceClick(workspace, rank) : void 0,
|
|
64057
64121
|
className: `${cardClass} p-3 rounded-lg border shadow-sm active:scale-[0.98] ${isClickable ? "cursor-pointer" : "cursor-not-allowed opacity-75"}`,
|
|
64058
|
-
children:
|
|
64059
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
|
|
64060
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-
|
|
64061
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "
|
|
64062
|
-
"
|
|
64063
|
-
|
|
64122
|
+
children: [
|
|
64123
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between mb-2 gap-3", children: [
|
|
64124
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
|
|
64125
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
64126
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-2xl font-bold text-gray-700", children: [
|
|
64127
|
+
"#",
|
|
64128
|
+
rank
|
|
64129
|
+
] }),
|
|
64130
|
+
getMedalIcon(rank)
|
|
64064
64131
|
] }),
|
|
64065
|
-
|
|
64132
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
64133
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "font-semibold text-gray-900", children: workspace.displayName }),
|
|
64134
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-gray-500", children: workspace.lineName })
|
|
64135
|
+
] })
|
|
64066
64136
|
] }),
|
|
64067
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
64068
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "font-
|
|
64069
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-gray-500", children:
|
|
64137
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-right", children: [
|
|
64138
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "font-bold text-gray-900 text-lg", children: isAssemblyMode ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "tabular-nums", children: formatCycleTimeValue(workspace.avg_cycle_time) }) : /* @__PURE__ */ jsxRuntime.jsx(AnimatedEfficiency, { value: workspace.efficiency || 0 }) }),
|
|
64139
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-gray-500", children: metricLabel })
|
|
64070
64140
|
] })
|
|
64071
64141
|
] }),
|
|
64072
|
-
/* @__PURE__ */ jsxRuntime.
|
|
64073
|
-
|
|
64074
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-gray-500", children: efficiencyLabel })
|
|
64075
|
-
] })
|
|
64076
|
-
] })
|
|
64142
|
+
isAssemblyMode && /* @__PURE__ */ jsxRuntime.jsx(CycleTimeComparison, { workspace, variant: "mobile" })
|
|
64143
|
+
]
|
|
64077
64144
|
}
|
|
64078
64145
|
), (prevProps, nextProps) => {
|
|
64079
|
-
return prevProps.
|
|
64146
|
+
return prevProps.metricLabel === nextProps.metricLabel && prevProps.isAssemblyMode === nextProps.isAssemblyMode && prevProps.rank === nextProps.rank && prevProps.cardClass === nextProps.cardClass && prevProps.isClickable === nextProps.isClickable && prevProps.workspace.workspace_uuid === nextProps.workspace.workspace_uuid && prevProps.workspace.efficiency === nextProps.workspace.efficiency && prevProps.workspace.ideal_cycle_time === nextProps.workspace.ideal_cycle_time && prevProps.workspace.action_count === nextProps.workspace.action_count && prevProps.workspace.action_threshold === nextProps.workspace.action_threshold && prevProps.workspace.avg_cycle_time === nextProps.workspace.avg_cycle_time && prevProps.workspace.displayName === nextProps.workspace.displayName && prevProps.workspace.lineName === nextProps.workspace.lineName;
|
|
64080
64147
|
});
|
|
64081
64148
|
MobileWorkspaceCard.displayName = "MobileWorkspaceCard";
|
|
64082
64149
|
var DesktopWorkspaceRow = React141.memo(({
|
|
@@ -64085,7 +64152,8 @@ var DesktopWorkspaceRow = React141.memo(({
|
|
|
64085
64152
|
rowClass,
|
|
64086
64153
|
isClickable,
|
|
64087
64154
|
onWorkspaceClick,
|
|
64088
|
-
getMedalIcon
|
|
64155
|
+
getMedalIcon,
|
|
64156
|
+
isAssemblyMode
|
|
64089
64157
|
}) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
64090
64158
|
motion.tr,
|
|
64091
64159
|
{
|
|
@@ -64102,11 +64170,11 @@ var DesktopWorkspaceRow = React141.memo(({
|
|
|
64102
64170
|
] }) }),
|
|
64103
64171
|
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-3 py-2.5 sm:p-4 text-sm sm:text-base whitespace-nowrap", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "font-medium", children: workspace.displayName }) }),
|
|
64104
64172
|
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-3 py-2.5 sm:p-4 text-sm sm:text-base whitespace-nowrap", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "font-medium", children: workspace.lineName }) }),
|
|
64105
|
-
/* @__PURE__ */ jsxRuntime.jsx("td", { className:
|
|
64173
|
+
/* @__PURE__ */ jsxRuntime.jsx("td", { className: `px-3 py-2.5 sm:p-4 text-sm sm:text-base font-medium ${isAssemblyMode ? "" : "whitespace-nowrap"}`, children: isAssemblyMode ? /* @__PURE__ */ jsxRuntime.jsx(CycleTimeComparison, { workspace, variant: "table" }) : /* @__PURE__ */ jsxRuntime.jsx(AnimatedEfficiency, { value: workspace.efficiency || 0 }) })
|
|
64106
64174
|
]
|
|
64107
64175
|
}
|
|
64108
64176
|
), (prevProps, nextProps) => {
|
|
64109
|
-
return prevProps.index === nextProps.index && prevProps.rowClass === nextProps.rowClass && prevProps.isClickable === nextProps.isClickable && prevProps.workspace.workspace_uuid === nextProps.workspace.workspace_uuid && prevProps.workspace.efficiency === nextProps.workspace.efficiency && prevProps.workspace.displayName === nextProps.workspace.displayName && prevProps.workspace.lineName === nextProps.workspace.lineName;
|
|
64177
|
+
return prevProps.index === nextProps.index && prevProps.rowClass === nextProps.rowClass && prevProps.isClickable === nextProps.isClickable && prevProps.isAssemblyMode === nextProps.isAssemblyMode && prevProps.workspace.workspace_uuid === nextProps.workspace.workspace_uuid && prevProps.workspace.efficiency === nextProps.workspace.efficiency && prevProps.workspace.ideal_cycle_time === nextProps.workspace.ideal_cycle_time && prevProps.workspace.avg_cycle_time === nextProps.workspace.avg_cycle_time && prevProps.workspace.displayName === nextProps.workspace.displayName && prevProps.workspace.lineName === nextProps.workspace.lineName;
|
|
64110
64178
|
});
|
|
64111
64179
|
DesktopWorkspaceRow.displayName = "DesktopWorkspaceRow";
|
|
64112
64180
|
var LeaderboardDetailView = React141.memo(({
|
|
@@ -64128,6 +64196,7 @@ var LeaderboardDetailView = React141.memo(({
|
|
|
64128
64196
|
const supabase = useSupabase();
|
|
64129
64197
|
const [sortAscending, setSortAscending] = React141.useState(false);
|
|
64130
64198
|
const [viewType, setViewType] = React141.useState("operator");
|
|
64199
|
+
const [outputCategory, setOutputCategory] = React141.useState("standard");
|
|
64131
64200
|
const [activeTab, setActiveTab] = React141.useState("today");
|
|
64132
64201
|
const timezone = useAppTimezone();
|
|
64133
64202
|
const staticShiftConfig = useShiftConfig();
|
|
@@ -64206,6 +64275,7 @@ var LeaderboardDetailView = React141.memo(({
|
|
|
64206
64275
|
const monthlyRequestKeyRef = React141.useRef(null);
|
|
64207
64276
|
const leaderboardUpdateQueuedRef = React141.useRef(false);
|
|
64208
64277
|
const leaderboardUpdateTimerRef = React141.useRef(null);
|
|
64278
|
+
const leaderboardViewTrackedRef = React141.useRef(null);
|
|
64209
64279
|
const filterRef = React141.useRef(null);
|
|
64210
64280
|
const filterButtonRef = React141.useRef(null);
|
|
64211
64281
|
const mobileFilterButtonRef = React141.useRef(null);
|
|
@@ -64338,6 +64408,17 @@ var LeaderboardDetailView = React141.memo(({
|
|
|
64338
64408
|
}
|
|
64339
64409
|
return Array.from(uniqueLines.entries()).map(([id3, name]) => ({ id: id3, label: name }));
|
|
64340
64410
|
}, [configuredLineIds, lines, getLineName]);
|
|
64411
|
+
const scopedLines = React141.useMemo(() => {
|
|
64412
|
+
const configuredLineIdSet = new Set(configuredLineIds);
|
|
64413
|
+
return lines.filter((line) => configuredLineIds.length === 0 || configuredLineIdSet.has(line.id));
|
|
64414
|
+
}, [configuredLineIds, lines]);
|
|
64415
|
+
const scopedLineAssemblyMap = React141.useMemo(() => {
|
|
64416
|
+
const map = /* @__PURE__ */ new Map();
|
|
64417
|
+
scopedLines.forEach((line) => {
|
|
64418
|
+
map.set(line.id, line.assembly === true);
|
|
64419
|
+
});
|
|
64420
|
+
return map;
|
|
64421
|
+
}, [scopedLines]);
|
|
64341
64422
|
const shiftOptions = React141.useMemo(() => {
|
|
64342
64423
|
if (activeShiftConfig?.shifts && activeShiftConfig.shifts.length > 0) {
|
|
64343
64424
|
return activeShiftConfig.shifts.map((shift2) => ({
|
|
@@ -64361,6 +64442,33 @@ var LeaderboardDetailView = React141.memo(({
|
|
|
64361
64442
|
const parsed = Number(selectedShiftFilter);
|
|
64362
64443
|
return Number.isFinite(parsed) ? parsed : void 0;
|
|
64363
64444
|
}, [selectedShiftFilter]);
|
|
64445
|
+
const outputScopeLines = React141.useMemo(() => {
|
|
64446
|
+
const outputLines = scopedLines.filter((line) => (line.monitoring_mode ?? "output") !== "uptime");
|
|
64447
|
+
if (selectedLineFilter === "all") {
|
|
64448
|
+
return outputLines;
|
|
64449
|
+
}
|
|
64450
|
+
return outputLines.filter((line) => line.id === selectedLineFilter);
|
|
64451
|
+
}, [scopedLines, selectedLineFilter]);
|
|
64452
|
+
const hasAssemblyOutputScope = React141.useMemo(
|
|
64453
|
+
() => outputScopeLines.some((line) => line.assembly === true),
|
|
64454
|
+
[outputScopeLines]
|
|
64455
|
+
);
|
|
64456
|
+
const hasStandardOutputScope = React141.useMemo(
|
|
64457
|
+
() => outputScopeLines.some((line) => line.assembly !== true),
|
|
64458
|
+
[outputScopeLines]
|
|
64459
|
+
);
|
|
64460
|
+
const showOutputCategoryDropdown = viewType === "operator" && hasAssemblyOutputScope && hasStandardOutputScope;
|
|
64461
|
+
const isAssemblyMode = viewType === "operator" && outputCategory === "assembly";
|
|
64462
|
+
React141.useEffect(() => {
|
|
64463
|
+
if (viewType !== "operator") return;
|
|
64464
|
+
if (hasAssemblyOutputScope && !hasStandardOutputScope && outputCategory !== "assembly") {
|
|
64465
|
+
setOutputCategory("assembly");
|
|
64466
|
+
return;
|
|
64467
|
+
}
|
|
64468
|
+
if (hasStandardOutputScope && !hasAssemblyOutputScope && outputCategory !== "standard") {
|
|
64469
|
+
setOutputCategory("standard");
|
|
64470
|
+
}
|
|
64471
|
+
}, [viewType, hasAssemblyOutputScope, hasStandardOutputScope, outputCategory]);
|
|
64364
64472
|
const handleLineFilterChange = React141.useCallback((value) => {
|
|
64365
64473
|
setSelectedLineFilter(value);
|
|
64366
64474
|
}, []);
|
|
@@ -64370,17 +64478,19 @@ var LeaderboardDetailView = React141.memo(({
|
|
|
64370
64478
|
const clearFilters = React141.useCallback(() => {
|
|
64371
64479
|
setSortAscending(false);
|
|
64372
64480
|
setSelectedLineFilter("all");
|
|
64481
|
+
setOutputCategory("standard");
|
|
64373
64482
|
setSelectedShiftFilter(currentShiftInfo.shiftId.toString());
|
|
64374
64483
|
}, [currentShiftInfo.shiftId]);
|
|
64375
64484
|
const activeFiltersCount = React141.useMemo(() => {
|
|
64376
64485
|
let count = 0;
|
|
64377
64486
|
if (sortAscending) count++;
|
|
64378
64487
|
if (selectedLineFilter !== "all") count++;
|
|
64488
|
+
if (showOutputCategoryDropdown && outputCategory !== "standard") count++;
|
|
64379
64489
|
if (selectedShiftFilter !== currentShiftInfo.shiftId.toString()) {
|
|
64380
64490
|
count++;
|
|
64381
64491
|
}
|
|
64382
64492
|
return count;
|
|
64383
|
-
}, [sortAscending, selectedLineFilter, selectedShiftFilter, currentShiftInfo.shiftId]);
|
|
64493
|
+
}, [sortAscending, selectedLineFilter, outputCategory, showOutputCategoryDropdown, selectedShiftFilter, currentShiftInfo.shiftId]);
|
|
64384
64494
|
const shouldFetchShiftConfigs = !date && shiftId === void 0;
|
|
64385
64495
|
const {
|
|
64386
64496
|
shiftConfigMap: multiLineShiftConfigMap,
|
|
@@ -64432,7 +64542,8 @@ var LeaderboardDetailView = React141.memo(({
|
|
|
64432
64542
|
action_count: entry.total_output || 0,
|
|
64433
64543
|
pph: entry.avg_pph || 0,
|
|
64434
64544
|
performance_score: entry.performance_score ?? 0,
|
|
64435
|
-
avg_cycle_time: entry.avg_cycle_time
|
|
64545
|
+
avg_cycle_time: toFiniteNumber(entry.avg_cycle_time) ?? 0,
|
|
64546
|
+
ideal_cycle_time: toFiniteNumber(entry.ideal_cycle_time) ?? void 0,
|
|
64436
64547
|
trend: 0,
|
|
64437
64548
|
predicted_output: 0,
|
|
64438
64549
|
efficiency: entry.efficiency || 0,
|
|
@@ -64610,7 +64721,7 @@ var LeaderboardDetailView = React141.memo(({
|
|
|
64610
64721
|
const currentShift = getCurrentShift(timezone || "Asia/Kolkata", activeShiftConfig);
|
|
64611
64722
|
return currentShift.shiftName || getShiftNameById(currentShift.shiftId, timezone || "Asia/Kolkata", activeShiftConfig);
|
|
64612
64723
|
}, [timezone, activeShiftConfig, shiftGroups]);
|
|
64613
|
-
const
|
|
64724
|
+
const getShiftIcon2 = React141.useCallback((shiftId2) => {
|
|
64614
64725
|
if (shiftId2 === void 0 && shiftGroups.length > 1) {
|
|
64615
64726
|
return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" }) });
|
|
64616
64727
|
}
|
|
@@ -64676,15 +64787,20 @@ var LeaderboardDetailView = React141.memo(({
|
|
|
64676
64787
|
if (!canOpenWorkspace(workspace.line_id)) {
|
|
64677
64788
|
return;
|
|
64678
64789
|
}
|
|
64790
|
+
const cycleRatio = getCycleRatio(workspace);
|
|
64679
64791
|
trackCoreEvent("Workspace from Leaderboard Clicked", {
|
|
64680
64792
|
workspace_name: workspace.workspace_name,
|
|
64681
64793
|
workspace_id: workspace.workspace_uuid,
|
|
64682
64794
|
rank,
|
|
64683
64795
|
total_workspaces: workspacesLengthRef.current,
|
|
64684
64796
|
// Use ref instead of state to avoid dependency
|
|
64797
|
+
metric_context: viewType === "machine" ? "machine" : outputCategory,
|
|
64685
64798
|
efficiency: workspace.efficiency,
|
|
64686
64799
|
action_count: workspace.action_count,
|
|
64687
|
-
action_threshold: workspace.action_threshold
|
|
64800
|
+
action_threshold: workspace.action_threshold,
|
|
64801
|
+
avg_cycle_time: workspace.avg_cycle_time,
|
|
64802
|
+
ideal_cycle_time: workspace.ideal_cycle_time ?? null,
|
|
64803
|
+
cycle_ratio: cycleRatio
|
|
64688
64804
|
});
|
|
64689
64805
|
const displayName = workspace.displayName || getWorkspaceDisplayName(workspace.workspace_name, workspace.line_id);
|
|
64690
64806
|
const navParams = workspace.workspace_uuid ? getWorkspaceNavigationParams(workspace.workspace_uuid, displayName, workspace.line_id) : "";
|
|
@@ -64708,7 +64824,7 @@ var LeaderboardDetailView = React141.memo(({
|
|
|
64708
64824
|
const combinedParams = navParams ? `${navParams}&${contextParamString}` : `?${contextParamString}`;
|
|
64709
64825
|
navigation.navigate(`/workspace/${workspace.workspace_uuid}${combinedParams}`);
|
|
64710
64826
|
}
|
|
64711
|
-
}, [canOpenWorkspace, onWorkspaceClick, navigation, date, shiftId]);
|
|
64827
|
+
}, [canOpenWorkspace, onWorkspaceClick, navigation, date, shiftId, outputCategory, viewType]);
|
|
64712
64828
|
React141.useEffect(() => {
|
|
64713
64829
|
workspacesLengthRef.current = activeEntries.length || 0;
|
|
64714
64830
|
}, [activeEntries.length]);
|
|
@@ -64729,16 +64845,20 @@ var LeaderboardDetailView = React141.memo(({
|
|
|
64729
64845
|
return activeEntries.map((ws) => ({
|
|
64730
64846
|
...ws,
|
|
64731
64847
|
displayName: ws.displayName || getWorkspaceDisplayName(ws.workspace_name, ws.line_id),
|
|
64732
|
-
lineName: getLineName(ws.line_id)
|
|
64848
|
+
lineName: getLineName(ws.line_id),
|
|
64849
|
+
isAssemblyLine: scopedLineAssemblyMap.get(ws.line_id) === true
|
|
64733
64850
|
}));
|
|
64734
|
-
}, [activeEntries, getLineName]);
|
|
64851
|
+
}, [activeEntries, getLineName, scopedLineAssemblyMap]);
|
|
64735
64852
|
const sortedWorkspaces = React141.useMemo(() => {
|
|
64736
64853
|
let filtered = [...workspaceDisplayData];
|
|
64737
64854
|
filtered = filtered.filter((ws) => {
|
|
64738
64855
|
if (viewType === "machine") {
|
|
64739
64856
|
return ws.monitoring_mode === "uptime";
|
|
64740
64857
|
}
|
|
64741
|
-
|
|
64858
|
+
if (ws.monitoring_mode === "uptime") {
|
|
64859
|
+
return false;
|
|
64860
|
+
}
|
|
64861
|
+
return isAssemblyMode ? ws.isAssemblyLine : !ws.isAssemblyLine;
|
|
64742
64862
|
});
|
|
64743
64863
|
if (selectedLineFilter !== "all") {
|
|
64744
64864
|
filtered = filtered.filter((ws) => ws.line_id === selectedLineFilter);
|
|
@@ -64747,13 +64867,61 @@ var LeaderboardDetailView = React141.memo(({
|
|
|
64747
64867
|
filtered = filtered.filter((ws) => ws.shift_id?.toString() === selectedShiftFilter);
|
|
64748
64868
|
}
|
|
64749
64869
|
return filtered.sort((a, b) => {
|
|
64870
|
+
if (isAssemblyMode) {
|
|
64871
|
+
const ratioA = getCycleRatio(a);
|
|
64872
|
+
const ratioB = getCycleRatio(b);
|
|
64873
|
+
if (ratioA === null && ratioB === null) return 0;
|
|
64874
|
+
if (ratioA === null) return 1;
|
|
64875
|
+
if (ratioB === null) return -1;
|
|
64876
|
+
return sortAscending ? ratioA - ratioB : ratioB - ratioA;
|
|
64877
|
+
}
|
|
64750
64878
|
const effA = a.efficiency || 0;
|
|
64751
64879
|
const effB = b.efficiency || 0;
|
|
64752
64880
|
return sortAscending ? effA - effB : effB - effA;
|
|
64753
64881
|
});
|
|
64754
|
-
}, [workspaceDisplayData, sortAscending, selectedLineFilter, selectedShiftFilter, activeTab, viewType]);
|
|
64882
|
+
}, [workspaceDisplayData, sortAscending, selectedLineFilter, selectedShiftFilter, activeTab, viewType, isAssemblyMode]);
|
|
64755
64883
|
const loading = activeTab === "today" ? todayLoading : monthlyLoading;
|
|
64756
64884
|
const error = activeTab === "today" ? todayError : monthlyError;
|
|
64885
|
+
React141.useEffect(() => {
|
|
64886
|
+
if (loading || error || sortedWorkspaces.length === 0) return;
|
|
64887
|
+
const trackingKey = [
|
|
64888
|
+
activeTab,
|
|
64889
|
+
viewType,
|
|
64890
|
+
outputCategory,
|
|
64891
|
+
selectedLineFilter,
|
|
64892
|
+
selectedShiftFilter,
|
|
64893
|
+
sortAscending ? "asc" : "desc",
|
|
64894
|
+
sortedWorkspaces.length
|
|
64895
|
+
].join("|");
|
|
64896
|
+
if (leaderboardViewTrackedRef.current === trackingKey) return;
|
|
64897
|
+
leaderboardViewTrackedRef.current = trackingKey;
|
|
64898
|
+
const topWorkspace = sortedWorkspaces[0];
|
|
64899
|
+
trackCoreEvent("Workspace Leaderboard View Loaded", {
|
|
64900
|
+
time_range: activeTab,
|
|
64901
|
+
view_type: viewType,
|
|
64902
|
+
metric_context: viewType === "machine" ? "machine" : outputCategory,
|
|
64903
|
+
line_filter: selectedLineFilter,
|
|
64904
|
+
shift_filter: selectedShiftFilter,
|
|
64905
|
+
sort_direction: sortAscending ? "asc" : "desc",
|
|
64906
|
+
workspace_count: sortedWorkspaces.length,
|
|
64907
|
+
top_workspace_id: topWorkspace?.workspace_uuid ?? null,
|
|
64908
|
+
top_workspace_name: topWorkspace?.workspace_name ?? null,
|
|
64909
|
+
top_efficiency: topWorkspace?.efficiency ?? null,
|
|
64910
|
+
top_avg_cycle_time: topWorkspace?.avg_cycle_time ?? null,
|
|
64911
|
+
top_ideal_cycle_time: topWorkspace?.ideal_cycle_time ?? null,
|
|
64912
|
+
top_cycle_ratio: topWorkspace ? getCycleRatio(topWorkspace) : null
|
|
64913
|
+
});
|
|
64914
|
+
}, [
|
|
64915
|
+
loading,
|
|
64916
|
+
error,
|
|
64917
|
+
sortedWorkspaces,
|
|
64918
|
+
activeTab,
|
|
64919
|
+
viewType,
|
|
64920
|
+
outputCategory,
|
|
64921
|
+
selectedLineFilter,
|
|
64922
|
+
selectedShiftFilter,
|
|
64923
|
+
sortAscending
|
|
64924
|
+
]);
|
|
64757
64925
|
const currentDateFormatted = React141.useMemo(() => {
|
|
64758
64926
|
const dateStr = (/* @__PURE__ */ new Date()).toDateString();
|
|
64759
64927
|
return formatDate2(new Date(dateStr));
|
|
@@ -64771,7 +64939,9 @@ var LeaderboardDetailView = React141.memo(({
|
|
|
64771
64939
|
error.message
|
|
64772
64940
|
] }) });
|
|
64773
64941
|
}
|
|
64774
|
-
const
|
|
64942
|
+
const metricLabel = viewType === "machine" ? "Utilization" : isAssemblyMode ? "Cycle Time" : "Efficiency";
|
|
64943
|
+
const descendingSortLabel = "Highest to Lowest";
|
|
64944
|
+
const ascendingSortLabel = "Lowest to Highest";
|
|
64775
64945
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `min-h-screen bg-slate-50 flex flex-col ${className}`, style: { willChange: "contents" }, children: [
|
|
64776
64946
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "sticky top-0 z-20 bg-white shadow-sm border-b border-gray-200/80", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-3 sm:px-6 md:px-8 py-2 sm:py-2.5", children: [
|
|
64777
64947
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "sm:hidden", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center", children: [
|
|
@@ -64821,7 +64991,7 @@ var LeaderboardDetailView = React141.memo(({
|
|
|
64821
64991
|
] }),
|
|
64822
64992
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3", children: [
|
|
64823
64993
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
|
|
64824
|
-
/* @__PURE__ */ jsxRuntime.jsx("label", { className: "text-xs font-medium text-gray-500 uppercase tracking-wide ml-1", children:
|
|
64994
|
+
/* @__PURE__ */ jsxRuntime.jsx("label", { className: "text-xs font-medium text-gray-500 uppercase tracking-wide ml-1", children: metricLabel }),
|
|
64825
64995
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
64826
64996
|
"select",
|
|
64827
64997
|
{
|
|
@@ -64830,8 +65000,25 @@ var LeaderboardDetailView = React141.memo(({
|
|
|
64830
65000
|
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",
|
|
64831
65001
|
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` },
|
|
64832
65002
|
children: [
|
|
64833
|
-
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "desc", children:
|
|
64834
|
-
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "asc", children:
|
|
65003
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "desc", children: descendingSortLabel }),
|
|
65004
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "asc", children: ascendingSortLabel })
|
|
65005
|
+
]
|
|
65006
|
+
}
|
|
65007
|
+
) })
|
|
65008
|
+
] }),
|
|
65009
|
+
showOutputCategoryDropdown && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1 sm:hidden", children: [
|
|
65010
|
+
/* @__PURE__ */ jsxRuntime.jsx("label", { className: "text-xs font-medium text-gray-500 uppercase tracking-wide ml-1", children: "Output Type" }),
|
|
65011
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
65012
|
+
"select",
|
|
65013
|
+
{
|
|
65014
|
+
"aria-label": "Output leaderboard category",
|
|
65015
|
+
value: outputCategory,
|
|
65016
|
+
onChange: (e) => setOutputCategory(e.target.value),
|
|
65017
|
+
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",
|
|
65018
|
+
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` },
|
|
65019
|
+
children: [
|
|
65020
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "standard", children: "Standard" }),
|
|
65021
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "assembly", children: "Assembly" })
|
|
64835
65022
|
]
|
|
64836
65023
|
}
|
|
64837
65024
|
) })
|
|
@@ -64873,7 +65060,7 @@ var LeaderboardDetailView = React141.memo(({
|
|
|
64873
65060
|
currentDate: activeTab === "monthly" ? monthlyRangeText : currentDateFormatted,
|
|
64874
65061
|
currentMobileDate: activeTab === "monthly" ? monthlyRangeText : currentMobileDateFormatted,
|
|
64875
65062
|
shiftId: activeTab === "monthly" ? monthlyShiftId : todayShiftId,
|
|
64876
|
-
getShiftIcon,
|
|
65063
|
+
getShiftIcon: getShiftIcon2,
|
|
64877
65064
|
getShiftName,
|
|
64878
65065
|
showTimer: activeTab === "today"
|
|
64879
65066
|
}
|
|
@@ -64971,6 +65158,20 @@ var LeaderboardDetailView = React141.memo(({
|
|
|
64971
65158
|
]
|
|
64972
65159
|
}
|
|
64973
65160
|
) }),
|
|
65161
|
+
showOutputCategoryDropdown && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
65162
|
+
"select",
|
|
65163
|
+
{
|
|
65164
|
+
"aria-label": "Output leaderboard category",
|
|
65165
|
+
value: outputCategory,
|
|
65166
|
+
onChange: (e) => setOutputCategory(e.target.value),
|
|
65167
|
+
className: "appearance-none pl-3 pr-8 py-1.5 text-sm font-medium bg-white border border-gray-200 hover:border-gray-300 rounded-lg text-gray-700 focus:outline-none focus:ring-2 focus:ring-blue-500 transition-all cursor-pointer shadow-sm",
|
|
65168
|
+
style: { backgroundImage: `url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e")`, backgroundPosition: `right 0.5rem center`, backgroundRepeat: `no-repeat`, backgroundSize: `1.2em 1.2em` },
|
|
65169
|
+
children: [
|
|
65170
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "standard", children: "Standard" }),
|
|
65171
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "assembly", children: "Assembly" })
|
|
65172
|
+
]
|
|
65173
|
+
}
|
|
65174
|
+
) }),
|
|
64974
65175
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
64975
65176
|
"button",
|
|
64976
65177
|
{
|
|
@@ -65002,7 +65203,8 @@ var LeaderboardDetailView = React141.memo(({
|
|
|
65002
65203
|
isClickable: canOpenWorkspace(ws.line_id),
|
|
65003
65204
|
onWorkspaceClick: stableHandleWorkspaceClick,
|
|
65004
65205
|
getMedalIcon: stableGetMedalIcon,
|
|
65005
|
-
|
|
65206
|
+
metricLabel,
|
|
65207
|
+
isAssemblyMode
|
|
65006
65208
|
},
|
|
65007
65209
|
ws.workspace_uuid
|
|
65008
65210
|
);
|
|
@@ -65013,7 +65215,7 @@ var LeaderboardDetailView = React141.memo(({
|
|
|
65013
65215
|
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-3 py-2.5 sm:p-4 text-left text-xs sm:text-sm font-semibold text-gray-600 whitespace-nowrap", children: "Rank" }),
|
|
65014
65216
|
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-3 py-2.5 sm:p-4 text-left text-xs sm:text-sm font-semibold text-gray-600 whitespace-nowrap", children: "Workspace" }),
|
|
65015
65217
|
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-3 py-2.5 sm:p-4 text-left text-xs sm:text-sm font-semibold text-gray-600 whitespace-nowrap", children: "Line" }),
|
|
65016
|
-
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-3 py-2.5 sm:p-4 text-left text-xs sm:text-sm font-semibold text-gray-600 whitespace-nowrap", children:
|
|
65218
|
+
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-3 py-2.5 sm:p-4 text-left text-xs sm:text-sm font-semibold text-gray-600 whitespace-nowrap", children: metricLabel })
|
|
65017
65219
|
] }) }),
|
|
65018
65220
|
/* @__PURE__ */ jsxRuntime.jsx("tbody", { className: "divide-y divide-gray-100", children: sortedWorkspaces.map((ws, index) => {
|
|
65019
65221
|
const isTopThree = index < 3;
|
|
@@ -65026,7 +65228,8 @@ var LeaderboardDetailView = React141.memo(({
|
|
|
65026
65228
|
rowClass,
|
|
65027
65229
|
isClickable: canOpenWorkspace(ws.line_id),
|
|
65028
65230
|
onWorkspaceClick: stableHandleWorkspaceClick,
|
|
65029
|
-
getMedalIcon: stableGetMedalIcon
|
|
65231
|
+
getMedalIcon: stableGetMedalIcon,
|
|
65232
|
+
isAssemblyMode
|
|
65030
65233
|
},
|
|
65031
65234
|
ws.workspace_uuid
|
|
65032
65235
|
);
|
|
@@ -65044,7 +65247,10 @@ function LoginView({
|
|
|
65044
65247
|
logoSrc = optifye_logo_default,
|
|
65045
65248
|
logoAlt = "Optifye",
|
|
65046
65249
|
brandName = "Optifye",
|
|
65047
|
-
onRateLimitCheck
|
|
65250
|
+
onRateLimitCheck,
|
|
65251
|
+
showDevTestLogin = false,
|
|
65252
|
+
devTestLoginLabel,
|
|
65253
|
+
onDevTestLogin
|
|
65048
65254
|
}) {
|
|
65049
65255
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
65050
65256
|
LoginPage,
|
|
@@ -65052,7 +65258,10 @@ function LoginView({
|
|
|
65052
65258
|
logoSrc,
|
|
65053
65259
|
logoAlt,
|
|
65054
65260
|
brandName,
|
|
65055
|
-
onRateLimitCheck
|
|
65261
|
+
onRateLimitCheck,
|
|
65262
|
+
showDevTestLogin,
|
|
65263
|
+
devTestLoginLabel,
|
|
65264
|
+
onDevTestLogin
|
|
65056
65265
|
}
|
|
65057
65266
|
);
|
|
65058
65267
|
}
|
|
@@ -68240,20 +68449,30 @@ function useTimezone(options = {}) {
|
|
|
68240
68449
|
}
|
|
68241
68450
|
|
|
68242
68451
|
// src/views/workspace-detail-view.utils.ts
|
|
68243
|
-
var
|
|
68452
|
+
var getWorkspaceDetailLayoutMode = ({
|
|
68244
68453
|
workspace,
|
|
68245
68454
|
showCycleTimeChart
|
|
68246
68455
|
}) => {
|
|
68247
68456
|
if (workspace?.monitoring_mode === "uptime") {
|
|
68248
|
-
return "
|
|
68457
|
+
return "uptime";
|
|
68249
68458
|
}
|
|
68250
68459
|
if (showCycleTimeChart === false) {
|
|
68251
68460
|
return "output";
|
|
68252
68461
|
}
|
|
68253
|
-
|
|
68462
|
+
return shouldUseAssemblyCycleTimeLayout(workspace) ? "assembly_cycle" : "output";
|
|
68463
|
+
};
|
|
68464
|
+
var getCycleTimeRenderState = ({
|
|
68465
|
+
workspace,
|
|
68466
|
+
authoritativeMetrics,
|
|
68467
|
+
showCycleTimeChart
|
|
68468
|
+
}) => {
|
|
68469
|
+
if (getWorkspaceDetailLayoutMode({ workspace, showCycleTimeChart }) !== "assembly_cycle") {
|
|
68254
68470
|
return "output";
|
|
68255
68471
|
}
|
|
68256
|
-
|
|
68472
|
+
if (!authoritativeMetrics) {
|
|
68473
|
+
return "chart_loading";
|
|
68474
|
+
}
|
|
68475
|
+
return authoritativeMetrics.cycle_time_data_status === "missing_clips" ? "cycle_unavailable" : "cycle_chart";
|
|
68257
68476
|
};
|
|
68258
68477
|
var formatDateInTimezone = (date = /* @__PURE__ */ new Date(), timezone, options) => {
|
|
68259
68478
|
const defaultOptions = {
|
|
@@ -68661,33 +68880,34 @@ var WorkspaceDetailView = ({
|
|
|
68661
68880
|
idle_time_hourly: void 0
|
|
68662
68881
|
};
|
|
68663
68882
|
}, [cachedOverviewMetrics, shiftConfig?.shifts]);
|
|
68664
|
-
const
|
|
68883
|
+
const authoritativeCycleMetrics = isHistoricView ? historicMetrics : liveMetrics;
|
|
68884
|
+
const workspace = authoritativeCycleMetrics || cachedDetailedMetrics || overviewFallback;
|
|
68665
68885
|
const { timezone: cycleTimeTimezone } = useTimezone({
|
|
68666
68886
|
lineId: effectiveLineId || workspace?.line_id || void 0,
|
|
68667
68887
|
workspaceId: workspaceId || void 0
|
|
68668
68888
|
});
|
|
68669
68889
|
const effectiveCycleTimeTimezone = cycleTimeTimezone || timezone;
|
|
68670
|
-
const detailedWorkspaceMetrics =
|
|
68890
|
+
const detailedWorkspaceMetrics = authoritativeCycleMetrics || cachedDetailedMetrics;
|
|
68671
68891
|
const cycleTimeChartData = React141.useMemo(
|
|
68672
|
-
() => Array.isArray(
|
|
68892
|
+
() => Array.isArray(authoritativeCycleMetrics?.hourly_cycle_times) ? authoritativeCycleMetrics.hourly_cycle_times.map((value) => {
|
|
68673
68893
|
const numericValue = Number(value);
|
|
68674
68894
|
return Number.isFinite(numericValue) ? numericValue : 0;
|
|
68675
68895
|
}) : [],
|
|
68676
|
-
[
|
|
68896
|
+
[authoritativeCycleMetrics?.hourly_cycle_times]
|
|
68677
68897
|
);
|
|
68678
68898
|
const maskedCycleTimeChartData = React141.useMemo(
|
|
68679
68899
|
() => maskFutureHourlySeries({
|
|
68680
68900
|
data: cycleTimeChartData,
|
|
68681
|
-
shiftStart:
|
|
68682
|
-
shiftEnd:
|
|
68683
|
-
shiftDate:
|
|
68901
|
+
shiftStart: authoritativeCycleMetrics?.shift_start,
|
|
68902
|
+
shiftEnd: authoritativeCycleMetrics?.shift_end,
|
|
68903
|
+
shiftDate: authoritativeCycleMetrics?.date || date || calculatedOperationalDate || null,
|
|
68684
68904
|
timezone: effectiveCycleTimeTimezone
|
|
68685
68905
|
}),
|
|
68686
68906
|
[
|
|
68687
68907
|
cycleTimeChartData,
|
|
68688
|
-
|
|
68689
|
-
|
|
68690
|
-
|
|
68908
|
+
authoritativeCycleMetrics?.shift_start,
|
|
68909
|
+
authoritativeCycleMetrics?.shift_end,
|
|
68910
|
+
authoritativeCycleMetrics?.date,
|
|
68691
68911
|
date,
|
|
68692
68912
|
calculatedOperationalDate,
|
|
68693
68913
|
effectiveCycleTimeTimezone
|
|
@@ -68695,13 +68915,13 @@ var WorkspaceDetailView = ({
|
|
|
68695
68915
|
);
|
|
68696
68916
|
const cycleTimeDatasetKey = React141.useMemo(
|
|
68697
68917
|
() => [
|
|
68698
|
-
|
|
68699
|
-
date ||
|
|
68700
|
-
parsedShiftId ??
|
|
68918
|
+
authoritativeCycleMetrics?.workspace_id || workspaceId || "workspace",
|
|
68919
|
+
date || authoritativeCycleMetrics?.date || "live",
|
|
68920
|
+
parsedShiftId ?? authoritativeCycleMetrics?.shift_id ?? "current",
|
|
68701
68921
|
"hourly",
|
|
68702
68922
|
"backend"
|
|
68703
68923
|
].join(":"),
|
|
68704
|
-
[
|
|
68924
|
+
[authoritativeCycleMetrics?.workspace_id, workspaceId, date, authoritativeCycleMetrics?.date, parsedShiftId, authoritativeCycleMetrics?.shift_id]
|
|
68705
68925
|
);
|
|
68706
68926
|
const hasWorkspaceSnapshot = Boolean(workspace);
|
|
68707
68927
|
const loading = ((isHistoricView ? historicLoading : liveLoading) || isShiftConfigLoading) && !hasWorkspaceSnapshot;
|
|
@@ -68950,30 +69170,46 @@ var WorkspaceDetailView = ({
|
|
|
68950
69170
|
action_type: workspace.action_type
|
|
68951
69171
|
} : null;
|
|
68952
69172
|
const isAssemblyWorkspace = shouldUseAssemblyCycleTimeLayout(workspaceCycleTimeEligibility);
|
|
68953
|
-
const
|
|
69173
|
+
const layoutMode = getWorkspaceDetailLayoutMode({
|
|
69174
|
+
workspace: workspace ? {
|
|
69175
|
+
monitoring_mode: workspace.monitoring_mode,
|
|
69176
|
+
line_assembly_enabled: workspace.line_assembly_enabled,
|
|
69177
|
+
action_family: workspace.action_family,
|
|
69178
|
+
action_type: workspace.action_type
|
|
69179
|
+
} : null,
|
|
69180
|
+
showCycleTimeChart
|
|
69181
|
+
});
|
|
69182
|
+
const isAssemblyCycleLayout = layoutMode === "assembly_cycle";
|
|
69183
|
+
const isOutputLayout = layoutMode === "output";
|
|
69184
|
+
const cycleTimePresentation = getCycleTimeRenderState({
|
|
68954
69185
|
workspace: workspace ? {
|
|
68955
69186
|
monitoring_mode: workspace.monitoring_mode,
|
|
68956
69187
|
line_assembly_enabled: workspace.line_assembly_enabled,
|
|
68957
69188
|
action_family: workspace.action_family,
|
|
68958
|
-
action_type: workspace.action_type
|
|
68959
|
-
|
|
69189
|
+
action_type: workspace.action_type
|
|
69190
|
+
} : null,
|
|
69191
|
+
authoritativeMetrics: authoritativeCycleMetrics ? {
|
|
69192
|
+
cycle_time_data_status: authoritativeCycleMetrics.cycle_time_data_status
|
|
68960
69193
|
} : null,
|
|
68961
69194
|
showCycleTimeChart
|
|
68962
69195
|
});
|
|
68963
|
-
const shouldShowCycleTimeChart = cycleTimePresentation
|
|
69196
|
+
const shouldShowCycleTimeChart = cycleTimePresentation === "cycle_chart";
|
|
68964
69197
|
const shouldShowCycleTimeUnavailableState = cycleTimePresentation === "cycle_unavailable";
|
|
68965
|
-
const
|
|
69198
|
+
const shouldShowCycleTimeLoadingState = cycleTimePresentation === "chart_loading";
|
|
69199
|
+
const shouldShowAssemblyOverviewLoadingState = isAssemblyCycleLayout && shouldShowCycleTimeLoadingState && hasWorkspaceSnapshot;
|
|
69200
|
+
const showIdleBreakdownChart = !isAssemblyCycleLayout && idleTimeVlmEnabled;
|
|
69201
|
+
const canToggleChartIdleTime = !isUptimeMode && !shouldShowCycleTimeLoadingState && !shouldShowCycleTimeUnavailableState;
|
|
68966
69202
|
const idleClipDate = date || workspace?.date || calculatedOperationalDate || getOperationalDate(timezone);
|
|
68967
69203
|
const idleClipShiftId = parsedShiftId ?? workspace?.shift_id;
|
|
68968
69204
|
const rawHourlyIdleMinutes = React141.useMemo(() => {
|
|
68969
69205
|
if (!shouldShowCycleTimeChart || !workspace?.idle_time_hourly || !workspace?.shift_start) return [];
|
|
68970
|
-
const
|
|
69206
|
+
const parseTimeToMinutes4 = (time2) => {
|
|
68971
69207
|
const [h, m] = time2.split(":").map(Number);
|
|
68972
69208
|
if (!Number.isFinite(h) || !Number.isFinite(m)) return 0;
|
|
68973
69209
|
return h * 60 + m;
|
|
68974
69210
|
};
|
|
68975
|
-
const startTotal =
|
|
68976
|
-
const endTotalRaw = workspace.shift_end ?
|
|
69211
|
+
const startTotal = parseTimeToMinutes4(workspace.shift_start);
|
|
69212
|
+
const endTotalRaw = workspace.shift_end ? parseTimeToMinutes4(workspace.shift_end) : startTotal + 11 * 60;
|
|
68977
69213
|
const endTotal = endTotalRaw <= startTotal ? endTotalRaw + 24 * 60 : endTotalRaw;
|
|
68978
69214
|
const shiftDuration = Math.max(60, endTotal - startTotal);
|
|
68979
69215
|
const totalHourSlots = Math.max(1, Math.ceil(shiftDuration / 60));
|
|
@@ -69023,6 +69259,18 @@ var WorkspaceDetailView = ({
|
|
|
69023
69259
|
workspace.cycle_completion_clip_count
|
|
69024
69260
|
] })
|
|
69025
69261
|
] }), [workspace?.cycle_completion_clip_count]);
|
|
69262
|
+
const assemblyOverviewLoadingView = React141.useMemo(() => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4 pb-4", "data-testid": "assembly-overview-loading-state", children: [
|
|
69263
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "bg-white rounded-lg shadow-sm p-6 lg:p-8", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-h-[280px] lg:min-h-[340px] flex flex-col justify-center", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-full max-w-xl mx-auto animate-pulse space-y-3", children: [
|
|
69264
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-3 bg-gray-200 rounded-full w-3/4 mx-auto" }),
|
|
69265
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-3 bg-gray-100 rounded-full w-full" }),
|
|
69266
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-3 bg-gray-100 rounded-full w-5/6 mx-auto" })
|
|
69267
|
+
] }) }) }),
|
|
69268
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4", children: [0, 1, 2].map((index) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "bg-white rounded-lg shadow-sm p-5", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "animate-pulse space-y-3", children: [
|
|
69269
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-4 w-24 bg-gray-200 rounded" }),
|
|
69270
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-10 w-20 bg-gray-100 rounded" }),
|
|
69271
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-3 w-28 bg-gray-100 rounded" })
|
|
69272
|
+
] }) }, index)) })
|
|
69273
|
+
] }), []);
|
|
69026
69274
|
const shiftDurationMinutes = React141.useMemo(
|
|
69027
69275
|
() => getShiftDurationMinutes(workspace?.shift_start, workspace?.shift_end),
|
|
69028
69276
|
[workspace?.shift_start, workspace?.shift_end]
|
|
@@ -69077,7 +69325,7 @@ var WorkspaceDetailView = ({
|
|
|
69077
69325
|
}, [isUptimeMode, uptimeSeries, shiftDurationMinutes, elapsedShiftMinutes, workspace?.idle_time]);
|
|
69078
69326
|
const overviewTabLabel = isUptimeMode ? "Utilization" : "Efficiency";
|
|
69079
69327
|
const idleClipFetchEnabled = Boolean(
|
|
69080
|
-
workspaceId && idleClipDate && idleClipShiftId !== void 0 && activeTab === "overview" && idleTimeVlmEnabled &&
|
|
69328
|
+
workspaceId && idleClipDate && idleClipShiftId !== void 0 && activeTab === "overview" && idleTimeVlmEnabled && isOutputLayout
|
|
69081
69329
|
);
|
|
69082
69330
|
const {
|
|
69083
69331
|
idleClips: idleTimeClips,
|
|
@@ -69148,7 +69396,7 @@ var WorkspaceDetailView = ({
|
|
|
69148
69396
|
}
|
|
69149
69397
|
}
|
|
69150
69398
|
};
|
|
69151
|
-
const
|
|
69399
|
+
const getShiftIcon2 = (shiftType) => {
|
|
69152
69400
|
const shiftTypeLower = shiftType?.toLowerCase() || "";
|
|
69153
69401
|
if (shiftTypeLower.includes("day") || shiftTypeLower.includes("morning")) {
|
|
69154
69402
|
return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" }) });
|
|
@@ -69297,7 +69545,7 @@ var WorkspaceDetailView = ({
|
|
|
69297
69545
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-gray-700 scale-90", children: (() => {
|
|
69298
69546
|
const shift2 = shiftConfig?.shifts?.find((s) => s.shiftId === selectedShift);
|
|
69299
69547
|
const shiftName = shift2?.shiftName || (selectedShift === 0 ? "Day Shift" : "Night Shift");
|
|
69300
|
-
return
|
|
69548
|
+
return getShiftIcon2(shiftName);
|
|
69301
69549
|
})() }),
|
|
69302
69550
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-gray-700", children: (() => {
|
|
69303
69551
|
const shift2 = shiftConfig?.shifts?.find((s) => s.shiftId === selectedShift);
|
|
@@ -69325,7 +69573,7 @@ var WorkspaceDetailView = ({
|
|
|
69325
69573
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "opacity-70", children: (() => {
|
|
69326
69574
|
const shift2 = shiftConfig?.shifts?.find((s) => s.shiftId === selectedShift);
|
|
69327
69575
|
const shiftName = shift2?.shiftName || (selectedShift === 0 ? "Day Shift" : "Night Shift");
|
|
69328
|
-
return
|
|
69576
|
+
return getShiftIcon2(shiftName);
|
|
69329
69577
|
})() }),
|
|
69330
69578
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm md:text-base font-semibold uppercase tracking-wider", children: (() => {
|
|
69331
69579
|
const shift2 = shiftConfig?.shifts?.find((s) => s.shiftId === selectedShift);
|
|
@@ -69338,7 +69586,7 @@ var WorkspaceDetailView = ({
|
|
|
69338
69586
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "sm:hidden mt-3 flex items-center justify-center gap-2", children: [
|
|
69339
69587
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "inline-flex items-center px-2.5 py-1 bg-gray-100 rounded-full", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-gray-700", children: formatISTDate2(new Date(workspace.date)) }) }),
|
|
69340
69588
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "inline-flex items-center gap-1 px-2.5 py-1 bg-gray-100 rounded-full", children: [
|
|
69341
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-gray-700 scale-90", children:
|
|
69589
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-gray-700 scale-90", children: getShiftIcon2(workspace.shift_type) }),
|
|
69342
69590
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-gray-700", children: workspace.shift_type })
|
|
69343
69591
|
] }),
|
|
69344
69592
|
!date && !shift && !usingFallbackData ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "inline-flex items-center px-2.5 py-1 bg-green-100 rounded-full", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-green-700", children: /* @__PURE__ */ jsxRuntime.jsx(LiveTimer, {}) }) }) : date ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "inline-flex items-center px-2.5 py-1 bg-blue-100 rounded-full", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-blue-700", children: getDaysDifference(workspace.date, timezone, dashboardConfig?.shiftConfig?.dayShift?.startTime || "06:00") }) }) : usingFallbackData ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "inline-flex items-center px-2.5 py-1 bg-amber-100 rounded-full", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-amber-700", children: getDaysDifference(workspace.date, timezone, dashboardConfig?.shiftConfig?.dayShift?.startTime || "06:00") }) }) : null
|
|
@@ -69369,7 +69617,7 @@ var WorkspaceDetailView = ({
|
|
|
69369
69617
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-px h-4 bg-blue-200" })
|
|
69370
69618
|
] }),
|
|
69371
69619
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-blue-600", children: [
|
|
69372
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "opacity-70", children:
|
|
69620
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "opacity-70", children: getShiftIcon2(workspace.shift_type) }),
|
|
69373
69621
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-sm md:text-base font-semibold uppercase tracking-wider", children: [
|
|
69374
69622
|
workspace.shift_type.replace(/ Shift$/i, ""),
|
|
69375
69623
|
" Shift"
|
|
@@ -69488,9 +69736,9 @@ var WorkspaceDetailView = ({
|
|
|
69488
69736
|
] })
|
|
69489
69737
|
] }),
|
|
69490
69738
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-grow p-1.5 sm:p-2 lg:p-4", children: [
|
|
69491
|
-
activeTab === "overview" && /* @__PURE__ */ jsxRuntime.
|
|
69739
|
+
activeTab === "overview" && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col h-full lg:h-[calc(100vh-12rem)] overflow-y-auto lg:min-h-0 pb-4", children: shouldShowAssemblyOverviewLoadingState ? assemblyOverviewLoadingView : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
69492
69740
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "block lg:hidden space-y-6 pb-6", children: [
|
|
69493
|
-
|
|
69741
|
+
isOutputLayout && !isUptimeMode && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
69494
69742
|
motion.div,
|
|
69495
69743
|
{
|
|
69496
69744
|
className: "bg-white rounded-lg shadow-sm p-6 h-[300px]",
|
|
@@ -69518,8 +69766,8 @@ var WorkspaceDetailView = ({
|
|
|
69518
69766
|
animate: "animate",
|
|
69519
69767
|
children: [
|
|
69520
69768
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-between items-center mb-4", children: [
|
|
69521
|
-
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-lg font-bold text-gray-700", children: isUptimeMode ? "Machine Utilization" :
|
|
69522
|
-
|
|
69769
|
+
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-lg font-bold text-gray-700", children: isUptimeMode ? "Machine Utilization" : isAssemblyCycleLayout ? "Cycle time trend" : "Hourly Output" }),
|
|
69770
|
+
canToggleChartIdleTime && /* @__PURE__ */ jsxRuntime.jsx(
|
|
69523
69771
|
"button",
|
|
69524
69772
|
{
|
|
69525
69773
|
onClick: () => setShowChartIdleTime(!showChartIdleTime),
|
|
@@ -69548,19 +69796,19 @@ var WorkspaceDetailView = ({
|
|
|
69548
69796
|
timezone,
|
|
69549
69797
|
elapsedMinutes: elapsedShiftMinutes
|
|
69550
69798
|
}
|
|
69551
|
-
) : shouldShowCycleTimeUnavailableState ? cycleTimeUnavailableView : shouldShowCycleTimeChart ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
69799
|
+
) : isAssemblyCycleLayout ? shouldShowCycleTimeUnavailableState ? cycleTimeUnavailableView : shouldShowCycleTimeChart ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
69552
69800
|
CycleTimeOverTimeChart,
|
|
69553
69801
|
{
|
|
69554
69802
|
data: maskedCycleTimeChartData,
|
|
69555
|
-
idealCycleTime:
|
|
69556
|
-
shiftStart:
|
|
69557
|
-
shiftEnd:
|
|
69803
|
+
idealCycleTime: authoritativeCycleMetrics?.ideal_cycle_time || 0,
|
|
69804
|
+
shiftStart: authoritativeCycleMetrics?.shift_start || "",
|
|
69805
|
+
shiftEnd: authoritativeCycleMetrics?.shift_end || "",
|
|
69558
69806
|
xAxisMode: "hourly",
|
|
69559
69807
|
datasetKey: cycleTimeDatasetKey,
|
|
69560
69808
|
showIdleTime: showChartIdleTime,
|
|
69561
69809
|
idleTimeData: hourlyIdleMinutes
|
|
69562
69810
|
}
|
|
69563
|
-
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
69811
|
+
) : null : /* @__PURE__ */ jsxRuntime.jsx(
|
|
69564
69812
|
HourlyOutputChart2,
|
|
69565
69813
|
{
|
|
69566
69814
|
data: workspace.hourly_action_counts || [],
|
|
@@ -69580,7 +69828,7 @@ var WorkspaceDetailView = ({
|
|
|
69580
69828
|
]
|
|
69581
69829
|
}
|
|
69582
69830
|
),
|
|
69583
|
-
|
|
69831
|
+
showIdleBreakdownChart && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
69584
69832
|
motion.div,
|
|
69585
69833
|
{
|
|
69586
69834
|
className: "bg-white rounded-lg shadow-sm p-4 h-[300px]",
|
|
@@ -69600,7 +69848,7 @@ var WorkspaceDetailView = ({
|
|
|
69600
69848
|
]
|
|
69601
69849
|
}
|
|
69602
69850
|
),
|
|
69603
|
-
isUptimeMode ? /* @__PURE__ */ jsxRuntime.jsx(UptimeMetricCards, { workspace, uptimePieData }) :
|
|
69851
|
+
isUptimeMode ? /* @__PURE__ */ jsxRuntime.jsx(UptimeMetricCards, { workspace, uptimePieData }) : isAssemblyCycleLayout ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
69604
69852
|
WorkspaceCycleTimeMetricCards,
|
|
69605
69853
|
{
|
|
69606
69854
|
workspace,
|
|
@@ -69620,7 +69868,7 @@ var WorkspaceDetailView = ({
|
|
|
69620
69868
|
desktopTopSectionClass
|
|
69621
69869
|
),
|
|
69622
69870
|
children: [
|
|
69623
|
-
|
|
69871
|
+
isOutputLayout && !isUptimeMode && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
69624
69872
|
motion.div,
|
|
69625
69873
|
{
|
|
69626
69874
|
className: "bg-white rounded-lg shadow-sm p-4 lg:col-span-2 flex flex-col min-h-0",
|
|
@@ -69644,15 +69892,15 @@ var WorkspaceDetailView = ({
|
|
|
69644
69892
|
{
|
|
69645
69893
|
className: clsx(
|
|
69646
69894
|
"bg-white rounded-lg shadow-sm p-4 flex flex-col min-h-0",
|
|
69647
|
-
isUptimeMode && showIdleBreakdownChart ? "lg:col-span-2" :
|
|
69895
|
+
isUptimeMode && showIdleBreakdownChart ? "lg:col-span-2" : isAssemblyCycleLayout || isUptimeMode ? "lg:col-span-10" : idleTimeVlmEnabled ? "lg:col-span-6" : "lg:col-span-8"
|
|
69648
69896
|
),
|
|
69649
69897
|
variants: chartCardVariants,
|
|
69650
69898
|
initial: "initial",
|
|
69651
69899
|
animate: "animate",
|
|
69652
69900
|
children: [
|
|
69653
69901
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-3 mb-4 flex-none", children: [
|
|
69654
|
-
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-lg font-bold text-gray-700", children: isUptimeMode ? "Machine Utilization" :
|
|
69655
|
-
|
|
69902
|
+
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-lg font-bold text-gray-700", children: isUptimeMode ? "Machine Utilization" : isAssemblyCycleLayout ? "Cycle time trend" : "Hourly Output" }),
|
|
69903
|
+
canToggleChartIdleTime && /* @__PURE__ */ jsxRuntime.jsx(
|
|
69656
69904
|
"button",
|
|
69657
69905
|
{
|
|
69658
69906
|
onClick: () => setShowChartIdleTime(!showChartIdleTime),
|
|
@@ -69677,19 +69925,19 @@ var WorkspaceDetailView = ({
|
|
|
69677
69925
|
timezone,
|
|
69678
69926
|
elapsedMinutes: elapsedShiftMinutes
|
|
69679
69927
|
}
|
|
69680
|
-
) : shouldShowCycleTimeUnavailableState ? cycleTimeUnavailableView : shouldShowCycleTimeChart ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
69928
|
+
) : isAssemblyCycleLayout ? shouldShowCycleTimeUnavailableState ? cycleTimeUnavailableView : shouldShowCycleTimeChart ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
69681
69929
|
CycleTimeOverTimeChart,
|
|
69682
69930
|
{
|
|
69683
69931
|
data: maskedCycleTimeChartData,
|
|
69684
|
-
idealCycleTime:
|
|
69685
|
-
shiftStart:
|
|
69686
|
-
shiftEnd:
|
|
69932
|
+
idealCycleTime: authoritativeCycleMetrics?.ideal_cycle_time || 0,
|
|
69933
|
+
shiftStart: authoritativeCycleMetrics?.shift_start || "",
|
|
69934
|
+
shiftEnd: authoritativeCycleMetrics?.shift_end || "",
|
|
69687
69935
|
xAxisMode: "hourly",
|
|
69688
69936
|
datasetKey: cycleTimeDatasetKey,
|
|
69689
69937
|
showIdleTime: showChartIdleTime,
|
|
69690
69938
|
idleTimeData: hourlyIdleMinutes
|
|
69691
69939
|
}
|
|
69692
|
-
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
69940
|
+
) : null : /* @__PURE__ */ jsxRuntime.jsx(
|
|
69693
69941
|
HourlyOutputChart2,
|
|
69694
69942
|
{
|
|
69695
69943
|
data: workspace.hourly_action_counts || [],
|
|
@@ -69707,7 +69955,7 @@ var WorkspaceDetailView = ({
|
|
|
69707
69955
|
]
|
|
69708
69956
|
}
|
|
69709
69957
|
),
|
|
69710
|
-
|
|
69958
|
+
showIdleBreakdownChart && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
69711
69959
|
motion.div,
|
|
69712
69960
|
{
|
|
69713
69961
|
className: clsx(
|
|
@@ -69733,7 +69981,7 @@ var WorkspaceDetailView = ({
|
|
|
69733
69981
|
]
|
|
69734
69982
|
}
|
|
69735
69983
|
),
|
|
69736
|
-
isUptimeMode ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: clsx("flex min-h-0", desktopBottomSectionClass), children: /* @__PURE__ */ jsxRuntime.jsx(UptimeMetricCards, { workspace, uptimePieData, className: "flex-1" }) }) :
|
|
69984
|
+
isUptimeMode ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: clsx("flex min-h-0", desktopBottomSectionClass), children: /* @__PURE__ */ jsxRuntime.jsx(UptimeMetricCards, { workspace, uptimePieData, className: "flex-1" }) }) : isAssemblyCycleLayout ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
69737
69985
|
WorkspaceCycleTimeMetricCards,
|
|
69738
69986
|
{
|
|
69739
69987
|
workspace,
|
|
@@ -69744,7 +69992,7 @@ var WorkspaceDetailView = ({
|
|
|
69744
69992
|
}
|
|
69745
69993
|
) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: clsx("flex min-h-0", desktopBottomSectionClass), children: /* @__PURE__ */ jsxRuntime.jsx(WorkspaceMetricCards, { workspace, legend: efficiencyLegend, className: "flex-1" }) })
|
|
69746
69994
|
] })
|
|
69747
|
-
] }),
|
|
69995
|
+
] }) }),
|
|
69748
69996
|
activeTab === "monthly_history" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "h-[calc(100vh-10rem)] overflow-y-auto px-2 sm:px-4 lg:px-0", children: [
|
|
69749
69997
|
usingFallbackData && !date && !shift && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-3 sm:mb-4 bg-amber-50 border border-amber-200 rounded-lg px-3 sm:px-4 py-2 sm:py-3 text-amber-800", children: /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-xs sm:text-sm font-medium flex items-center", children: [
|
|
69750
69998
|
/* @__PURE__ */ jsxRuntime.jsx("svg", { xmlns: "http://www.w3.org/2000/svg", className: "h-4 w-4 sm:h-5 sm:w-5 mr-2", viewBox: "0 0 20 20", fill: "currentColor", children: /* @__PURE__ */ jsxRuntime.jsx("path", { fillRule: "evenodd", d: "M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z", clipRule: "evenodd" }) }),
|
|
@@ -72376,7 +72624,7 @@ var normalizeLabel = (value) => {
|
|
|
72376
72624
|
const trimmed = value.trim();
|
|
72377
72625
|
return trimmed.length > 0 ? trimmed : void 0;
|
|
72378
72626
|
};
|
|
72379
|
-
var
|
|
72627
|
+
var toFiniteNumber2 = (value) => {
|
|
72380
72628
|
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
72381
72629
|
if (typeof value === "string" && value.trim().length > 0) {
|
|
72382
72630
|
const parsed = Number(value);
|
|
@@ -72410,7 +72658,7 @@ var formatImprovementPieceGain = (pcsGain) => {
|
|
|
72410
72658
|
var getPositiveImprovementGain = ({
|
|
72411
72659
|
estimated_gain_pieces
|
|
72412
72660
|
}) => {
|
|
72413
|
-
const issueGain =
|
|
72661
|
+
const issueGain = toFiniteNumber2(estimated_gain_pieces);
|
|
72414
72662
|
return {
|
|
72415
72663
|
pcsGain: issueGain !== null && issueGain > 0 ? issueGain : null
|
|
72416
72664
|
};
|
|
@@ -72418,7 +72666,7 @@ var getPositiveImprovementGain = ({
|
|
|
72418
72666
|
var getImprovementPcsGainSortValue = (input) => {
|
|
72419
72667
|
const { pcsGain } = getPositiveImprovementGain(input);
|
|
72420
72668
|
if (pcsGain !== null) return pcsGain;
|
|
72421
|
-
const raw =
|
|
72669
|
+
const raw = toFiniteNumber2(input.estimated_gain_pieces);
|
|
72422
72670
|
return raw ?? null;
|
|
72423
72671
|
};
|
|
72424
72672
|
var getImprovementDisplayMetadata = ({
|
|
@@ -72438,7 +72686,7 @@ var getImprovementDisplayMetadata = ({
|
|
|
72438
72686
|
metadataLabel: [workstationLabel, lineLabel, supervisorLabel].join(" \xB7 ")
|
|
72439
72687
|
};
|
|
72440
72688
|
};
|
|
72441
|
-
var
|
|
72689
|
+
var toFiniteNumber3 = (value) => {
|
|
72442
72690
|
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
72443
72691
|
if (typeof value === "string" && value.trim().length > 0) {
|
|
72444
72692
|
const parsed = Number(value);
|
|
@@ -72466,15 +72714,15 @@ var compareImprovementRecommendationPriority = (left, right) => {
|
|
|
72466
72714
|
if (leftIndustrial !== rightIndustrial) {
|
|
72467
72715
|
return rightIndustrial - leftIndustrial;
|
|
72468
72716
|
}
|
|
72469
|
-
const leftGain =
|
|
72470
|
-
const rightGain =
|
|
72717
|
+
const leftGain = toFiniteNumber3(left.estimated_gain_pieces);
|
|
72718
|
+
const rightGain = toFiniteNumber3(right.estimated_gain_pieces);
|
|
72471
72719
|
if (leftGain !== rightGain) {
|
|
72472
72720
|
if (leftGain === null) return 1;
|
|
72473
72721
|
if (rightGain === null) return -1;
|
|
72474
72722
|
return rightGain - leftGain;
|
|
72475
72723
|
}
|
|
72476
|
-
const leftRatio =
|
|
72477
|
-
const rightRatio =
|
|
72724
|
+
const leftRatio = toFiniteNumber3(left.gain_to_target_ratio);
|
|
72725
|
+
const rightRatio = toFiniteNumber3(right.gain_to_target_ratio);
|
|
72478
72726
|
if (leftRatio !== rightRatio) {
|
|
72479
72727
|
if (leftRatio === null) return 1;
|
|
72480
72728
|
if (rightRatio === null) return -1;
|
|
@@ -75779,6 +76027,7 @@ var EMPTY_OVERVIEW_POOREST_LINES = {
|
|
|
75779
76027
|
};
|
|
75780
76028
|
var EMPTY_OVERVIEW_TREND = {
|
|
75781
76029
|
shift_mode: "all",
|
|
76030
|
+
granularity: "day",
|
|
75782
76031
|
points: []
|
|
75783
76032
|
};
|
|
75784
76033
|
var EMPTY_IDLE_BREAKDOWN = [];
|
|
@@ -75851,8 +76100,11 @@ var normalizePoorestLines = (value) => ({
|
|
|
75851
76100
|
});
|
|
75852
76101
|
var normalizeTrend = (value) => ({
|
|
75853
76102
|
shift_mode: value?.shift_mode || "all",
|
|
76103
|
+
granularity: value?.granularity === "hour" ? "hour" : "day",
|
|
75854
76104
|
points: (value?.points || []).map((point) => ({
|
|
75855
76105
|
date: point?.date,
|
|
76106
|
+
label: point?.label,
|
|
76107
|
+
hour_index: normalizeNumber(point?.hour_index),
|
|
75856
76108
|
avg_efficiency: normalizeNumber(point?.avg_efficiency)
|
|
75857
76109
|
}))
|
|
75858
76110
|
});
|
|
@@ -76194,17 +76446,25 @@ var formatSignedIdleDuration = (seconds) => {
|
|
|
76194
76446
|
const sign = seconds > 0 ? "+" : "-";
|
|
76195
76447
|
return `${sign}${formatIdleDuration(Math.abs(seconds))}`;
|
|
76196
76448
|
};
|
|
76197
|
-
var formatComparisonWindow = (
|
|
76449
|
+
var formatComparisonWindow = ({
|
|
76450
|
+
currentDayCount,
|
|
76451
|
+
previousDayCount,
|
|
76452
|
+
comparisonStrategy,
|
|
76453
|
+
shiftMode
|
|
76454
|
+
}) => {
|
|
76198
76455
|
if (comparisonStrategy === "previous_full_week") return "last week";
|
|
76199
|
-
if (
|
|
76200
|
-
|
|
76456
|
+
if (comparisonStrategy === "matched_range" && shiftMode !== "all" && currentDayCount === 1 && previousDayCount === 1) {
|
|
76457
|
+
return "previous day";
|
|
76458
|
+
}
|
|
76459
|
+
if (!previousDayCount || !Number.isFinite(previousDayCount)) return "previous range";
|
|
76460
|
+
return `previous ${previousDayCount} ${previousDayCount === 1 ? "day" : "days"}`;
|
|
76201
76461
|
};
|
|
76202
76462
|
var buildDeltaBadge = (delta, options) => {
|
|
76203
76463
|
if (delta === null || delta === void 0 || !Number.isFinite(delta)) {
|
|
76204
76464
|
return {
|
|
76205
76465
|
icon: null,
|
|
76206
|
-
className: "bg-slate-100 text-slate-
|
|
76207
|
-
text:
|
|
76466
|
+
className: "bg-slate-100 text-slate-400",
|
|
76467
|
+
text: "\u2014"
|
|
76208
76468
|
};
|
|
76209
76469
|
}
|
|
76210
76470
|
const direction = delta >= 0 ? "up" : "down";
|
|
@@ -76215,6 +76475,25 @@ var buildDeltaBadge = (delta, options) => {
|
|
|
76215
76475
|
text: `${options.formatter(delta)} vs ${options.comparisonLabel}`
|
|
76216
76476
|
};
|
|
76217
76477
|
};
|
|
76478
|
+
var normalizeShiftLabel = (shiftName, shiftMode) => {
|
|
76479
|
+
const trimmedName = shiftName?.trim();
|
|
76480
|
+
if (trimmedName) {
|
|
76481
|
+
return /shift/i.test(trimmedName) ? trimmedName : `${trimmedName} Shift`;
|
|
76482
|
+
}
|
|
76483
|
+
if (shiftMode === "night") return "Night Shift";
|
|
76484
|
+
return "Day Shift";
|
|
76485
|
+
};
|
|
76486
|
+
var getShiftIcon = (shiftName, shiftMode) => {
|
|
76487
|
+
const normalizedName = (shiftName || "").toLowerCase();
|
|
76488
|
+
const normalizedMode = shiftMode || "day";
|
|
76489
|
+
if (normalizedName.includes("day") || normalizedName.includes("morning") || normalizedMode === "day") {
|
|
76490
|
+
return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", "aria-hidden": true, children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" }) });
|
|
76491
|
+
}
|
|
76492
|
+
if (normalizedName.includes("night") || normalizedName.includes("evening") || normalizedMode === "night") {
|
|
76493
|
+
return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", "aria-hidden": true, children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z" }) });
|
|
76494
|
+
}
|
|
76495
|
+
return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", "aria-hidden": true, children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" }) });
|
|
76496
|
+
};
|
|
76218
76497
|
var buildLineDeltaTone = (delta, comparisonLabel) => {
|
|
76219
76498
|
if (delta === null || delta === void 0 || !Number.isFinite(delta)) {
|
|
76220
76499
|
return {
|
|
@@ -76270,6 +76549,8 @@ var OperationsOverviewHeader = React141__namespace.default.memo(({
|
|
|
76270
76549
|
dateRange,
|
|
76271
76550
|
displayDateRange,
|
|
76272
76551
|
trendMode,
|
|
76552
|
+
isLiveScope,
|
|
76553
|
+
liveShiftName,
|
|
76273
76554
|
lineOptions,
|
|
76274
76555
|
supervisorOptions,
|
|
76275
76556
|
selectedSupervisorId,
|
|
@@ -76283,6 +76564,14 @@ var OperationsOverviewHeader = React141__namespace.default.memo(({
|
|
|
76283
76564
|
}) => {
|
|
76284
76565
|
bumpRenderCounter();
|
|
76285
76566
|
const subtitleRange = displayDateRange || dateRange;
|
|
76567
|
+
const liveShiftLabel = React141__namespace.default.useMemo(
|
|
76568
|
+
() => normalizeShiftLabel(liveShiftName, trendMode),
|
|
76569
|
+
[liveShiftName, trendMode]
|
|
76570
|
+
);
|
|
76571
|
+
const liveShiftIcon = React141__namespace.default.useMemo(
|
|
76572
|
+
() => getShiftIcon(liveShiftName, trendMode),
|
|
76573
|
+
[liveShiftName, trendMode]
|
|
76574
|
+
);
|
|
76286
76575
|
const [isFilterOpen, setIsFilterOpen] = React141__namespace.default.useState(false);
|
|
76287
76576
|
const [isLinesDropdownOpen, setIsLinesDropdownOpen] = React141__namespace.default.useState(false);
|
|
76288
76577
|
const filterRef = React141__namespace.default.useRef(null);
|
|
@@ -76399,9 +76688,25 @@ var OperationsOverviewHeader = React141__namespace.default.memo(({
|
|
|
76399
76688
|
className: "flex-shrink-0 -ml-1"
|
|
76400
76689
|
}
|
|
76401
76690
|
) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-8 flex-shrink-0" }),
|
|
76402
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 flex flex-col items-center justify-center", children: [
|
|
76403
|
-
/* @__PURE__ */ jsxRuntime.
|
|
76404
|
-
|
|
76691
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 flex flex-col items-center justify-center min-w-0", children: [
|
|
76692
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-center gap-1.5 min-w-0 max-w-[240px]", children: [
|
|
76693
|
+
/* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-lg font-semibold text-gray-900 leading-tight text-center truncate", children: "Operations Overview" }),
|
|
76694
|
+
isLiveScope ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
76695
|
+
"div",
|
|
76696
|
+
{
|
|
76697
|
+
"data-testid": "operations-overview-live-indicator",
|
|
76698
|
+
className: "h-2 w-2 rounded-full bg-emerald-500 animate-pulse ring-2 ring-emerald-500/20 flex-shrink-0"
|
|
76699
|
+
}
|
|
76700
|
+
) : null
|
|
76701
|
+
] }),
|
|
76702
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-1 flex flex-wrap items-center justify-center gap-x-2 gap-y-1 text-[11px] font-medium text-slate-500 min-w-0", children: [
|
|
76703
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-center", children: mobileSubtitle }),
|
|
76704
|
+
isLiveScope ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-slate-300", children: "|" }) : null,
|
|
76705
|
+
isLiveScope ? /* @__PURE__ */ jsxRuntime.jsx("span", { "data-testid": "operations-overview-live-meta", className: "inline-flex items-center gap-1.5 text-gray-600 min-w-0", children: /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1 justify-center truncate", children: [
|
|
76706
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "opacity-75 shrink-0", children: liveShiftIcon }),
|
|
76707
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: liveShiftLabel })
|
|
76708
|
+
] }) }) : null
|
|
76709
|
+
] })
|
|
76405
76710
|
] }),
|
|
76406
76711
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-shrink-0 flex items-center gap-1.5", children: [
|
|
76407
76712
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -76420,22 +76725,40 @@ var OperationsOverviewHeader = React141__namespace.default.memo(({
|
|
|
76420
76725
|
{
|
|
76421
76726
|
ref: mobileFilterButtonRef,
|
|
76422
76727
|
onClick: handleFilterToggle,
|
|
76423
|
-
className: `p-2 rounded-full transition-colors relative ${isFilterOpen || activeFilterCount > 0 ? "bg-
|
|
76728
|
+
className: `p-2 rounded-full transition-colors relative ${isFilterOpen || activeFilterCount > 0 ? "bg-slate-100 text-slate-700" : "active:bg-gray-100 text-slate-600"}`,
|
|
76424
76729
|
"aria-label": "Open filters",
|
|
76425
76730
|
children: [
|
|
76426
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Filter, { className:
|
|
76427
|
-
activeFilterCount > 0 ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute -top-1 -right-1 flex items-center justify-center w-4 h-4 bg-
|
|
76731
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Filter, { className: "w-5 h-5" }),
|
|
76732
|
+
activeFilterCount > 0 ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute -top-1 -right-1 flex items-center justify-center w-4 h-4 bg-slate-700 text-white text-[10px] rounded-full font-bold", children: activeFilterCount }) : null
|
|
76428
76733
|
]
|
|
76429
76734
|
}
|
|
76430
76735
|
)
|
|
76431
76736
|
] })
|
|
76432
76737
|
] }) }),
|
|
76433
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "hidden sm:block", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-center relative min-h-[
|
|
76434
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute left-1/2 -translate-x-1/2 flex flex-col items-center
|
|
76435
|
-
/* @__PURE__ */ jsxRuntime.
|
|
76436
|
-
|
|
76738
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "hidden sm:block", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-center relative min-h-[64px]", children: [
|
|
76739
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute left-1/2 -translate-x-1/2 flex flex-col items-center min-w-0 max-w-[min(70vw,720px)]", children: [
|
|
76740
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-center gap-2 min-w-0 max-w-full", children: [
|
|
76741
|
+
/* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-2xl md:text-3xl lg:text-4xl font-semibold text-gray-900 tracking-tight leading-tight text-center truncate max-w-full", children: "Operations Overview" }),
|
|
76742
|
+
isLiveScope ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
76743
|
+
"div",
|
|
76744
|
+
{
|
|
76745
|
+
"data-testid": "operations-overview-live-indicator",
|
|
76746
|
+
className: "h-1.5 w-1.5 md:h-2 md:w-2 rounded-full bg-green-500 animate-pulse ring-2 ring-green-500/30 ring-offset-1 flex-shrink-0"
|
|
76747
|
+
}
|
|
76748
|
+
) : null
|
|
76749
|
+
] }),
|
|
76750
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-2 flex flex-wrap items-center justify-center gap-x-3 gap-y-1 text-xs sm:text-sm font-medium text-slate-500 text-center", children: [
|
|
76751
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: desktopSubtitle }),
|
|
76752
|
+
isLiveScope ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
76753
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-slate-300", children: "|" }),
|
|
76754
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { "data-testid": "operations-overview-live-meta", className: "inline-flex items-center gap-1.5 text-gray-600", children: /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1.5 justify-center", children: [
|
|
76755
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "opacity-75", children: liveShiftIcon }),
|
|
76756
|
+
liveShiftLabel
|
|
76757
|
+
] }) })
|
|
76758
|
+
] }) : null
|
|
76759
|
+
] })
|
|
76437
76760
|
] }),
|
|
76438
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute right-0 flex items-center gap-3", children: [
|
|
76761
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute right-0 flex items-center gap-3 shrink-0", children: [
|
|
76439
76762
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
76440
76763
|
MonthlyRangeFilter_default,
|
|
76441
76764
|
{
|
|
@@ -76452,12 +76775,12 @@ var OperationsOverviewHeader = React141__namespace.default.memo(({
|
|
|
76452
76775
|
{
|
|
76453
76776
|
ref: filterButtonRef,
|
|
76454
76777
|
onClick: handleFilterToggle,
|
|
76455
|
-
className: `flex items-center gap-2 px-3 py-1.5 rounded-lg border text-sm font-medium transition-all shadow-sm ${isFilterOpen || activeFilterCount > 0 ? "border-
|
|
76778
|
+
className: `flex items-center gap-2 px-3 py-1.5 rounded-lg border text-sm font-medium transition-all shadow-sm ${isFilterOpen || activeFilterCount > 0 ? "border-slate-300 bg-slate-50 text-slate-700" : "border-slate-200 bg-white text-slate-600 hover:bg-slate-50 hover:text-slate-700"}`,
|
|
76456
76779
|
"aria-label": "Open filters",
|
|
76457
76780
|
children: [
|
|
76458
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Filter, { className: `w-[18px] h-[18px] ${activeFilterCount > 0 ? "text-
|
|
76781
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Filter, { className: `w-[18px] h-[18px] ${isFilterOpen || activeFilterCount > 0 ? "text-slate-500" : "text-slate-400"}` }),
|
|
76459
76782
|
"Filters",
|
|
76460
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { className: `w-4 h-4 ml-0.5 transition-transform duration-200 ${isFilterOpen ? "rotate-180" : ""}` })
|
|
76783
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { className: `w-4 h-4 ml-0.5 text-slate-400 transition-transform duration-200 ${isFilterOpen ? "rotate-180" : ""}` })
|
|
76461
76784
|
]
|
|
76462
76785
|
}
|
|
76463
76786
|
)
|
|
@@ -76585,11 +76908,18 @@ var OverviewSummaryCards = React141__namespace.default.memo(({ store }) => {
|
|
|
76585
76908
|
const snapshot = useOperationsOverviewSnapshot(store);
|
|
76586
76909
|
const showSnapshotSkeleton = snapshot.loading && !snapshot.hasLoadedOnce;
|
|
76587
76910
|
const comparisonLabel = React141__namespace.default.useMemo(() => {
|
|
76588
|
-
return formatComparisonWindow(
|
|
76589
|
-
scope.
|
|
76590
|
-
scope.
|
|
76591
|
-
|
|
76592
|
-
|
|
76911
|
+
return formatComparisonWindow({
|
|
76912
|
+
currentDayCount: scope.current_range?.day_count ?? null,
|
|
76913
|
+
previousDayCount: scope.previous_range?.day_count ?? null,
|
|
76914
|
+
comparisonStrategy: scope.comparison_strategy,
|
|
76915
|
+
shiftMode: scope.shift_mode
|
|
76916
|
+
});
|
|
76917
|
+
}, [
|
|
76918
|
+
scope.comparison_strategy,
|
|
76919
|
+
scope.current_range?.day_count,
|
|
76920
|
+
scope.previous_range?.day_count,
|
|
76921
|
+
scope.shift_mode
|
|
76922
|
+
]);
|
|
76593
76923
|
const [isIdleContributorsOpen, setIsIdleContributorsOpen] = React141__namespace.default.useState(false);
|
|
76594
76924
|
const [isIdleContributorsPinned, setIsIdleContributorsPinned] = React141__namespace.default.useState(false);
|
|
76595
76925
|
const idleContributorsRef = React141__namespace.default.useRef(null);
|
|
@@ -76679,10 +77009,17 @@ var OverviewSummaryCards = React141__namespace.default.memo(({ store }) => {
|
|
|
76679
77009
|
roundOne(snapshot.data.summary.plant_efficiency.current),
|
|
76680
77010
|
"%"
|
|
76681
77011
|
] }),
|
|
76682
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
76683
|
-
|
|
76684
|
-
|
|
76685
|
-
|
|
77012
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
77013
|
+
"div",
|
|
77014
|
+
{
|
|
77015
|
+
"data-testid": "operations-overview-efficiency-delta",
|
|
77016
|
+
className: `flex items-center gap-1 px-2.5 py-1 rounded-full ${plantEfficiencyBadge.className}`,
|
|
77017
|
+
children: [
|
|
77018
|
+
plantEfficiencyBadge.icon === "up" ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowUp, { className: "w-3.5 h-3.5", strokeWidth: 2.5 }) : plantEfficiencyBadge.icon === "down" ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowDown, { className: "w-3.5 h-3.5", strokeWidth: 2.5 }) : null,
|
|
77019
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs sm:text-sm font-medium", children: plantEfficiencyBadge.text })
|
|
77020
|
+
]
|
|
77021
|
+
}
|
|
77022
|
+
)
|
|
76686
77023
|
] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-2 text-sm text-slate-400", children: "No efficiency data available" })
|
|
76687
77024
|
] }),
|
|
76688
77025
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
@@ -76728,10 +77065,17 @@ var OverviewSummaryCards = React141__namespace.default.memo(({ store }) => {
|
|
|
76728
77065
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-1", children: /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-lg font-semibold text-gray-700", children: "Idle Time per Workstation" }) }),
|
|
76729
77066
|
showSnapshotSkeleton ? /* @__PURE__ */ jsxRuntime.jsx(OverviewMetricCardSkeleton, {}) : snapshot.data.summary.avg_idle_per_workstation?.current_seconds !== null && snapshot.data.summary.avg_idle_per_workstation?.current_seconds !== void 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center gap-2 sm:gap-3 mt-1", children: [
|
|
76730
77067
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-2xl sm:text-3xl font-bold text-slate-800 tracking-tight", children: formatIdleDuration(snapshot.data.summary.avg_idle_per_workstation.current_seconds) }),
|
|
76731
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
76732
|
-
|
|
76733
|
-
|
|
76734
|
-
|
|
77068
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
77069
|
+
"div",
|
|
77070
|
+
{
|
|
77071
|
+
"data-testid": "operations-overview-idle-delta",
|
|
77072
|
+
className: `flex items-center gap-1 px-2.5 py-1 rounded-full ${idleBadge.className}`,
|
|
77073
|
+
children: [
|
|
77074
|
+
idleBadge.icon === "up" ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowUp, { className: "w-3.5 h-3.5", strokeWidth: 2.5 }) : idleBadge.icon === "down" ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowDown, { className: "w-3.5 h-3.5", strokeWidth: 2.5 }) : null,
|
|
77075
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs sm:text-sm font-medium", children: idleBadge.text })
|
|
77076
|
+
]
|
|
77077
|
+
}
|
|
77078
|
+
)
|
|
76735
77079
|
] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-2 text-sm text-slate-400", children: "No idle time data available" })
|
|
76736
77080
|
]
|
|
76737
77081
|
}
|
|
@@ -76794,11 +77138,18 @@ var PoorestPerformersCard = React141__namespace.default.memo(({
|
|
|
76794
77138
|
}
|
|
76795
77139
|
}, [availableLineModes?.has_output, availableLineModes?.has_uptime, poorestLineMode]);
|
|
76796
77140
|
const comparisonLabel = React141__namespace.default.useMemo(() => {
|
|
76797
|
-
return formatComparisonWindow(
|
|
76798
|
-
scope.
|
|
76799
|
-
scope.
|
|
76800
|
-
|
|
76801
|
-
|
|
77141
|
+
return formatComparisonWindow({
|
|
77142
|
+
currentDayCount: scope.current_range?.day_count ?? null,
|
|
77143
|
+
previousDayCount: scope.previous_range?.day_count ?? null,
|
|
77144
|
+
comparisonStrategy: scope.comparison_strategy,
|
|
77145
|
+
shiftMode: scope.shift_mode
|
|
77146
|
+
});
|
|
77147
|
+
}, [
|
|
77148
|
+
scope.comparison_strategy,
|
|
77149
|
+
scope.current_range?.day_count,
|
|
77150
|
+
scope.previous_range?.day_count,
|
|
77151
|
+
scope.shift_mode
|
|
77152
|
+
]);
|
|
76802
77153
|
const showSnapshotSkeleton = snapshot.loading && !snapshot.hasLoadedOnce;
|
|
76803
77154
|
const mergedPoorestLines = React141__namespace.default.useMemo(() => {
|
|
76804
77155
|
const rows = snapshot.data.poorest_lines?.[poorestLineMode] || [];
|
|
@@ -76955,7 +77306,8 @@ IdleBreakdownCard.displayName = "IdleBreakdownCard";
|
|
|
76955
77306
|
var EfficiencyTrendCard = React141__namespace.default.memo(({
|
|
76956
77307
|
store,
|
|
76957
77308
|
dateRange,
|
|
76958
|
-
appTimezone
|
|
77309
|
+
appTimezone,
|
|
77310
|
+
hourlyLabelStartTime
|
|
76959
77311
|
}) => {
|
|
76960
77312
|
bumpRenderCounter();
|
|
76961
77313
|
const trend = useOperationsOverviewTrend(store);
|
|
@@ -76965,7 +77317,41 @@ var EfficiencyTrendCard = React141__namespace.default.memo(({
|
|
|
76965
77317
|
);
|
|
76966
77318
|
const isCurrentWeekToDateRange = dateRange.startKey === currentWeekRange.startKey && dateRange.endKey === currentWeekRange.endKey;
|
|
76967
77319
|
const showInitialSkeleton = trend.loading && trend.lastUpdated === null;
|
|
77320
|
+
const isHourlyTrend = trend.data.granularity === "hour";
|
|
76968
77321
|
const trendData = React141__namespace.default.useMemo(() => {
|
|
77322
|
+
if (isHourlyTrend) {
|
|
77323
|
+
return (trend.data.points || []).map((point, index) => ({
|
|
77324
|
+
name: (() => {
|
|
77325
|
+
const rawLabel = point.label?.trim() || "";
|
|
77326
|
+
if (!hourlyLabelStartTime) {
|
|
77327
|
+
return rawLabel || `Hour ${index + 1}`;
|
|
77328
|
+
}
|
|
77329
|
+
if (rawLabel && !/^Hour\s+\d+$/i.test(rawLabel)) {
|
|
77330
|
+
return rawLabel;
|
|
77331
|
+
}
|
|
77332
|
+
const hourIndex = typeof point.hour_index === "number" ? point.hour_index : index;
|
|
77333
|
+
const [hoursPart, minutesPart] = hourlyLabelStartTime.split(":");
|
|
77334
|
+
const startHours = Number(hoursPart);
|
|
77335
|
+
const startMinutes = Number(minutesPart);
|
|
77336
|
+
if (!Number.isFinite(startHours) || !Number.isFinite(startMinutes)) {
|
|
77337
|
+
return rawLabel || `Hour ${index + 1}`;
|
|
77338
|
+
}
|
|
77339
|
+
const totalMinutes = startHours * 60 + startMinutes + hourIndex * 60;
|
|
77340
|
+
const hour24 = Math.floor(totalMinutes / 60) % 24;
|
|
77341
|
+
const minutes = totalMinutes % 60;
|
|
77342
|
+
const suffix = hour24 < 12 ? "AM" : "PM";
|
|
77343
|
+
const hour12 = hour24 % 12 || 12;
|
|
77344
|
+
if (minutes === 0) {
|
|
77345
|
+
return `${hour12} ${suffix}`;
|
|
77346
|
+
}
|
|
77347
|
+
return `${hour12}:${minutes.toString().padStart(2, "0")} ${suffix}`;
|
|
77348
|
+
})(),
|
|
77349
|
+
efficiency: (() => {
|
|
77350
|
+
const value = toNumber3(point.avg_efficiency);
|
|
77351
|
+
return value === null ? void 0 : value;
|
|
77352
|
+
})()
|
|
77353
|
+
}));
|
|
77354
|
+
}
|
|
76969
77355
|
const pointsByDate = new Map(
|
|
76970
77356
|
(trend.data.points || []).flatMap((point) => {
|
|
76971
77357
|
if (!point.date) return [];
|
|
@@ -77003,12 +77389,13 @@ var EfficiencyTrendCard = React141__namespace.default.memo(({
|
|
|
77003
77389
|
})()
|
|
77004
77390
|
};
|
|
77005
77391
|
});
|
|
77006
|
-
}, [currentWeekRange.startKey, isCurrentWeekToDateRange, trend.data.points]);
|
|
77392
|
+
}, [currentWeekRange.startKey, hourlyLabelStartTime, isCurrentWeekToDateRange, isHourlyTrend, trend.data.points]);
|
|
77007
77393
|
const trendTooltipLabelFormatter = React141__namespace.default.useCallback((label, payload) => {
|
|
77394
|
+
if (isHourlyTrend) return label;
|
|
77008
77395
|
const dayOfWeek = payload?.[0]?.payload?.dayOfWeek;
|
|
77009
77396
|
if (!dayOfWeek || typeof label !== "string") return label;
|
|
77010
77397
|
return `${label} (${dayOfWeek})`;
|
|
77011
|
-
}, []);
|
|
77398
|
+
}, [isHourlyTrend]);
|
|
77012
77399
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { 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", children: [
|
|
77013
77400
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-6 py-5 flex-none flex justify-between items-center border-b border-slate-50/50", children: /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-lg font-semibold text-gray-700", children: "Efficiency Trend" }) }),
|
|
77014
77401
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 min-h-[250px] w-full p-4 pt-4 relative", children: showInitialSkeleton ? /* @__PURE__ */ jsxRuntime.jsx(OverviewChartSkeleton, {}) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 pb-2 pr-4 pl-1", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -77162,7 +77549,8 @@ var useOperationsOverviewRefresh = ({
|
|
|
77162
77549
|
endKey,
|
|
77163
77550
|
trendMode,
|
|
77164
77551
|
comparisonStrategy,
|
|
77165
|
-
isLiveScope
|
|
77552
|
+
isLiveScope,
|
|
77553
|
+
enabled = true
|
|
77166
77554
|
}) => {
|
|
77167
77555
|
const lineIdsKey = React141__namespace.default.useMemo(() => lineIds.join(","), [lineIds]);
|
|
77168
77556
|
const scopeSignature = React141__namespace.default.useMemo(
|
|
@@ -77208,7 +77596,7 @@ var useOperationsOverviewRefresh = ({
|
|
|
77208
77596
|
}, []);
|
|
77209
77597
|
const runRefresh = React141__namespace.default.useCallback(
|
|
77210
77598
|
async (section, begin, onSuccess, onError, request, reason) => {
|
|
77211
|
-
if (!supabase || !companyId || lineIds.length === 0) return;
|
|
77599
|
+
if (!enabled || !supabase || !companyId || lineIds.length === 0) return;
|
|
77212
77600
|
const requestId = requestIdsRef.current[section] + 1;
|
|
77213
77601
|
requestIdsRef.current[section] = requestId;
|
|
77214
77602
|
controllersRef.current[section]?.abort();
|
|
@@ -77228,7 +77616,7 @@ var useOperationsOverviewRefresh = ({
|
|
|
77228
77616
|
onError(error instanceof Error ? error.message : `Failed to refresh ${section}`);
|
|
77229
77617
|
}
|
|
77230
77618
|
},
|
|
77231
|
-
[companyId, lineIds.length, supabase]
|
|
77619
|
+
[companyId, enabled, lineIds.length, supabase]
|
|
77232
77620
|
);
|
|
77233
77621
|
const refreshSnapshot = React141__namespace.default.useCallback(
|
|
77234
77622
|
async (reason) => {
|
|
@@ -77398,6 +77786,12 @@ var useOperationsOverviewRefresh = ({
|
|
|
77398
77786
|
});
|
|
77399
77787
|
}, [refreshAll, startPolling, stopPolling]);
|
|
77400
77788
|
React141__namespace.default.useEffect(() => {
|
|
77789
|
+
if (!enabled) {
|
|
77790
|
+
stopPolling("disabled");
|
|
77791
|
+
abortAll();
|
|
77792
|
+
store.reset();
|
|
77793
|
+
return;
|
|
77794
|
+
}
|
|
77401
77795
|
if (!supabase || !companyId || lineIds.length === 0) {
|
|
77402
77796
|
stopPolling("scope_invalid");
|
|
77403
77797
|
abortAll();
|
|
@@ -77405,9 +77799,9 @@ var useOperationsOverviewRefresh = ({
|
|
|
77405
77799
|
return;
|
|
77406
77800
|
}
|
|
77407
77801
|
void refreshAll("scope_change");
|
|
77408
|
-
}, [abortAll, companyId, lineIds.length, refreshAll, scopeSignature, stopPolling, store, supabase]);
|
|
77802
|
+
}, [abortAll, companyId, enabled, lineIds.length, refreshAll, scopeSignature, stopPolling, store, supabase]);
|
|
77409
77803
|
React141__namespace.default.useEffect(() => {
|
|
77410
|
-
if (!isLiveScope || !supabase || !companyId || lineIds.length === 0) {
|
|
77804
|
+
if (!enabled || !isLiveScope || !supabase || !companyId || lineIds.length === 0) {
|
|
77411
77805
|
isPageActiveRef.current = false;
|
|
77412
77806
|
stopPolling("live_scope_disabled");
|
|
77413
77807
|
return;
|
|
@@ -77463,11 +77857,63 @@ var useOperationsOverviewRefresh = ({
|
|
|
77463
77857
|
window.removeEventListener("pageshow", handlePageShow);
|
|
77464
77858
|
window.removeEventListener("pagehide", handlePageHide);
|
|
77465
77859
|
};
|
|
77466
|
-
}, [companyId, getIsPageActive, isLiveScope, lineIds.length, refreshFromResume, startPolling, stopPolling, supabase]);
|
|
77860
|
+
}, [companyId, enabled, getIsPageActive, isLiveScope, lineIds.length, refreshFromResume, startPolling, stopPolling, supabase]);
|
|
77861
|
+
};
|
|
77862
|
+
var parseTimeToMinutes3 = (value) => {
|
|
77863
|
+
if (!value) return null;
|
|
77864
|
+
const parts = value.split(":");
|
|
77865
|
+
if (parts.length < 2) return null;
|
|
77866
|
+
const hours = Number(parts[0]);
|
|
77867
|
+
const minutes = Number(parts[1]);
|
|
77868
|
+
if (!Number.isFinite(hours) || !Number.isFinite(minutes)) return null;
|
|
77869
|
+
if (hours < 0 || hours > 23 || minutes < 0 || minutes > 59) return null;
|
|
77870
|
+
return hours * 60 + minutes;
|
|
77871
|
+
};
|
|
77872
|
+
var normalizeShiftId = (value) => {
|
|
77873
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
77874
|
+
return value;
|
|
77875
|
+
}
|
|
77876
|
+
if (typeof value === "string" && value.trim().length > 0) {
|
|
77877
|
+
const parsed = Number(value);
|
|
77878
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
77879
|
+
}
|
|
77880
|
+
return null;
|
|
77881
|
+
};
|
|
77882
|
+
var classifyShiftBucket = ({
|
|
77883
|
+
shiftName,
|
|
77884
|
+
shiftId,
|
|
77885
|
+
startTime,
|
|
77886
|
+
endTime
|
|
77887
|
+
}) => {
|
|
77888
|
+
const normalizedName = (shiftName || "").trim().toLowerCase();
|
|
77889
|
+
if (normalizedName) {
|
|
77890
|
+
if (["night", "graveyard", "evening"].some((keyword) => normalizedName.includes(keyword))) {
|
|
77891
|
+
return "night";
|
|
77892
|
+
}
|
|
77893
|
+
if (["day", "morning"].some((keyword) => normalizedName.includes(keyword))) {
|
|
77894
|
+
return "day";
|
|
77895
|
+
}
|
|
77896
|
+
}
|
|
77897
|
+
const startMinutes = parseTimeToMinutes3(startTime);
|
|
77898
|
+
const endMinutes = parseTimeToMinutes3(endTime);
|
|
77899
|
+
if (startMinutes !== null) {
|
|
77900
|
+
if (startMinutes >= 4 * 60 && startMinutes < 18 * 60) return "day";
|
|
77901
|
+
return "night";
|
|
77902
|
+
}
|
|
77903
|
+
if (endMinutes !== null) {
|
|
77904
|
+
if (endMinutes >= 6 * 60 && endMinutes <= 21 * 60) return "day";
|
|
77905
|
+
return "night";
|
|
77906
|
+
}
|
|
77907
|
+
const normalizedShiftId = normalizeShiftId(shiftId);
|
|
77908
|
+
if (normalizedShiftId === 0) return "day";
|
|
77909
|
+
if (normalizedShiftId === 1) return "night";
|
|
77910
|
+
return null;
|
|
77467
77911
|
};
|
|
77468
77912
|
var PlantHeadView = () => {
|
|
77469
77913
|
const supabase = useSupabase();
|
|
77470
77914
|
const entityConfig = useEntityConfig();
|
|
77915
|
+
const factoryViewId = entityConfig.factoryViewId || "factory";
|
|
77916
|
+
const staticShiftConfig = useShiftConfig();
|
|
77471
77917
|
const appTimezone = useAppTimezone() || "UTC";
|
|
77472
77918
|
const { navigate } = useNavigation();
|
|
77473
77919
|
const { accessibleLineIds } = useUserLineAccess();
|
|
@@ -77475,11 +77921,21 @@ var PlantHeadView = () => {
|
|
|
77475
77921
|
useHideMobileHeader(!!mobileMenuContext);
|
|
77476
77922
|
const storeRef = React141__namespace.default.useRef(createOperationsOverviewStore());
|
|
77477
77923
|
const store = storeRef.current;
|
|
77478
|
-
const
|
|
77479
|
-
|
|
77924
|
+
const fallbackOperationalDate = React141__namespace.default.useMemo(
|
|
77925
|
+
() => getOperationalDate(appTimezone),
|
|
77926
|
+
[appTimezone]
|
|
77927
|
+
);
|
|
77928
|
+
const [dateRange, setDateRange] = React141__namespace.default.useState(() => ({
|
|
77929
|
+
startKey: fallbackOperationalDate,
|
|
77930
|
+
endKey: fallbackOperationalDate
|
|
77931
|
+
}));
|
|
77932
|
+
const [usesThisWeekComparison, setUsesThisWeekComparison] = React141__namespace.default.useState(false);
|
|
77480
77933
|
const [trendMode, setTrendMode] = React141__namespace.default.useState("all");
|
|
77481
77934
|
const [selectedSupervisorId, setSelectedSupervisorId] = React141__namespace.default.useState("all");
|
|
77482
77935
|
const [selectedLineIds, setSelectedLineIds] = React141__namespace.default.useState([]);
|
|
77936
|
+
const [isInitialScopeReady, setIsInitialScopeReady] = React141__namespace.default.useState(false);
|
|
77937
|
+
const hasAutoInitializedScopeRef = React141__namespace.default.useRef(false);
|
|
77938
|
+
const hasUserAdjustedScopeRef = React141__namespace.default.useRef(false);
|
|
77483
77939
|
React141__namespace.default.useEffect(() => {
|
|
77484
77940
|
trackCorePageView("Operations Overview", {
|
|
77485
77941
|
dashboard_surface: "operations_overview"
|
|
@@ -77501,8 +77957,10 @@ var PlantHeadView = () => {
|
|
|
77501
77957
|
return dateRange;
|
|
77502
77958
|
}, [currentWeekDisplayRange, dateRange, isCurrentWeekToDateRange, usesThisWeekComparison]);
|
|
77503
77959
|
const normalizedLineIds = React141__namespace.default.useMemo(
|
|
77504
|
-
() => Array.from(new Set(
|
|
77505
|
-
|
|
77960
|
+
() => Array.from(new Set(
|
|
77961
|
+
(accessibleLineIds || []).filter(Boolean).filter((lineId) => lineId !== factoryViewId)
|
|
77962
|
+
)).sort(),
|
|
77963
|
+
[accessibleLineIds, factoryViewId]
|
|
77506
77964
|
);
|
|
77507
77965
|
const lineIdsKey = React141__namespace.default.useMemo(
|
|
77508
77966
|
() => normalizedLineIds.join(","),
|
|
@@ -77576,14 +78034,81 @@ var PlantHeadView = () => {
|
|
|
77576
78034
|
() => selectedLineIds.length > 0 ? selectedLineIds : normalizedLineIds,
|
|
77577
78035
|
[normalizedLineIds, selectedLineIds]
|
|
77578
78036
|
);
|
|
78037
|
+
const {
|
|
78038
|
+
shiftConfigMap,
|
|
78039
|
+
isLoading: isShiftConfigLoading
|
|
78040
|
+
} = useMultiLineShiftConfigs(scopedLineIds, staticShiftConfig);
|
|
78041
|
+
const { shiftGroups, hasComputed: hasComputedShiftGroups } = useShiftGroups({
|
|
78042
|
+
enabled: scopedLineIds.length > 0 && !isShiftConfigLoading,
|
|
78043
|
+
shiftConfigMap,
|
|
78044
|
+
timezone: appTimezone
|
|
78045
|
+
});
|
|
78046
|
+
const currentShiftScope = React141__namespace.default.useMemo(() => {
|
|
78047
|
+
if (shiftGroups.length !== 1) return null;
|
|
78048
|
+
const group = shiftGroups[0];
|
|
78049
|
+
const referenceLineId = group.lineIds[0];
|
|
78050
|
+
const referenceShiftConfig = referenceLineId ? shiftConfigMap.get(referenceLineId) : null;
|
|
78051
|
+
const normalizedGroupShiftId = normalizeShiftId(group.shiftId);
|
|
78052
|
+
const shiftDefinition = referenceShiftConfig?.shifts?.find((shift) => normalizeShiftId(shift.shiftId) === normalizedGroupShiftId);
|
|
78053
|
+
const resolvedMode = classifyShiftBucket({
|
|
78054
|
+
shiftName: group.shiftName,
|
|
78055
|
+
shiftId: normalizedGroupShiftId,
|
|
78056
|
+
startTime: shiftDefinition?.startTime,
|
|
78057
|
+
endTime: shiftDefinition?.endTime
|
|
78058
|
+
});
|
|
78059
|
+
if (!resolvedMode || resolvedMode === "all") return null;
|
|
78060
|
+
return {
|
|
78061
|
+
date: group.date,
|
|
78062
|
+
trendMode: resolvedMode,
|
|
78063
|
+
shiftName: shiftDefinition?.shiftName || group.shiftName || null
|
|
78064
|
+
};
|
|
78065
|
+
}, [shiftConfigMap, shiftGroups]);
|
|
78066
|
+
const isShiftScopeResolved = React141__namespace.default.useMemo(
|
|
78067
|
+
() => !isShiftConfigLoading && hasComputedShiftGroups,
|
|
78068
|
+
[hasComputedShiftGroups, isShiftConfigLoading]
|
|
78069
|
+
);
|
|
77579
78070
|
const initializedTimezoneRef = React141__namespace.default.useRef(appTimezone);
|
|
77580
78071
|
React141__namespace.default.useEffect(() => {
|
|
77581
78072
|
if (initializedTimezoneRef.current === appTimezone) return;
|
|
77582
|
-
|
|
77583
|
-
|
|
78073
|
+
hasAutoInitializedScopeRef.current = false;
|
|
78074
|
+
hasUserAdjustedScopeRef.current = false;
|
|
78075
|
+
setDateRange({
|
|
78076
|
+
startKey: fallbackOperationalDate,
|
|
78077
|
+
endKey: fallbackOperationalDate
|
|
78078
|
+
});
|
|
78079
|
+
setTrendMode("all");
|
|
78080
|
+
setUsesThisWeekComparison(false);
|
|
78081
|
+
setIsInitialScopeReady(false);
|
|
77584
78082
|
initializedTimezoneRef.current = appTimezone;
|
|
77585
|
-
}, [appTimezone]);
|
|
78083
|
+
}, [appTimezone, fallbackOperationalDate]);
|
|
78084
|
+
React141__namespace.default.useEffect(() => {
|
|
78085
|
+
if (hasAutoInitializedScopeRef.current || hasUserAdjustedScopeRef.current) {
|
|
78086
|
+
return;
|
|
78087
|
+
}
|
|
78088
|
+
if (scopedLineIds.length === 0) {
|
|
78089
|
+
return;
|
|
78090
|
+
}
|
|
78091
|
+
if (!isShiftScopeResolved) {
|
|
78092
|
+
return;
|
|
78093
|
+
}
|
|
78094
|
+
setDateRange((previous) => {
|
|
78095
|
+
const nextStartKey = currentShiftScope?.date || fallbackOperationalDate;
|
|
78096
|
+
if (previous.startKey === nextStartKey && previous.endKey === nextStartKey) {
|
|
78097
|
+
return previous;
|
|
78098
|
+
}
|
|
78099
|
+
return {
|
|
78100
|
+
startKey: nextStartKey,
|
|
78101
|
+
endKey: nextStartKey
|
|
78102
|
+
};
|
|
78103
|
+
});
|
|
78104
|
+
setTrendMode(currentShiftScope?.trendMode || "all");
|
|
78105
|
+
setUsesThisWeekComparison(false);
|
|
78106
|
+
hasAutoInitializedScopeRef.current = true;
|
|
78107
|
+
setIsInitialScopeReady(true);
|
|
78108
|
+
}, [currentShiftScope, fallbackOperationalDate, isShiftScopeResolved, scopedLineIds.length]);
|
|
77586
78109
|
const handleDateRangeChange = React141__namespace.default.useCallback((range, meta) => {
|
|
78110
|
+
hasUserAdjustedScopeRef.current = true;
|
|
78111
|
+
setIsInitialScopeReady(true);
|
|
77587
78112
|
trackCoreEvent("Operations Overview Date Range Changed", {
|
|
77588
78113
|
start_date: range.startKey,
|
|
77589
78114
|
end_date: range.endKey
|
|
@@ -77600,6 +78125,8 @@ var PlantHeadView = () => {
|
|
|
77600
78125
|
});
|
|
77601
78126
|
}, []);
|
|
77602
78127
|
const handleTrendModeChange = React141__namespace.default.useCallback((mode) => {
|
|
78128
|
+
hasUserAdjustedScopeRef.current = true;
|
|
78129
|
+
setIsInitialScopeReady(true);
|
|
77603
78130
|
setTrendMode(mode);
|
|
77604
78131
|
}, []);
|
|
77605
78132
|
const handleSelectedLineIdsChange = React141__namespace.default.useCallback((lineIds) => {
|
|
@@ -77626,15 +78153,6 @@ var PlantHeadView = () => {
|
|
|
77626
78153
|
params.set("rangeEnd", dateRange.endKey);
|
|
77627
78154
|
return `/kpis/${lineId}?${params.toString()}`;
|
|
77628
78155
|
}, [dateRange.endKey, dateRange.startKey]);
|
|
77629
|
-
const handleOpenLineMonthlyHistory = React141__namespace.default.useCallback((lineId, lineName) => {
|
|
77630
|
-
trackCoreEvent("Operations Overview Line Clicked", {
|
|
77631
|
-
line_id: lineId,
|
|
77632
|
-
line_name: lineName,
|
|
77633
|
-
range_start: dateRange.startKey,
|
|
77634
|
-
range_end: dateRange.endKey
|
|
77635
|
-
});
|
|
77636
|
-
navigate(buildLineMonthlyHistoryUrl(lineId));
|
|
77637
|
-
}, [buildLineMonthlyHistoryUrl, dateRange.endKey, dateRange.startKey, navigate]);
|
|
77638
78156
|
const handleViewAllPoorestPerformers = React141__namespace.default.useCallback(() => {
|
|
77639
78157
|
trackCoreEvent("Operations Overview View All Clicked", { section: "poorest_performers" });
|
|
77640
78158
|
navigate("/kpis?tab=leaderboard");
|
|
@@ -77660,16 +78178,74 @@ var PlantHeadView = () => {
|
|
|
77660
78178
|
}
|
|
77661
78179
|
return void 0;
|
|
77662
78180
|
}, [isCurrentWeekToDateRange, usesThisWeekComparison]);
|
|
78181
|
+
const effectiveDateRange = React141__namespace.default.useMemo(() => {
|
|
78182
|
+
if (isInitialScopeReady) {
|
|
78183
|
+
return dateRange;
|
|
78184
|
+
}
|
|
78185
|
+
const nextStartKey = currentShiftScope?.date || fallbackOperationalDate;
|
|
78186
|
+
return {
|
|
78187
|
+
startKey: nextStartKey,
|
|
78188
|
+
endKey: nextStartKey
|
|
78189
|
+
};
|
|
78190
|
+
}, [currentShiftScope, dateRange, fallbackOperationalDate, isInitialScopeReady]);
|
|
78191
|
+
const effectiveTrendMode = React141__namespace.default.useMemo(
|
|
78192
|
+
() => isInitialScopeReady ? trendMode : currentShiftScope?.trendMode || "all",
|
|
78193
|
+
[currentShiftScope, isInitialScopeReady, trendMode]
|
|
78194
|
+
);
|
|
78195
|
+
const hourlyLabelStartTime = React141__namespace.default.useMemo(() => {
|
|
78196
|
+
if (effectiveTrendMode === "all" || scopedLineIds.length === 0) {
|
|
78197
|
+
return null;
|
|
78198
|
+
}
|
|
78199
|
+
const shiftStartTimes = /* @__PURE__ */ new Set();
|
|
78200
|
+
scopedLineIds.forEach((lineId) => {
|
|
78201
|
+
const shiftConfig = shiftConfigMap.get(lineId);
|
|
78202
|
+
const matchingShift = shiftConfig?.shifts?.find((shift) => classifyShiftBucket({
|
|
78203
|
+
shiftName: shift.shiftName,
|
|
78204
|
+
shiftId: shift.shiftId,
|
|
78205
|
+
startTime: shift.startTime,
|
|
78206
|
+
endTime: shift.endTime
|
|
78207
|
+
}) === effectiveTrendMode);
|
|
78208
|
+
if (matchingShift?.startTime) {
|
|
78209
|
+
shiftStartTimes.add(matchingShift.startTime);
|
|
78210
|
+
}
|
|
78211
|
+
});
|
|
78212
|
+
if (shiftStartTimes.size !== 1) {
|
|
78213
|
+
return null;
|
|
78214
|
+
}
|
|
78215
|
+
return Array.from(shiftStartTimes)[0] || null;
|
|
78216
|
+
}, [effectiveTrendMode, scopedLineIds, shiftConfigMap]);
|
|
78217
|
+
const isSingleDayShiftScope = React141__namespace.default.useMemo(
|
|
78218
|
+
() => effectiveDateRange.startKey === effectiveDateRange.endKey && effectiveTrendMode !== "all",
|
|
78219
|
+
[effectiveDateRange.endKey, effectiveDateRange.startKey, effectiveTrendMode]
|
|
78220
|
+
);
|
|
78221
|
+
const isLiveScope = React141__namespace.default.useMemo(
|
|
78222
|
+
() => isSingleDayShiftScope && currentShiftScope !== null && effectiveDateRange.startKey === currentShiftScope.date && effectiveTrendMode === currentShiftScope.trendMode,
|
|
78223
|
+
[currentShiftScope, effectiveDateRange.startKey, effectiveTrendMode, isSingleDayShiftScope]
|
|
78224
|
+
);
|
|
78225
|
+
const handleOpenLineDetails = React141__namespace.default.useCallback((lineId, lineName) => {
|
|
78226
|
+
trackCoreEvent("Operations Overview Line Clicked", {
|
|
78227
|
+
line_id: lineId,
|
|
78228
|
+
line_name: lineName,
|
|
78229
|
+
range_start: dateRange.startKey,
|
|
78230
|
+
range_end: dateRange.endKey
|
|
78231
|
+
});
|
|
78232
|
+
if (isLiveScope) {
|
|
78233
|
+
navigate(`/kpis/${lineId}?returnTo=${encodeURIComponent("/")}`);
|
|
78234
|
+
return;
|
|
78235
|
+
}
|
|
78236
|
+
navigate(buildLineMonthlyHistoryUrl(lineId));
|
|
78237
|
+
}, [buildLineMonthlyHistoryUrl, dateRange.endKey, dateRange.startKey, isLiveScope, navigate]);
|
|
77663
78238
|
useOperationsOverviewRefresh({
|
|
77664
78239
|
store,
|
|
77665
78240
|
supabase,
|
|
77666
78241
|
companyId: entityConfig.companyId,
|
|
77667
78242
|
lineIds: scopedLineIds,
|
|
77668
|
-
startKey:
|
|
77669
|
-
endKey:
|
|
77670
|
-
trendMode,
|
|
78243
|
+
startKey: effectiveDateRange.startKey,
|
|
78244
|
+
endKey: effectiveDateRange.endKey,
|
|
78245
|
+
trendMode: effectiveTrendMode,
|
|
77671
78246
|
comparisonStrategy,
|
|
77672
|
-
isLiveScope
|
|
78247
|
+
isLiveScope,
|
|
78248
|
+
enabled: scopedLineIds.length > 0 && isShiftScopeResolved
|
|
77673
78249
|
});
|
|
77674
78250
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col min-h-screen bg-slate-50 w-full font-sans", children: [
|
|
77675
78251
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -77678,6 +78254,8 @@ var PlantHeadView = () => {
|
|
|
77678
78254
|
dateRange,
|
|
77679
78255
|
displayDateRange: headerDateRange,
|
|
77680
78256
|
trendMode,
|
|
78257
|
+
isLiveScope,
|
|
78258
|
+
liveShiftName: currentShiftScope?.shiftName || null,
|
|
77681
78259
|
lineOptions,
|
|
77682
78260
|
supervisorOptions,
|
|
77683
78261
|
selectedSupervisorId,
|
|
@@ -77700,7 +78278,7 @@ var PlantHeadView = () => {
|
|
|
77700
78278
|
store,
|
|
77701
78279
|
supervisorsByLineId,
|
|
77702
78280
|
onViewAll: handleViewAllPoorestPerformers,
|
|
77703
|
-
onLineClick:
|
|
78281
|
+
onLineClick: handleOpenLineDetails
|
|
77704
78282
|
}
|
|
77705
78283
|
),
|
|
77706
78284
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -77717,7 +78295,8 @@ var PlantHeadView = () => {
|
|
|
77717
78295
|
{
|
|
77718
78296
|
store,
|
|
77719
78297
|
dateRange,
|
|
77720
|
-
appTimezone
|
|
78298
|
+
appTimezone,
|
|
78299
|
+
hourlyLabelStartTime
|
|
77721
78300
|
}
|
|
77722
78301
|
),
|
|
77723
78302
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -78578,6 +79157,7 @@ exports.isEfficiencyOnTrack = isEfficiencyOnTrack;
|
|
|
78578
79157
|
exports.isFactoryScopedRole = isFactoryScopedRole;
|
|
78579
79158
|
exports.isFullMonthRange = isFullMonthRange;
|
|
78580
79159
|
exports.isLegacyConfiguration = isLegacyConfiguration;
|
|
79160
|
+
exports.isLoopbackHostname = isLoopbackHostname;
|
|
78581
79161
|
exports.isPrefetchError = isPrefetchError;
|
|
78582
79162
|
exports.isRecentFlowVideoGridMetricMode = isRecentFlowVideoGridMetricMode;
|
|
78583
79163
|
exports.isSafari = isSafari;
|
|
@@ -78619,6 +79199,7 @@ exports.resetSubscriptionManager = resetSubscriptionManager;
|
|
|
78619
79199
|
exports.s3VideoPreloader = s3VideoPreloader;
|
|
78620
79200
|
exports.setSentryUserContext = setSentryUserContext;
|
|
78621
79201
|
exports.setSentryWorkspaceContext = setSentryWorkspaceContext;
|
|
79202
|
+
exports.shouldEnableLocalDevTestLogin = shouldEnableLocalDevTestLogin;
|
|
78622
79203
|
exports.shuffleArray = shuffleArray;
|
|
78623
79204
|
exports.simulateApiDelay = simulateApiDelay;
|
|
78624
79205
|
exports.skuService = skuService;
|