@optifye/dashboard-core 6.9.2 → 6.9.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.css +0 -4
- package/dist/index.d.mts +43 -15
- package/dist/index.d.ts +43 -15
- package/dist/index.js +375 -609
- package/dist/index.mjs +375 -609
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2088,6 +2088,59 @@ var workspaceService = {
|
|
|
2088
2088
|
console.error("Error updating shift configuration:", error);
|
|
2089
2089
|
throw error;
|
|
2090
2090
|
}
|
|
2091
|
+
},
|
|
2092
|
+
/**
|
|
2093
|
+
* Fetch bulk targets data for multiple lines and shifts in a single API call
|
|
2094
|
+
* This replaces 120+ individual API calls with 1 optimized call
|
|
2095
|
+
*
|
|
2096
|
+
* @param params - Parameters for the bulk fetch
|
|
2097
|
+
* @returns Promise with complete targets data for all lines and shifts
|
|
2098
|
+
*/
|
|
2099
|
+
async fetchBulkTargets(params) {
|
|
2100
|
+
try {
|
|
2101
|
+
const token = await getAuthToken();
|
|
2102
|
+
const apiUrl = getBackendUrl();
|
|
2103
|
+
const {
|
|
2104
|
+
companyId,
|
|
2105
|
+
lineIds,
|
|
2106
|
+
date,
|
|
2107
|
+
shifts = [0, 1],
|
|
2108
|
+
includeSkus = true,
|
|
2109
|
+
includeActions = true
|
|
2110
|
+
} = params;
|
|
2111
|
+
const queryParams = new URLSearchParams({
|
|
2112
|
+
company_id: companyId,
|
|
2113
|
+
line_ids: lineIds.join(","),
|
|
2114
|
+
date,
|
|
2115
|
+
shifts: shifts.join(","),
|
|
2116
|
+
include_skus: includeSkus.toString(),
|
|
2117
|
+
include_actions: includeActions.toString()
|
|
2118
|
+
});
|
|
2119
|
+
const response = await fetch(
|
|
2120
|
+
`${apiUrl}/api/targets/bulk-load?${queryParams}`,
|
|
2121
|
+
{
|
|
2122
|
+
method: "GET",
|
|
2123
|
+
headers: {
|
|
2124
|
+
"Authorization": `Bearer ${token}`,
|
|
2125
|
+
"Content-Type": "application/json"
|
|
2126
|
+
}
|
|
2127
|
+
}
|
|
2128
|
+
);
|
|
2129
|
+
if (!response.ok) {
|
|
2130
|
+
const errorText = await response.text();
|
|
2131
|
+
throw new Error(`Backend API error (${response.status}): ${errorText}`);
|
|
2132
|
+
}
|
|
2133
|
+
const data = await response.json();
|
|
2134
|
+
console.log("[fetchBulkTargets] Success:", {
|
|
2135
|
+
lineCount: data.metadata?.line_count,
|
|
2136
|
+
totalWorkspaces: data.metadata?.total_workspaces,
|
|
2137
|
+
timestamp: data.metadata?.timestamp
|
|
2138
|
+
});
|
|
2139
|
+
return data;
|
|
2140
|
+
} catch (error) {
|
|
2141
|
+
console.error("Error fetching bulk targets:", error);
|
|
2142
|
+
throw error;
|
|
2143
|
+
}
|
|
2091
2144
|
}
|
|
2092
2145
|
};
|
|
2093
2146
|
var WorkspaceHealthService = class _WorkspaceHealthService {
|
|
@@ -5822,60 +5875,32 @@ var UserManagementService = class {
|
|
|
5822
5875
|
}
|
|
5823
5876
|
}
|
|
5824
5877
|
/**
|
|
5825
|
-
*
|
|
5826
|
-
* @param
|
|
5878
|
+
* Permanently delete a user
|
|
5879
|
+
* @param userId - The ID of the user to delete
|
|
5880
|
+
* @returns Promise with deletion response
|
|
5827
5881
|
*/
|
|
5828
|
-
async
|
|
5882
|
+
async deleteUser(userId) {
|
|
5829
5883
|
try {
|
|
5830
5884
|
const token = await this.getAuthToken();
|
|
5831
5885
|
const backendUrl = this.getBackendUrl();
|
|
5832
5886
|
const response = await fetch(
|
|
5833
|
-
`${backendUrl}/api/users
|
|
5834
|
-
{
|
|
5835
|
-
method: "POST",
|
|
5836
|
-
headers: {
|
|
5837
|
-
"Authorization": `Bearer ${token}`,
|
|
5838
|
-
"Content-Type": "application/json"
|
|
5839
|
-
},
|
|
5840
|
-
body: JSON.stringify(input)
|
|
5841
|
-
}
|
|
5842
|
-
);
|
|
5843
|
-
if (!response.ok) {
|
|
5844
|
-
const errorData = await response.json();
|
|
5845
|
-
throw new Error(`Failed to deactivate user: ${errorData.detail || response.statusText}`);
|
|
5846
|
-
}
|
|
5847
|
-
console.log("[UserManagementService] User deactivated successfully");
|
|
5848
|
-
} catch (error) {
|
|
5849
|
-
console.error("[UserManagementService] Error deactivating user:", error);
|
|
5850
|
-
throw error;
|
|
5851
|
-
}
|
|
5852
|
-
}
|
|
5853
|
-
/**
|
|
5854
|
-
* Reactivate a user
|
|
5855
|
-
* @param input - Reactivation input
|
|
5856
|
-
*/
|
|
5857
|
-
async reactivateUser(input) {
|
|
5858
|
-
try {
|
|
5859
|
-
const token = await this.getAuthToken();
|
|
5860
|
-
const backendUrl = this.getBackendUrl();
|
|
5861
|
-
const response = await fetch(
|
|
5862
|
-
`${backendUrl}/api/users/reactivate`,
|
|
5887
|
+
`${backendUrl}/api/users/${userId}`,
|
|
5863
5888
|
{
|
|
5864
|
-
method: "
|
|
5889
|
+
method: "DELETE",
|
|
5865
5890
|
headers: {
|
|
5866
|
-
"Authorization": `Bearer ${token}
|
|
5867
|
-
|
|
5868
|
-
},
|
|
5869
|
-
body: JSON.stringify(input)
|
|
5891
|
+
"Authorization": `Bearer ${token}`
|
|
5892
|
+
}
|
|
5870
5893
|
}
|
|
5871
5894
|
);
|
|
5872
5895
|
if (!response.ok) {
|
|
5873
5896
|
const errorData = await response.json();
|
|
5874
|
-
throw new Error(`Failed to
|
|
5897
|
+
throw new Error(`Failed to delete user: ${errorData.detail || response.statusText}`);
|
|
5875
5898
|
}
|
|
5876
|
-
|
|
5899
|
+
const result = await response.json();
|
|
5900
|
+
console.log("[UserManagementService] User permanently deleted:", result);
|
|
5901
|
+
return result;
|
|
5877
5902
|
} catch (error) {
|
|
5878
|
-
console.error("[UserManagementService] Error
|
|
5903
|
+
console.error("[UserManagementService] Error deleting user:", error);
|
|
5879
5904
|
throw error;
|
|
5880
5905
|
}
|
|
5881
5906
|
}
|
|
@@ -7688,7 +7713,7 @@ var useLeaderboardMetrics = (date, shiftId, limit = 10, filter2 = "all") => {
|
|
|
7688
7713
|
refetch: fetchLeaderboard
|
|
7689
7714
|
};
|
|
7690
7715
|
};
|
|
7691
|
-
var useDashboardMetrics = ({ onLineMetricsUpdate, lineId }) => {
|
|
7716
|
+
var useDashboardMetrics = ({ onLineMetricsUpdate, lineId, userAccessibleLineIds }) => {
|
|
7692
7717
|
const { supabaseUrl, supabaseKey } = useDashboardConfig();
|
|
7693
7718
|
const entityConfig = useEntityConfig();
|
|
7694
7719
|
const databaseConfig = useDatabaseConfig();
|
|
@@ -7733,7 +7758,7 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId }) => {
|
|
|
7733
7758
|
try {
|
|
7734
7759
|
const currentShiftDetails = getCurrentShift(defaultTimezone, shiftConfig);
|
|
7735
7760
|
const operationalDate = getOperationalDate(defaultTimezone);
|
|
7736
|
-
const targetLineIds = currentLineIdToUse === (entityConfig.factoryViewId || "factory") ? getConfiguredLineIds(entityConfig) : [currentLineIdToUse];
|
|
7761
|
+
const targetLineIds = currentLineIdToUse === (entityConfig.factoryViewId || "factory") ? userAccessibleLineIds || getConfiguredLineIds(entityConfig) : [currentLineIdToUse];
|
|
7737
7762
|
if (targetLineIds.length === 0 && currentLineIdToUse === (entityConfig.factoryViewId || "factory")) {
|
|
7738
7763
|
throw new Error("Factory view selected, but no lines are configured in entityConfig.");
|
|
7739
7764
|
}
|
|
@@ -7859,7 +7884,7 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId }) => {
|
|
|
7859
7884
|
}
|
|
7860
7885
|
const currentShiftDetails = getCurrentShift(defaultTimezone, shiftConfig);
|
|
7861
7886
|
const operationalDateForSubscription = getOperationalDate(defaultTimezone);
|
|
7862
|
-
const targetLineIds = currentLineIdToUse === (entityConfig.factoryViewId || "factory") ? getConfiguredLineIds(entityConfig) : [currentLineIdToUse];
|
|
7887
|
+
const targetLineIds = currentLineIdToUse === (entityConfig.factoryViewId || "factory") ? userAccessibleLineIds || getConfiguredLineIds(entityConfig) : [currentLineIdToUse];
|
|
7863
7888
|
if (targetLineIds.length === 0) return;
|
|
7864
7889
|
const wsMetricsFilter = `line_id=in.(${targetLineIds.map((id3) => `"${id3}"`).join(",")})`;
|
|
7865
7890
|
const lineMetricsFilter = `line_id=in.(${targetLineIds.map((id3) => `"${id3}"`).join(",")})`;
|
|
@@ -7897,7 +7922,8 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId }) => {
|
|
|
7897
7922
|
entityConfig?.companyId,
|
|
7898
7923
|
entityConfig?.factoryViewId,
|
|
7899
7924
|
defaultTimezone,
|
|
7900
|
-
lineId
|
|
7925
|
+
lineId,
|
|
7926
|
+
userAccessibleLineIds
|
|
7901
7927
|
]);
|
|
7902
7928
|
return {
|
|
7903
7929
|
workspaceMetrics: metrics2?.workspaceMetrics || [],
|
|
@@ -9887,7 +9913,8 @@ var useAllWorkspaceMetrics = (options) => {
|
|
|
9887
9913
|
}
|
|
9888
9914
|
setError(null);
|
|
9889
9915
|
try {
|
|
9890
|
-
const
|
|
9916
|
+
const allConfiguredLineIds = getConfiguredLineIds(entityConfig);
|
|
9917
|
+
const configuredLineIds = options?.allowedLineIds ? allConfiguredLineIds.filter((id3) => options.allowedLineIds.includes(id3)) : allConfiguredLineIds;
|
|
9891
9918
|
let enabledWorkspaceIds = [];
|
|
9892
9919
|
for (const lineId of configuredLineIds) {
|
|
9893
9920
|
const workspaces2 = await workspaceService.getWorkspaces(lineId);
|
|
@@ -9950,7 +9977,7 @@ var useAllWorkspaceMetrics = (options) => {
|
|
|
9950
9977
|
setLoading(false);
|
|
9951
9978
|
isFetchingRef.current = false;
|
|
9952
9979
|
}
|
|
9953
|
-
}, [queryDate, queryShiftId, metricsTable, supabase, entityConfig.companyId]);
|
|
9980
|
+
}, [queryDate, queryShiftId, metricsTable, supabase, entityConfig.companyId, entityConfig, options?.allowedLineIds]);
|
|
9954
9981
|
React23.useEffect(() => {
|
|
9955
9982
|
if (!initialized) {
|
|
9956
9983
|
fetchWorkspaceMetrics();
|
|
@@ -24335,6 +24362,7 @@ var VideoCard = React23__namespace.default.memo(({
|
|
|
24335
24362
|
useRAF = true,
|
|
24336
24363
|
className = "",
|
|
24337
24364
|
compact = false,
|
|
24365
|
+
displayName,
|
|
24338
24366
|
onMouseEnter,
|
|
24339
24367
|
onMouseLeave
|
|
24340
24368
|
}) => {
|
|
@@ -24356,7 +24384,7 @@ var VideoCard = React23__namespace.default.memo(({
|
|
|
24356
24384
|
onFatalError: onFatalError ?? (() => throttledReloadDashboard())
|
|
24357
24385
|
});
|
|
24358
24386
|
}
|
|
24359
|
-
const
|
|
24387
|
+
const workspaceDisplayName = displayName || getWorkspaceDisplayName(workspace.workspace_name, workspace.line_id);
|
|
24360
24388
|
const getEfficiencyOverlayColor = (efficiency) => {
|
|
24361
24389
|
if (efficiency >= 80) {
|
|
24362
24390
|
return "bg-[#00D654]/25";
|
|
@@ -24449,7 +24477,7 @@ var VideoCard = React23__namespace.default.memo(({
|
|
|
24449
24477
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: `absolute bottom-0 left-0 right-0 bg-black bg-opacity-60 p-1.5 sm:${compact ? "p-1" : "p-1.5"} flex justify-between items-center z-10`, children: [
|
|
24450
24478
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
|
|
24451
24479
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Camera, { size: compact ? 10 : 12, className: "text-white" }),
|
|
24452
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: `text-white text-[11px] sm:${compact ? "text-[10px]" : "text-xs"} font-medium tracking-wide`, children:
|
|
24480
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: `text-white text-[11px] sm:${compact ? "text-[10px]" : "text-xs"} font-medium tracking-wide`, children: workspaceDisplayName })
|
|
24453
24481
|
] }),
|
|
24454
24482
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: `flex items-center ${compact ? "gap-1" : "gap-1.5"}`, children: [
|
|
24455
24483
|
trendInfo && /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -24486,6 +24514,7 @@ var VideoGridView = React23__namespace.default.memo(({
|
|
|
24486
24514
|
selectedLine,
|
|
24487
24515
|
className = "",
|
|
24488
24516
|
videoSources = {},
|
|
24517
|
+
displayNames = {},
|
|
24489
24518
|
onWorkspaceHover,
|
|
24490
24519
|
onWorkspaceHoverEnd
|
|
24491
24520
|
}) => {
|
|
@@ -24700,6 +24729,7 @@ var VideoGridView = React23__namespace.default.memo(({
|
|
|
24700
24729
|
isVeryLowEfficiency,
|
|
24701
24730
|
cropping: workspaceCropping,
|
|
24702
24731
|
canvasFps: canvasConfig?.fps,
|
|
24732
|
+
displayName: displayNames[workspace.workspace_name] || workspace.workspace_name,
|
|
24703
24733
|
useRAF: canvasConfig?.useRAF,
|
|
24704
24734
|
compact: !selectedLine,
|
|
24705
24735
|
onMouseEnter: onWorkspaceHover ? () => onWorkspaceHover(workspaceId) : void 0,
|
|
@@ -24717,6 +24747,7 @@ VideoGridView.displayName = "VideoGridView";
|
|
|
24717
24747
|
var MapGridView = React23__namespace.default.memo(({
|
|
24718
24748
|
workspaces,
|
|
24719
24749
|
className = "",
|
|
24750
|
+
displayNames = {},
|
|
24720
24751
|
onWorkspaceHover,
|
|
24721
24752
|
onWorkspaceHoverEnd
|
|
24722
24753
|
}) => {
|
|
@@ -24747,10 +24778,10 @@ var MapGridView = React23__namespace.default.memo(({
|
|
|
24747
24778
|
efficiency: workspace.efficiency,
|
|
24748
24779
|
action_count: workspace.action_count
|
|
24749
24780
|
});
|
|
24750
|
-
const displayName = getWorkspaceDisplayName(workspace.workspace_name, workspace.line_id);
|
|
24781
|
+
const displayName = displayNames[workspace.workspace_name] || getWorkspaceDisplayName(workspace.workspace_name, workspace.line_id);
|
|
24751
24782
|
const navParams = getWorkspaceNavigationParams(workspaceId, displayName, workspace.line_id);
|
|
24752
24783
|
router$1.push(`/workspace/${workspaceId}${navParams}`);
|
|
24753
|
-
}, [router$1]);
|
|
24784
|
+
}, [router$1, displayNames]);
|
|
24754
24785
|
const activePositions = React23.useMemo(() => {
|
|
24755
24786
|
return workspacePositions.filter((pos) => {
|
|
24756
24787
|
const wsKey = pos.id.toUpperCase();
|
|
@@ -24776,7 +24807,7 @@ var MapGridView = React23__namespace.default.memo(({
|
|
|
24776
24807
|
if (!workspace) return null;
|
|
24777
24808
|
const workspaceId = workspace.workspace_uuid || workspace.workspace_name;
|
|
24778
24809
|
getPerformanceColor(workspace.efficiency);
|
|
24779
|
-
const
|
|
24810
|
+
const workspaceDisplayName = displayNames[workspace.workspace_name] || getWorkspaceDisplayName(workspace.workspace_name, workspace.line_id);
|
|
24780
24811
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
24781
24812
|
motion.div,
|
|
24782
24813
|
{
|
|
@@ -24802,7 +24833,7 @@ var MapGridView = React23__namespace.default.memo(({
|
|
|
24802
24833
|
${position.size === "conveyor" ? "w-32 h-24" : position.size === "large" ? "w-40 h-32" : "w-36 h-28"}
|
|
24803
24834
|
`,
|
|
24804
24835
|
children: [
|
|
24805
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute top-0 left-0 right-0 px-2 py-1.5 border-b border-gray-200", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs font-bold text-gray-800 truncate text-center leading-tight", children:
|
|
24836
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute top-0 left-0 right-0 px-2 py-1.5 border-b border-gray-200", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs font-bold text-gray-800 truncate text-center leading-tight", children: workspaceDisplayName }) }),
|
|
24806
24837
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute bottom-0 left-0 right-0 px-2 py-2", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col items-center", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-2xl font-bold text-gray-900", children: [
|
|
24807
24838
|
Math.round(workspace.efficiency),
|
|
24808
24839
|
"%"
|
|
@@ -34830,6 +34861,7 @@ var WorkspaceGrid = React23__namespace.default.memo(({
|
|
|
34830
34861
|
line2Uuid = "line-2",
|
|
34831
34862
|
className = "",
|
|
34832
34863
|
videoSources = {},
|
|
34864
|
+
displayNames = {},
|
|
34833
34865
|
onWorkspaceHover,
|
|
34834
34866
|
onWorkspaceHoverEnd
|
|
34835
34867
|
}) => {
|
|
@@ -34895,6 +34927,7 @@ var WorkspaceGrid = React23__namespace.default.memo(({
|
|
|
34895
34927
|
{
|
|
34896
34928
|
workspaces,
|
|
34897
34929
|
videoSources,
|
|
34930
|
+
displayNames,
|
|
34898
34931
|
onWorkspaceHover,
|
|
34899
34932
|
onWorkspaceHoverEnd
|
|
34900
34933
|
}
|
|
@@ -34913,6 +34946,7 @@ var WorkspaceGrid = React23__namespace.default.memo(({
|
|
|
34913
34946
|
MapGridViewComponent,
|
|
34914
34947
|
{
|
|
34915
34948
|
workspaces,
|
|
34949
|
+
displayNames,
|
|
34916
34950
|
onWorkspaceHover,
|
|
34917
34951
|
onWorkspaceHoverEnd
|
|
34918
34952
|
}
|
|
@@ -41449,7 +41483,6 @@ function HomeView({
|
|
|
41449
41483
|
factoryName = "Simba Beer - Line 1"
|
|
41450
41484
|
}) {
|
|
41451
41485
|
const [isHydrated, setIsHydrated] = React23.useState(false);
|
|
41452
|
-
const availableLineIds = React23.useMemo(() => [factoryViewId, ...allLineIds], [factoryViewId, allLineIds]);
|
|
41453
41486
|
const [selectedLineId, setSelectedLineId] = React23.useState(factoryViewId);
|
|
41454
41487
|
const [isChangingFilter, setIsChangingFilter] = React23.useState(false);
|
|
41455
41488
|
const [errorMessage, setErrorMessage] = React23.useState(null);
|
|
@@ -41459,6 +41492,21 @@ function HomeView({
|
|
|
41459
41492
|
const entityConfig = useEntityConfig();
|
|
41460
41493
|
const supabaseClient = useSupabaseClient();
|
|
41461
41494
|
const { user } = useAuth();
|
|
41495
|
+
const isSupervisor = user?.role_level === "supervisor";
|
|
41496
|
+
const hasMultipleLines = allLineIds.length > 1;
|
|
41497
|
+
const availableLineIds = React23.useMemo(() => {
|
|
41498
|
+
if (isSupervisor && !hasMultipleLines) {
|
|
41499
|
+
return allLineIds;
|
|
41500
|
+
}
|
|
41501
|
+
return [factoryViewId, ...allLineIds];
|
|
41502
|
+
}, [factoryViewId, allLineIds, isSupervisor, hasMultipleLines]);
|
|
41503
|
+
React23.useEffect(() => {
|
|
41504
|
+
if (user) {
|
|
41505
|
+
if (isSupervisor && allLineIds.length > 0) {
|
|
41506
|
+
setSelectedLineId(allLineIds[0]);
|
|
41507
|
+
}
|
|
41508
|
+
}
|
|
41509
|
+
}, [user, isSupervisor, allLineIds]);
|
|
41462
41510
|
const userCompanyId = React23.useMemo(() => {
|
|
41463
41511
|
return user?.properties?.company_id || user?.company_id || entityConfig.companyId;
|
|
41464
41512
|
}, [user, entityConfig.companyId]);
|
|
@@ -41493,7 +41541,7 @@ function HomeView({
|
|
|
41493
41541
|
displayNames: workspaceDisplayNames,
|
|
41494
41542
|
loading: displayNamesLoading,
|
|
41495
41543
|
error: displayNamesError
|
|
41496
|
-
} = useWorkspaceDisplayNames(void 0
|
|
41544
|
+
} = useWorkspaceDisplayNames(selectedLineId, void 0);
|
|
41497
41545
|
React23.useCallback(() => {
|
|
41498
41546
|
console.log("Refetching KPIs after line metrics update");
|
|
41499
41547
|
}, []);
|
|
@@ -41519,7 +41567,9 @@ function HomeView({
|
|
|
41519
41567
|
refetch: refetchMetrics
|
|
41520
41568
|
} = useDashboardMetrics({
|
|
41521
41569
|
lineId: selectedLineId,
|
|
41522
|
-
onLineMetricsUpdate
|
|
41570
|
+
onLineMetricsUpdate,
|
|
41571
|
+
userAccessibleLineIds: allLineIds
|
|
41572
|
+
// Pass user's accessible lines for supervisor filtering
|
|
41523
41573
|
});
|
|
41524
41574
|
const {
|
|
41525
41575
|
activeBreaks: allActiveBreaks,
|
|
@@ -41855,7 +41905,7 @@ function HomeView({
|
|
|
41855
41905
|
/* @__PURE__ */ jsxRuntime.jsx(SelectContent, { className: "z-50 bg-white shadow-lg border border-gray-200 rounded-md text-xs sm:text-sm", children: availableLineIds.map((id3) => /* @__PURE__ */ jsxRuntime.jsx(SelectItem, { value: id3, children: lineNames[id3] || (id3 === factoryViewId ? "All Lines" : `Line ${id3.substring(0, 4)}`) }, id3)) })
|
|
41856
41906
|
] });
|
|
41857
41907
|
}, [availableLineIds, handleLineChange, selectedLineId, lineNames, factoryViewId, allLineIds.length]);
|
|
41858
|
-
const isInitialLoading = !isHydrated || !displayNamesInitialized && displayNamesLoading;
|
|
41908
|
+
const isInitialLoading = !isHydrated || displayNamesLoading || !displayNamesInitialized && displayNamesLoading;
|
|
41859
41909
|
const isDataLoading = metricsLoading || kpisLoading;
|
|
41860
41910
|
if (isInitialLoading) {
|
|
41861
41911
|
return /* @__PURE__ */ jsxRuntime.jsx(LoadingPageCmp, { message: "Loading Dashboard..." });
|
|
@@ -41900,6 +41950,7 @@ function HomeView({
|
|
|
41900
41950
|
lineNames,
|
|
41901
41951
|
factoryView: factoryViewId,
|
|
41902
41952
|
videoSources,
|
|
41953
|
+
displayNames: workspaceDisplayNames,
|
|
41903
41954
|
className: "h-full",
|
|
41904
41955
|
onWorkspaceHover: handleWorkspaceHover,
|
|
41905
41956
|
onWorkspaceHoverEnd: handleWorkspaceHoverEnd
|
|
@@ -41927,6 +41978,7 @@ function HomeView({
|
|
|
41927
41978
|
lineNames,
|
|
41928
41979
|
factoryView: factoryViewId,
|
|
41929
41980
|
videoSources,
|
|
41981
|
+
displayNames: workspaceDisplayNames,
|
|
41930
41982
|
className: "h-full",
|
|
41931
41983
|
onWorkspaceHover: handleWorkspaceHover,
|
|
41932
41984
|
onWorkspaceHoverEnd: handleWorkspaceHoverEnd
|
|
@@ -43578,7 +43630,8 @@ var LeaderboardDetailView = React23.memo(({
|
|
|
43578
43630
|
line1Id = "",
|
|
43579
43631
|
line2Id = "",
|
|
43580
43632
|
lineNames = {},
|
|
43581
|
-
className = ""
|
|
43633
|
+
className = "",
|
|
43634
|
+
userAccessibleLineIds
|
|
43582
43635
|
}) => {
|
|
43583
43636
|
const navigation = useNavigation();
|
|
43584
43637
|
const entityConfig = useEntityConfig();
|
|
@@ -43618,7 +43671,9 @@ var LeaderboardDetailView = React23.memo(({
|
|
|
43618
43671
|
refreshWorkspaces
|
|
43619
43672
|
} = useAllWorkspaceMetrics({
|
|
43620
43673
|
initialDate: date,
|
|
43621
|
-
initialShiftId: typeof shift === "number" ? shift : typeof shift === "string" ? parseInt(shift) : void 0
|
|
43674
|
+
initialShiftId: typeof shift === "number" ? shift : typeof shift === "string" ? parseInt(shift) : void 0,
|
|
43675
|
+
allowedLineIds: userAccessibleLineIds
|
|
43676
|
+
// Filter to user's accessible lines only
|
|
43622
43677
|
});
|
|
43623
43678
|
const getShiftName = React23.useCallback((shiftId2) => {
|
|
43624
43679
|
if (shiftId2 === void 0) return "Day";
|
|
@@ -44974,12 +45029,17 @@ var ACTION_NAMES = {
|
|
|
44974
45029
|
var calculatePPH = (cycleTime, breaks = [], shiftHours = 0) => {
|
|
44975
45030
|
if (cycleTime === "" || cycleTime === 0) return "";
|
|
44976
45031
|
const pph = 3600 / cycleTime;
|
|
44977
|
-
return
|
|
45032
|
+
return Math.round(pph);
|
|
44978
45033
|
};
|
|
44979
45034
|
var calculateDayOutput = (pph, shiftHours, breaks = []) => {
|
|
44980
45035
|
if (pph === "") return "";
|
|
44981
45036
|
return Math.round(pph * shiftHours);
|
|
44982
45037
|
};
|
|
45038
|
+
var calculateDayOutputFromCycleTime = (cycleTime, shiftHours) => {
|
|
45039
|
+
if (cycleTime === "" || cycleTime === 0 || shiftHours === 0) return "";
|
|
45040
|
+
const dayOutput = 3600 / cycleTime * shiftHours;
|
|
45041
|
+
return Math.round(dayOutput);
|
|
45042
|
+
};
|
|
44983
45043
|
var formatWorkspaceName = (name, lineId) => {
|
|
44984
45044
|
return getWorkspaceDisplayName(name, lineId);
|
|
44985
45045
|
};
|
|
@@ -44991,20 +45051,6 @@ var getStoredLineState2 = (lineId) => {
|
|
|
44991
45051
|
return false;
|
|
44992
45052
|
}
|
|
44993
45053
|
};
|
|
44994
|
-
var calculateShiftHours2 = (startTime, endTime, breaks = []) => {
|
|
44995
|
-
if (!startTime || !endTime) return 8;
|
|
44996
|
-
const [startHour, startMinute] = startTime.split(":").map(Number);
|
|
44997
|
-
const [endHour, endMinute] = endTime.split(":").map(Number);
|
|
44998
|
-
let startMinutes = startHour * 60 + startMinute;
|
|
44999
|
-
let endMinutes = endHour * 60 + endMinute;
|
|
45000
|
-
if (endMinutes < startMinutes) {
|
|
45001
|
-
endMinutes += 24 * 60;
|
|
45002
|
-
}
|
|
45003
|
-
const safeBreaks = Array.isArray(breaks) ? breaks : [];
|
|
45004
|
-
const totalBreakMinutes = safeBreaks.reduce((total, breakItem) => total + breakItem.duration, 0);
|
|
45005
|
-
const hoursDiff = (endMinutes - startMinutes - totalBreakMinutes) / 60;
|
|
45006
|
-
return Number(hoursDiff.toFixed(1));
|
|
45007
|
-
};
|
|
45008
45054
|
var BulkConfigureModal = ({
|
|
45009
45055
|
isOpen,
|
|
45010
45056
|
onClose,
|
|
@@ -46212,121 +46258,6 @@ var TargetsView = ({
|
|
|
46212
46258
|
const dashboardConfig = useDashboardConfig();
|
|
46213
46259
|
const { skus, isLoading: skusLoading } = useSKUs(companyId);
|
|
46214
46260
|
const skuEnabled = dashboardConfig?.skuConfig?.enabled || false;
|
|
46215
|
-
const loadOperatingHours = React23.useCallback(async (lineId, shiftId) => {
|
|
46216
|
-
try {
|
|
46217
|
-
const { data: { session } } = await supabase.auth.getSession();
|
|
46218
|
-
if (!session?.access_token) {
|
|
46219
|
-
console.error("No authentication token available");
|
|
46220
|
-
return {
|
|
46221
|
-
startTime: "08:00",
|
|
46222
|
-
// Default values
|
|
46223
|
-
endTime: "19:00",
|
|
46224
|
-
breaks: []
|
|
46225
|
-
};
|
|
46226
|
-
}
|
|
46227
|
-
const backendUrl = process.env.NEXT_PUBLIC_BACKEND_URL;
|
|
46228
|
-
if (!backendUrl) {
|
|
46229
|
-
console.error("Backend URL is not configured");
|
|
46230
|
-
return {
|
|
46231
|
-
startTime: "08:00",
|
|
46232
|
-
// Default values
|
|
46233
|
-
endTime: "19:00",
|
|
46234
|
-
breaks: []
|
|
46235
|
-
};
|
|
46236
|
-
}
|
|
46237
|
-
const response = await fetch(`${backendUrl}/api/lines/${lineId}/operating-hours?shift_id=${shiftId}`, {
|
|
46238
|
-
headers: {
|
|
46239
|
-
"Authorization": `Bearer ${session.access_token}`,
|
|
46240
|
-
"Content-Type": "application/json"
|
|
46241
|
-
}
|
|
46242
|
-
});
|
|
46243
|
-
if (!response.ok) {
|
|
46244
|
-
console.log(`No operating hours found for line ${lineId}, shift ${shiftId} - using defaults`);
|
|
46245
|
-
return {
|
|
46246
|
-
startTime: "08:00",
|
|
46247
|
-
// Default values
|
|
46248
|
-
endTime: "19:00",
|
|
46249
|
-
breaks: []
|
|
46250
|
-
};
|
|
46251
|
-
}
|
|
46252
|
-
const data = await response.json();
|
|
46253
|
-
let breaks = [];
|
|
46254
|
-
if (data?.breaks) {
|
|
46255
|
-
if (Array.isArray(data.breaks)) {
|
|
46256
|
-
breaks = data.breaks.map((breakItem) => {
|
|
46257
|
-
const startTime = breakItem.start || breakItem.startTime || "00:00";
|
|
46258
|
-
const endTime = breakItem.end || breakItem.endTime || "00:00";
|
|
46259
|
-
const calculateDuration = (start, end) => {
|
|
46260
|
-
const [startHour, startMinute] = start.split(":").map(Number);
|
|
46261
|
-
const [endHour, endMinute] = end.split(":").map(Number);
|
|
46262
|
-
let startMinutes = startHour * 60 + startMinute;
|
|
46263
|
-
let endMinutes = endHour * 60 + endMinute;
|
|
46264
|
-
if (endMinutes < startMinutes) {
|
|
46265
|
-
endMinutes += 24 * 60;
|
|
46266
|
-
}
|
|
46267
|
-
return endMinutes - startMinutes;
|
|
46268
|
-
};
|
|
46269
|
-
return {
|
|
46270
|
-
startTime,
|
|
46271
|
-
endTime,
|
|
46272
|
-
duration: breakItem.duration || calculateDuration(startTime, endTime)
|
|
46273
|
-
};
|
|
46274
|
-
});
|
|
46275
|
-
} else if (typeof data.breaks === "object" && data.breaks.breaks) {
|
|
46276
|
-
breaks = data.breaks.breaks.map((breakItem) => {
|
|
46277
|
-
const startTime = breakItem.start || breakItem.startTime || "00:00";
|
|
46278
|
-
const endTime = breakItem.end || breakItem.endTime || "00:00";
|
|
46279
|
-
const calculateDuration = (start, end) => {
|
|
46280
|
-
const [startHour, startMinute] = start.split(":").map(Number);
|
|
46281
|
-
const [endHour, endMinute] = end.split(":").map(Number);
|
|
46282
|
-
let startMinutes = startHour * 60 + startMinute;
|
|
46283
|
-
let endMinutes = endHour * 60 + endMinute;
|
|
46284
|
-
if (endMinutes < startMinutes) {
|
|
46285
|
-
endMinutes += 24 * 60;
|
|
46286
|
-
}
|
|
46287
|
-
return endMinutes - startMinutes;
|
|
46288
|
-
};
|
|
46289
|
-
return {
|
|
46290
|
-
startTime,
|
|
46291
|
-
endTime,
|
|
46292
|
-
duration: breakItem.duration || calculateDuration(startTime, endTime)
|
|
46293
|
-
};
|
|
46294
|
-
});
|
|
46295
|
-
} else if (typeof data.breaks === "string") {
|
|
46296
|
-
try {
|
|
46297
|
-
const parsedBreaks = JSON.parse(data.breaks);
|
|
46298
|
-
if (Array.isArray(parsedBreaks)) {
|
|
46299
|
-
breaks = parsedBreaks.map((breakItem) => ({
|
|
46300
|
-
startTime: breakItem.start || breakItem.startTime || "00:00",
|
|
46301
|
-
endTime: breakItem.end || breakItem.endTime || "00:00",
|
|
46302
|
-
duration: breakItem.duration || 0
|
|
46303
|
-
}));
|
|
46304
|
-
} else if (parsedBreaks.breaks && Array.isArray(parsedBreaks.breaks)) {
|
|
46305
|
-
breaks = parsedBreaks.breaks.map((breakItem) => ({
|
|
46306
|
-
startTime: breakItem.start || breakItem.startTime || "00:00",
|
|
46307
|
-
endTime: breakItem.end || breakItem.endTime || "00:00",
|
|
46308
|
-
duration: breakItem.duration || 0
|
|
46309
|
-
}));
|
|
46310
|
-
}
|
|
46311
|
-
} catch (e) {
|
|
46312
|
-
console.error("Error parsing breaks data:", e);
|
|
46313
|
-
}
|
|
46314
|
-
}
|
|
46315
|
-
}
|
|
46316
|
-
return {
|
|
46317
|
-
startTime: data?.start_time || "08:00",
|
|
46318
|
-
endTime: data?.end_time || "19:00",
|
|
46319
|
-
breaks
|
|
46320
|
-
};
|
|
46321
|
-
} catch (e) {
|
|
46322
|
-
console.error("Exception when loading operating hours:", e);
|
|
46323
|
-
return {
|
|
46324
|
-
startTime: "08:00",
|
|
46325
|
-
endTime: "19:00",
|
|
46326
|
-
breaks: []
|
|
46327
|
-
};
|
|
46328
|
-
}
|
|
46329
|
-
}, [supabase]);
|
|
46330
46261
|
React23.useEffect(() => {
|
|
46331
46262
|
console.log("[TargetsView] Component mounted/re-rendered", {
|
|
46332
46263
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -46338,221 +46269,108 @@ var TargetsView = ({
|
|
|
46338
46269
|
};
|
|
46339
46270
|
}, []);
|
|
46340
46271
|
React23.useEffect(() => {
|
|
46341
|
-
let timeoutId;
|
|
46342
|
-
let retryCount = 0;
|
|
46343
|
-
const MAX_RETRIES2 = 2;
|
|
46344
|
-
const LOADING_TIMEOUT = 15e3;
|
|
46345
46272
|
const fetchInitialData = async () => {
|
|
46346
|
-
if (lineIds.length === 0) return;
|
|
46347
|
-
console.log("[TargetsView] Starting fetchInitialData");
|
|
46273
|
+
if (lineIds.length === 0 || !companyId) return;
|
|
46274
|
+
console.log("[TargetsView] Starting optimized fetchInitialData with bulk endpoint");
|
|
46348
46275
|
setIsLoading(true);
|
|
46349
|
-
timeoutId = setTimeout(() => {
|
|
46350
|
-
console.error("Loading timeout reached");
|
|
46351
|
-
if (retryCount < MAX_RETRIES2) {
|
|
46352
|
-
retryCount++;
|
|
46353
|
-
console.log(`Retrying... (attempt ${retryCount + 1}/${MAX_RETRIES2 + 1})`);
|
|
46354
|
-
sonner.toast.warning("Loading is taking longer than expected. Retrying...");
|
|
46355
|
-
fetchInitialData();
|
|
46356
|
-
} else {
|
|
46357
|
-
setIsLoading(false);
|
|
46358
|
-
sonner.toast.error("Failed to load data. Please refresh the page.");
|
|
46359
|
-
}
|
|
46360
|
-
}, LOADING_TIMEOUT);
|
|
46361
46276
|
try {
|
|
46362
|
-
const
|
|
46363
|
-
|
|
46364
|
-
|
|
46365
|
-
|
|
46366
|
-
|
|
46367
|
-
|
|
46368
|
-
|
|
46277
|
+
const currentDate = getOperationalDate(timezone);
|
|
46278
|
+
const bulkResponse = await workspaceService.fetchBulkTargets({
|
|
46279
|
+
companyId,
|
|
46280
|
+
lineIds,
|
|
46281
|
+
date: currentDate,
|
|
46282
|
+
shifts: [0, 1],
|
|
46283
|
+
// Fetch both shifts at once
|
|
46284
|
+
includeSkus: skuEnabled,
|
|
46285
|
+
includeActions: true
|
|
46286
|
+
});
|
|
46287
|
+
if (!bulkResponse.success) {
|
|
46288
|
+
throw new Error("Failed to fetch bulk targets data");
|
|
46369
46289
|
}
|
|
46370
|
-
const
|
|
46371
|
-
|
|
46372
|
-
|
|
46373
|
-
try {
|
|
46374
|
-
const response = await fetch(`${backendUrl}/api/lines/${lineId}`, {
|
|
46375
|
-
headers: {
|
|
46376
|
-
"Authorization": `Bearer ${session.access_token}`,
|
|
46377
|
-
"Content-Type": "application/json"
|
|
46378
|
-
}
|
|
46379
|
-
});
|
|
46380
|
-
if (!response.ok) {
|
|
46381
|
-
console.error(`Error fetching line data for ${lineId}:`, response.statusText);
|
|
46382
|
-
return { lineId, factoryId: void 0 };
|
|
46383
|
-
}
|
|
46384
|
-
const lineData = await response.json();
|
|
46385
|
-
return { lineId, factoryId: lineData.factory_id };
|
|
46386
|
-
} catch (err) {
|
|
46387
|
-
console.error(`Exception fetching line data for ${lineId}:`, err);
|
|
46388
|
-
return { lineId, factoryId: void 0 };
|
|
46389
|
-
}
|
|
46390
|
-
})),
|
|
46391
|
-
// Fetch action IDs
|
|
46392
|
-
actionService.getActionsByName(
|
|
46393
|
-
[ACTION_NAMES.ASSEMBLY, ACTION_NAMES.PACKAGING],
|
|
46394
|
-
companyId
|
|
46395
|
-
)
|
|
46396
|
-
]);
|
|
46397
|
-
const factoryResults = linesResponse;
|
|
46398
|
-
const assemblyAction = actions.find((a) => a.action_name === ACTION_NAMES.ASSEMBLY);
|
|
46399
|
-
const packagingAction = actions.find((a) => a.action_name === ACTION_NAMES.PACKAGING);
|
|
46290
|
+
const { data } = bulkResponse;
|
|
46291
|
+
const assemblyAction = Object.values(data.actions).find((a) => a.action_name === ACTION_NAMES.ASSEMBLY);
|
|
46292
|
+
const packagingAction = Object.values(data.actions).find((a) => a.action_name === ACTION_NAMES.PACKAGING);
|
|
46400
46293
|
if (!assemblyAction || !packagingAction) {
|
|
46401
|
-
throw new Error("Could not find required actions");
|
|
46294
|
+
throw new Error("Could not find required actions in bulk response");
|
|
46402
46295
|
}
|
|
46403
46296
|
const actionIdsData = {
|
|
46404
46297
|
assembly: assemblyAction.id,
|
|
46405
46298
|
packaging: packagingAction.id
|
|
46406
46299
|
};
|
|
46407
46300
|
setActionIds(actionIdsData);
|
|
46408
|
-
const
|
|
46409
|
-
|
|
46410
|
-
|
|
46411
|
-
|
|
46412
|
-
|
|
46413
|
-
|
|
46414
|
-
|
|
46415
|
-
|
|
46416
|
-
if (!updatedLineWorkspaces[lineId]?.factoryId) {
|
|
46417
|
-
console.warn(`Skipping workspace fetch for line ${lineId} - no factory ID`);
|
|
46418
|
-
continue;
|
|
46419
|
-
}
|
|
46420
|
-
try {
|
|
46421
|
-
const workspacesData = await workspaceService.getWorkspaces(lineId);
|
|
46422
|
-
const enabledWorkspaces = workspacesData.filter((ws) => ws.enable === true);
|
|
46423
|
-
const actionThresholds = await workspaceService.getActionThresholds(
|
|
46424
|
-
lineId,
|
|
46425
|
-
currentDate,
|
|
46426
|
-
0
|
|
46427
|
-
// Always use day shift for initial load
|
|
46428
|
-
);
|
|
46429
|
-
const operatingHoursData = await loadOperatingHours(lineId, 0);
|
|
46430
|
-
if (operatingHoursData) {
|
|
46431
|
-
updatedLineWorkspaces[lineId].shiftStartTime = operatingHoursData.startTime;
|
|
46432
|
-
updatedLineWorkspaces[lineId].shiftEndTime = operatingHoursData.endTime;
|
|
46433
|
-
updatedLineWorkspaces[lineId].breaks = operatingHoursData.breaks;
|
|
46434
|
-
updatedLineWorkspaces[lineId].shiftHours = calculateShiftHours2(
|
|
46435
|
-
operatingHoursData.startTime,
|
|
46436
|
-
operatingHoursData.endTime,
|
|
46437
|
-
operatingHoursData.breaks
|
|
46438
|
-
);
|
|
46301
|
+
const newAllShiftsData = { 0: {}, 1: {} };
|
|
46302
|
+
const newDbValues = { 0: {}, 1: {} };
|
|
46303
|
+
Object.entries(data.lines).forEach(([lineId, lineData]) => {
|
|
46304
|
+
[0, 1].forEach((shiftId) => {
|
|
46305
|
+
const shiftData = lineData.shifts[shiftId.toString()];
|
|
46306
|
+
if (!shiftData) {
|
|
46307
|
+
console.warn(`No shift ${shiftId} data for line ${lineId}`);
|
|
46308
|
+
return;
|
|
46439
46309
|
}
|
|
46310
|
+
const operatingHours = shiftData.operating_hours || {
|
|
46311
|
+
start_time: "08:00",
|
|
46312
|
+
end_time: "19:00",
|
|
46313
|
+
breaks: [],
|
|
46314
|
+
total_hours: 11
|
|
46315
|
+
};
|
|
46316
|
+
newAllShiftsData[shiftId][lineId] = {
|
|
46317
|
+
productId: "",
|
|
46318
|
+
shiftStartTime: operatingHours.start_time,
|
|
46319
|
+
shiftEndTime: operatingHours.end_time,
|
|
46320
|
+
breaks: operatingHours.breaks,
|
|
46321
|
+
shiftHours: operatingHours.total_hours,
|
|
46322
|
+
workspaces: [],
|
|
46323
|
+
factoryId: lineData.line_info.factory_id
|
|
46324
|
+
};
|
|
46325
|
+
newDbValues[shiftId][lineId] = {};
|
|
46326
|
+
const enabledWorkspaces = lineData.workspaces.filter((ws) => ws.enable === true);
|
|
46440
46327
|
const mappedWorkspaces = enabledWorkspaces.map((ws) => {
|
|
46441
|
-
const threshold =
|
|
46442
|
-
if (!dbValues[0][lineId]) {
|
|
46443
|
-
dbValues[0][lineId] = {};
|
|
46444
|
-
}
|
|
46328
|
+
const threshold = shiftData.thresholds.find((t) => t.workspace_id === ws.id);
|
|
46445
46329
|
if (threshold) {
|
|
46446
|
-
|
|
46447
|
-
targetPPH: threshold.pph_threshold,
|
|
46448
|
-
targetCycleTime: threshold.ideal_cycle_time,
|
|
46449
|
-
targetDayOutput: threshold.total_day_output
|
|
46330
|
+
newDbValues[shiftId][lineId][ws.id] = {
|
|
46331
|
+
targetPPH: threshold.pph_threshold ? Math.round(threshold.pph_threshold) : "",
|
|
46332
|
+
targetCycleTime: threshold.ideal_cycle_time ?? "",
|
|
46333
|
+
targetDayOutput: threshold.total_day_output ?? ""
|
|
46450
46334
|
};
|
|
46451
46335
|
}
|
|
46336
|
+
let actionType = "assembly";
|
|
46337
|
+
let actionId = actionIdsData.assembly;
|
|
46338
|
+
if (ws.action_id === packagingAction.id || ws.action_type === "packaging") {
|
|
46339
|
+
actionType = "packaging";
|
|
46340
|
+
actionId = packagingAction.id;
|
|
46341
|
+
} else if (ws.action_id === assemblyAction.id || ws.action_type === "assembly") {
|
|
46342
|
+
actionType = "assembly";
|
|
46343
|
+
actionId = assemblyAction.id;
|
|
46344
|
+
}
|
|
46452
46345
|
return {
|
|
46453
46346
|
id: ws.id,
|
|
46454
46347
|
name: ws.workspace_id,
|
|
46455
|
-
targetPPH: threshold?.pph_threshold
|
|
46456
|
-
targetCycleTime: threshold?.ideal_cycle_time ??
|
|
46457
|
-
targetDayOutput: threshold?.total_day_output ??
|
|
46458
|
-
actionType
|
|
46459
|
-
actionId
|
|
46348
|
+
targetPPH: threshold?.pph_threshold ? Math.round(threshold.pph_threshold) : "",
|
|
46349
|
+
targetCycleTime: threshold?.ideal_cycle_time ?? "",
|
|
46350
|
+
targetDayOutput: threshold?.total_day_output ?? "",
|
|
46351
|
+
actionType,
|
|
46352
|
+
actionId
|
|
46460
46353
|
};
|
|
46461
46354
|
}).sort((a, b) => a.name.localeCompare(b.name, void 0, { numeric: true }));
|
|
46462
|
-
|
|
46463
|
-
}
|
|
46464
|
-
|
|
46465
|
-
|
|
46466
|
-
|
|
46467
|
-
|
|
46468
|
-
|
|
46355
|
+
newAllShiftsData[shiftId][lineId].workspaces = mappedWorkspaces;
|
|
46356
|
+
});
|
|
46357
|
+
});
|
|
46358
|
+
setAllShiftsData(newAllShiftsData);
|
|
46359
|
+
setDbValues(newDbValues);
|
|
46360
|
+
console.log("[TargetsView] Successfully loaded all data with bulk endpoint:", {
|
|
46361
|
+
lineCount: bulkResponse.metadata.line_count,
|
|
46362
|
+
totalWorkspaces: bulkResponse.metadata.total_workspaces,
|
|
46363
|
+
loadTime: "Fast!"
|
|
46364
|
+
});
|
|
46469
46365
|
} catch (error) {
|
|
46470
|
-
console.error("Error fetching
|
|
46471
|
-
|
|
46472
|
-
if (retryCount < MAX_RETRIES2) {
|
|
46473
|
-
retryCount++;
|
|
46474
|
-
console.log(`Error occurred, retrying... (attempt ${retryCount + 1}/${MAX_RETRIES2 + 1})`);
|
|
46475
|
-
sonner.toast.warning("Error loading data. Retrying...");
|
|
46476
|
-
setTimeout(() => fetchInitialData(), 1e3);
|
|
46477
|
-
} else {
|
|
46478
|
-
sonner.toast.error("Failed to load initial data");
|
|
46479
|
-
setIsLoading(false);
|
|
46480
|
-
}
|
|
46366
|
+
console.error("[TargetsView] Error fetching bulk data:", error);
|
|
46367
|
+
sonner.toast.error("Failed to load targets data. Please refresh the page.");
|
|
46481
46368
|
} finally {
|
|
46482
|
-
|
|
46483
|
-
if (retryCount === 0 || retryCount >= MAX_RETRIES2) {
|
|
46484
|
-
setIsLoading(false);
|
|
46485
|
-
}
|
|
46369
|
+
setIsLoading(false);
|
|
46486
46370
|
}
|
|
46487
46371
|
};
|
|
46488
46372
|
fetchInitialData();
|
|
46489
|
-
|
|
46490
|
-
clearTimeout(timeoutId);
|
|
46491
|
-
};
|
|
46492
|
-
}, [lineIds, companyId, loadOperatingHours]);
|
|
46493
|
-
const fetchAllShiftsData = React23.useCallback(async (currentWorkspaces) => {
|
|
46494
|
-
if (!supabase) return;
|
|
46495
|
-
const currentDate = getOperationalDate(timezone);
|
|
46496
|
-
const newAllShiftsData = {
|
|
46497
|
-
0: JSON.parse(JSON.stringify(currentWorkspaces)),
|
|
46498
|
-
// Deep clone for day shift
|
|
46499
|
-
1: JSON.parse(JSON.stringify(currentWorkspaces))
|
|
46500
|
-
// Deep clone for night shift
|
|
46501
|
-
};
|
|
46502
|
-
const newDbValues = { 0: {}, 1: {} };
|
|
46503
|
-
for (const shiftId of [0, 1]) {
|
|
46504
|
-
for (const lineId of lineIds) {
|
|
46505
|
-
try {
|
|
46506
|
-
const operatingHoursData = await loadOperatingHours(lineId, shiftId);
|
|
46507
|
-
if (!operatingHoursData) {
|
|
46508
|
-
console.warn(`No operating hours for line ${lineId}, shift ${shiftId} - using defaults`);
|
|
46509
|
-
continue;
|
|
46510
|
-
}
|
|
46511
|
-
const { startTime, endTime, breaks } = operatingHoursData;
|
|
46512
|
-
const shiftHours = calculateShiftHours2(startTime, endTime, breaks);
|
|
46513
|
-
const actionThresholds = await workspaceService.getActionThresholds(
|
|
46514
|
-
lineId,
|
|
46515
|
-
currentDate,
|
|
46516
|
-
shiftId
|
|
46517
|
-
);
|
|
46518
|
-
if (!newDbValues[shiftId][lineId]) {
|
|
46519
|
-
newDbValues[shiftId][lineId] = {};
|
|
46520
|
-
}
|
|
46521
|
-
const existingLine = newAllShiftsData[shiftId][lineId];
|
|
46522
|
-
if (existingLine) {
|
|
46523
|
-
newAllShiftsData[shiftId][lineId] = {
|
|
46524
|
-
...existingLine,
|
|
46525
|
-
shiftStartTime: startTime,
|
|
46526
|
-
shiftEndTime: endTime,
|
|
46527
|
-
breaks,
|
|
46528
|
-
shiftHours: Number(shiftHours),
|
|
46529
|
-
workspaces: existingLine.workspaces.map((ws) => {
|
|
46530
|
-
const threshold = actionThresholds.find((t) => t.workspace_id === ws.id);
|
|
46531
|
-
if (threshold) {
|
|
46532
|
-
newDbValues[shiftId][lineId][ws.id] = {
|
|
46533
|
-
targetPPH: threshold.pph_threshold,
|
|
46534
|
-
targetCycleTime: threshold.ideal_cycle_time,
|
|
46535
|
-
targetDayOutput: threshold.total_day_output
|
|
46536
|
-
};
|
|
46537
|
-
return {
|
|
46538
|
-
...ws,
|
|
46539
|
-
targetPPH: threshold.pph_threshold,
|
|
46540
|
-
targetCycleTime: threshold.ideal_cycle_time,
|
|
46541
|
-
targetDayOutput: threshold.total_day_output
|
|
46542
|
-
};
|
|
46543
|
-
}
|
|
46544
|
-
return ws;
|
|
46545
|
-
})
|
|
46546
|
-
};
|
|
46547
|
-
}
|
|
46548
|
-
} catch (error) {
|
|
46549
|
-
console.error(`Error fetching data for line ${lineId}, shift ${shiftId}:`, error);
|
|
46550
|
-
}
|
|
46551
|
-
}
|
|
46552
|
-
}
|
|
46553
|
-
setAllShiftsData(newAllShiftsData);
|
|
46554
|
-
setDbValues(newDbValues);
|
|
46555
|
-
}, [supabase, lineIds, loadOperatingHours]);
|
|
46373
|
+
}, [lineIds, companyId, timezone, skuEnabled]);
|
|
46556
46374
|
const toggleLineDropdown = React23.useCallback((lineId) => {
|
|
46557
46375
|
setDropdownStates((prev) => {
|
|
46558
46376
|
const newIsOpen = !prev[lineId];
|
|
@@ -46625,7 +46443,7 @@ var TargetsView = ({
|
|
|
46625
46443
|
if (value !== "") {
|
|
46626
46444
|
const pph = calculatePPH(value, prev[lineId].breaks, shiftHours);
|
|
46627
46445
|
updates.targetPPH = pph;
|
|
46628
|
-
updates.targetDayOutput =
|
|
46446
|
+
updates.targetDayOutput = calculateDayOutputFromCycleTime(value, shiftHours);
|
|
46629
46447
|
} else {
|
|
46630
46448
|
updates.targetPPH = "";
|
|
46631
46449
|
updates.targetDayOutput = "";
|
|
@@ -46743,7 +46561,8 @@ var TargetsView = ({
|
|
|
46743
46561
|
action_id: ws.actionId,
|
|
46744
46562
|
workspace_id: ws.id,
|
|
46745
46563
|
date: currentDate,
|
|
46746
|
-
pph_threshold: Number(ws.targetPPH)
|
|
46564
|
+
pph_threshold: ws.targetPPH ? Math.round(Number(ws.targetPPH)) : 0,
|
|
46565
|
+
// Round to whole number
|
|
46747
46566
|
ideal_cycle_time: Number(ws.targetCycleTime) || 0,
|
|
46748
46567
|
total_day_output: Number(ws.targetDayOutput) || 0,
|
|
46749
46568
|
action_name: ws.actionType === "assembly" ? ACTION_NAMES.ASSEMBLY : ACTION_NAMES.PACKAGING,
|
|
@@ -46762,7 +46581,8 @@ var TargetsView = ({
|
|
|
46762
46581
|
shift_id: selectedShift,
|
|
46763
46582
|
product_code: lineDataToSave.productId,
|
|
46764
46583
|
threshold_day_output: packagingWorkspaces.reduce((acc, ws) => acc + (Number(ws.targetDayOutput) || 0), 0),
|
|
46765
|
-
threshold_pph: packagingWorkspaces.reduce((acc, ws) => acc + (Number(ws.targetPPH)
|
|
46584
|
+
threshold_pph: packagingWorkspaces.reduce((acc, ws) => acc + (ws.targetPPH ? Math.round(Number(ws.targetPPH)) : 0), 0),
|
|
46585
|
+
// Round each PPH value
|
|
46766
46586
|
...skuEnabled && lineDataToSave.selectedSKU ? { sku_id: lineDataToSave.selectedSKU.id } : {}
|
|
46767
46587
|
};
|
|
46768
46588
|
console.log(`[handleSaveLine] lineThresholdData for upsert on ${lineId}:`, lineThresholdData);
|
|
@@ -48514,94 +48334,14 @@ var SupervisorManagementView = ({
|
|
|
48514
48334
|
] });
|
|
48515
48335
|
};
|
|
48516
48336
|
var SupervisorManagementView_default = SupervisorManagementView;
|
|
48517
|
-
var
|
|
48518
|
-
|
|
48519
|
-
|
|
48520
|
-
|
|
48521
|
-
|
|
48522
|
-
|
|
48523
|
-
|
|
48524
|
-
|
|
48525
|
-
],
|
|
48526
|
-
colorClass: "text-blue-700 bg-blue-50 border-blue-200"
|
|
48527
|
-
},
|
|
48528
|
-
supervisor_to_owner: {
|
|
48529
|
-
title: "Supervisor \u2192 Owner",
|
|
48530
|
-
warnings: [
|
|
48531
|
-
"Will gain full company access",
|
|
48532
|
-
"Will lose line-specific restrictions",
|
|
48533
|
-
"Will be able to manage all users",
|
|
48534
|
-
"Will see all company data"
|
|
48535
|
-
],
|
|
48536
|
-
colorClass: "text-red-700 bg-red-50 border-red-200"
|
|
48537
|
-
},
|
|
48538
|
-
plant_head_to_supervisor: {
|
|
48539
|
-
title: "Plant Head \u2192 Supervisor",
|
|
48540
|
-
warnings: [
|
|
48541
|
-
"Will lose factory access",
|
|
48542
|
-
"Will lose ability to manage others",
|
|
48543
|
-
"Will need line assignment",
|
|
48544
|
-
"Will only see assigned line data"
|
|
48545
|
-
],
|
|
48546
|
-
colorClass: "text-orange-700 bg-orange-50 border-orange-200"
|
|
48547
|
-
},
|
|
48548
|
-
plant_head_to_owner: {
|
|
48549
|
-
title: "Plant Head \u2192 Owner",
|
|
48550
|
-
warnings: [
|
|
48551
|
-
"Will gain full company access",
|
|
48552
|
-
"Will lose factory-specific restrictions",
|
|
48553
|
-
"Will be able to manage all users",
|
|
48554
|
-
"Will see all company data"
|
|
48555
|
-
],
|
|
48556
|
-
colorClass: "text-blue-700 bg-blue-50 border-blue-200"
|
|
48557
|
-
},
|
|
48558
|
-
owner_to_plant_head: {
|
|
48559
|
-
title: "Owner \u2192 Plant Head",
|
|
48560
|
-
warnings: [
|
|
48561
|
-
"Will lose company-wide access",
|
|
48562
|
-
"Will need factory assignment",
|
|
48563
|
-
"Will only manage supervisors",
|
|
48564
|
-
"Will only see factory data"
|
|
48565
|
-
],
|
|
48566
|
-
colorClass: "text-orange-700 bg-orange-50 border-orange-200"
|
|
48567
|
-
},
|
|
48568
|
-
owner_to_supervisor: {
|
|
48569
|
-
title: "Owner \u2192 Supervisor",
|
|
48570
|
-
warnings: [
|
|
48571
|
-
"Will lose company-wide access",
|
|
48572
|
-
"Will lose ability to manage others",
|
|
48573
|
-
"Will need line assignment",
|
|
48574
|
-
"Will only see assigned line data"
|
|
48575
|
-
],
|
|
48576
|
-
colorClass: "text-red-700 bg-red-50 border-red-200"
|
|
48577
|
-
},
|
|
48578
|
-
to_optifye: {
|
|
48579
|
-
title: "Promoting to Optifye",
|
|
48580
|
-
warnings: [
|
|
48581
|
-
"Will gain access to ALL companies",
|
|
48582
|
-
"Will be able to manage all users globally",
|
|
48583
|
-
"Will see all data across the platform",
|
|
48584
|
-
"This is the highest privilege level"
|
|
48585
|
-
],
|
|
48586
|
-
colorClass: "text-purple-700 bg-purple-50 border-purple-200"
|
|
48587
|
-
},
|
|
48588
|
-
from_optifye: {
|
|
48589
|
-
title: "Demoting from Optifye",
|
|
48590
|
-
warnings: [
|
|
48591
|
-
"Will lose access to other companies",
|
|
48592
|
-
"Will only see assigned company data",
|
|
48593
|
-
"Will lose global management capabilities",
|
|
48594
|
-
"Will need appropriate assignments"
|
|
48595
|
-
],
|
|
48596
|
-
colorClass: "text-red-700 bg-red-50 border-red-200"
|
|
48597
|
-
}
|
|
48598
|
-
};
|
|
48599
|
-
var getRoleChangeKey = (currentRole, newRole) => {
|
|
48600
|
-
if (currentRole === newRole) return null;
|
|
48601
|
-
if (newRole === "optifye") return "to_optifye";
|
|
48602
|
-
if (currentRole === "optifye") return "from_optifye";
|
|
48603
|
-
const key = `${currentRole}_to_${newRole}`;
|
|
48604
|
-
return roleChangeImpacts[key] ? key : null;
|
|
48337
|
+
var getRoleLabel = (role) => {
|
|
48338
|
+
const labels = {
|
|
48339
|
+
"supervisor": "Supervisor",
|
|
48340
|
+
"plant_head": "Plant Head",
|
|
48341
|
+
"owner": "Owner",
|
|
48342
|
+
"optifye": "Optifye Admin"
|
|
48343
|
+
};
|
|
48344
|
+
return labels[role] || role;
|
|
48605
48345
|
};
|
|
48606
48346
|
var ChangeRoleDialog = ({
|
|
48607
48347
|
user,
|
|
@@ -48614,8 +48354,6 @@ var ChangeRoleDialog = ({
|
|
|
48614
48354
|
const [confirmed, setConfirmed] = React23.useState(false);
|
|
48615
48355
|
const [isChanging, setIsChanging] = React23.useState(false);
|
|
48616
48356
|
const roleChanged = selectedRole !== user.role_level;
|
|
48617
|
-
const changeKey = roleChanged ? getRoleChangeKey(user.role_level, selectedRole) : null;
|
|
48618
|
-
const impactInfo = changeKey ? roleChangeImpacts[changeKey] : null;
|
|
48619
48357
|
const handleNext = () => {
|
|
48620
48358
|
if (roleChanged) {
|
|
48621
48359
|
setStep("confirm");
|
|
@@ -48635,7 +48373,7 @@ var ChangeRoleDialog = ({
|
|
|
48635
48373
|
setStep("select");
|
|
48636
48374
|
setConfirmed(false);
|
|
48637
48375
|
};
|
|
48638
|
-
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "fixed inset-0 z-50 flex items-center justify-center bg-black/50", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-white rounded-
|
|
48376
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "fixed inset-0 z-50 flex items-center justify-center bg-black/50 backdrop-blur-sm", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-white rounded-xl shadow-2xl max-w-md w-full mx-4 transform transition-all", children: [
|
|
48639
48377
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between p-6 border-b border-gray-200", children: [
|
|
48640
48378
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
|
|
48641
48379
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-2 bg-blue-100 rounded-lg", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.UserCog, { className: "w-5 h-5 text-blue-600" }) }),
|
|
@@ -48645,20 +48383,14 @@ var ChangeRoleDialog = ({
|
|
|
48645
48383
|
"button",
|
|
48646
48384
|
{
|
|
48647
48385
|
onClick: onClose,
|
|
48648
|
-
className: "text-gray-400 hover:text-gray-600 transition-colors",
|
|
48386
|
+
className: "text-gray-400 hover:text-gray-600 transition-colors p-1 hover:bg-gray-100 rounded-lg",
|
|
48649
48387
|
disabled: isChanging,
|
|
48388
|
+
"aria-label": "Close dialog",
|
|
48650
48389
|
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "w-5 h-5" })
|
|
48651
48390
|
}
|
|
48652
48391
|
)
|
|
48653
48392
|
] }),
|
|
48654
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-6 space-y-
|
|
48655
|
-
roleChanged && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-3 p-4 bg-amber-50 border border-amber-200 rounded-lg", children: [
|
|
48656
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertCircle, { className: "w-5 h-5 text-amber-600 mt-0.5 flex-shrink-0" }),
|
|
48657
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
48658
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-medium text-amber-900 text-sm", children: "Changing roles affects access" }),
|
|
48659
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-amber-700 text-sm mt-1", children: "Review the impact carefully before confirming." })
|
|
48660
|
-
] })
|
|
48661
|
-
] }),
|
|
48393
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-6 space-y-5", children: step === "select" ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
48662
48394
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
|
|
48663
48395
|
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-gray-600", children: "User" }),
|
|
48664
48396
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-3 bg-gray-50 rounded-lg", children: [
|
|
@@ -48669,7 +48401,7 @@ var ChangeRoleDialog = ({
|
|
|
48669
48401
|
] })
|
|
48670
48402
|
] })
|
|
48671
48403
|
] }),
|
|
48672
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-
|
|
48404
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
|
|
48673
48405
|
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium text-gray-700", children: "Select new role" }),
|
|
48674
48406
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-2", children: availableRoles.map((role) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
48675
48407
|
"label",
|
|
@@ -48693,27 +48425,24 @@ var ChangeRoleDialog = ({
|
|
|
48693
48425
|
role
|
|
48694
48426
|
)) })
|
|
48695
48427
|
] }),
|
|
48696
|
-
|
|
48697
|
-
|
|
48698
|
-
/* @__PURE__ */ jsxRuntime.jsx("
|
|
48699
|
-
|
|
48700
|
-
|
|
48701
|
-
|
|
48702
|
-
] })
|
|
48428
|
+
roleChanged && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-3 py-2 bg-gray-50 border border-gray-200 rounded-lg", children: /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-xs text-gray-600", children: [
|
|
48429
|
+
"Changing from ",
|
|
48430
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium text-gray-900", children: getRoleLabel(user.role_level) }),
|
|
48431
|
+
" to ",
|
|
48432
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium text-gray-900", children: getRoleLabel(selectedRole) }),
|
|
48433
|
+
" will modify user permissions."
|
|
48434
|
+
] }) })
|
|
48703
48435
|
] }) : /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4", children: [
|
|
48704
48436
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-center gap-3 p-4 bg-gray-50 rounded-lg", children: [
|
|
48705
48437
|
/* @__PURE__ */ jsxRuntime.jsx(RoleBadge, { role: user.role_level }),
|
|
48706
48438
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { className: "w-5 h-5 text-gray-400" }),
|
|
48707
48439
|
/* @__PURE__ */ jsxRuntime.jsx(RoleBadge, { role: selectedRole })
|
|
48708
48440
|
] }),
|
|
48709
|
-
|
|
48710
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "
|
|
48711
|
-
/* @__PURE__ */ jsxRuntime.jsx("
|
|
48712
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "mt-0.5", children: "\u2022" }),
|
|
48713
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { children: warning6 })
|
|
48714
|
-
] }, idx)) })
|
|
48441
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
|
|
48442
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-gray-600", children: "User" }),
|
|
48443
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium text-gray-900", children: user.email })
|
|
48715
48444
|
] }),
|
|
48716
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-3 p-
|
|
48445
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-3 p-3 border border-gray-200 rounded-lg bg-gray-50", children: [
|
|
48717
48446
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
48718
48447
|
"input",
|
|
48719
48448
|
{
|
|
@@ -48724,7 +48453,7 @@ var ChangeRoleDialog = ({
|
|
|
48724
48453
|
className: "mt-0.5 h-4 w-4 text-blue-600 border-gray-300 rounded focus:ring-blue-500"
|
|
48725
48454
|
}
|
|
48726
48455
|
),
|
|
48727
|
-
/* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: "confirm-role-change", className: "text-sm text-gray-700 cursor-pointer", children: "I
|
|
48456
|
+
/* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: "confirm-role-change", className: "text-sm text-gray-700 cursor-pointer", children: "I confirm this role change and understand the permissions will be updated" })
|
|
48728
48457
|
] })
|
|
48729
48458
|
] }) }) }),
|
|
48730
48459
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-end gap-3 p-6 border-t border-gray-200 bg-gray-50", children: step === "select" ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
@@ -48767,7 +48496,7 @@ var ChangeRoleDialog = ({
|
|
|
48767
48496
|
/* @__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" })
|
|
48768
48497
|
] }),
|
|
48769
48498
|
"Changing..."
|
|
48770
|
-
] }) : "Change
|
|
48499
|
+
] }) : "Confirm Change"
|
|
48771
48500
|
}
|
|
48772
48501
|
)
|
|
48773
48502
|
] }) })
|
|
@@ -48790,32 +48519,34 @@ var ConfirmRemoveUserDialog = ({
|
|
|
48790
48519
|
setIsRemoving(false);
|
|
48791
48520
|
}
|
|
48792
48521
|
};
|
|
48793
|
-
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "fixed inset-0 z-50 flex items-center justify-center bg-black/50", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-white rounded-
|
|
48522
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "fixed inset-0 z-50 flex items-center justify-center bg-black/50 backdrop-blur-sm", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-white rounded-xl shadow-2xl max-w-md w-full mx-4 transform transition-all", children: [
|
|
48794
48523
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between p-6 border-b border-gray-200", children: [
|
|
48795
48524
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
|
|
48796
48525
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-2 bg-red-100 rounded-lg", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { className: "w-5 h-5 text-red-600" }) }),
|
|
48797
|
-
/* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-lg font-semibold text-gray-900", children: "
|
|
48526
|
+
/* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-lg font-semibold text-gray-900", children: "Permanently Delete User" })
|
|
48798
48527
|
] }),
|
|
48799
48528
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
48800
48529
|
"button",
|
|
48801
48530
|
{
|
|
48802
48531
|
onClick: onCancel,
|
|
48803
|
-
className: "text-gray-400 hover:text-gray-600 transition-colors",
|
|
48532
|
+
className: "text-gray-400 hover:text-gray-600 transition-colors p-1 hover:bg-gray-100 rounded-lg",
|
|
48533
|
+
disabled: isRemoving,
|
|
48534
|
+
"aria-label": "Close dialog",
|
|
48804
48535
|
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "w-5 h-5" })
|
|
48805
48536
|
}
|
|
48806
48537
|
)
|
|
48807
48538
|
] }),
|
|
48808
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-6 space-y-
|
|
48809
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-3 p-
|
|
48810
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertTriangle, { className: "w-
|
|
48811
|
-
/* @__PURE__ */ jsxRuntime.jsxs("
|
|
48812
|
-
/* @__PURE__ */ jsxRuntime.jsx("
|
|
48813
|
-
|
|
48539
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-6 space-y-5", children: [
|
|
48540
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-3 p-3 bg-red-50 border border-red-200 rounded-lg", children: [
|
|
48541
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertTriangle, { className: "w-4 h-4 text-red-600 mt-0.5 flex-shrink-0" }),
|
|
48542
|
+
/* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-sm text-red-900", children: [
|
|
48543
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: "This action cannot be undone." }),
|
|
48544
|
+
" This will permanently delete the user and all related data from the system."
|
|
48814
48545
|
] })
|
|
48815
48546
|
] }),
|
|
48816
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-
|
|
48817
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium text-gray-700", children: "You are about to
|
|
48818
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-
|
|
48547
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
|
|
48548
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium text-gray-700", children: "You are about to permanently delete:" }),
|
|
48549
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-3 bg-gray-50 rounded-lg space-y-2.5", children: [
|
|
48819
48550
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
|
|
48820
48551
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-gray-600", children: "Email" }),
|
|
48821
48552
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-medium text-gray-900", children: user.email })
|
|
@@ -48840,28 +48571,7 @@ var ConfirmRemoveUserDialog = ({
|
|
|
48840
48571
|
] })
|
|
48841
48572
|
] })
|
|
48842
48573
|
] }),
|
|
48843
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "
|
|
48844
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium text-gray-700", children: "This will:" }),
|
|
48845
|
-
/* @__PURE__ */ jsxRuntime.jsxs("ul", { className: "space-y-2 text-sm text-gray-600", children: [
|
|
48846
|
-
/* @__PURE__ */ jsxRuntime.jsxs("li", { className: "flex items-start gap-2", children: [
|
|
48847
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-red-500 mt-0.5", children: "\u2022" }),
|
|
48848
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "Revoke all access immediately" })
|
|
48849
|
-
] }),
|
|
48850
|
-
/* @__PURE__ */ jsxRuntime.jsxs("li", { className: "flex items-start gap-2", children: [
|
|
48851
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-red-500 mt-0.5", children: "\u2022" }),
|
|
48852
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "Remove all line and factory assignments" })
|
|
48853
|
-
] }),
|
|
48854
|
-
/* @__PURE__ */ jsxRuntime.jsxs("li", { className: "flex items-start gap-2", children: [
|
|
48855
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-red-500 mt-0.5", children: "\u2022" }),
|
|
48856
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "Log the user out of all sessions" })
|
|
48857
|
-
] }),
|
|
48858
|
-
/* @__PURE__ */ jsxRuntime.jsxs("li", { className: "flex items-start gap-2", children: [
|
|
48859
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-red-500 mt-0.5", children: "\u2022" }),
|
|
48860
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "User will not be able to access the dashboard" })
|
|
48861
|
-
] })
|
|
48862
|
-
] })
|
|
48863
|
-
] }),
|
|
48864
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-3 p-4 border border-gray-200 rounded-lg", children: [
|
|
48574
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-3 p-3 border border-gray-200 rounded-lg bg-gray-50", children: [
|
|
48865
48575
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
48866
48576
|
"input",
|
|
48867
48577
|
{
|
|
@@ -48872,7 +48582,7 @@ var ConfirmRemoveUserDialog = ({
|
|
|
48872
48582
|
className: "mt-0.5 h-4 w-4 text-red-600 border-gray-300 rounded focus:ring-red-500"
|
|
48873
48583
|
}
|
|
48874
48584
|
),
|
|
48875
|
-
/* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: "confirm-remove", className: "text-sm text-gray-700 cursor-pointer", children: "I understand this
|
|
48585
|
+
/* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: "confirm-remove", className: "text-sm text-gray-700 cursor-pointer", children: "I understand this will permanently delete the user and all related data, and this action cannot be undone" })
|
|
48876
48586
|
] })
|
|
48877
48587
|
] }),
|
|
48878
48588
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-end gap-3 p-6 border-t border-gray-200 bg-gray-50", children: [
|
|
@@ -48896,8 +48606,8 @@ var ConfirmRemoveUserDialog = ({
|
|
|
48896
48606
|
/* @__PURE__ */ jsxRuntime.jsx("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4", fill: "none" }),
|
|
48897
48607
|
/* @__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" })
|
|
48898
48608
|
] }),
|
|
48899
|
-
"
|
|
48900
|
-
] }) : "
|
|
48609
|
+
"Deleting..."
|
|
48610
|
+
] }) : "Delete User"
|
|
48901
48611
|
}
|
|
48902
48612
|
)
|
|
48903
48613
|
] })
|
|
@@ -49320,7 +49030,6 @@ var FactoryAssignmentDropdown = ({
|
|
|
49320
49030
|
var UserManagementTable = ({
|
|
49321
49031
|
users,
|
|
49322
49032
|
isLoading = false,
|
|
49323
|
-
onUserClick,
|
|
49324
49033
|
onRoleChange,
|
|
49325
49034
|
onRemoveUser,
|
|
49326
49035
|
onLineAssignmentUpdate,
|
|
@@ -49346,9 +49055,48 @@ var UserManagementTable = ({
|
|
|
49346
49055
|
const [sortField, setSortField] = React23.useState("email");
|
|
49347
49056
|
const [sortDirection, setSortDirection] = React23.useState("asc");
|
|
49348
49057
|
const [openActionMenuId, setOpenActionMenuId] = React23.useState(null);
|
|
49058
|
+
const [dropdownPosition, setDropdownPosition] = React23.useState(null);
|
|
49059
|
+
const actionButtonRefs = React23.useRef({});
|
|
49349
49060
|
const [selectedUser, setSelectedUser] = React23.useState(null);
|
|
49350
49061
|
const [showChangeRoleDialog, setShowChangeRoleDialog] = React23.useState(false);
|
|
49351
49062
|
const [showRemoveUserDialog, setShowRemoveUserDialog] = React23.useState(false);
|
|
49063
|
+
const handleOpenActionMenu = (userId) => {
|
|
49064
|
+
const buttonRef = actionButtonRefs.current[userId];
|
|
49065
|
+
if (buttonRef) {
|
|
49066
|
+
const rect = buttonRef.getBoundingClientRect();
|
|
49067
|
+
setDropdownPosition({
|
|
49068
|
+
top: rect.bottom + 8,
|
|
49069
|
+
// 8px below the button
|
|
49070
|
+
left: rect.right - 192
|
|
49071
|
+
// 192px is the dropdown width (w-48 = 12rem = 192px)
|
|
49072
|
+
});
|
|
49073
|
+
setOpenActionMenuId(userId);
|
|
49074
|
+
}
|
|
49075
|
+
};
|
|
49076
|
+
const handleCloseActionMenu = () => {
|
|
49077
|
+
setOpenActionMenuId(null);
|
|
49078
|
+
setDropdownPosition(null);
|
|
49079
|
+
};
|
|
49080
|
+
React23.useEffect(() => {
|
|
49081
|
+
if (openActionMenuId && actionButtonRefs.current[openActionMenuId]) {
|
|
49082
|
+
const updatePosition = () => {
|
|
49083
|
+
const buttonRef = actionButtonRefs.current[openActionMenuId];
|
|
49084
|
+
if (buttonRef) {
|
|
49085
|
+
const rect = buttonRef.getBoundingClientRect();
|
|
49086
|
+
setDropdownPosition({
|
|
49087
|
+
top: rect.bottom + 8,
|
|
49088
|
+
left: rect.right - 192
|
|
49089
|
+
});
|
|
49090
|
+
}
|
|
49091
|
+
};
|
|
49092
|
+
window.addEventListener("scroll", updatePosition, true);
|
|
49093
|
+
window.addEventListener("resize", updatePosition);
|
|
49094
|
+
return () => {
|
|
49095
|
+
window.removeEventListener("scroll", updatePosition, true);
|
|
49096
|
+
window.removeEventListener("resize", updatePosition);
|
|
49097
|
+
};
|
|
49098
|
+
}
|
|
49099
|
+
}, [openActionMenuId]);
|
|
49352
49100
|
const filteredAndSortedUsers = React23.useMemo(() => {
|
|
49353
49101
|
let filtered = users;
|
|
49354
49102
|
filtered = filtered.filter((user) => availableRoles.includes(user.role_level));
|
|
@@ -49539,7 +49287,7 @@ var UserManagementTable = ({
|
|
|
49539
49287
|
LineAssignmentDropdown,
|
|
49540
49288
|
{
|
|
49541
49289
|
userId: user.user_id,
|
|
49542
|
-
currentLineIds: user.properties?.
|
|
49290
|
+
currentLineIds: user.properties?.line_ids || [],
|
|
49543
49291
|
availableLines: (
|
|
49544
49292
|
// Filter lines to only show those from the target user's company
|
|
49545
49293
|
(() => {
|
|
@@ -49577,69 +49325,24 @@ var UserManagementTable = ({
|
|
|
49577
49325
|
}
|
|
49578
49326
|
) : /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-gray-900", children: formatAssignments(user) }) }),
|
|
49579
49327
|
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-6 py-4 whitespace-nowrap", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-gray-500", children: formatDate(user.created_at) }) }),
|
|
49580
|
-
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-6 py-4 whitespace-nowrap text-right", children: hasActions && /* @__PURE__ */ jsxRuntime.
|
|
49581
|
-
|
|
49582
|
-
|
|
49583
|
-
{
|
|
49584
|
-
|
|
49585
|
-
|
|
49586
|
-
|
|
49587
|
-
|
|
49588
|
-
|
|
49589
|
-
|
|
49590
|
-
|
|
49591
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
49592
|
-
"div",
|
|
49593
|
-
{
|
|
49594
|
-
className: "fixed inset-0 z-[9998]",
|
|
49595
|
-
onClick: () => setOpenActionMenuId(null)
|
|
49328
|
+
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-6 py-4 whitespace-nowrap text-right", children: hasActions && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
49329
|
+
"button",
|
|
49330
|
+
{
|
|
49331
|
+
ref: (el) => {
|
|
49332
|
+
actionButtonRefs.current[user.user_id] = el;
|
|
49333
|
+
},
|
|
49334
|
+
onClick: () => {
|
|
49335
|
+
if (openActionMenuId === user.user_id) {
|
|
49336
|
+
handleCloseActionMenu();
|
|
49337
|
+
} else {
|
|
49338
|
+
handleOpenActionMenu(user.user_id);
|
|
49596
49339
|
}
|
|
49597
|
-
|
|
49598
|
-
|
|
49599
|
-
|
|
49600
|
-
|
|
49601
|
-
|
|
49602
|
-
|
|
49603
|
-
onUserClick?.(user);
|
|
49604
|
-
setOpenActionMenuId(null);
|
|
49605
|
-
},
|
|
49606
|
-
className: "w-full px-4 py-2 text-sm text-left text-gray-700 hover:bg-gray-100 flex items-center gap-2",
|
|
49607
|
-
children: [
|
|
49608
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Eye, { className: "w-4 h-4" }),
|
|
49609
|
-
"View Details"
|
|
49610
|
-
]
|
|
49611
|
-
}
|
|
49612
|
-
),
|
|
49613
|
-
canChangeRole && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
49614
|
-
"button",
|
|
49615
|
-
{
|
|
49616
|
-
onClick: () => handleChangeRole(user),
|
|
49617
|
-
className: "w-full px-4 py-2 text-sm text-left text-gray-700 hover:bg-gray-100 flex items-center gap-2",
|
|
49618
|
-
disabled: isCurrentUser,
|
|
49619
|
-
children: [
|
|
49620
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.UserCog, { className: "w-4 h-4" }),
|
|
49621
|
-
"Change Role"
|
|
49622
|
-
]
|
|
49623
|
-
}
|
|
49624
|
-
),
|
|
49625
|
-
canRemove && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
49626
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-t border-gray-200 my-1" }),
|
|
49627
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
49628
|
-
"button",
|
|
49629
|
-
{
|
|
49630
|
-
onClick: () => handleRemoveUser(user),
|
|
49631
|
-
className: "w-full px-4 py-2 text-sm text-left text-red-600 hover:bg-red-50 flex items-center gap-2",
|
|
49632
|
-
disabled: isCurrentUser,
|
|
49633
|
-
children: [
|
|
49634
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { className: "w-4 h-4" }),
|
|
49635
|
-
"Remove User"
|
|
49636
|
-
]
|
|
49637
|
-
}
|
|
49638
|
-
)
|
|
49639
|
-
] })
|
|
49640
|
-
] }) })
|
|
49641
|
-
] })
|
|
49642
|
-
] }) })
|
|
49340
|
+
},
|
|
49341
|
+
className: "p-2 text-gray-400 hover:text-gray-600 hover:bg-gray-100 rounded-lg transition-colors",
|
|
49342
|
+
"aria-label": "User actions",
|
|
49343
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MoreVertical, { className: "w-4 h-4" })
|
|
49344
|
+
}
|
|
49345
|
+
) }) })
|
|
49643
49346
|
]
|
|
49644
49347
|
},
|
|
49645
49348
|
user.user_id
|
|
@@ -49647,6 +49350,75 @@ var UserManagementTable = ({
|
|
|
49647
49350
|
}) })
|
|
49648
49351
|
] }) }) })
|
|
49649
49352
|
] }),
|
|
49353
|
+
openActionMenuId && dropdownPosition && typeof document !== "undefined" && reactDom.createPortal(
|
|
49354
|
+
/* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
49355
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
49356
|
+
"div",
|
|
49357
|
+
{
|
|
49358
|
+
className: "fixed inset-0 z-[9998]",
|
|
49359
|
+
onClick: handleCloseActionMenu
|
|
49360
|
+
}
|
|
49361
|
+
),
|
|
49362
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
49363
|
+
"div",
|
|
49364
|
+
{
|
|
49365
|
+
className: "fixed w-48 bg-white rounded-lg shadow-lg border border-gray-200 z-[9999]",
|
|
49366
|
+
style: {
|
|
49367
|
+
top: `${dropdownPosition.top}px`,
|
|
49368
|
+
left: `${dropdownPosition.left}px`
|
|
49369
|
+
},
|
|
49370
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "py-1", children: [
|
|
49371
|
+
(() => {
|
|
49372
|
+
const user = users.find((u) => u.user_id === openActionMenuId);
|
|
49373
|
+
const isCurrentUser = user?.user_id === currentUserId;
|
|
49374
|
+
const canChangeRole = user && permissions.canChangeRole(user);
|
|
49375
|
+
return canChangeRole && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
49376
|
+
"button",
|
|
49377
|
+
{
|
|
49378
|
+
onClick: () => {
|
|
49379
|
+
if (user) {
|
|
49380
|
+
handleChangeRole(user);
|
|
49381
|
+
}
|
|
49382
|
+
},
|
|
49383
|
+
className: "w-full px-4 py-2 text-sm text-left text-gray-700 hover:bg-gray-100 flex items-center gap-2 disabled:opacity-50 disabled:cursor-not-allowed",
|
|
49384
|
+
disabled: isCurrentUser,
|
|
49385
|
+
children: [
|
|
49386
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.UserCog, { className: "w-4 h-4" }),
|
|
49387
|
+
"Change Role"
|
|
49388
|
+
]
|
|
49389
|
+
}
|
|
49390
|
+
);
|
|
49391
|
+
})(),
|
|
49392
|
+
(() => {
|
|
49393
|
+
const user = users.find((u) => u.user_id === openActionMenuId);
|
|
49394
|
+
const isCurrentUser = user?.user_id === currentUserId;
|
|
49395
|
+
const canRemove = user && permissions.canRemoveUser(user);
|
|
49396
|
+
return canRemove && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
49397
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-t border-gray-200 my-1" }),
|
|
49398
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
49399
|
+
"button",
|
|
49400
|
+
{
|
|
49401
|
+
onClick: () => {
|
|
49402
|
+
if (user) {
|
|
49403
|
+
handleRemoveUser(user);
|
|
49404
|
+
}
|
|
49405
|
+
},
|
|
49406
|
+
className: "w-full px-4 py-2 text-sm text-left text-red-600 hover:bg-red-50 flex items-center gap-2 disabled:opacity-50 disabled:cursor-not-allowed",
|
|
49407
|
+
disabled: isCurrentUser,
|
|
49408
|
+
children: [
|
|
49409
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { className: "w-4 h-4" }),
|
|
49410
|
+
"Delete User"
|
|
49411
|
+
]
|
|
49412
|
+
}
|
|
49413
|
+
)
|
|
49414
|
+
] });
|
|
49415
|
+
})()
|
|
49416
|
+
] })
|
|
49417
|
+
}
|
|
49418
|
+
)
|
|
49419
|
+
] }),
|
|
49420
|
+
document.body
|
|
49421
|
+
),
|
|
49650
49422
|
showChangeRoleDialog && selectedUser && /* @__PURE__ */ jsxRuntime.jsx(
|
|
49651
49423
|
ChangeRoleDialog,
|
|
49652
49424
|
{
|
|
@@ -50298,15 +50070,12 @@ var TeamManagementView = ({
|
|
|
50298
50070
|
if (!supabase || !user) return;
|
|
50299
50071
|
try {
|
|
50300
50072
|
const userManagementService = createUserManagementService(supabase);
|
|
50301
|
-
await userManagementService.
|
|
50302
|
-
|
|
50303
|
-
deactivated_by: user.id
|
|
50304
|
-
});
|
|
50305
|
-
sonner.toast.success("User removed successfully");
|
|
50073
|
+
const result = await userManagementService.deleteUser(userId);
|
|
50074
|
+
sonner.toast.success(`User ${result.deleted_user_email} permanently deleted`);
|
|
50306
50075
|
loadData();
|
|
50307
50076
|
} catch (err) {
|
|
50308
|
-
console.error("Error
|
|
50309
|
-
sonner.toast.error("Failed to
|
|
50077
|
+
console.error("Error deleting user:", err);
|
|
50078
|
+
sonner.toast.error("Failed to delete user");
|
|
50310
50079
|
}
|
|
50311
50080
|
}, [supabase, user, loadData]);
|
|
50312
50081
|
const handleLineAssignmentUpdate = React23.useCallback(async (userId, lineIds) => {
|
|
@@ -50400,9 +50169,6 @@ var TeamManagementView = ({
|
|
|
50400
50169
|
{
|
|
50401
50170
|
users,
|
|
50402
50171
|
currentUserId: user?.id,
|
|
50403
|
-
onUserClick: (clickedUser) => {
|
|
50404
|
-
console.log("View user details:", clickedUser);
|
|
50405
|
-
},
|
|
50406
50172
|
onRoleChange: handleRoleChange,
|
|
50407
50173
|
onRemoveUser: handleRemoveUser,
|
|
50408
50174
|
onLineAssignmentUpdate: handleLineAssignmentUpdate,
|