@optifye/dashboard-core 6.10.37 → 6.10.38
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 +6 -0
- package/dist/index.d.mts +79 -4
- package/dist/index.d.ts +79 -4
- package/dist/index.js +2086 -531
- package/dist/index.mjs +2085 -532
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -132,14 +132,18 @@ var DEFAULT_SHIFT_DATA = {
|
|
|
132
132
|
pph: 0,
|
|
133
133
|
pphThreshold: 0,
|
|
134
134
|
idealOutput: 0,
|
|
135
|
+
targetOutput: 0,
|
|
135
136
|
rank: 0,
|
|
136
137
|
idleTime: 0,
|
|
138
|
+
activeTimeSeconds: 0,
|
|
139
|
+
availableTimeSeconds: 0,
|
|
137
140
|
hasData: false
|
|
138
141
|
};
|
|
139
142
|
var getShiftData = (day, shiftId) => {
|
|
140
143
|
const shift = day.shifts[shiftId];
|
|
141
144
|
if (shift) {
|
|
142
|
-
|
|
145
|
+
const hasData = shift.hasData ?? true;
|
|
146
|
+
return { ...DEFAULT_SHIFT_DATA, ...shift, hasData };
|
|
143
147
|
}
|
|
144
148
|
return { ...DEFAULT_SHIFT_DATA };
|
|
145
149
|
};
|
|
@@ -1596,7 +1600,7 @@ var dashboardService = {
|
|
|
1596
1600
|
}
|
|
1597
1601
|
const lineIdsToQuery = configuredLineIds;
|
|
1598
1602
|
const [line1Result, metricsResult2] = await Promise.all([
|
|
1599
|
-
supabase.from(linesTable).select("id, line_name, factory_id, factories!lines_factory_id_fkey(factory_name), company_id, companies!lines_company_id_fkey(company_name:name)").eq("id", defaultLineId).single(),
|
|
1603
|
+
supabase.from(linesTable).select("id, line_name, factory_id, monitoring_mode, factories!lines_factory_id_fkey(factory_name), company_id, companies!lines_company_id_fkey(company_name:name)").eq("id", defaultLineId).single(),
|
|
1600
1604
|
supabase.from(lineMetricsTable).select("*").in("line_id", lineIdsToQuery).eq("shift_id", queryShiftId).eq("date", queryDate)
|
|
1601
1605
|
]);
|
|
1602
1606
|
if (line1Result.error) throw line1Result.error;
|
|
@@ -1651,6 +1655,7 @@ var dashboardService = {
|
|
|
1651
1655
|
factory_name: line1Data.factories?.factory_name ?? "N/A",
|
|
1652
1656
|
date: queryDate,
|
|
1653
1657
|
shift_id: queryShiftId,
|
|
1658
|
+
monitoring_mode: line1Data.monitoring_mode ?? void 0,
|
|
1654
1659
|
metrics: {
|
|
1655
1660
|
avg_efficiency: avgEfficiency,
|
|
1656
1661
|
avg_cycle_time: combinedMetricsData.avg_cycle_time / numLines,
|
|
@@ -1674,7 +1679,7 @@ var dashboardService = {
|
|
|
1674
1679
|
throw new Error("Company ID must be configured for detailed line requests.");
|
|
1675
1680
|
}
|
|
1676
1681
|
const [lineResult, metricsResult] = await Promise.all([
|
|
1677
|
-
supabase.from(linesTable).select("id, line_name, factory_id, factories!lines_factory_id_fkey(factory_name), company_id, companies!lines_company_id_fkey(company_name:name)").eq("id", lineIdToQuery).single(),
|
|
1682
|
+
supabase.from(linesTable).select("id, line_name, factory_id, monitoring_mode, factories!lines_factory_id_fkey(factory_name), company_id, companies!lines_company_id_fkey(company_name:name)").eq("id", lineIdToQuery).single(),
|
|
1678
1683
|
supabase.from(lineMetricsTable).select("*").eq("line_id", lineIdToQuery).eq("shift_id", queryShiftId).eq("date", queryDate).maybeSingle()
|
|
1679
1684
|
]);
|
|
1680
1685
|
if (lineResult.error) throw lineResult.error;
|
|
@@ -1693,6 +1698,7 @@ var dashboardService = {
|
|
|
1693
1698
|
factory_name: lineData.factories?.factory_name ?? "N/A",
|
|
1694
1699
|
date: queryDate,
|
|
1695
1700
|
shift_id: queryShiftId,
|
|
1701
|
+
monitoring_mode: lineData.monitoring_mode ?? void 0,
|
|
1696
1702
|
metrics: {
|
|
1697
1703
|
avg_efficiency: metrics2?.avg_efficiency ?? 0,
|
|
1698
1704
|
avg_cycle_time: metrics2?.avg_cycle_time || 0,
|
|
@@ -1722,8 +1728,6 @@ var dashboardService = {
|
|
|
1722
1728
|
const entityConfig = config.entityConfig ?? DEFAULT_ENTITY_CONFIG;
|
|
1723
1729
|
const shiftConfig = config.shiftConfig ?? DEFAULT_SHIFT_CONFIG;
|
|
1724
1730
|
const companyId = entityConfig.companyId;
|
|
1725
|
-
const metricsTablePrefixStr = getMetricsTablePrefix();
|
|
1726
|
-
const metricsTable = `${metricsTablePrefixStr}_${companyId ? companyId.replace(/-/g, "_") : "unknown_company"}`;
|
|
1727
1731
|
const startDate = new Date(year, month, 1);
|
|
1728
1732
|
const endDate = new Date(year, month + 1, 0);
|
|
1729
1733
|
const formatDate2 = (date) => {
|
|
@@ -1735,33 +1739,34 @@ var dashboardService = {
|
|
|
1735
1739
|
const formattedStartDate = formatDate2(startDate);
|
|
1736
1740
|
const formattedEndDate = formatDate2(endDate);
|
|
1737
1741
|
try {
|
|
1738
|
-
const
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
`).eq("workspace_id", workspaceUuid).gte("date", formattedStartDate).lte("date", formattedEndDate).order("date", { ascending: true }).order("shift_id", { ascending: true });
|
|
1750
|
-
if (error) throw error;
|
|
1751
|
-
if (!data) return [];
|
|
1752
|
-
const transformedData = data.map((item) => ({
|
|
1742
|
+
const searchParams = new URLSearchParams();
|
|
1743
|
+
searchParams.set("workspace_id", workspaceUuid);
|
|
1744
|
+
searchParams.set("company_id", companyId || "");
|
|
1745
|
+
searchParams.set("start_date", formattedStartDate);
|
|
1746
|
+
searchParams.set("end_date", formattedEndDate);
|
|
1747
|
+
const data = await fetchBackendJson(
|
|
1748
|
+
supabase,
|
|
1749
|
+
`/api/dashboard/workspace-monthly?${searchParams.toString()}`
|
|
1750
|
+
);
|
|
1751
|
+
const entries = data?.entries ?? [];
|
|
1752
|
+
const transformedData = entries.map((item) => ({
|
|
1753
1753
|
date: item.date,
|
|
1754
1754
|
shift_id: item.shift_id,
|
|
1755
1755
|
shift_type: item.shift_id === (shiftConfig.dayShift?.id ?? 0) ? "Day" : item.shift_id === (shiftConfig.nightShift?.id ?? 1) ? "Night" : "Unknown",
|
|
1756
|
-
avg_efficiency: item.
|
|
1756
|
+
avg_efficiency: item.avg_efficiency || 0,
|
|
1757
1757
|
total_output: item.total_output || 0,
|
|
1758
1758
|
avg_cycle_time: item.avg_cycle_time || 0,
|
|
1759
|
-
ideal_output: item.
|
|
1760
|
-
|
|
1759
|
+
ideal_output: item.ideal_output || 0,
|
|
1760
|
+
total_day_output: item.total_day_output ?? item.ideal_output ?? 0,
|
|
1761
1761
|
avg_pph: item.avg_pph || 0,
|
|
1762
1762
|
pph_threshold: item.pph_threshold || 0,
|
|
1763
1763
|
workspace_rank: item.workspace_rank || 0,
|
|
1764
|
-
idle_time: item.idle_time || 0
|
|
1764
|
+
idle_time: item.idle_time || 0,
|
|
1765
|
+
active_time_seconds: item.active_time_seconds,
|
|
1766
|
+
idle_time_seconds: item.idle_time_seconds,
|
|
1767
|
+
available_time_seconds: item.available_time_seconds,
|
|
1768
|
+
shift_start: item.shift_start ?? null,
|
|
1769
|
+
shift_end: item.shift_end ?? null
|
|
1765
1770
|
}));
|
|
1766
1771
|
return transformedData;
|
|
1767
1772
|
} catch (err) {
|
|
@@ -1769,16 +1774,14 @@ var dashboardService = {
|
|
|
1769
1774
|
throw err;
|
|
1770
1775
|
}
|
|
1771
1776
|
},
|
|
1772
|
-
async getLineMonthlyData(lineIdInput, month, year) {
|
|
1777
|
+
async getLineMonthlyData(lineIdInput, month, year, options) {
|
|
1773
1778
|
const supabase = _getSupabaseInstance();
|
|
1774
1779
|
const config = _getDashboardConfigInstance();
|
|
1775
|
-
const dbConfig = config.databaseConfig ?? DEFAULT_DATABASE_CONFIG;
|
|
1776
1780
|
const entityConfig = config.entityConfig ?? DEFAULT_ENTITY_CONFIG;
|
|
1777
|
-
const lineMetricsTable = getTable(dbConfig, "lineMetrics");
|
|
1778
1781
|
const configuredLineIds = getConfiguredLineIds(entityConfig);
|
|
1779
1782
|
const factoryViewId = entityConfig.factoryViewId ?? "factory";
|
|
1780
|
-
const startDate = new Date(year, month, 1);
|
|
1781
|
-
const endDate = new Date(year, month + 1, 0);
|
|
1783
|
+
const startDate = options?.startDate ? new Date(options.startDate) : new Date(year, month, 1);
|
|
1784
|
+
const endDate = options?.endDate ? new Date(options.endDate) : new Date(year, month + 1, 0);
|
|
1782
1785
|
const formatDate2 = (date) => {
|
|
1783
1786
|
const year2 = date.getFullYear();
|
|
1784
1787
|
const month2 = String(date.getMonth() + 1).padStart(2, "0");
|
|
@@ -1787,31 +1790,28 @@ var dashboardService = {
|
|
|
1787
1790
|
};
|
|
1788
1791
|
const formattedStartDate = formatDate2(startDate);
|
|
1789
1792
|
const formattedEndDate = formatDate2(endDate);
|
|
1790
|
-
|
|
1793
|
+
const params = new URLSearchParams({
|
|
1794
|
+
start_date: formattedStartDate,
|
|
1795
|
+
end_date: formattedEndDate,
|
|
1796
|
+
company_id: entityConfig.companyId || ""
|
|
1797
|
+
});
|
|
1791
1798
|
if (lineIdInput === factoryViewId) {
|
|
1792
1799
|
if (!isValidFactoryViewConfiguration(entityConfig)) {
|
|
1793
1800
|
throw new Error("Factory View requires at least one configured line for monthly data.");
|
|
1794
1801
|
}
|
|
1795
|
-
|
|
1802
|
+
params.set("line_ids", configuredLineIds.join(","));
|
|
1796
1803
|
} else {
|
|
1797
|
-
|
|
1804
|
+
params.set("line_id", lineIdInput);
|
|
1805
|
+
}
|
|
1806
|
+
if (options?.shiftIds && options.shiftIds.length > 0) {
|
|
1807
|
+
params.set("shift_ids", options.shiftIds.join(","));
|
|
1798
1808
|
}
|
|
1799
|
-
query = query.order("date", { ascending: true }).order("shift_id", { ascending: true });
|
|
1800
1809
|
try {
|
|
1801
|
-
const
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
shift_id: item.shift_id,
|
|
1807
|
-
avg_efficiency: item.avg_efficiency || 0,
|
|
1808
|
-
underperforming_workspaces: item.underperforming_workspaces || 0,
|
|
1809
|
-
total_workspaces: item.total_workspaces || 0,
|
|
1810
|
-
current_output: item.current_output || 0,
|
|
1811
|
-
ideal_output: item.ideal_output || 0,
|
|
1812
|
-
line_threshold: item.line_threshold || 0
|
|
1813
|
-
}));
|
|
1814
|
-
return transformedData;
|
|
1810
|
+
const response = await fetchBackendJson(
|
|
1811
|
+
supabase,
|
|
1812
|
+
`/api/dashboard/line-monthly?${params.toString()}`
|
|
1813
|
+
);
|
|
1814
|
+
return response?.entries || [];
|
|
1815
1815
|
} catch (err) {
|
|
1816
1816
|
console.error("Exception in getLineMonthlyData:", err);
|
|
1817
1817
|
throw err;
|
|
@@ -4078,11 +4078,163 @@ var authRateLimitService = {
|
|
|
4078
4078
|
clearRateLimit,
|
|
4079
4079
|
clearAllRateLimits
|
|
4080
4080
|
};
|
|
4081
|
+
|
|
4082
|
+
// src/lib/utils/rateLimit.ts
|
|
4083
|
+
var rateLimitMap2 = /* @__PURE__ */ new Map();
|
|
4084
|
+
function checkRateLimit2(identifier, options = {}) {
|
|
4085
|
+
const windowMs = options.windowMs || 60 * 1e3;
|
|
4086
|
+
const maxRequests = options.maxRequests || 3;
|
|
4087
|
+
const now4 = Date.now();
|
|
4088
|
+
const userLimit = rateLimitMap2.get(identifier);
|
|
4089
|
+
if (userLimit && userLimit.resetTime < now4) {
|
|
4090
|
+
rateLimitMap2.delete(identifier);
|
|
4091
|
+
}
|
|
4092
|
+
if (!userLimit || userLimit.resetTime < now4) {
|
|
4093
|
+
rateLimitMap2.set(identifier, {
|
|
4094
|
+
count: 1,
|
|
4095
|
+
resetTime: now4 + windowMs
|
|
4096
|
+
});
|
|
4097
|
+
return { allowed: true };
|
|
4098
|
+
}
|
|
4099
|
+
if (userLimit.count >= maxRequests) {
|
|
4100
|
+
const retryAfter = Math.ceil((userLimit.resetTime - now4) / 1e3);
|
|
4101
|
+
return { allowed: false, retryAfter };
|
|
4102
|
+
}
|
|
4103
|
+
userLimit.count++;
|
|
4104
|
+
return { allowed: true };
|
|
4105
|
+
}
|
|
4106
|
+
function clearRateLimit2(identifier) {
|
|
4107
|
+
rateLimitMap2.delete(identifier);
|
|
4108
|
+
}
|
|
4109
|
+
function clearAllRateLimits2() {
|
|
4110
|
+
rateLimitMap2.clear();
|
|
4111
|
+
}
|
|
4112
|
+
|
|
4113
|
+
// src/lib/utils/sentryContext.ts
|
|
4114
|
+
function getSentry() {
|
|
4115
|
+
try {
|
|
4116
|
+
return __require("@sentry/nextjs");
|
|
4117
|
+
} catch {
|
|
4118
|
+
return null;
|
|
4119
|
+
}
|
|
4120
|
+
}
|
|
4121
|
+
function setSentryUserContext(user) {
|
|
4122
|
+
const sentry = getSentry();
|
|
4123
|
+
if (!sentry) return;
|
|
4124
|
+
if (user) {
|
|
4125
|
+
sentry.setUser({
|
|
4126
|
+
id: user.id,
|
|
4127
|
+
email: user.email
|
|
4128
|
+
});
|
|
4129
|
+
sentry.setTags({
|
|
4130
|
+
company_id: user.company_id || "unknown",
|
|
4131
|
+
role: user.role || "unknown",
|
|
4132
|
+
role_level: user.role_level || "unknown"
|
|
4133
|
+
});
|
|
4134
|
+
} else {
|
|
4135
|
+
sentry.setUser(null);
|
|
4136
|
+
sentry.setTags({
|
|
4137
|
+
company_id: void 0,
|
|
4138
|
+
role: void 0,
|
|
4139
|
+
role_level: void 0
|
|
4140
|
+
});
|
|
4141
|
+
}
|
|
4142
|
+
}
|
|
4143
|
+
function setSentryWorkspaceContext(config) {
|
|
4144
|
+
const sentry = getSentry();
|
|
4145
|
+
if (!sentry) return;
|
|
4146
|
+
sentry.setTags({
|
|
4147
|
+
workspace_company: config.companyId || "unknown",
|
|
4148
|
+
workspace_factory: config.factoryId || "unknown",
|
|
4149
|
+
factory_name: config.factoryName || "unknown"
|
|
4150
|
+
});
|
|
4151
|
+
}
|
|
4152
|
+
function clearSentryContext() {
|
|
4153
|
+
const sentry = getSentry();
|
|
4154
|
+
if (!sentry) return;
|
|
4155
|
+
sentry.setUser(null);
|
|
4156
|
+
sentry.setTags({
|
|
4157
|
+
company_id: void 0,
|
|
4158
|
+
role: void 0,
|
|
4159
|
+
role_level: void 0,
|
|
4160
|
+
workspace_company: void 0,
|
|
4161
|
+
workspace_factory: void 0,
|
|
4162
|
+
factory_name: void 0
|
|
4163
|
+
});
|
|
4164
|
+
}
|
|
4165
|
+
function applyScopeExtras(scope, extras) {
|
|
4166
|
+
if (!extras) return;
|
|
4167
|
+
if (scope.setExtras) {
|
|
4168
|
+
scope.setExtras(extras);
|
|
4169
|
+
return;
|
|
4170
|
+
}
|
|
4171
|
+
if (scope.setExtra) {
|
|
4172
|
+
Object.entries(extras).forEach(([key, value]) => scope.setExtra?.(key, value));
|
|
4173
|
+
}
|
|
4174
|
+
}
|
|
4175
|
+
function captureSentryMessage(message, level = "warning", extras) {
|
|
4176
|
+
const sentry = getSentry();
|
|
4177
|
+
if (!sentry || !sentry.captureMessage) return;
|
|
4178
|
+
if (sentry.withScope) {
|
|
4179
|
+
sentry.withScope((scope) => {
|
|
4180
|
+
scope.setLevel?.(level);
|
|
4181
|
+
applyScopeExtras(scope, extras);
|
|
4182
|
+
sentry.captureMessage?.(message);
|
|
4183
|
+
});
|
|
4184
|
+
return;
|
|
4185
|
+
}
|
|
4186
|
+
sentry.captureMessage(message, level);
|
|
4187
|
+
}
|
|
4188
|
+
function captureSentryException(error, extras) {
|
|
4189
|
+
const sentry = getSentry();
|
|
4190
|
+
if (!sentry || !sentry.captureException) return;
|
|
4191
|
+
if (sentry.withScope) {
|
|
4192
|
+
sentry.withScope((scope) => {
|
|
4193
|
+
scope.setLevel?.("error");
|
|
4194
|
+
applyScopeExtras(scope, extras);
|
|
4195
|
+
sentry.captureException?.(error);
|
|
4196
|
+
});
|
|
4197
|
+
return;
|
|
4198
|
+
}
|
|
4199
|
+
sentry.captureException(error);
|
|
4200
|
+
}
|
|
4201
|
+
|
|
4202
|
+
// src/lib/services/mixpanelService.ts
|
|
4081
4203
|
var isMixpanelInitialized = false;
|
|
4082
4204
|
var currentUserProperties;
|
|
4205
|
+
var MIXPANEL_WARNING_RATE_LIMIT = {
|
|
4206
|
+
windowMs: 10 * 60 * 1e3,
|
|
4207
|
+
// 10 minutes
|
|
4208
|
+
maxRequests: 2
|
|
4209
|
+
};
|
|
4210
|
+
var MIXPANEL_ERROR_RATE_LIMIT = {
|
|
4211
|
+
windowMs: 10 * 60 * 1e3,
|
|
4212
|
+
// 10 minutes
|
|
4213
|
+
maxRequests: 5
|
|
4214
|
+
};
|
|
4215
|
+
var baseMixpanelExtras = () => ({
|
|
4216
|
+
isInitialized: isMixpanelInitialized,
|
|
4217
|
+
environment: process.env.NODE_ENV
|
|
4218
|
+
});
|
|
4219
|
+
var shouldReportMixpanel = (key, isError) => {
|
|
4220
|
+
const options = isError ? MIXPANEL_ERROR_RATE_LIMIT : MIXPANEL_WARNING_RATE_LIMIT;
|
|
4221
|
+
return checkRateLimit2(`mixpanel:${key}`, options).allowed;
|
|
4222
|
+
};
|
|
4223
|
+
var reportMixpanelWarning = (key, message, extras) => {
|
|
4224
|
+
if (!shouldReportMixpanel(key, false)) return;
|
|
4225
|
+
captureSentryMessage(message, "warning", { ...baseMixpanelExtras(), ...extras });
|
|
4226
|
+
};
|
|
4227
|
+
var reportMixpanelError = (key, error, extras) => {
|
|
4228
|
+
if (!shouldReportMixpanel(key, true)) return;
|
|
4229
|
+
captureSentryException(error, { ...baseMixpanelExtras(), ...extras });
|
|
4230
|
+
};
|
|
4083
4231
|
var initializeCoreMixpanel = (token, debugOrOptions, trackPageViewArg) => {
|
|
4084
4232
|
if (!token) {
|
|
4085
4233
|
console.warn("Mixpanel token not provided for initialization. Mixpanel will not be enabled.");
|
|
4234
|
+
reportMixpanelWarning("init_missing_token", "Mixpanel init skipped: missing token", {
|
|
4235
|
+
operation: "init",
|
|
4236
|
+
hasToken: false
|
|
4237
|
+
});
|
|
4086
4238
|
return;
|
|
4087
4239
|
}
|
|
4088
4240
|
if (isMixpanelInitialized) {
|
|
@@ -4130,25 +4282,61 @@ var initializeCoreMixpanel = (token, debugOrOptions, trackPageViewArg) => {
|
|
|
4130
4282
|
initOptions[key] = sessionOpts[key];
|
|
4131
4283
|
}
|
|
4132
4284
|
});
|
|
4133
|
-
|
|
4134
|
-
|
|
4285
|
+
try {
|
|
4286
|
+
mixpanel__default.default.init(token, initOptions);
|
|
4287
|
+
isMixpanelInitialized = true;
|
|
4288
|
+
} catch (err) {
|
|
4289
|
+
reportMixpanelError("init_failed", err, {
|
|
4290
|
+
operation: "init",
|
|
4291
|
+
hasToken: true,
|
|
4292
|
+
persistence: initOptions.persistence,
|
|
4293
|
+
trackPageView: initOptions.track_pageview
|
|
4294
|
+
});
|
|
4295
|
+
return;
|
|
4296
|
+
}
|
|
4135
4297
|
if (initOptions.debug) {
|
|
4136
4298
|
console.log("Mixpanel initialized in dashboard-core.");
|
|
4137
4299
|
}
|
|
4138
4300
|
};
|
|
4139
4301
|
var trackCorePageView = (pageName, properties) => {
|
|
4140
|
-
if (!isMixpanelInitialized)
|
|
4141
|
-
|
|
4302
|
+
if (!isMixpanelInitialized) {
|
|
4303
|
+
reportMixpanelWarning("track_pageview_not_initialized", "Mixpanel not initialized: page view dropped", {
|
|
4304
|
+
operation: "track_pageview",
|
|
4305
|
+
pageName
|
|
4306
|
+
});
|
|
4307
|
+
return;
|
|
4308
|
+
}
|
|
4309
|
+
try {
|
|
4310
|
+
mixpanel__default.default.track("Page View", { page: pageName, ...properties });
|
|
4311
|
+
} catch (err) {
|
|
4312
|
+
reportMixpanelError("track_pageview_failed", err, {
|
|
4313
|
+
operation: "track_pageview",
|
|
4314
|
+
pageName
|
|
4315
|
+
});
|
|
4316
|
+
}
|
|
4142
4317
|
};
|
|
4143
4318
|
var trackCoreEvent = (eventName, properties) => {
|
|
4144
|
-
if (!isMixpanelInitialized)
|
|
4319
|
+
if (!isMixpanelInitialized) {
|
|
4320
|
+
reportMixpanelWarning("track_event_not_initialized", "Mixpanel not initialized: event dropped", {
|
|
4321
|
+
operation: "track_event",
|
|
4322
|
+
eventName
|
|
4323
|
+
});
|
|
4324
|
+
return;
|
|
4325
|
+
}
|
|
4145
4326
|
const mergedProps = {
|
|
4146
4327
|
// Precedence order: explicit properties passed by caller should override
|
|
4147
4328
|
// automatically appended user properties to avoid accidental overwrites.
|
|
4148
4329
|
...currentUserProperties || {},
|
|
4149
4330
|
...properties || {}
|
|
4150
4331
|
};
|
|
4151
|
-
|
|
4332
|
+
try {
|
|
4333
|
+
mixpanel__default.default.track(eventName, mergedProps);
|
|
4334
|
+
} catch (err) {
|
|
4335
|
+
reportMixpanelError("track_event_failed", err, {
|
|
4336
|
+
operation: "track_event",
|
|
4337
|
+
eventName
|
|
4338
|
+
});
|
|
4339
|
+
}
|
|
4152
4340
|
};
|
|
4153
4341
|
var startCoreSessionRecording = () => {
|
|
4154
4342
|
try {
|
|
@@ -4158,6 +4346,9 @@ var startCoreSessionRecording = () => {
|
|
|
4158
4346
|
}
|
|
4159
4347
|
} catch (err) {
|
|
4160
4348
|
console.error("[Mixpanel] Unable to start session recording:", err);
|
|
4349
|
+
reportMixpanelError("start_session_recording_failed", err, {
|
|
4350
|
+
operation: "start_session_recording"
|
|
4351
|
+
});
|
|
4161
4352
|
}
|
|
4162
4353
|
};
|
|
4163
4354
|
var stopCoreSessionRecording = () => {
|
|
@@ -4168,6 +4359,9 @@ var stopCoreSessionRecording = () => {
|
|
|
4168
4359
|
}
|
|
4169
4360
|
} catch (err) {
|
|
4170
4361
|
console.error("[Mixpanel] Unable to stop session recording:", err);
|
|
4362
|
+
reportMixpanelError("stop_session_recording_failed", err, {
|
|
4363
|
+
operation: "stop_session_recording"
|
|
4364
|
+
});
|
|
4171
4365
|
}
|
|
4172
4366
|
};
|
|
4173
4367
|
var getCoreSessionRecordingProperties = () => {
|
|
@@ -4191,16 +4385,38 @@ var getCoreSessionReplayUrl = () => {
|
|
|
4191
4385
|
return null;
|
|
4192
4386
|
};
|
|
4193
4387
|
var identifyCoreUser = (userId, userProperties) => {
|
|
4194
|
-
if (!isMixpanelInitialized)
|
|
4195
|
-
|
|
4196
|
-
|
|
4197
|
-
|
|
4388
|
+
if (!isMixpanelInitialized) {
|
|
4389
|
+
reportMixpanelWarning("identify_not_initialized", "Mixpanel not initialized: identify dropped", {
|
|
4390
|
+
operation: "identify",
|
|
4391
|
+
userIdPresent: Boolean(userId),
|
|
4392
|
+
hasUserProperties: Boolean(userProperties)
|
|
4393
|
+
});
|
|
4394
|
+
return;
|
|
4395
|
+
}
|
|
4396
|
+
try {
|
|
4397
|
+
mixpanel__default.default.identify(userId);
|
|
4398
|
+
if (userProperties) {
|
|
4399
|
+
mixpanel__default.default.people.set(userProperties);
|
|
4400
|
+
}
|
|
4401
|
+
} catch (err) {
|
|
4402
|
+
reportMixpanelError("identify_failed", err, {
|
|
4403
|
+
operation: "identify",
|
|
4404
|
+
userIdPresent: Boolean(userId),
|
|
4405
|
+
hasUserProperties: Boolean(userProperties)
|
|
4406
|
+
});
|
|
4407
|
+
return;
|
|
4198
4408
|
}
|
|
4199
4409
|
currentUserProperties = { ...userProperties };
|
|
4200
4410
|
};
|
|
4201
4411
|
var resetCoreMixpanel = () => {
|
|
4202
4412
|
if (!isMixpanelInitialized) return;
|
|
4203
|
-
|
|
4413
|
+
try {
|
|
4414
|
+
mixpanel__default.default.reset();
|
|
4415
|
+
} catch (err) {
|
|
4416
|
+
reportMixpanelError("reset_failed", err, {
|
|
4417
|
+
operation: "reset"
|
|
4418
|
+
});
|
|
4419
|
+
}
|
|
4204
4420
|
};
|
|
4205
4421
|
|
|
4206
4422
|
// src/lib/services/sseClient.ts
|
|
@@ -9681,7 +9897,11 @@ var useLineWorkspaceMetrics = (lineId, options) => {
|
|
|
9681
9897
|
trend: item.trend_score === 1 ? 2 : 0,
|
|
9682
9898
|
predicted_output: item.ideal_output || 0,
|
|
9683
9899
|
efficiency: item.efficiency || 0,
|
|
9684
|
-
action_threshold: item.total_day_output || 0
|
|
9900
|
+
action_threshold: item.total_day_output || 0,
|
|
9901
|
+
idle_time: item.idle_time ?? void 0,
|
|
9902
|
+
idle_time_hourly: item.idle_time_hourly || null,
|
|
9903
|
+
shift_start: item.shift_start || void 0,
|
|
9904
|
+
shift_end: item.shift_end || void 0
|
|
9685
9905
|
})).sort((a, b) => a.workspace_name.localeCompare(b.workspace_name));
|
|
9686
9906
|
setWorkspaces(transformedData);
|
|
9687
9907
|
setInitialized(true);
|
|
@@ -10611,23 +10831,29 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId, userAccessibleLineIds
|
|
|
10611
10831
|
workspaceMetricsStore.setDetailed(detailedMetrics);
|
|
10612
10832
|
}
|
|
10613
10833
|
});
|
|
10614
|
-
const transformedWorkspaceData = allWorkspaceMetrics.map((item) =>
|
|
10615
|
-
|
|
10616
|
-
|
|
10617
|
-
|
|
10618
|
-
|
|
10619
|
-
|
|
10620
|
-
|
|
10621
|
-
|
|
10622
|
-
|
|
10623
|
-
|
|
10624
|
-
|
|
10625
|
-
|
|
10626
|
-
|
|
10627
|
-
|
|
10628
|
-
|
|
10629
|
-
|
|
10630
|
-
|
|
10834
|
+
const transformedWorkspaceData = allWorkspaceMetrics.map((item) => {
|
|
10835
|
+
const idleTimeValue = typeof item.idle_time === "number" ? item.idle_time : Number(item.idle_time);
|
|
10836
|
+
const idleTimeSeconds = Number.isFinite(idleTimeValue) ? idleTimeValue : void 0;
|
|
10837
|
+
return {
|
|
10838
|
+
company_id: item.company_id || companyId,
|
|
10839
|
+
line_id: item.line_id,
|
|
10840
|
+
shift_id: item.shift_id,
|
|
10841
|
+
date: item.date,
|
|
10842
|
+
workspace_uuid: item.workspace_id,
|
|
10843
|
+
workspace_name: item.workspace_name,
|
|
10844
|
+
action_count: item.total_output || 0,
|
|
10845
|
+
pph: item.avg_pph || 0,
|
|
10846
|
+
performance_score: item.performance_score || 0,
|
|
10847
|
+
avg_cycle_time: item.avg_cycle_time || 0,
|
|
10848
|
+
trend: item.trend_score === 1 ? 2 : 0,
|
|
10849
|
+
predicted_output: item.ideal_output || 0,
|
|
10850
|
+
efficiency: item.efficiency || 0,
|
|
10851
|
+
action_threshold: item.total_day_output || 0,
|
|
10852
|
+
show_exclamation: item.show_exclamation ?? void 0,
|
|
10853
|
+
monitoring_mode: item.monitoring_mode ?? void 0,
|
|
10854
|
+
idle_time: idleTimeSeconds
|
|
10855
|
+
};
|
|
10856
|
+
}).sort((a, b) => {
|
|
10631
10857
|
if (a.line_id !== b.line_id) return a.line_id.localeCompare(b.line_id);
|
|
10632
10858
|
const wsNumA = parseInt(a.workspace_name?.replace(/[^0-9]/g, "") || "0");
|
|
10633
10859
|
const wsNumB = parseInt(b.workspace_name?.replace(/[^0-9]/g, "") || "0");
|
|
@@ -11472,7 +11698,8 @@ var useRealtimeLineMetrics = ({
|
|
|
11472
11698
|
factory: {
|
|
11473
11699
|
id: lineDetailsPayload.factory_id || "",
|
|
11474
11700
|
factory_name: lineDetailsPayload.factory_name || ""
|
|
11475
|
-
}
|
|
11701
|
+
},
|
|
11702
|
+
monitoring_mode: lineDetailsPayload.monitoring_mode ?? void 0
|
|
11476
11703
|
});
|
|
11477
11704
|
} else {
|
|
11478
11705
|
setLineDetails(null);
|
|
@@ -11499,7 +11726,8 @@ var useRealtimeLineMetrics = ({
|
|
|
11499
11726
|
shift_start: "06:00",
|
|
11500
11727
|
shift_end: "14:00",
|
|
11501
11728
|
last_updated: (/* @__PURE__ */ new Date()).toISOString(),
|
|
11502
|
-
poorest_performing_workspaces: poorestPerformingWorkspaces
|
|
11729
|
+
poorest_performing_workspaces: poorestPerformingWorkspaces,
|
|
11730
|
+
idle_time_hourly: {}
|
|
11503
11731
|
});
|
|
11504
11732
|
} else {
|
|
11505
11733
|
setMetrics({
|
|
@@ -16108,70 +16336,121 @@ function useHasLineAccess(lineId, configLineIds) {
|
|
|
16108
16336
|
return accessibleLineIds.includes(lineId);
|
|
16109
16337
|
}, [lineId, accessibleLineIds]);
|
|
16110
16338
|
}
|
|
16111
|
-
function useLineSupervisor(lineId) {
|
|
16339
|
+
function useLineSupervisor(lineId, options) {
|
|
16112
16340
|
const supabase = useSupabase();
|
|
16341
|
+
const entityConfig = useEntityConfig();
|
|
16342
|
+
const enabled = options?.enabled ?? true;
|
|
16343
|
+
const useBackend = options?.useBackend ?? true;
|
|
16344
|
+
const resolvedCompanyId = options?.companyId || entityConfig.companyId;
|
|
16113
16345
|
const [supervisor, setSupervisor] = React26.useState(null);
|
|
16114
16346
|
const [supervisors, setSupervisors] = React26.useState([]);
|
|
16115
16347
|
const [isLoading, setIsLoading] = React26.useState(true);
|
|
16116
16348
|
const [error, setError] = React26.useState(null);
|
|
16117
16349
|
const fetchSupervisor = React26.useCallback(async () => {
|
|
16118
|
-
if (!lineId || !supabase) {
|
|
16350
|
+
if (!enabled || !lineId || !supabase) {
|
|
16119
16351
|
setIsLoading(false);
|
|
16120
16352
|
return;
|
|
16121
16353
|
}
|
|
16122
16354
|
try {
|
|
16123
16355
|
setIsLoading(true);
|
|
16124
16356
|
setError(null);
|
|
16125
|
-
const
|
|
16126
|
-
|
|
16127
|
-
|
|
16128
|
-
|
|
16129
|
-
|
|
16130
|
-
|
|
16131
|
-
|
|
16132
|
-
|
|
16133
|
-
|
|
16134
|
-
|
|
16357
|
+
const mapSupervisor = (row) => {
|
|
16358
|
+
const email = row.email || "";
|
|
16359
|
+
let displayName;
|
|
16360
|
+
if (row.first_name) {
|
|
16361
|
+
displayName = row.last_name ? `${row.first_name} ${row.last_name}` : row.first_name;
|
|
16362
|
+
} else {
|
|
16363
|
+
displayName = (typeof email === "string" && email.includes("@") ? email.split("@")[0] : email) || email;
|
|
16364
|
+
}
|
|
16365
|
+
return {
|
|
16366
|
+
userId: row.user_id,
|
|
16367
|
+
email,
|
|
16368
|
+
displayName,
|
|
16369
|
+
profilePhotoUrl: row.profile_photo_url
|
|
16370
|
+
};
|
|
16371
|
+
};
|
|
16372
|
+
const fetchFromBackend = async () => {
|
|
16373
|
+
if (!resolvedCompanyId) {
|
|
16374
|
+
throw new Error("Company ID is not configured");
|
|
16375
|
+
}
|
|
16376
|
+
const searchParams = new URLSearchParams({
|
|
16377
|
+
company_id: resolvedCompanyId,
|
|
16378
|
+
line_ids: lineId
|
|
16135
16379
|
});
|
|
16136
|
-
|
|
16137
|
-
|
|
16138
|
-
|
|
16139
|
-
|
|
16140
|
-
|
|
16141
|
-
|
|
16142
|
-
|
|
16143
|
-
|
|
16144
|
-
|
|
16145
|
-
|
|
16146
|
-
|
|
16147
|
-
|
|
16148
|
-
|
|
16149
|
-
|
|
16380
|
+
const data = await fetchBackendJson(supabase, `/api/dashboard/line-supervisors?${searchParams.toString()}`);
|
|
16381
|
+
const supervisorsForLine = (data?.supervisors || []).filter((row) => Array.isArray(row.line_ids) && row.line_ids.includes(lineId)).map(mapSupervisor);
|
|
16382
|
+
setSupervisors(supervisorsForLine);
|
|
16383
|
+
setSupervisor(supervisorsForLine[0] || null);
|
|
16384
|
+
};
|
|
16385
|
+
const fetchFromSupabase = async () => {
|
|
16386
|
+
const { data, error: fetchError } = await supabase.from("user_roles").select("user_id, email, first_name, last_name, properties, profile_photo_url").eq("role_level", "supervisor");
|
|
16387
|
+
if (fetchError) {
|
|
16388
|
+
console.error("[useLineSupervisor] Query error:", fetchError);
|
|
16389
|
+
throw fetchError;
|
|
16390
|
+
}
|
|
16391
|
+
if (data && data.length > 0) {
|
|
16392
|
+
const supervisorsForLine = data.filter((supervisorData) => {
|
|
16393
|
+
const lineIds = supervisorData.properties?.line_id || supervisorData.properties?.line_ids || [];
|
|
16394
|
+
const isAssigned = Array.isArray(lineIds) && lineIds.includes(lineId);
|
|
16395
|
+
return isAssigned;
|
|
16150
16396
|
});
|
|
16151
|
-
|
|
16152
|
-
|
|
16397
|
+
if (supervisorsForLine.length > 0) {
|
|
16398
|
+
const allSupervisors = supervisorsForLine.map(mapSupervisor);
|
|
16399
|
+
setSupervisors(allSupervisors);
|
|
16400
|
+
setSupervisor(allSupervisors[0]);
|
|
16401
|
+
} else {
|
|
16402
|
+
setSupervisors([]);
|
|
16403
|
+
setSupervisor(null);
|
|
16404
|
+
}
|
|
16153
16405
|
} else {
|
|
16154
16406
|
setSupervisors([]);
|
|
16155
16407
|
setSupervisor(null);
|
|
16156
16408
|
}
|
|
16409
|
+
};
|
|
16410
|
+
if (useBackend && resolvedCompanyId) {
|
|
16411
|
+
await fetchFromBackend();
|
|
16157
16412
|
} else {
|
|
16158
|
-
|
|
16159
|
-
setSupervisor(null);
|
|
16413
|
+
await fetchFromSupabase();
|
|
16160
16414
|
}
|
|
16161
16415
|
} catch (err) {
|
|
16162
16416
|
console.error("[useLineSupervisor] Error fetching supervisors:", err);
|
|
16163
|
-
|
|
16164
|
-
|
|
16165
|
-
|
|
16417
|
+
try {
|
|
16418
|
+
if (!useBackend) {
|
|
16419
|
+
throw err;
|
|
16420
|
+
}
|
|
16421
|
+
await (async () => {
|
|
16422
|
+
const { data } = await supabase.from("user_roles").select("user_id, email, first_name, last_name, properties, profile_photo_url").eq("role_level", "supervisor");
|
|
16423
|
+
const supervisorsForLine = (data || []).filter((supervisorData) => {
|
|
16424
|
+
const lineIds = supervisorData.properties?.line_id || supervisorData.properties?.line_ids || [];
|
|
16425
|
+
return Array.isArray(lineIds) && lineIds.includes(lineId);
|
|
16426
|
+
}).map((row) => {
|
|
16427
|
+
const email = row.email || "";
|
|
16428
|
+
const displayName = row.first_name ? row.last_name ? `${row.first_name} ${row.last_name}` : row.first_name : (typeof email === "string" && email.includes("@") ? email.split("@")[0] : email) || email;
|
|
16429
|
+
return {
|
|
16430
|
+
userId: row.user_id,
|
|
16431
|
+
email,
|
|
16432
|
+
displayName,
|
|
16433
|
+
profilePhotoUrl: row.profile_photo_url
|
|
16434
|
+
};
|
|
16435
|
+
});
|
|
16436
|
+
setSupervisors(supervisorsForLine);
|
|
16437
|
+
setSupervisor(supervisorsForLine[0] || null);
|
|
16438
|
+
})();
|
|
16439
|
+
} catch (fallbackError) {
|
|
16440
|
+
console.error("[useLineSupervisor] Fallback supervisor fetch failed:", fallbackError);
|
|
16441
|
+
setError(fallbackError instanceof Error ? fallbackError : new Error("Failed to fetch supervisors"));
|
|
16442
|
+
setSupervisors([]);
|
|
16443
|
+
setSupervisor(null);
|
|
16444
|
+
}
|
|
16166
16445
|
} finally {
|
|
16167
16446
|
setIsLoading(false);
|
|
16168
16447
|
}
|
|
16169
|
-
}, [lineId, supabase]);
|
|
16448
|
+
}, [enabled, lineId, supabase, useBackend, resolvedCompanyId]);
|
|
16170
16449
|
React26.useEffect(() => {
|
|
16171
16450
|
fetchSupervisor();
|
|
16172
16451
|
}, [fetchSupervisor]);
|
|
16173
16452
|
React26.useEffect(() => {
|
|
16174
|
-
if (!lineId || !supabase) {
|
|
16453
|
+
if (!enabled || !lineId || !supabase) {
|
|
16175
16454
|
return;
|
|
16176
16455
|
}
|
|
16177
16456
|
let channel = null;
|
|
@@ -16196,7 +16475,7 @@ function useLineSupervisor(lineId) {
|
|
|
16196
16475
|
supabase.removeChannel(channel);
|
|
16197
16476
|
}
|
|
16198
16477
|
};
|
|
16199
|
-
}, [lineId, supabase, fetchSupervisor]);
|
|
16478
|
+
}, [enabled, lineId, supabase, fetchSupervisor]);
|
|
16200
16479
|
const supervisorName = supervisors.length > 0 ? supervisors.map((s) => s.displayName).join(", ") : null;
|
|
16201
16480
|
return {
|
|
16202
16481
|
supervisorName,
|
|
@@ -19722,37 +20001,6 @@ var videoPreloader = new VideoPreloader();
|
|
|
19722
20001
|
var preloadVideoUrl = videoPreloader.preloadVideo;
|
|
19723
20002
|
var preloadVideosUrl = videoPreloader.preloadVideos;
|
|
19724
20003
|
|
|
19725
|
-
// src/lib/utils/rateLimit.ts
|
|
19726
|
-
var rateLimitMap2 = /* @__PURE__ */ new Map();
|
|
19727
|
-
function checkRateLimit2(identifier, options = {}) {
|
|
19728
|
-
const windowMs = options.windowMs || 60 * 1e3;
|
|
19729
|
-
const maxRequests = options.maxRequests || 3;
|
|
19730
|
-
const now4 = Date.now();
|
|
19731
|
-
const userLimit = rateLimitMap2.get(identifier);
|
|
19732
|
-
if (userLimit && userLimit.resetTime < now4) {
|
|
19733
|
-
rateLimitMap2.delete(identifier);
|
|
19734
|
-
}
|
|
19735
|
-
if (!userLimit || userLimit.resetTime < now4) {
|
|
19736
|
-
rateLimitMap2.set(identifier, {
|
|
19737
|
-
count: 1,
|
|
19738
|
-
resetTime: now4 + windowMs
|
|
19739
|
-
});
|
|
19740
|
-
return { allowed: true };
|
|
19741
|
-
}
|
|
19742
|
-
if (userLimit.count >= maxRequests) {
|
|
19743
|
-
const retryAfter = Math.ceil((userLimit.resetTime - now4) / 1e3);
|
|
19744
|
-
return { allowed: false, retryAfter };
|
|
19745
|
-
}
|
|
19746
|
-
userLimit.count++;
|
|
19747
|
-
return { allowed: true };
|
|
19748
|
-
}
|
|
19749
|
-
function clearRateLimit2(identifier) {
|
|
19750
|
-
rateLimitMap2.delete(identifier);
|
|
19751
|
-
}
|
|
19752
|
-
function clearAllRateLimits2() {
|
|
19753
|
-
rateLimitMap2.clear();
|
|
19754
|
-
}
|
|
19755
|
-
|
|
19756
20004
|
// src/lib/utils/s3VideoPreloader.ts
|
|
19757
20005
|
var videoCache = /* @__PURE__ */ new Map();
|
|
19758
20006
|
var MAX_CONCURRENT_PRELOADS = 2;
|
|
@@ -20020,59 +20268,6 @@ var createThrottledReload = (interval = 5e3, maxReloads = 3) => {
|
|
|
20020
20268
|
};
|
|
20021
20269
|
var throttledReloadDashboard = createThrottledReload(5e3, 3);
|
|
20022
20270
|
|
|
20023
|
-
// src/lib/utils/sentryContext.ts
|
|
20024
|
-
function getSentry() {
|
|
20025
|
-
try {
|
|
20026
|
-
return __require("@sentry/nextjs");
|
|
20027
|
-
} catch {
|
|
20028
|
-
return null;
|
|
20029
|
-
}
|
|
20030
|
-
}
|
|
20031
|
-
function setSentryUserContext(user) {
|
|
20032
|
-
const sentry = getSentry();
|
|
20033
|
-
if (!sentry) return;
|
|
20034
|
-
if (user) {
|
|
20035
|
-
sentry.setUser({
|
|
20036
|
-
id: user.id,
|
|
20037
|
-
email: user.email
|
|
20038
|
-
});
|
|
20039
|
-
sentry.setTags({
|
|
20040
|
-
company_id: user.company_id || "unknown",
|
|
20041
|
-
role: user.role || "unknown",
|
|
20042
|
-
role_level: user.role_level || "unknown"
|
|
20043
|
-
});
|
|
20044
|
-
} else {
|
|
20045
|
-
sentry.setUser(null);
|
|
20046
|
-
sentry.setTags({
|
|
20047
|
-
company_id: void 0,
|
|
20048
|
-
role: void 0,
|
|
20049
|
-
role_level: void 0
|
|
20050
|
-
});
|
|
20051
|
-
}
|
|
20052
|
-
}
|
|
20053
|
-
function setSentryWorkspaceContext(config) {
|
|
20054
|
-
const sentry = getSentry();
|
|
20055
|
-
if (!sentry) return;
|
|
20056
|
-
sentry.setTags({
|
|
20057
|
-
workspace_company: config.companyId || "unknown",
|
|
20058
|
-
workspace_factory: config.factoryId || "unknown",
|
|
20059
|
-
factory_name: config.factoryName || "unknown"
|
|
20060
|
-
});
|
|
20061
|
-
}
|
|
20062
|
-
function clearSentryContext() {
|
|
20063
|
-
const sentry = getSentry();
|
|
20064
|
-
if (!sentry) return;
|
|
20065
|
-
sentry.setUser(null);
|
|
20066
|
-
sentry.setTags({
|
|
20067
|
-
company_id: void 0,
|
|
20068
|
-
role: void 0,
|
|
20069
|
-
role_level: void 0,
|
|
20070
|
-
workspace_company: void 0,
|
|
20071
|
-
workspace_factory: void 0,
|
|
20072
|
-
factory_name: void 0
|
|
20073
|
-
});
|
|
20074
|
-
}
|
|
20075
|
-
|
|
20076
20271
|
// src/lib/utils/index.ts
|
|
20077
20272
|
var formatIdleTime = (idleTimeInSeconds) => {
|
|
20078
20273
|
if (!idleTimeInSeconds || idleTimeInSeconds <= 0) {
|
|
@@ -32164,6 +32359,29 @@ var buildUptimeSeries = ({
|
|
|
32164
32359
|
hasData: activeMinutes + idleMinutes > 0
|
|
32165
32360
|
};
|
|
32166
32361
|
};
|
|
32362
|
+
var getUptimeUtilizationPercent = (shift) => {
|
|
32363
|
+
const efficiency = shift.efficiency;
|
|
32364
|
+
if (Number.isFinite(efficiency)) {
|
|
32365
|
+
return Math.round(Math.max(0, Math.min(100, Number(efficiency))));
|
|
32366
|
+
}
|
|
32367
|
+
const idleSeconds = Number.isFinite(shift.idleTime) ? Number(shift.idleTime) : 0;
|
|
32368
|
+
const activeSeconds = Number.isFinite(shift.activeTimeSeconds) ? Number(shift.activeTimeSeconds) : null;
|
|
32369
|
+
let availableSeconds = Number.isFinite(shift.availableTimeSeconds) ? Number(shift.availableTimeSeconds) : null;
|
|
32370
|
+
if (availableSeconds === null) {
|
|
32371
|
+
if ((activeSeconds ?? 0) > 0 || idleSeconds > 0) {
|
|
32372
|
+
availableSeconds = (activeSeconds ?? 0) + idleSeconds;
|
|
32373
|
+
} else {
|
|
32374
|
+
return 0;
|
|
32375
|
+
}
|
|
32376
|
+
}
|
|
32377
|
+
if (availableSeconds <= 0) return 0;
|
|
32378
|
+
const clampedIdleSeconds = Math.min(Math.max(idleSeconds, 0), availableSeconds);
|
|
32379
|
+
const productiveSeconds = Math.max(
|
|
32380
|
+
activeSeconds ?? availableSeconds - clampedIdleSeconds,
|
|
32381
|
+
0
|
|
32382
|
+
);
|
|
32383
|
+
return Math.round(productiveSeconds / availableSeconds * 100);
|
|
32384
|
+
};
|
|
32167
32385
|
var getTimeFromTimeString = (timeStr) => {
|
|
32168
32386
|
if (!timeStr) {
|
|
32169
32387
|
return { hour: 0, minute: 0, decimalHour: 0 };
|
|
@@ -32178,6 +32396,7 @@ var getTimeFromTimeString = (timeStr) => {
|
|
|
32178
32396
|
};
|
|
32179
32397
|
var HourlyUptimeChartComponent = ({
|
|
32180
32398
|
idleTimeHourly,
|
|
32399
|
+
hourlyAggregates,
|
|
32181
32400
|
shiftStart,
|
|
32182
32401
|
shiftEnd,
|
|
32183
32402
|
shiftDate,
|
|
@@ -32195,6 +32414,7 @@ var HourlyUptimeChartComponent = ({
|
|
|
32195
32414
|
timezone,
|
|
32196
32415
|
elapsedMinutes
|
|
32197
32416
|
}), [idleTimeHourly, shiftStart, shiftEnd, shiftDate, timezone, elapsedMinutes]);
|
|
32417
|
+
const hasAggregateData = Boolean(hourlyAggregates && hourlyAggregates.length > 0);
|
|
32198
32418
|
const shiftStartTime = React26__namespace.default.useMemo(
|
|
32199
32419
|
() => getTimeFromTimeString(shiftStart),
|
|
32200
32420
|
[shiftStart]
|
|
@@ -32261,7 +32481,20 @@ var HourlyUptimeChartComponent = ({
|
|
|
32261
32481
|
return `${formatTime5(startHour, startMinute)} - ${formatTime5(endHour, endMinute)}`;
|
|
32262
32482
|
}, [shiftDuration, shiftStartTime.decimalHour, shiftEndTime]);
|
|
32263
32483
|
const chartData = React26__namespace.default.useMemo(() => {
|
|
32264
|
-
if (
|
|
32484
|
+
if (shiftDuration <= 0) return [];
|
|
32485
|
+
if (hasAggregateData) {
|
|
32486
|
+
return hourlyAggregates.map((entry, hourIndex) => ({
|
|
32487
|
+
hourIndex,
|
|
32488
|
+
hour: formatHour(hourIndex),
|
|
32489
|
+
timeRange: formatTimeRange2(hourIndex),
|
|
32490
|
+
idleMinutes: entry.idleMinutes ?? 0,
|
|
32491
|
+
productiveMinutes: entry.productiveMinutes ?? 0,
|
|
32492
|
+
productivePercent: Math.max(0, Math.min(100, entry.productivePercent)),
|
|
32493
|
+
idlePercent: Math.max(0, Math.min(100, entry.idlePercent)),
|
|
32494
|
+
idleArray: []
|
|
32495
|
+
}));
|
|
32496
|
+
}
|
|
32497
|
+
if (!uptimeSeries.points.length) return [];
|
|
32265
32498
|
const elapsedShiftMinutes = uptimeSeries.elapsedMinutes ?? uptimeSeries.shiftMinutes;
|
|
32266
32499
|
return Array.from({ length: shiftDuration }, (_, hourIndex) => {
|
|
32267
32500
|
const start = hourIndex * 60;
|
|
@@ -32286,7 +32519,7 @@ var HourlyUptimeChartComponent = ({
|
|
|
32286
32519
|
idleArray
|
|
32287
32520
|
};
|
|
32288
32521
|
});
|
|
32289
|
-
}, [uptimeSeries.points, uptimeSeries.elapsedMinutes, uptimeSeries.shiftMinutes, shiftDuration, formatHour, formatTimeRange2]);
|
|
32522
|
+
}, [hasAggregateData, hourlyAggregates, uptimeSeries.points, uptimeSeries.elapsedMinutes, uptimeSeries.shiftMinutes, shiftDuration, formatHour, formatTimeRange2]);
|
|
32290
32523
|
const maxYValue = 100;
|
|
32291
32524
|
const yAxisTicks = [0, 25, 50, 75, 100];
|
|
32292
32525
|
React26__namespace.default.useEffect(() => {
|
|
@@ -32311,7 +32544,7 @@ var HourlyUptimeChartComponent = ({
|
|
|
32311
32544
|
clearTimeout(fallbackTimeout);
|
|
32312
32545
|
};
|
|
32313
32546
|
}, []);
|
|
32314
|
-
if (!uptimeSeries.hasData) {
|
|
32547
|
+
if (!hasAggregateData && !uptimeSeries.hasData) {
|
|
32315
32548
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: `w-full h-full flex items-center justify-center text-sm text-gray-500 ${className}`, children: "No uptime data available." });
|
|
32316
32549
|
}
|
|
32317
32550
|
const renderLegend = () => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center text-sm text-gray-600 bg-white py-1", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-4 border border-gray-100 rounded-full px-3 py-1", children: [
|
|
@@ -32377,6 +32610,27 @@ var HourlyUptimeChartComponent = ({
|
|
|
32377
32610
|
content: (props) => {
|
|
32378
32611
|
if (!props.active || !props.payload || props.payload.length === 0) return null;
|
|
32379
32612
|
const data = props.payload[0].payload;
|
|
32613
|
+
if (hasAggregateData) {
|
|
32614
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-white rounded-xl shadow-xl border border-gray-100 p-4 min-w-[220px]", children: [
|
|
32615
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-between mb-3", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-semibold text-gray-900 text-sm", children: data.timeRange }) }),
|
|
32616
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
|
|
32617
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
|
|
32618
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-gray-500", children: "Productive" }),
|
|
32619
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-semibold text-gray-900 text-sm", children: [
|
|
32620
|
+
Number(data.productivePercent || 0).toFixed(2),
|
|
32621
|
+
"%"
|
|
32622
|
+
] })
|
|
32623
|
+
] }),
|
|
32624
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
|
|
32625
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-gray-500", children: "Idle Time" }),
|
|
32626
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-semibold text-orange-600 text-sm", children: [
|
|
32627
|
+
Number(data.idlePercent || 0).toFixed(2),
|
|
32628
|
+
"%"
|
|
32629
|
+
] })
|
|
32630
|
+
] })
|
|
32631
|
+
] })
|
|
32632
|
+
] });
|
|
32633
|
+
}
|
|
32380
32634
|
const idleRanges = [];
|
|
32381
32635
|
if (data.idleArray) {
|
|
32382
32636
|
let currentRange = null;
|
|
@@ -41498,7 +41752,7 @@ var DEFAULT_LINE_SHIFT_DATA = {
|
|
|
41498
41752
|
var getLineShiftData = (day, shiftId) => {
|
|
41499
41753
|
const shift = day.shifts[shiftId];
|
|
41500
41754
|
if (shift) {
|
|
41501
|
-
return { ...shift
|
|
41755
|
+
return { ...shift };
|
|
41502
41756
|
}
|
|
41503
41757
|
return { ...DEFAULT_LINE_SHIFT_DATA };
|
|
41504
41758
|
};
|
|
@@ -41510,6 +41764,7 @@ var LineHistoryCalendar = ({
|
|
|
41510
41764
|
lineId,
|
|
41511
41765
|
selectedShiftId,
|
|
41512
41766
|
legend,
|
|
41767
|
+
monitoringMode,
|
|
41513
41768
|
rangeStart,
|
|
41514
41769
|
rangeEnd,
|
|
41515
41770
|
onDateSelect,
|
|
@@ -41519,6 +41774,7 @@ var LineHistoryCalendar = ({
|
|
|
41519
41774
|
const { dateTimeConfig } = useDashboardConfig();
|
|
41520
41775
|
const configuredTimezone = dateTimeConfig?.defaultTimezone || "Asia/Kolkata";
|
|
41521
41776
|
const effectiveLegend = legend || DEFAULT_EFFICIENCY_LEGEND;
|
|
41777
|
+
const isUptimeMode = monitoringMode === "uptime";
|
|
41522
41778
|
const todayInZone = React26.useMemo(() => {
|
|
41523
41779
|
const currentTimeInZone = getCurrentTimeInZone(configuredTimezone);
|
|
41524
41780
|
return typeof currentTimeInZone === "string" ? new Date(currentTimeInZone) : currentTimeInZone;
|
|
@@ -41588,7 +41844,11 @@ var LineHistoryCalendar = ({
|
|
|
41588
41844
|
const nowString = `${istNow.getFullYear()}-${String(istNow.getMonth() + 1).padStart(2, "0")}-${String(istNow.getDate()).padStart(2, "0")}`;
|
|
41589
41845
|
const dateString = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}-${String(date.getDate()).padStart(2, "0")}`;
|
|
41590
41846
|
if (dateString > nowString) return null;
|
|
41591
|
-
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 bg-black/80 rounded-md sm:rounded-lg p-1 sm:p-1.5 lg:p-2 text-white opacity-0 group-hover:opacity-100 transition-opacity", children: /* @__PURE__ */ jsxRuntime.
|
|
41847
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 bg-black/80 rounded-md sm:rounded-lg p-1 sm:p-1.5 lg:p-2 text-white opacity-0 group-hover:opacity-100 transition-opacity", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-[8px] sm:text-[10px] lg:text-xs space-y-0.5 sm:space-y-1", children: isUptimeMode ? /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
41848
|
+
"Utilization: ",
|
|
41849
|
+
Math.round(shift.avg_efficiency || 0),
|
|
41850
|
+
"%"
|
|
41851
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
41592
41852
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
41593
41853
|
"Eff: ",
|
|
41594
41854
|
Math.round(shift.avg_efficiency || 0),
|
|
@@ -41606,7 +41866,7 @@ var LineHistoryCalendar = ({
|
|
|
41606
41866
|
"/",
|
|
41607
41867
|
shift.total_workspaces || 0
|
|
41608
41868
|
] })
|
|
41609
|
-
] }) });
|
|
41869
|
+
] }) }) });
|
|
41610
41870
|
};
|
|
41611
41871
|
const renderDayCell = (day) => {
|
|
41612
41872
|
if (!day) return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-full border border-gray-100 dark:border-gray-700 rounded-md sm:rounded-lg bg-gray-50 dark:bg-gray-800" });
|
|
@@ -41880,42 +42140,88 @@ var DEFAULT_PERFORMANCE_DATA = {
|
|
|
41880
42140
|
total_workspaces: 0,
|
|
41881
42141
|
hasData: false,
|
|
41882
42142
|
output: 0,
|
|
41883
|
-
idealOutput: 0
|
|
42143
|
+
idealOutput: 0,
|
|
42144
|
+
idle_time_seconds: 0,
|
|
42145
|
+
active_time_seconds: 0,
|
|
42146
|
+
available_time_seconds: 0,
|
|
42147
|
+
avg_idle_time_seconds: 0
|
|
41884
42148
|
};
|
|
41885
42149
|
var getOrdinal = (n) => {
|
|
41886
42150
|
const suffix = ["th", "st", "nd", "rd"];
|
|
41887
42151
|
const v = n % 100;
|
|
41888
42152
|
return n + (suffix[(v - 20) % 10] || suffix[v] || suffix[0]);
|
|
41889
42153
|
};
|
|
41890
|
-
var CustomTooltip2 = ({ active, payload, label }) => {
|
|
41891
|
-
if (active
|
|
42154
|
+
var CustomTooltip2 = ({ active, payload, label, isUptimeMode }) => {
|
|
42155
|
+
if (!active || !payload || payload.length === 0) return null;
|
|
42156
|
+
if (isUptimeMode) {
|
|
42157
|
+
const productive = payload.find((item) => item.dataKey === "productivePercent")?.value ?? 0;
|
|
42158
|
+
const idle = payload.find((item) => item.dataKey === "idlePercent")?.value ?? 0;
|
|
42159
|
+
const total = productive + idle;
|
|
42160
|
+
const utilization = total > 0 ? Math.round(productive / total * 100) : 0;
|
|
41892
42161
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-white/95 backdrop-blur-sm p-3 rounded-lg shadow-lg border border-gray-100", children: [
|
|
41893
42162
|
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-semibold text-gray-800 mb-1", children: label }),
|
|
41894
42163
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
|
|
41895
42164
|
/* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-xs text-gray-600", children: [
|
|
41896
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: "
|
|
42165
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: "Productive:" }),
|
|
41897
42166
|
" ",
|
|
41898
|
-
|
|
41899
|
-
"
|
|
42167
|
+
productive.toFixed(1),
|
|
42168
|
+
"%"
|
|
41900
42169
|
] }),
|
|
41901
|
-
|
|
41902
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: "
|
|
42170
|
+
/* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-xs text-gray-600", children: [
|
|
42171
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: "Idle:" }),
|
|
42172
|
+
" ",
|
|
42173
|
+
idle.toFixed(1),
|
|
42174
|
+
"%"
|
|
42175
|
+
] }),
|
|
42176
|
+
/* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-xs text-gray-600", children: [
|
|
42177
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: "Utilization:" }),
|
|
41903
42178
|
" ",
|
|
41904
|
-
|
|
41905
|
-
"
|
|
42179
|
+
utilization,
|
|
42180
|
+
"%"
|
|
41906
42181
|
] })
|
|
41907
42182
|
] })
|
|
41908
42183
|
] });
|
|
41909
42184
|
}
|
|
41910
|
-
return
|
|
42185
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-white/95 backdrop-blur-sm p-3 rounded-lg shadow-lg border border-gray-100", children: [
|
|
42186
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-semibold text-gray-800 mb-1", children: label }),
|
|
42187
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
|
|
42188
|
+
/* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-xs text-gray-600", children: [
|
|
42189
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: "Actual:" }),
|
|
42190
|
+
" ",
|
|
42191
|
+
Math.round(payload[0].value),
|
|
42192
|
+
" units"
|
|
42193
|
+
] }),
|
|
42194
|
+
payload[0].payload.idealOutput > 0 && /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-xs text-gray-600", children: [
|
|
42195
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: "Target:" }),
|
|
42196
|
+
" ",
|
|
42197
|
+
Math.round(payload[0].payload.idealOutput),
|
|
42198
|
+
" units"
|
|
42199
|
+
] })
|
|
42200
|
+
] })
|
|
42201
|
+
] });
|
|
41911
42202
|
};
|
|
41912
42203
|
var getShiftData2 = (day, shiftId) => {
|
|
41913
42204
|
const shift = day.shifts[shiftId];
|
|
41914
42205
|
if (shift) {
|
|
41915
|
-
return { ...shift
|
|
42206
|
+
return { ...shift };
|
|
41916
42207
|
}
|
|
41917
42208
|
return { ...DEFAULT_PERFORMANCE_DATA };
|
|
41918
42209
|
};
|
|
42210
|
+
var getUptimeTotals = (shift, hasShiftData) => {
|
|
42211
|
+
if (!shift) {
|
|
42212
|
+
return { availableSeconds: 0, productiveSeconds: 0, idleSeconds: 0 };
|
|
42213
|
+
}
|
|
42214
|
+
const idleSecondsRaw = Math.max(shift.idle_time_seconds || 0, 0);
|
|
42215
|
+
const activeSecondsRaw = Math.max(shift.active_time_seconds || 0, 0);
|
|
42216
|
+
const knownSeconds = activeSecondsRaw + idleSecondsRaw;
|
|
42217
|
+
if (knownSeconds <= 0) {
|
|
42218
|
+
return { availableSeconds: 0, productiveSeconds: 0, idleSeconds: 0 };
|
|
42219
|
+
}
|
|
42220
|
+
const availableSeconds = knownSeconds;
|
|
42221
|
+
const idleSeconds = Math.min(idleSecondsRaw, availableSeconds);
|
|
42222
|
+
const productiveSeconds = activeSecondsRaw > 0 ? Math.min(activeSecondsRaw, availableSeconds) : Math.max(availableSeconds - idleSeconds, 0);
|
|
42223
|
+
return { availableSeconds, productiveSeconds, idleSeconds };
|
|
42224
|
+
};
|
|
41919
42225
|
var LineMonthlyHistory = ({
|
|
41920
42226
|
month,
|
|
41921
42227
|
year,
|
|
@@ -41925,6 +42231,7 @@ var LineMonthlyHistory = ({
|
|
|
41925
42231
|
rangeEnd,
|
|
41926
42232
|
timezone,
|
|
41927
42233
|
legend,
|
|
42234
|
+
monitoringMode,
|
|
41928
42235
|
underperformingWorkspaces = {},
|
|
41929
42236
|
lineId,
|
|
41930
42237
|
selectedShiftId = 0,
|
|
@@ -41941,6 +42248,7 @@ var LineMonthlyHistory = ({
|
|
|
41941
42248
|
const navigation = useNavigation();
|
|
41942
42249
|
const { isIdleTimeVlmEnabled } = useIdleTimeVlmConfig();
|
|
41943
42250
|
const idleTimeVlmEnabled = isIdleTimeVlmEnabled(lineId);
|
|
42251
|
+
const isUptimeMode = monitoringMode === "uptime";
|
|
41944
42252
|
const effectiveLegend = legend || DEFAULT_EFFICIENCY_LEGEND;
|
|
41945
42253
|
const chartKey = React26.useMemo(() => `${lineId}-${month}-${year}-${selectedShiftId}-${rangeStart}-${rangeEnd}`, [lineId, month, year, selectedShiftId, rangeStart, rangeEnd]);
|
|
41946
42254
|
const monthBounds = React26.useMemo(() => getMonthKeyBounds(year, month), [year, month]);
|
|
@@ -41971,7 +42279,7 @@ var LineMonthlyHistory = ({
|
|
|
41971
42279
|
});
|
|
41972
42280
|
const hasRealData = (shift) => {
|
|
41973
42281
|
if (shift.hasData !== void 0) return shift.hasData;
|
|
41974
|
-
return shift.avg_efficiency > 0 || shift.underperforming_workspaces > 0 || shift.total_workspaces > 0 || (shift.output || 0) > 0 || (shift.idealOutput || 0) > 0;
|
|
42282
|
+
return shift.avg_efficiency > 0 || shift.underperforming_workspaces > 0 || shift.total_workspaces > 0 || (shift.output || 0) > 0 || (shift.idealOutput || 0) > 0 || (shift.idle_time_seconds || 0) > 0 || (shift.active_time_seconds || 0) > 0 || (shift.available_time_seconds || 0) > 0;
|
|
41975
42283
|
};
|
|
41976
42284
|
const averages = (analysisMonthlyData || []).reduce(
|
|
41977
42285
|
(acc, day) => {
|
|
@@ -42003,10 +42311,54 @@ var LineMonthlyHistory = ({
|
|
|
42003
42311
|
},
|
|
42004
42312
|
{ underperformingDays: 0, totalDays: 0 }
|
|
42005
42313
|
);
|
|
42314
|
+
const uptimeSummary = React26.useMemo(() => {
|
|
42315
|
+
if (!isUptimeMode) return null;
|
|
42316
|
+
const validDays = (analysisMonthlyData || []).map((day) => getShiftData2(day, selectedShiftId)).filter((shiftData) => shiftData && hasRealData(shiftData)).map((shiftData) => ({ shiftData, totals: getUptimeTotals(shiftData) }));
|
|
42317
|
+
if (!validDays.length) {
|
|
42318
|
+
return { avgUtilization: 0, avgIdleTime: 0, avgDailyStoppages: 0 };
|
|
42319
|
+
}
|
|
42320
|
+
let totalUtilization = 0;
|
|
42321
|
+
let totalIdleSeconds = 0;
|
|
42322
|
+
let idleSamples = 0;
|
|
42323
|
+
let totalStoppages = 0;
|
|
42324
|
+
validDays.forEach(({ shiftData, totals }) => {
|
|
42325
|
+
const utilization = Number.isFinite(shiftData?.avg_efficiency) ? Number(shiftData.avg_efficiency) : 0;
|
|
42326
|
+
totalUtilization += utilization;
|
|
42327
|
+
if (shiftData?.avg_idle_time_seconds !== void 0 && shiftData.avg_idle_time_seconds !== null) {
|
|
42328
|
+
totalIdleSeconds += shiftData.avg_idle_time_seconds;
|
|
42329
|
+
idleSamples += 1;
|
|
42330
|
+
} else if ((shiftData?.total_workspaces || 0) > 0) {
|
|
42331
|
+
totalIdleSeconds += totals.idleSeconds / (shiftData?.total_workspaces || 1);
|
|
42332
|
+
idleSamples += 1;
|
|
42333
|
+
}
|
|
42334
|
+
totalStoppages += shiftData?.output || 0;
|
|
42335
|
+
});
|
|
42336
|
+
return {
|
|
42337
|
+
avgUtilization: Math.round(totalUtilization / validDays.length),
|
|
42338
|
+
avgIdleTime: idleSamples > 0 ? Math.round(totalIdleSeconds / idleSamples) : 0,
|
|
42339
|
+
avgDailyStoppages: Math.round(totalStoppages / validDays.length)
|
|
42340
|
+
};
|
|
42341
|
+
}, [analysisMonthlyData, selectedShiftId, isUptimeMode]);
|
|
42006
42342
|
const efficiencyDelta = trendSummary?.avg_efficiency?.delta_pp ?? 0;
|
|
42007
42343
|
const efficiencyImproved = efficiencyDelta >= 0;
|
|
42008
42344
|
const EfficiencyTrendIcon = efficiencyImproved ? lucideReact.ArrowUp : lucideReact.ArrowDown;
|
|
42009
|
-
const efficiencyTrendText = `${Math.abs(efficiencyDelta).toFixed(1)}
|
|
42345
|
+
const efficiencyTrendText = `${Math.abs(efficiencyDelta).toFixed(1)}%`;
|
|
42346
|
+
const utilizationDelta = efficiencyDelta;
|
|
42347
|
+
const utilizationImproved = utilizationDelta >= 0;
|
|
42348
|
+
const UtilizationTrendIcon = utilizationImproved ? lucideReact.ArrowUp : lucideReact.ArrowDown;
|
|
42349
|
+
const utilizationTrendText = `${Math.abs(utilizationDelta).toFixed(1)}%`;
|
|
42350
|
+
const idleDeltaRaw = trendSummary?.avg_idle_time?.delta_seconds ?? 0;
|
|
42351
|
+
const idlePrev = trendSummary?.avg_idle_time?.previous ?? 0;
|
|
42352
|
+
const idleDelta = idlePrev ? idleDeltaRaw / idlePrev * 100 : 0;
|
|
42353
|
+
const idleImproved = idleDelta <= 0;
|
|
42354
|
+
const IdleTrendIcon = idleImproved ? lucideReact.ArrowDown : lucideReact.ArrowUp;
|
|
42355
|
+
const idleTrendText = `${Math.abs(idleDelta).toFixed(1)}%`;
|
|
42356
|
+
const stoppagesDeltaRaw = trendSummary?.avg_daily_stoppages?.delta_count ?? 0;
|
|
42357
|
+
const stoppagesPrev = trendSummary?.avg_daily_stoppages?.previous ?? 0;
|
|
42358
|
+
const stoppagesDelta = stoppagesPrev ? stoppagesDeltaRaw / stoppagesPrev * 100 : 0;
|
|
42359
|
+
const stoppagesImproved = stoppagesDelta <= 0;
|
|
42360
|
+
const StoppagesTrendIcon = stoppagesImproved ? lucideReact.ArrowDown : lucideReact.ArrowUp;
|
|
42361
|
+
const stoppagesTrendText = `${Math.abs(stoppagesDelta).toFixed(1)}%`;
|
|
42010
42362
|
const chartData = React26.useMemo(() => {
|
|
42011
42363
|
const rangeStartDate = parseDateKeyToDate(normalizedRange.startKey);
|
|
42012
42364
|
const rangeEndDate = parseDateKeyToDate(normalizedRange.endKey);
|
|
@@ -42014,6 +42366,37 @@ var LineMonthlyHistory = ({
|
|
|
42014
42366
|
for (let d = new Date(rangeStartDate); d <= rangeEndDate; d.setDate(d.getDate() + 1)) {
|
|
42015
42367
|
dayNumbers.push(d.getDate());
|
|
42016
42368
|
}
|
|
42369
|
+
if (isUptimeMode) {
|
|
42370
|
+
const dailyData2 = [];
|
|
42371
|
+
let maxHours = 0;
|
|
42372
|
+
const todayInZone = getCurrentTimeInZone(timezone);
|
|
42373
|
+
const todayDate = typeof todayInZone === "string" ? new Date(todayInZone) : todayInZone;
|
|
42374
|
+
const todayKey = `${todayDate.getFullYear()}-${String(todayDate.getMonth() + 1).padStart(2, "0")}-${String(todayDate.getDate()).padStart(2, "0")}`;
|
|
42375
|
+
for (const day of dayNumbers) {
|
|
42376
|
+
const dayKey = `${rangeStartDate.getFullYear()}-${String(rangeStartDate.getMonth() + 1).padStart(2, "0")}-${String(day).padStart(2, "0")}`;
|
|
42377
|
+
const isFutureDay = dayKey > todayKey;
|
|
42378
|
+
const dayData = analysisMonthlyData.find((d) => {
|
|
42379
|
+
const date = new Date(d.date);
|
|
42380
|
+
return date.getDate() === day;
|
|
42381
|
+
});
|
|
42382
|
+
const shiftData = dayData ? getShiftData2(dayData, selectedShiftId) : null;
|
|
42383
|
+
const hasShiftData = Boolean(shiftData && hasRealData(shiftData));
|
|
42384
|
+
const efficiencyValue = hasShiftData && Number.isFinite(shiftData?.avg_efficiency) ? Number(shiftData?.avg_efficiency) : 0;
|
|
42385
|
+
const utilization = !isFutureDay ? efficiencyValue : 0;
|
|
42386
|
+
const productivePercent = isFutureDay ? 0 : Math.max(0, Math.min(100, utilization));
|
|
42387
|
+
const idlePercent = isFutureDay ? 0 : Math.max(0, Math.min(100, 100 - productivePercent));
|
|
42388
|
+
maxHours = 100;
|
|
42389
|
+
dailyData2.push({
|
|
42390
|
+
hour: getOrdinal(day),
|
|
42391
|
+
timeRange: `Day ${day}`,
|
|
42392
|
+
productivePercent,
|
|
42393
|
+
idlePercent,
|
|
42394
|
+
utilization: Math.round(productivePercent)
|
|
42395
|
+
});
|
|
42396
|
+
}
|
|
42397
|
+
const yAxisMax2 = maxHours > 0 ? 100 : 1;
|
|
42398
|
+
return { data: dailyData2, maxOutput: 0, lastSetTarget: 0, yAxisMax: yAxisMax2 };
|
|
42399
|
+
}
|
|
42017
42400
|
const dailyData = [];
|
|
42018
42401
|
let maxOutput = 0;
|
|
42019
42402
|
let lastSetTarget = 0;
|
|
@@ -42054,7 +42437,7 @@ var LineMonthlyHistory = ({
|
|
|
42054
42437
|
const calculatedMax = Math.max(maxOutput, lastSetTarget);
|
|
42055
42438
|
const yAxisMax = calculatedMax > 0 ? calculatedMax * 1.1 : 100;
|
|
42056
42439
|
return { data: dailyData, maxOutput, lastSetTarget, yAxisMax };
|
|
42057
|
-
}, [analysisMonthlyData, normalizedRange.startKey, normalizedRange.endKey, selectedShiftId]);
|
|
42440
|
+
}, [analysisMonthlyData, normalizedRange.startKey, normalizedRange.endKey, selectedShiftId, isUptimeMode, timezone]);
|
|
42058
42441
|
const yAxisTicks = React26.useMemo(() => {
|
|
42059
42442
|
const max = chartData.yAxisMax;
|
|
42060
42443
|
const target = chartData.lastSetTarget;
|
|
@@ -42076,6 +42459,20 @@ var LineMonthlyHistory = ({
|
|
|
42076
42459
|
}
|
|
42077
42460
|
return Array.from(new Set(ticks)).filter((v) => v >= 0 && v <= max).sort((a, b) => a - b);
|
|
42078
42461
|
}, [chartData.yAxisMax, chartData.lastSetTarget]);
|
|
42462
|
+
const pieChartData = React26.useMemo(() => {
|
|
42463
|
+
if (!isUptimeMode) return [];
|
|
42464
|
+
const validShifts = (analysisMonthlyData || []).map((day) => getShiftData2(day, selectedShiftId)).filter(hasRealData);
|
|
42465
|
+
if (!validShifts.length) return [];
|
|
42466
|
+
const efficiencyValues = validShifts.map((shift) => Number.isFinite(shift.avg_efficiency) ? Number(shift.avg_efficiency) : null).filter((value) => value !== null);
|
|
42467
|
+
if (!efficiencyValues.length) return [];
|
|
42468
|
+
const avgEfficiency2 = efficiencyValues.reduce((sum, value) => sum + value, 0) / efficiencyValues.length;
|
|
42469
|
+
const productivePercent = Math.round(Math.max(0, Math.min(100, avgEfficiency2)));
|
|
42470
|
+
const idlePercent = Math.max(0, Math.min(100, 100 - productivePercent));
|
|
42471
|
+
return [
|
|
42472
|
+
{ name: "Productive", value: productivePercent },
|
|
42473
|
+
{ name: "Idle", value: idlePercent }
|
|
42474
|
+
];
|
|
42475
|
+
}, [analysisMonthlyData, selectedShiftId, isUptimeMode]);
|
|
42079
42476
|
if (isLoading) {
|
|
42080
42477
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center h-[calc(100vh-10rem)]", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
42081
42478
|
OptifyeLogoLoader_default,
|
|
@@ -42180,11 +42577,39 @@ var LineMonthlyHistory = ({
|
|
|
42180
42577
|
rangeStart: normalizedRange.startKey,
|
|
42181
42578
|
rangeEnd: normalizedRange.endKey,
|
|
42182
42579
|
legend,
|
|
42580
|
+
monitoringMode,
|
|
42183
42581
|
onDateSelect: onCalendarDateSelect
|
|
42184
42582
|
}
|
|
42185
42583
|
) }),
|
|
42186
42584
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2 sm:gap-3 lg:gap-4", children: [
|
|
42187
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-1 sm:grid-cols-2 gap-4", children: [
|
|
42585
|
+
isUptimeMode ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-1 sm:grid-cols-2 gap-4", children: [
|
|
42586
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-white rounded-lg shadow-sm border border-gray-100 p-3 flex flex-col justify-between", children: [
|
|
42587
|
+
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-sm font-bold text-gray-700 mb-1", children: "Avg Daily Stoppages" }),
|
|
42588
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 flex-nowrap", children: [
|
|
42589
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-base font-bold text-gray-900 whitespace-nowrap", children: uptimeSummary?.avgDailyStoppages ?? 0 }),
|
|
42590
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: `flex items-center gap-1 ${stoppagesImproved ? "bg-emerald-50 text-emerald-600" : "bg-red-50 text-red-600"} px-1.5 py-0.5 rounded-full text-[10px] font-medium whitespace-nowrap flex-shrink-0`, children: [
|
|
42591
|
+
/* @__PURE__ */ jsxRuntime.jsx(StoppagesTrendIcon, { className: "w-3 h-3" }),
|
|
42592
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
42593
|
+
stoppagesTrendText,
|
|
42594
|
+
" vs last month"
|
|
42595
|
+
] })
|
|
42596
|
+
] })
|
|
42597
|
+
] })
|
|
42598
|
+
] }),
|
|
42599
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-white rounded-lg shadow-sm border border-gray-100 p-3 flex flex-col justify-between", children: [
|
|
42600
|
+
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-sm font-bold text-gray-700 mb-1", children: "Avg Idle Time" }),
|
|
42601
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 flex-nowrap", children: [
|
|
42602
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-base font-bold text-gray-900 whitespace-nowrap", children: formatIdleTime(uptimeSummary?.avgIdleTime ?? 0) }),
|
|
42603
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: `flex items-center gap-1 ${idleImproved ? "bg-emerald-50 text-emerald-600" : "bg-red-50 text-red-600"} px-1.5 py-0.5 rounded-full text-[10px] font-medium whitespace-nowrap flex-shrink-0`, children: [
|
|
42604
|
+
/* @__PURE__ */ jsxRuntime.jsx(IdleTrendIcon, { className: "w-3 h-3" }),
|
|
42605
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
42606
|
+
idleTrendText,
|
|
42607
|
+
" vs last month"
|
|
42608
|
+
] })
|
|
42609
|
+
] })
|
|
42610
|
+
] })
|
|
42611
|
+
] })
|
|
42612
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-1 sm:grid-cols-2 gap-4", children: [
|
|
42188
42613
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-white rounded-lg shadow-sm border border-gray-100 p-4 flex flex-col justify-between", children: [
|
|
42189
42614
|
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-sm font-bold text-gray-700 mb-2", children: "Avg. Efficiency" }),
|
|
42190
42615
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 flex-nowrap", children: [
|
|
@@ -42194,7 +42619,10 @@ var LineMonthlyHistory = ({
|
|
|
42194
42619
|
] }),
|
|
42195
42620
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: `flex items-center gap-1 ${efficiencyImproved ? "bg-emerald-50 text-emerald-600" : "bg-red-50 text-red-600"} px-1.5 py-0.5 rounded-full text-[10px] font-medium whitespace-nowrap flex-shrink-0`, children: [
|
|
42196
42621
|
/* @__PURE__ */ jsxRuntime.jsx(EfficiencyTrendIcon, { className: "w-3 h-3" }),
|
|
42197
|
-
/* @__PURE__ */ jsxRuntime.
|
|
42622
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
42623
|
+
efficiencyTrendText,
|
|
42624
|
+
" vs last month"
|
|
42625
|
+
] })
|
|
42198
42626
|
] })
|
|
42199
42627
|
] })
|
|
42200
42628
|
] }),
|
|
@@ -42207,7 +42635,110 @@ var LineMonthlyHistory = ({
|
|
|
42207
42635
|
] }) })
|
|
42208
42636
|
] })
|
|
42209
42637
|
] }),
|
|
42210
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: `grid grid-cols-1 ${idleTimeVlmEnabled ? "sm:grid-cols-2" : "sm:grid-cols-1"} gap-2 sm:gap-3 lg:gap-4`, children: [
|
|
42638
|
+
isUptimeMode ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `grid grid-cols-1 ${idleTimeVlmEnabled ? "sm:grid-cols-2" : "sm:grid-cols-1"} gap-2 sm:gap-3 lg:gap-4`, children: [
|
|
42639
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-white rounded-lg sm:rounded-xl shadow-sm border border-gray-100 p-2 sm:p-3 lg:p-4 flex flex-col min-h-[160px] sm:min-h-[180px] lg:min-h-[220px]", children: [
|
|
42640
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between mb-0.5 sm:mb-1", children: [
|
|
42641
|
+
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-xs sm:text-sm font-bold text-gray-700 text-left", children: "Utilization" }),
|
|
42642
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: `flex items-center gap-1 ${utilizationImproved ? "bg-emerald-50 text-emerald-600" : "bg-red-50 text-red-600"} px-1.5 py-0.5 rounded-full text-[10px] font-medium whitespace-nowrap flex-shrink-0`, children: [
|
|
42643
|
+
/* @__PURE__ */ jsxRuntime.jsx(UtilizationTrendIcon, { className: "w-3 h-3" }),
|
|
42644
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
42645
|
+
utilizationTrendText,
|
|
42646
|
+
" vs last month"
|
|
42647
|
+
] })
|
|
42648
|
+
] })
|
|
42649
|
+
] }),
|
|
42650
|
+
pieChartData.length > 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-full h-[140px] sm:h-[160px] flex items-center overflow-hidden", children: [
|
|
42651
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 h-full min-w-0 relative flex items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
42652
|
+
"div",
|
|
42653
|
+
{
|
|
42654
|
+
className: "relative w-full aspect-square max-h-full",
|
|
42655
|
+
style: { maxWidth: "min(100%, 220px)", containerType: "inline-size" },
|
|
42656
|
+
children: [
|
|
42657
|
+
/* @__PURE__ */ jsxRuntime.jsx(recharts.ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxRuntime.jsx(recharts.PieChart, { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
42658
|
+
recharts.Pie,
|
|
42659
|
+
{
|
|
42660
|
+
data: pieChartData,
|
|
42661
|
+
cx: "50%",
|
|
42662
|
+
cy: "50%",
|
|
42663
|
+
innerRadius: "60%",
|
|
42664
|
+
outerRadius: "80%",
|
|
42665
|
+
dataKey: "value",
|
|
42666
|
+
startAngle: 90,
|
|
42667
|
+
endAngle: -270,
|
|
42668
|
+
isAnimationActive: true,
|
|
42669
|
+
animationBegin: 0,
|
|
42670
|
+
animationDuration: 1e3,
|
|
42671
|
+
animationEasing: "ease-out",
|
|
42672
|
+
children: pieChartData.map((_entry, index) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
42673
|
+
recharts.Cell,
|
|
42674
|
+
{
|
|
42675
|
+
fill: index === 0 ? "#00AB45" : "#e5e7eb",
|
|
42676
|
+
strokeWidth: 0
|
|
42677
|
+
},
|
|
42678
|
+
`cell-${index}`
|
|
42679
|
+
))
|
|
42680
|
+
}
|
|
42681
|
+
) }, `${chartKey}-pie`) }),
|
|
42682
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 flex flex-col items-center justify-center pointer-events-none", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center", style: { width: "100%" }, children: [
|
|
42683
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
42684
|
+
"div",
|
|
42685
|
+
{
|
|
42686
|
+
className: "font-bold text-gray-900 leading-none",
|
|
42687
|
+
style: { fontSize: "clamp(1rem, 14cqw, 1.4rem)" },
|
|
42688
|
+
children: [
|
|
42689
|
+
pieChartData[0]?.value ?? 0,
|
|
42690
|
+
"%"
|
|
42691
|
+
]
|
|
42692
|
+
}
|
|
42693
|
+
),
|
|
42694
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
42695
|
+
"div",
|
|
42696
|
+
{
|
|
42697
|
+
className: "text-gray-500 leading-tight mt-0.5",
|
|
42698
|
+
style: { fontSize: "clamp(0.6rem, 7cqw, 0.75rem)" },
|
|
42699
|
+
children: "Utilization"
|
|
42700
|
+
}
|
|
42701
|
+
)
|
|
42702
|
+
] }) })
|
|
42703
|
+
]
|
|
42704
|
+
}
|
|
42705
|
+
) }),
|
|
42706
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-[45%] max-w-[120px] pl-2 flex flex-col justify-center h-full overflow-y-auto", children: /* @__PURE__ */ jsxRuntime.jsxs("ul", { className: "text-xs space-y-1.5", children: [
|
|
42707
|
+
/* @__PURE__ */ jsxRuntime.jsxs("li", { className: "flex items-start", children: [
|
|
42708
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
42709
|
+
"span",
|
|
42710
|
+
{
|
|
42711
|
+
className: "inline-block w-2.5 h-2.5 rounded-full mr-1.5 mt-0.5 flex-shrink-0",
|
|
42712
|
+
style: { backgroundColor: "#00AB45" }
|
|
42713
|
+
}
|
|
42714
|
+
),
|
|
42715
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-gray-600 leading-tight text-[10px] sm:text-xs break-words", children: "Productive" })
|
|
42716
|
+
] }),
|
|
42717
|
+
/* @__PURE__ */ jsxRuntime.jsxs("li", { className: "flex items-start", children: [
|
|
42718
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
42719
|
+
"span",
|
|
42720
|
+
{
|
|
42721
|
+
className: "inline-block w-2.5 h-2.5 rounded-full mr-1.5 mt-0.5 flex-shrink-0",
|
|
42722
|
+
style: { backgroundColor: "#e5e7eb" }
|
|
42723
|
+
}
|
|
42724
|
+
),
|
|
42725
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-gray-600 leading-tight text-[10px] sm:text-xs break-words", children: "Idle" })
|
|
42726
|
+
] })
|
|
42727
|
+
] }) })
|
|
42728
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 flex items-center justify-center text-xs text-gray-400 italic", children: "No utilization data" })
|
|
42729
|
+
] }),
|
|
42730
|
+
idleTimeVlmEnabled && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-white rounded-lg sm:rounded-xl shadow-sm border border-gray-100 p-2 sm:p-3 lg:p-4 flex flex-col min-h-[160px] sm:min-h-[180px] lg:min-h-[220px]", children: [
|
|
42731
|
+
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-xs sm:text-sm font-bold text-gray-700 mb-0.5 sm:mb-1 text-left", children: "Idle time Breakdown" }),
|
|
42732
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 min-h-0 relative -ml-2 sm:-ml-4", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
42733
|
+
IdleTimeReasonChart,
|
|
42734
|
+
{
|
|
42735
|
+
data: idleReasonsChartData,
|
|
42736
|
+
isLoading: idleReasonsLoading,
|
|
42737
|
+
error: idleReasonsError
|
|
42738
|
+
}
|
|
42739
|
+
) })
|
|
42740
|
+
] })
|
|
42741
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `grid grid-cols-1 ${idleTimeVlmEnabled ? "sm:grid-cols-2" : "sm:grid-cols-1"} gap-2 sm:gap-3 lg:gap-4`, children: [
|
|
42211
42742
|
idleTimeVlmEnabled && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-white rounded-lg sm:rounded-xl shadow-sm border border-gray-100 p-2 sm:p-3 lg:p-4 flex flex-col min-h-[160px] sm:min-h-[180px] lg:min-h-[220px]", children: [
|
|
42212
42743
|
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-xs sm:text-sm font-bold text-gray-700 mb-0.5 sm:mb-1 text-left", children: "Idle time Breakdown" }),
|
|
42213
42744
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 min-h-0 relative -ml-2 sm:-ml-4", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -42246,7 +42777,7 @@ var LineMonthlyHistory = ({
|
|
|
42246
42777
|
] })
|
|
42247
42778
|
] }),
|
|
42248
42779
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-white rounded-lg sm:rounded-xl shadow-sm border border-gray-100 p-2 sm:p-3 lg:p-4", children: [
|
|
42249
|
-
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-xs sm:text-sm font-bold text-gray-700 mb-1 sm:mb-2 text-left", children: "Daily Output" }),
|
|
42780
|
+
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-xs sm:text-sm font-bold text-gray-700 mb-1 sm:mb-2 text-left", children: isUptimeMode ? "Daily Utilization" : "Daily Output" }),
|
|
42250
42781
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-[160px] sm:h-[180px] lg:h-[220px]", children: /* @__PURE__ */ jsxRuntime.jsx(recharts.ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
42251
42782
|
recharts.BarChart,
|
|
42252
42783
|
{
|
|
@@ -42270,8 +42801,9 @@ var LineMonthlyHistory = ({
|
|
|
42270
42801
|
{
|
|
42271
42802
|
domain: [0, chartData.yAxisMax],
|
|
42272
42803
|
width: 40,
|
|
42273
|
-
ticks: yAxisTicks,
|
|
42274
|
-
|
|
42804
|
+
ticks: isUptimeMode ? [0, 25, 50, 75, 100] : yAxisTicks,
|
|
42805
|
+
tickFormatter: isUptimeMode ? (value) => `${value}%` : void 0,
|
|
42806
|
+
tick: isUptimeMode ? void 0 : (props) => {
|
|
42275
42807
|
const { x, y, payload } = props;
|
|
42276
42808
|
const value = Math.round(payload.value);
|
|
42277
42809
|
const targetValue = Math.round(chartData.lastSetTarget);
|
|
@@ -42295,10 +42827,10 @@ var LineMonthlyHistory = ({
|
|
|
42295
42827
|
recharts.Tooltip,
|
|
42296
42828
|
{
|
|
42297
42829
|
cursor: false,
|
|
42298
|
-
content: CustomTooltip2
|
|
42830
|
+
content: (props) => /* @__PURE__ */ jsxRuntime.jsx(CustomTooltip2, { ...props, isUptimeMode })
|
|
42299
42831
|
}
|
|
42300
42832
|
),
|
|
42301
|
-
chartData.lastSetTarget > 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
42833
|
+
!isUptimeMode && chartData.lastSetTarget > 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
42302
42834
|
recharts.ReferenceLine,
|
|
42303
42835
|
{
|
|
42304
42836
|
y: chartData.lastSetTarget,
|
|
@@ -42307,7 +42839,34 @@ var LineMonthlyHistory = ({
|
|
|
42307
42839
|
strokeWidth: 2
|
|
42308
42840
|
}
|
|
42309
42841
|
),
|
|
42310
|
-
/* @__PURE__ */ jsxRuntime.
|
|
42842
|
+
isUptimeMode ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
42843
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
42844
|
+
recharts.Bar,
|
|
42845
|
+
{
|
|
42846
|
+
dataKey: "productivePercent",
|
|
42847
|
+
stackId: "uptime",
|
|
42848
|
+
radius: [4, 4, 0, 0],
|
|
42849
|
+
fill: "#00AB45",
|
|
42850
|
+
isAnimationActive: true,
|
|
42851
|
+
animationBegin: 0,
|
|
42852
|
+
animationDuration: 800,
|
|
42853
|
+
animationEasing: "ease-out"
|
|
42854
|
+
}
|
|
42855
|
+
),
|
|
42856
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
42857
|
+
recharts.Bar,
|
|
42858
|
+
{
|
|
42859
|
+
dataKey: "idlePercent",
|
|
42860
|
+
stackId: "uptime",
|
|
42861
|
+
radius: [4, 4, 0, 0],
|
|
42862
|
+
fill: "#e5e7eb",
|
|
42863
|
+
isAnimationActive: true,
|
|
42864
|
+
animationBegin: 0,
|
|
42865
|
+
animationDuration: 800,
|
|
42866
|
+
animationEasing: "ease-out"
|
|
42867
|
+
}
|
|
42868
|
+
)
|
|
42869
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
42311
42870
|
recharts.Bar,
|
|
42312
42871
|
{
|
|
42313
42872
|
dataKey: "output",
|
|
@@ -42339,7 +42898,13 @@ var DEFAULT_PERFORMANCE_DATA2 = {
|
|
|
42339
42898
|
avg_efficiency: 0,
|
|
42340
42899
|
underperforming_workspaces: 0,
|
|
42341
42900
|
total_workspaces: 0,
|
|
42342
|
-
hasData: false
|
|
42901
|
+
hasData: false,
|
|
42902
|
+
output: 0,
|
|
42903
|
+
idealOutput: 0,
|
|
42904
|
+
idle_time_seconds: 0,
|
|
42905
|
+
active_time_seconds: 0,
|
|
42906
|
+
available_time_seconds: 0,
|
|
42907
|
+
avg_idle_time_seconds: 0
|
|
42343
42908
|
};
|
|
42344
42909
|
var getLineShiftData2 = (day, shiftId) => {
|
|
42345
42910
|
const shift = day.shifts[shiftId];
|
|
@@ -42360,6 +42925,7 @@ var LineMonthlyPdfGenerator = ({
|
|
|
42360
42925
|
lineName,
|
|
42361
42926
|
monthlyData,
|
|
42362
42927
|
analysisData,
|
|
42928
|
+
monitoringMode,
|
|
42363
42929
|
underperformingWorkspaces,
|
|
42364
42930
|
legend,
|
|
42365
42931
|
selectedMonth,
|
|
@@ -42376,6 +42942,7 @@ var LineMonthlyPdfGenerator = ({
|
|
|
42376
42942
|
const generatePDF = async () => {
|
|
42377
42943
|
setIsGenerating(true);
|
|
42378
42944
|
try {
|
|
42945
|
+
const isUptimeMode = monitoringMode === "uptime";
|
|
42379
42946
|
const monthBounds = getMonthKeyBounds(selectedYear, selectedMonth);
|
|
42380
42947
|
const requestedRange = {
|
|
42381
42948
|
startKey: rangeStart || monthBounds.startKey,
|
|
@@ -42420,7 +42987,7 @@ var LineMonthlyPdfGenerator = ({
|
|
|
42420
42987
|
doc.setFontSize(11);
|
|
42421
42988
|
doc.setFont("helvetica", "normal");
|
|
42422
42989
|
doc.setTextColor(80, 80, 80);
|
|
42423
|
-
const reportText = "MONTHLY PERFORMANCE REPORT";
|
|
42990
|
+
const reportText = isUptimeMode ? "MONTHLY UTILIZATION REPORT" : "MONTHLY PERFORMANCE REPORT";
|
|
42424
42991
|
const reportTextWidth = doc.getStringUnitWidth(reportText) * 11 / doc.internal.scaleFactor;
|
|
42425
42992
|
doc.text(reportText, doc.internal.pageSize.width - 20 - reportTextWidth, 15);
|
|
42426
42993
|
doc.setDrawColor(200, 200, 200);
|
|
@@ -42449,16 +43016,66 @@ var LineMonthlyPdfGenerator = ({
|
|
|
42449
43016
|
doc.setTextColor(0, 0, 0);
|
|
42450
43017
|
doc.setDrawColor(180, 180, 180);
|
|
42451
43018
|
doc.setLineWidth(0.8);
|
|
42452
|
-
|
|
43019
|
+
const mainSeparatorY = isUptimeMode ? 90 : 85;
|
|
43020
|
+
doc.line(20, mainSeparatorY, 190, mainSeparatorY);
|
|
42453
43021
|
const reportData = analysisData ? analysisData : filterDataByDateKeyRange(monthlyData, normalizedRange);
|
|
42454
43022
|
const validDays = reportData.filter((day) => {
|
|
42455
43023
|
const date = new Date(day.date);
|
|
42456
43024
|
return date.getMonth() === selectedMonth && date.getFullYear() === selectedYear;
|
|
42457
43025
|
});
|
|
42458
|
-
const
|
|
42459
|
-
(
|
|
42460
|
-
|
|
42461
|
-
|
|
43026
|
+
const hasShiftData = (shift) => {
|
|
43027
|
+
if (shift.hasData !== void 0) return shift.hasData;
|
|
43028
|
+
return shift.total_workspaces > 0 || shift.avg_efficiency > 0 || shift.underperforming_workspaces > 0 || (shift.available_time_seconds ?? 0) > 0 || (shift.idle_time_seconds ?? 0) > 0 || (shift.output ?? 0) > 0;
|
|
43029
|
+
};
|
|
43030
|
+
const getUptimeTotals2 = (shift, hasData) => {
|
|
43031
|
+
if (!hasData || !shift) {
|
|
43032
|
+
return { availableSeconds: 0, productiveSeconds: 0, idleSeconds: 0 };
|
|
43033
|
+
}
|
|
43034
|
+
const idleSecondsRaw = Math.max(shift.idle_time_seconds || 0, 0);
|
|
43035
|
+
const activeSecondsRaw = Math.max(shift.active_time_seconds || 0, 0);
|
|
43036
|
+
const knownSeconds = activeSecondsRaw + idleSecondsRaw;
|
|
43037
|
+
if (knownSeconds <= 0) {
|
|
43038
|
+
return { availableSeconds: 0, productiveSeconds: 0, idleSeconds: 0 };
|
|
43039
|
+
}
|
|
43040
|
+
const availableSeconds = knownSeconds;
|
|
43041
|
+
const idleSeconds = Math.min(idleSecondsRaw, availableSeconds);
|
|
43042
|
+
const productiveSeconds = activeSecondsRaw > 0 ? Math.min(activeSecondsRaw, availableSeconds) : Math.max(availableSeconds - idleSeconds, 0);
|
|
43043
|
+
return { availableSeconds, productiveSeconds, idleSeconds };
|
|
43044
|
+
};
|
|
43045
|
+
const validShifts = validDays.map((day) => getLineShiftData2(day, selectedShiftId)).filter((shift) => isUptimeMode ? hasShiftData(shift) : shift.avg_efficiency >= 5);
|
|
43046
|
+
const monthlyMetrics = validShifts.length > 0 ? isUptimeMode ? (() => {
|
|
43047
|
+
let utilizationSum = 0;
|
|
43048
|
+
let idleTimeSum = 0;
|
|
43049
|
+
let stoppagesSum = 0;
|
|
43050
|
+
let idleSamples = 0;
|
|
43051
|
+
let underperformingDays = 0;
|
|
43052
|
+
validShifts.forEach((shift) => {
|
|
43053
|
+
const totals = getUptimeTotals2(shift, hasShiftData(shift));
|
|
43054
|
+
const utilization = Number.isFinite(shift.avg_efficiency) ? Number(shift.avg_efficiency) : 0;
|
|
43055
|
+
utilizationSum += utilization;
|
|
43056
|
+
if (utilization < effectiveLegend.green_min) {
|
|
43057
|
+
underperformingDays += 1;
|
|
43058
|
+
}
|
|
43059
|
+
if (shift.avg_idle_time_seconds !== void 0 && shift.avg_idle_time_seconds !== null) {
|
|
43060
|
+
idleTimeSum += shift.avg_idle_time_seconds;
|
|
43061
|
+
idleSamples += 1;
|
|
43062
|
+
} else if ((shift.total_workspaces || 0) > 0) {
|
|
43063
|
+
idleTimeSum += totals.idleSeconds / (shift.total_workspaces || 1);
|
|
43064
|
+
idleSamples += 1;
|
|
43065
|
+
}
|
|
43066
|
+
stoppagesSum += shift.output || 0;
|
|
43067
|
+
});
|
|
43068
|
+
const avgUtilization = Math.round(utilizationSum / validShifts.length);
|
|
43069
|
+
const avgIdleTime = idleSamples > 0 ? Math.round(idleTimeSum / idleSamples) : 0;
|
|
43070
|
+
const avgDailyStoppages = Math.round(stoppagesSum / validShifts.length);
|
|
43071
|
+
return {
|
|
43072
|
+
avgUtilization,
|
|
43073
|
+
avgIdleTime,
|
|
43074
|
+
avgDailyStoppages,
|
|
43075
|
+
totalDays: validShifts.length,
|
|
43076
|
+
underperformingDays
|
|
43077
|
+
};
|
|
43078
|
+
})() : {
|
|
42462
43079
|
avgEfficiency: validShifts.reduce((sum, shift) => sum + shift.avg_efficiency, 0) / validShifts.length,
|
|
42463
43080
|
avgUnderperforming: validShifts.reduce((sum, shift) => sum + shift.underperforming_workspaces, 0) / validShifts.length,
|
|
42464
43081
|
avgTotalWorkspaces: validShifts.reduce((sum, shift) => sum + shift.total_workspaces, 0) / validShifts.length,
|
|
@@ -42472,109 +43089,167 @@ var LineMonthlyPdfGenerator = ({
|
|
|
42472
43089
|
doc.setLineWidth(0.2);
|
|
42473
43090
|
doc.roundedRect(22, y - 7, 165, 12, 2, 2, "S");
|
|
42474
43091
|
};
|
|
43092
|
+
const overviewStartY = isUptimeMode ? 95 : 90;
|
|
43093
|
+
const overviewHeight = 60;
|
|
43094
|
+
const overviewTitleY = isUptimeMode ? 105 : 100;
|
|
42475
43095
|
doc.setFillColor(245, 245, 245);
|
|
42476
|
-
doc.roundedRect(15,
|
|
43096
|
+
doc.roundedRect(15, overviewStartY, 180, overviewHeight, 3, 3, "F");
|
|
42477
43097
|
doc.setFontSize(18);
|
|
42478
43098
|
doc.setFont("helvetica", "bold");
|
|
42479
43099
|
doc.setTextColor(40, 40, 40);
|
|
42480
|
-
doc.text("Monthly Performance Overview", 20,
|
|
43100
|
+
doc.text(isUptimeMode ? "Monthly Utilization Overview" : "Monthly Performance Overview", 20, overviewTitleY);
|
|
42481
43101
|
doc.setTextColor(0, 0, 0);
|
|
42482
43102
|
if (monthlyMetrics) {
|
|
42483
|
-
const kpiStartY = 112;
|
|
43103
|
+
const kpiStartY = isUptimeMode ? 117 : 112;
|
|
42484
43104
|
const kpiSpacing = 10;
|
|
42485
|
-
|
|
42486
|
-
|
|
42487
|
-
|
|
42488
|
-
|
|
42489
|
-
|
|
42490
|
-
|
|
42491
|
-
|
|
42492
|
-
|
|
42493
|
-
|
|
42494
|
-
|
|
42495
|
-
|
|
42496
|
-
|
|
42497
|
-
|
|
42498
|
-
|
|
42499
|
-
|
|
42500
|
-
|
|
42501
|
-
|
|
42502
|
-
|
|
42503
|
-
|
|
42504
|
-
|
|
42505
|
-
|
|
43105
|
+
if (isUptimeMode) {
|
|
43106
|
+
const uptimeMetrics = monthlyMetrics;
|
|
43107
|
+
createKPIBox(kpiStartY);
|
|
43108
|
+
doc.setFontSize(11);
|
|
43109
|
+
doc.setFont("helvetica", "normal");
|
|
43110
|
+
doc.text("Average Utilization:", 25, kpiStartY);
|
|
43111
|
+
doc.setFont("helvetica", "bold");
|
|
43112
|
+
doc.text(`${uptimeMetrics.avgUtilization}%`, 120, kpiStartY);
|
|
43113
|
+
createKPIBox(kpiStartY + kpiSpacing);
|
|
43114
|
+
doc.setFont("helvetica", "normal");
|
|
43115
|
+
doc.text("Average Idle Time:", 25, kpiStartY + kpiSpacing);
|
|
43116
|
+
doc.setFont("helvetica", "bold");
|
|
43117
|
+
doc.text(formatIdleTime(uptimeMetrics.avgIdleTime), 120, kpiStartY + kpiSpacing);
|
|
43118
|
+
createKPIBox(kpiStartY + kpiSpacing * 2);
|
|
43119
|
+
doc.setFont("helvetica", "normal");
|
|
43120
|
+
doc.text("Avg Daily Stoppages:", 25, kpiStartY + kpiSpacing * 2);
|
|
43121
|
+
doc.setFont("helvetica", "bold");
|
|
43122
|
+
doc.text(`${uptimeMetrics.avgDailyStoppages}`, 120, kpiStartY + kpiSpacing * 2);
|
|
43123
|
+
createKPIBox(kpiStartY + kpiSpacing * 3);
|
|
43124
|
+
doc.setFont("helvetica", "normal");
|
|
43125
|
+
doc.text("Low Utilization Days:", 25, kpiStartY + kpiSpacing * 3);
|
|
43126
|
+
doc.setFont("helvetica", "bold");
|
|
43127
|
+
doc.text(`${uptimeMetrics.underperformingDays} of ${uptimeMetrics.totalDays}`, 120, kpiStartY + kpiSpacing * 3);
|
|
43128
|
+
} else {
|
|
43129
|
+
const outputMetrics = monthlyMetrics;
|
|
43130
|
+
createKPIBox(kpiStartY);
|
|
43131
|
+
doc.setFontSize(11);
|
|
43132
|
+
doc.setFont("helvetica", "normal");
|
|
43133
|
+
doc.text("Average Efficiency:", 25, kpiStartY);
|
|
43134
|
+
doc.setFont("helvetica", "bold");
|
|
43135
|
+
doc.text(`${outputMetrics.avgEfficiency.toFixed(1)}% (Target: ${Math.round(effectiveLegend.green_min)}%)`, 120, kpiStartY);
|
|
43136
|
+
createKPIBox(kpiStartY + kpiSpacing);
|
|
43137
|
+
doc.setFont("helvetica", "normal");
|
|
43138
|
+
doc.text("Avg. Underperforming:", 25, kpiStartY + kpiSpacing);
|
|
43139
|
+
doc.setFont("helvetica", "bold");
|
|
43140
|
+
doc.text(`${outputMetrics.avgUnderperforming.toFixed(1)}/${outputMetrics.avgTotalWorkspaces.toFixed(1)}`, 120, kpiStartY + kpiSpacing);
|
|
43141
|
+
createKPIBox(kpiStartY + kpiSpacing * 2);
|
|
43142
|
+
doc.setFont("helvetica", "normal");
|
|
43143
|
+
doc.text("Working Days:", 25, kpiStartY + kpiSpacing * 2);
|
|
43144
|
+
doc.setFont("helvetica", "bold");
|
|
43145
|
+
doc.text(`${outputMetrics.totalDays} days`, 120, kpiStartY + kpiSpacing * 2);
|
|
43146
|
+
createKPIBox(kpiStartY + kpiSpacing * 3);
|
|
43147
|
+
doc.setFont("helvetica", "normal");
|
|
43148
|
+
doc.text("Underperforming Days:", 25, kpiStartY + kpiSpacing * 3);
|
|
43149
|
+
doc.setFont("helvetica", "bold");
|
|
43150
|
+
doc.text(`${outputMetrics.underperformingDays} of ${outputMetrics.totalDays}`, 120, kpiStartY + kpiSpacing * 3);
|
|
43151
|
+
}
|
|
42506
43152
|
} else {
|
|
42507
43153
|
doc.setFontSize(12);
|
|
42508
43154
|
doc.setFont("helvetica", "normal");
|
|
42509
43155
|
doc.setTextColor(100, 100, 100);
|
|
42510
|
-
doc.text("No data available for this month", 25, 115);
|
|
43156
|
+
doc.text("No data available for this month", 25, isUptimeMode ? 125 : 115);
|
|
42511
43157
|
doc.setTextColor(0, 0, 0);
|
|
42512
43158
|
}
|
|
43159
|
+
const dailySeparatorY = isUptimeMode ? 180 : 165;
|
|
43160
|
+
const dailySectionStartY = isUptimeMode ? 185 : 170;
|
|
43161
|
+
const dailyTitleY = isUptimeMode ? 195 : 180;
|
|
43162
|
+
const dailyHeaderY = isUptimeMode ? 200 : 185;
|
|
43163
|
+
const dailyHeaderTextY = isUptimeMode ? 205 : 190;
|
|
43164
|
+
const dailyHeaderLineY = isUptimeMode ? 208 : 193;
|
|
43165
|
+
const dailyContentStartY = isUptimeMode ? 215 : 200;
|
|
43166
|
+
const dailyMaxY = isUptimeMode ? 260 : 245;
|
|
42513
43167
|
doc.setDrawColor(180, 180, 180);
|
|
42514
43168
|
doc.setLineWidth(0.8);
|
|
42515
|
-
doc.line(20,
|
|
43169
|
+
doc.line(20, dailySeparatorY, 190, dailySeparatorY);
|
|
42516
43170
|
doc.setFillColor(245, 245, 245);
|
|
42517
|
-
doc.roundedRect(15,
|
|
43171
|
+
doc.roundedRect(15, dailySectionStartY, 180, 85, 3, 3, "F");
|
|
42518
43172
|
doc.setFontSize(18);
|
|
42519
43173
|
doc.setFont("helvetica", "bold");
|
|
42520
43174
|
doc.setTextColor(40, 40, 40);
|
|
42521
|
-
doc.text("Daily Performance Summary", 20,
|
|
43175
|
+
doc.text(isUptimeMode ? "Daily Utilization Summary" : "Daily Performance Summary", 20, dailyTitleY);
|
|
42522
43176
|
doc.setTextColor(0, 0, 0);
|
|
42523
43177
|
if (validDays.length > 0) {
|
|
42524
43178
|
doc.setFontSize(10);
|
|
42525
43179
|
doc.setFont("helvetica", "bold");
|
|
42526
43180
|
doc.setFillColor(240, 240, 240);
|
|
42527
|
-
doc.roundedRect(20,
|
|
42528
|
-
doc.text("Date", 25,
|
|
42529
|
-
|
|
42530
|
-
|
|
42531
|
-
|
|
42532
|
-
|
|
43181
|
+
doc.roundedRect(20, dailyHeaderY, 170, 7, 1, 1, "F");
|
|
43182
|
+
doc.text("Date", 25, dailyHeaderTextY);
|
|
43183
|
+
if (isUptimeMode) {
|
|
43184
|
+
doc.text("Utilization", 95, dailyHeaderTextY);
|
|
43185
|
+
} else {
|
|
43186
|
+
doc.text("Actual", 60, dailyHeaderTextY);
|
|
43187
|
+
doc.text("Standard", 95, dailyHeaderTextY);
|
|
43188
|
+
doc.text("Efficiency", 135, dailyHeaderTextY);
|
|
43189
|
+
doc.text("Status", 170, dailyHeaderTextY);
|
|
43190
|
+
}
|
|
42533
43191
|
doc.setLineWidth(0.2);
|
|
42534
43192
|
doc.setDrawColor(220, 220, 220);
|
|
42535
|
-
doc.line(20,
|
|
43193
|
+
doc.line(20, dailyHeaderLineY, 190, dailyHeaderLineY);
|
|
42536
43194
|
doc.setFont("helvetica", "normal");
|
|
42537
|
-
let yPos =
|
|
43195
|
+
let yPos = dailyContentStartY;
|
|
42538
43196
|
const recentDays = validDays.slice(-10).reverse();
|
|
42539
43197
|
recentDays.forEach((dayData, index) => {
|
|
42540
|
-
if (yPos >
|
|
43198
|
+
if (yPos > dailyMaxY) return;
|
|
42541
43199
|
const shift = getLineShiftData2(dayData, selectedShiftId);
|
|
42542
|
-
if (
|
|
42543
|
-
if (
|
|
42544
|
-
doc.
|
|
42545
|
-
doc.
|
|
42546
|
-
|
|
42547
|
-
|
|
42548
|
-
|
|
42549
|
-
|
|
42550
|
-
|
|
42551
|
-
|
|
42552
|
-
|
|
42553
|
-
|
|
42554
|
-
|
|
42555
|
-
|
|
42556
|
-
const statusColor = getEfficiencyColor(shift.avg_efficiency, effectiveLegend);
|
|
42557
|
-
if (statusColor === "green") {
|
|
42558
|
-
doc.setTextColor(0, 171, 69);
|
|
42559
|
-
doc.text("\u2713", 170, yPos);
|
|
42560
|
-
} else if (statusColor === "yellow") {
|
|
42561
|
-
doc.setTextColor(255, 176, 32);
|
|
42562
|
-
doc.text("!", 170, yPos);
|
|
43200
|
+
if (!hasShiftData(shift)) return;
|
|
43201
|
+
if (isUptimeMode) {
|
|
43202
|
+
doc.setDrawColor(200, 200, 200);
|
|
43203
|
+
doc.setLineWidth(0.1);
|
|
43204
|
+
doc.rect(20, yPos - 5, 75, 8, "S");
|
|
43205
|
+
const dateStr = new Date(dayData.date).toLocaleDateString("en-IN", {
|
|
43206
|
+
day: "2-digit",
|
|
43207
|
+
month: "short",
|
|
43208
|
+
timeZone: "Asia/Kolkata"
|
|
43209
|
+
});
|
|
43210
|
+
doc.text(dateStr, 25, yPos);
|
|
43211
|
+
doc.rect(95, yPos - 5, 95, 8, "S");
|
|
43212
|
+
const utilization = Number.isFinite(shift.avg_efficiency) ? Math.round(Number(shift.avg_efficiency)) : 0;
|
|
43213
|
+
doc.text(`${utilization}%`, 100, yPos);
|
|
42563
43214
|
} else {
|
|
42564
|
-
|
|
42565
|
-
|
|
43215
|
+
if (index % 2 === 0) {
|
|
43216
|
+
doc.setFillColor(252, 252, 252);
|
|
43217
|
+
doc.roundedRect(20, yPos - 4, 170, 7, 1, 1, "F");
|
|
43218
|
+
}
|
|
43219
|
+
const dateStr = new Date(dayData.date).toLocaleDateString("en-IN", {
|
|
43220
|
+
day: "2-digit",
|
|
43221
|
+
month: "short",
|
|
43222
|
+
timeZone: "Asia/Kolkata"
|
|
43223
|
+
});
|
|
43224
|
+
doc.text(dateStr, 25, yPos);
|
|
43225
|
+
doc.text(`${shift.total_workspaces - shift.underperforming_workspaces}`, 60, yPos);
|
|
43226
|
+
doc.text(`${shift.total_workspaces}`, 95, yPos);
|
|
43227
|
+
doc.text(`${shift.avg_efficiency.toFixed(1)}%`, 135, yPos);
|
|
43228
|
+
const statusColor = getEfficiencyColor(shift.avg_efficiency, effectiveLegend);
|
|
43229
|
+
if (statusColor === "green") {
|
|
43230
|
+
doc.setTextColor(0, 171, 69);
|
|
43231
|
+
doc.text("\u2713", 170, yPos);
|
|
43232
|
+
} else if (statusColor === "yellow") {
|
|
43233
|
+
doc.setTextColor(255, 176, 32);
|
|
43234
|
+
doc.text("!", 170, yPos);
|
|
43235
|
+
} else {
|
|
43236
|
+
doc.setTextColor(227, 67, 41);
|
|
43237
|
+
doc.text("\xD7", 170, yPos);
|
|
43238
|
+
}
|
|
43239
|
+
doc.setTextColor(0, 0, 0);
|
|
42566
43240
|
}
|
|
42567
|
-
doc.setTextColor(0, 0, 0);
|
|
42568
43241
|
yPos += 8;
|
|
42569
43242
|
});
|
|
42570
|
-
|
|
42571
|
-
|
|
42572
|
-
|
|
43243
|
+
if (!isUptimeMode) {
|
|
43244
|
+
doc.setLineWidth(0.2);
|
|
43245
|
+
doc.setDrawColor(220, 220, 220);
|
|
43246
|
+
doc.roundedRect(20, dailyHeaderY, 170, yPos - dailyHeaderY - 3, 1, 1, "S");
|
|
43247
|
+
}
|
|
42573
43248
|
} else {
|
|
42574
43249
|
doc.setFontSize(12);
|
|
42575
43250
|
doc.setFont("helvetica", "normal");
|
|
42576
43251
|
doc.setTextColor(100, 100, 100);
|
|
42577
|
-
doc.text("No daily data available for this month", 25,
|
|
43252
|
+
doc.text("No daily data available for this month", 25, dailyContentStartY);
|
|
42578
43253
|
doc.setTextColor(0, 0, 0);
|
|
42579
43254
|
}
|
|
42580
43255
|
const poorestWorkspaces = underperformingWorkspaces[selectedShiftId] || [];
|
|
@@ -42587,7 +43262,7 @@ var LineMonthlyPdfGenerator = ({
|
|
|
42587
43262
|
doc.setFontSize(11);
|
|
42588
43263
|
doc.setFont("helvetica", "normal");
|
|
42589
43264
|
doc.setTextColor(80, 80, 80);
|
|
42590
|
-
const reportText2 = "MONTHLY PERFORMANCE REPORT";
|
|
43265
|
+
const reportText2 = isUptimeMode ? "MONTHLY UTILIZATION REPORT" : "MONTHLY PERFORMANCE REPORT";
|
|
42591
43266
|
const reportTextWidth2 = doc.getStringUnitWidth(reportText2) * 11 / doc.internal.scaleFactor;
|
|
42592
43267
|
doc.text(reportText2, doc.internal.pageSize.width - 20 - reportTextWidth2, 15);
|
|
42593
43268
|
doc.setDrawColor(200, 200, 200);
|
|
@@ -42603,7 +43278,7 @@ var LineMonthlyPdfGenerator = ({
|
|
|
42603
43278
|
doc.setFillColor(245, 245, 245);
|
|
42604
43279
|
doc.roundedRect(20, 45, 170, 8, 1, 1, "F");
|
|
42605
43280
|
doc.text("Workspace", 25, 50);
|
|
42606
|
-
doc.text("Avg Efficiency", 120, 50);
|
|
43281
|
+
doc.text(isUptimeMode ? "Avg Utilization" : "Avg Efficiency", 120, 50);
|
|
42607
43282
|
doc.text("Last 5 Days", 160, 50);
|
|
42608
43283
|
doc.setLineWidth(0.2);
|
|
42609
43284
|
doc.setDrawColor(220, 220, 220);
|
|
@@ -42681,7 +43356,21 @@ var LineWhatsAppShareButton = ({
|
|
|
42681
43356
|
line_name: lineInfo.line_name,
|
|
42682
43357
|
factory_id: lineInfo.factory_id
|
|
42683
43358
|
});
|
|
42684
|
-
const
|
|
43359
|
+
const isUptimeMode = lineInfo.monitoring_mode === "uptime";
|
|
43360
|
+
const uptimeSeries = isUptimeMode ? buildUptimeSeries({
|
|
43361
|
+
idleTimeHourly: lineInfo.metrics.idle_time_hourly,
|
|
43362
|
+
shiftStart: lineInfo.metrics.shift_start,
|
|
43363
|
+
shiftEnd: lineInfo.metrics.shift_end,
|
|
43364
|
+
shiftDate: lineInfo.date,
|
|
43365
|
+
timezone: "Asia/Kolkata"
|
|
43366
|
+
}) : null;
|
|
43367
|
+
const efficiencyValue = Number.isFinite(lineInfo.metrics.avg_efficiency) ? Number(lineInfo.metrics.avg_efficiency) : null;
|
|
43368
|
+
const utilization = efficiencyValue !== null ? efficiencyValue : uptimeSeries && uptimeSeries.availableMinutes > 0 ? uptimeSeries.activeMinutes / uptimeSeries.availableMinutes * 100 : 0;
|
|
43369
|
+
const idleTimeSeconds = uptimeSeries ? uptimeSeries.idleMinutes * 60 : 0;
|
|
43370
|
+
const message = isUptimeMode ? `Line Utilization Update for ${lineInfo.line_name}:
|
|
43371
|
+
Utilization: ${utilization.toFixed(1)}%
|
|
43372
|
+
Stoppages: ${lineInfo.metrics.current_output}
|
|
43373
|
+
Idle Time: ${formatIdleTime(idleTimeSeconds)}` : `Line Performance Update for ${lineInfo.line_name}:
|
|
42685
43374
|
Current Output: ${lineInfo.metrics.current_output} / ${lineInfo.metrics.line_threshold}
|
|
42686
43375
|
Average Efficiency: ${lineInfo.metrics.avg_efficiency.toFixed(1)}%
|
|
42687
43376
|
Underperforming Workspaces: ${lineInfo.metrics.underperforming_workspaces} / ${lineInfo.metrics.total_workspaces}`;
|
|
@@ -42751,13 +43440,15 @@ var LinePdfGenerator = ({
|
|
|
42751
43440
|
doc.line(20, 20, 190, 20);
|
|
42752
43441
|
return 30;
|
|
42753
43442
|
};
|
|
43443
|
+
const createKPIBox = (y) => {
|
|
43444
|
+
doc.setFillColor(255, 255, 255);
|
|
43445
|
+
doc.roundedRect(22, y - 7, 165, 12, 2, 2, "F");
|
|
43446
|
+
doc.setDrawColor(230, 230, 230);
|
|
43447
|
+
doc.setLineWidth(0.2);
|
|
43448
|
+
doc.roundedRect(22, y - 7, 165, 12, 2, 2, "S");
|
|
43449
|
+
};
|
|
42754
43450
|
addHeaderPage1();
|
|
42755
|
-
|
|
42756
|
-
doc.setFont("helvetica", "bold");
|
|
42757
|
-
doc.setTextColor(0, 0, 0);
|
|
42758
|
-
doc.text(lineInfo.line_name, 20, 30);
|
|
42759
|
-
doc.setFontSize(14);
|
|
42760
|
-
doc.setFont("helvetica", "normal");
|
|
43451
|
+
const isUptimeMode = lineInfo.monitoring_mode === "uptime";
|
|
42761
43452
|
const rawShiftType = shiftName || (lineInfo.shift_id === 0 ? "Day" : lineInfo.shift_id === 1 ? "Night" : `Shift ${lineInfo.shift_id}`);
|
|
42762
43453
|
const shiftType = rawShiftType.toLowerCase().includes("shift") ? rawShiftType : `${rawShiftType} Shift`;
|
|
42763
43454
|
const date = new Date(lineInfo.date).toLocaleDateString("en-IN", {
|
|
@@ -42766,7 +43457,6 @@ var LinePdfGenerator = ({
|
|
|
42766
43457
|
month: "long",
|
|
42767
43458
|
timeZone: "Asia/Kolkata"
|
|
42768
43459
|
});
|
|
42769
|
-
doc.text(`${date} - ${shiftType}`, 20, 40);
|
|
42770
43460
|
const shiftStartTime = lineInfo.metrics.shift_start ? (/* @__PURE__ */ new Date(`2000-01-01 ${lineInfo.metrics.shift_start}`)).toLocaleTimeString("en-IN", {
|
|
42771
43461
|
hour: "2-digit",
|
|
42772
43462
|
minute: "2-digit",
|
|
@@ -42789,6 +43479,256 @@ var LinePdfGenerator = ({
|
|
|
42789
43479
|
timeZone: "Asia/Kolkata"
|
|
42790
43480
|
}) : "N/A";
|
|
42791
43481
|
}
|
|
43482
|
+
if (isUptimeMode) {
|
|
43483
|
+
const configuredTimezone = "Asia/Kolkata";
|
|
43484
|
+
const lineShiftStart = lineInfo.metrics.shift_start || "06:00";
|
|
43485
|
+
const lineShiftEnd = lineInfo.metrics.shift_end || "14:00";
|
|
43486
|
+
const shiftMinutes = getShiftDurationMinutes(lineShiftStart, lineShiftEnd) || 0;
|
|
43487
|
+
const workspaceSummaries = workspaceData.map((workspace) => {
|
|
43488
|
+
const shiftStart = workspace.shift_start || lineShiftStart;
|
|
43489
|
+
const shiftEnd = workspace.shift_end || lineShiftEnd;
|
|
43490
|
+
const shiftDate = workspace.date || lineInfo.date;
|
|
43491
|
+
const shiftDurationMinutes = getShiftDurationMinutes(shiftStart, shiftEnd) || shiftMinutes;
|
|
43492
|
+
const uptimeSeries = buildUptimeSeries({
|
|
43493
|
+
idleTimeHourly: workspace.idle_time_hourly,
|
|
43494
|
+
shiftStart,
|
|
43495
|
+
shiftEnd,
|
|
43496
|
+
shiftDate,
|
|
43497
|
+
timezone: configuredTimezone
|
|
43498
|
+
});
|
|
43499
|
+
let activeMinutes = uptimeSeries.activeMinutes;
|
|
43500
|
+
let idleMinutes = uptimeSeries.idleMinutes;
|
|
43501
|
+
let availableMinutes = uptimeSeries.availableMinutes;
|
|
43502
|
+
let hasData = uptimeSeries.hasData;
|
|
43503
|
+
if (!hasData) {
|
|
43504
|
+
const idleTimeValue = workspace.idle_time;
|
|
43505
|
+
const hasIdleTimeValue = Number.isFinite(idleTimeValue);
|
|
43506
|
+
const fallbackDuration = shiftDurationMinutes;
|
|
43507
|
+
if (hasIdleTimeValue && idleTimeValue > 0 && fallbackDuration > 0) {
|
|
43508
|
+
const idleFromAggregate = Math.min(Math.max(Number(idleTimeValue) / 60, 0), fallbackDuration);
|
|
43509
|
+
idleMinutes = idleFromAggregate;
|
|
43510
|
+
activeMinutes = Math.max(fallbackDuration - idleFromAggregate, 0);
|
|
43511
|
+
availableMinutes = activeMinutes + idleMinutes;
|
|
43512
|
+
hasData = true;
|
|
43513
|
+
}
|
|
43514
|
+
}
|
|
43515
|
+
const utilization = availableMinutes > 0 ? activeMinutes / availableMinutes * 100 : 0;
|
|
43516
|
+
return {
|
|
43517
|
+
workspace,
|
|
43518
|
+
utilization,
|
|
43519
|
+
idleTimeSeconds: idleMinutes * 60,
|
|
43520
|
+
hasData: hasData || availableMinutes > 0,
|
|
43521
|
+
uptimeSeries
|
|
43522
|
+
};
|
|
43523
|
+
});
|
|
43524
|
+
const validSummaries = workspaceSummaries.filter((summary) => summary.hasData);
|
|
43525
|
+
const computedAvgUtilization = validSummaries.length > 0 ? validSummaries.reduce((sum, summary) => sum + summary.utilization, 0) / validSummaries.length : 0;
|
|
43526
|
+
const avgUtilization = Number.isFinite(lineInfo.metrics.avg_efficiency) ? Number(lineInfo.metrics.avg_efficiency) : computedAvgUtilization;
|
|
43527
|
+
const avgIdleSeconds = validSummaries.length > 0 ? validSummaries.reduce((sum, summary) => sum + summary.idleTimeSeconds, 0) / validSummaries.length : 0;
|
|
43528
|
+
const buildHourlyFromSeries = (uptimeSeries) => {
|
|
43529
|
+
if (!uptimeSeries.shiftMinutes || uptimeSeries.shiftMinutes <= 0) return [];
|
|
43530
|
+
const totalHours = Math.ceil(uptimeSeries.shiftMinutes / 60);
|
|
43531
|
+
return Array.from({ length: totalHours }, (_, index) => {
|
|
43532
|
+
const start = index * 60;
|
|
43533
|
+
const end = Math.min(start + 60, uptimeSeries.points.length);
|
|
43534
|
+
const slice = uptimeSeries.points.slice(start, end);
|
|
43535
|
+
const activeMinutes = slice.filter((point) => point.status === "active").length;
|
|
43536
|
+
const idleMinutes = slice.filter((point) => point.status === "idle").length;
|
|
43537
|
+
const total = activeMinutes + idleMinutes;
|
|
43538
|
+
const uptimePercent = total > 0 ? Math.round(activeMinutes / total * 100) : 0;
|
|
43539
|
+
return { uptimePercent };
|
|
43540
|
+
});
|
|
43541
|
+
};
|
|
43542
|
+
let hourlyData = [];
|
|
43543
|
+
const seriesSummaries = workspaceSummaries.filter((summary) => summary.uptimeSeries.hasData && summary.uptimeSeries.points.length > 0);
|
|
43544
|
+
if (seriesSummaries.length > 0) {
|
|
43545
|
+
const hourlyShiftMinutes = seriesSummaries[0].uptimeSeries.shiftMinutes;
|
|
43546
|
+
const shiftDurationHours = Math.ceil(hourlyShiftMinutes / 60);
|
|
43547
|
+
hourlyData = Array.from({ length: shiftDurationHours }, (_, hourIndex) => {
|
|
43548
|
+
const start = hourIndex * 60;
|
|
43549
|
+
const end = Math.min(start + 60, hourlyShiftMinutes);
|
|
43550
|
+
let totalProductivePercent = 0;
|
|
43551
|
+
let workspaceCount = 0;
|
|
43552
|
+
seriesSummaries.forEach((summary) => {
|
|
43553
|
+
const slice = summary.uptimeSeries.points.slice(start, end);
|
|
43554
|
+
if (!slice.length) return;
|
|
43555
|
+
let activeForWorkspace = 0;
|
|
43556
|
+
let idleForWorkspace = 0;
|
|
43557
|
+
slice.forEach((point) => {
|
|
43558
|
+
if (point.status === "active") activeForWorkspace += 1;
|
|
43559
|
+
if (point.status === "idle") idleForWorkspace += 1;
|
|
43560
|
+
});
|
|
43561
|
+
const known = activeForWorkspace + idleForWorkspace;
|
|
43562
|
+
if (known > 0) {
|
|
43563
|
+
workspaceCount += 1;
|
|
43564
|
+
totalProductivePercent += activeForWorkspace / known * 100;
|
|
43565
|
+
}
|
|
43566
|
+
});
|
|
43567
|
+
const avgProductivePercent = workspaceCount > 0 ? totalProductivePercent / workspaceCount : 0;
|
|
43568
|
+
return {
|
|
43569
|
+
uptimePercent: Math.round(avgProductivePercent)
|
|
43570
|
+
};
|
|
43571
|
+
});
|
|
43572
|
+
} else {
|
|
43573
|
+
const lineUptimeSeries = buildUptimeSeries({
|
|
43574
|
+
idleTimeHourly: lineInfo.metrics.idle_time_hourly,
|
|
43575
|
+
shiftStart: lineShiftStart,
|
|
43576
|
+
shiftEnd: lineShiftEnd,
|
|
43577
|
+
shiftDate: lineInfo.date,
|
|
43578
|
+
timezone: configuredTimezone
|
|
43579
|
+
});
|
|
43580
|
+
hourlyData = buildHourlyFromSeries(lineUptimeSeries);
|
|
43581
|
+
}
|
|
43582
|
+
if (hourlyData.length === 0 && shiftMinutes > 0) {
|
|
43583
|
+
const shiftHours = Math.ceil(shiftMinutes / 60);
|
|
43584
|
+
hourlyData = Array.from({ length: shiftHours }, () => ({ uptimePercent: 0 }));
|
|
43585
|
+
}
|
|
43586
|
+
doc.setFillColor(250, 250, 250);
|
|
43587
|
+
doc.roundedRect(15, 25, 180, 53, 3, 3, "F");
|
|
43588
|
+
doc.setFontSize(32);
|
|
43589
|
+
doc.setFont("helvetica", "bold");
|
|
43590
|
+
doc.setTextColor(0, 0, 0);
|
|
43591
|
+
doc.text(lineInfo.line_name, 20, 39);
|
|
43592
|
+
doc.setFontSize(13);
|
|
43593
|
+
doc.setFont("helvetica", "normal");
|
|
43594
|
+
doc.setTextColor(60, 60, 60);
|
|
43595
|
+
doc.text(`${date}`, 20, 51);
|
|
43596
|
+
doc.text(`${shiftType}`, 20, 59);
|
|
43597
|
+
doc.setFontSize(12);
|
|
43598
|
+
doc.setTextColor(80, 80, 80);
|
|
43599
|
+
doc.text(`Report Period: ${shiftStartTime} - ${reportEndTime}`, 20, 67);
|
|
43600
|
+
doc.setTextColor(0, 0, 0);
|
|
43601
|
+
doc.setDrawColor(180, 180, 180);
|
|
43602
|
+
doc.setLineWidth(0.8);
|
|
43603
|
+
doc.line(20, 76, 190, 76);
|
|
43604
|
+
const perfOverviewStartY2 = 81;
|
|
43605
|
+
doc.setFillColor(245, 245, 245);
|
|
43606
|
+
doc.roundedRect(15, perfOverviewStartY2, 180, 60, 3, 3, "F");
|
|
43607
|
+
doc.setFontSize(18);
|
|
43608
|
+
doc.setFont("helvetica", "bold");
|
|
43609
|
+
doc.setTextColor(40, 40, 40);
|
|
43610
|
+
doc.text("Overview", 20, 91);
|
|
43611
|
+
doc.setTextColor(0, 0, 0);
|
|
43612
|
+
const kpiStartY2 = 103;
|
|
43613
|
+
const kpiSpacing2 = 10;
|
|
43614
|
+
createKPIBox(kpiStartY2);
|
|
43615
|
+
doc.setFontSize(11);
|
|
43616
|
+
doc.setFont("helvetica", "normal");
|
|
43617
|
+
doc.text("Utilization:", 25, kpiStartY2);
|
|
43618
|
+
doc.setFont("helvetica", "bold");
|
|
43619
|
+
doc.text(`${Math.round(avgUtilization)}%`, 120, kpiStartY2);
|
|
43620
|
+
createKPIBox(kpiStartY2 + kpiSpacing2);
|
|
43621
|
+
doc.setFont("helvetica", "normal");
|
|
43622
|
+
doc.text("Average Idle Time:", 25, kpiStartY2 + kpiSpacing2);
|
|
43623
|
+
doc.setFont("helvetica", "bold");
|
|
43624
|
+
doc.text(formatIdleTime(avgIdleSeconds), 120, kpiStartY2 + kpiSpacing2);
|
|
43625
|
+
createKPIBox(kpiStartY2 + kpiSpacing2 * 2);
|
|
43626
|
+
doc.setFont("helvetica", "normal");
|
|
43627
|
+
doc.text("Stoppages:", 25, kpiStartY2 + kpiSpacing2 * 2);
|
|
43628
|
+
doc.setFont("helvetica", "bold");
|
|
43629
|
+
doc.text(`${lineInfo.metrics.current_output || 0}`, 120, kpiStartY2 + kpiSpacing2 * 2);
|
|
43630
|
+
const separatorBeforeHourlyY = 151;
|
|
43631
|
+
doc.setDrawColor(180, 180, 180);
|
|
43632
|
+
doc.setLineWidth(0.8);
|
|
43633
|
+
doc.line(20, separatorBeforeHourlyY, 190, separatorBeforeHourlyY);
|
|
43634
|
+
const hourlyPerfStartY = 156;
|
|
43635
|
+
const maxContentY = pageHeight - 15;
|
|
43636
|
+
const baseTableStartY = hourlyPerfStartY + 31;
|
|
43637
|
+
let tableStartY2 = baseTableStartY;
|
|
43638
|
+
let rowHeight = 8;
|
|
43639
|
+
let headerFontSize = 11;
|
|
43640
|
+
let contentFontSize = 11;
|
|
43641
|
+
let titleFontSize = 18;
|
|
43642
|
+
const bottomPadding2 = 8;
|
|
43643
|
+
const estimatedEndY = tableStartY2 + hourlyData.length * rowHeight + bottomPadding2;
|
|
43644
|
+
if (estimatedEndY > maxContentY) {
|
|
43645
|
+
rowHeight = 6.5;
|
|
43646
|
+
headerFontSize = 9;
|
|
43647
|
+
contentFontSize = 9;
|
|
43648
|
+
titleFontSize = 16;
|
|
43649
|
+
tableStartY2 = hourlyPerfStartY + 27;
|
|
43650
|
+
}
|
|
43651
|
+
const backgroundHeight2 = tableStartY2 - hourlyPerfStartY + hourlyData.length * rowHeight + bottomPadding2;
|
|
43652
|
+
doc.setFillColor(245, 245, 245);
|
|
43653
|
+
doc.roundedRect(15, hourlyPerfStartY, 180, backgroundHeight2, 3, 3, "F");
|
|
43654
|
+
doc.setFontSize(titleFontSize);
|
|
43655
|
+
doc.setFont("helvetica", "bold");
|
|
43656
|
+
doc.setTextColor(40, 40, 40);
|
|
43657
|
+
const hourlyTitleY = hourlyPerfStartY + 10;
|
|
43658
|
+
doc.text("Hourly Utilization", 20, hourlyTitleY);
|
|
43659
|
+
doc.setTextColor(0, 0, 0);
|
|
43660
|
+
const headerY = titleFontSize === 16 ? hourlyPerfStartY + 18 : hourlyPerfStartY + 20;
|
|
43661
|
+
const gridTopY2 = headerY - 5;
|
|
43662
|
+
const headerBottomY2 = gridTopY2 + 8;
|
|
43663
|
+
const colBoundaries2 = [20, 105, 190];
|
|
43664
|
+
const totalRows2 = hourlyData.length;
|
|
43665
|
+
const gridBottomY2 = headerBottomY2 + totalRows2 * rowHeight;
|
|
43666
|
+
const tableHeight2 = gridBottomY2 - gridTopY2;
|
|
43667
|
+
doc.setFillColor(255, 255, 255);
|
|
43668
|
+
doc.roundedRect(20, gridTopY2, 170, tableHeight2, 2, 2, "F");
|
|
43669
|
+
doc.setDrawColor(230, 230, 230);
|
|
43670
|
+
doc.setLineWidth(0.2);
|
|
43671
|
+
doc.roundedRect(20, gridTopY2, 170, tableHeight2, 2, 2, "S");
|
|
43672
|
+
doc.setDrawColor(200, 200, 200);
|
|
43673
|
+
doc.setLineWidth(0.3);
|
|
43674
|
+
doc.line(20, headerBottomY2, 190, headerBottomY2);
|
|
43675
|
+
colBoundaries2.slice(1, -1).forEach((x) => {
|
|
43676
|
+
doc.line(x, gridTopY2, x, gridBottomY2);
|
|
43677
|
+
});
|
|
43678
|
+
doc.setFontSize(headerFontSize);
|
|
43679
|
+
doc.setFont("helvetica", "bold");
|
|
43680
|
+
const headerTextY = gridTopY2 + 5.5;
|
|
43681
|
+
doc.text("Time Range", 25, headerTextY);
|
|
43682
|
+
doc.text("Utilization", 147, headerTextY);
|
|
43683
|
+
doc.setFontSize(contentFontSize);
|
|
43684
|
+
doc.setFont("helvetica", "normal");
|
|
43685
|
+
let yPos2 = headerBottomY2 + 5.5;
|
|
43686
|
+
const now5 = /* @__PURE__ */ new Date();
|
|
43687
|
+
const currentTimeIST2 = new Date(now5.toLocaleString("en-US", { timeZone: configuredTimezone }));
|
|
43688
|
+
const [sYear2, sMonth2, sDay2] = lineInfo.date.split("-").map(Number);
|
|
43689
|
+
const [sStartH2, sStartM2] = (lineShiftStart || "06:00").split(":").map(Number);
|
|
43690
|
+
const shiftStartBase2 = new Date(sYear2, sMonth2 - 1, sDay2, sStartH2, sStartM2 || 0);
|
|
43691
|
+
hourlyData.forEach((entry, index) => {
|
|
43692
|
+
const bucketStartTime = new Date(shiftStartBase2);
|
|
43693
|
+
bucketStartTime.setHours(bucketStartTime.getHours() + index);
|
|
43694
|
+
const bucketEndTime = new Date(bucketStartTime);
|
|
43695
|
+
bucketEndTime.setHours(bucketEndTime.getHours() + 1);
|
|
43696
|
+
const timeRange = `${bucketStartTime.toLocaleTimeString("en-IN", {
|
|
43697
|
+
hour: "numeric",
|
|
43698
|
+
hour12: true
|
|
43699
|
+
})} - ${bucketEndTime.toLocaleTimeString("en-IN", {
|
|
43700
|
+
hour: "numeric",
|
|
43701
|
+
hour12: true
|
|
43702
|
+
})}`;
|
|
43703
|
+
const dataCollected = bucketEndTime.getTime() <= currentTimeIST2.getTime();
|
|
43704
|
+
if (index < totalRows2 - 1) {
|
|
43705
|
+
const rowBottomY = headerBottomY2 + (index + 1) * rowHeight;
|
|
43706
|
+
doc.setDrawColor(200, 200, 200);
|
|
43707
|
+
doc.line(20, rowBottomY, 190, rowBottomY);
|
|
43708
|
+
}
|
|
43709
|
+
doc.text(timeRange, 25, yPos2);
|
|
43710
|
+
const utilizationStr = dataCollected ? `${entry.uptimePercent}%` : "TBD";
|
|
43711
|
+
doc.text(utilizationStr, 147, yPos2);
|
|
43712
|
+
yPos2 += rowHeight;
|
|
43713
|
+
});
|
|
43714
|
+
const fileDate2 = new Date(lineInfo.date).toLocaleDateString("en-IN", {
|
|
43715
|
+
day: "2-digit",
|
|
43716
|
+
month: "short",
|
|
43717
|
+
year: "numeric",
|
|
43718
|
+
timeZone: "Asia/Kolkata"
|
|
43719
|
+
}).replace(/ /g, "_");
|
|
43720
|
+
const fileShift2 = shiftType.replace(/ /g, "_");
|
|
43721
|
+
const fileName2 = `${lineInfo.line_name}_${fileDate2}_${fileShift2}.pdf`;
|
|
43722
|
+
doc.save(fileName2);
|
|
43723
|
+
return;
|
|
43724
|
+
}
|
|
43725
|
+
doc.setFontSize(26);
|
|
43726
|
+
doc.setFont("helvetica", "bold");
|
|
43727
|
+
doc.setTextColor(0, 0, 0);
|
|
43728
|
+
doc.text(lineInfo.line_name, 20, 30);
|
|
43729
|
+
doc.setFontSize(14);
|
|
43730
|
+
doc.setFont("helvetica", "normal");
|
|
43731
|
+
doc.text(`${date} - ${shiftType}`, 20, 40);
|
|
42792
43732
|
doc.setFontSize(12);
|
|
42793
43733
|
doc.setTextColor(100, 100, 100);
|
|
42794
43734
|
doc.text(`Report Period: ${shiftStartTime} - ${reportEndTime}`, 20, 47);
|
|
@@ -42804,13 +43744,6 @@ var LinePdfGenerator = ({
|
|
|
42804
43744
|
doc.setTextColor(40, 40, 40);
|
|
42805
43745
|
doc.text("Line Performance Overview", 20, 68);
|
|
42806
43746
|
doc.setTextColor(0, 0, 0);
|
|
42807
|
-
const createKPIBox = (y) => {
|
|
42808
|
-
doc.setFillColor(255, 255, 255);
|
|
42809
|
-
doc.roundedRect(22, y - 7, 165, 12, 2, 2, "F");
|
|
42810
|
-
doc.setDrawColor(230, 230, 230);
|
|
42811
|
-
doc.setLineWidth(0.2);
|
|
42812
|
-
doc.roundedRect(22, y - 7, 165, 12, 2, 2, "S");
|
|
42813
|
-
};
|
|
42814
43747
|
const kpiStartY = 80;
|
|
42815
43748
|
const kpiSpacing = 10;
|
|
42816
43749
|
createKPIBox(kpiStartY);
|
|
@@ -43084,23 +44017,17 @@ var LinePdfGenerator = ({
|
|
|
43084
44017
|
doc.text("Remarks", 160, tableHeaderY);
|
|
43085
44018
|
doc.setFont("helvetica", "normal");
|
|
43086
44019
|
let yPos = tableStartY;
|
|
43087
|
-
const
|
|
43088
|
-
const
|
|
43089
|
-
|
|
43090
|
-
|
|
43091
|
-
const
|
|
43092
|
-
let currentHour = 24;
|
|
43093
|
-
if (isTodayForTable) {
|
|
43094
|
-
const now4 = /* @__PURE__ */ new Date();
|
|
43095
|
-
const currentTimeIST = new Date(now4.toLocaleString("en-US", { timeZone: "Asia/Kolkata" }));
|
|
43096
|
-
currentHour = currentTimeIST.getHours();
|
|
43097
|
-
}
|
|
44020
|
+
const now4 = /* @__PURE__ */ new Date();
|
|
44021
|
+
const currentTimeIST = new Date(now4.toLocaleString("en-US", { timeZone: "Asia/Kolkata" }));
|
|
44022
|
+
const [sYear, sMonth, sDay] = lineInfo.date.split("-").map(Number);
|
|
44023
|
+
const [sStartH, sStartM] = (lineInfo.metrics.shift_start || "06:00").split(":").map(Number);
|
|
44024
|
+
const shiftStartBase = new Date(sYear, sMonth - 1, sDay, sStartH, sStartM || 0);
|
|
43098
44025
|
hourlyTimeRanges.forEach((timeRange, index) => {
|
|
43099
44026
|
const actualOutput = hourlyActualOutput[index] || 0;
|
|
43100
|
-
const
|
|
43101
|
-
|
|
43102
|
-
const
|
|
43103
|
-
const dataCollected =
|
|
44027
|
+
const bucketStartTime = new Date(shiftStartBase);
|
|
44028
|
+
bucketStartTime.setHours(bucketStartTime.getHours() + index);
|
|
44029
|
+
const bucketEndTime = new Date(bucketStartTime.getTime() + timeRange.minutes * 60 * 1e3);
|
|
44030
|
+
const dataCollected = bucketEndTime.getTime() <= currentTimeIST.getTime();
|
|
43104
44031
|
const outputStr = dataCollected ? actualOutput.toString() : "TBD";
|
|
43105
44032
|
if (index < totalRows - 1) {
|
|
43106
44033
|
const rowBottomY = headerBottomY + (index + 1) * rowSpacing;
|
|
@@ -43516,7 +44443,7 @@ var WorkspaceHistoryCalendar = ({
|
|
|
43516
44443
|
const effectiveLegend = legend || DEFAULT_EFFICIENCY_LEGEND;
|
|
43517
44444
|
const hasRealData = (shift) => {
|
|
43518
44445
|
if (shift.hasData !== void 0) return shift.hasData;
|
|
43519
|
-
return shift.efficiency > 0 || shift.output > 0 || shift.cycleTime > 0 || shift.pph > 0 || shift.
|
|
44446
|
+
return shift.efficiency > 0 || shift.output > 0 || shift.cycleTime > 0 || shift.pph > 0 || shift.targetOutput > 0 || shift.idleTime > 0;
|
|
43520
44447
|
};
|
|
43521
44448
|
React26.useEffect(() => {
|
|
43522
44449
|
setAnimationComplete(false);
|
|
@@ -43663,7 +44590,7 @@ var WorkspaceHistoryCalendar = ({
|
|
|
43663
44590
|
"Output: ",
|
|
43664
44591
|
Math.round(shift.output),
|
|
43665
44592
|
" / ",
|
|
43666
|
-
Math.round(shift.
|
|
44593
|
+
Math.round(shift.targetOutput)
|
|
43667
44594
|
] }),
|
|
43668
44595
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
43669
44596
|
"Cycle: ",
|
|
@@ -43827,7 +44754,8 @@ var CustomTooltip3 = ({ active, payload, label, isUptimeMode }) => {
|
|
|
43827
44754
|
/* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-xs text-gray-600", children: [
|
|
43828
44755
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: "Utilization:" }),
|
|
43829
44756
|
" ",
|
|
43830
|
-
utilization
|
|
44757
|
+
utilization,
|
|
44758
|
+
"%"
|
|
43831
44759
|
] })
|
|
43832
44760
|
] })
|
|
43833
44761
|
] });
|
|
@@ -43917,7 +44845,7 @@ var WorkspaceMonthlyHistory = ({
|
|
|
43917
44845
|
});
|
|
43918
44846
|
const hasRealData = (shift) => {
|
|
43919
44847
|
if (shift.hasData !== void 0) return shift.hasData;
|
|
43920
|
-
return shift.efficiency > 0 || shift.output > 0 || shift.cycleTime > 0 || shift.pph > 0 || shift.idealOutput > 0 || shift.idleTime > 0;
|
|
44848
|
+
return shift.efficiency > 0 || shift.output > 0 || shift.cycleTime > 0 || shift.pph > 0 || shift.idealOutput > 0 || shift.idleTime > 0 || (shift.availableTimeSeconds ?? 0) > 0;
|
|
43921
44849
|
};
|
|
43922
44850
|
const shiftWorkSeconds = React26.useMemo(() => {
|
|
43923
44851
|
if (!shiftConfig) return null;
|
|
@@ -43933,7 +44861,6 @@ var WorkspaceMonthlyHistory = ({
|
|
|
43933
44861
|
const dailyData = [];
|
|
43934
44862
|
if (isUptimeMode) {
|
|
43935
44863
|
let maxHours = 0;
|
|
43936
|
-
const shiftSeconds = shiftWorkSeconds ?? 0;
|
|
43937
44864
|
for (const day of dayNumbers) {
|
|
43938
44865
|
const dayData = analysisMonthlyData.find((d) => {
|
|
43939
44866
|
const date = new Date(d.date);
|
|
@@ -43941,12 +44868,28 @@ var WorkspaceMonthlyHistory = ({
|
|
|
43941
44868
|
});
|
|
43942
44869
|
const shiftData = dayData ? getShiftData(dayData, selectedShiftId) : null;
|
|
43943
44870
|
const hasShiftData = Boolean(shiftData && hasRealData(shiftData));
|
|
43944
|
-
const
|
|
43945
|
-
const
|
|
43946
|
-
|
|
43947
|
-
|
|
43948
|
-
|
|
43949
|
-
|
|
44871
|
+
const availableSeconds = hasShiftData ? shiftData.availableTimeSeconds ?? shiftWorkSeconds ?? 0 : 0;
|
|
44872
|
+
const efficiencyValue = hasShiftData && Number.isFinite(shiftData?.efficiency) ? Number(shiftData.efficiency) : null;
|
|
44873
|
+
let productiveHours = 0;
|
|
44874
|
+
let idleHours = 0;
|
|
44875
|
+
let utilization = 0;
|
|
44876
|
+
if (efficiencyValue !== null && availableSeconds > 0) {
|
|
44877
|
+
const clampedEfficiency = Math.max(0, Math.min(100, efficiencyValue));
|
|
44878
|
+
utilization = Math.round(clampedEfficiency);
|
|
44879
|
+
const totalHours = availableSeconds / 3600;
|
|
44880
|
+
productiveHours = totalHours * clampedEfficiency / 100;
|
|
44881
|
+
idleHours = Math.max(0, totalHours - productiveHours);
|
|
44882
|
+
} else if (hasShiftData && availableSeconds > 0) {
|
|
44883
|
+
const idleSeconds = shiftData.idleTime || 0;
|
|
44884
|
+
const clampedIdleSeconds = Math.min(Math.max(idleSeconds, 0), availableSeconds);
|
|
44885
|
+
const productiveSeconds = Math.max(
|
|
44886
|
+
shiftData.activeTimeSeconds ?? availableSeconds - clampedIdleSeconds,
|
|
44887
|
+
0
|
|
44888
|
+
);
|
|
44889
|
+
productiveHours = productiveSeconds / 3600;
|
|
44890
|
+
idleHours = clampedIdleSeconds / 3600;
|
|
44891
|
+
utilization = Math.round(productiveSeconds / availableSeconds * 100);
|
|
44892
|
+
}
|
|
43950
44893
|
maxHours = Math.max(maxHours, idleHours + productiveHours);
|
|
43951
44894
|
dailyData.push({
|
|
43952
44895
|
hour: getOrdinal2(day),
|
|
@@ -44043,12 +44986,11 @@ var WorkspaceMonthlyHistory = ({
|
|
|
44043
44986
|
}, [chartData.yAxisMax, chartData.lastSetTarget, isUptimeMode]);
|
|
44044
44987
|
const pieChartData = React26.useMemo(() => {
|
|
44045
44988
|
const validShifts = analysisMonthlyData.map((d) => getShiftData(d, selectedShiftId)).filter(hasRealData);
|
|
44046
|
-
if (validShifts.length === 0
|
|
44047
|
-
const
|
|
44048
|
-
|
|
44049
|
-
const
|
|
44050
|
-
const
|
|
44051
|
-
const productivePercent = Math.round(activeTime / totalShiftTime * 100);
|
|
44989
|
+
if (validShifts.length === 0) return [];
|
|
44990
|
+
const efficiencyValues = validShifts.map((shift) => Number.isFinite(shift.efficiency) ? Number(shift.efficiency) : null).filter((value) => value !== null);
|
|
44991
|
+
if (!efficiencyValues.length) return [];
|
|
44992
|
+
const avgEfficiency = efficiencyValues.reduce((sum, value) => sum + value, 0) / efficiencyValues.length;
|
|
44993
|
+
const productivePercent = Math.round(Math.max(0, Math.min(100, avgEfficiency)));
|
|
44052
44994
|
const idlePercent = Math.max(0, Math.min(100, 100 - productivePercent));
|
|
44053
44995
|
return [
|
|
44054
44996
|
{ name: "Productive", value: productivePercent },
|
|
@@ -44057,30 +44999,37 @@ var WorkspaceMonthlyHistory = ({
|
|
|
44057
44999
|
}, [analysisMonthlyData, selectedShiftId, shiftWorkSeconds]);
|
|
44058
45000
|
const metrics2 = React26.useMemo(() => {
|
|
44059
45001
|
const validShifts = analysisMonthlyData.map((d) => getShiftData(d, selectedShiftId)).filter(hasRealData);
|
|
44060
|
-
|
|
44061
|
-
|
|
44062
|
-
const
|
|
44063
|
-
const
|
|
44064
|
-
|
|
44065
|
-
|
|
44066
|
-
|
|
45002
|
+
const filteredShifts = isUptimeMode ? validShifts : validShifts.filter((shift) => (shift.efficiency ?? 0) >= 5);
|
|
45003
|
+
if (filteredShifts.length === 0) return null;
|
|
45004
|
+
const totalEfficiency = filteredShifts.reduce((sum, shift) => sum + (shift.efficiency || 0), 0);
|
|
45005
|
+
const totalUtilization = filteredShifts.reduce(
|
|
45006
|
+
(sum, shift) => sum + getUptimeUtilizationPercent(shift),
|
|
45007
|
+
0
|
|
45008
|
+
);
|
|
45009
|
+
const totalCycleTime = filteredShifts.reduce((sum, shift) => sum + shift.cycleTime, 0);
|
|
45010
|
+
const totalOutput = filteredShifts.reduce((sum, shift) => sum + shift.output, 0);
|
|
45011
|
+
filteredShifts.reduce((sum, shift) => sum + shift.idealOutput, 0);
|
|
45012
|
+
const totalIdleTime = filteredShifts.reduce((sum, shift) => sum + shift.idleTime, 0);
|
|
45013
|
+
const ranks = filteredShifts.map((s) => s.rank).filter((r2) => typeof r2 === "number" && r2 > 0);
|
|
44067
45014
|
if (isUptimeMode) {
|
|
44068
|
-
|
|
44069
|
-
|
|
44070
|
-
|
|
44071
|
-
|
|
44072
|
-
|
|
44073
|
-
|
|
45015
|
+
let totalIdleSeconds = 0;
|
|
45016
|
+
filteredShifts.forEach((shift) => {
|
|
45017
|
+
const availableSeconds = shift.availableTimeSeconds ?? shiftWorkSeconds ?? 0;
|
|
45018
|
+
const idleSeconds = Math.min(Math.max(shift.idleTime || 0, 0), availableSeconds);
|
|
45019
|
+
totalIdleSeconds += idleSeconds;
|
|
45020
|
+
});
|
|
45021
|
+
const avgUtilization = filteredShifts.length > 0 ? Math.round(totalUtilization / filteredShifts.length) : 0;
|
|
45022
|
+
const avgIdleTime = filteredShifts.length > 0 ? Math.round(totalIdleSeconds / filteredShifts.length) : 0;
|
|
45023
|
+
Math.round(totalCycleTime / filteredShifts.length);
|
|
44074
45024
|
return {
|
|
44075
45025
|
avgUtilization,
|
|
44076
45026
|
avgIdleTime,
|
|
44077
|
-
avgDailyStoppages:
|
|
44078
|
-
// Mock data
|
|
45027
|
+
avgDailyStoppages: Math.round(totalOutput / filteredShifts.length)
|
|
44079
45028
|
};
|
|
44080
45029
|
}
|
|
44081
|
-
const avgEfficiency = Math.round(totalEfficiency /
|
|
44082
|
-
const avgDailyOutput = Math.round(totalOutput /
|
|
44083
|
-
const avgCycleTime = Math.round(totalCycleTime /
|
|
45030
|
+
const avgEfficiency = Math.round(totalEfficiency / filteredShifts.length);
|
|
45031
|
+
const avgDailyOutput = Math.round(totalOutput / filteredShifts.length);
|
|
45032
|
+
const avgCycleTime = Math.round(totalCycleTime / filteredShifts.length);
|
|
44084
45033
|
const avgRank = ranks.length > 0 ? Math.round(ranks.reduce((a, b) => a + b, 0) / ranks.length) : null;
|
|
44085
45034
|
return {
|
|
44086
45035
|
avgEfficiency,
|
|
@@ -44088,7 +45037,7 @@ var WorkspaceMonthlyHistory = ({
|
|
|
44088
45037
|
avgCycleTime,
|
|
44089
45038
|
avgRank,
|
|
44090
45039
|
totalOutput,
|
|
44091
|
-
avgIdleTime: Math.round(totalIdleTime /
|
|
45040
|
+
avgIdleTime: Math.round(totalIdleTime / filteredShifts.length)
|
|
44092
45041
|
};
|
|
44093
45042
|
}, [analysisMonthlyData, selectedShiftId, isUptimeMode, shiftWorkSeconds]);
|
|
44094
45043
|
const efficiencyDelta = trendSummary?.avg_efficiency?.delta_pp ?? 0;
|
|
@@ -44101,6 +45050,19 @@ var WorkspaceMonthlyHistory = ({
|
|
|
44101
45050
|
const outputImproved = outputDelta >= 0;
|
|
44102
45051
|
const cycleDelta = cyclePrev ? cycleDeltaRaw / cyclePrev * 100 : 0;
|
|
44103
45052
|
const cycleWorsened = cycleDelta > 0;
|
|
45053
|
+
const utilizationDelta = efficiencyDelta;
|
|
45054
|
+
const utilizationImproved = utilizationDelta >= 0;
|
|
45055
|
+
const utilizationTrendText = `${Math.abs(utilizationDelta).toFixed(1)}% vs last month`;
|
|
45056
|
+
const idleDeltaRaw = trendSummary?.avg_idle_time?.delta_seconds ?? 0;
|
|
45057
|
+
const idlePrev = trendSummary?.avg_idle_time?.previous ?? 0;
|
|
45058
|
+
const idleDelta = idlePrev ? idleDeltaRaw / idlePrev * 100 : 0;
|
|
45059
|
+
const idleImproved = idleDelta <= 0;
|
|
45060
|
+
const idleTrendText = `${Math.abs(idleDelta).toFixed(1)}% vs last month`;
|
|
45061
|
+
const stoppagesDeltaRaw = trendSummary?.avg_daily_stoppages?.delta_count ?? 0;
|
|
45062
|
+
const stoppagesPrev = trendSummary?.avg_daily_stoppages?.previous ?? 0;
|
|
45063
|
+
const stoppagesDelta = stoppagesPrev ? stoppagesDeltaRaw / stoppagesPrev * 100 : 0;
|
|
45064
|
+
const stoppagesImproved = stoppagesDelta <= 0;
|
|
45065
|
+
const stoppagesTrendText = `${Math.abs(stoppagesDelta).toFixed(1)}% vs last month`;
|
|
44104
45066
|
const calendarData = React26.useMemo(() => {
|
|
44105
45067
|
const startOfMonth2 = new Date(year, month, 1);
|
|
44106
45068
|
const endOfMonth2 = new Date(year, month + 1, 0);
|
|
@@ -44185,11 +45147,12 @@ var WorkspaceMonthlyHistory = ({
|
|
|
44185
45147
|
if (!hasData || !shiftData) return "bg-gray-300 dark:bg-gray-600";
|
|
44186
45148
|
if (showRange && !inRange) return "bg-gray-200 dark:bg-gray-700";
|
|
44187
45149
|
const idleSeconds = Math.max(shiftData.idleTime || 0, 0);
|
|
44188
|
-
const totalShiftSeconds = shiftWorkSeconds ?? 0;
|
|
45150
|
+
const totalShiftSeconds = shiftData.availableTimeSeconds ?? shiftWorkSeconds ?? 0;
|
|
44189
45151
|
const clampedIdleSeconds = totalShiftSeconds > 0 ? Math.min(idleSeconds, totalShiftSeconds) : idleSeconds;
|
|
44190
|
-
const
|
|
45152
|
+
const fallbackUtilization = totalShiftSeconds > 0 ? Math.round((totalShiftSeconds - clampedIdleSeconds) / totalShiftSeconds * 100) : 0;
|
|
45153
|
+
const utilizationValue = Number.isFinite(shiftData.efficiency) ? shiftData.efficiency : fallbackUtilization;
|
|
44191
45154
|
const efficiencyColor = getEfficiencyColor(
|
|
44192
|
-
isUptimeMode ?
|
|
45155
|
+
isUptimeMode ? utilizationValue : shiftData.efficiency,
|
|
44193
45156
|
effectiveLegend
|
|
44194
45157
|
);
|
|
44195
45158
|
if (efficiencyColor === "green") return "bg-green-500 dark:bg-green-600";
|
|
@@ -44220,7 +45183,16 @@ var WorkspaceMonthlyHistory = ({
|
|
|
44220
45183
|
!isFuture && hasData && shiftData && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 bg-black/80 rounded-lg p-2 text-white opacity-0 group-hover:opacity-100 transition-opacity", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs space-y-1", children: isUptimeMode ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
44221
45184
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
44222
45185
|
"Utilization: ",
|
|
44223
|
-
|
|
45186
|
+
(() => {
|
|
45187
|
+
const totalShiftSeconds = shiftData.availableTimeSeconds ?? shiftWorkSeconds ?? 0;
|
|
45188
|
+
const idleSeconds = Math.min(
|
|
45189
|
+
Math.max(shiftData.idleTime || 0, 0),
|
|
45190
|
+
totalShiftSeconds
|
|
45191
|
+
);
|
|
45192
|
+
const fallbackUtilization = totalShiftSeconds > 0 ? Math.round((totalShiftSeconds - idleSeconds) / totalShiftSeconds * 100) : 0;
|
|
45193
|
+
return Number.isFinite(shiftData.efficiency) ? Math.round(shiftData.efficiency) : fallbackUtilization;
|
|
45194
|
+
})(),
|
|
45195
|
+
"%"
|
|
44224
45196
|
] }),
|
|
44225
45197
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
44226
45198
|
"Idle Time: ",
|
|
@@ -44246,33 +45218,42 @@ var WorkspaceMonthlyHistory = ({
|
|
|
44246
45218
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-4", children: [
|
|
44247
45219
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-1 md:grid-cols-3 gap-4", children: [
|
|
44248
45220
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-white rounded-lg shadow-sm border border-gray-100 p-4 flex flex-col justify-between", children: [
|
|
44249
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm font-
|
|
45221
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm font-semibold text-gray-600 mb-1", children: isUptimeMode ? "Avg Utilization" : "Avg Efficiency" }),
|
|
44250
45222
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 flex-nowrap", children: [
|
|
44251
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-
|
|
44252
|
-
|
|
45223
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-2xl font-bold text-gray-900", children: isUptimeMode ? `${metrics2?.avgUtilization ?? 0}%` : `${metrics2?.avgEfficiency ?? 0}%` }),
|
|
45224
|
+
isUptimeMode ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `flex items-center gap-1 ${utilizationImproved ? "bg-emerald-50 text-emerald-600" : "bg-red-50 text-red-600"} px-2 py-0.5 rounded-full text-[10px] font-medium whitespace-nowrap flex-shrink-0`, children: [
|
|
45225
|
+
utilizationImproved ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowUp, { className: "w-3 h-3" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowDown, { className: "w-3 h-3" }),
|
|
45226
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: utilizationTrendText })
|
|
45227
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `flex items-center gap-1 ${efficiencyImproved ? "bg-emerald-50 text-emerald-600" : "bg-red-50 text-red-600"} px-2 py-0.5 rounded-full text-[10px] font-medium whitespace-nowrap flex-shrink-0`, children: [
|
|
44253
45228
|
efficiencyImproved ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowUp, { className: "w-3 h-3" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowDown, { className: "w-3 h-3" }),
|
|
44254
45229
|
/* @__PURE__ */ jsxRuntime.jsx("span", { children: `${Math.abs(efficiencyDelta).toFixed(1)}% vs last month` })
|
|
44255
45230
|
] })
|
|
44256
45231
|
] })
|
|
44257
45232
|
] }),
|
|
44258
45233
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-white rounded-lg shadow-sm border border-gray-100 p-4 flex flex-col justify-between", children: [
|
|
44259
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm font-
|
|
45234
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm font-semibold text-gray-600 mb-1", children: isUptimeMode ? "Avg Idle Time" : "Avg Daily Output" }),
|
|
44260
45235
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 flex-nowrap", children: [
|
|
44261
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-
|
|
44262
|
-
|
|
45236
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-2xl font-bold text-gray-900", children: isUptimeMode ? formatIdleTime(metrics2?.avgIdleTime ?? 0) : metrics2?.avgDailyOutput?.toLocaleString?.() ?? 0 }),
|
|
45237
|
+
isUptimeMode ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `flex items-center gap-1 ${idleImproved ? "bg-emerald-50 text-emerald-600" : "bg-red-50 text-red-600"} px-2 py-0.5 rounded-full text-[10px] font-medium whitespace-nowrap flex-shrink-0`, children: [
|
|
45238
|
+
idleImproved ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowDown, { className: "w-3 h-3" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowUp, { className: "w-3 h-3" }),
|
|
45239
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: idleTrendText })
|
|
45240
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `flex items-center gap-1 ${outputImproved ? "bg-emerald-50 text-emerald-600" : "bg-red-50 text-red-600"} px-2 py-0.5 rounded-full text-[10px] font-medium whitespace-nowrap flex-shrink-0`, children: [
|
|
44263
45241
|
outputImproved ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowUp, { className: "w-3 h-3" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowDown, { className: "w-3 h-3" }),
|
|
44264
45242
|
/* @__PURE__ */ jsxRuntime.jsx("span", { children: `${Math.abs(outputDelta).toFixed(1)}% vs last month` })
|
|
44265
45243
|
] })
|
|
44266
45244
|
] })
|
|
44267
45245
|
] }),
|
|
44268
45246
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-white rounded-lg shadow-sm border border-gray-100 p-4 flex flex-col justify-between", children: [
|
|
44269
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm font-
|
|
45247
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm font-semibold text-gray-600 mb-1", children: isUptimeMode ? "Avg Daily Stoppages" : "Avg Cycle Time" }),
|
|
44270
45248
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 flex-nowrap", children: [
|
|
44271
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-
|
|
45249
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-2xl font-bold text-gray-900", children: [
|
|
44272
45250
|
isUptimeMode ? metrics2?.avgDailyStoppages ?? 0 : metrics2?.avgCycleTime ?? 0,
|
|
44273
45251
|
isUptimeMode ? "" : "s"
|
|
44274
45252
|
] }),
|
|
44275
|
-
|
|
45253
|
+
isUptimeMode ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `flex items-center gap-1 ${stoppagesImproved ? "bg-emerald-50 text-emerald-600" : "bg-red-50 text-red-600"} px-2 py-0.5 rounded-full text-[10px] font-medium whitespace-nowrap flex-shrink-0`, children: [
|
|
45254
|
+
stoppagesImproved ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowDown, { className: "w-3 h-3" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowUp, { className: "w-3 h-3" }),
|
|
45255
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: stoppagesTrendText })
|
|
45256
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `flex items-center gap-1 ${cycleWorsened ? "bg-red-50 text-red-600" : "bg-emerald-50 text-emerald-600"} px-2 py-0.5 rounded-full text-[10px] font-medium whitespace-nowrap flex-shrink-0`, children: [
|
|
44276
45257
|
cycleWorsened ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowUp, { className: "w-3 h-3" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowDown, { className: "w-3 h-3" }),
|
|
44277
45258
|
/* @__PURE__ */ jsxRuntime.jsx("span", { children: `${Math.abs(cycleDelta).toFixed(1)}% vs last month` })
|
|
44278
45259
|
] })
|
|
@@ -44316,8 +45297,8 @@ var WorkspaceMonthlyHistory = ({
|
|
|
44316
45297
|
className: "font-bold text-gray-900 leading-none",
|
|
44317
45298
|
style: { fontSize: "clamp(1rem, 15cqw, 1.5rem)" },
|
|
44318
45299
|
children: [
|
|
44319
|
-
pieChartData[0]?.value,
|
|
44320
|
-
|
|
45300
|
+
pieChartData[0]?.value ?? 0,
|
|
45301
|
+
"%"
|
|
44321
45302
|
]
|
|
44322
45303
|
}
|
|
44323
45304
|
),
|
|
@@ -44547,7 +45528,8 @@ var WorkspaceWhatsAppShareButton = ({
|
|
|
44547
45528
|
const shiftSeconds = shiftMinutes ? shiftMinutes * 60 : 0;
|
|
44548
45529
|
const idleSeconds = Math.max(workspace.idle_time || 0, 0);
|
|
44549
45530
|
const clampedIdleSeconds = shiftSeconds > 0 ? Math.min(idleSeconds, shiftSeconds) : idleSeconds;
|
|
44550
|
-
const
|
|
45531
|
+
const efficiencyValue = Number.isFinite(workspace.avg_efficiency) ? Number(workspace.avg_efficiency) : null;
|
|
45532
|
+
const utilization = efficiencyValue !== null ? Math.max(0, Math.round(efficiencyValue)) : shiftSeconds > 0 ? Math.max(0, Math.round((shiftSeconds - clampedIdleSeconds) / shiftSeconds * 100)) : 0;
|
|
44551
45533
|
const progressPercent = workspace.target_output > 0 ? workspace.total_actions / workspace.target_output * 100 : 0;
|
|
44552
45534
|
const message = isUptimeMode ? `*${workspace.workspace_name} Utilization Report*%0A${date} - ${workspace.shift_type}%0A%0A*Utilization:* ${utilization}%0A*Stoppages:* ${workspace.total_actions}%0A*Idle Time:* ${formatIdleTime(clampedIdleSeconds)}%0A*Avg Machine Continuous On Time:* ${workspace.avg_cycle_time.toFixed(1)}s%0A*Rank:* ${workspace.workspace_rank} of ${workspace.total_workspaces}%0A%0AGenerated by Optifye.ai` : `*${workspace.workspace_name} Performance Report*%0A${date} - ${workspace.shift_type}%0A%0A*Progress:* ${progressPercent.toFixed(1)}% of Today's target%0A*Current Output:* ${workspace.total_actions} / ${workspace.target_output}%0A*Efficiency:* ${(workspace.avg_efficiency || 0).toFixed(1)}%25%0A*PPH:* ${workspace.avg_pph.toFixed(1)} (Target: ${workspace.pph_threshold.toFixed(1)})%0A*Cycle Time:* ${workspace.avg_cycle_time.toFixed(1)}s (Standard: ${workspace.ideal_cycle_time.toFixed(1)}s)%0A*Rank:* ${workspace.workspace_rank} of ${workspace.total_workspaces}%0A%0AGenerated by Optifye.ai`;
|
|
44553
45535
|
window.open(`https://wa.me/?text=${message}`, "_blank");
|
|
@@ -44576,7 +45558,8 @@ var WorkspacePdfGenerator = ({ workspace, className, idleTimeReasons, efficiency
|
|
|
44576
45558
|
const shiftSeconds = shiftMinutes ? shiftMinutes * 60 : 0;
|
|
44577
45559
|
const idleSeconds = Math.max(workspace.idle_time || 0, 0);
|
|
44578
45560
|
const clampedIdleSeconds = shiftSeconds > 0 ? Math.min(idleSeconds, shiftSeconds) : idleSeconds;
|
|
44579
|
-
const
|
|
45561
|
+
const computedUtilization = shiftSeconds > 0 ? Math.max(0, Math.round((shiftSeconds - clampedIdleSeconds) / shiftSeconds * 100)) : 0;
|
|
45562
|
+
const utilization = Number.isFinite(workspace.avg_efficiency) ? Math.round(Number(workspace.avg_efficiency)) : computedUtilization;
|
|
44580
45563
|
const lineName = workspace.line_name || getLineDisplayName(entityConfig, workspace.line_id);
|
|
44581
45564
|
trackCoreEvent("Workspace PDF Export Clicked", {
|
|
44582
45565
|
workspace_id: workspace.workspace_id,
|
|
@@ -44666,7 +45649,7 @@ var WorkspacePdfGenerator = ({ workspace, className, idleTimeReasons, efficiency
|
|
|
44666
45649
|
doc.setFont("helvetica", "normal");
|
|
44667
45650
|
doc.text("Utilization:", 25, kpiStartY);
|
|
44668
45651
|
doc.setFont("helvetica", "bold");
|
|
44669
|
-
doc.text(`${utilization}
|
|
45652
|
+
doc.text(`${utilization}%`, 120, kpiStartY);
|
|
44670
45653
|
createKPIBox(kpiStartY + kpiSpacing);
|
|
44671
45654
|
doc.setFont("helvetica", "normal");
|
|
44672
45655
|
doc.text("Total Idle Time:", 25, kpiStartY + kpiSpacing);
|
|
@@ -44773,7 +45756,7 @@ var WorkspacePdfGenerator = ({ workspace, className, idleTimeReasons, efficiency
|
|
|
44773
45756
|
const headerY = titleFontSize === 16 ? hourlyPerfStartY + 18 : hourlyPerfStartY + 20;
|
|
44774
45757
|
const gridTopY = headerY - 5;
|
|
44775
45758
|
const headerBottomY = gridTopY + 8;
|
|
44776
|
-
const colBoundaries = isUptimeMode ? [20,
|
|
45759
|
+
const colBoundaries = isUptimeMode ? [20, 105, 190] : [20, 70, 100, 130, 155, 190];
|
|
44777
45760
|
const totalRows = hourlyData.length;
|
|
44778
45761
|
const gridBottomY = headerBottomY + totalRows * rowHeight;
|
|
44779
45762
|
const tableHeight = gridBottomY - gridTopY;
|
|
@@ -44793,9 +45776,7 @@ var WorkspacePdfGenerator = ({ workspace, className, idleTimeReasons, efficiency
|
|
|
44793
45776
|
const headerTextY = gridTopY + 5.5;
|
|
44794
45777
|
doc.text("Time Range", 25, headerTextY);
|
|
44795
45778
|
if (isUptimeMode) {
|
|
44796
|
-
doc.text("
|
|
44797
|
-
doc.text("Idle (min)", 120, headerTextY);
|
|
44798
|
-
doc.text("Utilization", 160, headerTextY);
|
|
45779
|
+
doc.text("Utilization", 147, headerTextY);
|
|
44799
45780
|
} else {
|
|
44800
45781
|
doc.text("Output", 75, headerTextY);
|
|
44801
45782
|
doc.text("Target", 105, headerTextY);
|
|
@@ -44842,10 +45823,8 @@ var WorkspacePdfGenerator = ({ workspace, className, idleTimeReasons, efficiency
|
|
|
44842
45823
|
}
|
|
44843
45824
|
doc.text(timeRange, 25, yPos);
|
|
44844
45825
|
if (isUptimeMode) {
|
|
44845
|
-
|
|
44846
|
-
doc.text(
|
|
44847
|
-
const utilizationStr = dataCollected ? `${uptimePercent}` : "TBD";
|
|
44848
|
-
doc.text(utilizationStr, 160, yPos);
|
|
45826
|
+
const utilizationStr = dataCollected ? `${uptimePercent}%` : "TBD";
|
|
45827
|
+
doc.text(utilizationStr, 147, yPos);
|
|
44849
45828
|
} else {
|
|
44850
45829
|
doc.text(outputStr, 75, yPos);
|
|
44851
45830
|
doc.text(targetStr, 105, yPos);
|
|
@@ -44928,7 +45907,7 @@ var WorkspaceMonthlyPdfGenerator = ({
|
|
|
44928
45907
|
const shiftWorkSeconds = shiftConfig ? getShiftWorkDurationSeconds(shiftConfig, selectedShiftId) : null;
|
|
44929
45908
|
const hasShiftData = (shift) => {
|
|
44930
45909
|
if (shift.hasData !== void 0) return shift.hasData;
|
|
44931
|
-
return shift.efficiency > 0 || shift.output > 0 || shift.cycleTime > 0 || shift.pph > 0 || shift.
|
|
45910
|
+
return shift.efficiency > 0 || shift.output > 0 || shift.cycleTime > 0 || shift.pph > 0 || shift.targetOutput > 0 || shift.idleTime > 0;
|
|
44932
45911
|
};
|
|
44933
45912
|
const monthBounds = getMonthKeyBounds(selectedYear, selectedMonth);
|
|
44934
45913
|
const requestedRange = {
|
|
@@ -45014,33 +45993,34 @@ var WorkspaceMonthlyPdfGenerator = ({
|
|
|
45014
45993
|
return date.getMonth() === selectedMonth && date.getFullYear() === selectedYear;
|
|
45015
45994
|
});
|
|
45016
45995
|
const validShifts = validDays.map((day) => getShiftData(day, selectedShiftId)).filter(hasShiftData);
|
|
45017
|
-
const
|
|
45018
|
-
|
|
45019
|
-
const
|
|
45020
|
-
const
|
|
45021
|
-
const
|
|
45022
|
-
|
|
45023
|
-
|
|
45024
|
-
|
|
45025
|
-
const
|
|
45026
|
-
|
|
45027
|
-
|
|
45028
|
-
|
|
45029
|
-
|
|
45996
|
+
const filteredShifts = isUptimeMode ? validShifts : validShifts.filter((shift) => (shift.efficiency ?? 0) >= 5);
|
|
45997
|
+
const monthlyMetrics = filteredShifts.length > 0 ? isUptimeMode ? (() => {
|
|
45998
|
+
const totalIdleTime = filteredShifts.reduce((sum, shift) => sum + shift.idleTime, 0);
|
|
45999
|
+
const totalCycleTime = filteredShifts.reduce((sum, shift) => sum + shift.cycleTime, 0);
|
|
46000
|
+
const totalUtilization = filteredShifts.reduce(
|
|
46001
|
+
(sum, shift) => sum + getUptimeUtilizationPercent(shift),
|
|
46002
|
+
0
|
|
46003
|
+
);
|
|
46004
|
+
const totalOutput = filteredShifts.reduce((sum, shift) => sum + (shift.output || 0), 0);
|
|
46005
|
+
const avgUtilization = Math.round(totalUtilization / filteredShifts.length);
|
|
46006
|
+
const avgIdleTime = Math.round(totalIdleTime / filteredShifts.length);
|
|
46007
|
+
const avgCycleTime = Math.round(totalCycleTime / filteredShifts.length);
|
|
46008
|
+
const underperformingDays = filteredShifts.filter((shift) => (shift.efficiency || 0) < effectiveLegend.green_min).length;
|
|
45030
46009
|
return {
|
|
45031
46010
|
avgUtilization,
|
|
45032
46011
|
avgIdleTime,
|
|
45033
46012
|
avgCycleTime,
|
|
45034
|
-
|
|
46013
|
+
avgDailyStoppages: Math.round(totalOutput / filteredShifts.length),
|
|
46014
|
+
totalDays: filteredShifts.length,
|
|
45035
46015
|
underperformingDays
|
|
45036
46016
|
};
|
|
45037
46017
|
})() : {
|
|
45038
|
-
avgEfficiency:
|
|
45039
|
-
avgOutput:
|
|
45040
|
-
avgCycleTime:
|
|
45041
|
-
avgPph:
|
|
45042
|
-
totalDays:
|
|
45043
|
-
underperformingDays:
|
|
46018
|
+
avgEfficiency: filteredShifts.reduce((sum, shift) => sum + shift.efficiency, 0) / filteredShifts.length,
|
|
46019
|
+
avgOutput: filteredShifts.reduce((sum, shift) => sum + shift.output, 0) / filteredShifts.length,
|
|
46020
|
+
avgCycleTime: filteredShifts.reduce((sum, shift) => sum + shift.cycleTime, 0) / filteredShifts.length,
|
|
46021
|
+
avgPph: filteredShifts.reduce((sum, shift) => sum + shift.pph, 0) / filteredShifts.length,
|
|
46022
|
+
totalDays: filteredShifts.length,
|
|
46023
|
+
underperformingDays: filteredShifts.filter((shift) => shift.efficiency < effectiveLegend.green_min).length
|
|
45044
46024
|
} : null;
|
|
45045
46025
|
const createKPIBox = (y) => {
|
|
45046
46026
|
doc.setFillColor(255, 255, 255);
|
|
@@ -45066,7 +46046,7 @@ var WorkspaceMonthlyPdfGenerator = ({
|
|
|
45066
46046
|
doc.setFont("helvetica", "normal");
|
|
45067
46047
|
doc.text("Average Utilization:", 25, kpiStartY);
|
|
45068
46048
|
doc.setFont("helvetica", "bold");
|
|
45069
|
-
doc.text(`${uptimeMetrics.avgUtilization}
|
|
46049
|
+
doc.text(`${uptimeMetrics.avgUtilization}%`, 120, kpiStartY);
|
|
45070
46050
|
createKPIBox(kpiStartY + kpiSpacing);
|
|
45071
46051
|
doc.setFont("helvetica", "normal");
|
|
45072
46052
|
doc.text("Average Idle Time:", 25, kpiStartY + kpiSpacing);
|
|
@@ -45076,7 +46056,7 @@ var WorkspaceMonthlyPdfGenerator = ({
|
|
|
45076
46056
|
doc.setFont("helvetica", "normal");
|
|
45077
46057
|
doc.text("Avg Daily Stoppages:", 25, kpiStartY + kpiSpacing * 2);
|
|
45078
46058
|
doc.setFont("helvetica", "bold");
|
|
45079
|
-
doc.text(
|
|
46059
|
+
doc.text(`${uptimeMetrics.avgDailyStoppages}`, 120, kpiStartY + kpiSpacing * 2);
|
|
45080
46060
|
createKPIBox(kpiStartY + kpiSpacing * 3);
|
|
45081
46061
|
doc.setFont("helvetica", "normal");
|
|
45082
46062
|
doc.text("Working Days:", 25, kpiStartY + kpiSpacing * 3);
|
|
@@ -45168,10 +46148,10 @@ var WorkspaceMonthlyPdfGenerator = ({
|
|
|
45168
46148
|
const idleSeconds = Math.max(shift.idleTime || 0, 0);
|
|
45169
46149
|
const clampedIdleSeconds = totalShiftSeconds > 0 ? Math.min(idleSeconds, totalShiftSeconds) : idleSeconds;
|
|
45170
46150
|
const productiveSeconds = totalShiftSeconds > 0 ? Math.max(totalShiftSeconds - clampedIdleSeconds, 0) : 0;
|
|
45171
|
-
const utilization =
|
|
46151
|
+
const utilization = Number.isFinite(shift.efficiency) ? Math.round(Number(shift.efficiency)) : 0;
|
|
45172
46152
|
doc.text(formatIdleTime(productiveSeconds), 60, yPos);
|
|
45173
46153
|
doc.text(formatIdleTime(clampedIdleSeconds), 95, yPos);
|
|
45174
|
-
doc.text(`${utilization}
|
|
46154
|
+
doc.text(`${utilization}%`, 135, yPos);
|
|
45175
46155
|
if (utilization >= effectiveLegend.green_min) {
|
|
45176
46156
|
doc.setTextColor(0, 171, 69);
|
|
45177
46157
|
doc.text("\u2713", 170, yPos);
|
|
@@ -45182,7 +46162,7 @@ var WorkspaceMonthlyPdfGenerator = ({
|
|
|
45182
46162
|
doc.setTextColor(0, 0, 0);
|
|
45183
46163
|
} else {
|
|
45184
46164
|
doc.text(`${shift.output}`, 60, yPos);
|
|
45185
|
-
doc.text(`${shift.
|
|
46165
|
+
doc.text(`${shift.targetOutput}`, 95, yPos);
|
|
45186
46166
|
doc.text(`${shift.efficiency.toFixed(1)}%`, 135, yPos);
|
|
45187
46167
|
if (shift.efficiency >= effectiveLegend.green_min) {
|
|
45188
46168
|
doc.setTextColor(0, 171, 69);
|
|
@@ -45236,14 +46216,18 @@ var UptimeMetricCards = ({
|
|
|
45236
46216
|
uptimePieData = [],
|
|
45237
46217
|
className = ""
|
|
45238
46218
|
}) => {
|
|
46219
|
+
const efficiencyValue = Number.isFinite(workspace.avg_efficiency) ? Math.max(0, Math.min(100, Number(workspace.avg_efficiency))) : null;
|
|
45239
46220
|
const total = uptimePieData.reduce((sum, item) => sum + item.value, 0);
|
|
45240
46221
|
const active = uptimePieData.find((item) => item.name === "Productive")?.value || 0;
|
|
45241
|
-
const uptimePercent = total > 0 ? (active / total * 100).toFixed(1) : "0.0";
|
|
46222
|
+
const uptimePercent = efficiencyValue !== null ? efficiencyValue.toFixed(1) : total > 0 ? (active / total * 100).toFixed(1) : "0.0";
|
|
45242
46223
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `grid grid-cols-1 gap-4 sm:gap-3 sm:grid-cols-3 w-full h-full ${className}`, children: [
|
|
45243
46224
|
/* @__PURE__ */ jsxRuntime.jsxs(Card2, { className: "flex flex-col bg-white shadow-sm h-full min-h-[150px] sm:min-h-0", children: [
|
|
45244
46225
|
/* @__PURE__ */ jsxRuntime.jsx(CardHeader2, { className: "pb-2 flex-none", children: /* @__PURE__ */ jsxRuntime.jsx(CardTitle2, { className: "text-lg text-center", children: "Utilization" }) }),
|
|
45245
46226
|
/* @__PURE__ */ jsxRuntime.jsx(CardContent2, { className: "flex-1 flex items-center justify-center py-6 sm:py-3", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center", children: [
|
|
45246
|
-
/* @__PURE__ */ jsxRuntime.
|
|
46227
|
+
/* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-5xl font-bold text-gray-900", children: [
|
|
46228
|
+
uptimePercent,
|
|
46229
|
+
"%"
|
|
46230
|
+
] }),
|
|
45247
46231
|
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-gray-500 mt-2", children: "Total productive time" })
|
|
45248
46232
|
] }) })
|
|
45249
46233
|
] }),
|
|
@@ -46035,7 +47019,9 @@ var KPISection = React26.memo(({
|
|
|
46035
47019
|
gridGap = "md",
|
|
46036
47020
|
cardVariant = "default",
|
|
46037
47021
|
compactCards = false,
|
|
46038
|
-
useSrcLayout = false
|
|
47022
|
+
useSrcLayout = false,
|
|
47023
|
+
mode = "output",
|
|
47024
|
+
averageIdleTimeSeconds = null
|
|
46039
47025
|
}) => {
|
|
46040
47026
|
const showSkeleton = isLoading || !kpis;
|
|
46041
47027
|
const outputDifference = kpis ? kpis.outputProgress.current - kpis.outputProgress.idealOutput : 0;
|
|
@@ -46043,6 +47029,10 @@ var KPISection = React26.memo(({
|
|
|
46043
47029
|
if (useSrcLayout) {
|
|
46044
47030
|
const effChange = showSkeleton ? 0 : kpis.efficiency.change ?? 0;
|
|
46045
47031
|
const effTrend = effChange > 0 ? "up" : effChange < 0 ? "down" : "neutral";
|
|
47032
|
+
const isUptimeMode = mode === "uptime";
|
|
47033
|
+
const efficiencyTitle = isUptimeMode ? "Utilization %" : "Efficiency";
|
|
47034
|
+
const secondaryTitle = isUptimeMode ? "Average Idle Time" : "Output Progress";
|
|
47035
|
+
const secondaryValue = isUptimeMode ? showSkeleton ? "" : formatIdleTime(averageIdleTimeSeconds ?? 0) : showSkeleton ? "" : `${kpis.outputProgress.current}/${kpis.outputProgress.target}`;
|
|
46046
47036
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
46047
47037
|
"div",
|
|
46048
47038
|
{
|
|
@@ -46056,7 +47046,7 @@ var KPISection = React26.memo(({
|
|
|
46056
47046
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
46057
47047
|
KPICard,
|
|
46058
47048
|
{
|
|
46059
|
-
title:
|
|
47049
|
+
title: efficiencyTitle,
|
|
46060
47050
|
value: showSkeleton ? "" : kpis.efficiency.value,
|
|
46061
47051
|
change: effChange,
|
|
46062
47052
|
trend: effTrend,
|
|
@@ -46070,10 +47060,10 @@ var KPISection = React26.memo(({
|
|
|
46070
47060
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
46071
47061
|
KPICard,
|
|
46072
47062
|
{
|
|
46073
|
-
title:
|
|
46074
|
-
value:
|
|
47063
|
+
title: secondaryTitle,
|
|
47064
|
+
value: secondaryValue,
|
|
46075
47065
|
outputDifference,
|
|
46076
|
-
showOutputDetails: !showSkeleton,
|
|
47066
|
+
showOutputDetails: !showSkeleton && !isUptimeMode,
|
|
46077
47067
|
isLoading: showSkeleton
|
|
46078
47068
|
}
|
|
46079
47069
|
) })
|
|
@@ -46145,7 +47135,7 @@ var KPISection = React26.memo(({
|
|
|
46145
47135
|
if (prevKpis.underperformingWorkers.change !== nextKpis.underperformingWorkers.change) return false;
|
|
46146
47136
|
if (prevKpis.outputProgress.current !== nextKpis.outputProgress.current || prevKpis.outputProgress.target !== nextKpis.outputProgress.target) return false;
|
|
46147
47137
|
if (prevKpis.outputProgress.change !== nextKpis.outputProgress.change) return false;
|
|
46148
|
-
if (prevProps.layout !== nextProps.layout || prevProps.cardVariant !== nextProps.cardVariant || prevProps.compactCards !== nextProps.compactCards || prevProps.useSrcLayout !== nextProps.useSrcLayout || prevProps.className !== nextProps.className) return false;
|
|
47138
|
+
if (prevProps.layout !== nextProps.layout || prevProps.cardVariant !== nextProps.cardVariant || prevProps.compactCards !== nextProps.compactCards || prevProps.useSrcLayout !== nextProps.useSrcLayout || prevProps.className !== nextProps.className || prevProps.mode !== nextProps.mode || prevProps.averageIdleTimeSeconds !== nextProps.averageIdleTimeSeconds) return false;
|
|
46149
47139
|
return true;
|
|
46150
47140
|
});
|
|
46151
47141
|
KPISection.displayName = "KPISection";
|
|
@@ -54010,6 +55000,20 @@ function HomeView({
|
|
|
54010
55000
|
}
|
|
54011
55001
|
};
|
|
54012
55002
|
}, [kpis, kpiTrend]);
|
|
55003
|
+
const selectedLineMeta = React26.useMemo(
|
|
55004
|
+
() => dbLines.find((line) => line.id === selectedLineId),
|
|
55005
|
+
[dbLines, selectedLineId]
|
|
55006
|
+
);
|
|
55007
|
+
const selectedMonitoringMode = selectedLineId === factoryViewId ? "output" : selectedLineMeta?.monitoring_mode ?? "output";
|
|
55008
|
+
const isUptimeMode = selectedMonitoringMode === "uptime";
|
|
55009
|
+
const averageIdleTimeSeconds = React26.useMemo(() => {
|
|
55010
|
+
if (!isUptimeMode) return null;
|
|
55011
|
+
const targetWorkspaces = selectedLineId === factoryViewId ? workspaceMetrics : workspaceMetrics.filter((ws) => ws.line_id === selectedLineId);
|
|
55012
|
+
const idleValues = targetWorkspaces.map((ws) => ws.idle_time).filter((value) => Number.isFinite(value));
|
|
55013
|
+
if (idleValues.length === 0) return 0;
|
|
55014
|
+
const totalIdle = idleValues.reduce((sum, value) => sum + value, 0);
|
|
55015
|
+
return totalIdle / idleValues.length;
|
|
55016
|
+
}, [isUptimeMode, selectedLineId, factoryViewId, workspaceMetrics]);
|
|
54013
55017
|
const {
|
|
54014
55018
|
activeBreaks: allActiveBreaks,
|
|
54015
55019
|
isLoading: breaksLoading,
|
|
@@ -54452,10 +55456,12 @@ function HomeView({
|
|
|
54452
55456
|
kpis: displayKpis,
|
|
54453
55457
|
isLoading: shouldShowKpiLoading,
|
|
54454
55458
|
className: "w-full sm:w-auto",
|
|
54455
|
-
useSrcLayout: true
|
|
55459
|
+
useSrcLayout: true,
|
|
55460
|
+
mode: isUptimeMode ? "uptime" : "output",
|
|
55461
|
+
averageIdleTimeSeconds
|
|
54456
55462
|
},
|
|
54457
55463
|
"kpi-section-control"
|
|
54458
|
-
), [displayKpis, shouldShowKpiLoading]);
|
|
55464
|
+
), [displayKpis, shouldShowKpiLoading, isUptimeMode, averageIdleTimeSeconds]);
|
|
54459
55465
|
if (isInitialLoading) {
|
|
54460
55466
|
return /* @__PURE__ */ jsxRuntime.jsx(LoadingPageCmp, { message: "Loading Dashboard..." });
|
|
54461
55467
|
}
|
|
@@ -55375,6 +56381,56 @@ var MetricCards = React26.memo(({
|
|
|
55375
56381
|
return prevMetrics.current_output === nextMetrics.current_output && prevMetrics.line_threshold === nextMetrics.line_threshold && prevMetrics.underperforming_workspaces === nextMetrics.underperforming_workspaces && prevMetrics.total_workspaces === nextMetrics.total_workspaces && prevMetrics.avg_efficiency === nextMetrics.avg_efficiency;
|
|
55376
56382
|
});
|
|
55377
56383
|
MetricCards.displayName = "MetricCards";
|
|
56384
|
+
var LineUptimeMetricCards = React26.memo(({
|
|
56385
|
+
utilizationPercent,
|
|
56386
|
+
stoppages,
|
|
56387
|
+
idleTimeSeconds,
|
|
56388
|
+
idleTimeData,
|
|
56389
|
+
showIdleTime
|
|
56390
|
+
}) => {
|
|
56391
|
+
const utilizationText = Number.isFinite(utilizationPercent) ? utilizationPercent.toFixed(1) : "0.0";
|
|
56392
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
56393
|
+
motion.div,
|
|
56394
|
+
{
|
|
56395
|
+
variants: containerVariants,
|
|
56396
|
+
initial: "initial",
|
|
56397
|
+
animate: "animate",
|
|
56398
|
+
className: `grid grid-cols-1 sm:grid-cols-2 ${showIdleTime ? "lg:grid-cols-4" : "lg:grid-cols-3"} gap-3 sm:gap-4 mb-2 md:h-[35vh] h-auto`,
|
|
56399
|
+
children: [
|
|
56400
|
+
/* @__PURE__ */ jsxRuntime.jsxs(motion.div, { variants: itemVariants, className: "bg-white rounded-xl shadow-sm p-3 sm:p-4 overflow-hidden h-[240px] sm:h-[260px] md:h-auto", children: [
|
|
56401
|
+
/* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-sm sm:text-base font-bold text-gray-700 mb-2 text-center", children: "Utilization" }),
|
|
56402
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-[calc(100%-2.5rem)]", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full h-full flex items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
56403
|
+
OutputProgressChart,
|
|
56404
|
+
{
|
|
56405
|
+
currentOutput: Number(utilizationText),
|
|
56406
|
+
targetOutput: 100
|
|
56407
|
+
}
|
|
56408
|
+
) }) })
|
|
56409
|
+
] }),
|
|
56410
|
+
/* @__PURE__ */ jsxRuntime.jsxs(motion.div, { variants: itemVariants, className: "bg-white rounded-xl shadow-sm p-3 sm:p-4 overflow-hidden h-[240px] sm:h-[260px] md:h-auto", children: [
|
|
56411
|
+
/* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-sm sm:text-base font-bold text-gray-700 text-center mb-2", children: "Stoppages" }),
|
|
56412
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center h-[calc(100%-2.5rem)]", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-4xl sm:text-5xl md:text-6xl lg:text-7xl font-bold text-red-600", children: stoppages }) })
|
|
56413
|
+
] }),
|
|
56414
|
+
/* @__PURE__ */ jsxRuntime.jsxs(motion.div, { variants: itemVariants, className: "bg-white rounded-xl shadow-sm p-3 sm:p-4 overflow-hidden h-[240px] sm:h-[260px] md:h-auto", children: [
|
|
56415
|
+
/* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-sm sm:text-base font-bold text-gray-700 text-center mb-2", children: "Average Idle Time" }),
|
|
56416
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center h-[calc(100%-2.5rem)]", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: `text-4xl sm:text-5xl md:text-6xl lg:text-7xl font-bold ${idleTimeSeconds <= 0 ? "text-green-500" : idleTimeSeconds <= 300 ? "text-yellow-500" : "text-red-500"}`, children: formatIdleTime(idleTimeSeconds) }) })
|
|
56417
|
+
] }),
|
|
56418
|
+
showIdleTime && /* @__PURE__ */ jsxRuntime.jsxs(motion.div, { variants: itemVariants, className: "bg-white rounded-xl shadow-sm p-3 sm:p-4 overflow-hidden h-[240px] sm:h-[260px] md:h-auto", children: [
|
|
56419
|
+
/* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-sm sm:text-base font-bold text-gray-700 text-center mb-2", children: "Idle Time Breakdown" }),
|
|
56420
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-[calc(100%-2.5rem)]", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
56421
|
+
IdleTimeReasonChart,
|
|
56422
|
+
{
|
|
56423
|
+
data: idleTimeData?.chartData,
|
|
56424
|
+
isLoading: idleTimeData?.isLoading,
|
|
56425
|
+
error: idleTimeData?.error
|
|
56426
|
+
}
|
|
56427
|
+
) })
|
|
56428
|
+
] })
|
|
56429
|
+
]
|
|
56430
|
+
}
|
|
56431
|
+
);
|
|
56432
|
+
});
|
|
56433
|
+
LineUptimeMetricCards.displayName = "LineUptimeMetricCards";
|
|
55378
56434
|
var BottomSection = React26.memo(({
|
|
55379
56435
|
lineInfo,
|
|
55380
56436
|
lineId,
|
|
@@ -55536,6 +56592,116 @@ var BottomSection = React26.memo(({
|
|
|
55536
56592
|
return true;
|
|
55537
56593
|
});
|
|
55538
56594
|
BottomSection.displayName = "BottomSection";
|
|
56595
|
+
var UptimeBottomSection = React26.memo(({
|
|
56596
|
+
lineId,
|
|
56597
|
+
workspaceData,
|
|
56598
|
+
sortedByUtilization,
|
|
56599
|
+
workspaceDisplayNames,
|
|
56600
|
+
idleTimeData,
|
|
56601
|
+
showIdleTime,
|
|
56602
|
+
idleTimeHourly,
|
|
56603
|
+
hourlyAggregates,
|
|
56604
|
+
shiftStart,
|
|
56605
|
+
shiftEnd,
|
|
56606
|
+
shiftDate,
|
|
56607
|
+
timezone,
|
|
56608
|
+
elapsedMinutes,
|
|
56609
|
+
urlDate,
|
|
56610
|
+
urlShift,
|
|
56611
|
+
navigate
|
|
56612
|
+
}) => {
|
|
56613
|
+
const navigation = useNavigation();
|
|
56614
|
+
const handleNavigate = navigate || navigation.navigate;
|
|
56615
|
+
const handleWorkspaceClick = React26.useCallback((ws, index) => {
|
|
56616
|
+
trackCoreEvent("Workspace from KPI Clicked", {
|
|
56617
|
+
workspace_name: ws.workspace_name,
|
|
56618
|
+
workspace_id: ws.workspace_uuid,
|
|
56619
|
+
rank: index + 1,
|
|
56620
|
+
total_workspaces: workspaceData.length,
|
|
56621
|
+
efficiency: ws.utilization,
|
|
56622
|
+
action_count: ws.action_count,
|
|
56623
|
+
action_threshold: ws.action_threshold,
|
|
56624
|
+
section: "Lowest Utilization Workspaces"
|
|
56625
|
+
});
|
|
56626
|
+
}, [workspaceData.length]);
|
|
56627
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
56628
|
+
motion.div,
|
|
56629
|
+
{
|
|
56630
|
+
variants: containerVariants,
|
|
56631
|
+
initial: "initial",
|
|
56632
|
+
animate: "animate",
|
|
56633
|
+
className: "grid grid-cols-1 lg:grid-cols-5 gap-3 sm:gap-4 md:h-[calc(57vh-4rem)] h-auto md:mt-0 mt-4",
|
|
56634
|
+
children: [
|
|
56635
|
+
/* @__PURE__ */ jsxRuntime.jsxs(motion.div, { variants: itemVariants, className: "lg:col-span-2 bg-white rounded-xl shadow-sm p-3 sm:p-4 flex flex-col overflow-hidden h-[350px] sm:h-[400px] md:h-auto", children: [
|
|
56636
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-between items-center mb-2", children: [
|
|
56637
|
+
/* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-base sm:text-lg font-bold text-gray-700 text-center flex-1", children: "Lowest Utilization Workspaces" }),
|
|
56638
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
56639
|
+
"div",
|
|
56640
|
+
{
|
|
56641
|
+
className: "p-1.5 hover:bg-gray-100 rounded-lg transition-colors cursor-pointer",
|
|
56642
|
+
onClick: () => handleNavigate && handleNavigate(`/leaderboard`),
|
|
56643
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(outline.ArrowRightIcon, { className: "w-4 h-4 sm:w-5 sm:h-5 text-gray-500" })
|
|
56644
|
+
}
|
|
56645
|
+
)
|
|
56646
|
+
] }),
|
|
56647
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "divide-y overflow-auto flex-1 pr-1 sm:pr-2", children: [
|
|
56648
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between pb-2", children: [
|
|
56649
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 sm:gap-3 md:gap-6", children: [
|
|
56650
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "font-medium text-gray-500 min-w-[80px] sm:min-w-[100px] md:min-w-[120px] text-xs sm:text-sm md:text-base", children: "Workspace" }),
|
|
56651
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs md:text-sm font-medium text-gray-500", children: "Stoppages" })
|
|
56652
|
+
] }),
|
|
56653
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs md:text-sm font-medium text-gray-500 pr-1 sm:pr-2", children: "Utilization" })
|
|
56654
|
+
] }),
|
|
56655
|
+
sortedByUtilization.map((ws, index) => {
|
|
56656
|
+
const displayName = workspaceDisplayNames && workspaceDisplayNames[ws.workspace_name] || getWorkspaceDisplayName(ws.workspace_name, lineId);
|
|
56657
|
+
const navParams = ws.workspace_uuid ? getWorkspaceNavigationParams(ws.workspace_uuid, displayName, lineId) : "";
|
|
56658
|
+
const dateShiftParams = urlDate ? `&date=${urlDate}&shift=${urlShift || "0"}` : "";
|
|
56659
|
+
const returnToParam = `&returnTo=${encodeURIComponent(`/kpis/${lineId}`)}`;
|
|
56660
|
+
const fullUrl = `/workspace/${ws.workspace_uuid}${navParams}${dateShiftParams}${returnToParam}`;
|
|
56661
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
56662
|
+
"div",
|
|
56663
|
+
{
|
|
56664
|
+
onClick: () => {
|
|
56665
|
+
handleWorkspaceClick(ws, index);
|
|
56666
|
+
handleNavigate && handleNavigate(fullUrl);
|
|
56667
|
+
},
|
|
56668
|
+
className: "block py-2 sm:py-3 hover:bg-gray-50 transition-colors rounded-lg cursor-pointer",
|
|
56669
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
|
|
56670
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 sm:gap-3 md:gap-6", children: [
|
|
56671
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-w-[80px] sm:min-w-[100px] md:min-w-[120px]", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "font-medium text-gray-900 text-xs sm:text-sm md:text-base truncate", children: displayName }) }),
|
|
56672
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs md:text-sm font-medium text-gray-900", children: ws.action_count || 0 })
|
|
56673
|
+
] }),
|
|
56674
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-xs md:text-sm font-medium text-gray-900", children: [
|
|
56675
|
+
ws.utilization.toFixed(1),
|
|
56676
|
+
"%"
|
|
56677
|
+
] })
|
|
56678
|
+
] })
|
|
56679
|
+
},
|
|
56680
|
+
ws.workspace_uuid || `${ws.workspace_name}-${index}`
|
|
56681
|
+
);
|
|
56682
|
+
})
|
|
56683
|
+
] })
|
|
56684
|
+
] }),
|
|
56685
|
+
/* @__PURE__ */ jsxRuntime.jsxs(motion.div, { variants: itemVariants, className: "lg:col-span-3 bg-white rounded-xl shadow-sm p-3 sm:p-4 flex flex-col overflow-hidden h-[350px] sm:h-[400px] md:h-auto", children: [
|
|
56686
|
+
/* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-base sm:text-lg font-bold text-gray-700 mb-2 text-center", children: "Hourly Utilization" }),
|
|
56687
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 min-h-[280px] sm:min-h-[300px] md:min-h-[400px]", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
56688
|
+
HourlyUptimeChart,
|
|
56689
|
+
{
|
|
56690
|
+
hourlyAggregates,
|
|
56691
|
+
idleTimeHourly,
|
|
56692
|
+
shiftStart,
|
|
56693
|
+
shiftEnd,
|
|
56694
|
+
shiftDate,
|
|
56695
|
+
timezone,
|
|
56696
|
+
elapsedMinutes
|
|
56697
|
+
}
|
|
56698
|
+
) })
|
|
56699
|
+
] })
|
|
56700
|
+
]
|
|
56701
|
+
}
|
|
56702
|
+
);
|
|
56703
|
+
});
|
|
56704
|
+
UptimeBottomSection.displayName = "UptimeBottomSection";
|
|
55539
56705
|
var QualityOverview = React26.memo(({ lineInfo }) => {
|
|
55540
56706
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center justify-center h-full p-6 bg-white rounded-lg shadow-sm", children: [
|
|
55541
56707
|
/* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-xl font-semibold text-gray-700 mb-4", children: "Quality Overview" }),
|
|
@@ -55647,7 +56813,11 @@ var KPIDetailView = ({
|
|
|
55647
56813
|
React26.useMemo(() => getCurrentTimeInZone(configuredTimezone), [configuredTimezone]);
|
|
55648
56814
|
const { legend: efficiencyLegend } = useEfficiencyLegend(companyId);
|
|
55649
56815
|
const supervisorEnabled = dashboardConfig?.supervisorConfig?.enabled || false;
|
|
55650
|
-
const { supervisorName, supervisors } = useLineSupervisor(lineId
|
|
56816
|
+
const { supervisorName, supervisors } = useLineSupervisor(lineId, {
|
|
56817
|
+
enabled: supervisorEnabled,
|
|
56818
|
+
companyId: resolvedCompanyId,
|
|
56819
|
+
useBackend: true
|
|
56820
|
+
});
|
|
55651
56821
|
const { displayNames: workspaceDisplayNames } = useWorkspaceDisplayNames(lineId, companyId);
|
|
55652
56822
|
const { isIdleTimeVlmEnabled } = useIdleTimeVlmConfig();
|
|
55653
56823
|
const idleTimeVlmEnabled = isIdleTimeVlmEnabled(lineId);
|
|
@@ -55675,6 +56845,25 @@ var KPIDetailView = ({
|
|
|
55675
56845
|
}
|
|
55676
56846
|
return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" }) });
|
|
55677
56847
|
}, []);
|
|
56848
|
+
const resolveShiftTimes = React26.useCallback((shiftId) => {
|
|
56849
|
+
if (!shiftConfig) return { start: void 0, end: void 0 };
|
|
56850
|
+
const targetShiftId = shiftId ?? 0;
|
|
56851
|
+
if (shiftConfig.shifts && shiftConfig.shifts.length > 0) {
|
|
56852
|
+
const shift = shiftConfig.shifts.find((s) => s.shiftId === targetShiftId);
|
|
56853
|
+
if (shift) {
|
|
56854
|
+
return { start: shift.startTime, end: shift.endTime };
|
|
56855
|
+
}
|
|
56856
|
+
}
|
|
56857
|
+
shiftConfig.dayShift?.id ?? 0;
|
|
56858
|
+
const nightShiftId = shiftConfig.nightShift?.id ?? 1;
|
|
56859
|
+
if (targetShiftId === nightShiftId && shiftConfig.nightShift) {
|
|
56860
|
+
return { start: shiftConfig.nightShift.startTime, end: shiftConfig.nightShift.endTime };
|
|
56861
|
+
}
|
|
56862
|
+
if (shiftConfig.dayShift) {
|
|
56863
|
+
return { start: shiftConfig.dayShift.startTime, end: shiftConfig.dayShift.endTime };
|
|
56864
|
+
}
|
|
56865
|
+
return { start: void 0, end: void 0 };
|
|
56866
|
+
}, [shiftConfig]);
|
|
55678
56867
|
const getDaysDifference2 = React26.useCallback((date) => {
|
|
55679
56868
|
const compareDate = new Date(date);
|
|
55680
56869
|
const shiftStartTime = shiftConfig?.dayShift?.startTime || shiftConfig?.shifts?.[0]?.startTime || "06:00";
|
|
@@ -55704,6 +56893,9 @@ var KPIDetailView = ({
|
|
|
55704
56893
|
shiftId: parsedShiftId,
|
|
55705
56894
|
enabled: !isShiftConfigLoading && (!historicalRouteRequested || historicalParamsReady)
|
|
55706
56895
|
});
|
|
56896
|
+
const resolvedMonitoringMode = lineDetails?.monitoring_mode ?? "output";
|
|
56897
|
+
const isUptimeMode = resolvedMonitoringMode === "uptime";
|
|
56898
|
+
const overviewTabLabel = isUptimeMode ? "Utilization" : "Efficiency";
|
|
55707
56899
|
const {
|
|
55708
56900
|
workspaces,
|
|
55709
56901
|
loading: workspacesLoading,
|
|
@@ -55743,7 +56935,11 @@ var KPIDetailView = ({
|
|
|
55743
56935
|
}
|
|
55744
56936
|
setMonthlyDataLoading(true);
|
|
55745
56937
|
Promise.all([
|
|
55746
|
-
dashboardService.getLineMonthlyData(lineId, currentMonth, currentYear
|
|
56938
|
+
dashboardService.getLineMonthlyData(lineId, currentMonth, currentYear, {
|
|
56939
|
+
startDate: isFullRange ? void 0 : range.startKey,
|
|
56940
|
+
endDate: isFullRange ? void 0 : range.endKey,
|
|
56941
|
+
shiftIds: shiftConfig?.shifts?.map((s) => s.shiftId)
|
|
56942
|
+
}),
|
|
55747
56943
|
dashboardService.getUnderperformingWorkspaces(
|
|
55748
56944
|
lineId,
|
|
55749
56945
|
currentMonth,
|
|
@@ -55756,6 +56952,7 @@ var KPIDetailView = ({
|
|
|
55756
56952
|
]).then(([monthlyMetrics, underperformingData]) => {
|
|
55757
56953
|
console.log("Fetched monthly metrics data:", monthlyMetrics);
|
|
55758
56954
|
const dayDataMap = /* @__PURE__ */ new Map();
|
|
56955
|
+
const resolveMonthlyShiftTimes = (metricShiftId) => resolveShiftTimes(metricShiftId);
|
|
55759
56956
|
monthlyMetrics.forEach((metric) => {
|
|
55760
56957
|
const date = new Date(metric.date);
|
|
55761
56958
|
const dateKey = date.toISOString().split("T")[0];
|
|
@@ -55768,15 +56965,40 @@ var KPIDetailView = ({
|
|
|
55768
56965
|
};
|
|
55769
56966
|
dayDataMap.set(dateKey, dayData);
|
|
55770
56967
|
}
|
|
56968
|
+
const fallbackTimes = resolveMonthlyShiftTimes(metric.shift_id);
|
|
56969
|
+
const resolvedShiftStart = metric.shift_start || fallbackTimes.start;
|
|
56970
|
+
const resolvedShiftEnd = metric.shift_end || fallbackTimes.end;
|
|
56971
|
+
const hasBackendUptimeSeconds = isUptimeMode && (Number.isFinite(metric.active_time_seconds) || Number.isFinite(metric.idle_time_seconds) || Number.isFinite(metric.available_time_seconds));
|
|
56972
|
+
const uptimeSeries2 = isUptimeMode && !hasBackendUptimeSeconds ? buildUptimeSeries({
|
|
56973
|
+
idleTimeHourly: metric.idle_time_hourly || {},
|
|
56974
|
+
shiftStart: resolvedShiftStart || void 0,
|
|
56975
|
+
shiftEnd: resolvedShiftEnd || void 0,
|
|
56976
|
+
shiftDate: metric.date,
|
|
56977
|
+
timezone: configuredTimezone
|
|
56978
|
+
}) : null;
|
|
56979
|
+
const idleTimeSeconds = isUptimeMode ? hasBackendUptimeSeconds ? metric.idle_time_seconds || 0 : (uptimeSeries2?.idleMinutes || 0) * 60 : 0;
|
|
56980
|
+
const activeTimeSeconds = isUptimeMode ? hasBackendUptimeSeconds ? metric.active_time_seconds || 0 : (uptimeSeries2?.activeMinutes || 0) * 60 : 0;
|
|
56981
|
+
const availableTimeSeconds = isUptimeMode ? hasBackendUptimeSeconds ? metric.available_time_seconds || activeTimeSeconds + idleTimeSeconds : (uptimeSeries2?.availableMinutes || 0) * 60 : 0;
|
|
56982
|
+
const computedUptimeEfficiency = (() => {
|
|
56983
|
+
const availableMinutes = availableTimeSeconds / 60;
|
|
56984
|
+
if (!availableMinutes || availableMinutes <= 0) return 0;
|
|
56985
|
+
const idleMinutes = Math.min(Math.max(idleTimeSeconds / 60, 0), availableMinutes);
|
|
56986
|
+
const productiveMinutes = Math.max(activeTimeSeconds / 60 || availableMinutes - idleMinutes, 0);
|
|
56987
|
+
return Math.round(productiveMinutes / availableMinutes * 100);
|
|
56988
|
+
})();
|
|
55771
56989
|
const shiftData = {
|
|
55772
|
-
avg_efficiency: metric.avg_efficiency || 0,
|
|
56990
|
+
avg_efficiency: isUptimeMode ? Number.isFinite(metric.avg_efficiency) ? Number(metric.avg_efficiency) : computedUptimeEfficiency : metric.avg_efficiency || 0,
|
|
55773
56991
|
underperforming_workspaces: metric.underperforming_workspaces || 0,
|
|
55774
56992
|
total_workspaces: metric.total_workspaces || 0,
|
|
55775
56993
|
output: metric.current_output || 0,
|
|
55776
|
-
|
|
56994
|
+
targetOutput: Number(metric.line_threshold || 0),
|
|
55777
56995
|
compliance_percentage: 95 + Math.random() * 5,
|
|
55778
56996
|
// Mock data: random value between 95-100%
|
|
55779
|
-
hasData: true
|
|
56997
|
+
hasData: isUptimeMode ? availableTimeSeconds > 0 : true,
|
|
56998
|
+
idle_time_seconds: idleTimeSeconds,
|
|
56999
|
+
active_time_seconds: activeTimeSeconds,
|
|
57000
|
+
available_time_seconds: availableTimeSeconds,
|
|
57001
|
+
avg_idle_time_seconds: isUptimeMode ? metric.avg_idle_time_seconds || 0 : 0
|
|
55780
57002
|
};
|
|
55781
57003
|
dayData.shifts[metric.shift_id] = shiftData;
|
|
55782
57004
|
});
|
|
@@ -55815,7 +57037,7 @@ var KPIDetailView = ({
|
|
|
55815
57037
|
setMonthlyDataLoading(false);
|
|
55816
57038
|
});
|
|
55817
57039
|
}
|
|
55818
|
-
}, [activeTab, lineId, currentMonth, currentYear, supabase, dashboardConfig, shiftConfig, range.startKey, range.endKey, isFullRange]);
|
|
57040
|
+
}, [activeTab, lineId, currentMonth, currentYear, supabase, dashboardConfig, shiftConfig, range.startKey, range.endKey, isFullRange, configuredTimezone, isUptimeMode, resolveShiftTimes]);
|
|
55819
57041
|
const analysisMonthlyData = React26.useMemo(() => {
|
|
55820
57042
|
return filterDataByDateKeyRange(monthlyData, range);
|
|
55821
57043
|
}, [monthlyData, range]);
|
|
@@ -55832,6 +57054,7 @@ var KPIDetailView = ({
|
|
|
55832
57054
|
factory_name: lineDetails.factory.factory_name,
|
|
55833
57055
|
shift_id: metrics2.shift_id ?? 0,
|
|
55834
57056
|
date: metrics2.date || getOperationalDate(timezone || "UTC"),
|
|
57057
|
+
monitoring_mode: lineDetails.monitoring_mode ?? void 0,
|
|
55835
57058
|
metrics: {
|
|
55836
57059
|
avg_efficiency: metrics2.avg_efficiency ?? 0,
|
|
55837
57060
|
avg_cycle_time: metrics2.avg_cycle_time ?? 0,
|
|
@@ -55848,7 +57071,8 @@ var KPIDetailView = ({
|
|
|
55848
57071
|
shift_start: metrics2.shift_start || "06:00",
|
|
55849
57072
|
shift_end: metrics2.shift_end || "14:00",
|
|
55850
57073
|
last_updated: metrics2.last_updated || (/* @__PURE__ */ new Date()).toISOString(),
|
|
55851
|
-
poorest_performing_workspaces: metrics2.poorest_performing_workspaces || []
|
|
57074
|
+
poorest_performing_workspaces: metrics2.poorest_performing_workspaces || [],
|
|
57075
|
+
idle_time_hourly: metrics2.idle_time_hourly || null
|
|
55852
57076
|
}
|
|
55853
57077
|
};
|
|
55854
57078
|
}, [metrics2, lineDetails, companyId]);
|
|
@@ -55893,6 +57117,188 @@ var KPIDetailView = ({
|
|
|
55893
57117
|
date: resolvedLineInfo.date
|
|
55894
57118
|
};
|
|
55895
57119
|
}, [metrics2, metricsMatchRequest, resolvedLineInfo]);
|
|
57120
|
+
const resolvedShiftTimes = React26.useMemo(() => {
|
|
57121
|
+
if (!chartMetrics) return { start: void 0, end: void 0 };
|
|
57122
|
+
const fallback = resolveShiftTimes(chartMetrics.shift_id);
|
|
57123
|
+
return {
|
|
57124
|
+
start: chartMetrics.shift_start || fallback.start,
|
|
57125
|
+
end: chartMetrics.shift_end || fallback.end
|
|
57126
|
+
};
|
|
57127
|
+
}, [chartMetrics?.shift_start, chartMetrics?.shift_end, chartMetrics?.shift_id, resolveShiftTimes]);
|
|
57128
|
+
const currentShiftDetails = React26.useMemo(() => {
|
|
57129
|
+
if (!shiftConfig) return null;
|
|
57130
|
+
return getCurrentShift(configuredTimezone, shiftConfig);
|
|
57131
|
+
}, [configuredTimezone, shiftConfig]);
|
|
57132
|
+
const isCurrentShiftView = React26.useMemo(() => {
|
|
57133
|
+
if (!currentShiftDetails || !chartMetrics?.date || chartMetrics?.shift_id === void 0 || chartMetrics?.shift_id === null) {
|
|
57134
|
+
return false;
|
|
57135
|
+
}
|
|
57136
|
+
return currentShiftDetails.date === chartMetrics.date && currentShiftDetails.shiftId === chartMetrics.shift_id;
|
|
57137
|
+
}, [currentShiftDetails, chartMetrics?.date, chartMetrics?.shift_id]);
|
|
57138
|
+
const elapsedShiftMinutes = React26.useMemo(() => {
|
|
57139
|
+
if (!isCurrentShiftView || !chartMetrics) return null;
|
|
57140
|
+
return getShiftElapsedMinutes({
|
|
57141
|
+
shiftStart: resolvedShiftTimes.start,
|
|
57142
|
+
shiftEnd: resolvedShiftTimes.end,
|
|
57143
|
+
shiftDate: chartMetrics.date,
|
|
57144
|
+
timezone: configuredTimezone
|
|
57145
|
+
});
|
|
57146
|
+
}, [isCurrentShiftView, chartMetrics, resolvedShiftTimes.start, resolvedShiftTimes.end, configuredTimezone]);
|
|
57147
|
+
const uptimeSeries = React26.useMemo(() => {
|
|
57148
|
+
if (!chartMetrics) {
|
|
57149
|
+
return buildUptimeSeries({
|
|
57150
|
+
idleTimeHourly: null,
|
|
57151
|
+
shiftStart: null,
|
|
57152
|
+
shiftEnd: null,
|
|
57153
|
+
shiftDate: null,
|
|
57154
|
+
timezone: configuredTimezone,
|
|
57155
|
+
elapsedMinutes: null
|
|
57156
|
+
});
|
|
57157
|
+
}
|
|
57158
|
+
return buildUptimeSeries({
|
|
57159
|
+
idleTimeHourly: chartMetrics.idle_time_hourly,
|
|
57160
|
+
shiftStart: resolvedShiftTimes.start,
|
|
57161
|
+
shiftEnd: resolvedShiftTimes.end,
|
|
57162
|
+
shiftDate: chartMetrics.date,
|
|
57163
|
+
timezone: configuredTimezone,
|
|
57164
|
+
elapsedMinutes: elapsedShiftMinutes
|
|
57165
|
+
});
|
|
57166
|
+
}, [chartMetrics, resolvedShiftTimes.start, resolvedShiftTimes.end, configuredTimezone, elapsedShiftMinutes]);
|
|
57167
|
+
const lineUtilizationFromLine = React26.useMemo(() => {
|
|
57168
|
+
const efficiencyValue = Number.isFinite(chartMetrics?.avg_efficiency) ? Number(chartMetrics?.avg_efficiency) : null;
|
|
57169
|
+
if (efficiencyValue !== null) return efficiencyValue;
|
|
57170
|
+
if (!uptimeSeries.availableMinutes) return 0;
|
|
57171
|
+
return uptimeSeries.activeMinutes / uptimeSeries.availableMinutes * 100;
|
|
57172
|
+
}, [chartMetrics?.avg_efficiency, uptimeSeries.availableMinutes, uptimeSeries.activeMinutes]);
|
|
57173
|
+
const lineIdleTimeSecondsFromLine = React26.useMemo(() => uptimeSeries.idleMinutes * 60, [uptimeSeries.idleMinutes]);
|
|
57174
|
+
const workspaceUptimeSummaries = React26.useMemo(() => {
|
|
57175
|
+
if (!isUptimeMode || !resolvedWorkspaces || resolvedWorkspaces.length === 0) return [];
|
|
57176
|
+
return resolvedWorkspaces.map((workspace) => {
|
|
57177
|
+
const shiftStart = workspace.shift_start || resolvedShiftTimes.start;
|
|
57178
|
+
const shiftEnd = workspace.shift_end || resolvedShiftTimes.end;
|
|
57179
|
+
const shiftDate = workspace.date || chartMetrics?.date || null;
|
|
57180
|
+
const shiftMinutes = getShiftDurationMinutes(shiftStart, shiftEnd) || 0;
|
|
57181
|
+
const workspaceElapsedMinutes = isCurrentShiftView ? getShiftElapsedMinutes({
|
|
57182
|
+
shiftStart,
|
|
57183
|
+
shiftEnd,
|
|
57184
|
+
shiftDate,
|
|
57185
|
+
timezone: configuredTimezone
|
|
57186
|
+
}) : null;
|
|
57187
|
+
const uptimeSeries2 = buildUptimeSeries({
|
|
57188
|
+
idleTimeHourly: workspace.idle_time_hourly,
|
|
57189
|
+
shiftStart,
|
|
57190
|
+
shiftEnd,
|
|
57191
|
+
shiftDate,
|
|
57192
|
+
timezone: configuredTimezone,
|
|
57193
|
+
elapsedMinutes: workspaceElapsedMinutes
|
|
57194
|
+
});
|
|
57195
|
+
let activeMinutes = uptimeSeries2.activeMinutes;
|
|
57196
|
+
let idleMinutes = uptimeSeries2.idleMinutes;
|
|
57197
|
+
let availableMinutes = uptimeSeries2.availableMinutes;
|
|
57198
|
+
let hasData = uptimeSeries2.hasData;
|
|
57199
|
+
if (!hasData) {
|
|
57200
|
+
const hasIdleHourlyPayload = Boolean(
|
|
57201
|
+
workspace.idle_time_hourly && Object.keys(workspace.idle_time_hourly).length > 0
|
|
57202
|
+
);
|
|
57203
|
+
const idleTimeValue = workspace.idle_time;
|
|
57204
|
+
const hasIdleTimeValue = Number.isFinite(idleTimeValue);
|
|
57205
|
+
const fallbackDuration = workspaceElapsedMinutes ?? shiftMinutes;
|
|
57206
|
+
if (!hasIdleHourlyPayload && hasIdleTimeValue && idleTimeValue > 0 && fallbackDuration > 0) {
|
|
57207
|
+
const idleSeconds = Number(idleTimeValue);
|
|
57208
|
+
const idleFromAggregate = Math.min(Math.max(idleSeconds / 60, 0), fallbackDuration);
|
|
57209
|
+
idleMinutes = idleFromAggregate;
|
|
57210
|
+
activeMinutes = Math.max(fallbackDuration - idleFromAggregate, 0);
|
|
57211
|
+
availableMinutes = activeMinutes + idleMinutes;
|
|
57212
|
+
hasData = true;
|
|
57213
|
+
}
|
|
57214
|
+
}
|
|
57215
|
+
const efficiencyValue = Number.isFinite(workspace.efficiency) ? Number(workspace.efficiency) : null;
|
|
57216
|
+
const utilization = efficiencyValue !== null ? efficiencyValue : availableMinutes > 0 ? activeMinutes / availableMinutes * 100 : 0;
|
|
57217
|
+
return {
|
|
57218
|
+
workspace,
|
|
57219
|
+
utilization,
|
|
57220
|
+
idleTimeSeconds: idleMinutes * 60,
|
|
57221
|
+
activeMinutes,
|
|
57222
|
+
idleMinutes,
|
|
57223
|
+
availableMinutes,
|
|
57224
|
+
hasData: efficiencyValue !== null || hasData || availableMinutes > 0,
|
|
57225
|
+
uptimeSeries: uptimeSeries2
|
|
57226
|
+
};
|
|
57227
|
+
});
|
|
57228
|
+
}, [
|
|
57229
|
+
isUptimeMode,
|
|
57230
|
+
resolvedWorkspaces,
|
|
57231
|
+
resolvedShiftTimes.start,
|
|
57232
|
+
resolvedShiftTimes.end,
|
|
57233
|
+
chartMetrics?.date,
|
|
57234
|
+
configuredTimezone,
|
|
57235
|
+
isCurrentShiftView
|
|
57236
|
+
]);
|
|
57237
|
+
const lineUptimeStats = React26.useMemo(() => {
|
|
57238
|
+
if (!isUptimeMode) {
|
|
57239
|
+
return {
|
|
57240
|
+
utilizationPercent: lineUtilizationFromLine,
|
|
57241
|
+
idleTimeSeconds: lineIdleTimeSecondsFromLine
|
|
57242
|
+
};
|
|
57243
|
+
}
|
|
57244
|
+
const validSummaries = workspaceUptimeSummaries.filter((summary) => summary.hasData);
|
|
57245
|
+
if (!validSummaries.length) {
|
|
57246
|
+
return {
|
|
57247
|
+
utilizationPercent: lineUtilizationFromLine,
|
|
57248
|
+
idleTimeSeconds: lineIdleTimeSecondsFromLine
|
|
57249
|
+
};
|
|
57250
|
+
}
|
|
57251
|
+
const avgUtilization = validSummaries.reduce((sum, summary) => sum + summary.utilization, 0) / validSummaries.length;
|
|
57252
|
+
const avgIdleSeconds = validSummaries.reduce((sum, summary) => sum + summary.idleTimeSeconds, 0) / validSummaries.length;
|
|
57253
|
+
return {
|
|
57254
|
+
utilizationPercent: avgUtilization,
|
|
57255
|
+
idleTimeSeconds: avgIdleSeconds
|
|
57256
|
+
};
|
|
57257
|
+
}, [isUptimeMode, workspaceUptimeSummaries, lineUtilizationFromLine, lineIdleTimeSecondsFromLine]);
|
|
57258
|
+
const hourlyAggregates = React26.useMemo(() => {
|
|
57259
|
+
if (!isUptimeMode || workspaceUptimeSummaries.length === 0) return null;
|
|
57260
|
+
const seriesSummaries = workspaceUptimeSummaries.filter((summary) => summary.uptimeSeries.hasData && summary.uptimeSeries.points.length > 0);
|
|
57261
|
+
if (!seriesSummaries.length) return null;
|
|
57262
|
+
const shiftMinutes = seriesSummaries[0].uptimeSeries.shiftMinutes;
|
|
57263
|
+
if (!shiftMinutes || shiftMinutes <= 0) return null;
|
|
57264
|
+
const shiftDurationHours = Math.ceil(shiftMinutes / 60);
|
|
57265
|
+
return Array.from({ length: shiftDurationHours }, (_, hourIndex) => {
|
|
57266
|
+
const start = hourIndex * 60;
|
|
57267
|
+
const end = Math.min(start + 60, shiftMinutes);
|
|
57268
|
+
let totalActive = 0;
|
|
57269
|
+
let totalIdle = 0;
|
|
57270
|
+
let totalProductivePercent = 0;
|
|
57271
|
+
let workspaceCount = 0;
|
|
57272
|
+
seriesSummaries.forEach((summary) => {
|
|
57273
|
+
const slice = summary.uptimeSeries.points.slice(start, end);
|
|
57274
|
+
if (!slice.length) return;
|
|
57275
|
+
let activeForWorkspace = 0;
|
|
57276
|
+
let idleForWorkspace = 0;
|
|
57277
|
+
slice.forEach((point) => {
|
|
57278
|
+
if (point.status === "active") activeForWorkspace += 1;
|
|
57279
|
+
if (point.status === "idle") idleForWorkspace += 1;
|
|
57280
|
+
});
|
|
57281
|
+
const known = activeForWorkspace + idleForWorkspace;
|
|
57282
|
+
if (known > 0) {
|
|
57283
|
+
workspaceCount += 1;
|
|
57284
|
+
totalActive += activeForWorkspace;
|
|
57285
|
+
totalIdle += idleForWorkspace;
|
|
57286
|
+
totalProductivePercent += activeForWorkspace / known * 100;
|
|
57287
|
+
}
|
|
57288
|
+
});
|
|
57289
|
+
const avgProductivePercent = workspaceCount > 0 ? totalProductivePercent / workspaceCount : 0;
|
|
57290
|
+
const productivePercent = workspaceCount > 0 ? Number(avgProductivePercent.toFixed(2)) : 0;
|
|
57291
|
+
const idlePercent = workspaceCount > 0 ? Math.max(0, Math.min(100, Number((100 - productivePercent).toFixed(2)))) : 0;
|
|
57292
|
+
const avgIdleMinutes = workspaceCount > 0 ? totalIdle / workspaceCount : 0;
|
|
57293
|
+
const avgProductiveMinutes = workspaceCount > 0 ? totalActive / workspaceCount : 0;
|
|
57294
|
+
return {
|
|
57295
|
+
productivePercent,
|
|
57296
|
+
idlePercent,
|
|
57297
|
+
idleMinutes: avgIdleMinutes,
|
|
57298
|
+
productiveMinutes: avgProductiveMinutes
|
|
57299
|
+
};
|
|
57300
|
+
});
|
|
57301
|
+
}, [isUptimeMode, workspaceUptimeSummaries]);
|
|
55896
57302
|
const isHistoricalAwaitingParams = historicalRouteRequested && !historicalParamsReady;
|
|
55897
57303
|
const isHistoricalAwaitingData = historicalRouteRequested && historicalParamsReady && (lineMetricsLoading || workspacesLoading);
|
|
55898
57304
|
React26.useEffect(() => {
|
|
@@ -56058,6 +57464,10 @@ var KPIDetailView = ({
|
|
|
56058
57464
|
if (!resolvedWorkspaces) return [];
|
|
56059
57465
|
return [...resolvedWorkspaces].filter((w) => w.efficiency >= 10).sort((a, b) => (a.efficiency || 0) - (b.efficiency || 0)).slice(0, 5);
|
|
56060
57466
|
}, [resolvedWorkspaces]);
|
|
57467
|
+
const sortedByUtilization = React26.useMemo(() => {
|
|
57468
|
+
if (!isUptimeMode || workspaceUptimeSummaries.length === 0) return [];
|
|
57469
|
+
return [...workspaceUptimeSummaries].filter((summary) => summary.hasData).sort((a, b) => a.utilization - b.utilization).slice(0, 5).map((summary) => ({ ...summary.workspace, utilization: summary.utilization }));
|
|
57470
|
+
}, [isUptimeMode, workspaceUptimeSummaries]);
|
|
56061
57471
|
React26.useEffect(() => {
|
|
56062
57472
|
let timeoutId;
|
|
56063
57473
|
const suppressNotFound = isHistoricalAwaitingParams || isHistoricalAwaitingData;
|
|
@@ -56378,7 +57788,7 @@ var KPIDetailView = ({
|
|
|
56378
57788
|
{
|
|
56379
57789
|
onClick: handleOverviewClick,
|
|
56380
57790
|
className: `flex-1 px-2 py-1.5 text-xs font-medium rounded-md transition-all duration-200 ${activeTab === "overview" ? "bg-white text-gray-900 shadow-sm" : "text-gray-600"}`,
|
|
56381
|
-
children:
|
|
57791
|
+
children: overviewTabLabel
|
|
56382
57792
|
}
|
|
56383
57793
|
),
|
|
56384
57794
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -56397,7 +57807,7 @@ var KPIDetailView = ({
|
|
|
56397
57807
|
{
|
|
56398
57808
|
onClick: handleOverviewClick,
|
|
56399
57809
|
className: `px-3 py-1.5 text-sm font-medium rounded-lg transition-colors whitespace-nowrap ${activeTab === "overview" ? "bg-blue-50 text-blue-600" : "text-gray-600 hover:bg-gray-50"}`,
|
|
56400
|
-
children:
|
|
57810
|
+
children: overviewTabLabel
|
|
56401
57811
|
}
|
|
56402
57812
|
),
|
|
56403
57813
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -56431,6 +57841,7 @@ var KPIDetailView = ({
|
|
|
56431
57841
|
lineName: resolvedLineInfo?.line_name || "Line",
|
|
56432
57842
|
monthlyData,
|
|
56433
57843
|
analysisData: analysisMonthlyData,
|
|
57844
|
+
monitoringMode: resolvedMonitoringMode,
|
|
56434
57845
|
underperformingWorkspaces,
|
|
56435
57846
|
legend: efficiencyLegend,
|
|
56436
57847
|
selectedMonth: currentMonth,
|
|
@@ -56455,7 +57866,16 @@ var KPIDetailView = ({
|
|
|
56455
57866
|
exit: "exit",
|
|
56456
57867
|
className: "space-y-6 md:space-y-0",
|
|
56457
57868
|
children: resolvedLineInfo && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
56458
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
57869
|
+
isUptimeMode ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
57870
|
+
LineUptimeMetricCards,
|
|
57871
|
+
{
|
|
57872
|
+
utilizationPercent: lineUptimeStats.utilizationPercent,
|
|
57873
|
+
stoppages: chartMetrics?.current_output || 0,
|
|
57874
|
+
idleTimeSeconds: lineUptimeStats.idleTimeSeconds,
|
|
57875
|
+
idleTimeData,
|
|
57876
|
+
showIdleTime: idleTimeVlmEnabled
|
|
57877
|
+
}
|
|
57878
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
56459
57879
|
MetricCards,
|
|
56460
57880
|
{
|
|
56461
57881
|
lineInfo: resolvedLineInfo,
|
|
@@ -56464,7 +57884,25 @@ var KPIDetailView = ({
|
|
|
56464
57884
|
efficiencyLegend
|
|
56465
57885
|
}
|
|
56466
57886
|
),
|
|
56467
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
57887
|
+
isUptimeMode ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
57888
|
+
UptimeBottomSection,
|
|
57889
|
+
{
|
|
57890
|
+
lineId,
|
|
57891
|
+
workspaceData: resolvedWorkspaces || [],
|
|
57892
|
+
sortedByUtilization,
|
|
57893
|
+
workspaceDisplayNames,
|
|
57894
|
+
idleTimeHourly: chartMetrics?.idle_time_hourly,
|
|
57895
|
+
hourlyAggregates,
|
|
57896
|
+
shiftStart: resolvedShiftTimes.start,
|
|
57897
|
+
shiftEnd: resolvedShiftTimes.end,
|
|
57898
|
+
shiftDate: chartMetrics?.date,
|
|
57899
|
+
timezone: configuredTimezone,
|
|
57900
|
+
elapsedMinutes: elapsedShiftMinutes,
|
|
57901
|
+
urlDate,
|
|
57902
|
+
urlShift,
|
|
57903
|
+
navigate
|
|
57904
|
+
}
|
|
57905
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
56468
57906
|
BottomSection,
|
|
56469
57907
|
{
|
|
56470
57908
|
lineInfo: resolvedLineInfo,
|
|
@@ -56503,6 +57941,8 @@ var KPIDetailView = ({
|
|
|
56503
57941
|
rangeEnd,
|
|
56504
57942
|
timezone: configuredTimezone,
|
|
56505
57943
|
legend: efficiencyLegend,
|
|
57944
|
+
monitoringMode: resolvedMonitoringMode,
|
|
57945
|
+
shiftConfig,
|
|
56506
57946
|
selectedShiftId,
|
|
56507
57947
|
onShiftChange: setSelectedShiftId,
|
|
56508
57948
|
onRangeChange: handleRangeChange,
|
|
@@ -56523,7 +57963,16 @@ var KPIDetailView = ({
|
|
|
56523
57963
|
exit: "exit",
|
|
56524
57964
|
className: "space-y-6 md:space-y-0",
|
|
56525
57965
|
children: resolvedLineInfo && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
56526
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
57966
|
+
isUptimeMode ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
57967
|
+
LineUptimeMetricCards,
|
|
57968
|
+
{
|
|
57969
|
+
utilizationPercent: lineUptimeStats.utilizationPercent,
|
|
57970
|
+
stoppages: chartMetrics?.current_output || 0,
|
|
57971
|
+
idleTimeSeconds: lineUptimeStats.idleTimeSeconds,
|
|
57972
|
+
idleTimeData,
|
|
57973
|
+
showIdleTime: idleTimeVlmEnabled
|
|
57974
|
+
}
|
|
57975
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
56527
57976
|
MetricCards,
|
|
56528
57977
|
{
|
|
56529
57978
|
lineInfo: resolvedLineInfo,
|
|
@@ -56532,7 +57981,25 @@ var KPIDetailView = ({
|
|
|
56532
57981
|
efficiencyLegend
|
|
56533
57982
|
}
|
|
56534
57983
|
),
|
|
56535
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
57984
|
+
isUptimeMode ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
57985
|
+
UptimeBottomSection,
|
|
57986
|
+
{
|
|
57987
|
+
lineId,
|
|
57988
|
+
workspaceData: resolvedWorkspaces || [],
|
|
57989
|
+
sortedByUtilization,
|
|
57990
|
+
workspaceDisplayNames,
|
|
57991
|
+
idleTimeHourly: chartMetrics?.idle_time_hourly,
|
|
57992
|
+
hourlyAggregates,
|
|
57993
|
+
shiftStart: resolvedShiftTimes.start,
|
|
57994
|
+
shiftEnd: resolvedShiftTimes.end,
|
|
57995
|
+
shiftDate: chartMetrics?.date,
|
|
57996
|
+
timezone: configuredTimezone,
|
|
57997
|
+
elapsedMinutes: elapsedShiftMinutes,
|
|
57998
|
+
urlDate,
|
|
57999
|
+
urlShift,
|
|
58000
|
+
navigate
|
|
58001
|
+
}
|
|
58002
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
56536
58003
|
BottomSection,
|
|
56537
58004
|
{
|
|
56538
58005
|
lineInfo: resolvedLineInfo,
|
|
@@ -56881,7 +58348,7 @@ var LinesLeaderboard = ({
|
|
|
56881
58348
|
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: `font-bold text-gray-900 text-center line-clamp-1 mb-1 ${isFirst ? "text-xs md:text-sm lg:text-base xl:text-lg" : "text-[10px] md:text-xs lg:text-sm xl:text-base"}`, children: item.supervisorName }),
|
|
56882
58349
|
/* @__PURE__ */ jsxRuntime.jsx("p", { className: `text-gray-600 text-center line-clamp-1 font-medium opacity-80 bg-white/50 px-2 md:px-3 py-0.5 rounded-full ${isFirst ? "text-[9px] md:text-[10px] lg:text-xs xl:text-sm mb-2 md:mb-3" : "text-[8px] md:text-[9px] lg:text-[10px] xl:text-xs mb-1 md:mb-2"}`, children: item.line.line_name }),
|
|
56883
58350
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center mt-auto", children: [
|
|
56884
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: `font-bold uppercase tracking-widest mb-0.5 ${isFirst ? "text-yellow-700/70 text-[8px] md:text-[9px] lg:text-[10px] xl:text-xs" : isSecond ? "text-gray-600/70 text-[7px] md:text-[8px] lg:text-[9px] xl:text-[10px]" : "text-orange-700/70 text-[7px] md:text-[8px] lg:text-[9px] xl:text-[10px]"}`, children: "Efficiency" }),
|
|
58351
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: `font-bold uppercase tracking-widest mb-0.5 ${isFirst ? "text-yellow-700/70 text-[8px] md:text-[9px] lg:text-[10px] xl:text-xs" : isSecond ? "text-gray-600/70 text-[7px] md:text-[8px] lg:text-[9px] xl:text-[10px]" : "text-orange-700/70 text-[7px] md:text-[8px] lg:text-[9px] xl:text-[10px]"}`, children: viewType === "machine" ? "Utilization" : "Efficiency" }),
|
|
56885
58352
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: `font-black tracking-tight leading-none ${isFirst ? "text-lg md:text-xl lg:text-2xl xl:text-3xl text-transparent bg-clip-text bg-gradient-to-br from-yellow-600 to-yellow-800 drop-shadow-sm" : isSecond ? "text-base md:text-lg lg:text-xl xl:text-2xl text-transparent bg-clip-text bg-gradient-to-br from-gray-600 to-gray-800 drop-shadow-sm" : "text-sm md:text-base lg:text-lg xl:text-xl text-transparent bg-clip-text bg-gradient-to-br from-orange-600 to-orange-800 drop-shadow-sm"}`, children: formatEfficiency(item.efficiency) })
|
|
56886
58353
|
] })
|
|
56887
58354
|
] })
|
|
@@ -56898,7 +58365,7 @@ var LinesLeaderboard = ({
|
|
|
56898
58365
|
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold text-gray-500 uppercase tracking-wider w-16", children: "Rank" }),
|
|
56899
58366
|
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold text-gray-500 uppercase tracking-wider", children: "Assigned To" }),
|
|
56900
58367
|
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold text-gray-500 uppercase tracking-wider", children: "Line" }),
|
|
56901
|
-
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 text-right text-xs font-semibold text-gray-500 uppercase tracking-wider", children: "Efficiency" })
|
|
58368
|
+
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 text-right text-xs font-semibold text-gray-500 uppercase tracking-wider", children: viewType === "machine" ? "Utilization" : "Efficiency" })
|
|
56902
58369
|
] }) }),
|
|
56903
58370
|
/* @__PURE__ */ jsxRuntime.jsx("tbody", { className: "divide-y divide-gray-100", children: leaderboardData.map((item) => {
|
|
56904
58371
|
const isTopThree = item.rank <= 3;
|
|
@@ -56954,7 +58421,8 @@ var LineCard = ({
|
|
|
56954
58421
|
supervisorName,
|
|
56955
58422
|
supervisors
|
|
56956
58423
|
}) => {
|
|
56957
|
-
const
|
|
58424
|
+
const isUptimeLine = (line.monitoring_mode ?? "output") === "uptime";
|
|
58425
|
+
React26__namespace.default.useMemo(() => {
|
|
56958
58426
|
if (!kpis) return null;
|
|
56959
58427
|
return kpis.efficiency.value > 90;
|
|
56960
58428
|
}, [kpis]);
|
|
@@ -56967,73 +58435,67 @@ var LineCard = ({
|
|
|
56967
58435
|
onClick: () => onClick(kpis),
|
|
56968
58436
|
className: "relative bg-white border border-gray-200/80 shadow-sm hover:shadow-lg \n rounded-xl p-4 sm:p-5 md:p-6 transition-all duration-200 cursor-pointer \n hover:scale-[1.01] active:scale-[0.99] group",
|
|
56969
58437
|
children: [
|
|
56970
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-4 sm:mb-5 md:mb-6", children: /* @__PURE__ */ jsxRuntime.
|
|
56971
|
-
/* @__PURE__ */ jsxRuntime.
|
|
56972
|
-
|
|
56973
|
-
|
|
56974
|
-
|
|
56975
|
-
|
|
56976
|
-
|
|
56977
|
-
|
|
56978
|
-
|
|
56979
|
-
|
|
56980
|
-
|
|
56981
|
-
|
|
56982
|
-
|
|
56983
|
-
/* @__PURE__ */ jsxRuntime.
|
|
56984
|
-
|
|
56985
|
-
|
|
56986
|
-
|
|
56987
|
-
|
|
56988
|
-
|
|
56989
|
-
|
|
56990
|
-
|
|
56991
|
-
|
|
56992
|
-
|
|
56993
|
-
|
|
56994
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute top-full left-1/2 -translate-x-1/2 -mt-[1px] border-4 border-transparent border-t-gray-900" })
|
|
56995
|
-
] })
|
|
58438
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-4 sm:mb-5 md:mb-6", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap items-start gap-2 sm:gap-3", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 min-w-0", children: [
|
|
58439
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
58440
|
+
FittingTitle,
|
|
58441
|
+
{
|
|
58442
|
+
title: line.line_name,
|
|
58443
|
+
className: "text-[10px] sm:text-xs md:text-sm"
|
|
58444
|
+
}
|
|
58445
|
+
),
|
|
58446
|
+
supervisorEnabled && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-4", children: [
|
|
58447
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[10px] font-semibold text-gray-400 uppercase tracking-wider mb-1.5", children: "Assigned To" }),
|
|
58448
|
+
supervisors && supervisors.length > 0 ? supervisors.length === 1 ? (
|
|
58449
|
+
// Single supervisor - just avatar with tooltip
|
|
58450
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative w-12 h-12 rounded-full bg-white border border-gray-100 shadow-sm flex-shrink-0 group/avatar hover:scale-110 transition-transform", children: [
|
|
58451
|
+
supervisors[0].profilePhotoUrl ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
58452
|
+
"img",
|
|
58453
|
+
{
|
|
58454
|
+
src: supervisors[0].profilePhotoUrl,
|
|
58455
|
+
alt: supervisors[0].displayName,
|
|
58456
|
+
className: "w-full h-full object-cover rounded-full"
|
|
58457
|
+
}
|
|
58458
|
+
) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full h-full flex items-center justify-center bg-gray-50 text-base font-bold text-gray-500 uppercase rounded-full", children: getInitials(supervisors[0].displayName) }),
|
|
58459
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute bottom-full left-1/2 -translate-x-1/2 mb-2 px-2 py-1 bg-gray-900 text-white text-[10px] font-medium rounded shadow-lg opacity-0 group-hover/avatar:opacity-100 transition-opacity whitespace-nowrap pointer-events-none z-20", children: [
|
|
58460
|
+
supervisors[0].displayName,
|
|
58461
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute top-full left-1/2 -translate-x-1/2 -mt-[1px] border-4 border-transparent border-t-gray-900" })
|
|
56996
58462
|
] })
|
|
56997
|
-
)
|
|
56998
|
-
|
|
56999
|
-
|
|
57000
|
-
|
|
57001
|
-
|
|
57002
|
-
|
|
57003
|
-
|
|
57004
|
-
|
|
57005
|
-
|
|
57006
|
-
|
|
57007
|
-
|
|
57008
|
-
|
|
57009
|
-
|
|
57010
|
-
|
|
57011
|
-
|
|
57012
|
-
|
|
57013
|
-
|
|
57014
|
-
|
|
57015
|
-
|
|
57016
|
-
] })
|
|
57017
|
-
]
|
|
57018
|
-
|
|
57019
|
-
|
|
57020
|
-
|
|
57021
|
-
|
|
57022
|
-
|
|
57023
|
-
|
|
57024
|
-
|
|
58463
|
+
] })
|
|
58464
|
+
) : (
|
|
58465
|
+
// Multiple supervisors - overlapping avatars
|
|
58466
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex -space-x-4 py-1", children: [
|
|
58467
|
+
supervisors.slice(0, 3).map((supervisor) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
58468
|
+
"div",
|
|
58469
|
+
{
|
|
58470
|
+
className: "relative inline-block w-12 h-12 rounded-full ring-2 ring-white bg-white shadow-sm z-0 hover:z-10 transition-all hover:scale-110 group/avatar",
|
|
58471
|
+
children: [
|
|
58472
|
+
supervisor.profilePhotoUrl ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
58473
|
+
"img",
|
|
58474
|
+
{
|
|
58475
|
+
src: supervisor.profilePhotoUrl,
|
|
58476
|
+
alt: supervisor.displayName,
|
|
58477
|
+
className: "w-full h-full object-cover rounded-full"
|
|
58478
|
+
}
|
|
58479
|
+
) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full h-full flex items-center justify-center bg-gray-100 text-sm font-bold text-gray-600 uppercase rounded-full", children: getInitials(supervisor.displayName) }),
|
|
58480
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute bottom-full left-1/2 -translate-x-1/2 mb-2 px-2 py-1 bg-gray-900 text-white text-[10px] font-medium rounded shadow-lg opacity-0 group-hover/avatar:opacity-100 transition-opacity whitespace-nowrap pointer-events-none z-20", children: [
|
|
58481
|
+
supervisor.displayName,
|
|
58482
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute top-full left-1/2 -translate-x-1/2 -mt-[1px] border-4 border-transparent border-t-gray-900" })
|
|
58483
|
+
] })
|
|
58484
|
+
]
|
|
58485
|
+
},
|
|
58486
|
+
supervisor.userId
|
|
58487
|
+
)),
|
|
58488
|
+
supervisors.length > 3 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "inline-flex w-12 h-12 rounded-full ring-2 ring-white bg-gray-100 items-center justify-center text-sm font-medium text-gray-600 z-0", children: [
|
|
58489
|
+
"+",
|
|
58490
|
+
supervisors.length - 3
|
|
57025
58491
|
] })
|
|
57026
|
-
) : /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-sm text-gray-600", children: [
|
|
57027
|
-
"Supervisor: ",
|
|
57028
|
-
supervisorName || "Unassigned"
|
|
57029
58492
|
] })
|
|
58493
|
+
) : /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-sm text-gray-600", children: [
|
|
58494
|
+
"Supervisor: ",
|
|
58495
|
+
supervisorName || "Unassigned"
|
|
57030
58496
|
] })
|
|
57031
|
-
] }),
|
|
57032
|
-
kpis && isOnTrack !== null && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `flex items-center gap-1.5 px-2.5 sm:px-3 py-1 sm:py-1.5 rounded-full text-xs font-medium flex-shrink-0 ${isOnTrack ? "bg-emerald-100 text-emerald-700 border border-emerald-200" : "bg-red-100 text-red-700 border border-red-200"}`, style: { minWidth: "fit-content" }, children: [
|
|
57033
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: `w-2 h-2 rounded-full ${isOnTrack ? "bg-emerald-500" : "bg-red-500"} animate-pulse` }),
|
|
57034
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { children: isOnTrack ? "On Track" : "Behind" })
|
|
57035
58497
|
] })
|
|
57036
|
-
] }) }),
|
|
58498
|
+
] }) }) }),
|
|
57037
58499
|
isLoading && !kpis && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4", children: [
|
|
57038
58500
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "animate-pulse", children: [
|
|
57039
58501
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-4 bg-gray-200 rounded w-1/3 mb-2" }),
|
|
@@ -57051,7 +58513,7 @@ var LineCard = ({
|
|
|
57051
58513
|
error && !kpis && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-center py-8", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-gray-500", children: "Unable to load metrics" }) }),
|
|
57052
58514
|
kpis && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4 sm:space-y-5 pb-8 sm:pb-10", children: [
|
|
57053
58515
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
57054
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs font-medium text-gray-500 uppercase tracking-wider mb-1.5 sm:mb-2", children: "Efficiency" }),
|
|
58516
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs font-medium text-gray-500 uppercase tracking-wider mb-1.5 sm:mb-2", children: isUptimeLine ? "Utilization" : "Efficiency" }),
|
|
57055
58517
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-baseline justify-between", children: [
|
|
57056
58518
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-2xl sm:text-3xl font-semibold text-gray-900", children: [
|
|
57057
58519
|
kpis.efficiency.value.toFixed(1),
|
|
@@ -57065,16 +58527,16 @@ var LineCard = ({
|
|
|
57065
58527
|
] })
|
|
57066
58528
|
] }),
|
|
57067
58529
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
57068
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs font-medium text-gray-500 uppercase tracking-wider mb-1.5 sm:mb-2", children: "Output Progress" }),
|
|
58530
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs font-medium text-gray-500 uppercase tracking-wider mb-1.5 sm:mb-2", children: isUptimeLine ? "Stoppages" : "Output Progress" }),
|
|
57069
58531
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-baseline justify-between mb-2 sm:mb-3", children: [
|
|
57070
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xl sm:text-2xl font-semibold text-gray-900"
|
|
57071
|
-
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs sm:text-sm text-gray-500 font-medium", children: [
|
|
58532
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: `${isUptimeLine ? "text-2xl sm:text-3xl font-bold text-red-600" : "text-xl sm:text-2xl font-semibold text-gray-900"}`, children: kpis.outputProgress.current }),
|
|
58533
|
+
!isUptimeLine && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs sm:text-sm text-gray-500 font-medium", children: [
|
|
57072
58534
|
"/ ",
|
|
57073
58535
|
kpis.outputProgress.target,
|
|
57074
58536
|
" units"
|
|
57075
58537
|
] })
|
|
57076
58538
|
] }),
|
|
57077
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full bg-gray-200 rounded-full h-2 sm:h-2.5", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
58539
|
+
!isUptimeLine && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full bg-gray-200 rounded-full h-2 sm:h-2.5", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
57078
58540
|
"div",
|
|
57079
58541
|
{
|
|
57080
58542
|
className: "bg-blue-600 h-2 sm:h-2.5 rounded-full transition-all duration-500 ease-out",
|
|
@@ -57150,6 +58612,38 @@ var KPIsOverviewView = ({
|
|
|
57150
58612
|
const targetMode = viewType === "machine" ? "uptime" : "output";
|
|
57151
58613
|
return leaderboardLines.filter((line) => (line.monitoring_mode ?? "output") === targetMode);
|
|
57152
58614
|
}, [leaderboardLines, viewType]);
|
|
58615
|
+
const linesForView = React26__namespace.default.useMemo(() => {
|
|
58616
|
+
const targetMode = viewType === "machine" ? "uptime" : "output";
|
|
58617
|
+
return lines.filter((line) => (line.monitoring_mode ?? "output") === targetMode);
|
|
58618
|
+
}, [lines, viewType]);
|
|
58619
|
+
const relevantLinesForMode = React26__namespace.default.useMemo(() => {
|
|
58620
|
+
if (activeTab === "leaderboard") {
|
|
58621
|
+
return leaderboardLines.length > 0 ? leaderboardLines : lines;
|
|
58622
|
+
}
|
|
58623
|
+
return lines;
|
|
58624
|
+
}, [activeTab, leaderboardLines, lines]);
|
|
58625
|
+
const { hasUptime, hasOutput } = React26__namespace.default.useMemo(() => {
|
|
58626
|
+
let uptime = false;
|
|
58627
|
+
let output = false;
|
|
58628
|
+
for (const line of relevantLinesForMode) {
|
|
58629
|
+
const mode = line.monitoring_mode ?? "output";
|
|
58630
|
+
if (mode === "uptime") {
|
|
58631
|
+
uptime = true;
|
|
58632
|
+
} else {
|
|
58633
|
+
output = true;
|
|
58634
|
+
}
|
|
58635
|
+
if (uptime && output) break;
|
|
58636
|
+
}
|
|
58637
|
+
return { hasUptime: uptime, hasOutput: output };
|
|
58638
|
+
}, [relevantLinesForMode]);
|
|
58639
|
+
const showViewTypeDropdown = hasUptime && hasOutput;
|
|
58640
|
+
React26.useEffect(() => {
|
|
58641
|
+
if (hasUptime && !hasOutput && viewType !== "machine") {
|
|
58642
|
+
setViewType("machine");
|
|
58643
|
+
} else if (hasOutput && !hasUptime && viewType !== "operator") {
|
|
58644
|
+
setViewType("operator");
|
|
58645
|
+
}
|
|
58646
|
+
}, [hasUptime, hasOutput, viewType]);
|
|
57153
58647
|
const currentShiftDetails = getCurrentShift(configuredTimezone, shiftConfig);
|
|
57154
58648
|
const currentShiftDate = currentShiftDetails.date;
|
|
57155
58649
|
const currentShiftId = currentShiftDetails.shiftId;
|
|
@@ -57822,7 +59316,7 @@ var KPIsOverviewView = ({
|
|
|
57822
59316
|
}
|
|
57823
59317
|
)
|
|
57824
59318
|
] }),
|
|
57825
|
-
activeTab === "leaderboard" && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
59319
|
+
(activeTab === "leaderboard" || activeTab === "today") && showViewTypeDropdown && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
57826
59320
|
"select",
|
|
57827
59321
|
{
|
|
57828
59322
|
value: viewType,
|
|
@@ -57830,7 +59324,7 @@ var KPIsOverviewView = ({
|
|
|
57830
59324
|
className: "appearance-none pl-3 pr-8 py-1.5 text-sm font-medium bg-white border border-gray-200 hover:border-gray-300 rounded-lg text-gray-700 focus:outline-none focus:ring-2 focus:ring-blue-500 transition-all cursor-pointer shadow-sm",
|
|
57831
59325
|
style: { backgroundImage: `url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e")`, backgroundPosition: `right 0.5rem center`, backgroundRepeat: `no-repeat`, backgroundSize: `1.2em 1.2em` },
|
|
57832
59326
|
children: [
|
|
57833
|
-
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "operator", children: "
|
|
59327
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "operator", children: "Workforce" }),
|
|
57834
59328
|
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "machine", children: "Machine" })
|
|
57835
59329
|
]
|
|
57836
59330
|
}
|
|
@@ -57840,7 +59334,7 @@ var KPIsOverviewView = ({
|
|
|
57840
59334
|
] }) }),
|
|
57841
59335
|
/* @__PURE__ */ jsxRuntime.jsx("main", { className: `flex-1 p-3 sm:p-4 md:p-6 bg-slate-50 ${activeTab === "leaderboard" ? "overflow-hidden flex flex-col" : "overflow-y-auto"}`, children: activeTab === "today" ? (
|
|
57842
59336
|
/* Line Cards Grid */
|
|
57843
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-3 sm:gap-4 md:gap-6", children:
|
|
59337
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-3 sm:gap-4 md:gap-6", children: linesForView.map((line) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
57844
59338
|
LineCard,
|
|
57845
59339
|
{
|
|
57846
59340
|
line,
|
|
@@ -57947,7 +59441,8 @@ var MobileWorkspaceCard = React26.memo(({
|
|
|
57947
59441
|
rank,
|
|
57948
59442
|
cardClass,
|
|
57949
59443
|
onWorkspaceClick,
|
|
57950
|
-
getMedalIcon
|
|
59444
|
+
getMedalIcon,
|
|
59445
|
+
efficiencyLabel
|
|
57951
59446
|
}) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
57952
59447
|
motion.div,
|
|
57953
59448
|
{
|
|
@@ -57975,12 +59470,12 @@ var MobileWorkspaceCard = React26.memo(({
|
|
|
57975
59470
|
] }),
|
|
57976
59471
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-right", children: [
|
|
57977
59472
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-lg font-bold text-gray-900", children: /* @__PURE__ */ jsxRuntime.jsx(AnimatedEfficiency, { value: workspace.efficiency || 0 }) }),
|
|
57978
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-gray-500", children:
|
|
59473
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-gray-500", children: efficiencyLabel })
|
|
57979
59474
|
] })
|
|
57980
59475
|
] })
|
|
57981
59476
|
}
|
|
57982
59477
|
), (prevProps, nextProps) => {
|
|
57983
|
-
return prevProps.rank === nextProps.rank && prevProps.cardClass === nextProps.cardClass && prevProps.workspace.workspace_uuid === nextProps.workspace.workspace_uuid && prevProps.workspace.efficiency === nextProps.workspace.efficiency && prevProps.workspace.action_count === nextProps.workspace.action_count && prevProps.workspace.action_threshold === nextProps.workspace.action_threshold && prevProps.workspace.avg_cycle_time === nextProps.workspace.avg_cycle_time && prevProps.workspace.displayName === nextProps.workspace.displayName && prevProps.workspace.lineName === nextProps.workspace.lineName;
|
|
59478
|
+
return prevProps.efficiencyLabel === nextProps.efficiencyLabel && prevProps.rank === nextProps.rank && prevProps.cardClass === nextProps.cardClass && prevProps.workspace.workspace_uuid === nextProps.workspace.workspace_uuid && prevProps.workspace.efficiency === nextProps.workspace.efficiency && prevProps.workspace.action_count === nextProps.workspace.action_count && prevProps.workspace.action_threshold === nextProps.workspace.action_threshold && prevProps.workspace.avg_cycle_time === nextProps.workspace.avg_cycle_time && prevProps.workspace.displayName === nextProps.workspace.displayName && prevProps.workspace.lineName === nextProps.workspace.lineName;
|
|
57984
59479
|
});
|
|
57985
59480
|
MobileWorkspaceCard.displayName = "MobileWorkspaceCard";
|
|
57986
59481
|
var DesktopWorkspaceRow = React26.memo(({
|
|
@@ -58169,6 +59664,39 @@ var LeaderboardDetailView = React26.memo(({
|
|
|
58169
59664
|
}
|
|
58170
59665
|
return allLineIds;
|
|
58171
59666
|
}, [entityConfig, userAccessibleLineIds]);
|
|
59667
|
+
const { hasUptime: lineModeHasUptime, hasOutput: lineModeHasOutput } = React26.useMemo(() => {
|
|
59668
|
+
if (!lines || lines.length === 0) {
|
|
59669
|
+
return { hasUptime: false, hasOutput: false };
|
|
59670
|
+
}
|
|
59671
|
+
if (selectedLineFilter !== "all") {
|
|
59672
|
+
const selectedLine = lines.find((line) => line.id === selectedLineFilter);
|
|
59673
|
+
if (!selectedLine) {
|
|
59674
|
+
return { hasUptime: false, hasOutput: false };
|
|
59675
|
+
}
|
|
59676
|
+
const mode = selectedLine.monitoring_mode ?? "output";
|
|
59677
|
+
return { hasUptime: mode === "uptime", hasOutput: mode !== "uptime" };
|
|
59678
|
+
}
|
|
59679
|
+
let uptime = false;
|
|
59680
|
+
let output = false;
|
|
59681
|
+
for (const line of lines) {
|
|
59682
|
+
const mode = line.monitoring_mode ?? "output";
|
|
59683
|
+
if (mode === "uptime") {
|
|
59684
|
+
uptime = true;
|
|
59685
|
+
} else {
|
|
59686
|
+
output = true;
|
|
59687
|
+
}
|
|
59688
|
+
if (uptime && output) break;
|
|
59689
|
+
}
|
|
59690
|
+
return { hasUptime: uptime, hasOutput: output };
|
|
59691
|
+
}, [lines, selectedLineFilter]);
|
|
59692
|
+
const showViewTypeDropdown = lineModeHasUptime && lineModeHasOutput;
|
|
59693
|
+
React26.useEffect(() => {
|
|
59694
|
+
if (lineModeHasUptime && !lineModeHasOutput && viewType !== "machine") {
|
|
59695
|
+
setViewType("machine");
|
|
59696
|
+
} else if (lineModeHasOutput && !lineModeHasUptime && viewType !== "operator") {
|
|
59697
|
+
setViewType("operator");
|
|
59698
|
+
}
|
|
59699
|
+
}, [lineModeHasUptime, lineModeHasOutput, viewType]);
|
|
58172
59700
|
const lineKey = React26.useMemo(() => {
|
|
58173
59701
|
if (configuredLineIds.length === 0) {
|
|
58174
59702
|
return "all";
|
|
@@ -58628,6 +60156,7 @@ var LeaderboardDetailView = React26.memo(({
|
|
|
58628
60156
|
error.message
|
|
58629
60157
|
] }) });
|
|
58630
60158
|
}
|
|
60159
|
+
const efficiencyLabel = viewType === "machine" ? "Utilization" : "Efficiency";
|
|
58631
60160
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `min-h-screen bg-slate-50 flex flex-col ${className}`, style: { willChange: "contents" }, children: [
|
|
58632
60161
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "sticky top-0 z-20 bg-white shadow-sm border-b border-gray-200/80", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-3 sm:px-6 md:px-8 py-2 sm:py-2.5", children: [
|
|
58633
60162
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "sm:hidden", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center", children: [
|
|
@@ -58677,7 +60206,7 @@ var LeaderboardDetailView = React26.memo(({
|
|
|
58677
60206
|
] }),
|
|
58678
60207
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3", children: [
|
|
58679
60208
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
|
|
58680
|
-
/* @__PURE__ */ jsxRuntime.jsx("label", { className: "text-xs font-medium text-gray-500 uppercase tracking-wide ml-1", children:
|
|
60209
|
+
/* @__PURE__ */ jsxRuntime.jsx("label", { className: "text-xs font-medium text-gray-500 uppercase tracking-wide ml-1", children: efficiencyLabel }),
|
|
58681
60210
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
58682
60211
|
"select",
|
|
58683
60212
|
{
|
|
@@ -58814,7 +60343,7 @@ var LeaderboardDetailView = React26.memo(({
|
|
|
58814
60343
|
showLabel: false
|
|
58815
60344
|
}
|
|
58816
60345
|
),
|
|
58817
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
60346
|
+
showViewTypeDropdown && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
58818
60347
|
"select",
|
|
58819
60348
|
{
|
|
58820
60349
|
value: viewType,
|
|
@@ -58822,7 +60351,7 @@ var LeaderboardDetailView = React26.memo(({
|
|
|
58822
60351
|
className: "appearance-none pl-3 pr-8 py-1.5 text-sm font-medium bg-white border border-gray-200 hover:border-gray-300 rounded-lg text-gray-700 focus:outline-none focus:ring-2 focus:ring-blue-500 transition-all cursor-pointer shadow-sm",
|
|
58823
60352
|
style: { backgroundImage: `url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e")`, backgroundPosition: `right 0.5rem center`, backgroundRepeat: `no-repeat`, backgroundSize: `1.2em 1.2em` },
|
|
58824
60353
|
children: [
|
|
58825
|
-
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "operator", children: "
|
|
60354
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "operator", children: "Workforce" }),
|
|
58826
60355
|
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "machine", children: "Machine" })
|
|
58827
60356
|
]
|
|
58828
60357
|
}
|
|
@@ -58856,7 +60385,8 @@ var LeaderboardDetailView = React26.memo(({
|
|
|
58856
60385
|
rank,
|
|
58857
60386
|
cardClass,
|
|
58858
60387
|
onWorkspaceClick: stableHandleWorkspaceClick,
|
|
58859
|
-
getMedalIcon: stableGetMedalIcon
|
|
60388
|
+
getMedalIcon: stableGetMedalIcon,
|
|
60389
|
+
efficiencyLabel
|
|
58860
60390
|
},
|
|
58861
60391
|
ws.workspace_uuid
|
|
58862
60392
|
);
|
|
@@ -58867,7 +60397,7 @@ var LeaderboardDetailView = React26.memo(({
|
|
|
58867
60397
|
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-3 py-2.5 sm:p-4 text-left text-xs sm:text-sm font-semibold text-gray-600 whitespace-nowrap", children: "Rank" }),
|
|
58868
60398
|
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-3 py-2.5 sm:p-4 text-left text-xs sm:text-sm font-semibold text-gray-600 whitespace-nowrap", children: "Workspace" }),
|
|
58869
60399
|
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-3 py-2.5 sm:p-4 text-left text-xs sm:text-sm font-semibold text-gray-600 whitespace-nowrap", children: "Line" }),
|
|
58870
|
-
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-3 py-2.5 sm:p-4 text-left text-xs sm:text-sm font-semibold text-gray-600 whitespace-nowrap", children:
|
|
60400
|
+
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-3 py-2.5 sm:p-4 text-left text-xs sm:text-sm font-semibold text-gray-600 whitespace-nowrap", children: efficiencyLabel })
|
|
58871
60401
|
] }) }),
|
|
58872
60402
|
/* @__PURE__ */ jsxRuntime.jsx("tbody", { className: "divide-y divide-gray-100", children: sortedWorkspaces.map((ws, index) => {
|
|
58873
60403
|
const isTopThree = index < 3;
|
|
@@ -62018,7 +63548,7 @@ var WorkspaceDetailView = ({
|
|
|
62018
63548
|
date: cachedOverviewMetrics.date,
|
|
62019
63549
|
shift_id: cachedOverviewMetrics.shift_id,
|
|
62020
63550
|
action_name: "",
|
|
62021
|
-
monitoring_mode: "output",
|
|
63551
|
+
monitoring_mode: cachedOverviewMetrics.monitoring_mode ?? "output",
|
|
62022
63552
|
shift_start: shiftDefinition?.startTime || "",
|
|
62023
63553
|
shift_end: shiftDefinition?.endTime || "",
|
|
62024
63554
|
shift_type: shiftType,
|
|
@@ -62034,7 +63564,7 @@ var WorkspaceDetailView = ({
|
|
|
62034
63564
|
total_workspaces: 0,
|
|
62035
63565
|
ideal_output_until_now: idealOutput,
|
|
62036
63566
|
output_difference: totalActions - idealOutput,
|
|
62037
|
-
idle_time: 0,
|
|
63567
|
+
idle_time: Number(cachedOverviewMetrics.idle_time || 0),
|
|
62038
63568
|
idle_time_hourly: void 0
|
|
62039
63569
|
};
|
|
62040
63570
|
}, [cachedOverviewMetrics, shiftConfig?.shifts]);
|
|
@@ -62213,16 +63743,39 @@ var WorkspaceDetailView = ({
|
|
|
62213
63743
|
};
|
|
62214
63744
|
dayDataMap.set(dateKey, dayEntry);
|
|
62215
63745
|
}
|
|
63746
|
+
const idleTimeSecondsRaw = Number.isFinite(metric.idle_time_seconds) ? Number(metric.idle_time_seconds) : Number.isFinite(metric.idle_time) ? Number(metric.idle_time) : 0;
|
|
63747
|
+
const activeTimeSeconds = Number.isFinite(metric.active_time_seconds) ? Number(metric.active_time_seconds) : void 0;
|
|
63748
|
+
let availableTimeSeconds = Number.isFinite(metric.available_time_seconds) ? Number(metric.available_time_seconds) : void 0;
|
|
63749
|
+
if (availableTimeSeconds === void 0) {
|
|
63750
|
+
const activeFallback = activeTimeSeconds ?? 0;
|
|
63751
|
+
if (activeFallback > 0 || idleTimeSecondsRaw > 0) {
|
|
63752
|
+
availableTimeSeconds = activeFallback + idleTimeSecondsRaw;
|
|
63753
|
+
}
|
|
63754
|
+
}
|
|
63755
|
+
const idleTimeSeconds = idleTimeSecondsRaw;
|
|
63756
|
+
const computedUptimeEfficiency = (() => {
|
|
63757
|
+
const availableMinutes = (availableTimeSeconds ?? 0) / 60;
|
|
63758
|
+
if (!availableMinutes || availableMinutes <= 0) return 0;
|
|
63759
|
+
const idleMinutes = Math.min(Math.max(idleTimeSeconds / 60, 0), availableMinutes);
|
|
63760
|
+
const productiveMinutes = Math.max(
|
|
63761
|
+
(activeTimeSeconds ?? 0) / 60 || availableMinutes - idleMinutes,
|
|
63762
|
+
0
|
|
63763
|
+
);
|
|
63764
|
+
return Math.round(productiveMinutes / availableMinutes * 100);
|
|
63765
|
+
})();
|
|
62216
63766
|
const shiftData = {
|
|
62217
|
-
efficiency: metric.avg_efficiency
|
|
63767
|
+
efficiency: monitoringMode === "uptime" ? Number.isFinite(metric.avg_efficiency) ? Number(metric.avg_efficiency) : computedUptimeEfficiency : Number.isFinite(metric.avg_efficiency) ? Number(metric.avg_efficiency) : 0,
|
|
62218
63768
|
output: metric.total_output || 0,
|
|
62219
63769
|
cycleTime: metric.avg_cycle_time || 0,
|
|
62220
63770
|
pph: metric.avg_pph || 0,
|
|
62221
63771
|
pphThreshold: metric.pph_threshold || 0,
|
|
62222
|
-
idealOutput: metric.ideal_output || 0,
|
|
63772
|
+
idealOutput: Number(metric.ideal_output || 0),
|
|
63773
|
+
targetOutput: Number(metric.total_day_output || 0),
|
|
62223
63774
|
rank: metric.workspace_rank || 0,
|
|
62224
|
-
idleTime:
|
|
62225
|
-
|
|
63775
|
+
idleTime: idleTimeSeconds || 0,
|
|
63776
|
+
activeTimeSeconds,
|
|
63777
|
+
availableTimeSeconds,
|
|
63778
|
+
hasData: monitoringMode === "uptime" ? Boolean(availableTimeSeconds && availableTimeSeconds > 0) : true
|
|
62226
63779
|
};
|
|
62227
63780
|
dayEntry.shifts[metric.shift_id] = shiftData;
|
|
62228
63781
|
});
|
|
@@ -62235,7 +63788,7 @@ var WorkspaceDetailView = ({
|
|
|
62235
63788
|
sample: processedData.slice(0, 1)
|
|
62236
63789
|
});
|
|
62237
63790
|
setMonthlyData(processedData);
|
|
62238
|
-
}, []);
|
|
63791
|
+
}, [monitoringMode]);
|
|
62239
63792
|
React26.useEffect(() => {
|
|
62240
63793
|
if (activeTab === "monthly_history" && workspaceId) {
|
|
62241
63794
|
if (!supabase || !dashboardConfig || !dashboardConfig.supabaseUrl || !dashboardConfig.supabaseKey) {
|
|
@@ -69473,6 +71026,8 @@ exports.awardsService = awardsService;
|
|
|
69473
71026
|
exports.buildDateKey = buildDateKey;
|
|
69474
71027
|
exports.buildKPIsFromLineMetricsRow = buildKPIsFromLineMetricsRow;
|
|
69475
71028
|
exports.buildShiftGroupsKey = buildShiftGroupsKey;
|
|
71029
|
+
exports.captureSentryException = captureSentryException;
|
|
71030
|
+
exports.captureSentryMessage = captureSentryMessage;
|
|
69476
71031
|
exports.checkRateLimit = checkRateLimit2;
|
|
69477
71032
|
exports.clearAllRateLimits = clearAllRateLimits2;
|
|
69478
71033
|
exports.clearRateLimit = clearRateLimit2;
|