@optifye/dashboard-core 6.5.8 → 6.5.10

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.
Files changed (3) hide show
  1. package/dist/index.js +699 -190
  2. package/dist/index.mjs +699 -190
  3. package/package.json +1 -1
package/dist/index.mjs CHANGED
@@ -859,40 +859,140 @@ var dashboardService = {
859
859
  if (hasOutputHourlyData) {
860
860
  console.log("Using new output_hourly column for workspace:", data.workspace_name);
861
861
  console.log("Raw output_hourly data:", outputHourly);
862
- const isNightShift = data.shift_id === 1;
863
- const shiftStart = data.shift_start || (isNightShift ? "22:00" : "06:00");
864
- const shiftEnd = data.shift_end || (isNightShift ? "06:00" : "14:00");
862
+ const isNightShift = data.shift_id === (shiftConfig.nightShift?.id ?? 1);
863
+ const shiftStart = data.shift_start || (isNightShift ? shiftConfig.nightShift?.startTime || "22:00" : shiftConfig.dayShift?.startTime || "06:00");
864
+ const shiftEnd = data.shift_end || (isNightShift ? shiftConfig.nightShift?.endTime || "06:00" : shiftConfig.dayShift?.endTime || "14:00");
865
865
  const startHour = parseInt(shiftStart.split(":")[0]);
866
866
  const startMinute = parseInt(shiftStart.split(":")[1] || "0");
867
867
  const endHour = parseInt(shiftEnd.split(":")[0]);
868
868
  const endMinute = parseInt(shiftEnd.split(":")[1] || "0");
869
869
  let shiftDuration = endHour - startHour;
870
- if (endMinute > startMinute) {
871
- shiftDuration += 1;
872
- }
873
870
  if (shiftDuration <= 0) {
874
871
  shiftDuration += 24;
875
872
  }
873
+ const hasPartialLastHour = endMinute > 0 && endMinute < 60;
874
+ const hourCount = hasPartialLastHour ? Math.ceil(shiftDuration + endMinute / 60) : shiftDuration;
876
875
  let expectedHours = [];
877
- for (let i = 0; i < shiftDuration; i++) {
876
+ for (let i = 0; i < hourCount; i++) {
878
877
  expectedHours.push((startHour + i) % 24);
879
878
  }
880
879
  console.log("Expected shift hours:", expectedHours);
881
880
  console.log("Available data hours:", Object.keys(outputHourly));
882
- hourlyActionCounts = expectedHours.map((expectedHour) => {
883
- let hourData = outputHourly[expectedHour.toString()];
884
- if (!hourData && isNightShift) {
885
- for (const [storedHour, data2] of Object.entries(outputHourly)) {
886
- if (Array.isArray(data2) && data2.length > 0 && data2.some((val) => val > 0)) {
887
- if (storedHour === "18" && expectedHour === 1) {
888
- hourData = data2;
889
- console.log(`Mapping stored hour ${storedHour} to expected hour ${expectedHour}`);
890
- break;
881
+ hourlyActionCounts = expectedHours.map((expectedHour, index) => {
882
+ let hourSum = 0;
883
+ const hourData = outputHourly[expectedHour.toString()] || [];
884
+ if (startMinute > 0) {
885
+ if (index === 0) {
886
+ if (Array.isArray(hourData)) {
887
+ for (let i = startMinute; i < hourData.length; i++) {
888
+ const val = hourData[i];
889
+ if (val !== "x" && typeof val === "number") {
890
+ hourSum += val;
891
+ }
892
+ }
893
+ }
894
+ const nextHour = (expectedHour + 1) % 24;
895
+ const nextHourData = outputHourly[nextHour.toString()] || [];
896
+ if (Array.isArray(nextHourData)) {
897
+ for (let i = 0; i < startMinute && i < nextHourData.length; i++) {
898
+ const val = nextHourData[i];
899
+ if (val !== "x" && typeof val === "number") {
900
+ hourSum += val;
901
+ }
902
+ }
903
+ }
904
+ } else if (index < expectedHours.length - 1) {
905
+ if (Array.isArray(hourData)) {
906
+ for (let i = startMinute; i < hourData.length; i++) {
907
+ const val = hourData[i];
908
+ if (val !== "x" && typeof val === "number") {
909
+ hourSum += val;
910
+ }
911
+ }
912
+ }
913
+ const nextHour = (expectedHour + 1) % 24;
914
+ const nextHourData = outputHourly[nextHour.toString()] || [];
915
+ if (Array.isArray(nextHourData)) {
916
+ for (let i = 0; i < startMinute && i < nextHourData.length; i++) {
917
+ const val = nextHourData[i];
918
+ if (val !== "x" && typeof val === "number") {
919
+ hourSum += val;
920
+ }
921
+ }
922
+ }
923
+ } else {
924
+ if (hasPartialLastHour && endMinute > 0) {
925
+ if (startMinute > 0) {
926
+ if (Array.isArray(hourData)) {
927
+ for (let i = startMinute; i < hourData.length; i++) {
928
+ const val = hourData[i];
929
+ if (val !== "x" && typeof val === "number") {
930
+ hourSum += val;
931
+ }
932
+ }
933
+ }
934
+ const nextHour = (expectedHour + 1) % 24;
935
+ const nextHourData = outputHourly[nextHour.toString()] || [];
936
+ if (Array.isArray(nextHourData)) {
937
+ for (let i = 0; i < endMinute && i < nextHourData.length; i++) {
938
+ const val = nextHourData[i];
939
+ if (val !== "x" && typeof val === "number") {
940
+ hourSum += val;
941
+ }
942
+ }
943
+ }
944
+ } else {
945
+ if (Array.isArray(hourData)) {
946
+ for (let i = 0; i < endMinute && i < hourData.length; i++) {
947
+ const val = hourData[i];
948
+ if (val !== "x" && typeof val === "number") {
949
+ hourSum += val;
950
+ }
951
+ }
952
+ }
953
+ }
954
+ } else {
955
+ if (Array.isArray(hourData)) {
956
+ for (let i = startMinute; i < hourData.length; i++) {
957
+ const val = hourData[i];
958
+ if (val !== "x" && typeof val === "number") {
959
+ hourSum += val;
960
+ }
961
+ }
962
+ }
963
+ const nextHour = (expectedHour + 1) % 24;
964
+ const nextHourData = outputHourly[nextHour.toString()] || [];
965
+ if (Array.isArray(nextHourData)) {
966
+ for (let i = 0; i < startMinute && i < nextHourData.length; i++) {
967
+ const val = nextHourData[i];
968
+ if (val !== "x" && typeof val === "number") {
969
+ hourSum += val;
970
+ }
971
+ }
972
+ }
973
+ }
974
+ }
975
+ } else {
976
+ if (Array.isArray(hourData)) {
977
+ hourData.forEach((val) => {
978
+ if (val !== "x" && typeof val === "number") {
979
+ hourSum += val;
980
+ }
981
+ });
982
+ }
983
+ if (index === expectedHours.length - 1 && hasPartialLastHour && endMinute > 0) {
984
+ hourSum = 0;
985
+ if (Array.isArray(hourData)) {
986
+ for (let i = 0; i < endMinute && i < hourData.length; i++) {
987
+ const val = hourData[i];
988
+ if (val !== "x" && typeof val === "number") {
989
+ hourSum += val;
990
+ }
891
991
  }
892
992
  }
893
993
  }
894
994
  }
895
- return Array.isArray(hourData) ? hourData.reduce((sum, count) => sum + (count || 0), 0) : 0;
995
+ return hourSum;
896
996
  });
897
997
  console.log("Final hourly action counts:", hourlyActionCounts);
898
998
  } else {
@@ -2093,136 +2193,142 @@ var WorkspaceHealthService = class _WorkspaceHealthService {
2093
2193
  const now2 = /* @__PURE__ */ new Date();
2094
2194
  const currentHour = now2.getHours();
2095
2195
  const currentMinute = now2.getMinutes();
2096
- let shiftStartHour;
2097
- let shiftEndHour;
2196
+ const dayShiftStart = shiftConfig?.dayShift?.startTime || "08:00";
2197
+ const dayShiftEnd = shiftConfig?.dayShift?.endTime || "19:30";
2198
+ const nightShiftStart = shiftConfig?.nightShift?.startTime || "19:30";
2199
+ const nightShiftEnd = shiftConfig?.nightShift?.endTime || "06:00";
2200
+ const parseShiftTime = (timeStr) => {
2201
+ const [hour, minute] = timeStr.split(":").map(Number);
2202
+ return { hour, minute };
2203
+ };
2204
+ let shiftStart, shiftEnd;
2098
2205
  if (currentShiftId === 0) {
2099
- shiftStartHour = 9;
2100
- shiftEndHour = 18;
2206
+ shiftStart = parseShiftTime(dayShiftStart);
2207
+ shiftEnd = parseShiftTime(dayShiftEnd);
2101
2208
  } else {
2102
- shiftStartHour = 20;
2103
- shiftEndHour = 3;
2209
+ shiftStart = parseShiftTime(nightShiftStart);
2210
+ shiftEnd = parseShiftTime(nightShiftEnd);
2104
2211
  }
2105
2212
  let elapsedMinutes = 0;
2106
2213
  if (currentShiftId === 0) {
2107
- if (currentHour >= shiftStartHour && currentHour < shiftEndHour) {
2108
- elapsedMinutes = (currentHour - shiftStartHour) * 60 + currentMinute;
2109
- } else if (currentHour >= shiftEndHour) {
2110
- elapsedMinutes = (shiftEndHour - shiftStartHour) * 60;
2214
+ const shiftStartTotalMinutes = shiftStart.hour * 60 + shiftStart.minute;
2215
+ const currentTotalMinutes = currentHour * 60 + currentMinute;
2216
+ const shiftEndTotalMinutes = shiftEnd.hour * 60 + shiftEnd.minute;
2217
+ if (currentTotalMinutes >= shiftStartTotalMinutes && currentTotalMinutes < shiftEndTotalMinutes) {
2218
+ elapsedMinutes = currentTotalMinutes - shiftStartTotalMinutes;
2219
+ } else if (currentTotalMinutes >= shiftEndTotalMinutes) {
2220
+ elapsedMinutes = shiftEndTotalMinutes - shiftStartTotalMinutes;
2111
2221
  }
2112
2222
  } else {
2113
- if (currentHour >= shiftStartHour) {
2114
- elapsedMinutes = (currentHour - shiftStartHour) * 60 + currentMinute;
2115
- } else if (currentHour < shiftEndHour) {
2116
- elapsedMinutes = (24 - shiftStartHour + currentHour) * 60 + currentMinute;
2223
+ const shiftStartTotalMinutes = shiftStart.hour * 60 + shiftStart.minute;
2224
+ const currentTotalMinutes = currentHour * 60 + currentMinute;
2225
+ const shiftEndTotalMinutes = shiftEnd.hour * 60 + shiftEnd.minute;
2226
+ if (currentHour >= shiftStart.hour || currentHour < shiftEnd.hour) {
2227
+ if (currentHour >= shiftStart.hour) {
2228
+ elapsedMinutes = currentTotalMinutes - shiftStartTotalMinutes;
2229
+ } else {
2230
+ elapsedMinutes = 24 * 60 - shiftStartTotalMinutes + currentTotalMinutes;
2231
+ }
2232
+ if (currentHour >= shiftEnd.hour && currentTotalMinutes >= shiftEndTotalMinutes) {
2233
+ const totalShiftMinutes = 24 * 60 - shiftStartTotalMinutes + shiftEndTotalMinutes;
2234
+ elapsedMinutes = Math.min(elapsedMinutes, totalShiftMinutes);
2235
+ }
2117
2236
  }
2118
2237
  }
2119
2238
  const tableName = `performance_metrics_${companyId.replace(/-/g, "_")}`;
2120
- const query = `
2121
- WITH workspace_uptime AS (
2122
- SELECT
2123
- workspace_id,
2124
- workspace_display_name,
2125
- idle_time_hourly,
2126
- output_hourly,
2127
- shift_start,
2128
- shift_end
2129
- FROM ${tableName}
2130
- WHERE date = $1::date
2131
- AND shift_id = $2
2132
- ),
2133
- calculated_uptime AS (
2134
- SELECT
2135
- workspace_id,
2136
- workspace_display_name,
2137
- -- Calculate actual minutes from hourly data
2138
- (
2139
- SELECT COALESCE(SUM(
2140
- CASE
2141
- WHEN jsonb_array_length(idle_time_hourly->key::text) >= 58 THEN 60
2142
- WHEN jsonb_array_length(idle_time_hourly->key::text) > 0 THEN jsonb_array_length(idle_time_hourly->key::text)
2143
- ELSE 0
2144
- END
2145
- ), 0)
2146
- FROM jsonb_object_keys(idle_time_hourly) AS key
2147
- WHERE key::int >= $3 AND key::int < $4
2148
- ) +
2149
- -- Add current hour's data if applicable
2150
- CASE
2151
- WHEN $4::int >= $3 AND $4::int < $5 THEN
2152
- LEAST($6::int,
2153
- COALESCE(jsonb_array_length(idle_time_hourly->$4::text), 0))
2154
- ELSE 0
2155
- END as actual_minutes
2156
- FROM workspace_uptime
2157
- )
2158
- SELECT
2159
- workspace_id,
2160
- workspace_display_name,
2161
- actual_minutes,
2162
- $7::int as expected_minutes,
2163
- ROUND(
2164
- CASE
2165
- WHEN $7::int > 0 THEN (actual_minutes::numeric / $7::numeric) * 100
2166
- ELSE 100
2167
- END, 1
2168
- ) as uptime_percentage
2169
- FROM calculated_uptime
2170
- `;
2171
2239
  try {
2172
- const { data, error } = await supabase.rpc("sql_query", {
2173
- query_text: query,
2174
- params: [
2175
- currentDate,
2176
- currentShiftId,
2177
- shiftStartHour,
2178
- currentHour,
2179
- shiftEndHour,
2180
- currentMinute,
2181
- elapsedMinutes
2182
- ]
2183
- }).single();
2240
+ const { data: queryData, error } = await supabase.from(tableName).select("workspace_id, workspace_display_name, output_hourly").eq("date", currentDate).eq("shift_id", currentShiftId);
2184
2241
  if (error) {
2185
- const { data: queryData, error: queryError } = await supabase.from(tableName).select("workspace_id, workspace_display_name, idle_time_hourly, output_hourly").eq("date", currentDate).eq("shift_id", currentShiftId);
2186
- if (queryError) {
2187
- console.error("Error fetching performance metrics:", queryError);
2188
- return /* @__PURE__ */ new Map();
2189
- }
2190
- const uptimeMap2 = /* @__PURE__ */ new Map();
2191
- for (const record of queryData || []) {
2192
- let actualMinutes = 0;
2193
- const idleTimeHourly = record.idle_time_hourly || {};
2194
- if (idleTimeHourly && typeof idleTimeHourly === "object") {
2195
- for (const [hour, dataArray] of Object.entries(idleTimeHourly)) {
2196
- const hourNum = parseInt(hour);
2197
- if (hourNum >= shiftStartHour && hourNum < currentHour) {
2198
- const arrayLength = Array.isArray(dataArray) ? dataArray.length : 0;
2199
- actualMinutes += arrayLength >= 58 ? 60 : arrayLength;
2200
- } else if (hourNum === currentHour && currentHour >= shiftStartHour) {
2201
- const arrayLength = Array.isArray(dataArray) ? dataArray.length : 0;
2202
- actualMinutes += Math.min(currentMinute, arrayLength);
2242
+ console.error("Error fetching performance metrics:", error);
2243
+ return /* @__PURE__ */ new Map();
2244
+ }
2245
+ const uptimeMap = /* @__PURE__ */ new Map();
2246
+ for (const record of queryData || []) {
2247
+ let actualMinutes = 0;
2248
+ let totalPossibleMinutes = 0;
2249
+ const outputHourly = record.output_hourly || {};
2250
+ const hoursElapsed = Math.ceil(elapsedMinutes / 60);
2251
+ for (let hourIndex = 0; hourIndex < hoursElapsed; hourIndex++) {
2252
+ const actualHour = (shiftStart.hour + hourIndex) % 24;
2253
+ let hourData = [];
2254
+ let minutesInThisHour = 60;
2255
+ if (shiftStart.minute > 0) {
2256
+ if (hourIndex === 0) {
2257
+ const firstHourData = outputHourly[actualHour.toString()] || [];
2258
+ const nextHour = (actualHour + 1) % 24;
2259
+ const nextHourData = outputHourly[nextHour.toString()] || [];
2260
+ hourData = [
2261
+ ...Array.isArray(firstHourData) ? firstHourData.slice(shiftStart.minute) : [],
2262
+ ...Array.isArray(nextHourData) ? nextHourData.slice(0, shiftStart.minute) : []
2263
+ ];
2264
+ } else if (hourIndex < hoursElapsed - 1) {
2265
+ const currentHourData = outputHourly[actualHour.toString()] || [];
2266
+ const nextHour = (actualHour + 1) % 24;
2267
+ const nextHourData = outputHourly[nextHour.toString()] || [];
2268
+ hourData = [
2269
+ ...Array.isArray(currentHourData) ? currentHourData.slice(shiftStart.minute) : [],
2270
+ ...Array.isArray(nextHourData) ? nextHourData.slice(0, shiftStart.minute) : []
2271
+ ];
2272
+ } else {
2273
+ const isLastHourPartial = hourIndex === hoursElapsed - 1 && elapsedMinutes % 60 > 0;
2274
+ if (isLastHourPartial) {
2275
+ minutesInThisHour = elapsedMinutes % 60;
2276
+ const currentHourData = outputHourly[actualHour.toString()] || [];
2277
+ if (shiftStart.minute > 0) {
2278
+ const nextHour = (actualHour + 1) % 24;
2279
+ const nextHourData = outputHourly[nextHour.toString()] || [];
2280
+ const firstPart = Array.isArray(currentHourData) ? currentHourData.slice(shiftStart.minute) : [];
2281
+ const secondPart = Array.isArray(nextHourData) ? nextHourData.slice(0, Math.min(shiftStart.minute, minutesInThisHour)) : [];
2282
+ hourData = [...firstPart, ...secondPart].slice(0, minutesInThisHour);
2283
+ } else {
2284
+ hourData = Array.isArray(currentHourData) ? currentHourData.slice(0, minutesInThisHour) : [];
2285
+ }
2286
+ } else {
2287
+ const currentHourData = outputHourly[actualHour.toString()] || [];
2288
+ const nextHour = (actualHour + 1) % 24;
2289
+ const nextHourData = outputHourly[nextHour.toString()] || [];
2290
+ hourData = [
2291
+ ...Array.isArray(currentHourData) ? currentHourData.slice(shiftStart.minute) : [],
2292
+ ...Array.isArray(nextHourData) ? nextHourData.slice(0, shiftStart.minute) : []
2293
+ ];
2294
+ }
2295
+ }
2296
+ } else {
2297
+ hourData = outputHourly[actualHour.toString()] || [];
2298
+ if (hourIndex === hoursElapsed - 1) {
2299
+ const remainingMinutes = elapsedMinutes % 60;
2300
+ if (remainingMinutes > 0) {
2301
+ minutesInThisHour = remainingMinutes;
2302
+ hourData = Array.isArray(hourData) ? hourData.slice(0, minutesInThisHour) : [];
2203
2303
  }
2204
2304
  }
2205
2305
  }
2206
- const percentage = elapsedMinutes > 0 ? Math.round(actualMinutes / elapsedMinutes * 1e3) / 10 : 100;
2207
- uptimeMap2.set(record.workspace_id, {
2208
- expectedMinutes: elapsedMinutes,
2209
- actualMinutes,
2210
- percentage,
2211
- lastCalculated: (/* @__PURE__ */ new Date()).toISOString()
2212
- });
2213
- }
2214
- return uptimeMap2;
2215
- }
2216
- const uptimeMap = /* @__PURE__ */ new Map();
2217
- if (Array.isArray(data)) {
2218
- for (const record of data) {
2219
- uptimeMap.set(record.workspace_id, {
2220
- expectedMinutes: record.expected_minutes,
2221
- actualMinutes: record.actual_minutes,
2222
- percentage: record.uptime_percentage,
2223
- lastCalculated: (/* @__PURE__ */ new Date()).toISOString()
2224
- });
2306
+ const hasXArchitecture = Array.isArray(hourData) && hourData.some((val) => val === "x");
2307
+ if (hasXArchitecture) {
2308
+ const xCount = hourData.filter((val) => val === "x").length;
2309
+ if (xCount <= 2) {
2310
+ actualMinutes += minutesInThisHour;
2311
+ } else {
2312
+ const uptimeCount = hourData.filter((val) => val !== "x").length;
2313
+ actualMinutes += Math.min(uptimeCount, minutesInThisHour);
2314
+ }
2315
+ } else {
2316
+ const arrayLength = Array.isArray(hourData) ? hourData.length : 0;
2317
+ if (arrayLength >= Math.min(58, minutesInThisHour - 2)) {
2318
+ actualMinutes += minutesInThisHour;
2319
+ } else {
2320
+ actualMinutes += Math.min(arrayLength, minutesInThisHour);
2321
+ }
2322
+ }
2323
+ totalPossibleMinutes += minutesInThisHour;
2225
2324
  }
2325
+ const percentage = totalPossibleMinutes > 0 ? Math.round(actualMinutes / totalPossibleMinutes * 1e3) / 10 : 100;
2326
+ uptimeMap.set(record.workspace_id, {
2327
+ expectedMinutes: totalPossibleMinutes,
2328
+ actualMinutes,
2329
+ percentage,
2330
+ lastCalculated: (/* @__PURE__ */ new Date()).toISOString()
2331
+ });
2226
2332
  }
2227
2333
  return uptimeMap;
2228
2334
  } catch (error) {
@@ -5673,39 +5779,139 @@ var useWorkspaceDetailedMetrics = (workspaceId, date, shiftId) => {
5673
5779
  console.log("Using new output_hourly column for workspace (fallback):", recentData.workspace_name);
5674
5780
  console.log("Raw output_hourly data (fallback):", outputHourly2);
5675
5781
  const isNightShift = recentData.shift_id === 1;
5676
- const shiftStart = recentData.shift_start || (isNightShift ? "22:00" : "06:00");
5677
- const shiftEnd = recentData.shift_end || (isNightShift ? "06:00" : "14:00");
5782
+ const shiftStart = recentData.shift_start || (isNightShift ? shiftConfig.nightShift?.startTime || "22:00" : shiftConfig.dayShift?.startTime || "06:00");
5783
+ const shiftEnd = recentData.shift_end || (isNightShift ? shiftConfig.nightShift?.endTime || "06:00" : shiftConfig.dayShift?.endTime || "14:00");
5678
5784
  const startHour = parseInt(shiftStart.split(":")[0]);
5679
5785
  const startMinute = parseInt(shiftStart.split(":")[1] || "0");
5680
5786
  const endHour = parseInt(shiftEnd.split(":")[0]);
5681
5787
  const endMinute = parseInt(shiftEnd.split(":")[1] || "0");
5682
5788
  let shiftDuration = endHour - startHour;
5683
- if (endMinute > startMinute) {
5684
- shiftDuration += 1;
5685
- }
5686
5789
  if (shiftDuration <= 0) {
5687
5790
  shiftDuration += 24;
5688
5791
  }
5792
+ const hasPartialLastHour = endMinute > 0 && endMinute < 60;
5793
+ const hourCount = hasPartialLastHour ? Math.ceil(shiftDuration + endMinute / 60) : shiftDuration;
5689
5794
  let expectedHours = [];
5690
- for (let i = 0; i < shiftDuration; i++) {
5795
+ for (let i = 0; i < hourCount; i++) {
5691
5796
  expectedHours.push((startHour + i) % 24);
5692
5797
  }
5693
5798
  console.log("Expected shift hours (fallback):", expectedHours);
5694
5799
  console.log("Available data hours (fallback):", Object.keys(outputHourly2));
5695
- hourlyActionCounts2 = expectedHours.map((expectedHour) => {
5696
- let hourData = outputHourly2[expectedHour.toString()];
5697
- if (!hourData && isNightShift) {
5698
- for (const [storedHour, data2] of Object.entries(outputHourly2)) {
5699
- if (Array.isArray(data2) && data2.length > 0 && data2.some((val) => val > 0)) {
5700
- if (storedHour === "18" && expectedHour === 1) {
5701
- hourData = data2;
5702
- console.log(`Mapping stored hour ${storedHour} to expected hour ${expectedHour} (fallback)`);
5703
- break;
5800
+ hourlyActionCounts2 = expectedHours.map((expectedHour, index) => {
5801
+ let hourSum = 0;
5802
+ const hourData = outputHourly2[expectedHour.toString()] || [];
5803
+ if (startMinute > 0) {
5804
+ if (index === 0) {
5805
+ if (Array.isArray(hourData)) {
5806
+ for (let i = startMinute; i < hourData.length; i++) {
5807
+ const val = hourData[i];
5808
+ if (val !== "x" && typeof val === "number") {
5809
+ hourSum += val;
5810
+ }
5811
+ }
5812
+ }
5813
+ const nextHour = (expectedHour + 1) % 24;
5814
+ const nextHourData = outputHourly2[nextHour.toString()] || [];
5815
+ if (Array.isArray(nextHourData)) {
5816
+ for (let i = 0; i < startMinute && i < nextHourData.length; i++) {
5817
+ const val = nextHourData[i];
5818
+ if (val !== "x" && typeof val === "number") {
5819
+ hourSum += val;
5820
+ }
5821
+ }
5822
+ }
5823
+ } else if (index < expectedHours.length - 1) {
5824
+ if (Array.isArray(hourData)) {
5825
+ for (let i = startMinute; i < hourData.length; i++) {
5826
+ const val = hourData[i];
5827
+ if (val !== "x" && typeof val === "number") {
5828
+ hourSum += val;
5829
+ }
5830
+ }
5831
+ }
5832
+ const nextHour = (expectedHour + 1) % 24;
5833
+ const nextHourData = outputHourly2[nextHour.toString()] || [];
5834
+ if (Array.isArray(nextHourData)) {
5835
+ for (let i = 0; i < startMinute && i < nextHourData.length; i++) {
5836
+ const val = nextHourData[i];
5837
+ if (val !== "x" && typeof val === "number") {
5838
+ hourSum += val;
5839
+ }
5840
+ }
5841
+ }
5842
+ } else {
5843
+ if (hasPartialLastHour && endMinute > 0) {
5844
+ if (startMinute > 0) {
5845
+ if (Array.isArray(hourData)) {
5846
+ for (let i = startMinute; i < hourData.length; i++) {
5847
+ const val = hourData[i];
5848
+ if (val !== "x" && typeof val === "number") {
5849
+ hourSum += val;
5850
+ }
5851
+ }
5852
+ }
5853
+ const nextHour = (expectedHour + 1) % 24;
5854
+ const nextHourData = outputHourly2[nextHour.toString()] || [];
5855
+ if (Array.isArray(nextHourData)) {
5856
+ for (let i = 0; i < endMinute && i < nextHourData.length; i++) {
5857
+ const val = nextHourData[i];
5858
+ if (val !== "x" && typeof val === "number") {
5859
+ hourSum += val;
5860
+ }
5861
+ }
5862
+ }
5863
+ } else {
5864
+ if (Array.isArray(hourData)) {
5865
+ for (let i = 0; i < endMinute && i < hourData.length; i++) {
5866
+ const val = hourData[i];
5867
+ if (val !== "x" && typeof val === "number") {
5868
+ hourSum += val;
5869
+ }
5870
+ }
5871
+ }
5872
+ }
5873
+ } else {
5874
+ if (Array.isArray(hourData)) {
5875
+ for (let i = startMinute; i < hourData.length; i++) {
5876
+ const val = hourData[i];
5877
+ if (val !== "x" && typeof val === "number") {
5878
+ hourSum += val;
5879
+ }
5880
+ }
5881
+ }
5882
+ const nextHour = (expectedHour + 1) % 24;
5883
+ const nextHourData = outputHourly2[nextHour.toString()] || [];
5884
+ if (Array.isArray(nextHourData)) {
5885
+ for (let i = 0; i < startMinute && i < nextHourData.length; i++) {
5886
+ const val = nextHourData[i];
5887
+ if (val !== "x" && typeof val === "number") {
5888
+ hourSum += val;
5889
+ }
5890
+ }
5891
+ }
5892
+ }
5893
+ }
5894
+ } else {
5895
+ if (Array.isArray(hourData)) {
5896
+ hourData.forEach((val) => {
5897
+ if (val !== "x" && typeof val === "number") {
5898
+ hourSum += val;
5899
+ }
5900
+ });
5901
+ }
5902
+ if (index === expectedHours.length - 1 && hasPartialLastHour && endMinute > 0) {
5903
+ hourSum = 0;
5904
+ if (Array.isArray(hourData)) {
5905
+ for (let i = 0; i < endMinute && i < hourData.length; i++) {
5906
+ const val = hourData[i];
5907
+ if (val !== "x" && typeof val === "number") {
5908
+ hourSum += val;
5909
+ }
5704
5910
  }
5705
5911
  }
5706
5912
  }
5707
5913
  }
5708
- return Array.isArray(hourData) ? hourData.reduce((sum, count) => sum + (count || 0), 0) : 0;
5914
+ return hourSum;
5709
5915
  });
5710
5916
  console.log("Final hourly action counts (fallback):", hourlyActionCounts2);
5711
5917
  } else {
@@ -5732,8 +5938,8 @@ var useWorkspaceDetailedMetrics = (workspaceId, date, shiftId) => {
5732
5938
  date: recentData.date,
5733
5939
  shift_id: recentData.shift_id,
5734
5940
  action_name: recentData.action_name || "",
5735
- shift_start: recentData.shift_start || "06:00",
5736
- shift_end: recentData.shift_end || "14:00",
5941
+ shift_start: recentData.shift_start || (recentData.shift_id === 1 ? shiftConfig.nightShift?.startTime || "22:00" : shiftConfig.dayShift?.startTime || "06:00"),
5942
+ shift_end: recentData.shift_end || (recentData.shift_id === 1 ? shiftConfig.nightShift?.endTime || "06:00" : shiftConfig.dayShift?.endTime || "14:00"),
5737
5943
  shift_type: recentData.shift_type || (recentData.shift_id === 0 ? "Day" : "Night"),
5738
5944
  pph_threshold: recentData.pph_threshold || 0,
5739
5945
  target_output: recentData.total_day_output || 0,
@@ -5789,39 +5995,139 @@ var useWorkspaceDetailedMetrics = (workspaceId, date, shiftId) => {
5789
5995
  console.log("\u2705 Using new output_hourly column for workspace:", data.workspace_name);
5790
5996
  console.log("Raw output_hourly data:", JSON.stringify(outputHourly));
5791
5997
  const isNightShift = data.shift_id === 1;
5792
- const shiftStart = data.shift_start || (isNightShift ? "22:00" : "06:00");
5793
- const shiftEnd = data.shift_end || (isNightShift ? "06:00" : "14:00");
5998
+ const shiftStart = data.shift_start || (isNightShift ? shiftConfig.nightShift?.startTime || "22:00" : shiftConfig.dayShift?.startTime || "06:00");
5999
+ const shiftEnd = data.shift_end || (isNightShift ? shiftConfig.nightShift?.endTime || "06:00" : shiftConfig.dayShift?.endTime || "14:00");
5794
6000
  const startHour = parseInt(shiftStart.split(":")[0]);
5795
6001
  const startMinute = parseInt(shiftStart.split(":")[1] || "0");
5796
6002
  const endHour = parseInt(shiftEnd.split(":")[0]);
5797
6003
  const endMinute = parseInt(shiftEnd.split(":")[1] || "0");
5798
6004
  let shiftDuration = endHour - startHour;
5799
- if (endMinute > startMinute) {
5800
- shiftDuration += 1;
5801
- }
5802
6005
  if (shiftDuration <= 0) {
5803
6006
  shiftDuration += 24;
5804
6007
  }
6008
+ const hasPartialLastHour = endMinute > 0 && endMinute < 60;
6009
+ const hourCount = hasPartialLastHour ? Math.ceil(shiftDuration + endMinute / 60) : shiftDuration;
5805
6010
  let expectedHours = [];
5806
- for (let i = 0; i < shiftDuration; i++) {
6011
+ for (let i = 0; i < hourCount; i++) {
5807
6012
  expectedHours.push((startHour + i) % 24);
5808
6013
  }
5809
6014
  console.log("Expected shift hours:", expectedHours);
5810
6015
  console.log("Available data hours:", Object.keys(outputHourly));
5811
- hourlyActionCounts = expectedHours.map((expectedHour) => {
5812
- let hourData = outputHourly[expectedHour.toString()];
5813
- if (!hourData && isNightShift) {
5814
- for (const [storedHour, data2] of Object.entries(outputHourly)) {
5815
- if (Array.isArray(data2) && data2.length > 0 && data2.some((val) => val > 0)) {
5816
- if (storedHour === "18" && expectedHour === 1) {
5817
- hourData = data2;
5818
- console.log(`Mapping stored hour ${storedHour} to expected hour ${expectedHour}`);
5819
- break;
6016
+ hourlyActionCounts = expectedHours.map((expectedHour, index) => {
6017
+ let hourSum = 0;
6018
+ const hourData = outputHourly[expectedHour.toString()] || [];
6019
+ if (startMinute > 0) {
6020
+ if (index === 0) {
6021
+ if (Array.isArray(hourData)) {
6022
+ for (let i = startMinute; i < hourData.length; i++) {
6023
+ const val = hourData[i];
6024
+ if (val !== "x" && typeof val === "number") {
6025
+ hourSum += val;
6026
+ }
6027
+ }
6028
+ }
6029
+ const nextHour = (expectedHour + 1) % 24;
6030
+ const nextHourData = outputHourly[nextHour.toString()] || [];
6031
+ if (Array.isArray(nextHourData)) {
6032
+ for (let i = 0; i < startMinute && i < nextHourData.length; i++) {
6033
+ const val = nextHourData[i];
6034
+ if (val !== "x" && typeof val === "number") {
6035
+ hourSum += val;
6036
+ }
6037
+ }
6038
+ }
6039
+ } else if (index < expectedHours.length - 1) {
6040
+ if (Array.isArray(hourData)) {
6041
+ for (let i = startMinute; i < hourData.length; i++) {
6042
+ const val = hourData[i];
6043
+ if (val !== "x" && typeof val === "number") {
6044
+ hourSum += val;
6045
+ }
6046
+ }
6047
+ }
6048
+ const nextHour = (expectedHour + 1) % 24;
6049
+ const nextHourData = outputHourly[nextHour.toString()] || [];
6050
+ if (Array.isArray(nextHourData)) {
6051
+ for (let i = 0; i < startMinute && i < nextHourData.length; i++) {
6052
+ const val = nextHourData[i];
6053
+ if (val !== "x" && typeof val === "number") {
6054
+ hourSum += val;
6055
+ }
6056
+ }
6057
+ }
6058
+ } else {
6059
+ if (hasPartialLastHour && endMinute > 0) {
6060
+ if (startMinute > 0) {
6061
+ if (Array.isArray(hourData)) {
6062
+ for (let i = startMinute; i < hourData.length; i++) {
6063
+ const val = hourData[i];
6064
+ if (val !== "x" && typeof val === "number") {
6065
+ hourSum += val;
6066
+ }
6067
+ }
6068
+ }
6069
+ const nextHour = (expectedHour + 1) % 24;
6070
+ const nextHourData = outputHourly[nextHour.toString()] || [];
6071
+ if (Array.isArray(nextHourData)) {
6072
+ for (let i = 0; i < endMinute && i < nextHourData.length; i++) {
6073
+ const val = nextHourData[i];
6074
+ if (val !== "x" && typeof val === "number") {
6075
+ hourSum += val;
6076
+ }
6077
+ }
6078
+ }
6079
+ } else {
6080
+ if (Array.isArray(hourData)) {
6081
+ for (let i = 0; i < endMinute && i < hourData.length; i++) {
6082
+ const val = hourData[i];
6083
+ if (val !== "x" && typeof val === "number") {
6084
+ hourSum += val;
6085
+ }
6086
+ }
6087
+ }
6088
+ }
6089
+ } else {
6090
+ if (Array.isArray(hourData)) {
6091
+ for (let i = startMinute; i < hourData.length; i++) {
6092
+ const val = hourData[i];
6093
+ if (val !== "x" && typeof val === "number") {
6094
+ hourSum += val;
6095
+ }
6096
+ }
6097
+ }
6098
+ const nextHour = (expectedHour + 1) % 24;
6099
+ const nextHourData = outputHourly[nextHour.toString()] || [];
6100
+ if (Array.isArray(nextHourData)) {
6101
+ for (let i = 0; i < startMinute && i < nextHourData.length; i++) {
6102
+ const val = nextHourData[i];
6103
+ if (val !== "x" && typeof val === "number") {
6104
+ hourSum += val;
6105
+ }
6106
+ }
6107
+ }
6108
+ }
6109
+ }
6110
+ } else {
6111
+ if (Array.isArray(hourData)) {
6112
+ hourData.forEach((val) => {
6113
+ if (val !== "x" && typeof val === "number") {
6114
+ hourSum += val;
6115
+ }
6116
+ });
6117
+ }
6118
+ if (index === expectedHours.length - 1 && hasPartialLastHour && endMinute > 0) {
6119
+ hourSum = 0;
6120
+ if (Array.isArray(hourData)) {
6121
+ for (let i = 0; i < endMinute && i < hourData.length; i++) {
6122
+ const val = hourData[i];
6123
+ if (val !== "x" && typeof val === "number") {
6124
+ hourSum += val;
6125
+ }
5820
6126
  }
5821
6127
  }
5822
6128
  }
5823
6129
  }
5824
- return Array.isArray(hourData) ? hourData.reduce((sum, count) => sum + (count || 0), 0) : 0;
6130
+ return hourSum;
5825
6131
  });
5826
6132
  console.log("Final hourly action counts:", hourlyActionCounts);
5827
6133
  } else {
@@ -5851,8 +6157,8 @@ var useWorkspaceDetailedMetrics = (workspaceId, date, shiftId) => {
5851
6157
  date: data.date,
5852
6158
  shift_id: data.shift_id,
5853
6159
  action_name: data.action_name || "",
5854
- shift_start: data.shift_start || "06:00",
5855
- shift_end: data.shift_end || "14:00",
6160
+ shift_start: data.shift_start || (data.shift_id === 1 ? shiftConfig.nightShift?.startTime || "22:00" : shiftConfig.dayShift?.startTime || "06:00"),
6161
+ shift_end: data.shift_end || (data.shift_id === 1 ? shiftConfig.nightShift?.endTime || "06:00" : shiftConfig.dayShift?.endTime || "14:00"),
5856
6162
  shift_type: data.shift_type || (data.shift_id === 0 ? "Day" : "Night"),
5857
6163
  pph_threshold: data.pph_threshold || 0,
5858
6164
  target_output: data.total_day_output || 0,
@@ -21243,18 +21549,41 @@ var HourlyOutputChartComponent = ({
21243
21549
  return { hour, minute, decimalHour };
21244
21550
  };
21245
21551
  const shiftStartTime = getTimeFromTimeString(shiftStart);
21246
- const calculateShiftDuration = React19__default.useMemo(() => {
21552
+ const { shiftDuration, shiftEndTime, hasPartialLastHour } = React19__default.useMemo(() => {
21553
+ console.log("[HourlyOutputChart] Calculating shift duration with:", {
21554
+ shiftStart,
21555
+ shiftEnd,
21556
+ shiftStartTime
21557
+ });
21247
21558
  if (!shiftEnd) {
21248
- return 11;
21559
+ console.log("[HourlyOutputChart] No shiftEnd provided, using default 11 hours");
21560
+ return {
21561
+ shiftDuration: 11,
21562
+ shiftEndTime: null,
21563
+ hasPartialLastHour: false
21564
+ };
21249
21565
  }
21250
21566
  const endTime = getTimeFromTimeString(shiftEnd);
21251
21567
  let duration = endTime.decimalHour - shiftStartTime.decimalHour;
21252
21568
  if (duration <= 0) {
21253
21569
  duration += 24;
21254
21570
  }
21255
- return Math.round(duration);
21571
+ const hasPartial = endTime.minute > 0 && endTime.minute < 60;
21572
+ const hourCount = hasPartial ? Math.ceil(duration) : Math.round(duration);
21573
+ console.log("[HourlyOutputChart] Shift calculation results:", {
21574
+ endTime,
21575
+ duration,
21576
+ hasPartial,
21577
+ hourCount
21578
+ });
21579
+ return {
21580
+ shiftDuration: hourCount,
21581
+ shiftEndTime: endTime,
21582
+ hasPartialLastHour: hasPartial
21583
+ };
21256
21584
  }, [shiftEnd, shiftStartTime.decimalHour]);
21257
- const SHIFT_DURATION = calculateShiftDuration;
21585
+ const SHIFT_DURATION = shiftDuration;
21586
+ shiftEndTime ? shiftEndTime.hour : (shiftStartTime.hour + SHIFT_DURATION) % 24;
21258
21587
  const [animatedData, setAnimatedData] = React19__default.useState(
21259
21588
  () => Array(SHIFT_DURATION).fill(0)
21260
21589
  );
@@ -21365,12 +21694,19 @@ var HourlyOutputChartComponent = ({
21365
21694
  };
21366
21695
  }, []);
21367
21696
  const formatHour = React19__default.useCallback((hourIndex) => {
21697
+ const isLastHour = hourIndex === SHIFT_DURATION - 1;
21368
21698
  const startDecimalHour = shiftStartTime.decimalHour + hourIndex;
21369
21699
  const startHour = Math.floor(startDecimalHour) % 24;
21370
21700
  const startMinute = Math.round(startDecimalHour % 1 * 60);
21371
- const endDecimalHour = startDecimalHour + 1;
21372
- const endHour = Math.floor(endDecimalHour) % 24;
21373
- const endMinute = Math.round(endDecimalHour % 1 * 60);
21701
+ let endHour, endMinute;
21702
+ if (isLastHour && shiftEndTime) {
21703
+ endHour = shiftEndTime.hour;
21704
+ endMinute = shiftEndTime.minute;
21705
+ } else {
21706
+ const endDecimalHour = startDecimalHour + 1;
21707
+ endHour = Math.floor(endDecimalHour) % 24;
21708
+ endMinute = Math.round(endDecimalHour % 1 * 60);
21709
+ }
21374
21710
  const formatTime3 = (h, m) => {
21375
21711
  const period = h >= 12 ? "PM" : "AM";
21376
21712
  const hour12 = h === 0 ? 12 : h > 12 ? h - 12 : h;
@@ -21380,26 +21716,85 @@ var HourlyOutputChartComponent = ({
21380
21716
  return `${hour12}:${m.toString().padStart(2, "0")}${period}`;
21381
21717
  };
21382
21718
  return `${formatTime3(startHour, startMinute)}-${formatTime3(endHour, endMinute)}`;
21383
- }, [shiftStartTime.decimalHour]);
21719
+ }, [shiftStartTime.decimalHour, SHIFT_DURATION, shiftEndTime]);
21384
21720
  const formatTimeRange = React19__default.useCallback((hourIndex) => {
21721
+ const isLastHour = hourIndex === SHIFT_DURATION - 1;
21385
21722
  const startDecimalHour = shiftStartTime.decimalHour + hourIndex;
21386
21723
  const startHour = Math.floor(startDecimalHour) % 24;
21387
21724
  const startMinute = Math.round(startDecimalHour % 1 * 60);
21388
- const endDecimalHour = startDecimalHour + 1;
21389
- const endHour = Math.floor(endDecimalHour) % 24;
21390
- const endMinute = Math.round(endDecimalHour % 1 * 60);
21725
+ let endHour, endMinute;
21726
+ if (isLastHour && shiftEndTime) {
21727
+ endHour = shiftEndTime.hour;
21728
+ endMinute = shiftEndTime.minute;
21729
+ } else {
21730
+ const endDecimalHour = startDecimalHour + 1;
21731
+ endHour = Math.floor(endDecimalHour) % 24;
21732
+ endMinute = Math.round(endDecimalHour % 1 * 60);
21733
+ }
21391
21734
  const formatTime3 = (h, m) => {
21392
21735
  const period = h >= 12 ? "PM" : "AM";
21393
21736
  const hour12 = h === 0 ? 12 : h > 12 ? h - 12 : h;
21394
21737
  return `${hour12}:${m.toString().padStart(2, "0")} ${period}`;
21395
21738
  };
21396
21739
  return `${formatTime3(startHour, startMinute)} - ${formatTime3(endHour, endMinute)}`;
21397
- }, [shiftStartTime.decimalHour]);
21740
+ }, [shiftStartTime.decimalHour, SHIFT_DURATION, shiftEndTime]);
21398
21741
  const chartData = React19__default.useMemo(() => {
21399
21742
  return Array.from({ length: SHIFT_DURATION }, (_, i) => {
21400
21743
  const actualHour = (shiftStartTime.hour + i) % 24;
21401
- const idleArray = idleTimeHourly?.[actualHour.toString()] || [];
21402
- const idleMinutes = idleArray.filter((val) => val === "1").length;
21744
+ const startMinute = shiftStartTime.minute;
21745
+ let idleArray = [];
21746
+ let idleMinutes = 0;
21747
+ if (idleTimeHourly) {
21748
+ if (startMinute > 0) {
21749
+ if (i === 0) {
21750
+ const firstHourData = idleTimeHourly[actualHour.toString()] || [];
21751
+ const nextHour = (actualHour + 1) % 24;
21752
+ const nextHourData = idleTimeHourly[nextHour.toString()] || [];
21753
+ idleArray = [
21754
+ ...firstHourData.slice(startMinute) || [],
21755
+ ...nextHourData.slice(0, startMinute) || []
21756
+ ];
21757
+ } else if (i < SHIFT_DURATION - 1) {
21758
+ const currentHourData = idleTimeHourly[actualHour.toString()] || [];
21759
+ const nextHour = (actualHour + 1) % 24;
21760
+ const nextHourData = idleTimeHourly[nextHour.toString()] || [];
21761
+ idleArray = [
21762
+ ...currentHourData.slice(startMinute) || [],
21763
+ ...nextHourData.slice(0, startMinute) || []
21764
+ ];
21765
+ } else {
21766
+ const hasPartialLastHour2 = shiftEndTime && shiftEndTime.minute > 0 && shiftEndTime.minute < 60;
21767
+ if (hasPartialLastHour2) {
21768
+ const currentHourData = idleTimeHourly[actualHour.toString()] || [];
21769
+ const nextHour = (actualHour + 1) % 24;
21770
+ const nextHourData = idleTimeHourly[nextHour.toString()] || [];
21771
+ if (startMinute > 0) {
21772
+ const firstPart = currentHourData.slice(startMinute) || [];
21773
+ const secondPart = nextHourData.slice(0, shiftEndTime.minute) || [];
21774
+ idleArray = [...firstPart, ...secondPart];
21775
+ } else {
21776
+ idleArray = currentHourData.slice(0, shiftEndTime.minute) || [];
21777
+ }
21778
+ } else {
21779
+ const currentHourData = idleTimeHourly[actualHour.toString()] || [];
21780
+ const nextHour = (actualHour + 1) % 24;
21781
+ const nextHourData = idleTimeHourly[nextHour.toString()] || [];
21782
+ idleArray = [
21783
+ ...currentHourData.slice(startMinute) || [],
21784
+ ...nextHourData.slice(0, startMinute) || []
21785
+ ];
21786
+ }
21787
+ }
21788
+ } else {
21789
+ const currentHourData = idleTimeHourly[actualHour.toString()] || [];
21790
+ if (i === SHIFT_DURATION - 1 && shiftEndTime && shiftEndTime.minute > 0 && shiftEndTime.minute < 60) {
21791
+ idleArray = currentHourData.slice(0, shiftEndTime.minute) || [];
21792
+ } else {
21793
+ idleArray = currentHourData || [];
21794
+ }
21795
+ }
21796
+ }
21797
+ idleMinutes = idleArray.filter((val) => val === "1" || val === 1).length;
21403
21798
  return {
21404
21799
  hour: formatHour(i),
21405
21800
  timeRange: formatTimeRange(i),
@@ -21411,7 +21806,7 @@ var HourlyOutputChartComponent = ({
21411
21806
  idleArray
21412
21807
  };
21413
21808
  });
21414
- }, [animatedData, data, pphThreshold, idleTimeHourly, shiftStartTime.hour, formatHour, formatTimeRange]);
21809
+ }, [animatedData, data, pphThreshold, idleTimeHourly, shiftStartTime.hour, shiftStartTime.minute, shiftEndTime, formatHour, formatTimeRange, SHIFT_DURATION]);
21415
21810
  const IdleBar = React19__default.useMemo(() => {
21416
21811
  if (!idleBarState.visible) return null;
21417
21812
  return /* @__PURE__ */ jsx(
@@ -21571,13 +21966,13 @@ var HourlyOutputChartComponent = ({
21571
21966
  if (showIdleTime && data2.idleArray) {
21572
21967
  let currentRange = null;
21573
21968
  data2.idleArray.forEach((val, idx) => {
21574
- if (val === "1") {
21969
+ if (val === "1" || val === 1) {
21575
21970
  if (!currentRange) {
21576
21971
  currentRange = { start: idx, end: idx };
21577
21972
  } else {
21578
21973
  currentRange.end = idx;
21579
21974
  }
21580
- } else if (currentRange) {
21975
+ } else if (val !== "x" && currentRange) {
21581
21976
  idleRanges.push(currentRange);
21582
21977
  currentRange = null;
21583
21978
  }
@@ -34119,21 +34514,135 @@ var KPIDetailView = ({
34119
34514
  const shiftStart = metrics2.shift_start || (isNightShift ? "22:00" : "06:00");
34120
34515
  const shiftEnd = metrics2.shift_end || (isNightShift ? "06:00" : "14:00");
34121
34516
  const startHour = parseInt(shiftStart.split(":")[0]);
34517
+ const startMinute = parseInt(shiftStart.split(":")[1] || "0");
34122
34518
  const endHour = parseInt(shiftEnd.split(":")[0]);
34519
+ const endMinute = parseInt(shiftEnd.split(":")[1] || "0");
34123
34520
  let shiftDuration = endHour - startHour;
34124
34521
  if (shiftDuration <= 0) {
34125
34522
  shiftDuration += 24;
34126
34523
  }
34524
+ const hasPartialLastHour = endMinute > 0 && endMinute < 60;
34525
+ const hourCount = hasPartialLastHour ? Math.ceil(shiftDuration + endMinute / 60) : shiftDuration;
34127
34526
  let expectedHours = [];
34128
- for (let i = 0; i < shiftDuration; i++) {
34527
+ for (let i = 0; i < hourCount; i++) {
34129
34528
  expectedHours.push((startHour + i) % 24);
34130
34529
  }
34131
- return expectedHours.map((hour) => {
34132
- const hourData = metrics2.output_hourly[hour.toString()];
34133
- if (hourData && Array.isArray(hourData)) {
34134
- return hourData.reduce((sum, val) => sum + (val || 0), 0);
34530
+ return expectedHours.map((expectedHour, index) => {
34531
+ let hourSum = 0;
34532
+ const outputHourly = metrics2.output_hourly;
34533
+ const hourData = outputHourly[expectedHour.toString()] || [];
34534
+ if (startMinute > 0) {
34535
+ if (index === 0) {
34536
+ if (Array.isArray(hourData)) {
34537
+ for (let i = startMinute; i < hourData.length; i++) {
34538
+ const val = hourData[i];
34539
+ if (val !== "x" && typeof val === "number") {
34540
+ hourSum += val;
34541
+ }
34542
+ }
34543
+ }
34544
+ const nextHour = (expectedHour + 1) % 24;
34545
+ const nextHourData = outputHourly[nextHour.toString()] || [];
34546
+ if (Array.isArray(nextHourData)) {
34547
+ for (let i = 0; i < startMinute && i < nextHourData.length; i++) {
34548
+ const val = nextHourData[i];
34549
+ if (val !== "x" && typeof val === "number") {
34550
+ hourSum += val;
34551
+ }
34552
+ }
34553
+ }
34554
+ } else if (index < expectedHours.length - 1) {
34555
+ if (Array.isArray(hourData)) {
34556
+ for (let i = startMinute; i < hourData.length; i++) {
34557
+ const val = hourData[i];
34558
+ if (val !== "x" && typeof val === "number") {
34559
+ hourSum += val;
34560
+ }
34561
+ }
34562
+ }
34563
+ const nextHour = (expectedHour + 1) % 24;
34564
+ const nextHourData = outputHourly[nextHour.toString()] || [];
34565
+ if (Array.isArray(nextHourData)) {
34566
+ for (let i = 0; i < startMinute && i < nextHourData.length; i++) {
34567
+ const val = nextHourData[i];
34568
+ if (val !== "x" && typeof val === "number") {
34569
+ hourSum += val;
34570
+ }
34571
+ }
34572
+ }
34573
+ } else {
34574
+ if (hasPartialLastHour && endMinute > 0) {
34575
+ if (startMinute > 0) {
34576
+ if (Array.isArray(hourData)) {
34577
+ for (let i = startMinute; i < hourData.length; i++) {
34578
+ const val = hourData[i];
34579
+ if (val !== "x" && typeof val === "number") {
34580
+ hourSum += val;
34581
+ }
34582
+ }
34583
+ }
34584
+ const nextHour = (expectedHour + 1) % 24;
34585
+ const nextHourData = outputHourly[nextHour.toString()] || [];
34586
+ if (Array.isArray(nextHourData)) {
34587
+ for (let i = 0; i < endMinute && i < nextHourData.length; i++) {
34588
+ const val = nextHourData[i];
34589
+ if (val !== "x" && typeof val === "number") {
34590
+ hourSum += val;
34591
+ }
34592
+ }
34593
+ }
34594
+ } else {
34595
+ if (Array.isArray(hourData)) {
34596
+ for (let i = 0; i < endMinute && i < hourData.length; i++) {
34597
+ const val = hourData[i];
34598
+ if (val !== "x" && typeof val === "number") {
34599
+ hourSum += val;
34600
+ }
34601
+ }
34602
+ }
34603
+ }
34604
+ } else {
34605
+ if (Array.isArray(hourData)) {
34606
+ for (let i = startMinute; i < hourData.length; i++) {
34607
+ const val = hourData[i];
34608
+ if (val !== "x" && typeof val === "number") {
34609
+ hourSum += val;
34610
+ }
34611
+ }
34612
+ }
34613
+ const nextHour = (expectedHour + 1) % 24;
34614
+ const nextHourData = outputHourly[nextHour.toString()] || [];
34615
+ if (Array.isArray(nextHourData)) {
34616
+ for (let i = 0; i < startMinute && i < nextHourData.length; i++) {
34617
+ const val = nextHourData[i];
34618
+ if (val !== "x" && typeof val === "number") {
34619
+ hourSum += val;
34620
+ }
34621
+ }
34622
+ }
34623
+ }
34624
+ }
34625
+ } else {
34626
+ if (Array.isArray(hourData)) {
34627
+ hourData.forEach((val) => {
34628
+ if (val !== "x" && typeof val === "number") {
34629
+ hourSum += val;
34630
+ }
34631
+ });
34632
+ }
34633
+ if (index === expectedHours.length - 1 && hasPartialLastHour && endMinute > 0) {
34634
+ hourSum = 0;
34635
+ if (Array.isArray(hourData)) {
34636
+ for (let i = 0; i < endMinute && i < hourData.length; i++) {
34637
+ const val = hourData[i];
34638
+ if (val !== "x" && typeof val === "number") {
34639
+ hourSum += val;
34640
+ }
34641
+ }
34642
+ }
34643
+ }
34135
34644
  }
34136
- return 0;
34645
+ return hourSum;
34137
34646
  });
34138
34647
  }
34139
34648
  if (metrics2.output_array) {