@optifye/dashboard-core 6.10.0 → 6.10.1
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.d.mts +73 -1
- package/dist/index.d.ts +73 -1
- package/dist/index.js +789 -347
- package/dist/index.mjs +786 -348
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -8838,27 +8838,208 @@ var useLeaderboardMetrics = (date, shiftId, limit = 10, filter2 = "all") => {
|
|
|
8838
8838
|
refetch: fetchLeaderboard
|
|
8839
8839
|
};
|
|
8840
8840
|
};
|
|
8841
|
+
var useMultiLineShiftConfigs = (lineIds, fallbackConfig) => {
|
|
8842
|
+
const [shiftConfigMap, setShiftConfigMap] = useState(/* @__PURE__ */ new Map());
|
|
8843
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
8844
|
+
const [error, setError] = useState(null);
|
|
8845
|
+
const supabase = useSupabase();
|
|
8846
|
+
const lineIdsKey = useMemo(() => lineIds.sort().join(","), [lineIds]);
|
|
8847
|
+
useEffect(() => {
|
|
8848
|
+
if (!lineIds || lineIds.length === 0) {
|
|
8849
|
+
setShiftConfigMap(/* @__PURE__ */ new Map());
|
|
8850
|
+
setIsLoading(false);
|
|
8851
|
+
return;
|
|
8852
|
+
}
|
|
8853
|
+
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
8854
|
+
const validLineIds = lineIds.filter((id3) => uuidRegex.test(id3));
|
|
8855
|
+
if (validLineIds.length === 0) {
|
|
8856
|
+
console.warn("[useMultiLineShiftConfigs] No valid line IDs provided");
|
|
8857
|
+
setShiftConfigMap(/* @__PURE__ */ new Map());
|
|
8858
|
+
setIsLoading(false);
|
|
8859
|
+
return;
|
|
8860
|
+
}
|
|
8861
|
+
let mounted = true;
|
|
8862
|
+
const calculateBreakDuration2 = (startTime, endTime) => {
|
|
8863
|
+
const [sh, sm] = startTime.split(":").map(Number);
|
|
8864
|
+
const [eh, em] = endTime.split(":").map(Number);
|
|
8865
|
+
let startMinutes = sh * 60 + sm;
|
|
8866
|
+
let endMinutes = eh * 60 + em;
|
|
8867
|
+
if (endMinutes < startMinutes) {
|
|
8868
|
+
endMinutes += 24 * 60;
|
|
8869
|
+
}
|
|
8870
|
+
return endMinutes - startMinutes;
|
|
8871
|
+
};
|
|
8872
|
+
const stripSeconds = (timeStr) => {
|
|
8873
|
+
if (!timeStr) return timeStr;
|
|
8874
|
+
return timeStr.substring(0, 5);
|
|
8875
|
+
};
|
|
8876
|
+
const buildShiftConfigFromRows = (shifts, fallback) => {
|
|
8877
|
+
const mapped = shifts.map((shift) => ({
|
|
8878
|
+
shiftId: shift.shift_id,
|
|
8879
|
+
shiftName: shift.shift_name || `Shift ${shift.shift_id}`,
|
|
8880
|
+
startTime: stripSeconds(shift.start_time),
|
|
8881
|
+
endTime: stripSeconds(shift.end_time),
|
|
8882
|
+
breaks: Array.isArray(shift.breaks) ? shift.breaks.map((b) => ({
|
|
8883
|
+
startTime: b.start || b.startTime || "00:00",
|
|
8884
|
+
endTime: b.end || b.endTime || "00:00",
|
|
8885
|
+
duration: calculateBreakDuration2(
|
|
8886
|
+
b.start || b.startTime || "00:00",
|
|
8887
|
+
b.end || b.endTime || "00:00"
|
|
8888
|
+
),
|
|
8889
|
+
remarks: b.remarks || b.name || ""
|
|
8890
|
+
})) : [],
|
|
8891
|
+
timezone: shift.timezone
|
|
8892
|
+
}));
|
|
8893
|
+
const day = mapped.find((s) => s.shiftId === 0);
|
|
8894
|
+
const night = mapped.find((s) => s.shiftId === 1);
|
|
8895
|
+
return {
|
|
8896
|
+
shifts: mapped,
|
|
8897
|
+
timezone: mapped[0]?.timezone,
|
|
8898
|
+
dayShift: day ? { id: day.shiftId, startTime: day.startTime, endTime: day.endTime, name: day.shiftName } : fallback?.dayShift,
|
|
8899
|
+
nightShift: night ? { id: night.shiftId, startTime: night.startTime, endTime: night.endTime, name: night.shiftName } : fallback?.nightShift,
|
|
8900
|
+
transitionPeriodMinutes: fallback?.transitionPeriodMinutes || 0
|
|
8901
|
+
};
|
|
8902
|
+
};
|
|
8903
|
+
const fetchAllConfigs = async () => {
|
|
8904
|
+
try {
|
|
8905
|
+
setIsLoading(true);
|
|
8906
|
+
setError(null);
|
|
8907
|
+
console.log(`[useMultiLineShiftConfigs] Fetching shift configs for ${validLineIds.length} lines`);
|
|
8908
|
+
const { data, error: fetchError } = await supabase.from("line_operating_hours").select("line_id, shift_id, shift_name, start_time, end_time, breaks, timezone").in("line_id", validLineIds);
|
|
8909
|
+
if (fetchError) {
|
|
8910
|
+
console.error("[useMultiLineShiftConfigs] Error fetching shift configs:", fetchError);
|
|
8911
|
+
throw new Error(`Failed to fetch shift configs: ${fetchError.message}`);
|
|
8912
|
+
}
|
|
8913
|
+
const lineShiftsMap = /* @__PURE__ */ new Map();
|
|
8914
|
+
data?.forEach((row) => {
|
|
8915
|
+
if (!lineShiftsMap.has(row.line_id)) {
|
|
8916
|
+
lineShiftsMap.set(row.line_id, []);
|
|
8917
|
+
}
|
|
8918
|
+
lineShiftsMap.get(row.line_id).push(row);
|
|
8919
|
+
});
|
|
8920
|
+
const configMap = /* @__PURE__ */ new Map();
|
|
8921
|
+
lineShiftsMap.forEach((shifts, lineId) => {
|
|
8922
|
+
const config = buildShiftConfigFromRows(shifts, fallbackConfig);
|
|
8923
|
+
configMap.set(lineId, config);
|
|
8924
|
+
});
|
|
8925
|
+
validLineIds.forEach((lineId) => {
|
|
8926
|
+
if (!configMap.has(lineId) && fallbackConfig) {
|
|
8927
|
+
console.warn(`[useMultiLineShiftConfigs] No config found for line ${lineId}, using fallback`);
|
|
8928
|
+
configMap.set(lineId, fallbackConfig);
|
|
8929
|
+
}
|
|
8930
|
+
});
|
|
8931
|
+
console.log(`[useMultiLineShiftConfigs] Built configs for ${configMap.size} lines`);
|
|
8932
|
+
if (mounted) {
|
|
8933
|
+
setShiftConfigMap(configMap);
|
|
8934
|
+
setIsLoading(false);
|
|
8935
|
+
}
|
|
8936
|
+
} catch (err) {
|
|
8937
|
+
console.error("[useMultiLineShiftConfigs] Error:", err);
|
|
8938
|
+
if (mounted) {
|
|
8939
|
+
setError(err instanceof Error ? err.message : "Failed to fetch shift configs");
|
|
8940
|
+
if (fallbackConfig) {
|
|
8941
|
+
const fallbackMap = /* @__PURE__ */ new Map();
|
|
8942
|
+
validLineIds.forEach((lineId) => {
|
|
8943
|
+
fallbackMap.set(lineId, fallbackConfig);
|
|
8944
|
+
});
|
|
8945
|
+
setShiftConfigMap(fallbackMap);
|
|
8946
|
+
}
|
|
8947
|
+
setIsLoading(false);
|
|
8948
|
+
}
|
|
8949
|
+
}
|
|
8950
|
+
};
|
|
8951
|
+
fetchAllConfigs();
|
|
8952
|
+
return () => {
|
|
8953
|
+
mounted = false;
|
|
8954
|
+
};
|
|
8955
|
+
}, [lineIdsKey, supabase]);
|
|
8956
|
+
return {
|
|
8957
|
+
shiftConfigMap,
|
|
8958
|
+
isLoading,
|
|
8959
|
+
error
|
|
8960
|
+
};
|
|
8961
|
+
};
|
|
8962
|
+
|
|
8963
|
+
// src/lib/utils/shiftGrouping.ts
|
|
8964
|
+
var getCurrentShiftForLine = (lineId, shiftConfig, timezone, now2 = /* @__PURE__ */ new Date()) => {
|
|
8965
|
+
const currentShift = getCurrentShift(timezone, shiftConfig, now2);
|
|
8966
|
+
return {
|
|
8967
|
+
lineId,
|
|
8968
|
+
shiftId: currentShift.shiftId,
|
|
8969
|
+
date: currentShift.date,
|
|
8970
|
+
shiftName: currentShift.shiftName || `Shift ${currentShift.shiftId}`
|
|
8971
|
+
};
|
|
8972
|
+
};
|
|
8973
|
+
var groupLinesByShift = (shiftConfigMap, timezone, now2 = /* @__PURE__ */ new Date()) => {
|
|
8974
|
+
const lineShiftInfos = [];
|
|
8975
|
+
shiftConfigMap.forEach((shiftConfig, lineId) => {
|
|
8976
|
+
const info = getCurrentShiftForLine(lineId, shiftConfig, timezone, now2);
|
|
8977
|
+
lineShiftInfos.push(info);
|
|
8978
|
+
});
|
|
8979
|
+
const groupMap = /* @__PURE__ */ new Map();
|
|
8980
|
+
lineShiftInfos.forEach((info) => {
|
|
8981
|
+
const key = `${info.shiftId}-${info.date}`;
|
|
8982
|
+
if (!groupMap.has(key)) {
|
|
8983
|
+
groupMap.set(key, {
|
|
8984
|
+
shiftId: info.shiftId,
|
|
8985
|
+
date: info.date,
|
|
8986
|
+
shiftName: info.shiftName,
|
|
8987
|
+
lineIds: []
|
|
8988
|
+
});
|
|
8989
|
+
}
|
|
8990
|
+
groupMap.get(key).lineIds.push(info.lineId);
|
|
8991
|
+
});
|
|
8992
|
+
return Array.from(groupMap.values()).sort((a, b) => a.shiftId - b.shiftId);
|
|
8993
|
+
};
|
|
8994
|
+
var areAllLinesOnSameShift = (shiftConfigMap, timezone, now2 = /* @__PURE__ */ new Date()) => {
|
|
8995
|
+
if (shiftConfigMap.size <= 1) return true;
|
|
8996
|
+
const groups = groupLinesByShift(shiftConfigMap, timezone, now2);
|
|
8997
|
+
return groups.length === 1;
|
|
8998
|
+
};
|
|
8999
|
+
var getUniformShiftGroup = (shiftConfigMap, timezone, now2 = /* @__PURE__ */ new Date()) => {
|
|
9000
|
+
const groups = groupLinesByShift(shiftConfigMap, timezone, now2);
|
|
9001
|
+
return groups.length === 1 ? groups[0] : null;
|
|
9002
|
+
};
|
|
9003
|
+
|
|
9004
|
+
// src/lib/hooks/useDashboardMetrics.ts
|
|
8841
9005
|
var useDashboardMetrics = ({ onLineMetricsUpdate, lineId, userAccessibleLineIds }) => {
|
|
8842
9006
|
const { supabaseUrl, supabaseKey } = useDashboardConfig();
|
|
8843
9007
|
const entityConfig = useEntityConfig();
|
|
8844
9008
|
const databaseConfig = useDatabaseConfig();
|
|
8845
9009
|
const dateTimeConfig = useDateTimeConfig();
|
|
8846
9010
|
const isFactoryView = lineId === (entityConfig.factoryViewId || "factory");
|
|
8847
|
-
const
|
|
8848
|
-
|
|
8849
|
-
|
|
9011
|
+
const appTimezone = useAppTimezone();
|
|
9012
|
+
const defaultTimezone = appTimezone || dateTimeConfig?.defaultTimezone || "UTC";
|
|
9013
|
+
const configuredLineIds = useMemo(() => {
|
|
9014
|
+
return getConfiguredLineIds(entityConfig);
|
|
8850
9015
|
}, [entityConfig]);
|
|
8851
|
-
const
|
|
8852
|
-
const {
|
|
9016
|
+
const { shiftConfig: staticShiftConfig } = useDashboardConfig();
|
|
9017
|
+
const {
|
|
9018
|
+
shiftConfigMap: multiLineShiftConfigMap,
|
|
9019
|
+
isLoading: isMultiLineShiftConfigLoading
|
|
9020
|
+
} = useMultiLineShiftConfigs(
|
|
9021
|
+
isFactoryView ? configuredLineIds : [],
|
|
9022
|
+
staticShiftConfig
|
|
9023
|
+
);
|
|
9024
|
+
const {
|
|
9025
|
+
shiftConfig: singleLineShiftConfig,
|
|
9026
|
+
isLoading: isSingleLineShiftConfigLoading,
|
|
9027
|
+
isFromDatabase
|
|
9028
|
+
} = useDynamicShiftConfig(isFactoryView ? void 0 : lineId);
|
|
9029
|
+
const shiftLoading = isFactoryView ? isMultiLineShiftConfigLoading : isSingleLineShiftConfigLoading;
|
|
9030
|
+
const shiftGroups = useMemo(() => {
|
|
9031
|
+
if (!isFactoryView) return [];
|
|
9032
|
+
if (isMultiLineShiftConfigLoading || multiLineShiftConfigMap.size === 0) return [];
|
|
9033
|
+
return groupLinesByShift(multiLineShiftConfigMap, defaultTimezone);
|
|
9034
|
+
}, [isFactoryView, isMultiLineShiftConfigLoading, multiLineShiftConfigMap, defaultTimezone]);
|
|
9035
|
+
const shiftConfig = isFactoryView ? null : singleLineShiftConfig;
|
|
8853
9036
|
console.log(`[useDashboardMetrics] \u{1F3AF} Shift config for line ${lineId}:`, {
|
|
8854
9037
|
isFactoryView,
|
|
8855
|
-
lineIdForShiftConfig,
|
|
8856
|
-
firstLineId,
|
|
8857
9038
|
isFromDatabase,
|
|
8858
|
-
shiftConfig: shiftConfig ? { shifts: shiftConfig.shifts?.length, timezone: shiftConfig.timezone } : null
|
|
9039
|
+
shiftConfig: shiftConfig ? { shifts: shiftConfig.shifts?.length, timezone: shiftConfig.timezone } : null,
|
|
9040
|
+
shiftGroupsCount: shiftGroups.length,
|
|
9041
|
+
shiftGroups: shiftGroups.map((g) => ({ shiftId: g.shiftId, date: g.date, lineCount: g.lineIds.length }))
|
|
8859
9042
|
});
|
|
8860
|
-
const appTimezone = useAppTimezone();
|
|
8861
|
-
const defaultTimezone = appTimezone || dateTimeConfig?.defaultTimezone || "UTC";
|
|
8862
9043
|
const configuredLineMetricsTable = databaseConfig?.tables?.lineMetrics ?? "line_metrics";
|
|
8863
9044
|
const schema = databaseConfig?.schema ?? "public";
|
|
8864
9045
|
const supabase = useSupabase();
|
|
@@ -8895,16 +9076,6 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId, userAccessibleLineIds
|
|
|
8895
9076
|
setIsLoading(true);
|
|
8896
9077
|
setError(null);
|
|
8897
9078
|
try {
|
|
8898
|
-
const currentShiftDetails = getCurrentShift(defaultTimezone, shiftConfig);
|
|
8899
|
-
const operationalDate = getOperationalDate(defaultTimezone);
|
|
8900
|
-
const targetLineIds = currentLineIdToUse === (entityConfig.factoryViewId || "factory") ? userAccessibleLineIds || getConfiguredLineIds(entityConfig) : [currentLineIdToUse];
|
|
8901
|
-
if (targetLineIds.length === 0 && currentLineIdToUse === (entityConfig.factoryViewId || "factory")) {
|
|
8902
|
-
throw new Error("Factory view selected, but no lines are configured in entityConfig.");
|
|
8903
|
-
}
|
|
8904
|
-
if (targetLineIds.length === 0) {
|
|
8905
|
-
throw new Error("No target line IDs available for fetching metrics.");
|
|
8906
|
-
}
|
|
8907
|
-
const isFactoryView2 = currentLineIdToUse === (entityConfig.factoryViewId || "factory");
|
|
8908
9079
|
const { data: { session } } = await supabase.auth.getSession();
|
|
8909
9080
|
console.log("[useDashboardMetrics] Session check:", {
|
|
8910
9081
|
hasSession: !!session,
|
|
@@ -8918,42 +9089,98 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId, userAccessibleLineIds
|
|
|
8918
9089
|
if (!apiUrl) {
|
|
8919
9090
|
throw new Error("Backend URL is not configured. Please set NEXT_PUBLIC_BACKEND_URL in your environment.");
|
|
8920
9091
|
}
|
|
8921
|
-
const
|
|
8922
|
-
const
|
|
8923
|
-
|
|
8924
|
-
|
|
8925
|
-
|
|
8926
|
-
lineIdsParam,
|
|
8927
|
-
operationalDate,
|
|
8928
|
-
shiftId: currentShiftDetails.shiftId,
|
|
8929
|
-
companyId: entityConfig.companyId
|
|
8930
|
-
});
|
|
8931
|
-
const response = await fetch(url, {
|
|
8932
|
-
method: "GET",
|
|
8933
|
-
headers: {
|
|
8934
|
-
"Authorization": `Bearer ${session.access_token}`,
|
|
8935
|
-
"Content-Type": "application/json"
|
|
8936
|
-
}
|
|
8937
|
-
});
|
|
8938
|
-
console.log("[useDashboardMetrics] Response status:", response.status, response.statusText);
|
|
8939
|
-
if (!response.ok) {
|
|
8940
|
-
const errorText = await response.text();
|
|
8941
|
-
console.error("[useDashboardMetrics] Backend API error response:", errorText);
|
|
8942
|
-
throw new Error(`Backend API error (${response.status}): ${errorText}`);
|
|
9092
|
+
const factoryViewIdentifier = entityConfig.factoryViewId || "factory";
|
|
9093
|
+
const isFactory = currentLineIdToUse === factoryViewIdentifier;
|
|
9094
|
+
const targetLineIds = isFactory ? userAccessibleLineIds || configuredLineIds : [currentLineIdToUse];
|
|
9095
|
+
if (targetLineIds.length === 0) {
|
|
9096
|
+
throw new Error("No target line IDs available for fetching metrics.");
|
|
8943
9097
|
}
|
|
8944
|
-
|
|
8945
|
-
let
|
|
8946
|
-
|
|
8947
|
-
|
|
8948
|
-
|
|
8949
|
-
|
|
8950
|
-
|
|
9098
|
+
let allWorkspaceMetrics = [];
|
|
9099
|
+
let allLineMetrics = [];
|
|
9100
|
+
if (isFactory && shiftGroups.length > 0) {
|
|
9101
|
+
console.log(`[useDashboardMetrics] \u{1F3ED} Factory view: Fetching for ${shiftGroups.length} shift group(s)`);
|
|
9102
|
+
const metricsPromises = shiftGroups.map(async (group) => {
|
|
9103
|
+
const lineIdsParam = `line_ids=${group.lineIds.join(",")}`;
|
|
9104
|
+
const url = `${apiUrl}/api/dashboard/metrics?${lineIdsParam}&date=${group.date}&shift_id=${group.shiftId}&company_id=${entityConfig.companyId}`;
|
|
9105
|
+
console.log(`[useDashboardMetrics] \u{1F4CA} Fetching for shift ${group.shiftId} (${group.shiftName}):`, {
|
|
9106
|
+
lineIds: group.lineIds,
|
|
9107
|
+
date: group.date
|
|
9108
|
+
});
|
|
9109
|
+
const response = await fetch(url, {
|
|
9110
|
+
method: "GET",
|
|
9111
|
+
headers: {
|
|
9112
|
+
"Authorization": `Bearer ${session.access_token}`,
|
|
9113
|
+
"Content-Type": "application/json"
|
|
9114
|
+
}
|
|
9115
|
+
});
|
|
9116
|
+
if (!response.ok) {
|
|
9117
|
+
const errorText = await response.text();
|
|
9118
|
+
console.error(`[useDashboardMetrics] Backend API error for shift ${group.shiftId}:`, errorText);
|
|
9119
|
+
throw new Error(`Backend API error (${response.status}): ${errorText}`);
|
|
9120
|
+
}
|
|
9121
|
+
const responseText = await response.text();
|
|
9122
|
+
try {
|
|
9123
|
+
return JSON.parse(responseText);
|
|
9124
|
+
} catch (parseError) {
|
|
9125
|
+
console.error("[useDashboardMetrics] Failed to parse response:", responseText.substring(0, 500));
|
|
9126
|
+
throw new Error(`Invalid JSON response from backend`);
|
|
9127
|
+
}
|
|
9128
|
+
});
|
|
9129
|
+
const results = await Promise.all(metricsPromises);
|
|
9130
|
+
results.forEach((result) => {
|
|
9131
|
+
if (result.workspace_metrics) {
|
|
9132
|
+
allWorkspaceMetrics.push(...result.workspace_metrics);
|
|
9133
|
+
}
|
|
9134
|
+
if (result.line_metrics) {
|
|
9135
|
+
allLineMetrics.push(...result.line_metrics);
|
|
9136
|
+
}
|
|
9137
|
+
});
|
|
9138
|
+
console.log(`[useDashboardMetrics] \u{1F4CA} Merged metrics from ${results.length} shift groups:`, {
|
|
9139
|
+
workspaceCount: allWorkspaceMetrics.length,
|
|
9140
|
+
lineMetricsCount: allLineMetrics.length
|
|
9141
|
+
});
|
|
9142
|
+
} else {
|
|
9143
|
+
const currentShiftDetails = shiftConfig ? getCurrentShift(defaultTimezone, shiftConfig) : shiftGroups.length === 1 ? { date: shiftGroups[0].date, shiftId: shiftGroups[0].shiftId } : getCurrentShift(defaultTimezone, staticShiftConfig);
|
|
9144
|
+
const operationalDate = currentShiftDetails.date;
|
|
9145
|
+
const lineIdsParam = isFactory ? `line_ids=${targetLineIds.join(",")}` : `line_id=${targetLineIds[0]}`;
|
|
9146
|
+
const url = `${apiUrl}/api/dashboard/metrics?${lineIdsParam}&date=${operationalDate}&shift_id=${currentShiftDetails.shiftId}&company_id=${entityConfig.companyId}`;
|
|
9147
|
+
console.log("[useDashboardMetrics] Calling backend API:", {
|
|
9148
|
+
url,
|
|
9149
|
+
apiUrl,
|
|
9150
|
+
lineIdsParam,
|
|
9151
|
+
operationalDate,
|
|
9152
|
+
shiftId: currentShiftDetails.shiftId,
|
|
9153
|
+
companyId: entityConfig.companyId
|
|
9154
|
+
});
|
|
9155
|
+
const response = await fetch(url, {
|
|
9156
|
+
method: "GET",
|
|
9157
|
+
headers: {
|
|
9158
|
+
"Authorization": `Bearer ${session.access_token}`,
|
|
9159
|
+
"Content-Type": "application/json"
|
|
9160
|
+
}
|
|
9161
|
+
});
|
|
9162
|
+
console.log("[useDashboardMetrics] Response status:", response.status, response.statusText);
|
|
9163
|
+
if (!response.ok) {
|
|
9164
|
+
const errorText = await response.text();
|
|
9165
|
+
console.error("[useDashboardMetrics] Backend API error response:", errorText);
|
|
9166
|
+
throw new Error(`Backend API error (${response.status}): ${errorText}`);
|
|
9167
|
+
}
|
|
9168
|
+
const responseText = await response.text();
|
|
9169
|
+
let backendData;
|
|
9170
|
+
try {
|
|
9171
|
+
backendData = JSON.parse(responseText);
|
|
9172
|
+
} catch (parseError) {
|
|
9173
|
+
console.error("[useDashboardMetrics] Failed to parse response as JSON. Response text:", responseText.substring(0, 500));
|
|
9174
|
+
throw new Error(`Invalid JSON response from backend. Received: ${responseText.substring(0, 100)}...`);
|
|
9175
|
+
}
|
|
9176
|
+
console.log("[useDashboardMetrics] Backend response:", {
|
|
9177
|
+
workspaceCount: backendData.workspace_metrics?.length || 0,
|
|
9178
|
+
lineCount: backendData.line_metrics?.length || 0
|
|
9179
|
+
});
|
|
9180
|
+
allWorkspaceMetrics = backendData.workspace_metrics || [];
|
|
9181
|
+
allLineMetrics = backendData.line_metrics || [];
|
|
8951
9182
|
}
|
|
8952
|
-
|
|
8953
|
-
workspaceCount: backendData.workspace_metrics?.length || 0,
|
|
8954
|
-
lineCount: backendData.line_metrics?.length || 0
|
|
8955
|
-
});
|
|
8956
|
-
const transformedWorkspaceData = (backendData.workspace_metrics || []).map((item) => ({
|
|
9183
|
+
const transformedWorkspaceData = allWorkspaceMetrics.map((item) => ({
|
|
8957
9184
|
company_id: item.company_id || entityConfig.companyId,
|
|
8958
9185
|
line_id: item.line_id,
|
|
8959
9186
|
shift_id: item.shift_id,
|
|
@@ -8976,7 +9203,7 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId, userAccessibleLineIds
|
|
|
8976
9203
|
});
|
|
8977
9204
|
const newMetricsState = {
|
|
8978
9205
|
workspaceMetrics: transformedWorkspaceData,
|
|
8979
|
-
lineMetrics:
|
|
9206
|
+
lineMetrics: allLineMetrics || []
|
|
8980
9207
|
};
|
|
8981
9208
|
console.log("[useDashboardMetrics] Setting metrics state:", {
|
|
8982
9209
|
workspaceMetrics: newMetricsState.workspaceMetrics.length,
|
|
@@ -8997,9 +9224,12 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId, userAccessibleLineIds
|
|
|
8997
9224
|
metrics2?.lineMetrics?.length || 0,
|
|
8998
9225
|
companySpecificMetricsTable,
|
|
8999
9226
|
entityConfig,
|
|
9000
|
-
appTimezone,
|
|
9001
9227
|
defaultTimezone,
|
|
9002
9228
|
shiftConfig,
|
|
9229
|
+
shiftGroups,
|
|
9230
|
+
configuredLineIds,
|
|
9231
|
+
staticShiftConfig,
|
|
9232
|
+
userAccessibleLineIds,
|
|
9003
9233
|
shiftLoading
|
|
9004
9234
|
]);
|
|
9005
9235
|
const fetchAllMetricsRef = useRef(fetchAllMetrics);
|
|
@@ -9023,32 +9253,68 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId, userAccessibleLineIds
|
|
|
9023
9253
|
if (!currentLineIdToUse || !supabase || companySpecificMetricsTable.includes("unknown_company") || !entityConfig.companyId) {
|
|
9024
9254
|
return;
|
|
9025
9255
|
}
|
|
9026
|
-
const
|
|
9027
|
-
const
|
|
9028
|
-
const targetLineIds = currentLineIdToUse === (entityConfig.factoryViewId || "factory") ? userAccessibleLineIds || getConfiguredLineIds(entityConfig) : [currentLineIdToUse];
|
|
9029
|
-
if (targetLineIds.length === 0) return;
|
|
9030
|
-
const wsMetricsFilter = `line_id=in.(${targetLineIds.map((id3) => `"${id3}"`).join(",")})`;
|
|
9031
|
-
const lineMetricsFilter = `line_id=in.(${targetLineIds.map((id3) => `"${id3}"`).join(",")})`;
|
|
9256
|
+
const factoryViewIdentifier = entityConfig.factoryViewId || "factory";
|
|
9257
|
+
const isFactory = currentLineIdToUse === factoryViewIdentifier;
|
|
9032
9258
|
const channels = [];
|
|
9033
|
-
|
|
9034
|
-
|
|
9035
|
-
|
|
9036
|
-
|
|
9037
|
-
{
|
|
9038
|
-
|
|
9039
|
-
|
|
9040
|
-
|
|
9041
|
-
|
|
9259
|
+
if (isFactory && shiftGroups.length > 0) {
|
|
9260
|
+
console.log(`[useDashboardMetrics] \u{1F4E1} Setting up subscriptions for ${shiftGroups.length} shift group(s)`);
|
|
9261
|
+
shiftGroups.forEach((group, index) => {
|
|
9262
|
+
const baseFilterParts = `date=eq.${group.date},shift_id=eq.${group.shiftId}`;
|
|
9263
|
+
const lineIdFilterPart = `line_id=in.(${group.lineIds.map((id3) => `"${id3}"`).join(",")})`;
|
|
9264
|
+
const filter2 = `${baseFilterParts},${lineIdFilterPart}`;
|
|
9265
|
+
const wsChannelName = `dashboard-ws-g${index}-${group.date}-${group.shiftId}`.replace(/[^a-zA-Z0-9_-]/g, "");
|
|
9266
|
+
const wsChannel = supabase.channel(wsChannelName).on(
|
|
9267
|
+
"postgres_changes",
|
|
9268
|
+
{ event: "*", schema, table: companySpecificMetricsTable, filter: filter2 },
|
|
9269
|
+
(payload) => {
|
|
9270
|
+
const payloadData = payload.new || payload.old;
|
|
9271
|
+
if (payloadData?.date === group.date && payloadData?.shift_id === group.shiftId) {
|
|
9272
|
+
queueUpdate();
|
|
9273
|
+
}
|
|
9042
9274
|
}
|
|
9043
|
-
|
|
9044
|
-
|
|
9045
|
-
|
|
9046
|
-
|
|
9047
|
-
|
|
9048
|
-
|
|
9049
|
-
|
|
9050
|
-
|
|
9051
|
-
|
|
9275
|
+
).subscribe();
|
|
9276
|
+
channels.push(wsChannel);
|
|
9277
|
+
const lmChannelName = `dashboard-lm-g${index}-${group.date}-${group.shiftId}`.replace(/[^a-zA-Z0-9_-]/g, "");
|
|
9278
|
+
const lmChannel = supabase.channel(lmChannelName).on(
|
|
9279
|
+
"postgres_changes",
|
|
9280
|
+
{ event: "*", schema, table: configuredLineMetricsTable, filter: filter2 },
|
|
9281
|
+
(payload) => {
|
|
9282
|
+
const payloadData = payload.new || payload.old;
|
|
9283
|
+
if (payloadData?.date === group.date && payloadData?.shift_id === group.shiftId) {
|
|
9284
|
+
queueUpdate();
|
|
9285
|
+
onLineMetricsUpdateRef.current?.();
|
|
9286
|
+
}
|
|
9287
|
+
}
|
|
9288
|
+
).subscribe();
|
|
9289
|
+
channels.push(lmChannel);
|
|
9290
|
+
});
|
|
9291
|
+
} else {
|
|
9292
|
+
const currentShiftDetails = shiftConfig ? getCurrentShift(defaultTimezone, shiftConfig) : getCurrentShift(defaultTimezone, staticShiftConfig);
|
|
9293
|
+
const operationalDateForSubscription = currentShiftDetails.date;
|
|
9294
|
+
const targetLineIds = [currentLineIdToUse];
|
|
9295
|
+
if (targetLineIds.length === 0) return;
|
|
9296
|
+
const wsMetricsFilter = `line_id=in.(${targetLineIds.map((id3) => `"${id3}"`).join(",")})`;
|
|
9297
|
+
const lineMetricsFilter = `line_id=in.(${targetLineIds.map((id3) => `"${id3}"`).join(",")})`;
|
|
9298
|
+
const createSubscription = (table, filter2, channelNameBase, callback) => {
|
|
9299
|
+
const channelName = `${channelNameBase}-${Date.now()}`.replace(/[^a-zA-Z0-9_-]/g, "");
|
|
9300
|
+
const channel = supabase.channel(channelName).on(
|
|
9301
|
+
"postgres_changes",
|
|
9302
|
+
{ event: "*", schema, table, filter: filter2 },
|
|
9303
|
+
(payload) => {
|
|
9304
|
+
const payloadData = payload.new;
|
|
9305
|
+
if (payloadData?.date === operationalDateForSubscription && payloadData?.shift_id === currentShiftDetails.shiftId) {
|
|
9306
|
+
callback();
|
|
9307
|
+
}
|
|
9308
|
+
}
|
|
9309
|
+
).subscribe();
|
|
9310
|
+
channels.push(channel);
|
|
9311
|
+
};
|
|
9312
|
+
createSubscription(companySpecificMetricsTable, wsMetricsFilter, "dashboard-ws-metrics", queueUpdate);
|
|
9313
|
+
createSubscription(configuredLineMetricsTable, lineMetricsFilter, "dashboard-line-metrics", () => {
|
|
9314
|
+
queueUpdate();
|
|
9315
|
+
onLineMetricsUpdateRef.current?.();
|
|
9316
|
+
});
|
|
9317
|
+
}
|
|
9052
9318
|
return () => {
|
|
9053
9319
|
channels.forEach((channel) => {
|
|
9054
9320
|
supabase?.removeChannel(channel);
|
|
@@ -9062,9 +9328,10 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId, userAccessibleLineIds
|
|
|
9062
9328
|
schema,
|
|
9063
9329
|
entityConfig?.companyId,
|
|
9064
9330
|
entityConfig?.factoryViewId,
|
|
9065
|
-
appTimezone,
|
|
9066
9331
|
defaultTimezone,
|
|
9067
9332
|
shiftConfig,
|
|
9333
|
+
staticShiftConfig,
|
|
9334
|
+
shiftGroups,
|
|
9068
9335
|
lineId,
|
|
9069
9336
|
userAccessibleLineIds
|
|
9070
9337
|
]);
|
|
@@ -9082,20 +9349,37 @@ var useLineKPIs = ({ lineId, enabled }) => {
|
|
|
9082
9349
|
const isFactoryView = lineId === (entityConfig.factoryViewId || "factory");
|
|
9083
9350
|
const databaseConfig = useDatabaseConfig();
|
|
9084
9351
|
const dateTimeConfig = useDateTimeConfig();
|
|
9085
|
-
useShiftConfig();
|
|
9086
|
-
const
|
|
9087
|
-
|
|
9088
|
-
|
|
9352
|
+
const staticShiftConfig = useShiftConfig();
|
|
9353
|
+
const appTimezone = useAppTimezone();
|
|
9354
|
+
const timezone = appTimezone || dateTimeConfig.defaultTimezone || "UTC";
|
|
9355
|
+
const configuredLineIds = useMemo(() => {
|
|
9356
|
+
return getConfiguredLineIds(entityConfig);
|
|
9089
9357
|
}, [entityConfig]);
|
|
9090
|
-
const
|
|
9091
|
-
|
|
9092
|
-
|
|
9358
|
+
const {
|
|
9359
|
+
shiftConfigMap: multiLineShiftConfigMap,
|
|
9360
|
+
isLoading: isMultiLineShiftConfigLoading
|
|
9361
|
+
} = useMultiLineShiftConfigs(
|
|
9362
|
+
isFactoryView ? configuredLineIds : [],
|
|
9363
|
+
staticShiftConfig
|
|
9364
|
+
);
|
|
9365
|
+
const {
|
|
9366
|
+
shiftConfig: singleLineShiftConfig,
|
|
9367
|
+
isFromDatabase,
|
|
9368
|
+
isLoading: isSingleLineShiftConfigLoading
|
|
9369
|
+
} = useDynamicShiftConfig(isFactoryView ? void 0 : lineId);
|
|
9370
|
+
const isShiftConfigLoading = isFactoryView ? isMultiLineShiftConfigLoading : isSingleLineShiftConfigLoading;
|
|
9371
|
+
const shiftGroups = useMemo(() => {
|
|
9372
|
+
if (!isFactoryView) return [];
|
|
9373
|
+
if (isMultiLineShiftConfigLoading || multiLineShiftConfigMap.size === 0) return [];
|
|
9374
|
+
return groupLinesByShift(multiLineShiftConfigMap, timezone);
|
|
9375
|
+
}, [isFactoryView, isMultiLineShiftConfigLoading, multiLineShiftConfigMap, timezone]);
|
|
9376
|
+
const shiftConfig = isFactoryView ? null : singleLineShiftConfig;
|
|
9093
9377
|
console.log(`[useLineKPIs] \u{1F3AF} Shift config for line ${lineId}:`, {
|
|
9094
9378
|
isFactoryView,
|
|
9095
|
-
lineIdForShiftConfig,
|
|
9096
|
-
firstLineId,
|
|
9097
9379
|
isFromDatabase,
|
|
9098
|
-
shiftConfig
|
|
9380
|
+
shiftConfig,
|
|
9381
|
+
shiftGroupsCount: shiftGroups.length,
|
|
9382
|
+
shiftGroups: shiftGroups.map((g) => ({ shiftId: g.shiftId, date: g.date, lineCount: g.lineIds.length }))
|
|
9099
9383
|
});
|
|
9100
9384
|
const supabase = useSupabase();
|
|
9101
9385
|
useMemo(() => {
|
|
@@ -9109,8 +9393,6 @@ var useLineKPIs = ({ lineId, enabled }) => {
|
|
|
9109
9393
|
const updateQueueRef = useRef(false);
|
|
9110
9394
|
const updateTimeoutRef = useRef(null);
|
|
9111
9395
|
const queueUpdateRef = useRef(void 0);
|
|
9112
|
-
const appTimezone = useAppTimezone();
|
|
9113
|
-
const timezone = appTimezone || dateTimeConfig.defaultTimezone || "UTC";
|
|
9114
9396
|
const schema = databaseConfig.schema ?? "public";
|
|
9115
9397
|
const lineMetricsTable = databaseConfig.tables?.lineMetrics ?? "line_metrics";
|
|
9116
9398
|
const companySpecificMetricsTable = useMemo(
|
|
@@ -9129,8 +9411,6 @@ var useLineKPIs = ({ lineId, enabled }) => {
|
|
|
9129
9411
|
setIsLoading(true);
|
|
9130
9412
|
setError(null);
|
|
9131
9413
|
try {
|
|
9132
|
-
const currentShiftDetails = getCurrentShift(timezone, shiftConfig ?? void 0);
|
|
9133
|
-
const operationalDate = currentShiftDetails.date;
|
|
9134
9414
|
const { data: { session } } = await supabase.auth.getSession();
|
|
9135
9415
|
if (!session?.access_token) {
|
|
9136
9416
|
throw new Error("No authentication token available");
|
|
@@ -9141,33 +9421,68 @@ var useLineKPIs = ({ lineId, enabled }) => {
|
|
|
9141
9421
|
}
|
|
9142
9422
|
const factoryViewIdentifier = entityConfig.factoryViewId || "factory";
|
|
9143
9423
|
const isFactory = currentLineId === factoryViewIdentifier;
|
|
9144
|
-
|
|
9145
|
-
|
|
9146
|
-
|
|
9147
|
-
|
|
9148
|
-
|
|
9149
|
-
|
|
9150
|
-
|
|
9424
|
+
if (isFactory && shiftGroups.length > 0) {
|
|
9425
|
+
console.log(`[useLineKPIs] \u{1F3ED} Factory view: Fetching KPIs for ${shiftGroups.length} shift group(s)`);
|
|
9426
|
+
const kpiPromises = shiftGroups.map(async (group) => {
|
|
9427
|
+
const lineIdsParam = `line_ids=${group.lineIds.join(",")}`;
|
|
9428
|
+
const url = `${apiUrl}/api/dashboard/line-kpis?${lineIdsParam}&date=${group.date}&shift_id=${group.shiftId}&company_id=${entityConfig.companyId}`;
|
|
9429
|
+
console.log(`[useLineKPIs] \u{1F4CA} Fetching for shift ${group.shiftId} (${group.shiftName}):`, {
|
|
9430
|
+
lineIds: group.lineIds,
|
|
9431
|
+
date: group.date
|
|
9432
|
+
});
|
|
9433
|
+
const response = await fetch(url, {
|
|
9434
|
+
headers: {
|
|
9435
|
+
"Authorization": `Bearer ${session.access_token}`,
|
|
9436
|
+
"Content-Type": "application/json"
|
|
9437
|
+
}
|
|
9438
|
+
});
|
|
9439
|
+
if (!response.ok) {
|
|
9440
|
+
const errorText = await response.text();
|
|
9441
|
+
console.error(`[useLineKPIs] Backend API error for shift ${group.shiftId}:`, errorText);
|
|
9442
|
+
throw new Error(`Backend API error (${response.status}): ${errorText}`);
|
|
9151
9443
|
}
|
|
9152
|
-
|
|
9153
|
-
|
|
9154
|
-
|
|
9155
|
-
|
|
9156
|
-
|
|
9157
|
-
|
|
9158
|
-
|
|
9159
|
-
|
|
9160
|
-
|
|
9161
|
-
|
|
9162
|
-
|
|
9163
|
-
} catch (parseError) {
|
|
9164
|
-
console.error("[useLineKPIs] Failed to parse response as JSON. Response text:", responseText.substring(0, 500));
|
|
9165
|
-
throw new Error(`Invalid JSON response from backend. Received: ${responseText.substring(0, 100)}...`);
|
|
9166
|
-
}
|
|
9167
|
-
if (backendData.kpis) {
|
|
9168
|
-
setKPIs(backendData.kpis);
|
|
9444
|
+
const responseText = await response.text();
|
|
9445
|
+
try {
|
|
9446
|
+
return JSON.parse(responseText);
|
|
9447
|
+
} catch (parseError) {
|
|
9448
|
+
console.error("[useLineKPIs] Failed to parse response as JSON:", responseText.substring(0, 500));
|
|
9449
|
+
throw new Error(`Invalid JSON response from backend`);
|
|
9450
|
+
}
|
|
9451
|
+
});
|
|
9452
|
+
const results = await Promise.all(kpiPromises);
|
|
9453
|
+
const aggregatedKPIs = aggregateKPIResults(results);
|
|
9454
|
+
setKPIs(aggregatedKPIs);
|
|
9169
9455
|
} else {
|
|
9170
|
-
|
|
9456
|
+
const currentShiftDetails = shiftConfig ? getCurrentShift(timezone, shiftConfig) : shiftGroups.length === 1 ? { date: shiftGroups[0].date, shiftId: shiftGroups[0].shiftId } : getCurrentShift(timezone, staticShiftConfig);
|
|
9457
|
+
const operationalDate = currentShiftDetails.date;
|
|
9458
|
+
const lineParam = isFactory ? `line_ids=${configuredLineIds.join(",")}` : `line_id=${currentLineId}`;
|
|
9459
|
+
const response = await fetch(
|
|
9460
|
+
`${apiUrl}/api/dashboard/line-kpis?${lineParam}&date=${operationalDate}&shift_id=${currentShiftDetails.shiftId}&company_id=${entityConfig.companyId}`,
|
|
9461
|
+
{
|
|
9462
|
+
headers: {
|
|
9463
|
+
"Authorization": `Bearer ${session.access_token}`,
|
|
9464
|
+
"Content-Type": "application/json"
|
|
9465
|
+
}
|
|
9466
|
+
}
|
|
9467
|
+
);
|
|
9468
|
+
if (!response.ok) {
|
|
9469
|
+
const errorText = await response.text();
|
|
9470
|
+
console.error("[useLineKPIs] Backend API error response:", errorText);
|
|
9471
|
+
throw new Error(`Backend API error (${response.status}): ${errorText}`);
|
|
9472
|
+
}
|
|
9473
|
+
const responseText = await response.text();
|
|
9474
|
+
let backendData;
|
|
9475
|
+
try {
|
|
9476
|
+
backendData = JSON.parse(responseText);
|
|
9477
|
+
} catch (parseError) {
|
|
9478
|
+
console.error("[useLineKPIs] Failed to parse response as JSON. Response text:", responseText.substring(0, 500));
|
|
9479
|
+
throw new Error(`Invalid JSON response from backend. Received: ${responseText.substring(0, 100)}...`);
|
|
9480
|
+
}
|
|
9481
|
+
if (backendData.kpis) {
|
|
9482
|
+
setKPIs(backendData.kpis);
|
|
9483
|
+
} else {
|
|
9484
|
+
setKPIs(null);
|
|
9485
|
+
}
|
|
9171
9486
|
}
|
|
9172
9487
|
} catch (err) {
|
|
9173
9488
|
console.error("[useLineKPIs] Error fetching KPIs:", err);
|
|
@@ -9178,7 +9493,80 @@ var useLineKPIs = ({ lineId, enabled }) => {
|
|
|
9178
9493
|
isFetchingRef.current = false;
|
|
9179
9494
|
updateQueueRef.current = false;
|
|
9180
9495
|
}
|
|
9181
|
-
}, [timezone, shiftConfig, entityConfig, supabase, enabled, isShiftConfigLoading]);
|
|
9496
|
+
}, [timezone, shiftConfig, shiftGroups, configuredLineIds, staticShiftConfig, entityConfig, supabase, enabled, isShiftConfigLoading]);
|
|
9497
|
+
const aggregateKPIResults = (results) => {
|
|
9498
|
+
const validResults = results.filter((r2) => r2?.kpis);
|
|
9499
|
+
if (validResults.length === 0) return null;
|
|
9500
|
+
if (validResults.length === 1) return validResults[0].kpis;
|
|
9501
|
+
let totalEfficiency = 0;
|
|
9502
|
+
let totalEfficiencyWeight = 0;
|
|
9503
|
+
let totalOutputCurrent = 0;
|
|
9504
|
+
let totalOutputTarget = 0;
|
|
9505
|
+
let totalIdealOutput = 0;
|
|
9506
|
+
let totalUnderperformingCurrent = 0;
|
|
9507
|
+
let totalUnderperformingTotal = 0;
|
|
9508
|
+
let totalCycleTimeSum = 0;
|
|
9509
|
+
let totalCycleTimeCount = 0;
|
|
9510
|
+
let totalQualitySum = 0;
|
|
9511
|
+
let totalQualityCount = 0;
|
|
9512
|
+
validResults.forEach((result) => {
|
|
9513
|
+
const kpis2 = result.kpis;
|
|
9514
|
+
if (kpis2.efficiency?.value !== void 0) {
|
|
9515
|
+
const weight = kpis2.outputProgress?.current || 1;
|
|
9516
|
+
totalEfficiency += kpis2.efficiency.value * weight;
|
|
9517
|
+
totalEfficiencyWeight += weight;
|
|
9518
|
+
}
|
|
9519
|
+
if (kpis2.outputProgress) {
|
|
9520
|
+
totalOutputCurrent += kpis2.outputProgress.current || 0;
|
|
9521
|
+
totalOutputTarget += kpis2.outputProgress.target || 0;
|
|
9522
|
+
totalIdealOutput += kpis2.outputProgress.idealOutput || 0;
|
|
9523
|
+
}
|
|
9524
|
+
if (kpis2.underperformingWorkers) {
|
|
9525
|
+
totalUnderperformingCurrent += kpis2.underperformingWorkers.current || 0;
|
|
9526
|
+
totalUnderperformingTotal += kpis2.underperformingWorkers.total || 0;
|
|
9527
|
+
}
|
|
9528
|
+
if (kpis2.avgCycleTime?.value !== void 0) {
|
|
9529
|
+
totalCycleTimeSum += kpis2.avgCycleTime.value;
|
|
9530
|
+
totalCycleTimeCount++;
|
|
9531
|
+
}
|
|
9532
|
+
if (kpis2.qualityCompliance?.value !== void 0) {
|
|
9533
|
+
totalQualitySum += kpis2.qualityCompliance.value;
|
|
9534
|
+
totalQualityCount++;
|
|
9535
|
+
}
|
|
9536
|
+
});
|
|
9537
|
+
const aggregated = {
|
|
9538
|
+
efficiency: {
|
|
9539
|
+
value: totalEfficiencyWeight > 0 ? totalEfficiency / totalEfficiencyWeight : 0,
|
|
9540
|
+
change: 0
|
|
9541
|
+
// Change not meaningful when aggregating across shifts
|
|
9542
|
+
},
|
|
9543
|
+
outputProgress: {
|
|
9544
|
+
current: totalOutputCurrent,
|
|
9545
|
+
target: totalOutputTarget,
|
|
9546
|
+
change: 0,
|
|
9547
|
+
// Change not meaningful when aggregating across shifts
|
|
9548
|
+
idealOutput: totalIdealOutput
|
|
9549
|
+
},
|
|
9550
|
+
underperformingWorkers: {
|
|
9551
|
+
current: totalUnderperformingCurrent,
|
|
9552
|
+
total: totalUnderperformingTotal,
|
|
9553
|
+
change: 0
|
|
9554
|
+
// Change not meaningful when aggregating across shifts
|
|
9555
|
+
},
|
|
9556
|
+
avgCycleTime: {
|
|
9557
|
+
value: totalCycleTimeCount > 0 ? totalCycleTimeSum / totalCycleTimeCount : 0,
|
|
9558
|
+
change: 0
|
|
9559
|
+
// Change not meaningful when aggregating across shifts
|
|
9560
|
+
},
|
|
9561
|
+
qualityCompliance: {
|
|
9562
|
+
value: totalQualityCount > 0 ? totalQualitySum / totalQualityCount : 0,
|
|
9563
|
+
change: 0
|
|
9564
|
+
// Change not meaningful when aggregating across shifts
|
|
9565
|
+
}
|
|
9566
|
+
};
|
|
9567
|
+
console.log("[useLineKPIs] \u{1F4CA} Aggregated KPIs from", validResults.length, "shift groups:", aggregated);
|
|
9568
|
+
return aggregated;
|
|
9569
|
+
};
|
|
9182
9570
|
const queueUpdate = useCallback(() => {
|
|
9183
9571
|
if (updateTimeoutRef.current) {
|
|
9184
9572
|
clearTimeout(updateTimeoutRef.current);
|
|
@@ -9198,40 +9586,66 @@ var useLineKPIs = ({ lineId, enabled }) => {
|
|
|
9198
9586
|
return;
|
|
9199
9587
|
}
|
|
9200
9588
|
fetchKPIs();
|
|
9201
|
-
const currentShiftDetails = getCurrentShift(timezone, shiftConfig ?? void 0);
|
|
9202
|
-
const operationalDate = currentShiftDetails.date;
|
|
9203
9589
|
const factoryViewIdentifier = entityConfig.factoryViewId || "factory";
|
|
9204
|
-
const
|
|
9205
|
-
if (targetLineIds.length === 0) {
|
|
9206
|
-
console.warn("[useLineKPIs] No target line IDs for subscription. LineId:", currentLineId);
|
|
9207
|
-
return;
|
|
9208
|
-
}
|
|
9209
|
-
const baseFilterParts = `date=eq.${operationalDate},shift_id=eq.${currentShiftDetails.shiftId}`;
|
|
9210
|
-
const lineIdFilterPart = `line_id=in.(${targetLineIds.join(",")})`;
|
|
9211
|
-
const lineMetricsFilter = `${baseFilterParts},${lineIdFilterPart}`;
|
|
9212
|
-
const companyTableFilter = `${baseFilterParts},${lineIdFilterPart}`;
|
|
9590
|
+
const isFactory = currentLineId === factoryViewIdentifier;
|
|
9213
9591
|
const activeChannels = [];
|
|
9214
|
-
|
|
9215
|
-
|
|
9216
|
-
|
|
9217
|
-
|
|
9218
|
-
|
|
9219
|
-
const
|
|
9220
|
-
|
|
9221
|
-
|
|
9592
|
+
if (isFactory && shiftGroups.length > 0) {
|
|
9593
|
+
console.log(`[useLineKPIs] \u{1F4E1} Setting up subscriptions for ${shiftGroups.length} shift group(s)`);
|
|
9594
|
+
shiftGroups.forEach((group, index) => {
|
|
9595
|
+
const baseFilterParts = `date=eq.${group.date},shift_id=eq.${group.shiftId}`;
|
|
9596
|
+
const lineIdFilterPart = `line_id=in.(${group.lineIds.join(",")})`;
|
|
9597
|
+
const filter2 = `${baseFilterParts},${lineIdFilterPart}`;
|
|
9598
|
+
const lmChannelName = `kpi-lm-factory-g${index}-${group.date}-${group.shiftId}`.replace(/[^a-zA-Z0-9_-]/g, "");
|
|
9599
|
+
const lmChannel = supabase.channel(lmChannelName).on(
|
|
9600
|
+
"postgres_changes",
|
|
9601
|
+
{ event: "*", schema, table: lineMetricsTable, filter: filter2 },
|
|
9602
|
+
(payload) => {
|
|
9603
|
+
const payloadData = payload.new || payload.old;
|
|
9604
|
+
if (payloadData?.date === group.date && payloadData?.shift_id === group.shiftId) {
|
|
9605
|
+
queueUpdateRef.current?.();
|
|
9606
|
+
}
|
|
9607
|
+
}
|
|
9608
|
+
).subscribe((status, err) => {
|
|
9609
|
+
if (status === REALTIME_SUBSCRIBE_STATES.CHANNEL_ERROR || status === REALTIME_SUBSCRIBE_STATES.TIMED_OUT) {
|
|
9610
|
+
console.error(`[useLineKPIs] Subscription to ${lineMetricsTable} (group ${index}) FAILED:`, status, err);
|
|
9611
|
+
}
|
|
9612
|
+
});
|
|
9613
|
+
activeChannels.push(lmChannel);
|
|
9614
|
+
if (companySpecificMetricsTable && !companySpecificMetricsTable.includes("unknown_company")) {
|
|
9615
|
+
const csChannelName = `kpi-cs-factory-g${index}-${group.date}-${group.shiftId}`.replace(/[^a-zA-Z0-9_-]/g, "");
|
|
9616
|
+
const csChannel = supabase.channel(csChannelName).on(
|
|
9617
|
+
"postgres_changes",
|
|
9618
|
+
{ event: "*", schema, table: companySpecificMetricsTable, filter: filter2 },
|
|
9619
|
+
(payload) => {
|
|
9620
|
+
const payloadData = payload.new || payload.old;
|
|
9621
|
+
if (payloadData?.date === group.date && payloadData?.shift_id === group.shiftId) {
|
|
9622
|
+
queueUpdateRef.current?.();
|
|
9623
|
+
}
|
|
9624
|
+
}
|
|
9625
|
+
).subscribe((status, err) => {
|
|
9626
|
+
if (status === REALTIME_SUBSCRIBE_STATES.CHANNEL_ERROR || status === REALTIME_SUBSCRIBE_STATES.TIMED_OUT) {
|
|
9627
|
+
console.error(`[useLineKPIs] Subscription to ${companySpecificMetricsTable} (group ${index}) FAILED:`, status, err);
|
|
9628
|
+
}
|
|
9629
|
+
});
|
|
9630
|
+
activeChannels.push(csChannel);
|
|
9222
9631
|
}
|
|
9632
|
+
});
|
|
9633
|
+
} else {
|
|
9634
|
+
const currentShiftDetails = shiftConfig ? getCurrentShift(timezone, shiftConfig) : getCurrentShift(timezone, staticShiftConfig);
|
|
9635
|
+
const operationalDate = currentShiftDetails.date;
|
|
9636
|
+
const targetLineIds = [currentLineId];
|
|
9637
|
+
if (targetLineIds.length === 0) {
|
|
9638
|
+
console.warn("[useLineKPIs] No target line IDs for subscription. LineId:", currentLineId);
|
|
9639
|
+
return;
|
|
9223
9640
|
}
|
|
9224
|
-
|
|
9225
|
-
|
|
9226
|
-
|
|
9227
|
-
}
|
|
9228
|
-
|
|
9229
|
-
|
|
9230
|
-
if (companySpecificMetricsTable && !companySpecificMetricsTable.includes("unknown_company")) {
|
|
9231
|
-
const csChannelName = `kpi-cs-${currentLineId}-${operationalDate}-${currentShiftDetails.shiftId}`.replace(/[^a-zA-Z0-9_-]/g, "");
|
|
9232
|
-
const csChannel = supabase.channel(csChannelName).on(
|
|
9641
|
+
const baseFilterParts = `date=eq.${operationalDate},shift_id=eq.${currentShiftDetails.shiftId}`;
|
|
9642
|
+
const lineIdFilterPart = `line_id=in.(${targetLineIds.join(",")})`;
|
|
9643
|
+
const lineMetricsFilter = `${baseFilterParts},${lineIdFilterPart}`;
|
|
9644
|
+
const companyTableFilter = `${baseFilterParts},${lineIdFilterPart}`;
|
|
9645
|
+
const lmChannelName = `kpi-lm-${currentLineId}-${operationalDate}-${currentShiftDetails.shiftId}`.replace(/[^a-zA-Z0-9_-]/g, "");
|
|
9646
|
+
const lmChannel = supabase.channel(lmChannelName).on(
|
|
9233
9647
|
"postgres_changes",
|
|
9234
|
-
{ event: "*", schema, table:
|
|
9648
|
+
{ event: "*", schema, table: lineMetricsTable, filter: lineMetricsFilter },
|
|
9235
9649
|
(payload) => {
|
|
9236
9650
|
const payloadData = payload.new || payload.old;
|
|
9237
9651
|
if (payloadData?.date === operationalDate && payloadData?.shift_id === currentShiftDetails.shiftId) {
|
|
@@ -9240,10 +9654,28 @@ var useLineKPIs = ({ lineId, enabled }) => {
|
|
|
9240
9654
|
}
|
|
9241
9655
|
).subscribe((status, err) => {
|
|
9242
9656
|
if (status === REALTIME_SUBSCRIBE_STATES.CHANNEL_ERROR || status === REALTIME_SUBSCRIBE_STATES.TIMED_OUT) {
|
|
9243
|
-
console.error(`[useLineKPIs] Subscription to ${
|
|
9657
|
+
console.error(`[useLineKPIs] Subscription to ${lineMetricsTable} FAILED: ${status}`, err || "");
|
|
9244
9658
|
}
|
|
9245
9659
|
});
|
|
9246
|
-
activeChannels.push(
|
|
9660
|
+
activeChannels.push(lmChannel);
|
|
9661
|
+
if (companySpecificMetricsTable && !companySpecificMetricsTable.includes("unknown_company")) {
|
|
9662
|
+
const csChannelName = `kpi-cs-${currentLineId}-${operationalDate}-${currentShiftDetails.shiftId}`.replace(/[^a-zA-Z0-9_-]/g, "");
|
|
9663
|
+
const csChannel = supabase.channel(csChannelName).on(
|
|
9664
|
+
"postgres_changes",
|
|
9665
|
+
{ event: "*", schema, table: companySpecificMetricsTable, filter: companyTableFilter },
|
|
9666
|
+
(payload) => {
|
|
9667
|
+
const payloadData = payload.new || payload.old;
|
|
9668
|
+
if (payloadData?.date === operationalDate && payloadData?.shift_id === currentShiftDetails.shiftId) {
|
|
9669
|
+
queueUpdateRef.current?.();
|
|
9670
|
+
}
|
|
9671
|
+
}
|
|
9672
|
+
).subscribe((status, err) => {
|
|
9673
|
+
if (status === REALTIME_SUBSCRIBE_STATES.CHANNEL_ERROR || status === REALTIME_SUBSCRIBE_STATES.TIMED_OUT) {
|
|
9674
|
+
console.error(`[useLineKPIs] Subscription to ${companySpecificMetricsTable} FAILED: ${status}`, err || "");
|
|
9675
|
+
}
|
|
9676
|
+
});
|
|
9677
|
+
activeChannels.push(csChannel);
|
|
9678
|
+
}
|
|
9247
9679
|
}
|
|
9248
9680
|
return () => {
|
|
9249
9681
|
activeChannels.forEach((ch) => supabase.removeChannel(ch).catch((err) => console.error("[useLineKPIs] Error removing KPI channel:", err)));
|
|
@@ -9251,7 +9683,7 @@ var useLineKPIs = ({ lineId, enabled }) => {
|
|
|
9251
9683
|
clearTimeout(updateTimeoutRef.current);
|
|
9252
9684
|
}
|
|
9253
9685
|
};
|
|
9254
|
-
}, [lineId, supabase, entityConfig, schema, lineMetricsTable, companySpecificMetricsTable, timezone, shiftConfig, isShiftConfigLoading]);
|
|
9686
|
+
}, [lineId, supabase, entityConfig, schema, lineMetricsTable, companySpecificMetricsTable, timezone, shiftConfig, staticShiftConfig, shiftGroups, isShiftConfigLoading]);
|
|
9255
9687
|
return {
|
|
9256
9688
|
kpis,
|
|
9257
9689
|
isLoading,
|
|
@@ -10924,10 +11356,26 @@ var useAllWorkspaceMetrics = (options) => {
|
|
|
10924
11356
|
const dateTimeConfig = useDateTimeConfig();
|
|
10925
11357
|
const staticShiftConfig = useShiftConfig();
|
|
10926
11358
|
const timezone = useAppTimezone();
|
|
10927
|
-
const configuredLineIds = useMemo(() =>
|
|
10928
|
-
|
|
10929
|
-
|
|
10930
|
-
|
|
11359
|
+
const configuredLineIds = useMemo(() => {
|
|
11360
|
+
const allLineIds = getConfiguredLineIds(entityConfig);
|
|
11361
|
+
if (options?.allowedLineIds) {
|
|
11362
|
+
return allLineIds.filter((id3) => options.allowedLineIds.includes(id3));
|
|
11363
|
+
}
|
|
11364
|
+
return allLineIds;
|
|
11365
|
+
}, [entityConfig, options?.allowedLineIds]);
|
|
11366
|
+
const {
|
|
11367
|
+
shiftConfigMap: multiLineShiftConfigMap,
|
|
11368
|
+
isLoading: isShiftConfigLoading
|
|
11369
|
+
} = useMultiLineShiftConfigs(configuredLineIds, staticShiftConfig);
|
|
11370
|
+
const shiftGroups = useMemo(() => {
|
|
11371
|
+
if (isShiftConfigLoading || multiLineShiftConfigMap.size === 0) return [];
|
|
11372
|
+
return groupLinesByShift(multiLineShiftConfigMap, timezone || dateTimeConfig.defaultTimezone || "Asia/Kolkata");
|
|
11373
|
+
}, [isShiftConfigLoading, multiLineShiftConfigMap, timezone, dateTimeConfig.defaultTimezone]);
|
|
11374
|
+
console.log(`[useAllWorkspaceMetrics] \u{1F4CA} Shift groups:`, shiftGroups.map((g) => ({
|
|
11375
|
+
shiftId: g.shiftId,
|
|
11376
|
+
date: g.date,
|
|
11377
|
+
lineIds: g.lineIds
|
|
11378
|
+
})));
|
|
10931
11379
|
const supabase = useSupabase();
|
|
10932
11380
|
const [workspaces, setWorkspaces] = useState([]);
|
|
10933
11381
|
const [loading, setLoading] = useState(true);
|
|
@@ -10935,19 +11383,29 @@ var useAllWorkspaceMetrics = (options) => {
|
|
|
10935
11383
|
const [initialized, setInitialized] = useState(false);
|
|
10936
11384
|
const fetchTimeoutRef = useRef(null);
|
|
10937
11385
|
const isFetchingRef = useRef(false);
|
|
10938
|
-
const
|
|
11386
|
+
const hasSpecificDateShift = options?.initialDate !== void 0 || options?.initialShiftId !== void 0;
|
|
11387
|
+
const fallbackQueryShiftId = useMemo(() => {
|
|
10939
11388
|
if (options?.initialShiftId !== void 0) {
|
|
10940
11389
|
return options.initialShiftId;
|
|
10941
11390
|
}
|
|
11391
|
+
if (shiftGroups.length > 0) {
|
|
11392
|
+
return shiftGroups[0].shiftId;
|
|
11393
|
+
}
|
|
10942
11394
|
const currentShift = getCurrentShift(
|
|
10943
11395
|
timezone || dateTimeConfig.defaultTimezone || "Asia/Kolkata",
|
|
10944
|
-
|
|
11396
|
+
staticShiftConfig
|
|
10945
11397
|
);
|
|
10946
11398
|
return currentShift.shiftId;
|
|
10947
|
-
}, [options?.initialShiftId, timezone, dateTimeConfig.defaultTimezone,
|
|
10948
|
-
const
|
|
10949
|
-
|
|
10950
|
-
|
|
11399
|
+
}, [options?.initialShiftId, shiftGroups, timezone, dateTimeConfig.defaultTimezone, staticShiftConfig]);
|
|
11400
|
+
const fallbackQueryDate = useMemo(() => {
|
|
11401
|
+
if (options?.initialDate) {
|
|
11402
|
+
return options.initialDate;
|
|
11403
|
+
}
|
|
11404
|
+
if (shiftGroups.length > 0) {
|
|
11405
|
+
return shiftGroups[0].date;
|
|
11406
|
+
}
|
|
11407
|
+
return getOperationalDate(timezone || dateTimeConfig.defaultTimezone || "UTC");
|
|
11408
|
+
}, [options?.initialDate, shiftGroups, timezone, dateTimeConfig.defaultTimezone]);
|
|
10951
11409
|
const metricsTable = useMemo(() => {
|
|
10952
11410
|
const companyId = entityConfig.companyId;
|
|
10953
11411
|
if (!companyId) return "";
|
|
@@ -10965,49 +11423,99 @@ var useAllWorkspaceMetrics = (options) => {
|
|
|
10965
11423
|
}
|
|
10966
11424
|
setError(null);
|
|
10967
11425
|
try {
|
|
10968
|
-
const
|
|
10969
|
-
|
|
10970
|
-
|
|
10971
|
-
|
|
10972
|
-
const
|
|
10973
|
-
|
|
10974
|
-
|
|
10975
|
-
}
|
|
10976
|
-
if (
|
|
11426
|
+
const lineWorkspaceMap = /* @__PURE__ */ new Map();
|
|
11427
|
+
let allEnabledWorkspaceIds = [];
|
|
11428
|
+
for (const lineId of configuredLineIds) {
|
|
11429
|
+
const lineWorkspaces = await workspaceService.getWorkspaces(lineId);
|
|
11430
|
+
const enabledIds = lineWorkspaces.filter((ws) => ws.enable === true).map((ws) => ws.id);
|
|
11431
|
+
lineWorkspaceMap.set(lineId, enabledIds);
|
|
11432
|
+
allEnabledWorkspaceIds.push(...enabledIds);
|
|
11433
|
+
}
|
|
11434
|
+
if (allEnabledWorkspaceIds.length === 0) {
|
|
10977
11435
|
setWorkspaces([]);
|
|
10978
11436
|
setInitialized(true);
|
|
10979
11437
|
setLoading(false);
|
|
10980
11438
|
return;
|
|
10981
11439
|
}
|
|
10982
|
-
|
|
10983
|
-
|
|
10984
|
-
|
|
10985
|
-
|
|
10986
|
-
|
|
10987
|
-
|
|
10988
|
-
|
|
10989
|
-
|
|
10990
|
-
|
|
10991
|
-
|
|
10992
|
-
|
|
10993
|
-
|
|
10994
|
-
|
|
10995
|
-
|
|
10996
|
-
|
|
10997
|
-
|
|
10998
|
-
|
|
10999
|
-
|
|
11000
|
-
|
|
11001
|
-
|
|
11002
|
-
|
|
11003
|
-
|
|
11004
|
-
|
|
11005
|
-
|
|
11006
|
-
|
|
11007
|
-
|
|
11008
|
-
|
|
11009
|
-
|
|
11010
|
-
|
|
11440
|
+
let transformedData = [];
|
|
11441
|
+
if (hasSpecificDateShift) {
|
|
11442
|
+
console.log(`[useAllWorkspaceMetrics] \u{1F4CA} Using specific date/shift: ${fallbackQueryDate} / ${fallbackQueryShiftId}`);
|
|
11443
|
+
const { data, error: fetchError } = await supabase.from(metricsTable).select(`
|
|
11444
|
+
workspace_name,
|
|
11445
|
+
total_output,
|
|
11446
|
+
avg_pph,
|
|
11447
|
+
efficiency,
|
|
11448
|
+
workspace_id,
|
|
11449
|
+
avg_cycle_time,
|
|
11450
|
+
performance_score,
|
|
11451
|
+
trend_score,
|
|
11452
|
+
line_id,
|
|
11453
|
+
total_day_output
|
|
11454
|
+
`).eq("date", fallbackQueryDate).eq("shift_id", fallbackQueryShiftId).in("workspace_id", allEnabledWorkspaceIds).order("efficiency", { ascending: false });
|
|
11455
|
+
if (fetchError) throw fetchError;
|
|
11456
|
+
transformedData = (data || []).map((item) => ({
|
|
11457
|
+
company_id: entityConfig.companyId || "unknown",
|
|
11458
|
+
line_id: item.line_id,
|
|
11459
|
+
shift_id: fallbackQueryShiftId,
|
|
11460
|
+
date: fallbackQueryDate,
|
|
11461
|
+
workspace_uuid: item.workspace_id,
|
|
11462
|
+
workspace_name: item.workspace_name,
|
|
11463
|
+
action_count: item.total_output || 0,
|
|
11464
|
+
pph: item.avg_pph || 0,
|
|
11465
|
+
performance_score: item.performance_score || 0,
|
|
11466
|
+
avg_cycle_time: item.avg_cycle_time || 0,
|
|
11467
|
+
trend: item.trend_score === 1 ? 2 : 0,
|
|
11468
|
+
predicted_output: 0,
|
|
11469
|
+
efficiency: item.efficiency || 0,
|
|
11470
|
+
action_threshold: item.total_day_output || 0
|
|
11471
|
+
}));
|
|
11472
|
+
} else if (shiftGroups.length > 0) {
|
|
11473
|
+
console.log(`[useAllWorkspaceMetrics] \u{1F3ED} Fetching per-shift: ${shiftGroups.length} group(s)`);
|
|
11474
|
+
const queryPromises = shiftGroups.map(async (group) => {
|
|
11475
|
+
const groupWorkspaceIds = group.lineIds.flatMap(
|
|
11476
|
+
(lineId) => lineWorkspaceMap.get(lineId) || []
|
|
11477
|
+
);
|
|
11478
|
+
if (groupWorkspaceIds.length === 0) {
|
|
11479
|
+
return [];
|
|
11480
|
+
}
|
|
11481
|
+
console.log(`[useAllWorkspaceMetrics] \u{1F4CA} Fetching shift ${group.shiftId} (${group.shiftName}):`, {
|
|
11482
|
+
lineIds: group.lineIds,
|
|
11483
|
+
date: group.date,
|
|
11484
|
+
workspaceCount: groupWorkspaceIds.length
|
|
11485
|
+
});
|
|
11486
|
+
const { data, error: fetchError } = await supabase.from(metricsTable).select(`
|
|
11487
|
+
workspace_name,
|
|
11488
|
+
total_output,
|
|
11489
|
+
avg_pph,
|
|
11490
|
+
efficiency,
|
|
11491
|
+
workspace_id,
|
|
11492
|
+
avg_cycle_time,
|
|
11493
|
+
performance_score,
|
|
11494
|
+
trend_score,
|
|
11495
|
+
line_id,
|
|
11496
|
+
total_day_output
|
|
11497
|
+
`).eq("date", group.date).eq("shift_id", group.shiftId).in("workspace_id", groupWorkspaceIds);
|
|
11498
|
+
if (fetchError) throw fetchError;
|
|
11499
|
+
return (data || []).map((item) => ({
|
|
11500
|
+
company_id: entityConfig.companyId || "unknown",
|
|
11501
|
+
line_id: item.line_id,
|
|
11502
|
+
shift_id: group.shiftId,
|
|
11503
|
+
date: group.date,
|
|
11504
|
+
workspace_uuid: item.workspace_id,
|
|
11505
|
+
workspace_name: item.workspace_name,
|
|
11506
|
+
action_count: item.total_output || 0,
|
|
11507
|
+
pph: item.avg_pph || 0,
|
|
11508
|
+
performance_score: item.performance_score || 0,
|
|
11509
|
+
avg_cycle_time: item.avg_cycle_time || 0,
|
|
11510
|
+
trend: item.trend_score === 1 ? 2 : 0,
|
|
11511
|
+
predicted_output: 0,
|
|
11512
|
+
efficiency: item.efficiency || 0,
|
|
11513
|
+
action_threshold: item.total_day_output || 0
|
|
11514
|
+
}));
|
|
11515
|
+
});
|
|
11516
|
+
const results = await Promise.all(queryPromises);
|
|
11517
|
+
transformedData = results.flat().sort((a, b) => (b.efficiency || 0) - (a.efficiency || 0));
|
|
11518
|
+
}
|
|
11011
11519
|
setWorkspaces((prevWorkspaces) => {
|
|
11012
11520
|
if (prevWorkspaces.length !== transformedData.length) {
|
|
11013
11521
|
return transformedData;
|
|
@@ -11029,11 +11537,19 @@ var useAllWorkspaceMetrics = (options) => {
|
|
|
11029
11537
|
setLoading(false);
|
|
11030
11538
|
isFetchingRef.current = false;
|
|
11031
11539
|
}
|
|
11032
|
-
}, [
|
|
11540
|
+
}, [fallbackQueryDate, fallbackQueryShiftId, hasSpecificDateShift, shiftGroups, metricsTable, supabase, entityConfig.companyId, configuredLineIds, options?.enabled, isShiftConfigLoading]);
|
|
11033
11541
|
useEffect(() => {
|
|
11034
11542
|
if (!initialized) {
|
|
11035
11543
|
fetchWorkspaceMetrics();
|
|
11036
11544
|
}
|
|
11545
|
+
const validDateShiftCombos = /* @__PURE__ */ new Set();
|
|
11546
|
+
if (hasSpecificDateShift) {
|
|
11547
|
+
validDateShiftCombos.add(`${fallbackQueryDate}-${fallbackQueryShiftId}`);
|
|
11548
|
+
} else {
|
|
11549
|
+
shiftGroups.forEach((group) => {
|
|
11550
|
+
validDateShiftCombos.add(`${group.date}-${group.shiftId}`);
|
|
11551
|
+
});
|
|
11552
|
+
}
|
|
11037
11553
|
const setupSubscription = () => {
|
|
11038
11554
|
const channel2 = supabase.channel(`all-workspace-metrics-${Date.now()}`).on(
|
|
11039
11555
|
"postgres_changes",
|
|
@@ -11044,7 +11560,8 @@ var useAllWorkspaceMetrics = (options) => {
|
|
|
11044
11560
|
},
|
|
11045
11561
|
async (payload) => {
|
|
11046
11562
|
const data = payload.new || payload.old;
|
|
11047
|
-
|
|
11563
|
+
const dataKey = `${data?.date}-${data?.shift_id}`;
|
|
11564
|
+
if (!validDateShiftCombos.has(dataKey)) {
|
|
11048
11565
|
return;
|
|
11049
11566
|
}
|
|
11050
11567
|
if (fetchTimeoutRef.current) {
|
|
@@ -11070,10 +11587,10 @@ var useAllWorkspaceMetrics = (options) => {
|
|
|
11070
11587
|
supabase.removeChannel(channel);
|
|
11071
11588
|
}
|
|
11072
11589
|
};
|
|
11073
|
-
}, [
|
|
11590
|
+
}, [fallbackQueryDate, fallbackQueryShiftId, hasSpecificDateShift, shiftGroups, metricsTable, fetchWorkspaceMetrics, initialized, supabase, schema, entityConfig.companyId]);
|
|
11074
11591
|
useEffect(() => {
|
|
11075
11592
|
setInitialized(false);
|
|
11076
|
-
}, [
|
|
11593
|
+
}, [fallbackQueryDate, fallbackQueryShiftId, shiftGroups]);
|
|
11077
11594
|
const refreshWorkspaces = useCallback(() => fetchWorkspaceMetrics(), [fetchWorkspaceMetrics]);
|
|
11078
11595
|
return useMemo(
|
|
11079
11596
|
() => ({ workspaces, loading, error, refreshWorkspaces }),
|
|
@@ -11562,127 +12079,6 @@ function useClipTypesWithCounts(workspaceId, date, shiftId, totalOutput, options
|
|
|
11562
12079
|
counts
|
|
11563
12080
|
};
|
|
11564
12081
|
}
|
|
11565
|
-
var useMultiLineShiftConfigs = (lineIds, fallbackConfig) => {
|
|
11566
|
-
const [shiftConfigMap, setShiftConfigMap] = useState(/* @__PURE__ */ new Map());
|
|
11567
|
-
const [isLoading, setIsLoading] = useState(true);
|
|
11568
|
-
const [error, setError] = useState(null);
|
|
11569
|
-
const supabase = useSupabase();
|
|
11570
|
-
const lineIdsKey = useMemo(() => lineIds.sort().join(","), [lineIds]);
|
|
11571
|
-
useEffect(() => {
|
|
11572
|
-
if (!lineIds || lineIds.length === 0) {
|
|
11573
|
-
setShiftConfigMap(/* @__PURE__ */ new Map());
|
|
11574
|
-
setIsLoading(false);
|
|
11575
|
-
return;
|
|
11576
|
-
}
|
|
11577
|
-
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
11578
|
-
const validLineIds = lineIds.filter((id3) => uuidRegex.test(id3));
|
|
11579
|
-
if (validLineIds.length === 0) {
|
|
11580
|
-
console.warn("[useMultiLineShiftConfigs] No valid line IDs provided");
|
|
11581
|
-
setShiftConfigMap(/* @__PURE__ */ new Map());
|
|
11582
|
-
setIsLoading(false);
|
|
11583
|
-
return;
|
|
11584
|
-
}
|
|
11585
|
-
let mounted = true;
|
|
11586
|
-
const calculateBreakDuration2 = (startTime, endTime) => {
|
|
11587
|
-
const [sh, sm] = startTime.split(":").map(Number);
|
|
11588
|
-
const [eh, em] = endTime.split(":").map(Number);
|
|
11589
|
-
let startMinutes = sh * 60 + sm;
|
|
11590
|
-
let endMinutes = eh * 60 + em;
|
|
11591
|
-
if (endMinutes < startMinutes) {
|
|
11592
|
-
endMinutes += 24 * 60;
|
|
11593
|
-
}
|
|
11594
|
-
return endMinutes - startMinutes;
|
|
11595
|
-
};
|
|
11596
|
-
const stripSeconds = (timeStr) => {
|
|
11597
|
-
if (!timeStr) return timeStr;
|
|
11598
|
-
return timeStr.substring(0, 5);
|
|
11599
|
-
};
|
|
11600
|
-
const buildShiftConfigFromRows = (shifts, fallback) => {
|
|
11601
|
-
const mapped = shifts.map((shift) => ({
|
|
11602
|
-
shiftId: shift.shift_id,
|
|
11603
|
-
shiftName: shift.shift_name || `Shift ${shift.shift_id}`,
|
|
11604
|
-
startTime: stripSeconds(shift.start_time),
|
|
11605
|
-
endTime: stripSeconds(shift.end_time),
|
|
11606
|
-
breaks: Array.isArray(shift.breaks) ? shift.breaks.map((b) => ({
|
|
11607
|
-
startTime: b.start || b.startTime || "00:00",
|
|
11608
|
-
endTime: b.end || b.endTime || "00:00",
|
|
11609
|
-
duration: calculateBreakDuration2(
|
|
11610
|
-
b.start || b.startTime || "00:00",
|
|
11611
|
-
b.end || b.endTime || "00:00"
|
|
11612
|
-
),
|
|
11613
|
-
remarks: b.remarks || b.name || ""
|
|
11614
|
-
})) : [],
|
|
11615
|
-
timezone: shift.timezone
|
|
11616
|
-
}));
|
|
11617
|
-
const day = mapped.find((s) => s.shiftId === 0);
|
|
11618
|
-
const night = mapped.find((s) => s.shiftId === 1);
|
|
11619
|
-
return {
|
|
11620
|
-
shifts: mapped,
|
|
11621
|
-
timezone: mapped[0]?.timezone,
|
|
11622
|
-
dayShift: day ? { id: day.shiftId, startTime: day.startTime, endTime: day.endTime, name: day.shiftName } : fallback?.dayShift,
|
|
11623
|
-
nightShift: night ? { id: night.shiftId, startTime: night.startTime, endTime: night.endTime, name: night.shiftName } : fallback?.nightShift,
|
|
11624
|
-
transitionPeriodMinutes: fallback?.transitionPeriodMinutes || 0
|
|
11625
|
-
};
|
|
11626
|
-
};
|
|
11627
|
-
const fetchAllConfigs = async () => {
|
|
11628
|
-
try {
|
|
11629
|
-
setIsLoading(true);
|
|
11630
|
-
setError(null);
|
|
11631
|
-
console.log(`[useMultiLineShiftConfigs] Fetching shift configs for ${validLineIds.length} lines`);
|
|
11632
|
-
const { data, error: fetchError } = await supabase.from("line_operating_hours").select("line_id, shift_id, shift_name, start_time, end_time, breaks, timezone").in("line_id", validLineIds);
|
|
11633
|
-
if (fetchError) {
|
|
11634
|
-
console.error("[useMultiLineShiftConfigs] Error fetching shift configs:", fetchError);
|
|
11635
|
-
throw new Error(`Failed to fetch shift configs: ${fetchError.message}`);
|
|
11636
|
-
}
|
|
11637
|
-
const lineShiftsMap = /* @__PURE__ */ new Map();
|
|
11638
|
-
data?.forEach((row) => {
|
|
11639
|
-
if (!lineShiftsMap.has(row.line_id)) {
|
|
11640
|
-
lineShiftsMap.set(row.line_id, []);
|
|
11641
|
-
}
|
|
11642
|
-
lineShiftsMap.get(row.line_id).push(row);
|
|
11643
|
-
});
|
|
11644
|
-
const configMap = /* @__PURE__ */ new Map();
|
|
11645
|
-
lineShiftsMap.forEach((shifts, lineId) => {
|
|
11646
|
-
const config = buildShiftConfigFromRows(shifts, fallbackConfig);
|
|
11647
|
-
configMap.set(lineId, config);
|
|
11648
|
-
});
|
|
11649
|
-
validLineIds.forEach((lineId) => {
|
|
11650
|
-
if (!configMap.has(lineId) && fallbackConfig) {
|
|
11651
|
-
console.warn(`[useMultiLineShiftConfigs] No config found for line ${lineId}, using fallback`);
|
|
11652
|
-
configMap.set(lineId, fallbackConfig);
|
|
11653
|
-
}
|
|
11654
|
-
});
|
|
11655
|
-
console.log(`[useMultiLineShiftConfigs] Built configs for ${configMap.size} lines`);
|
|
11656
|
-
if (mounted) {
|
|
11657
|
-
setShiftConfigMap(configMap);
|
|
11658
|
-
setIsLoading(false);
|
|
11659
|
-
}
|
|
11660
|
-
} catch (err) {
|
|
11661
|
-
console.error("[useMultiLineShiftConfigs] Error:", err);
|
|
11662
|
-
if (mounted) {
|
|
11663
|
-
setError(err instanceof Error ? err.message : "Failed to fetch shift configs");
|
|
11664
|
-
if (fallbackConfig) {
|
|
11665
|
-
const fallbackMap = /* @__PURE__ */ new Map();
|
|
11666
|
-
validLineIds.forEach((lineId) => {
|
|
11667
|
-
fallbackMap.set(lineId, fallbackConfig);
|
|
11668
|
-
});
|
|
11669
|
-
setShiftConfigMap(fallbackMap);
|
|
11670
|
-
}
|
|
11671
|
-
setIsLoading(false);
|
|
11672
|
-
}
|
|
11673
|
-
}
|
|
11674
|
-
};
|
|
11675
|
-
fetchAllConfigs();
|
|
11676
|
-
return () => {
|
|
11677
|
-
mounted = false;
|
|
11678
|
-
};
|
|
11679
|
-
}, [lineIdsKey, supabase]);
|
|
11680
|
-
return {
|
|
11681
|
-
shiftConfigMap,
|
|
11682
|
-
isLoading,
|
|
11683
|
-
error
|
|
11684
|
-
};
|
|
11685
|
-
};
|
|
11686
12082
|
var MAX_RETRIES = 10;
|
|
11687
12083
|
var RETRY_DELAY = 500;
|
|
11688
12084
|
function useNavigation(customNavigate) {
|
|
@@ -45237,6 +45633,10 @@ function HomeView({
|
|
|
45237
45633
|
const [diagnosisModalOpen, setDiagnosisModalOpen] = useState(false);
|
|
45238
45634
|
const [diagnoses, setDiagnoses] = useState([]);
|
|
45239
45635
|
const timezone = useAppTimezone();
|
|
45636
|
+
const { shiftConfigMap: lineShiftConfigs } = useMultiLineShiftConfigs(
|
|
45637
|
+
allLineIds,
|
|
45638
|
+
dashboardConfig?.shiftConfig
|
|
45639
|
+
);
|
|
45240
45640
|
useEffect(() => {
|
|
45241
45641
|
const initDisplayNames = async () => {
|
|
45242
45642
|
try {
|
|
@@ -45334,12 +45734,18 @@ function HomeView({
|
|
|
45334
45734
|
label: "Diagnose",
|
|
45335
45735
|
onClick: async () => {
|
|
45336
45736
|
console.log("\u{1F50D} Investigating bottleneck:", bottleneck.log_number);
|
|
45337
|
-
const operationalDate = getOperationalDate(
|
|
45338
|
-
timezone || dashboardConfig.dateTimeConfig?.defaultTimezone || "UTC"
|
|
45339
|
-
);
|
|
45340
45737
|
const tz = timezone || dashboardConfig.dateTimeConfig?.defaultTimezone || "UTC";
|
|
45341
|
-
const
|
|
45738
|
+
const lineShiftConfig = bottleneck.line_id && lineShiftConfigs.get(bottleneck.line_id);
|
|
45739
|
+
const effectiveShiftConfig = lineShiftConfig || dashboardConfig?.shiftConfig;
|
|
45740
|
+
const shiftResult = getCurrentShift(tz, effectiveShiftConfig);
|
|
45342
45741
|
const currentShift = shiftResult.shiftId;
|
|
45742
|
+
const operationalDate = shiftResult.date;
|
|
45743
|
+
console.log("\u{1F550} Using shift config for line:", {
|
|
45744
|
+
lineId: bottleneck.line_id,
|
|
45745
|
+
hasLineConfig: !!lineShiftConfig,
|
|
45746
|
+
shiftId: currentShift,
|
|
45747
|
+
date: operationalDate
|
|
45748
|
+
});
|
|
45343
45749
|
console.log("\u{1F3AC} [Investigate] Opening clips modal with data:", {
|
|
45344
45750
|
workspaceId: bottleneck.workspace_id,
|
|
45345
45751
|
ticketId: bottleneck.id,
|
|
@@ -45409,12 +45815,18 @@ function HomeView({
|
|
|
45409
45815
|
state,
|
|
45410
45816
|
priority: bottleneck.priority
|
|
45411
45817
|
});
|
|
45412
|
-
const operationalDate = getOperationalDate(
|
|
45413
|
-
timezone || dashboardConfig.dateTimeConfig?.defaultTimezone || "UTC"
|
|
45414
|
-
);
|
|
45415
45818
|
const tz = timezone || dashboardConfig.dateTimeConfig?.defaultTimezone || "UTC";
|
|
45416
|
-
const
|
|
45819
|
+
const lineShiftConfig = bottleneck.line_id && lineShiftConfigs.get(bottleneck.line_id);
|
|
45820
|
+
const effectiveShiftConfig = lineShiftConfig || dashboardConfig?.shiftConfig;
|
|
45821
|
+
const shiftResult = getCurrentShift(tz, effectiveShiftConfig);
|
|
45417
45822
|
const currentShift = shiftResult.shiftId;
|
|
45823
|
+
const operationalDate = shiftResult.date;
|
|
45824
|
+
console.log("\u{1F550} Using shift config for line:", {
|
|
45825
|
+
lineId: bottleneck.line_id,
|
|
45826
|
+
hasLineConfig: !!lineShiftConfig,
|
|
45827
|
+
shiftId: currentShift,
|
|
45828
|
+
date: operationalDate
|
|
45829
|
+
});
|
|
45418
45830
|
setBottleneckModalData({
|
|
45419
45831
|
workspaceId: bottleneck.workspace_id,
|
|
45420
45832
|
workspaceName: bottleneck_workspace.workspace_name || "Unknown Workspace",
|
|
@@ -45471,7 +45883,7 @@ function HomeView({
|
|
|
45471
45883
|
};
|
|
45472
45884
|
setBottleneckNotification(errorNotification);
|
|
45473
45885
|
}
|
|
45474
|
-
}, [notificationService, timezone, dashboardConfig]);
|
|
45886
|
+
}, [notificationService, timezone, dashboardConfig, lineShiftConfigs]);
|
|
45475
45887
|
useEffect(() => {
|
|
45476
45888
|
const ticketsEnabled = dashboardConfig?.ticketsConfig?.enabled ?? true;
|
|
45477
45889
|
if (!ticketsEnabled) {
|
|
@@ -47414,6 +47826,7 @@ var LeaderboardDetailView = memo(({
|
|
|
47414
47826
|
const entityConfig = useEntityConfig();
|
|
47415
47827
|
const [sortAscending, setSortAscending] = useState(false);
|
|
47416
47828
|
const timezone = useAppTimezone();
|
|
47829
|
+
const staticShiftConfig = useShiftConfig();
|
|
47417
47830
|
const [isMobile, setIsMobile] = useState(false);
|
|
47418
47831
|
React24__default.useEffect(() => {
|
|
47419
47832
|
const checkMobile = () => setIsMobile(window.innerWidth < 640);
|
|
@@ -47442,9 +47855,27 @@ var LeaderboardDetailView = memo(({
|
|
|
47442
47855
|
() => typeof shift === "number" ? shift : typeof shift === "string" ? parseInt(shift) : void 0,
|
|
47443
47856
|
[shift]
|
|
47444
47857
|
);
|
|
47445
|
-
const
|
|
47446
|
-
|
|
47447
|
-
|
|
47858
|
+
const configuredLineIds = useMemo(() => {
|
|
47859
|
+
const allLineIds = getConfiguredLineIds(entityConfig);
|
|
47860
|
+
if (userAccessibleLineIds) {
|
|
47861
|
+
return allLineIds.filter((id3) => userAccessibleLineIds.includes(id3));
|
|
47862
|
+
}
|
|
47863
|
+
return allLineIds;
|
|
47864
|
+
}, [entityConfig, userAccessibleLineIds]);
|
|
47865
|
+
const shouldFetchShiftConfigs = !date && shiftId === void 0;
|
|
47866
|
+
const {
|
|
47867
|
+
shiftConfigMap: multiLineShiftConfigMap,
|
|
47868
|
+
isLoading: isShiftConfigLoading
|
|
47869
|
+
} = useMultiLineShiftConfigs(
|
|
47870
|
+
shouldFetchShiftConfigs ? configuredLineIds : [],
|
|
47871
|
+
staticShiftConfig
|
|
47872
|
+
);
|
|
47873
|
+
const shiftGroups = useMemo(() => {
|
|
47874
|
+
if (!shouldFetchShiftConfigs || isShiftConfigLoading || multiLineShiftConfigMap.size === 0) {
|
|
47875
|
+
return [];
|
|
47876
|
+
}
|
|
47877
|
+
return groupLinesByShift(multiLineShiftConfigMap, timezone || "Asia/Kolkata");
|
|
47878
|
+
}, [shouldFetchShiftConfigs, isShiftConfigLoading, multiLineShiftConfigMap, timezone]);
|
|
47448
47879
|
const {
|
|
47449
47880
|
workspaces,
|
|
47450
47881
|
loading: workspacesLoading,
|
|
@@ -47452,21 +47883,28 @@ var LeaderboardDetailView = memo(({
|
|
|
47452
47883
|
refreshWorkspaces
|
|
47453
47884
|
} = useAllWorkspaceMetrics({
|
|
47454
47885
|
initialDate: date,
|
|
47455
|
-
initialShiftId:
|
|
47886
|
+
initialShiftId: shiftId,
|
|
47456
47887
|
allowedLineIds: userAccessibleLineIds,
|
|
47457
|
-
// Filter to user's accessible lines only
|
|
47458
47888
|
enabled: !isShiftConfigLoading
|
|
47459
|
-
// Pass enabled flag
|
|
47460
47889
|
});
|
|
47461
47890
|
const getShiftName = useCallback((shiftId2) => {
|
|
47462
47891
|
if (shiftId2 !== void 0) {
|
|
47463
|
-
return getShiftNameById(shiftId2, timezone || "Asia/Kolkata",
|
|
47892
|
+
return getShiftNameById(shiftId2, timezone || "Asia/Kolkata", staticShiftConfig);
|
|
47464
47893
|
}
|
|
47465
|
-
|
|
47466
|
-
|
|
47467
|
-
|
|
47894
|
+
if (shiftGroups.length > 1) {
|
|
47895
|
+
const shiftNames = shiftGroups.map((g) => g.shiftName).join(" & ");
|
|
47896
|
+
return shiftNames;
|
|
47897
|
+
} else if (shiftGroups.length === 1) {
|
|
47898
|
+
return shiftGroups[0].shiftName;
|
|
47899
|
+
}
|
|
47900
|
+
const currentShift = getCurrentShift(timezone || "Asia/Kolkata", staticShiftConfig);
|
|
47901
|
+
return currentShift.shiftName || getShiftNameById(currentShift.shiftId, timezone || "Asia/Kolkata", staticShiftConfig);
|
|
47902
|
+
}, [timezone, staticShiftConfig, shiftGroups]);
|
|
47468
47903
|
const getShiftIcon = useCallback((shiftId2) => {
|
|
47469
|
-
|
|
47904
|
+
if (shiftId2 === void 0 && shiftGroups.length > 1) {
|
|
47905
|
+
return /* @__PURE__ */ jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" }) });
|
|
47906
|
+
}
|
|
47907
|
+
const effectiveShiftId = shiftId2 !== void 0 ? shiftId2 : shiftGroups.length === 1 ? shiftGroups[0].shiftId : getCurrentShift(timezone || "Asia/Kolkata", staticShiftConfig).shiftId;
|
|
47470
47908
|
const shiftNameLower = getShiftName(effectiveShiftId).toLowerCase();
|
|
47471
47909
|
if (shiftNameLower.includes("day") || shiftNameLower.includes("morning")) {
|
|
47472
47910
|
return /* @__PURE__ */ jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ 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" }) });
|
|
@@ -47478,7 +47916,7 @@ var LeaderboardDetailView = memo(({
|
|
|
47478
47916
|
return /* @__PURE__ */ jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ 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" }) });
|
|
47479
47917
|
}
|
|
47480
47918
|
return /* @__PURE__ */ jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" }) });
|
|
47481
|
-
}, [getShiftName]);
|
|
47919
|
+
}, [getShiftName, shiftGroups, timezone, staticShiftConfig]);
|
|
47482
47920
|
const formatDate2 = useCallback((date2) => {
|
|
47483
47921
|
return new Intl.DateTimeFormat("en-US", {
|
|
47484
47922
|
weekday: "long",
|
|
@@ -56608,4 +57046,4 @@ function shuffleArray(array) {
|
|
|
56608
57046
|
return shuffled;
|
|
56609
57047
|
}
|
|
56610
57048
|
|
|
56611
|
-
export { ACTION_NAMES, AIAgentView_default as AIAgentView, AcceptInvite, AcceptInviteView_default as AcceptInviteView, AdvancedFilterDialog, AdvancedFilterPanel, AudioService, AuthCallback, AuthCallbackView_default as AuthCallbackView, AuthProvider, AuthService, AuthenticatedBottleneckClipsView, AuthenticatedFactoryView, AuthenticatedHelpView, AuthenticatedHomeView, AuthenticatedShiftsView, AuthenticatedTargetsView, AuthenticatedTicketsView, AuthenticatedWorkspaceHealthView, AxelNotificationPopup, AxelOrb, BackButton, BackButtonMinimal, BarChart, BaseHistoryCalendar, BottleneckClipsModal, BottleneckClipsView_default as BottleneckClipsView, BottlenecksContent, BreakNotificationPopup, CachePrefetchStatus, Card2 as Card, CardContent2 as CardContent, CardDescription2 as CardDescription, CardFooter2 as CardFooter, CardHeader2 as CardHeader, CardTitle2 as CardTitle, ClipFilterProvider, CompactWorkspaceHealthCard, CongratulationsOverlay, CroppedHlsVideoPlayer, CroppedVideoPlayer, CycleTimeChart, CycleTimeOverTimeChart, DEFAULT_ANALYTICS_CONFIG, DEFAULT_AUTH_CONFIG, DEFAULT_CONFIG, DEFAULT_DATABASE_CONFIG, DEFAULT_DATE_TIME_CONFIG, DEFAULT_ENDPOINTS_CONFIG, DEFAULT_ENTITY_CONFIG, DEFAULT_MAP_VIEW_CONFIG, DEFAULT_SHIFT_CONFIG, DEFAULT_SHIFT_DATA, DEFAULT_THEME_CONFIG, DEFAULT_VIDEO_CONFIG, DEFAULT_WORKSPACE_CONFIG, DEFAULT_WORKSPACE_POSITIONS, DashboardHeader, DashboardLayout, DashboardOverridesProvider, DashboardProvider, DateDisplay_default as DateDisplay, DateTimeDisplay, DebugAuth, DebugAuthView_default as DebugAuthView, DetailedHealthStatus, DiagnosisVideoModal, EmptyStateMessage, EncouragementOverlay, FactoryView_default as FactoryView, FileManagerFilters, FilterDialogTrigger, FirstTimeLoginDebug, FirstTimeLoginHandler, GaugeChart, GridComponentsPlaceholder, HamburgerButton, Header, HealthDateShiftSelector, HealthStatusGrid, HealthStatusIndicator, HelpView_default as HelpView, HlsVideoPlayer, HomeView_default as HomeView, HourlyOutputChart2 as HourlyOutputChart, ISTTimer_default as ISTTimer, InlineEditableText, InteractiveOnboardingTour, InvitationService, KPICard, KPIDetailView_default as KPIDetailView, KPIGrid, KPIHeader, KPISection, KPIsOverviewView_default as KPIsOverviewView, LINE_1_UUID, LINE_2_UUID, LargeOutputProgressChart, LeaderboardDetailView_default as LeaderboardDetailView, Legend6 as Legend, LineChart, LineHistoryCalendar, LineMonthlyHistory, LineMonthlyPdfGenerator, LinePdfExportButton, LinePdfGenerator, LineWhatsAppShareButton, LinesService, LiveTimer, LoadingInline, LoadingOverlay_default as LoadingOverlay, LoadingPage_default as LoadingPage, LoadingSkeleton, LoadingState, LoginPage, LoginView_default as LoginView, Logo, MainLayout, MapGridView, MetricCard_default as MetricCard, MinimalOnboardingPopup, NewClipsNotification, NoWorkspaceData, OnboardingDemo, OnboardingTour, OptifyeAgentClient, OptifyeLogoLoader_default as OptifyeLogoLoader, OutputProgressChart, PageHeader, PieChart4 as PieChart, PlayPauseIndicator, PrefetchConfigurationError, PrefetchError, PrefetchEvents, PrefetchStatus, PrefetchTimeoutError, ProfileView_default as ProfileView, RegistryProvider, S3ClipsSupabaseService as S3ClipsService, S3Service, SKUManagementView, SOPComplianceChart, SSEChatClient, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, SessionTracker, SessionTrackingContext, SessionTrackingProvider, ShiftDisplay_default as ShiftDisplay, ShiftsView_default as ShiftsView, SideNavBar, SignupWithInvitation, SilentErrorBoundary, SimpleOnboardingPopup, SingleVideoStream_default as SingleVideoStream, Skeleton, SubscriptionManager, SubscriptionManagerProvider, SupabaseProvider, SupervisorDropdown_default as SupervisorDropdown, SupervisorManagementView_default as SupervisorManagementView, SupervisorService, TargetWorkspaceGrid, TargetsView_default as TargetsView, TeamManagementView_default as TeamManagementView, ThreadSidebar, TicketHistory_default as TicketHistory, TicketHistoryService, TicketsView_default as TicketsView, TimeDisplay_default as TimeDisplay, TimePickerDropdown, Timer_default as Timer, TimezoneProvider, TimezoneService, UserManagementService, UserService, VideoCard, VideoGridView, VideoPlayer, VideoPreloader, WORKSPACE_POSITIONS, WhatsAppShareButton, WorkspaceCard, WorkspaceDetailView_default as WorkspaceDetailView, WorkspaceDisplayNameExample, WorkspaceGrid, WorkspaceGridItem, WorkspaceHealthCard, WorkspaceHealthView_default as WorkspaceHealthView, WorkspaceHistoryCalendar, WorkspaceMetricCards, WorkspaceMetricCardsImpl, WorkspaceMonthlyDataFetcher, WorkspaceMonthlyHistory, WorkspaceMonthlyPdfGenerator, WorkspacePdfExportButton, WorkspacePdfGenerator, WorkspaceWhatsAppShareButton, actionService, apiUtils, authCoreService, authOTPService, authRateLimitService, checkRateLimit2 as checkRateLimit, clearAllRateLimits2 as clearAllRateLimits, clearRateLimit2 as clearRateLimit, clearS3VideoCache, clearS3VideoFromCache, clearWorkspaceDisplayNamesCache, cn, createInvitationService, createLinesService, createSessionTracker, createStreamProxyHandler, createSupabaseClient, createSupervisorService, createThrottledReload, createUserManagementService, createUserService, dashboardService, deleteThread, fetchIdleTimeReasons, forceRefreshWorkspaceDisplayNames, formatDateInZone, formatDateTimeInZone, formatISTDate, formatIdleTime, formatReasonLabel, formatRelativeTime, formatTimeInZone, fromUrlFriendlyName, getAllLineDisplayNames, getAllThreadMessages, getAllWorkspaceDisplayNamesAsync, getAnonClient, getAvailableShiftIds, getBrowserName, getCameraNumber, getCompanyMetricsTableName, getConfigurableShortWorkspaceDisplayName, getConfigurableWorkspaceDisplayName, getConfiguredLineIds, getCoreSessionRecordingProperties, getCoreSessionReplayUrl, getCurrentShift, getCurrentTimeInZone, getDashboardHeaderTimeInZone, getDaysDifferenceInZone, getDefaultCameraStreamUrl, getDefaultLineId, getDefaultTabForWorkspace, getLineDisplayName, getManufacturingInsights, getMetricsTablePrefix, getNextUpdateInterval, getOperationalDate, getReasonColor, getS3SignedUrl, getS3VideoSrc, getShiftData, getShiftNameById, getShortShiftName, getShortWorkspaceDisplayName, getShortWorkspaceDisplayNameAsync, getStoredWorkspaceMappings, getSubscriptionManager, getThreadMessages, getUserThreads, getUserThreadsPaginated, getWorkspaceDisplayName, getWorkspaceDisplayNameAsync, getWorkspaceDisplayNamesMap, getWorkspaceFromUrl, getWorkspaceNavigationParams, hasAnyShiftData, identifyCoreUser, initializeCoreMixpanel, isLegacyConfiguration, isPrefetchError, isSafari, isTransitionPeriod, isUrlPermanentlyFailed, isValidFactoryViewConfiguration, isValidLineInfoPayload, isValidPrefetchParams, isValidPrefetchStatus, isValidWorkspaceDetailedMetricsPayload, isValidWorkspaceMetricsPayload, isWorkspaceDisplayNamesLoaded, isWorkspaceDisplayNamesLoading, linesService, mergeWithDefaultConfig, migrateLegacyConfiguration, optifyeAgentClient, parseS3Uri, preInitializeWorkspaceDisplayNames, preloadS3Video, preloadS3VideoUrl, preloadS3VideosUrl, preloadVideoUrl, preloadVideosUrl, qualityService, realtimeService, refreshWorkspaceDisplayNames, resetCoreMixpanel, resetFailedUrl, resetSubscriptionManager, s3VideoPreloader, shuffleArray, simulateApiDelay, skuService, startCoreSessionRecording, stopCoreSessionRecording, storeWorkspaceMapping, streamProxyConfig, throttledReloadDashboard, toUrlFriendlyName, trackCoreEvent, trackCorePageView, transformToChartData, updateThreadTitle, useAccessControl, useActiveBreaks, useActiveLineId, useAllWorkspaceMetrics, useAnalyticsConfig, useAppTimezone, useAudioService, useAuth, useAuthConfig, useAxelNotifications, useCanSaveTargets, useClipFilter, useClipTypes, useClipTypesWithCounts, useCompanyUsersUsage, useComponentOverride, useCustomConfig, useDashboardConfig, useDashboardMetrics, useDatabaseConfig, useDateFormatter, useDateTimeConfig, useDynamicShiftConfig, useEndpointsConfig, useEntityConfig, useFactoryOverviewMetrics, useFeatureFlags, useFormatNumber, useHasLineAccess, useHistoricWorkspaceMetrics, useHlsStream, useHlsStreamWithCropping, useHookOverride, useHourEndTimer, useHourlyTargetAchievements, useHourlyTargetMisses, useIdleTimeReasons, useLeaderboardMetrics, useLineDetailedMetrics, useLineKPIs, useLineMetrics, useLineShiftConfig, useLineSupervisor, useLineWorkspaceMetrics, useMessages, useMetrics, useMultiLineShiftConfigs, useNavigation, useOverrides, usePageOverride, usePrefetchClipCounts, useRealtimeLineMetrics, useRegistry, useSKUs, useSessionKeepAlive, useSessionTracking, useSessionTrackingContext, useShiftConfig, useShifts, useSubscriptionManager, useSubscriptionManagerSafe, useSupabase, useSupabaseClient, useTargets, useTeamManagementPermissions, useTheme, useThemeConfig, useThreads, useTicketHistory, useTimezoneContext, useUserLineAccess, useUserUsage, useVideoConfig, useWorkspaceConfig, useWorkspaceDetailedMetrics, useWorkspaceDisplayName, useWorkspaceDisplayNames, useWorkspaceDisplayNamesMap, useWorkspaceHealthById, useWorkspaceHealthStatus, useWorkspaceMetrics, useWorkspaceNavigation, useWorkspaceOperators, useWorkspaceUptimeTimeline, userService, videoPrefetchManager, videoPreloader, whatsappService, withAccessControl, withAuth, withRegistry, withTimezone, workspaceHealthService, workspaceService };
|
|
57049
|
+
export { ACTION_NAMES, AIAgentView_default as AIAgentView, AcceptInvite, AcceptInviteView_default as AcceptInviteView, AdvancedFilterDialog, AdvancedFilterPanel, AudioService, AuthCallback, AuthCallbackView_default as AuthCallbackView, AuthProvider, AuthService, AuthenticatedBottleneckClipsView, AuthenticatedFactoryView, AuthenticatedHelpView, AuthenticatedHomeView, AuthenticatedShiftsView, AuthenticatedTargetsView, AuthenticatedTicketsView, AuthenticatedWorkspaceHealthView, AxelNotificationPopup, AxelOrb, BackButton, BackButtonMinimal, BarChart, BaseHistoryCalendar, BottleneckClipsModal, BottleneckClipsView_default as BottleneckClipsView, BottlenecksContent, BreakNotificationPopup, CachePrefetchStatus, Card2 as Card, CardContent2 as CardContent, CardDescription2 as CardDescription, CardFooter2 as CardFooter, CardHeader2 as CardHeader, CardTitle2 as CardTitle, ClipFilterProvider, CompactWorkspaceHealthCard, CongratulationsOverlay, CroppedHlsVideoPlayer, CroppedVideoPlayer, CycleTimeChart, CycleTimeOverTimeChart, DEFAULT_ANALYTICS_CONFIG, DEFAULT_AUTH_CONFIG, DEFAULT_CONFIG, DEFAULT_DATABASE_CONFIG, DEFAULT_DATE_TIME_CONFIG, DEFAULT_ENDPOINTS_CONFIG, DEFAULT_ENTITY_CONFIG, DEFAULT_MAP_VIEW_CONFIG, DEFAULT_SHIFT_CONFIG, DEFAULT_SHIFT_DATA, DEFAULT_THEME_CONFIG, DEFAULT_VIDEO_CONFIG, DEFAULT_WORKSPACE_CONFIG, DEFAULT_WORKSPACE_POSITIONS, DashboardHeader, DashboardLayout, DashboardOverridesProvider, DashboardProvider, DateDisplay_default as DateDisplay, DateTimeDisplay, DebugAuth, DebugAuthView_default as DebugAuthView, DetailedHealthStatus, DiagnosisVideoModal, EmptyStateMessage, EncouragementOverlay, FactoryView_default as FactoryView, FileManagerFilters, FilterDialogTrigger, FirstTimeLoginDebug, FirstTimeLoginHandler, GaugeChart, GridComponentsPlaceholder, HamburgerButton, Header, HealthDateShiftSelector, HealthStatusGrid, HealthStatusIndicator, HelpView_default as HelpView, HlsVideoPlayer, HomeView_default as HomeView, HourlyOutputChart2 as HourlyOutputChart, ISTTimer_default as ISTTimer, InlineEditableText, InteractiveOnboardingTour, InvitationService, KPICard, KPIDetailView_default as KPIDetailView, KPIGrid, KPIHeader, KPISection, KPIsOverviewView_default as KPIsOverviewView, LINE_1_UUID, LINE_2_UUID, LargeOutputProgressChart, LeaderboardDetailView_default as LeaderboardDetailView, Legend6 as Legend, LineChart, LineHistoryCalendar, LineMonthlyHistory, LineMonthlyPdfGenerator, LinePdfExportButton, LinePdfGenerator, LineWhatsAppShareButton, LinesService, LiveTimer, LoadingInline, LoadingOverlay_default as LoadingOverlay, LoadingPage_default as LoadingPage, LoadingSkeleton, LoadingState, LoginPage, LoginView_default as LoginView, Logo, MainLayout, MapGridView, MetricCard_default as MetricCard, MinimalOnboardingPopup, NewClipsNotification, NoWorkspaceData, OnboardingDemo, OnboardingTour, OptifyeAgentClient, OptifyeLogoLoader_default as OptifyeLogoLoader, OutputProgressChart, PageHeader, PieChart4 as PieChart, PlayPauseIndicator, PrefetchConfigurationError, PrefetchError, PrefetchEvents, PrefetchStatus, PrefetchTimeoutError, ProfileView_default as ProfileView, RegistryProvider, S3ClipsSupabaseService as S3ClipsService, S3Service, SKUManagementView, SOPComplianceChart, SSEChatClient, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, SessionTracker, SessionTrackingContext, SessionTrackingProvider, ShiftDisplay_default as ShiftDisplay, ShiftsView_default as ShiftsView, SideNavBar, SignupWithInvitation, SilentErrorBoundary, SimpleOnboardingPopup, SingleVideoStream_default as SingleVideoStream, Skeleton, SubscriptionManager, SubscriptionManagerProvider, SupabaseProvider, SupervisorDropdown_default as SupervisorDropdown, SupervisorManagementView_default as SupervisorManagementView, SupervisorService, TargetWorkspaceGrid, TargetsView_default as TargetsView, TeamManagementView_default as TeamManagementView, ThreadSidebar, TicketHistory_default as TicketHistory, TicketHistoryService, TicketsView_default as TicketsView, TimeDisplay_default as TimeDisplay, TimePickerDropdown, Timer_default as Timer, TimezoneProvider, TimezoneService, UserManagementService, UserService, VideoCard, VideoGridView, VideoPlayer, VideoPreloader, WORKSPACE_POSITIONS, WhatsAppShareButton, WorkspaceCard, WorkspaceDetailView_default as WorkspaceDetailView, WorkspaceDisplayNameExample, WorkspaceGrid, WorkspaceGridItem, WorkspaceHealthCard, WorkspaceHealthView_default as WorkspaceHealthView, WorkspaceHistoryCalendar, WorkspaceMetricCards, WorkspaceMetricCardsImpl, WorkspaceMonthlyDataFetcher, WorkspaceMonthlyHistory, WorkspaceMonthlyPdfGenerator, WorkspacePdfExportButton, WorkspacePdfGenerator, WorkspaceWhatsAppShareButton, actionService, apiUtils, areAllLinesOnSameShift, authCoreService, authOTPService, authRateLimitService, checkRateLimit2 as checkRateLimit, clearAllRateLimits2 as clearAllRateLimits, clearRateLimit2 as clearRateLimit, clearS3VideoCache, clearS3VideoFromCache, clearWorkspaceDisplayNamesCache, cn, createInvitationService, createLinesService, createSessionTracker, createStreamProxyHandler, createSupabaseClient, createSupervisorService, createThrottledReload, createUserManagementService, createUserService, dashboardService, deleteThread, fetchIdleTimeReasons, forceRefreshWorkspaceDisplayNames, formatDateInZone, formatDateTimeInZone, formatISTDate, formatIdleTime, formatReasonLabel, formatRelativeTime, formatTimeInZone, fromUrlFriendlyName, getAllLineDisplayNames, getAllThreadMessages, getAllWorkspaceDisplayNamesAsync, getAnonClient, getAvailableShiftIds, getBrowserName, getCameraNumber, getCompanyMetricsTableName, getConfigurableShortWorkspaceDisplayName, getConfigurableWorkspaceDisplayName, getConfiguredLineIds, getCoreSessionRecordingProperties, getCoreSessionReplayUrl, getCurrentShift, getCurrentShiftForLine, getCurrentTimeInZone, getDashboardHeaderTimeInZone, getDaysDifferenceInZone, getDefaultCameraStreamUrl, getDefaultLineId, getDefaultTabForWorkspace, getLineDisplayName, getManufacturingInsights, getMetricsTablePrefix, getNextUpdateInterval, getOperationalDate, getReasonColor, getS3SignedUrl, getS3VideoSrc, getShiftData, getShiftNameById, getShortShiftName, getShortWorkspaceDisplayName, getShortWorkspaceDisplayNameAsync, getStoredWorkspaceMappings, getSubscriptionManager, getThreadMessages, getUniformShiftGroup, getUserThreads, getUserThreadsPaginated, getWorkspaceDisplayName, getWorkspaceDisplayNameAsync, getWorkspaceDisplayNamesMap, getWorkspaceFromUrl, getWorkspaceNavigationParams, groupLinesByShift, hasAnyShiftData, identifyCoreUser, initializeCoreMixpanel, isLegacyConfiguration, isPrefetchError, isSafari, isTransitionPeriod, isUrlPermanentlyFailed, isValidFactoryViewConfiguration, isValidLineInfoPayload, isValidPrefetchParams, isValidPrefetchStatus, isValidWorkspaceDetailedMetricsPayload, isValidWorkspaceMetricsPayload, isWorkspaceDisplayNamesLoaded, isWorkspaceDisplayNamesLoading, linesService, mergeWithDefaultConfig, migrateLegacyConfiguration, optifyeAgentClient, parseS3Uri, preInitializeWorkspaceDisplayNames, preloadS3Video, preloadS3VideoUrl, preloadS3VideosUrl, preloadVideoUrl, preloadVideosUrl, qualityService, realtimeService, refreshWorkspaceDisplayNames, resetCoreMixpanel, resetFailedUrl, resetSubscriptionManager, s3VideoPreloader, shuffleArray, simulateApiDelay, skuService, startCoreSessionRecording, stopCoreSessionRecording, storeWorkspaceMapping, streamProxyConfig, throttledReloadDashboard, toUrlFriendlyName, trackCoreEvent, trackCorePageView, transformToChartData, updateThreadTitle, useAccessControl, useActiveBreaks, useActiveLineId, useAllWorkspaceMetrics, useAnalyticsConfig, useAppTimezone, useAudioService, useAuth, useAuthConfig, useAxelNotifications, useCanSaveTargets, useClipFilter, useClipTypes, useClipTypesWithCounts, useCompanyUsersUsage, useComponentOverride, useCustomConfig, useDashboardConfig, useDashboardMetrics, useDatabaseConfig, useDateFormatter, useDateTimeConfig, useDynamicShiftConfig, useEndpointsConfig, useEntityConfig, useFactoryOverviewMetrics, useFeatureFlags, useFormatNumber, useHasLineAccess, useHistoricWorkspaceMetrics, useHlsStream, useHlsStreamWithCropping, useHookOverride, useHourEndTimer, useHourlyTargetAchievements, useHourlyTargetMisses, useIdleTimeReasons, useLeaderboardMetrics, useLineDetailedMetrics, useLineKPIs, useLineMetrics, useLineShiftConfig, useLineSupervisor, useLineWorkspaceMetrics, useMessages, useMetrics, useMultiLineShiftConfigs, useNavigation, useOverrides, usePageOverride, usePrefetchClipCounts, useRealtimeLineMetrics, useRegistry, useSKUs, useSessionKeepAlive, useSessionTracking, useSessionTrackingContext, useShiftConfig, useShifts, useSubscriptionManager, useSubscriptionManagerSafe, useSupabase, useSupabaseClient, useTargets, useTeamManagementPermissions, useTheme, useThemeConfig, useThreads, useTicketHistory, useTimezoneContext, useUserLineAccess, useUserUsage, useVideoConfig, useWorkspaceConfig, useWorkspaceDetailedMetrics, useWorkspaceDisplayName, useWorkspaceDisplayNames, useWorkspaceDisplayNamesMap, useWorkspaceHealthById, useWorkspaceHealthStatus, useWorkspaceMetrics, useWorkspaceNavigation, useWorkspaceOperators, useWorkspaceUptimeTimeline, userService, videoPrefetchManager, videoPreloader, whatsappService, withAccessControl, withAuth, withRegistry, withTimezone, workspaceHealthService, workspaceService };
|