@optifye/dashboard-core 6.3.4 → 6.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +137 -51
- package/dist/index.d.ts +137 -51
- package/dist/index.js +896 -1071
- package/dist/index.mjs +904 -1079
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -424,11 +424,11 @@ var actionService = {
|
|
|
424
424
|
};
|
|
425
425
|
function createMemoizedFunction(fn, getCacheKey) {
|
|
426
426
|
const cache = /* @__PURE__ */ new Map();
|
|
427
|
-
const
|
|
427
|
+
const CACHE_DURATION = 5 * 60 * 1e3;
|
|
428
428
|
return (...args) => {
|
|
429
429
|
const key = getCacheKey(...args);
|
|
430
430
|
const cached = cache.get(key);
|
|
431
|
-
if (cached && Date.now() - cached.timestamp <
|
|
431
|
+
if (cached && Date.now() - cached.timestamp < CACHE_DURATION) {
|
|
432
432
|
return cached.result;
|
|
433
433
|
}
|
|
434
434
|
const result = fn(...args);
|
|
@@ -2479,199 +2479,6 @@ async function deleteThread(threadId) {
|
|
|
2479
2479
|
if (error) throw error;
|
|
2480
2480
|
}
|
|
2481
2481
|
|
|
2482
|
-
// src/lib/services/cacheService.ts
|
|
2483
|
-
var CacheService = class {
|
|
2484
|
-
constructor() {
|
|
2485
|
-
this.memoryCache = /* @__PURE__ */ new Map();
|
|
2486
|
-
this.DEFAULT_DURATION = 5 * 60 * 1e3;
|
|
2487
|
-
}
|
|
2488
|
-
// 5 minutes
|
|
2489
|
-
/**
|
|
2490
|
-
* Generate a cache key from multiple parts
|
|
2491
|
-
*/
|
|
2492
|
-
generateKey(...parts) {
|
|
2493
|
-
return parts.filter((p) => p !== void 0 && p !== null).join(":");
|
|
2494
|
-
}
|
|
2495
|
-
/**
|
|
2496
|
-
* Get item from cache
|
|
2497
|
-
*/
|
|
2498
|
-
get(key, options) {
|
|
2499
|
-
const storage = options?.storage || "memory";
|
|
2500
|
-
try {
|
|
2501
|
-
let cacheItem = null;
|
|
2502
|
-
if (storage === "memory") {
|
|
2503
|
-
cacheItem = this.memoryCache.get(key) || null;
|
|
2504
|
-
} else if (storage === "localStorage" || storage === "sessionStorage") {
|
|
2505
|
-
const stored = window[storage].getItem(key);
|
|
2506
|
-
if (stored) {
|
|
2507
|
-
cacheItem = JSON.parse(stored);
|
|
2508
|
-
}
|
|
2509
|
-
}
|
|
2510
|
-
if (!cacheItem) {
|
|
2511
|
-
return null;
|
|
2512
|
-
}
|
|
2513
|
-
if (Date.now() > cacheItem.expiresAt) {
|
|
2514
|
-
this.delete(key, options);
|
|
2515
|
-
return null;
|
|
2516
|
-
}
|
|
2517
|
-
return cacheItem.data;
|
|
2518
|
-
} catch (error) {
|
|
2519
|
-
console.error(`Error getting cache item ${key}:`, error);
|
|
2520
|
-
return null;
|
|
2521
|
-
}
|
|
2522
|
-
}
|
|
2523
|
-
/**
|
|
2524
|
-
* Set item in cache
|
|
2525
|
-
*/
|
|
2526
|
-
set(key, data, options) {
|
|
2527
|
-
const storage = options?.storage || "memory";
|
|
2528
|
-
const duration = options?.duration || this.DEFAULT_DURATION;
|
|
2529
|
-
const cacheItem = {
|
|
2530
|
-
data,
|
|
2531
|
-
timestamp: Date.now(),
|
|
2532
|
-
expiresAt: Date.now() + duration
|
|
2533
|
-
};
|
|
2534
|
-
try {
|
|
2535
|
-
if (storage === "memory") {
|
|
2536
|
-
this.memoryCache.set(key, cacheItem);
|
|
2537
|
-
if (this.memoryCache.size > 100) {
|
|
2538
|
-
const firstKey = this.memoryCache.keys().next().value;
|
|
2539
|
-
if (firstKey) {
|
|
2540
|
-
this.memoryCache.delete(firstKey);
|
|
2541
|
-
}
|
|
2542
|
-
}
|
|
2543
|
-
} else if (storage === "localStorage" || storage === "sessionStorage") {
|
|
2544
|
-
window[storage].setItem(key, JSON.stringify(cacheItem));
|
|
2545
|
-
}
|
|
2546
|
-
} catch (error) {
|
|
2547
|
-
console.error(`Error setting cache item ${key}:`, error);
|
|
2548
|
-
}
|
|
2549
|
-
}
|
|
2550
|
-
/**
|
|
2551
|
-
* Delete item from cache
|
|
2552
|
-
*/
|
|
2553
|
-
delete(key, options) {
|
|
2554
|
-
const storage = options?.storage || "memory";
|
|
2555
|
-
try {
|
|
2556
|
-
if (storage === "memory") {
|
|
2557
|
-
this.memoryCache.delete(key);
|
|
2558
|
-
} else if (storage === "localStorage" || storage === "sessionStorage") {
|
|
2559
|
-
window[storage].removeItem(key);
|
|
2560
|
-
}
|
|
2561
|
-
} catch (error) {
|
|
2562
|
-
console.error(`Error deleting cache item ${key}:`, error);
|
|
2563
|
-
}
|
|
2564
|
-
}
|
|
2565
|
-
/**
|
|
2566
|
-
* Clear all items from cache
|
|
2567
|
-
*/
|
|
2568
|
-
clear(options) {
|
|
2569
|
-
const storage = options?.storage || "memory";
|
|
2570
|
-
try {
|
|
2571
|
-
if (storage === "memory") {
|
|
2572
|
-
this.memoryCache.clear();
|
|
2573
|
-
} else if (storage === "localStorage" || storage === "sessionStorage") {
|
|
2574
|
-
const keys = Object.keys(window[storage]);
|
|
2575
|
-
keys.forEach((key) => {
|
|
2576
|
-
try {
|
|
2577
|
-
const item = window[storage].getItem(key);
|
|
2578
|
-
if (item) {
|
|
2579
|
-
const parsed = JSON.parse(item);
|
|
2580
|
-
if (parsed.timestamp && parsed.expiresAt && parsed.data !== void 0) {
|
|
2581
|
-
window[storage].removeItem(key);
|
|
2582
|
-
}
|
|
2583
|
-
}
|
|
2584
|
-
} catch {
|
|
2585
|
-
}
|
|
2586
|
-
});
|
|
2587
|
-
}
|
|
2588
|
-
} catch (error) {
|
|
2589
|
-
console.error("Error clearing cache:", error);
|
|
2590
|
-
}
|
|
2591
|
-
}
|
|
2592
|
-
/**
|
|
2593
|
-
* Get or set item in cache with a factory function
|
|
2594
|
-
*/
|
|
2595
|
-
async getOrSet(key, factory, options) {
|
|
2596
|
-
const cached = this.get(key, options);
|
|
2597
|
-
if (cached !== null) {
|
|
2598
|
-
return cached;
|
|
2599
|
-
}
|
|
2600
|
-
const data = await factory();
|
|
2601
|
-
this.set(key, data, options);
|
|
2602
|
-
return data;
|
|
2603
|
-
}
|
|
2604
|
-
/**
|
|
2605
|
-
* Invalidate cache entries matching a pattern
|
|
2606
|
-
*/
|
|
2607
|
-
invalidatePattern(pattern, options) {
|
|
2608
|
-
const storage = options?.storage || "memory";
|
|
2609
|
-
const regex = typeof pattern === "string" ? new RegExp(pattern) : pattern;
|
|
2610
|
-
try {
|
|
2611
|
-
if (storage === "memory") {
|
|
2612
|
-
const keysToDelete = [];
|
|
2613
|
-
this.memoryCache.forEach((_, key) => {
|
|
2614
|
-
if (regex.test(key)) {
|
|
2615
|
-
keysToDelete.push(key);
|
|
2616
|
-
}
|
|
2617
|
-
});
|
|
2618
|
-
keysToDelete.forEach((key) => this.memoryCache.delete(key));
|
|
2619
|
-
} else if (storage === "localStorage" || storage === "sessionStorage") {
|
|
2620
|
-
const keys = Object.keys(window[storage]);
|
|
2621
|
-
keys.forEach((key) => {
|
|
2622
|
-
if (regex.test(key)) {
|
|
2623
|
-
window[storage].removeItem(key);
|
|
2624
|
-
}
|
|
2625
|
-
});
|
|
2626
|
-
}
|
|
2627
|
-
} catch (error) {
|
|
2628
|
-
console.error("Error invalidating cache pattern:", error);
|
|
2629
|
-
}
|
|
2630
|
-
}
|
|
2631
|
-
/**
|
|
2632
|
-
* Clean up expired items
|
|
2633
|
-
*/
|
|
2634
|
-
cleanup(options) {
|
|
2635
|
-
const storage = options?.storage || "memory";
|
|
2636
|
-
const now2 = Date.now();
|
|
2637
|
-
try {
|
|
2638
|
-
if (storage === "memory") {
|
|
2639
|
-
const keysToDelete = [];
|
|
2640
|
-
this.memoryCache.forEach((item, key) => {
|
|
2641
|
-
if (now2 > item.expiresAt) {
|
|
2642
|
-
keysToDelete.push(key);
|
|
2643
|
-
}
|
|
2644
|
-
});
|
|
2645
|
-
keysToDelete.forEach((key) => this.memoryCache.delete(key));
|
|
2646
|
-
} else if (storage === "localStorage" || storage === "sessionStorage") {
|
|
2647
|
-
const keys = Object.keys(window[storage]);
|
|
2648
|
-
keys.forEach((key) => {
|
|
2649
|
-
try {
|
|
2650
|
-
const item = window[storage].getItem(key);
|
|
2651
|
-
if (item) {
|
|
2652
|
-
const parsed = JSON.parse(item);
|
|
2653
|
-
if (parsed.expiresAt && now2 > parsed.expiresAt) {
|
|
2654
|
-
window[storage].removeItem(key);
|
|
2655
|
-
}
|
|
2656
|
-
}
|
|
2657
|
-
} catch {
|
|
2658
|
-
}
|
|
2659
|
-
});
|
|
2660
|
-
}
|
|
2661
|
-
} catch (error) {
|
|
2662
|
-
console.error("Error cleaning up cache:", error);
|
|
2663
|
-
}
|
|
2664
|
-
}
|
|
2665
|
-
};
|
|
2666
|
-
var cacheService = new CacheService();
|
|
2667
|
-
if (typeof window !== "undefined") {
|
|
2668
|
-
setInterval(() => {
|
|
2669
|
-
cacheService.cleanup({ storage: "localStorage" });
|
|
2670
|
-
cacheService.cleanup({ storage: "sessionStorage" });
|
|
2671
|
-
cacheService.cleanup({ storage: "memory" });
|
|
2672
|
-
}, 60 * 1e3);
|
|
2673
|
-
}
|
|
2674
|
-
|
|
2675
2482
|
// src/lib/services/subscriptionManager.ts
|
|
2676
2483
|
var SubscriptionManager = class {
|
|
2677
2484
|
constructor(supabase) {
|
|
@@ -4000,6 +3807,13 @@ var S3ClipsService = class {
|
|
|
4000
3807
|
constructor(config) {
|
|
4001
3808
|
// Request deduplication cache
|
|
4002
3809
|
this.requestCache = new RequestDeduplicationCache();
|
|
3810
|
+
// Flag to prevent metadata fetching during index building
|
|
3811
|
+
this.isIndexBuilding = false;
|
|
3812
|
+
// Flag to prevent metadata fetching during entire prefetch operation
|
|
3813
|
+
this.isPrefetching = false;
|
|
3814
|
+
// Global safeguard: limit concurrent metadata fetches to prevent flooding
|
|
3815
|
+
this.currentMetadataFetches = 0;
|
|
3816
|
+
this.MAX_CONCURRENT_METADATA = 3;
|
|
4003
3817
|
this.config = config;
|
|
4004
3818
|
if (!config.s3Config) {
|
|
4005
3819
|
throw new Error("S3 configuration is required");
|
|
@@ -4147,16 +3961,36 @@ var S3ClipsService = class {
|
|
|
4147
3961
|
return null;
|
|
4148
3962
|
}
|
|
4149
3963
|
}
|
|
3964
|
+
/**
|
|
3965
|
+
* Control prefetch mode to prevent metadata fetching during background operations
|
|
3966
|
+
*/
|
|
3967
|
+
setPrefetchMode(enabled) {
|
|
3968
|
+
this.isPrefetching = enabled;
|
|
3969
|
+
console.log(`[S3ClipsService] Prefetch mode ${enabled ? "enabled" : "disabled"} - metadata fetching ${enabled ? "blocked" : "allowed"}`);
|
|
3970
|
+
}
|
|
4150
3971
|
/**
|
|
4151
3972
|
* Fetches full metadata including timestamps with deduplication
|
|
4152
3973
|
*/
|
|
4153
3974
|
async getFullMetadata(playlistUri) {
|
|
4154
|
-
|
|
4155
|
-
|
|
4156
|
-
|
|
4157
|
-
|
|
4158
|
-
|
|
4159
|
-
|
|
3975
|
+
if (this.isIndexBuilding || this.isPrefetching) {
|
|
3976
|
+
console.warn(`[S3ClipsService] Skipping metadata fetch - building: ${this.isIndexBuilding}, prefetching: ${this.isPrefetching}`);
|
|
3977
|
+
return null;
|
|
3978
|
+
}
|
|
3979
|
+
if (this.currentMetadataFetches >= this.MAX_CONCURRENT_METADATA) {
|
|
3980
|
+
console.warn(`[S3ClipsService] Skipping metadata - max concurrent fetches (${this.MAX_CONCURRENT_METADATA}) reached`);
|
|
3981
|
+
return null;
|
|
3982
|
+
}
|
|
3983
|
+
this.currentMetadataFetches++;
|
|
3984
|
+
try {
|
|
3985
|
+
const deduplicationKey = `full-metadata:${playlistUri}`;
|
|
3986
|
+
return await this.requestCache.deduplicate(
|
|
3987
|
+
deduplicationKey,
|
|
3988
|
+
() => this.executeGetFullMetadata(playlistUri),
|
|
3989
|
+
"FullMetadata"
|
|
3990
|
+
);
|
|
3991
|
+
} finally {
|
|
3992
|
+
this.currentMetadataFetches--;
|
|
3993
|
+
}
|
|
4160
3994
|
}
|
|
4161
3995
|
/**
|
|
4162
3996
|
* Internal implementation of full metadata fetching
|
|
@@ -4217,141 +4051,152 @@ var S3ClipsService = class {
|
|
|
4217
4051
|
* Internal implementation of clip counts fetching
|
|
4218
4052
|
*/
|
|
4219
4053
|
async executeGetClipCounts(workspaceId, date, shiftId, buildIndex) {
|
|
4220
|
-
|
|
4221
|
-
|
|
4222
|
-
|
|
4223
|
-
|
|
4224
|
-
|
|
4225
|
-
|
|
4226
|
-
|
|
4227
|
-
|
|
4228
|
-
|
|
4229
|
-
|
|
4230
|
-
|
|
4231
|
-
|
|
4232
|
-
|
|
4233
|
-
|
|
4234
|
-
|
|
4235
|
-
|
|
4236
|
-
|
|
4237
|
-
|
|
4238
|
-
|
|
4239
|
-
|
|
4240
|
-
|
|
4241
|
-
|
|
4242
|
-
|
|
4243
|
-
|
|
4244
|
-
|
|
4245
|
-
|
|
4246
|
-
|
|
4247
|
-
|
|
4248
|
-
|
|
4249
|
-
|
|
4250
|
-
|
|
4251
|
-
|
|
4252
|
-
|
|
4253
|
-
|
|
4254
|
-
|
|
4255
|
-
|
|
4256
|
-
|
|
4257
|
-
|
|
4258
|
-
|
|
4259
|
-
}
|
|
4260
|
-
|
|
4261
|
-
|
|
4262
|
-
|
|
4263
|
-
|
|
4264
|
-
|
|
4265
|
-
|
|
4266
|
-
|
|
4267
|
-
|
|
4268
|
-
|
|
4269
|
-
|
|
4270
|
-
|
|
4271
|
-
|
|
4272
|
-
|
|
4273
|
-
const
|
|
4274
|
-
|
|
4275
|
-
|
|
4276
|
-
|
|
4277
|
-
|
|
4278
|
-
|
|
4279
|
-
|
|
4280
|
-
|
|
4281
|
-
|
|
4282
|
-
|
|
4283
|
-
|
|
4054
|
+
if (buildIndex) {
|
|
4055
|
+
this.isIndexBuilding = true;
|
|
4056
|
+
console.log(`[S3ClipsService] Starting index building - metadata fetching disabled`);
|
|
4057
|
+
}
|
|
4058
|
+
try {
|
|
4059
|
+
const basePrefix = `sop_violations/${workspaceId}/${date}/${shiftId}/`;
|
|
4060
|
+
const counts = { total: 0 };
|
|
4061
|
+
const categoryFolders = [
|
|
4062
|
+
"idle_time",
|
|
4063
|
+
"low_value",
|
|
4064
|
+
"sop_deviation",
|
|
4065
|
+
"missing_quality_check",
|
|
4066
|
+
"best_cycle_time",
|
|
4067
|
+
"worst_cycle_time",
|
|
4068
|
+
"long_cycle_time",
|
|
4069
|
+
"cycle_completion",
|
|
4070
|
+
"bottleneck"
|
|
4071
|
+
];
|
|
4072
|
+
console.log(`[S3ClipsService] ${buildIndex ? "Building video index and counting" : "Fast counting"} clips for ${workspaceId} on ${date}, shift ${shiftId}`);
|
|
4073
|
+
const startTime = performance.now();
|
|
4074
|
+
const videoIndex = buildIndex ? {
|
|
4075
|
+
byCategory: /* @__PURE__ */ new Map(),
|
|
4076
|
+
allVideos: [],
|
|
4077
|
+
counts: {},
|
|
4078
|
+
workspaceId,
|
|
4079
|
+
date,
|
|
4080
|
+
shiftId: shiftId.toString(),
|
|
4081
|
+
lastUpdated: /* @__PURE__ */ new Date(),
|
|
4082
|
+
_debugId: `vid_${Date.now()}_${Math.random().toString(36).substring(7)}`
|
|
4083
|
+
} : null;
|
|
4084
|
+
const countPromises = categoryFolders.map(async (category) => {
|
|
4085
|
+
const categoryPrefix = `${basePrefix}${category}/videos/`;
|
|
4086
|
+
const categoryVideos = [];
|
|
4087
|
+
try {
|
|
4088
|
+
if (buildIndex) {
|
|
4089
|
+
const command = new clientS3.ListObjectsV2Command({
|
|
4090
|
+
Bucket: this.config.s3Config.bucketName,
|
|
4091
|
+
Prefix: categoryPrefix,
|
|
4092
|
+
MaxKeys: 1e3
|
|
4093
|
+
});
|
|
4094
|
+
let continuationToken;
|
|
4095
|
+
do {
|
|
4096
|
+
if (continuationToken) {
|
|
4097
|
+
command.input.ContinuationToken = continuationToken;
|
|
4098
|
+
}
|
|
4099
|
+
const response = await this.s3Client.send(command);
|
|
4100
|
+
if (response.Contents) {
|
|
4101
|
+
for (const obj of response.Contents) {
|
|
4102
|
+
if (obj.Key && obj.Key.endsWith("playlist.m3u8")) {
|
|
4103
|
+
if (obj.Key.includes("missed_qchecks")) {
|
|
4104
|
+
continue;
|
|
4105
|
+
}
|
|
4106
|
+
const s3Uri = `s3://${this.config.s3Config.bucketName}/${obj.Key}`;
|
|
4107
|
+
const sopCategories = this.getSOPCategories(workspaceId);
|
|
4108
|
+
const parsedInfo = parseS3Uri(s3Uri, sopCategories);
|
|
4109
|
+
const belongsToCategory = parsedInfo && (parsedInfo.type === category || // Handle specific mismatches between folder names and parsed types
|
|
4110
|
+
category === "cycle_completion" && parsedInfo.type === "cycle_completion" || category === "sop_deviation" && parsedInfo.type === "missing_quality_check" || category === "missing_quality_check" && parsedInfo.type === "missing_quality_check" || category === "idle_time" && parsedInfo.type === "low_value" || category === "low_value" && parsedInfo.type === "low_value");
|
|
4111
|
+
if (belongsToCategory) {
|
|
4112
|
+
const videoEntry = {
|
|
4113
|
+
uri: s3Uri,
|
|
4114
|
+
category: parsedInfo.type,
|
|
4115
|
+
// Use the parsed type, not the folder name
|
|
4116
|
+
timestamp: parsedInfo.timestamp,
|
|
4117
|
+
videoId: `${workspaceId}-${parsedInfo.timestamp}`,
|
|
4118
|
+
workspaceId,
|
|
4119
|
+
date,
|
|
4120
|
+
shiftId: shiftId.toString()
|
|
4121
|
+
};
|
|
4122
|
+
categoryVideos.push(videoEntry);
|
|
4123
|
+
}
|
|
4284
4124
|
}
|
|
4285
4125
|
}
|
|
4286
4126
|
}
|
|
4127
|
+
continuationToken = response.NextContinuationToken;
|
|
4128
|
+
} while (continuationToken);
|
|
4129
|
+
categoryVideos.sort((a, b) => b.timestamp.localeCompare(a.timestamp));
|
|
4130
|
+
if (categoryVideos.length > 0) {
|
|
4131
|
+
console.log(`[S3ClipsService] Found ${categoryVideos.length} videos for category '${category}' (parsed types: ${[...new Set(categoryVideos.map((v) => v.category))].join(", ")})`);
|
|
4287
4132
|
}
|
|
4288
|
-
|
|
4289
|
-
}
|
|
4290
|
-
|
|
4291
|
-
|
|
4292
|
-
|
|
4133
|
+
return { category, count: categoryVideos.length, videos: categoryVideos };
|
|
4134
|
+
} else {
|
|
4135
|
+
const command = new clientS3.ListObjectsV2Command({
|
|
4136
|
+
Bucket: this.config.s3Config.bucketName,
|
|
4137
|
+
Prefix: categoryPrefix,
|
|
4138
|
+
Delimiter: "/",
|
|
4139
|
+
MaxKeys: 1e3
|
|
4140
|
+
});
|
|
4141
|
+
let folderCount = 0;
|
|
4142
|
+
let continuationToken;
|
|
4143
|
+
do {
|
|
4144
|
+
if (continuationToken) {
|
|
4145
|
+
command.input.ContinuationToken = continuationToken;
|
|
4146
|
+
}
|
|
4147
|
+
const response = await this.s3Client.send(command);
|
|
4148
|
+
if (response.CommonPrefixes) {
|
|
4149
|
+
folderCount += response.CommonPrefixes.length;
|
|
4150
|
+
}
|
|
4151
|
+
continuationToken = response.NextContinuationToken;
|
|
4152
|
+
} while (continuationToken);
|
|
4153
|
+
return { category, count: folderCount, videos: [] };
|
|
4293
4154
|
}
|
|
4294
|
-
|
|
4295
|
-
|
|
4296
|
-
|
|
4297
|
-
|
|
4298
|
-
|
|
4299
|
-
|
|
4300
|
-
|
|
4301
|
-
|
|
4302
|
-
|
|
4303
|
-
|
|
4304
|
-
|
|
4305
|
-
|
|
4306
|
-
|
|
4307
|
-
}
|
|
4308
|
-
|
|
4309
|
-
|
|
4310
|
-
|
|
4155
|
+
} catch (error) {
|
|
4156
|
+
console.error(`Error ${buildIndex ? "building index for" : "counting folders for"} category ${category}:`, error);
|
|
4157
|
+
return { category, count: 0, videos: [] };
|
|
4158
|
+
}
|
|
4159
|
+
});
|
|
4160
|
+
const results = await Promise.all(countPromises);
|
|
4161
|
+
for (const { category, count, videos } of results) {
|
|
4162
|
+
counts[category] = count;
|
|
4163
|
+
counts.total += count;
|
|
4164
|
+
if (buildIndex && videoIndex && videos) {
|
|
4165
|
+
if (videos.length > 0) {
|
|
4166
|
+
const parsedType = videos[0].category;
|
|
4167
|
+
videoIndex.byCategory.set(parsedType, videos);
|
|
4168
|
+
console.log(`[S3ClipsService] Indexed ${videos.length} videos under parsed type '${parsedType}'`);
|
|
4169
|
+
if (category !== parsedType) {
|
|
4170
|
+
videoIndex.byCategory.set(category, videos);
|
|
4171
|
+
console.log(`[S3ClipsService] Created alias: S3 folder '${category}' -> parsed type '${parsedType}' (${videos.length} videos)`);
|
|
4311
4172
|
}
|
|
4312
|
-
|
|
4313
|
-
|
|
4314
|
-
return { category, count: folderCount, videos: [] };
|
|
4173
|
+
}
|
|
4174
|
+
videoIndex.allVideos.push(...videos);
|
|
4315
4175
|
}
|
|
4316
|
-
} catch (error) {
|
|
4317
|
-
console.error(`Error ${buildIndex ? "building index for" : "counting folders for"} category ${category}:`, error);
|
|
4318
|
-
return { category, count: 0, videos: [] };
|
|
4319
4176
|
}
|
|
4320
|
-
|
|
4321
|
-
|
|
4322
|
-
|
|
4323
|
-
|
|
4324
|
-
|
|
4325
|
-
|
|
4326
|
-
|
|
4327
|
-
|
|
4328
|
-
|
|
4329
|
-
|
|
4330
|
-
|
|
4331
|
-
|
|
4332
|
-
|
|
4333
|
-
}
|
|
4177
|
+
if (buildIndex && videoIndex) {
|
|
4178
|
+
videoIndex.allVideos.sort((a, b) => b.timestamp.localeCompare(a.timestamp));
|
|
4179
|
+
videoIndex.counts = { ...counts };
|
|
4180
|
+
}
|
|
4181
|
+
const elapsed = performance.now() - startTime;
|
|
4182
|
+
console.log(`[S3ClipsService] ${buildIndex ? "Video index and counts" : "Clip counts"} completed in ${elapsed.toFixed(2)}ms - Total: ${counts.total}`);
|
|
4183
|
+
if (buildIndex && videoIndex) {
|
|
4184
|
+
console.log(`[S3ClipsService] Final video index summary:`);
|
|
4185
|
+
console.log(` - VideoIndex ID: ${videoIndex._debugId}`);
|
|
4186
|
+
console.log(` - Total videos in allVideos: ${videoIndex.allVideos.length}`);
|
|
4187
|
+
console.log(` - Categories in byCategory Map: ${Array.from(videoIndex.byCategory.keys()).join(", ")}`);
|
|
4188
|
+
for (const [cat, vids] of videoIndex.byCategory.entries()) {
|
|
4189
|
+
console.log(` - '${cat}': ${vids.length} videos`);
|
|
4334
4190
|
}
|
|
4335
|
-
videoIndex
|
|
4191
|
+
return { counts, videoIndex };
|
|
4336
4192
|
}
|
|
4337
|
-
|
|
4338
|
-
|
|
4339
|
-
|
|
4340
|
-
|
|
4341
|
-
|
|
4342
|
-
const elapsed = performance.now() - startTime;
|
|
4343
|
-
console.log(`[S3ClipsService] ${buildIndex ? "Video index and counts" : "Clip counts"} completed in ${elapsed.toFixed(2)}ms - Total: ${counts.total}`);
|
|
4344
|
-
if (buildIndex && videoIndex) {
|
|
4345
|
-
console.log(`[S3ClipsService] Final video index summary:`);
|
|
4346
|
-
console.log(` - VideoIndex ID: ${videoIndex._debugId}`);
|
|
4347
|
-
console.log(` - Total videos in allVideos: ${videoIndex.allVideos.length}`);
|
|
4348
|
-
console.log(` - Categories in byCategory Map: ${Array.from(videoIndex.byCategory.keys()).join(", ")}`);
|
|
4349
|
-
for (const [cat, vids] of videoIndex.byCategory.entries()) {
|
|
4350
|
-
console.log(` - '${cat}': ${vids.length} videos`);
|
|
4193
|
+
return counts;
|
|
4194
|
+
} finally {
|
|
4195
|
+
if (buildIndex) {
|
|
4196
|
+
this.isIndexBuilding = false;
|
|
4197
|
+
console.log(`[S3ClipsService] Index building complete - metadata fetching re-enabled`);
|
|
4351
4198
|
}
|
|
4352
|
-
return { counts, videoIndex };
|
|
4353
4199
|
}
|
|
4354
|
-
return counts;
|
|
4355
4200
|
}
|
|
4356
4201
|
async getClipCountsCacheFirst(workspaceId, date, shiftId, buildIndex) {
|
|
4357
4202
|
const cacheKey = `clip-counts:${workspaceId}:${date}:${shiftId}`;
|
|
@@ -4445,18 +4290,18 @@ var S3ClipsService = class {
|
|
|
4445
4290
|
* Get a specific clip by index for a category with deduplication
|
|
4446
4291
|
* @deprecated Use getVideoFromIndex with a pre-built VideoIndex for better performance
|
|
4447
4292
|
*/
|
|
4448
|
-
async getClipByIndex(workspaceId, date, shiftId, category, index) {
|
|
4449
|
-
const deduplicationKey = `clip-by-index:${workspaceId}:${date}:${shiftId}:${category}:${index}`;
|
|
4293
|
+
async getClipByIndex(workspaceId, date, shiftId, category, index, includeCycleTime = true, includeMetadata = false) {
|
|
4294
|
+
const deduplicationKey = `clip-by-index:${workspaceId}:${date}:${shiftId}:${category}:${index}:${includeCycleTime}:${includeMetadata}`;
|
|
4450
4295
|
return this.requestCache.deduplicate(
|
|
4451
4296
|
deduplicationKey,
|
|
4452
|
-
() => this.executeGetClipByIndex(workspaceId, date, shiftId, category, index),
|
|
4297
|
+
() => this.executeGetClipByIndex(workspaceId, date, shiftId, category, index, includeCycleTime, includeMetadata),
|
|
4453
4298
|
"ClipByIndex"
|
|
4454
4299
|
);
|
|
4455
4300
|
}
|
|
4456
4301
|
/**
|
|
4457
4302
|
* Internal implementation of clip by index fetching
|
|
4458
4303
|
*/
|
|
4459
|
-
async executeGetClipByIndex(workspaceId, date, shiftId, category, index) {
|
|
4304
|
+
async executeGetClipByIndex(workspaceId, date, shiftId, category, index, includeCycleTime = true, includeMetadata = false) {
|
|
4460
4305
|
const categoryPrefix = `sop_violations/${workspaceId}/${date}/${shiftId}/${category}/videos/`;
|
|
4461
4306
|
try {
|
|
4462
4307
|
const command = new clientS3.ListObjectsV2Command({
|
|
@@ -4494,10 +4339,8 @@ var S3ClipsService = class {
|
|
|
4494
4339
|
workspaceId,
|
|
4495
4340
|
date,
|
|
4496
4341
|
shiftId.toString(),
|
|
4497
|
-
|
|
4498
|
-
|
|
4499
|
-
true
|
|
4500
|
-
// includeMetadata
|
|
4342
|
+
includeCycleTime,
|
|
4343
|
+
includeMetadata
|
|
4501
4344
|
);
|
|
4502
4345
|
}
|
|
4503
4346
|
} catch (error) {
|
|
@@ -4568,7 +4411,7 @@ var S3ClipsService = class {
|
|
|
4568
4411
|
}
|
|
4569
4412
|
let cycleTimeSeconds = null;
|
|
4570
4413
|
let creationTimestamp = void 0;
|
|
4571
|
-
if (includeMetadata
|
|
4414
|
+
if (includeMetadata) {
|
|
4572
4415
|
const metadata = await this.getFullMetadata(uri);
|
|
4573
4416
|
if (metadata) {
|
|
4574
4417
|
if (metadata.original_task_metadata?.cycle_time) {
|
|
@@ -4576,6 +4419,8 @@ var S3ClipsService = class {
|
|
|
4576
4419
|
}
|
|
4577
4420
|
creationTimestamp = metadata.upload_timestamp || metadata.original_task_metadata?.timestamp || metadata.creation_timestamp || metadata[""];
|
|
4578
4421
|
}
|
|
4422
|
+
} else if (includeCycleTime && (parsedInfo.type === "bottleneck" && parsedInfo.description.toLowerCase().includes("cycle time") || parsedInfo.type === "best_cycle_time" || parsedInfo.type === "worst_cycle_time" || parsedInfo.type === "cycle_completion")) {
|
|
4423
|
+
cycleTimeSeconds = null;
|
|
4579
4424
|
}
|
|
4580
4425
|
const cloudfrontPlaylistUrl = this.s3UriToCloudfront(uri);
|
|
4581
4426
|
const { type: videoType, timestamp: videoTimestamp } = parsedInfo;
|
|
@@ -4647,7 +4492,8 @@ var S3ClipsService = class {
|
|
|
4647
4492
|
date,
|
|
4648
4493
|
shiftId.toString(),
|
|
4649
4494
|
includeCycleTime || false,
|
|
4650
|
-
includeMetadata ||
|
|
4495
|
+
includeMetadata || false
|
|
4496
|
+
// Never fetch metadata for timestamp filtering to prevent flooding
|
|
4651
4497
|
);
|
|
4652
4498
|
});
|
|
4653
4499
|
const videoResults = await Promise.all(videoPromises);
|
|
@@ -4718,6 +4564,7 @@ var VideoPrefetchManager = class extends events.EventEmitter {
|
|
|
4718
4564
|
}
|
|
4719
4565
|
/**
|
|
4720
4566
|
* Get or create S3 service instance for dashboard config
|
|
4567
|
+
* Public method to allow sharing the same S3Service instance across components
|
|
4721
4568
|
*/
|
|
4722
4569
|
getS3Service(dashboardConfig) {
|
|
4723
4570
|
const configKey = JSON.stringify(dashboardConfig.s3Config);
|
|
@@ -4787,75 +4634,80 @@ var VideoPrefetchManager = class extends events.EventEmitter {
|
|
|
4787
4634
|
* Perform the actual prefetch work
|
|
4788
4635
|
*/
|
|
4789
4636
|
async performPrefetchWork(key, params, s3Service, buildIndex) {
|
|
4790
|
-
|
|
4791
|
-
|
|
4792
|
-
|
|
4793
|
-
|
|
4794
|
-
|
|
4795
|
-
|
|
4796
|
-
|
|
4797
|
-
|
|
4798
|
-
|
|
4637
|
+
s3Service.setPrefetchMode(true);
|
|
4638
|
+
try {
|
|
4639
|
+
const cacheKey = `clip-counts:${params.workspaceId}:${params.date}:${params.shift}`;
|
|
4640
|
+
const cachedResult = await smartVideoCache.getClipCounts(cacheKey);
|
|
4641
|
+
if (cachedResult) {
|
|
4642
|
+
console.log(`[VideoPrefetchManager] Found cached data for ${key}`);
|
|
4643
|
+
this.updateRequestStatus(key, "fully_indexed" /* FULLY_INDEXED */, cachedResult);
|
|
4644
|
+
return cachedResult;
|
|
4645
|
+
}
|
|
4646
|
+
if (buildIndex) {
|
|
4647
|
+
const countsOnly = await s3Service.getClipCounts(
|
|
4648
|
+
params.workspaceId,
|
|
4649
|
+
params.date,
|
|
4650
|
+
params.shift
|
|
4651
|
+
);
|
|
4652
|
+
if (typeof countsOnly === "object" && countsOnly !== null) {
|
|
4653
|
+
const renderReadyData = {
|
|
4654
|
+
counts: countsOnly,
|
|
4655
|
+
videoIndex: {
|
|
4656
|
+
byCategory: /* @__PURE__ */ new Map(),
|
|
4657
|
+
allVideos: [],
|
|
4658
|
+
counts: countsOnly,
|
|
4659
|
+
workspaceId: params.workspaceId,
|
|
4660
|
+
date: params.date,
|
|
4661
|
+
shiftId: params.shift,
|
|
4662
|
+
lastUpdated: /* @__PURE__ */ new Date(),
|
|
4663
|
+
_debugId: `vid_RENDER_READY_${Date.now()}_${Math.random().toString(36).substring(7)}`
|
|
4664
|
+
}
|
|
4665
|
+
};
|
|
4666
|
+
this.updateRequestStatus(key, "render_ready" /* RENDER_READY */, renderReadyData);
|
|
4667
|
+
console.log(`[VideoPrefetchManager] Render ready, building full index for ${key}`);
|
|
4668
|
+
}
|
|
4669
|
+
}
|
|
4670
|
+
const fullResult = await s3Service.getClipCountsCacheFirst(
|
|
4799
4671
|
params.workspaceId,
|
|
4800
4672
|
params.date,
|
|
4801
|
-
params.shift
|
|
4673
|
+
params.shift,
|
|
4674
|
+
true
|
|
4802
4675
|
);
|
|
4803
|
-
if (typeof
|
|
4804
|
-
const
|
|
4805
|
-
|
|
4676
|
+
if (fullResult && typeof fullResult === "object" && "videoIndex" in fullResult) {
|
|
4677
|
+
const clipCountsWithIndex = fullResult;
|
|
4678
|
+
if (clipCountsWithIndex.videoIndex.allVideos.length > 0) {
|
|
4679
|
+
console.log(`[VideoPrefetchManager] Video index properly populated with ${clipCountsWithIndex.videoIndex.allVideos.length} videos`);
|
|
4680
|
+
} else {
|
|
4681
|
+
console.warn(`[VideoPrefetchManager] Video index is empty, but counts available:`, clipCountsWithIndex.counts);
|
|
4682
|
+
}
|
|
4683
|
+
await smartVideoCache.setClipCounts(cacheKey, clipCountsWithIndex, 5 * 60);
|
|
4684
|
+
this.updateRequestStatus(key, "fully_indexed" /* FULLY_INDEXED */, clipCountsWithIndex);
|
|
4685
|
+
console.log(`[VideoPrefetchManager] Fully indexed: ${key} (${clipCountsWithIndex.videoIndex.allVideos.length} videos)`);
|
|
4686
|
+
return clipCountsWithIndex;
|
|
4687
|
+
} else if (fullResult && typeof fullResult === "object") {
|
|
4688
|
+
console.log(`[VideoPrefetchManager] Received counts only, building fallback data structure`);
|
|
4689
|
+
const countsResult = fullResult;
|
|
4690
|
+
const fallbackData = {
|
|
4691
|
+
counts: countsResult,
|
|
4806
4692
|
videoIndex: {
|
|
4807
4693
|
byCategory: /* @__PURE__ */ new Map(),
|
|
4808
4694
|
allVideos: [],
|
|
4809
|
-
counts:
|
|
4695
|
+
counts: countsResult,
|
|
4810
4696
|
workspaceId: params.workspaceId,
|
|
4811
4697
|
date: params.date,
|
|
4812
4698
|
shiftId: params.shift,
|
|
4813
4699
|
lastUpdated: /* @__PURE__ */ new Date(),
|
|
4814
|
-
_debugId: `
|
|
4700
|
+
_debugId: `vid_FALLBACK_${Date.now()}_${Math.random().toString(36).substring(7)}`
|
|
4815
4701
|
}
|
|
4816
4702
|
};
|
|
4817
|
-
this.updateRequestStatus(key, "render_ready" /* RENDER_READY */,
|
|
4818
|
-
|
|
4819
|
-
}
|
|
4820
|
-
}
|
|
4821
|
-
const fullResult = await s3Service.getClipCountsCacheFirst(
|
|
4822
|
-
params.workspaceId,
|
|
4823
|
-
params.date,
|
|
4824
|
-
params.shift,
|
|
4825
|
-
true
|
|
4826
|
-
);
|
|
4827
|
-
if (fullResult && typeof fullResult === "object" && "videoIndex" in fullResult) {
|
|
4828
|
-
const clipCountsWithIndex = fullResult;
|
|
4829
|
-
if (clipCountsWithIndex.videoIndex.allVideos.length > 0) {
|
|
4830
|
-
console.log(`[VideoPrefetchManager] Video index properly populated with ${clipCountsWithIndex.videoIndex.allVideos.length} videos`);
|
|
4703
|
+
this.updateRequestStatus(key, "render_ready" /* RENDER_READY */, fallbackData);
|
|
4704
|
+
return fallbackData;
|
|
4831
4705
|
} else {
|
|
4832
|
-
console.
|
|
4833
|
-
|
|
4834
|
-
|
|
4835
|
-
|
|
4836
|
-
|
|
4837
|
-
return clipCountsWithIndex;
|
|
4838
|
-
} else if (fullResult && typeof fullResult === "object") {
|
|
4839
|
-
console.log(`[VideoPrefetchManager] Received counts only, building fallback data structure`);
|
|
4840
|
-
const countsResult = fullResult;
|
|
4841
|
-
const fallbackData = {
|
|
4842
|
-
counts: countsResult,
|
|
4843
|
-
videoIndex: {
|
|
4844
|
-
byCategory: /* @__PURE__ */ new Map(),
|
|
4845
|
-
allVideos: [],
|
|
4846
|
-
counts: countsResult,
|
|
4847
|
-
workspaceId: params.workspaceId,
|
|
4848
|
-
date: params.date,
|
|
4849
|
-
shiftId: params.shift,
|
|
4850
|
-
lastUpdated: /* @__PURE__ */ new Date(),
|
|
4851
|
-
_debugId: `vid_FALLBACK_${Date.now()}_${Math.random().toString(36).substring(7)}`
|
|
4852
|
-
}
|
|
4853
|
-
};
|
|
4854
|
-
this.updateRequestStatus(key, "render_ready" /* RENDER_READY */, fallbackData);
|
|
4855
|
-
return fallbackData;
|
|
4856
|
-
} else {
|
|
4857
|
-
console.error(`[VideoPrefetchManager] Received null/undefined result from S3 service`);
|
|
4858
|
-
throw new Error("Failed to fetch clip counts from S3 service");
|
|
4706
|
+
console.error(`[VideoPrefetchManager] Received null/undefined result from S3 service`);
|
|
4707
|
+
throw new Error("Failed to fetch clip counts from S3 service");
|
|
4708
|
+
}
|
|
4709
|
+
} finally {
|
|
4710
|
+
s3Service.setPrefetchMode(false);
|
|
4859
4711
|
}
|
|
4860
4712
|
}
|
|
4861
4713
|
/**
|
|
@@ -5118,9 +4970,13 @@ var AuthProvider = ({ children }) => {
|
|
|
5118
4970
|
const [loading, setLoading] = React19.useState(true);
|
|
5119
4971
|
const [error, setError] = React19.useState(null);
|
|
5120
4972
|
const router$1 = router.useRouter();
|
|
5121
|
-
|
|
5122
|
-
|
|
4973
|
+
authConfig?.userProfileTable;
|
|
4974
|
+
authConfig?.roleColumn || "role";
|
|
5123
4975
|
const fetchUserDetails = React19.useCallback(async (supabaseUser) => {
|
|
4976
|
+
console.log("[fetchUserDetails] Called for user:", supabaseUser.id, {
|
|
4977
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4978
|
+
stackTrace: new Error().stack?.split("\n").slice(1, 4).join(" -> ")
|
|
4979
|
+
});
|
|
5124
4980
|
if (!supabaseUser) return null;
|
|
5125
4981
|
const basicUser = {
|
|
5126
4982
|
id: supabaseUser.id,
|
|
@@ -5129,42 +4985,34 @@ var AuthProvider = ({ children }) => {
|
|
|
5129
4985
|
if (!supabase) return basicUser;
|
|
5130
4986
|
try {
|
|
5131
4987
|
const timeoutPromise = new Promise(
|
|
5132
|
-
(_, reject) => setTimeout(() =>
|
|
4988
|
+
(_, reject) => setTimeout(() => {
|
|
4989
|
+
console.log("[fetchUserDetails] Timeout triggered after 2 seconds");
|
|
4990
|
+
reject(new Error("Profile fetch timeout"));
|
|
4991
|
+
}, 2e3)
|
|
5133
4992
|
);
|
|
5134
4993
|
const rolePromise = supabase.from("user_roles").select("role_level").eq("user_id", supabaseUser.id).single();
|
|
5135
|
-
|
|
5136
|
-
|
|
5137
|
-
|
|
5138
|
-
|
|
5139
|
-
const [roleResult, profileResult] = await Promise.race([
|
|
5140
|
-
Promise.all([
|
|
5141
|
-
rolePromise,
|
|
5142
|
-
profilePromise || Promise.resolve(null)
|
|
5143
|
-
]),
|
|
5144
|
-
timeoutPromise.then(() => {
|
|
5145
|
-
throw new Error("Timeout");
|
|
5146
|
-
})
|
|
4994
|
+
const roleResult = await Promise.race([
|
|
4995
|
+
rolePromise,
|
|
4996
|
+
timeoutPromise
|
|
4997
|
+
// Fixed: removed .then() which was causing the bug
|
|
5147
4998
|
]);
|
|
5148
4999
|
let roleLevel = void 0;
|
|
5149
5000
|
if (roleResult && !roleResult.error && roleResult.data) {
|
|
5150
5001
|
roleLevel = roleResult.data.role_level;
|
|
5151
|
-
} else if (roleResult?.error) {
|
|
5002
|
+
} else if (roleResult?.error && roleResult.error.code !== "PGRST116") {
|
|
5152
5003
|
console.log("Error fetching role_level:", roleResult.error.message);
|
|
5153
5004
|
}
|
|
5154
|
-
let roleValue = void 0;
|
|
5155
|
-
if (profileResult && !profileResult.error && profileResult.data) {
|
|
5156
|
-
roleValue = profileResult.data[roleColumn];
|
|
5157
|
-
}
|
|
5158
5005
|
return {
|
|
5159
5006
|
...basicUser,
|
|
5160
|
-
role: roleValue,
|
|
5161
5007
|
role_level: roleLevel
|
|
5162
5008
|
};
|
|
5163
5009
|
} catch (err) {
|
|
5164
|
-
|
|
5010
|
+
if (err instanceof Error && err.message.includes("timeout")) {
|
|
5011
|
+
console.warn("Auth fetch timeout - using basic user info");
|
|
5012
|
+
}
|
|
5165
5013
|
return basicUser;
|
|
5166
5014
|
}
|
|
5167
|
-
}, [supabase
|
|
5015
|
+
}, [supabase]);
|
|
5168
5016
|
React19.useEffect(() => {
|
|
5169
5017
|
if (!supabase) return;
|
|
5170
5018
|
let mounted = true;
|
|
@@ -5175,6 +5023,7 @@ var AuthProvider = ({ children }) => {
|
|
|
5175
5023
|
}
|
|
5176
5024
|
}, 1e4);
|
|
5177
5025
|
const initializeAuth = async () => {
|
|
5026
|
+
const startTime = performance.now();
|
|
5178
5027
|
try {
|
|
5179
5028
|
const { data: { session: initialSession }, error: sessionError } = await supabase.auth.getSession();
|
|
5180
5029
|
if (!mounted) return;
|
|
@@ -5217,12 +5066,38 @@ var AuthProvider = ({ children }) => {
|
|
|
5217
5066
|
if (mounted) {
|
|
5218
5067
|
setLoading(false);
|
|
5219
5068
|
clearTimeout(safetyTimeout);
|
|
5069
|
+
const duration = performance.now() - startTime;
|
|
5070
|
+
if (duration > 3e3) {
|
|
5071
|
+
console.warn(`[Auth] Initialization took ${duration.toFixed(0)}ms - consider optimization`);
|
|
5072
|
+
} else if (process.env.NODE_ENV === "development") {
|
|
5073
|
+
console.log(`[Auth] Initialized in ${duration.toFixed(0)}ms`);
|
|
5074
|
+
}
|
|
5220
5075
|
}
|
|
5221
5076
|
}
|
|
5222
5077
|
};
|
|
5223
5078
|
initializeAuth();
|
|
5224
|
-
const { data: { subscription } } = supabase.auth.onAuthStateChange(async (
|
|
5079
|
+
const { data: { subscription } } = supabase.auth.onAuthStateChange(async (event, currentSession) => {
|
|
5225
5080
|
if (!mounted) return;
|
|
5081
|
+
console.log("[AuthContext] Auth event fired:", {
|
|
5082
|
+
event,
|
|
5083
|
+
sessionId: currentSession?.user?.id,
|
|
5084
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
5085
|
+
currentPath: typeof window !== "undefined" ? window.location.pathname : "unknown"
|
|
5086
|
+
});
|
|
5087
|
+
if (event === "TOKEN_REFRESHED") {
|
|
5088
|
+
if (session?.user?.id === currentSession?.user?.id && session?.user?.email === currentSession?.user?.email) {
|
|
5089
|
+
console.log("[AuthContext] Skipping TOKEN_REFRESHED - session unchanged");
|
|
5090
|
+
return;
|
|
5091
|
+
}
|
|
5092
|
+
}
|
|
5093
|
+
if (event !== "TOKEN_REFRESHED" && currentSession?.user) {
|
|
5094
|
+
console.log("[AuthContext] Non-TOKEN_REFRESHED event will trigger fetchUserDetails:", event);
|
|
5095
|
+
}
|
|
5096
|
+
const sessionChanged = session?.user?.id !== currentSession?.user?.id || session?.user?.email !== currentSession?.user?.email;
|
|
5097
|
+
if (!sessionChanged && user) {
|
|
5098
|
+
console.log("[AuthContext] Session and user unchanged, skipping update");
|
|
5099
|
+
return;
|
|
5100
|
+
}
|
|
5226
5101
|
setSession(currentSession);
|
|
5227
5102
|
setUser(null);
|
|
5228
5103
|
setLoading(false);
|
|
@@ -5597,7 +5472,6 @@ var useWorkspaceDetailedMetrics = (workspaceId, date, shiftId) => {
|
|
|
5597
5472
|
const [error, setError] = React19.useState(null);
|
|
5598
5473
|
const updateQueueRef = React19.useRef(false);
|
|
5599
5474
|
const isFetchingRef = React19.useRef(false);
|
|
5600
|
-
const timeoutRef = React19.useRef(null);
|
|
5601
5475
|
const channelRef = React19.useRef(null);
|
|
5602
5476
|
const schema = databaseConfig.schema ?? "public";
|
|
5603
5477
|
const companyId = entityConfig.companyId || "";
|
|
@@ -5606,7 +5480,7 @@ var useWorkspaceDetailedMetrics = (workspaceId, date, shiftId) => {
|
|
|
5606
5480
|
const defaultTimezone = dateTimeConfig.defaultTimezone;
|
|
5607
5481
|
const workspaceMetricsBaseTable = databaseConfig.tables?.workspaces ?? "workspace_metrics";
|
|
5608
5482
|
const workspaceActionsTable = databaseConfig.tables?.actions ?? "workspace_actions";
|
|
5609
|
-
const fetchMetrics = React19.useCallback(async (
|
|
5483
|
+
const fetchMetrics = React19.useCallback(async () => {
|
|
5610
5484
|
if (!workspaceId || isFetchingRef.current) return;
|
|
5611
5485
|
try {
|
|
5612
5486
|
isFetchingRef.current = true;
|
|
@@ -5615,28 +5489,6 @@ var useWorkspaceDetailedMetrics = (workspaceId, date, shiftId) => {
|
|
|
5615
5489
|
const queryShiftId = shiftId !== void 0 ? shiftId : currentShift.shiftId;
|
|
5616
5490
|
console.log("[useWorkspaceDetailedMetrics] Using shift ID:", queryShiftId, "from input shift:", shiftId);
|
|
5617
5491
|
console.log("[useWorkspaceDetailedMetrics] Using date:", queryDate, "from input date:", date);
|
|
5618
|
-
const cacheKey = cacheService.generateKey(
|
|
5619
|
-
"workspace-detailed-metrics",
|
|
5620
|
-
workspaceId,
|
|
5621
|
-
queryDate,
|
|
5622
|
-
queryShiftId,
|
|
5623
|
-
companyId
|
|
5624
|
-
);
|
|
5625
|
-
if (!skipCache) {
|
|
5626
|
-
const cachedData = cacheService.get(cacheKey, {
|
|
5627
|
-
storage: "memory",
|
|
5628
|
-
duration: 5 * 60 * 1e3
|
|
5629
|
-
// 5 minutes
|
|
5630
|
-
});
|
|
5631
|
-
if (cachedData) {
|
|
5632
|
-
console.log("[useWorkspaceDetailedMetrics] Using cached data for:", cacheKey);
|
|
5633
|
-
setMetrics(cachedData);
|
|
5634
|
-
setIsLoading(false);
|
|
5635
|
-
updateQueueRef.current = false;
|
|
5636
|
-
isFetchingRef.current = false;
|
|
5637
|
-
return;
|
|
5638
|
-
}
|
|
5639
|
-
}
|
|
5640
5492
|
console.log(`[useWorkspaceDetailedMetrics] Querying ${metricsTable} for workspace: ${workspaceId}, date: ${queryDate}, shift: ${queryShiftId}`);
|
|
5641
5493
|
const { data, error: fetchError } = await supabase.from(metricsTable).select("*").eq("workspace_id", workspaceId).eq("date", queryDate).eq("shift_id", queryShiftId).maybeSingle();
|
|
5642
5494
|
if (fetchError) throw fetchError;
|
|
@@ -5739,18 +5591,6 @@ var useWorkspaceDetailedMetrics = (workspaceId, date, shiftId) => {
|
|
|
5739
5591
|
setIsLoading(false);
|
|
5740
5592
|
updateQueueRef.current = false;
|
|
5741
5593
|
isFetchingRef.current = false;
|
|
5742
|
-
const fallbackCacheKey = cacheService.generateKey(
|
|
5743
|
-
"workspace-detailed-metrics",
|
|
5744
|
-
workspaceId,
|
|
5745
|
-
recentData.date,
|
|
5746
|
-
recentData.shift_id,
|
|
5747
|
-
companyId
|
|
5748
|
-
);
|
|
5749
|
-
cacheService.set(fallbackCacheKey, transformedData2, {
|
|
5750
|
-
storage: "memory",
|
|
5751
|
-
duration: 2 * 60 * 1e3
|
|
5752
|
-
// 2 minutes for fallback data
|
|
5753
|
-
});
|
|
5754
5594
|
return;
|
|
5755
5595
|
} else {
|
|
5756
5596
|
console.warn("[useWorkspaceDetailedMetrics] No data found for workspace:", workspaceId, "at all");
|
|
@@ -5864,11 +5704,6 @@ var useWorkspaceDetailedMetrics = (workspaceId, date, shiftId) => {
|
|
|
5864
5704
|
...data.sop_check !== void 0 && { sop_check: data.sop_check }
|
|
5865
5705
|
};
|
|
5866
5706
|
setMetrics(transformedData);
|
|
5867
|
-
cacheService.set(cacheKey, transformedData, {
|
|
5868
|
-
storage: "memory",
|
|
5869
|
-
duration: 5 * 60 * 1e3
|
|
5870
|
-
// 5 minutes
|
|
5871
|
-
});
|
|
5872
5707
|
} catch (err) {
|
|
5873
5708
|
console.error("Error fetching workspace metrics:", err);
|
|
5874
5709
|
setError({ message: err.message, code: err.code });
|
|
@@ -5881,12 +5716,7 @@ var useWorkspaceDetailedMetrics = (workspaceId, date, shiftId) => {
|
|
|
5881
5716
|
const queueUpdate = React19.useCallback(() => {
|
|
5882
5717
|
if (!workspaceId || updateQueueRef.current) return;
|
|
5883
5718
|
updateQueueRef.current = true;
|
|
5884
|
-
|
|
5885
|
-
clearTimeout(timeoutRef.current);
|
|
5886
|
-
}
|
|
5887
|
-
timeoutRef.current = setTimeout(() => {
|
|
5888
|
-
fetchMetrics();
|
|
5889
|
-
}, 500);
|
|
5719
|
+
fetchMetrics();
|
|
5890
5720
|
}, [fetchMetrics, workspaceId]);
|
|
5891
5721
|
const setupSubscription = React19.useCallback(() => {
|
|
5892
5722
|
if (!workspaceId) return;
|
|
@@ -5903,7 +5733,7 @@ var useWorkspaceDetailedMetrics = (workspaceId, date, shiftId) => {
|
|
|
5903
5733
|
},
|
|
5904
5734
|
async (payload) => {
|
|
5905
5735
|
console.log(`Received ${metricsTablePrefix} update:`, payload);
|
|
5906
|
-
await fetchMetrics(
|
|
5736
|
+
await fetchMetrics();
|
|
5907
5737
|
}
|
|
5908
5738
|
).subscribe((status) => {
|
|
5909
5739
|
console.log(`Workspace detailed metrics subscription status:`, status);
|
|
@@ -5937,14 +5767,6 @@ var useWorkspaceDetailedMetrics = (workspaceId, date, shiftId) => {
|
|
|
5937
5767
|
matches: payloadData?.date === operationalDate && payloadData?.shift_id === queryShiftId
|
|
5938
5768
|
});
|
|
5939
5769
|
if (payloadData?.date === operationalDate && payloadData?.shift_id === queryShiftId) {
|
|
5940
|
-
const cacheKey = cacheService.generateKey(
|
|
5941
|
-
"workspace-detailed-metrics",
|
|
5942
|
-
workspaceId,
|
|
5943
|
-
operationalDate,
|
|
5944
|
-
queryShiftId,
|
|
5945
|
-
companyId
|
|
5946
|
-
);
|
|
5947
|
-
cacheService.delete(cacheKey, { storage: "memory" });
|
|
5948
5770
|
queueUpdate();
|
|
5949
5771
|
}
|
|
5950
5772
|
}
|
|
@@ -5970,14 +5792,6 @@ var useWorkspaceDetailedMetrics = (workspaceId, date, shiftId) => {
|
|
|
5970
5792
|
matches: payloadData?.date === operationalDate && payloadData?.shift_id === queryShiftId
|
|
5971
5793
|
});
|
|
5972
5794
|
if (payloadData?.date === operationalDate && payloadData?.shift_id === queryShiftId) {
|
|
5973
|
-
const cacheKey = cacheService.generateKey(
|
|
5974
|
-
"workspace-detailed-metrics",
|
|
5975
|
-
workspaceId,
|
|
5976
|
-
operationalDate,
|
|
5977
|
-
queryShiftId,
|
|
5978
|
-
companyId
|
|
5979
|
-
);
|
|
5980
|
-
cacheService.delete(cacheKey, { storage: "memory" });
|
|
5981
5795
|
queueUpdate();
|
|
5982
5796
|
}
|
|
5983
5797
|
}
|
|
@@ -6003,14 +5817,6 @@ var useWorkspaceDetailedMetrics = (workspaceId, date, shiftId) => {
|
|
|
6003
5817
|
matches: payloadData?.date === operationalDate && payloadData?.shift_id === queryShiftId
|
|
6004
5818
|
});
|
|
6005
5819
|
if (payloadData?.date === operationalDate && payloadData?.shift_id === queryShiftId) {
|
|
6006
|
-
const cacheKey = cacheService.generateKey(
|
|
6007
|
-
"workspace-detailed-metrics",
|
|
6008
|
-
workspaceId,
|
|
6009
|
-
operationalDate,
|
|
6010
|
-
queryShiftId,
|
|
6011
|
-
companyId
|
|
6012
|
-
);
|
|
6013
|
-
cacheService.delete(cacheKey, { storage: "memory" });
|
|
6014
5820
|
queueUpdate();
|
|
6015
5821
|
}
|
|
6016
5822
|
}
|
|
@@ -6021,9 +5827,6 @@ var useWorkspaceDetailedMetrics = (workspaceId, date, shiftId) => {
|
|
|
6021
5827
|
fetchMetrics();
|
|
6022
5828
|
setupSubscription();
|
|
6023
5829
|
return () => {
|
|
6024
|
-
if (timeoutRef.current) {
|
|
6025
|
-
clearTimeout(timeoutRef.current);
|
|
6026
|
-
}
|
|
6027
5830
|
channels.forEach((channel) => {
|
|
6028
5831
|
console.log("Cleaning up channel subscription");
|
|
6029
5832
|
supabase.removeChannel(channel);
|
|
@@ -6037,7 +5840,7 @@ var useWorkspaceDetailedMetrics = (workspaceId, date, shiftId) => {
|
|
|
6037
5840
|
metrics: metrics2,
|
|
6038
5841
|
isLoading,
|
|
6039
5842
|
error,
|
|
6040
|
-
refetch: () => fetchMetrics(
|
|
5843
|
+
refetch: () => fetchMetrics()
|
|
6041
5844
|
// Force refresh without cache
|
|
6042
5845
|
};
|
|
6043
5846
|
};
|
|
@@ -6482,33 +6285,6 @@ var useLeaderboardMetrics = (lineId, topCount = 10) => {
|
|
|
6482
6285
|
refetch: fetchLeaderboardData
|
|
6483
6286
|
};
|
|
6484
6287
|
};
|
|
6485
|
-
var CACHE_KEY_PREFIX = "dashboard_metrics_cache_";
|
|
6486
|
-
var CACHE_DURATION = 5 * 60 * 1e3;
|
|
6487
|
-
var getCache = (lineId) => {
|
|
6488
|
-
if (typeof window === "undefined") return null;
|
|
6489
|
-
try {
|
|
6490
|
-
const cached = localStorage.getItem(`${CACHE_KEY_PREFIX}${lineId}`);
|
|
6491
|
-
if (!cached) return null;
|
|
6492
|
-
const parsedCache = JSON.parse(cached);
|
|
6493
|
-
if (!parsedCache.lastUpdated || Date.now() - parsedCache.lastUpdated > CACHE_DURATION) {
|
|
6494
|
-
localStorage.removeItem(`${CACHE_KEY_PREFIX}${lineId}`);
|
|
6495
|
-
return null;
|
|
6496
|
-
}
|
|
6497
|
-
return parsedCache;
|
|
6498
|
-
} catch {
|
|
6499
|
-
return null;
|
|
6500
|
-
}
|
|
6501
|
-
};
|
|
6502
|
-
var setCache = (lineId, metrics2) => {
|
|
6503
|
-
if (typeof window === "undefined") return;
|
|
6504
|
-
try {
|
|
6505
|
-
localStorage.setItem(`${CACHE_KEY_PREFIX}${lineId}`, JSON.stringify({
|
|
6506
|
-
...metrics2,
|
|
6507
|
-
lastUpdated: Date.now()
|
|
6508
|
-
}));
|
|
6509
|
-
} catch {
|
|
6510
|
-
}
|
|
6511
|
-
};
|
|
6512
6288
|
var useDashboardMetrics = ({ onLineMetricsUpdate, lineId }) => {
|
|
6513
6289
|
const { supabaseUrl, supabaseKey } = useDashboardConfig();
|
|
6514
6290
|
const entityConfig = useEntityConfig();
|
|
@@ -6519,22 +6295,20 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId }) => {
|
|
|
6519
6295
|
const configuredLineMetricsTable = databaseConfig?.tables?.lineMetrics ?? "line_metrics";
|
|
6520
6296
|
const schema = databaseConfig?.schema ?? "public";
|
|
6521
6297
|
const supabase = useSupabase();
|
|
6522
|
-
const [metrics2, setMetrics] = React19.useState(
|
|
6523
|
-
const [isLoading, setIsLoading] = React19.useState(
|
|
6298
|
+
const [metrics2, setMetrics] = React19.useState({ workspaceMetrics: [], lineMetrics: [] });
|
|
6299
|
+
const [isLoading, setIsLoading] = React19.useState(true);
|
|
6524
6300
|
const [error, setError] = React19.useState(null);
|
|
6525
6301
|
const lineIdRef = React19.useRef(lineId);
|
|
6526
6302
|
const isFetchingRef = React19.useRef(false);
|
|
6527
6303
|
const updateQueueRef = React19.useRef(false);
|
|
6528
|
-
const timeoutRef = React19.useRef(null);
|
|
6529
6304
|
const companySpecificMetricsTable = React19.useMemo(
|
|
6530
6305
|
() => getCompanyMetricsTableName(entityConfig.companyId, "performance_metrics"),
|
|
6531
6306
|
[entityConfig.companyId]
|
|
6532
6307
|
);
|
|
6533
6308
|
React19.useEffect(() => {
|
|
6534
6309
|
lineIdRef.current = lineId;
|
|
6535
|
-
|
|
6536
|
-
|
|
6537
|
-
setIsLoading(!cachedData);
|
|
6310
|
+
setMetrics({ workspaceMetrics: [], lineMetrics: [] });
|
|
6311
|
+
setIsLoading(true);
|
|
6538
6312
|
}, [lineId]);
|
|
6539
6313
|
const fetchAllMetrics = React19.useCallback(async () => {
|
|
6540
6314
|
const currentLineIdToUse = lineIdRef.current;
|
|
@@ -6546,9 +6320,7 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId }) => {
|
|
|
6546
6320
|
return;
|
|
6547
6321
|
}
|
|
6548
6322
|
isFetchingRef.current = true;
|
|
6549
|
-
|
|
6550
|
-
setIsLoading(true);
|
|
6551
|
-
}
|
|
6323
|
+
setIsLoading(true);
|
|
6552
6324
|
setError(null);
|
|
6553
6325
|
try {
|
|
6554
6326
|
const currentShiftDetails = getCurrentShift(defaultTimezone, shiftConfig);
|
|
@@ -6573,7 +6345,6 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId }) => {
|
|
|
6573
6345
|
lineMetrics: []
|
|
6574
6346
|
};
|
|
6575
6347
|
setMetrics(newMetricsState2);
|
|
6576
|
-
setCache(currentLineIdToUse, newMetricsState2);
|
|
6577
6348
|
return;
|
|
6578
6349
|
}
|
|
6579
6350
|
let workspaceQuery = supabase.from(companySpecificMetricsTable).select("company_id,line_id,shift_id,date,workspace_id,workspace_name,total_output,avg_pph,performance_score,avg_cycle_time,trend_score,ideal_output,efficiency,total_day_output").eq("date", operationalDate).eq("shift_id", currentShiftDetails.shiftId).in("workspace_id", enabledWorkspaceIds);
|
|
@@ -6625,7 +6396,6 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId }) => {
|
|
|
6625
6396
|
lineMetrics: lineData || []
|
|
6626
6397
|
};
|
|
6627
6398
|
setMetrics(newMetricsState);
|
|
6628
|
-
setCache(currentLineIdToUse, newMetricsState);
|
|
6629
6399
|
} catch (err) {
|
|
6630
6400
|
setError({ message: err.message, code: err.code || "FETCH_ERROR" });
|
|
6631
6401
|
} finally {
|
|
@@ -6651,12 +6421,7 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId }) => {
|
|
|
6651
6421
|
return;
|
|
6652
6422
|
}
|
|
6653
6423
|
updateQueueRef.current = true;
|
|
6654
|
-
|
|
6655
|
-
clearTimeout(timeoutRef.current);
|
|
6656
|
-
}
|
|
6657
|
-
timeoutRef.current = setTimeout(() => {
|
|
6658
|
-
fetchAllMetrics();
|
|
6659
|
-
}, 500);
|
|
6424
|
+
fetchAllMetrics();
|
|
6660
6425
|
}, [fetchAllMetrics, supabase]);
|
|
6661
6426
|
React19.useEffect(() => {
|
|
6662
6427
|
if (lineId && supabase) {
|
|
@@ -6701,9 +6466,6 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId }) => {
|
|
|
6701
6466
|
onLineMetricsUpdate?.();
|
|
6702
6467
|
});
|
|
6703
6468
|
return () => {
|
|
6704
|
-
if (timeoutRef.current) {
|
|
6705
|
-
clearTimeout(timeoutRef.current);
|
|
6706
|
-
}
|
|
6707
6469
|
channels.forEach((channel) => {
|
|
6708
6470
|
supabase?.removeChannel(channel).catch((err) => console.error("[useDashboardMetrics] Error removing channel:", err.message));
|
|
6709
6471
|
});
|
|
@@ -6732,30 +6494,6 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId }) => {
|
|
|
6732
6494
|
refetch: fetchAllMetrics
|
|
6733
6495
|
};
|
|
6734
6496
|
};
|
|
6735
|
-
var CACHE_KEY_PREFIX2 = "line_kpis_cache_";
|
|
6736
|
-
var CACHE_DURATION2 = 5 * 60 * 1e3;
|
|
6737
|
-
var getCache2 = (lineId) => {
|
|
6738
|
-
if (typeof window === "undefined") return null;
|
|
6739
|
-
try {
|
|
6740
|
-
const cached = localStorage.getItem(`${CACHE_KEY_PREFIX2}${lineId}`);
|
|
6741
|
-
if (!cached) return null;
|
|
6742
|
-
const parsedCache = JSON.parse(cached);
|
|
6743
|
-
if (!parsedCache.timestamp || Date.now() - parsedCache.timestamp > CACHE_DURATION2) {
|
|
6744
|
-
localStorage.removeItem(`${CACHE_KEY_PREFIX2}${lineId}`);
|
|
6745
|
-
return null;
|
|
6746
|
-
}
|
|
6747
|
-
return parsedCache.data;
|
|
6748
|
-
} catch (error) {
|
|
6749
|
-
return null;
|
|
6750
|
-
}
|
|
6751
|
-
};
|
|
6752
|
-
var setCache2 = (lineId, data) => {
|
|
6753
|
-
if (typeof window === "undefined") return;
|
|
6754
|
-
try {
|
|
6755
|
-
localStorage.setItem(`${CACHE_KEY_PREFIX2}${lineId}`, JSON.stringify({ data, timestamp: Date.now() }));
|
|
6756
|
-
} catch (error) {
|
|
6757
|
-
}
|
|
6758
|
-
};
|
|
6759
6497
|
var useLineKPIs = ({ lineId }) => {
|
|
6760
6498
|
useDashboardConfig();
|
|
6761
6499
|
const entityConfig = useEntityConfig();
|
|
@@ -6767,13 +6505,12 @@ var useLineKPIs = ({ lineId }) => {
|
|
|
6767
6505
|
const dashboardServiceInstance = React19.useMemo(() => {
|
|
6768
6506
|
return dashboardService;
|
|
6769
6507
|
}, []);
|
|
6770
|
-
const [kpis, setKPIs] = React19.useState(
|
|
6771
|
-
const [isLoading, setIsLoading] = React19.useState(
|
|
6508
|
+
const [kpis, setKPIs] = React19.useState(null);
|
|
6509
|
+
const [isLoading, setIsLoading] = React19.useState(true);
|
|
6772
6510
|
const [error, setError] = React19.useState(null);
|
|
6773
6511
|
const lineIdRef = React19.useRef(lineId);
|
|
6774
6512
|
const isFetchingRef = React19.useRef(false);
|
|
6775
6513
|
const updateQueueRef = React19.useRef(false);
|
|
6776
|
-
const timeoutRef = React19.useRef(null);
|
|
6777
6514
|
const defaultTimezone = dateTimeConfig.defaultTimezone;
|
|
6778
6515
|
const schema = databaseConfig.schema ?? "public";
|
|
6779
6516
|
const lineMetricsTable = databaseConfig.tables?.lineMetrics ?? "line_metrics";
|
|
@@ -6804,7 +6541,6 @@ var useLineKPIs = ({ lineId }) => {
|
|
|
6804
6541
|
if (lineInfo) {
|
|
6805
6542
|
const newKPIs = dashboardServiceInstance.calculateKPIs(lineInfo);
|
|
6806
6543
|
setKPIs(newKPIs);
|
|
6807
|
-
setCache2(currentLineId, newKPIs);
|
|
6808
6544
|
} else {
|
|
6809
6545
|
setKPIs(null);
|
|
6810
6546
|
}
|
|
@@ -6821,12 +6557,7 @@ var useLineKPIs = ({ lineId }) => {
|
|
|
6821
6557
|
const queueUpdate = React19.useCallback(() => {
|
|
6822
6558
|
if (updateQueueRef.current) return;
|
|
6823
6559
|
updateQueueRef.current = true;
|
|
6824
|
-
|
|
6825
|
-
clearTimeout(timeoutRef.current);
|
|
6826
|
-
}
|
|
6827
|
-
timeoutRef.current = setTimeout(() => {
|
|
6828
|
-
fetchKPIs();
|
|
6829
|
-
}, 500);
|
|
6560
|
+
fetchKPIs();
|
|
6830
6561
|
}, [fetchKPIs]);
|
|
6831
6562
|
React19.useEffect(() => {
|
|
6832
6563
|
const currentLineId = lineIdRef.current;
|
|
@@ -6884,9 +6615,6 @@ var useLineKPIs = ({ lineId }) => {
|
|
|
6884
6615
|
activeChannels.push(csChannel);
|
|
6885
6616
|
}
|
|
6886
6617
|
return () => {
|
|
6887
|
-
if (timeoutRef.current) {
|
|
6888
|
-
clearTimeout(timeoutRef.current);
|
|
6889
|
-
}
|
|
6890
6618
|
activeChannels.forEach((ch) => supabase.removeChannel(ch).catch((err) => console.error("[useLineKPIs] Error removing KPI channel:", err)));
|
|
6891
6619
|
};
|
|
6892
6620
|
}, [supabase, lineId, fetchKPIs, queueUpdate, dashboardServiceInstance, entityConfig, schema, lineMetricsTable, companySpecificMetricsTable, defaultTimezone, shiftConfig, kpis, isFactoryView]);
|
|
@@ -6915,7 +6643,6 @@ var useRealtimeLineMetrics = ({
|
|
|
6915
6643
|
const [initialized, setInitialized] = React19.useState(false);
|
|
6916
6644
|
const lineIdRef = React19.useRef(null);
|
|
6917
6645
|
const updateQueueRef = React19.useRef(false);
|
|
6918
|
-
const timeoutRef = React19.useRef(null);
|
|
6919
6646
|
const isFetchingRef = React19.useRef(false);
|
|
6920
6647
|
const channelsRef = React19.useRef([]);
|
|
6921
6648
|
const currentShift = React19.useMemo(() => getCurrentShift(dateTimeConfig.defaultTimezone || "Asia/Kolkata", shiftConfig), [dateTimeConfig.defaultTimezone, shiftConfig]);
|
|
@@ -7128,12 +6855,7 @@ var useRealtimeLineMetrics = ({
|
|
|
7128
6855
|
const queueUpdate = React19.useCallback(() => {
|
|
7129
6856
|
if (updateQueueRef.current) return;
|
|
7130
6857
|
updateQueueRef.current = true;
|
|
7131
|
-
|
|
7132
|
-
clearTimeout(timeoutRef.current);
|
|
7133
|
-
}
|
|
7134
|
-
timeoutRef.current = setTimeout(() => {
|
|
7135
|
-
fetchData();
|
|
7136
|
-
}, 500);
|
|
6858
|
+
fetchData();
|
|
7137
6859
|
}, [fetchData]);
|
|
7138
6860
|
const setupSubscriptions = React19.useCallback(() => {
|
|
7139
6861
|
if (channelsRef.current.length > 0) {
|
|
@@ -7211,9 +6933,6 @@ var useRealtimeLineMetrics = ({
|
|
|
7211
6933
|
}
|
|
7212
6934
|
setupSubscriptions();
|
|
7213
6935
|
return () => {
|
|
7214
|
-
if (timeoutRef.current) {
|
|
7215
|
-
clearTimeout(timeoutRef.current);
|
|
7216
|
-
}
|
|
7217
6936
|
if (channelsRef.current.length > 0) {
|
|
7218
6937
|
channelsRef.current.forEach((channel) => {
|
|
7219
6938
|
if (process.env.NODE_ENV === "development") {
|
|
@@ -7299,16 +7018,12 @@ var useTargets = (options) => {
|
|
|
7299
7018
|
};
|
|
7300
7019
|
var DEFAULT_SHIFTS_TABLE_NAME = "shift_configurations";
|
|
7301
7020
|
var useShifts = () => {
|
|
7302
|
-
const { supabaseUrl, supabaseKey } = useDashboardConfig();
|
|
7303
7021
|
const { companyId } = useEntityConfig();
|
|
7304
7022
|
const { tables } = useDatabaseConfig();
|
|
7023
|
+
const supabase = useSupabase();
|
|
7305
7024
|
const [shifts, setShifts] = React19.useState([]);
|
|
7306
7025
|
const [isLoading, setIsLoading] = React19.useState(true);
|
|
7307
7026
|
const [error, setError] = React19.useState(null);
|
|
7308
|
-
const supabase = React19.useMemo(() => {
|
|
7309
|
-
if (!supabaseUrl || !supabaseKey) return null;
|
|
7310
|
-
return supabaseJs.createClient(supabaseUrl, supabaseKey);
|
|
7311
|
-
}, [supabaseUrl, supabaseKey]);
|
|
7312
7027
|
const shiftsTable = tables?.shiftConfigurations || DEFAULT_SHIFTS_TABLE_NAME;
|
|
7313
7028
|
const fetchData = React19.useCallback(async () => {
|
|
7314
7029
|
if (!supabase) {
|
|
@@ -8007,6 +7722,7 @@ var runtimeWorkspaceDisplayNames = {};
|
|
|
8007
7722
|
var isInitialized = false;
|
|
8008
7723
|
var isInitializing = false;
|
|
8009
7724
|
var initializedWithLineIds = [];
|
|
7725
|
+
var initializationPromise = null;
|
|
8010
7726
|
function getCurrentLineIds() {
|
|
8011
7727
|
try {
|
|
8012
7728
|
const config = _getDashboardConfigInstance();
|
|
@@ -8027,52 +7743,79 @@ function getCurrentLineIds() {
|
|
|
8027
7743
|
}
|
|
8028
7744
|
async function initializeWorkspaceDisplayNames(explicitLineId) {
|
|
8029
7745
|
console.log("\u{1F504} initializeWorkspaceDisplayNames called", { isInitialized, isInitializing, explicitLineId });
|
|
8030
|
-
if (isInitialized
|
|
8031
|
-
|
|
8032
|
-
|
|
8033
|
-
|
|
8034
|
-
|
|
8035
|
-
|
|
8036
|
-
|
|
8037
|
-
|
|
8038
|
-
|
|
7746
|
+
if (isInitialized) return;
|
|
7747
|
+
if (initializationPromise) {
|
|
7748
|
+
console.log("\u{1F504} Already initializing, waiting for existing initialization...");
|
|
7749
|
+
await initializationPromise;
|
|
7750
|
+
return;
|
|
7751
|
+
}
|
|
7752
|
+
initializationPromise = (async () => {
|
|
7753
|
+
isInitializing = true;
|
|
7754
|
+
try {
|
|
7755
|
+
console.log("\u{1F504} Starting Supabase workspace display names initialization...");
|
|
7756
|
+
let targetLineIds = [];
|
|
7757
|
+
if (explicitLineId) {
|
|
7758
|
+
targetLineIds = [explicitLineId];
|
|
7759
|
+
} else {
|
|
7760
|
+
targetLineIds = getCurrentLineIds();
|
|
7761
|
+
}
|
|
7762
|
+
console.log("\u{1F504} Target line IDs for workspace filtering:", targetLineIds);
|
|
7763
|
+
runtimeWorkspaceDisplayNames = {};
|
|
7764
|
+
if (targetLineIds.length > 0) {
|
|
7765
|
+
for (const lineId of targetLineIds) {
|
|
7766
|
+
console.log(`\u{1F504} Fetching workspaces for line: ${lineId}`);
|
|
7767
|
+
const lineDisplayNamesMap = await workspaceService.getWorkspaceDisplayNames(void 0, lineId);
|
|
7768
|
+
runtimeWorkspaceDisplayNames[lineId] = {};
|
|
7769
|
+
lineDisplayNamesMap.forEach((displayName, workspaceId) => {
|
|
7770
|
+
runtimeWorkspaceDisplayNames[lineId][workspaceId] = displayName;
|
|
7771
|
+
});
|
|
7772
|
+
console.log(`\u2705 Stored ${lineDisplayNamesMap.size} workspaces for line ${lineId}`);
|
|
7773
|
+
}
|
|
7774
|
+
} else {
|
|
7775
|
+
console.warn("\u26A0\uFE0F No line IDs found, fetching all workspaces (less efficient)");
|
|
7776
|
+
const allWorkspacesMap = await workspaceService.getWorkspaceDisplayNames();
|
|
7777
|
+
runtimeWorkspaceDisplayNames["global"] = {};
|
|
7778
|
+
allWorkspacesMap.forEach((displayName, workspaceId) => {
|
|
7779
|
+
runtimeWorkspaceDisplayNames["global"][workspaceId] = displayName;
|
|
7780
|
+
});
|
|
7781
|
+
}
|
|
7782
|
+
isInitialized = true;
|
|
7783
|
+
initializedWithLineIds = targetLineIds;
|
|
7784
|
+
console.log("\u2705 Workspace display names initialized from Supabase:", runtimeWorkspaceDisplayNames);
|
|
7785
|
+
console.log("\u2705 Initialized with line IDs:", initializedWithLineIds);
|
|
7786
|
+
} catch (error) {
|
|
7787
|
+
console.error("\u274C Failed to initialize workspace display names from Supabase:", error);
|
|
7788
|
+
} finally {
|
|
7789
|
+
isInitializing = false;
|
|
7790
|
+
initializationPromise = null;
|
|
8039
7791
|
}
|
|
8040
|
-
|
|
8041
|
-
|
|
8042
|
-
|
|
8043
|
-
|
|
8044
|
-
|
|
7792
|
+
})();
|
|
7793
|
+
await initializationPromise;
|
|
7794
|
+
}
|
|
7795
|
+
var preInitializeWorkspaceDisplayNames = async (lineId) => {
|
|
7796
|
+
console.log("\u{1F504} preInitializeWorkspaceDisplayNames called for lineId:", lineId);
|
|
7797
|
+
if (isInitialized) {
|
|
7798
|
+
console.log("\u{1F504} Already initialized");
|
|
7799
|
+
if (lineId && !runtimeWorkspaceDisplayNames[lineId]) {
|
|
7800
|
+
console.log(`\u{1F504} Line ${lineId} not in cache, fetching...`);
|
|
7801
|
+
try {
|
|
8045
7802
|
const lineDisplayNamesMap = await workspaceService.getWorkspaceDisplayNames(void 0, lineId);
|
|
8046
7803
|
runtimeWorkspaceDisplayNames[lineId] = {};
|
|
8047
7804
|
lineDisplayNamesMap.forEach((displayName, workspaceId) => {
|
|
8048
7805
|
runtimeWorkspaceDisplayNames[lineId][workspaceId] = displayName;
|
|
8049
7806
|
});
|
|
8050
|
-
console.log(`\u2705
|
|
7807
|
+
console.log(`\u2705 Added ${lineDisplayNamesMap.size} workspaces for line ${lineId}`);
|
|
7808
|
+
} catch (error) {
|
|
7809
|
+
console.error(`\u274C Failed to fetch workspaces for line ${lineId}:`, error);
|
|
8051
7810
|
}
|
|
8052
|
-
} else {
|
|
8053
|
-
console.warn("\u26A0\uFE0F No line IDs found, fetching all workspaces (less efficient)");
|
|
8054
|
-
const allWorkspacesMap = await workspaceService.getWorkspaceDisplayNames();
|
|
8055
|
-
runtimeWorkspaceDisplayNames["global"] = {};
|
|
8056
|
-
allWorkspacesMap.forEach((displayName, workspaceId) => {
|
|
8057
|
-
runtimeWorkspaceDisplayNames["global"][workspaceId] = displayName;
|
|
8058
|
-
});
|
|
8059
7811
|
}
|
|
8060
|
-
|
|
8061
|
-
initializedWithLineIds = targetLineIds;
|
|
8062
|
-
console.log("\u2705 Workspace display names initialized from Supabase:", runtimeWorkspaceDisplayNames);
|
|
8063
|
-
console.log("\u2705 Initialized with line IDs:", initializedWithLineIds);
|
|
8064
|
-
} catch (error) {
|
|
8065
|
-
console.error("\u274C Failed to initialize workspace display names from Supabase:", error);
|
|
8066
|
-
} finally {
|
|
8067
|
-
isInitializing = false;
|
|
7812
|
+
return;
|
|
8068
7813
|
}
|
|
8069
|
-
|
|
8070
|
-
|
|
8071
|
-
|
|
8072
|
-
if (isInitialized || isInitializing) {
|
|
8073
|
-
console.log("\u{1F504} Already initialized or initializing");
|
|
7814
|
+
if (initializationPromise) {
|
|
7815
|
+
console.log("\u{1F504} Already initializing, waiting for completion...");
|
|
7816
|
+
await initializationPromise;
|
|
8074
7817
|
if (lineId && !runtimeWorkspaceDisplayNames[lineId]) {
|
|
8075
|
-
console.log(`\u{1F504} Line ${lineId} not in cache, fetching...`);
|
|
7818
|
+
console.log(`\u{1F504} Line ${lineId} not in cache after init, fetching...`);
|
|
8076
7819
|
try {
|
|
8077
7820
|
const lineDisplayNamesMap = await workspaceService.getWorkspaceDisplayNames(void 0, lineId);
|
|
8078
7821
|
runtimeWorkspaceDisplayNames[lineId] = {};
|
|
@@ -8090,7 +7833,12 @@ var preInitializeWorkspaceDisplayNames = async (lineId) => {
|
|
|
8090
7833
|
};
|
|
8091
7834
|
var forceRefreshWorkspaceDisplayNames = async (lineId) => {
|
|
8092
7835
|
console.log("\u{1F504} forceRefreshWorkspaceDisplayNames called for lineId:", lineId);
|
|
7836
|
+
if (initializationPromise) {
|
|
7837
|
+
console.log("\u{1F504} Waiting for existing initialization to complete before refresh...");
|
|
7838
|
+
await initializationPromise;
|
|
7839
|
+
}
|
|
8093
7840
|
clearWorkspaceDisplayNamesCache();
|
|
7841
|
+
initializationPromise = null;
|
|
8094
7842
|
await initializeWorkspaceDisplayNames(lineId);
|
|
8095
7843
|
};
|
|
8096
7844
|
console.log("\u{1F504} Module loaded, will initialize lazily when first function is called");
|
|
@@ -8238,6 +7986,7 @@ var clearWorkspaceDisplayNamesCache = () => {
|
|
|
8238
7986
|
isInitialized = false;
|
|
8239
7987
|
isInitializing = false;
|
|
8240
7988
|
initializedWithLineIds = [];
|
|
7989
|
+
initializationPromise = null;
|
|
8241
7990
|
};
|
|
8242
7991
|
|
|
8243
7992
|
// src/lib/hooks/useWorkspaceDisplayNames.ts
|
|
@@ -8501,32 +8250,12 @@ var useAllWorkspaceMetrics = (options) => {
|
|
|
8501
8250
|
return `${metricsTablePrefix}_${companyId.replace(/-/g, "_")}`;
|
|
8502
8251
|
}, [entityConfig.companyId]);
|
|
8503
8252
|
const schema = databaseConfig.schema ?? "public";
|
|
8504
|
-
const fetchWorkspaceMetrics = React19.useCallback(async (
|
|
8253
|
+
const fetchWorkspaceMetrics = React19.useCallback(async () => {
|
|
8505
8254
|
if (!initialized) {
|
|
8506
8255
|
setLoading(true);
|
|
8507
8256
|
}
|
|
8508
8257
|
setError(null);
|
|
8509
8258
|
try {
|
|
8510
|
-
const cacheKey = cacheService.generateKey(
|
|
8511
|
-
"all-workspace-metrics",
|
|
8512
|
-
entityConfig.companyId,
|
|
8513
|
-
queryDate,
|
|
8514
|
-
queryShiftId
|
|
8515
|
-
);
|
|
8516
|
-
if (!skipCache && !loading) {
|
|
8517
|
-
const cachedData = cacheService.get(cacheKey, {
|
|
8518
|
-
storage: "memory",
|
|
8519
|
-
duration: 5 * 60 * 1e3
|
|
8520
|
-
// 5 minutes
|
|
8521
|
-
});
|
|
8522
|
-
if (cachedData) {
|
|
8523
|
-
console.log("[useAllWorkspaceMetrics] Using cached data for:", cacheKey);
|
|
8524
|
-
setWorkspaces(cachedData);
|
|
8525
|
-
setInitialized(true);
|
|
8526
|
-
setLoading(false);
|
|
8527
|
-
return;
|
|
8528
|
-
}
|
|
8529
|
-
}
|
|
8530
8259
|
console.log("Fetching all workspace metrics with params:", {
|
|
8531
8260
|
queryDate,
|
|
8532
8261
|
queryShiftId,
|
|
@@ -8576,11 +8305,6 @@ var useAllWorkspaceMetrics = (options) => {
|
|
|
8576
8305
|
}));
|
|
8577
8306
|
setWorkspaces(transformedData);
|
|
8578
8307
|
setInitialized(true);
|
|
8579
|
-
cacheService.set(cacheKey, transformedData, {
|
|
8580
|
-
storage: "memory",
|
|
8581
|
-
duration: 5 * 60 * 1e3
|
|
8582
|
-
// 5 minutes
|
|
8583
|
-
});
|
|
8584
8308
|
} catch (err) {
|
|
8585
8309
|
console.error("Error fetching all workspace metrics:", err);
|
|
8586
8310
|
setError({ message: err.message, code: err.code || "FETCH_ERROR" });
|
|
@@ -8605,14 +8329,7 @@ var useAllWorkspaceMetrics = (options) => {
|
|
|
8605
8329
|
},
|
|
8606
8330
|
async (payload) => {
|
|
8607
8331
|
console.log("All workspace metrics update received:", payload);
|
|
8608
|
-
|
|
8609
|
-
"all-workspace-metrics",
|
|
8610
|
-
entityConfig.companyId,
|
|
8611
|
-
queryDate,
|
|
8612
|
-
queryShiftId
|
|
8613
|
-
);
|
|
8614
|
-
cacheService.delete(cacheKey, { storage: "memory" });
|
|
8615
|
-
await fetchWorkspaceMetrics(true);
|
|
8332
|
+
await fetchWorkspaceMetrics();
|
|
8616
8333
|
}
|
|
8617
8334
|
).subscribe();
|
|
8618
8335
|
return channel2;
|
|
@@ -8627,7 +8344,7 @@ var useAllWorkspaceMetrics = (options) => {
|
|
|
8627
8344
|
React19.useEffect(() => {
|
|
8628
8345
|
setInitialized(false);
|
|
8629
8346
|
}, [queryDate, queryShiftId]);
|
|
8630
|
-
const refreshWorkspaces = React19.useCallback(() => fetchWorkspaceMetrics(
|
|
8347
|
+
const refreshWorkspaces = React19.useCallback(() => fetchWorkspaceMetrics(), [fetchWorkspaceMetrics]);
|
|
8631
8348
|
return React19.useMemo(
|
|
8632
8349
|
() => ({ workspaces, loading, error, refreshWorkspaces }),
|
|
8633
8350
|
[workspaces, loading, error, refreshWorkspaces]
|
|
@@ -19910,11 +19627,13 @@ var withAuth = (WrappedComponent2, options) => {
|
|
|
19910
19627
|
requireAuth: true,
|
|
19911
19628
|
...options
|
|
19912
19629
|
};
|
|
19913
|
-
|
|
19630
|
+
const WithAuthComponent = React19__namespace.memo(function WithAuthComponent2(props) {
|
|
19914
19631
|
const { session, loading } = useAuth();
|
|
19915
19632
|
const router$1 = router.useRouter();
|
|
19916
19633
|
React19__namespace.useEffect(() => {
|
|
19917
|
-
|
|
19634
|
+
if (process.env.NODE_ENV === "development" && process.env.DEBUG_AUTH === "true") {
|
|
19635
|
+
console.log("withAuth state:", { loading, hasSession: !!session, requireAuth: defaultOptions.requireAuth });
|
|
19636
|
+
}
|
|
19918
19637
|
}, [session, loading]);
|
|
19919
19638
|
React19__namespace.useEffect(() => {
|
|
19920
19639
|
if (!loading && defaultOptions.requireAuth && !session) {
|
|
@@ -19929,7 +19648,9 @@ var withAuth = (WrappedComponent2, options) => {
|
|
|
19929
19648
|
return null;
|
|
19930
19649
|
}
|
|
19931
19650
|
return /* @__PURE__ */ jsxRuntime.jsx(WrappedComponent2, { ...props });
|
|
19932
|
-
};
|
|
19651
|
+
});
|
|
19652
|
+
WithAuthComponent.displayName = `withAuth(${WrappedComponent2.displayName || WrappedComponent2.name || "Component"})`;
|
|
19653
|
+
return WithAuthComponent;
|
|
19933
19654
|
};
|
|
19934
19655
|
var LoginPage = ({
|
|
19935
19656
|
onRateLimitCheck,
|
|
@@ -26517,7 +26238,7 @@ var BottlenecksContent = ({
|
|
|
26517
26238
|
const [duration, setDuration] = React19.useState(0);
|
|
26518
26239
|
const [currentIndex, setCurrentIndex] = React19.useState(0);
|
|
26519
26240
|
const [activeFilter, setActiveFilter] = React19.useState(initialFilter);
|
|
26520
|
-
const previousFilterRef = React19.useRef(
|
|
26241
|
+
const previousFilterRef = React19.useRef("");
|
|
26521
26242
|
const [allVideos, setAllVideos] = React19.useState([]);
|
|
26522
26243
|
const [isLoading, setIsLoading] = React19.useState(true);
|
|
26523
26244
|
const [isCategoryLoading, setIsCategoryLoading] = React19.useState(false);
|
|
@@ -26567,7 +26288,7 @@ var BottlenecksContent = ({
|
|
|
26567
26288
|
console.warn("S3 configuration not found in dashboard config");
|
|
26568
26289
|
return null;
|
|
26569
26290
|
}
|
|
26570
|
-
return
|
|
26291
|
+
return videoPrefetchManager.getS3Service(dashboardConfig);
|
|
26571
26292
|
}, [dashboardConfig]);
|
|
26572
26293
|
const {
|
|
26573
26294
|
data: prefetchData,
|
|
@@ -26635,6 +26356,85 @@ var BottlenecksContent = ({
|
|
|
26635
26356
|
}, [workspaceId, date, s3ClipsService, shift, dashboardConfig, updateClipCounts, updateVideoIndex]);
|
|
26636
26357
|
const loadingCategoryRef = React19.useRef(null);
|
|
26637
26358
|
const videoRetryCountRef = React19.useRef(0);
|
|
26359
|
+
const loadingVideosRef = React19.useRef(/* @__PURE__ */ new Set());
|
|
26360
|
+
const loadedVideosMapRef = React19.useRef(/* @__PURE__ */ new Map());
|
|
26361
|
+
const ensureVideosLoaded = React19.useCallback(async (centerIndex) => {
|
|
26362
|
+
if (!s3ClipsService || !workspaceId || !isMountedRef.current) return;
|
|
26363
|
+
const currentFilter = activeFilterRef.current;
|
|
26364
|
+
const currentVideoIndex = videoIndexRef.current;
|
|
26365
|
+
let effectiveFilter = currentFilter;
|
|
26366
|
+
if (sopCategories && sopCategories.length > 0) {
|
|
26367
|
+
const category = sopCategories.find((cat) => cat.id === currentFilter);
|
|
26368
|
+
if (category && category.s3FolderName) {
|
|
26369
|
+
effectiveFilter = category.s3FolderName;
|
|
26370
|
+
}
|
|
26371
|
+
}
|
|
26372
|
+
const cacheKey = `${effectiveFilter}:${date}:${shift}`;
|
|
26373
|
+
if (!loadedVideosMapRef.current.has(cacheKey)) {
|
|
26374
|
+
loadedVideosMapRef.current.set(cacheKey, /* @__PURE__ */ new Set());
|
|
26375
|
+
}
|
|
26376
|
+
const loadedIndices = loadedVideosMapRef.current.get(cacheKey);
|
|
26377
|
+
const indicesToLoad = [];
|
|
26378
|
+
const rangeBefore = 1;
|
|
26379
|
+
const rangeAfter = 3;
|
|
26380
|
+
for (let i = Math.max(0, centerIndex - rangeBefore); i <= Math.min(clipCounts[effectiveFilter] - 1, centerIndex + rangeAfter); i++) {
|
|
26381
|
+
if (!loadedIndices.has(i) && !loadingVideosRef.current.has(i)) {
|
|
26382
|
+
indicesToLoad.push(i);
|
|
26383
|
+
}
|
|
26384
|
+
}
|
|
26385
|
+
if (indicesToLoad.length === 0) return;
|
|
26386
|
+
console.log(`[ensureVideosLoaded] Preloading ${indicesToLoad.length} videos around index ${centerIndex}: [${indicesToLoad.join(", ")}]`);
|
|
26387
|
+
indicesToLoad.forEach((idx) => loadingVideosRef.current.add(idx));
|
|
26388
|
+
const loadPromises = indicesToLoad.map(async (index) => {
|
|
26389
|
+
try {
|
|
26390
|
+
let video = null;
|
|
26391
|
+
if (currentVideoIndex && currentVideoIndex.byCategory && currentVideoIndex.allVideos.length > 0) {
|
|
26392
|
+
video = await s3ClipsService.getVideoFromIndex(
|
|
26393
|
+
currentVideoIndex,
|
|
26394
|
+
effectiveFilter,
|
|
26395
|
+
index,
|
|
26396
|
+
true,
|
|
26397
|
+
// includeCycleTime - OK for preloading
|
|
26398
|
+
false
|
|
26399
|
+
// includeMetadata - NO metadata during bulk preloading to prevent flooding
|
|
26400
|
+
);
|
|
26401
|
+
}
|
|
26402
|
+
if (!video) {
|
|
26403
|
+
const operationalDate = date || getOperationalDate();
|
|
26404
|
+
const shiftStr = shift?.toString() || "0";
|
|
26405
|
+
video = await s3ClipsService.getClipByIndex(
|
|
26406
|
+
workspaceId,
|
|
26407
|
+
operationalDate,
|
|
26408
|
+
shiftStr,
|
|
26409
|
+
effectiveFilter,
|
|
26410
|
+
index,
|
|
26411
|
+
true,
|
|
26412
|
+
// includeCycleTime - OK for preloading
|
|
26413
|
+
false
|
|
26414
|
+
// includeMetadata - NO metadata during bulk preloading to prevent flooding
|
|
26415
|
+
);
|
|
26416
|
+
}
|
|
26417
|
+
if (video && isMountedRef.current) {
|
|
26418
|
+
setAllVideos((prev) => {
|
|
26419
|
+
const exists = prev.some((v) => v.id === video.id);
|
|
26420
|
+
if (!exists) {
|
|
26421
|
+
return [...prev, video];
|
|
26422
|
+
}
|
|
26423
|
+
return prev;
|
|
26424
|
+
});
|
|
26425
|
+
loadedIndices.add(index);
|
|
26426
|
+
preloadVideoUrl(video.src);
|
|
26427
|
+
}
|
|
26428
|
+
} catch (error2) {
|
|
26429
|
+
console.warn(`[ensureVideosLoaded] Failed to load video at index ${index}:`, error2);
|
|
26430
|
+
} finally {
|
|
26431
|
+
loadingVideosRef.current.delete(index);
|
|
26432
|
+
}
|
|
26433
|
+
});
|
|
26434
|
+
Promise.all(loadPromises).catch((err) => {
|
|
26435
|
+
console.warn("[ensureVideosLoaded] Some videos failed to preload:", err);
|
|
26436
|
+
});
|
|
26437
|
+
}, [s3ClipsService, workspaceId, clipCounts, sopCategories, date, shift]);
|
|
26638
26438
|
const loadFirstVideoForCategory = React19.useCallback(async (category) => {
|
|
26639
26439
|
if (!workspaceId || !s3ClipsService || !isMountedRef.current) return;
|
|
26640
26440
|
const targetCategory = category || activeFilterRef.current;
|
|
@@ -26671,8 +26471,16 @@ var BottlenecksContent = ({
|
|
|
26671
26471
|
);
|
|
26672
26472
|
if (firstVideo) {
|
|
26673
26473
|
console.log(`[BottlenecksContent] Successfully loaded first video via direct S3 method`);
|
|
26674
|
-
setAllVideos(
|
|
26474
|
+
setAllVideos((prev) => {
|
|
26475
|
+
const exists = prev.some((v) => v.id === firstVideo.id);
|
|
26476
|
+
if (!exists) {
|
|
26477
|
+
return [...prev, firstVideo];
|
|
26478
|
+
}
|
|
26479
|
+
return prev;
|
|
26480
|
+
});
|
|
26675
26481
|
preloadVideoUrl(firstVideo.src);
|
|
26482
|
+
setIsLoading(false);
|
|
26483
|
+
setHasInitialLoad(true);
|
|
26676
26484
|
loadingCategoryRef.current = null;
|
|
26677
26485
|
setIsCategoryLoading(false);
|
|
26678
26486
|
return;
|
|
@@ -26695,7 +26503,13 @@ var BottlenecksContent = ({
|
|
|
26695
26503
|
);
|
|
26696
26504
|
if (firstVideo && isMountedRef.current) {
|
|
26697
26505
|
console.log(`[BottlenecksContent] Successfully loaded first video via video index`);
|
|
26698
|
-
setAllVideos(
|
|
26506
|
+
setAllVideos((prev) => {
|
|
26507
|
+
const exists = prev.some((v) => v.id === firstVideo.id);
|
|
26508
|
+
if (!exists) {
|
|
26509
|
+
return [...prev, firstVideo];
|
|
26510
|
+
}
|
|
26511
|
+
return prev;
|
|
26512
|
+
});
|
|
26699
26513
|
preloadVideoUrl(firstVideo.src);
|
|
26700
26514
|
setIsCategoryLoading(false);
|
|
26701
26515
|
return;
|
|
@@ -26720,15 +26534,17 @@ var BottlenecksContent = ({
|
|
|
26720
26534
|
}
|
|
26721
26535
|
}, [workspaceId, date, s3ClipsService, clipCounts, videoIndex, shift, updateClipCounts, updateVideoIndex]);
|
|
26722
26536
|
React19.useEffect(() => {
|
|
26723
|
-
if (s3ClipsService) {
|
|
26537
|
+
if (s3ClipsService && !prefetchData) {
|
|
26724
26538
|
fetchClipCounts();
|
|
26725
26539
|
}
|
|
26726
|
-
}, [workspaceId, date, shift, s3ClipsService, fetchClipCounts, updateClipCounts, updateVideoIndex]);
|
|
26540
|
+
}, [workspaceId, date, shift, s3ClipsService, fetchClipCounts, updateClipCounts, updateVideoIndex, prefetchData]);
|
|
26727
26541
|
React19.useEffect(() => {
|
|
26728
26542
|
if (prefetchData) {
|
|
26729
26543
|
console.log(`[BottlenecksContent] Received prefetch update - status: ${prefetchStatus}, videos: ${prefetchData.videoIndex.allVideos.length}, ID: ${prefetchData.videoIndex._debugId || "NO_ID"}`);
|
|
26730
26544
|
updateClipCounts(prefetchData.counts);
|
|
26731
|
-
|
|
26545
|
+
if (prefetchData.videoIndex.allVideos.length > 0) {
|
|
26546
|
+
updateVideoIndex(prefetchData.videoIndex);
|
|
26547
|
+
}
|
|
26732
26548
|
if (!hasInitialLoad && prefetchData.videoIndex.allVideos.length > 0) {
|
|
26733
26549
|
setIsLoading(false);
|
|
26734
26550
|
setHasInitialLoad(true);
|
|
@@ -26736,10 +26552,45 @@ var BottlenecksContent = ({
|
|
|
26736
26552
|
}
|
|
26737
26553
|
}, [prefetchData, prefetchStatus, updateClipCounts, updateVideoIndex, hasInitialLoad]);
|
|
26738
26554
|
React19.useEffect(() => {
|
|
26739
|
-
if (s3ClipsService &&
|
|
26740
|
-
|
|
26555
|
+
if (s3ClipsService && clipCounts[activeFilter] > 0) {
|
|
26556
|
+
const hasVideosForCurrentFilter = allVideos.some((video) => {
|
|
26557
|
+
if (sopCategories && sopCategories.length > 0) {
|
|
26558
|
+
const selectedCategory = sopCategories.find((cat) => cat.id === activeFilter);
|
|
26559
|
+
if (selectedCategory) {
|
|
26560
|
+
return video.type === selectedCategory.id;
|
|
26561
|
+
}
|
|
26562
|
+
}
|
|
26563
|
+
if (activeFilter === "all") return true;
|
|
26564
|
+
if (activeFilter === "low_value") {
|
|
26565
|
+
return video.type === "low_value";
|
|
26566
|
+
}
|
|
26567
|
+
if (activeFilter === "idle_time") {
|
|
26568
|
+
return video.type === "idle_time";
|
|
26569
|
+
}
|
|
26570
|
+
if (activeFilter === "sop_deviations") {
|
|
26571
|
+
return video.type === "missing_quality_check";
|
|
26572
|
+
}
|
|
26573
|
+
if (activeFilter === "best_cycle_time") {
|
|
26574
|
+
return video.type === "best_cycle_time";
|
|
26575
|
+
}
|
|
26576
|
+
if (activeFilter === "worst_cycle_time") {
|
|
26577
|
+
return video.type === "worst_cycle_time";
|
|
26578
|
+
}
|
|
26579
|
+
if (activeFilter === "cycle_completion") {
|
|
26580
|
+
return video.type === "cycle_completion";
|
|
26581
|
+
}
|
|
26582
|
+
if (activeFilter === "long_cycle_time") {
|
|
26583
|
+
return video.type === "long_cycle_time";
|
|
26584
|
+
}
|
|
26585
|
+
return video.type === "bottleneck" && video.severity === activeFilter;
|
|
26586
|
+
});
|
|
26587
|
+
if (!hasVideosForCurrentFilter) {
|
|
26588
|
+
loadFirstVideoForCategory(activeFilter);
|
|
26589
|
+
} else {
|
|
26590
|
+
setIsCategoryLoading(false);
|
|
26591
|
+
}
|
|
26741
26592
|
}
|
|
26742
|
-
}, [activeFilter, s3ClipsService, videoIndex, clipCounts, loadFirstVideoForCategory]);
|
|
26593
|
+
}, [activeFilter, s3ClipsService, videoIndex, clipCounts, loadFirstVideoForCategory, allVideos, sopCategories]);
|
|
26743
26594
|
React19.useEffect(() => {
|
|
26744
26595
|
if (previousFilterRef.current !== activeFilter) {
|
|
26745
26596
|
console.log(`Filter changed from ${previousFilterRef.current} to ${activeFilter} - resetting to first video`);
|
|
@@ -26808,26 +26659,25 @@ var BottlenecksContent = ({
|
|
|
26808
26659
|
return new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime();
|
|
26809
26660
|
});
|
|
26810
26661
|
}, [activeFilter, allVideos, sopCategories]);
|
|
26811
|
-
React19.useEffect(() => {
|
|
26812
|
-
if (filteredVideos.length === 0) return;
|
|
26813
|
-
const upcoming = [];
|
|
26814
|
-
if (currentIndex + 1 < filteredVideos.length && filteredVideos[currentIndex + 1]) {
|
|
26815
|
-
upcoming.push(filteredVideos[currentIndex + 1].src);
|
|
26816
|
-
}
|
|
26817
|
-
if (currentIndex - 1 >= 0 && currentIndex - 1 < filteredVideos.length && filteredVideos[currentIndex - 1]) {
|
|
26818
|
-
upcoming.push(filteredVideos[currentIndex - 1].src);
|
|
26819
|
-
}
|
|
26820
|
-
if (upcoming.length > 0) {
|
|
26821
|
-
preloadVideosUrl(upcoming);
|
|
26822
|
-
}
|
|
26823
|
-
}, [currentIndex, filteredVideos]);
|
|
26824
26662
|
React19.useEffect(() => {
|
|
26825
26663
|
if (isNavigating && currentIndex < filteredVideos.length) {
|
|
26826
26664
|
setIsNavigating(false);
|
|
26827
26665
|
setError(null);
|
|
26828
26666
|
videoRetryCountRef.current = 0;
|
|
26667
|
+
ensureVideosLoaded(currentIndex);
|
|
26829
26668
|
}
|
|
26830
26669
|
}, [isNavigating, currentIndex, filteredVideos.length]);
|
|
26670
|
+
React19.useEffect(() => {
|
|
26671
|
+
if (!isPlaying || !isMountedRef.current) return;
|
|
26672
|
+
const preloadInterval = setInterval(() => {
|
|
26673
|
+
if (isMountedRef.current) {
|
|
26674
|
+
const currentIdx = currentIndexRef.current;
|
|
26675
|
+
console.log(`[Background Preloader] Ensuring videos loaded around index ${currentIdx}`);
|
|
26676
|
+
ensureVideosLoaded(currentIdx);
|
|
26677
|
+
}
|
|
26678
|
+
}, 2e3);
|
|
26679
|
+
return () => clearInterval(preloadInterval);
|
|
26680
|
+
}, [isPlaying]);
|
|
26831
26681
|
const handleNext = React19.useCallback(async () => {
|
|
26832
26682
|
if (!isMountedRef.current) return;
|
|
26833
26683
|
const currentIdx = currentIndexRef.current;
|
|
@@ -26848,6 +26698,7 @@ var BottlenecksContent = ({
|
|
|
26848
26698
|
}
|
|
26849
26699
|
if (nextIndex < filteredVideos.length) {
|
|
26850
26700
|
setIsNavigating(false);
|
|
26701
|
+
ensureVideosLoaded(nextIndex);
|
|
26851
26702
|
return;
|
|
26852
26703
|
}
|
|
26853
26704
|
if (isMountedRef.current) {
|
|
@@ -26865,8 +26716,8 @@ var BottlenecksContent = ({
|
|
|
26865
26716
|
nextIndex,
|
|
26866
26717
|
true,
|
|
26867
26718
|
// includeCycleTime
|
|
26868
|
-
|
|
26869
|
-
// includeMetadata
|
|
26719
|
+
false
|
|
26720
|
+
// includeMetadata - DON'T fetch metadata during navigation to prevent flooding!
|
|
26870
26721
|
);
|
|
26871
26722
|
} else {
|
|
26872
26723
|
console.warn(`[BottlenecksContent] Video index not ready for navigation: ID: ${currentVideoIndex?._debugId || "NO_ID"}, byCategory exists = ${!!currentVideoIndex?.byCategory}, allVideos = ${currentVideoIndex?.allVideos?.length || 0}`);
|
|
@@ -26879,7 +26730,11 @@ var BottlenecksContent = ({
|
|
|
26879
26730
|
operationalDate,
|
|
26880
26731
|
shiftStr,
|
|
26881
26732
|
effectiveFilter,
|
|
26882
|
-
nextIndex
|
|
26733
|
+
nextIndex,
|
|
26734
|
+
true,
|
|
26735
|
+
// includeCycleTime - needed for main video display
|
|
26736
|
+
false
|
|
26737
|
+
// includeMetadata - DON'T fetch metadata during navigation to prevent flooding!
|
|
26883
26738
|
);
|
|
26884
26739
|
}
|
|
26885
26740
|
if (video && isMountedRef.current) {
|
|
@@ -26892,26 +26747,7 @@ var BottlenecksContent = ({
|
|
|
26892
26747
|
return prev;
|
|
26893
26748
|
});
|
|
26894
26749
|
preloadVideoUrl(video.src);
|
|
26895
|
-
|
|
26896
|
-
setTimeout(() => {
|
|
26897
|
-
const videoIndexForPreload = videoIndexRef.current;
|
|
26898
|
-
if (videoIndexForPreload && s3ClipsService && isMountedRef.current) {
|
|
26899
|
-
s3ClipsService.getVideoFromIndex(videoIndexForPreload, effectiveFilter, nextIndex + 1, true, true).then((nextVideo) => {
|
|
26900
|
-
if (nextVideo && isMountedRef.current) {
|
|
26901
|
-
setAllVideos((prev) => {
|
|
26902
|
-
if (!prev.some((v) => v.id === nextVideo.id)) {
|
|
26903
|
-
const newVideos = [...prev, nextVideo];
|
|
26904
|
-
return newVideos;
|
|
26905
|
-
}
|
|
26906
|
-
return prev;
|
|
26907
|
-
});
|
|
26908
|
-
preloadVideoUrl(nextVideo.src);
|
|
26909
|
-
}
|
|
26910
|
-
}).catch(() => {
|
|
26911
|
-
});
|
|
26912
|
-
}
|
|
26913
|
-
}, 100);
|
|
26914
|
-
}
|
|
26750
|
+
ensureVideosLoaded(nextIndex);
|
|
26915
26751
|
}
|
|
26916
26752
|
} catch (error2) {
|
|
26917
26753
|
console.error("Error loading next video:", error2);
|
|
@@ -26933,15 +26769,43 @@ var BottlenecksContent = ({
|
|
|
26933
26769
|
if (prevIndex < filteredVideos.length) {
|
|
26934
26770
|
setCurrentIndex(prevIndex);
|
|
26935
26771
|
setError(null);
|
|
26772
|
+
ensureVideosLoaded(prevIndex);
|
|
26936
26773
|
}
|
|
26937
26774
|
}
|
|
26938
26775
|
}, [filteredVideos.length]);
|
|
26776
|
+
const currentVideo = React19.useMemo(() => {
|
|
26777
|
+
if (!filteredVideos || filteredVideos.length === 0 || currentIndex >= filteredVideos.length) {
|
|
26778
|
+
return null;
|
|
26779
|
+
}
|
|
26780
|
+
return filteredVideos[currentIndex];
|
|
26781
|
+
}, [filteredVideos, currentIndex]);
|
|
26939
26782
|
const handleVideoReady = React19.useCallback((player) => {
|
|
26940
26783
|
console.log("Video.js player ready");
|
|
26941
26784
|
}, []);
|
|
26942
|
-
const handleVideoPlay = React19.useCallback((player) => {
|
|
26785
|
+
const handleVideoPlay = React19.useCallback(async (player) => {
|
|
26943
26786
|
setIsPlaying(true);
|
|
26944
|
-
|
|
26787
|
+
const currentIdx = currentIndexRef.current;
|
|
26788
|
+
ensureVideosLoaded(currentIdx);
|
|
26789
|
+
if (currentVideo && !currentVideo.creation_timestamp && s3ClipsService) {
|
|
26790
|
+
try {
|
|
26791
|
+
const originalUri = currentVideo.originalUri || currentVideo.src;
|
|
26792
|
+
if (originalUri && originalUri.includes("s3://")) {
|
|
26793
|
+
const metadata = await s3ClipsService.getFullMetadata(originalUri);
|
|
26794
|
+
if (metadata && isMountedRef.current) {
|
|
26795
|
+
setAllVideos((prev) => prev.map(
|
|
26796
|
+
(v) => v.id === currentVideo.id ? {
|
|
26797
|
+
...v,
|
|
26798
|
+
creation_timestamp: metadata.upload_timestamp || metadata.original_task_metadata?.timestamp || metadata.creation_timestamp,
|
|
26799
|
+
cycle_time_seconds: metadata.original_task_metadata?.cycle_time || v.cycle_time_seconds
|
|
26800
|
+
} : v
|
|
26801
|
+
));
|
|
26802
|
+
}
|
|
26803
|
+
}
|
|
26804
|
+
} catch (error2) {
|
|
26805
|
+
console.warn("[BottlenecksContent] Failed to load metadata for current video:", error2);
|
|
26806
|
+
}
|
|
26807
|
+
}
|
|
26808
|
+
}, [currentVideo, s3ClipsService]);
|
|
26945
26809
|
const handleVideoPause = React19.useCallback((player) => {
|
|
26946
26810
|
setIsPlaying(false);
|
|
26947
26811
|
}, []);
|
|
@@ -26968,13 +26832,6 @@ var BottlenecksContent = ({
|
|
|
26968
26832
|
fetchInProgressRef.current.clear();
|
|
26969
26833
|
setIsCategoryLoading(false);
|
|
26970
26834
|
setIsNavigating(false);
|
|
26971
|
-
if (s3ClipsService) {
|
|
26972
|
-
try {
|
|
26973
|
-
s3ClipsService.dispose();
|
|
26974
|
-
} catch (error2) {
|
|
26975
|
-
console.warn("[BottlenecksContent] Error disposing S3 service:", error2);
|
|
26976
|
-
}
|
|
26977
|
-
}
|
|
26978
26835
|
};
|
|
26979
26836
|
}, [s3ClipsService]);
|
|
26980
26837
|
React19.useEffect(() => {
|
|
@@ -27015,12 +26872,6 @@ var BottlenecksContent = ({
|
|
|
27015
26872
|
counts.bottlenecks = counts.bottleneck || counts.bottlenecks || 0;
|
|
27016
26873
|
return counts;
|
|
27017
26874
|
}, [clipCounts]);
|
|
27018
|
-
const currentVideo = React19.useMemo(() => {
|
|
27019
|
-
if (!filteredVideos || filteredVideos.length === 0 || currentIndex >= filteredVideos.length) {
|
|
27020
|
-
return null;
|
|
27021
|
-
}
|
|
27022
|
-
return filteredVideos[currentIndex];
|
|
27023
|
-
}, [filteredVideos, currentIndex]);
|
|
27024
26875
|
const getClipTypeLabel = (video) => {
|
|
27025
26876
|
if (!video) return "";
|
|
27026
26877
|
switch (video.type) {
|
|
@@ -27255,8 +27106,8 @@ var BottlenecksContent = ({
|
|
|
27255
27106
|
] }),
|
|
27256
27107
|
/* Priority 1: Show loading if initial load hasn't completed yet */
|
|
27257
27108
|
isLoading && !hasInitialLoad ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-4 h-[calc(100%-4rem)]", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative h-full", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative w-full h-full overflow-hidden rounded-md shadow-inner bg-gray-900 flex items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(OptifyeLogoLoader_default, { size: "md", message: "Loading clips..." }) }) }) }) : (
|
|
27258
|
-
/* Priority 2: Show loading if category is loading
|
|
27259
|
-
isCategoryLoading ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-4 h-[calc(100%-4rem)]", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative h-full", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative w-full h-full overflow-hidden rounded-md shadow-inner bg-gray-900 flex items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(OptifyeLogoLoader_default, { size: "md", message: "Loading videos..." }) }) }) }) : (
|
|
27109
|
+
/* Priority 2: Show loading if category is loading BUT only if no video is available */
|
|
27110
|
+
isCategoryLoading && (!filteredVideos.length || !currentVideo) ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-4 h-[calc(100%-4rem)]", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative h-full", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative w-full h-full overflow-hidden rounded-md shadow-inner bg-gray-900 flex items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(OptifyeLogoLoader_default, { size: "md", message: "Loading videos..." }) }) }) }) : (
|
|
27260
27111
|
/* Priority 3: Show loading if navigating and current video not available */
|
|
27261
27112
|
isNavigating || currentIndex >= filteredVideos.length && currentIndex < clipCounts[activeFilter] ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-4 h-[calc(100%-4rem)]", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative h-full", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative w-full h-full overflow-hidden rounded-md shadow-inner bg-gray-900 flex items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(OptifyeLogoLoader_default, { size: "md", message: "Loading video..." }) }) }) }) : (
|
|
27262
27113
|
/* Priority 4: Show video if we have filtered videos and current video */
|
|
@@ -32054,9 +31905,25 @@ function withWorkspaceDisplayNames(Component3, options = {}) {
|
|
|
32054
31905
|
return function WithWorkspaceDisplayNamesWrapper(props) {
|
|
32055
31906
|
const [isInitialized2, setIsInitialized] = React19.useState(false);
|
|
32056
31907
|
const [error, setError] = React19.useState(null);
|
|
31908
|
+
const [lastInitKey, setLastInitKey] = React19.useState("");
|
|
31909
|
+
const lineIdsKey = React19.useMemo(() => {
|
|
31910
|
+
if (!props.lineIds) return "";
|
|
31911
|
+
if (Array.isArray(props.lineIds)) {
|
|
31912
|
+
return props.lineIds.sort().join(",");
|
|
31913
|
+
}
|
|
31914
|
+
const values = Object.values(props.lineIds).filter(Boolean);
|
|
31915
|
+
return values.sort().join(",");
|
|
31916
|
+
}, [props.lineIds]);
|
|
31917
|
+
const initKey = React19.useMemo(() => {
|
|
31918
|
+
return `${lineIdsKey}-${props.selectedLineId || ""}-${props.factoryViewId || ""}-${initializeFor}`;
|
|
31919
|
+
}, [lineIdsKey, props.selectedLineId, props.factoryViewId]);
|
|
32057
31920
|
React19.useEffect(() => {
|
|
32058
|
-
|
|
32059
|
-
|
|
31921
|
+
if (initKey === lastInitKey && isInitialized2) {
|
|
31922
|
+
return;
|
|
31923
|
+
}
|
|
31924
|
+
if (initKey !== lastInitKey) {
|
|
31925
|
+
setError(null);
|
|
31926
|
+
}
|
|
32060
31927
|
const initializeDisplayNames = async () => {
|
|
32061
31928
|
try {
|
|
32062
31929
|
const { lineIds, selectedLineId, factoryViewId } = props;
|
|
@@ -32082,20 +31949,17 @@ function withWorkspaceDisplayNames(Component3, options = {}) {
|
|
|
32082
31949
|
await preInitializeWorkspaceDisplayNames();
|
|
32083
31950
|
}
|
|
32084
31951
|
setIsInitialized(true);
|
|
31952
|
+
setLastInitKey(initKey);
|
|
32085
31953
|
} catch (err) {
|
|
32086
31954
|
console.error("Failed to initialize workspace display names:", err);
|
|
32087
31955
|
setError(err);
|
|
32088
31956
|
setIsInitialized(true);
|
|
31957
|
+
setLastInitKey(initKey);
|
|
32089
31958
|
}
|
|
32090
31959
|
};
|
|
32091
31960
|
initializeDisplayNames();
|
|
32092
|
-
}, [
|
|
32093
|
-
|
|
32094
|
-
props.selectedLineId,
|
|
32095
|
-
props.factoryViewId,
|
|
32096
|
-
initializeFor
|
|
32097
|
-
]);
|
|
32098
|
-
if (!isInitialized2 && showLoading) {
|
|
31961
|
+
}, [initKey]);
|
|
31962
|
+
if (!isInitialized2 && showLoading && lastInitKey === "") {
|
|
32099
31963
|
return /* @__PURE__ */ jsxRuntime.jsx(LoadingPage, { message: loadingMessage });
|
|
32100
31964
|
}
|
|
32101
31965
|
if (error && showLoading) {
|
|
@@ -34166,7 +34030,15 @@ var ShiftsView = ({
|
|
|
34166
34030
|
className = ""
|
|
34167
34031
|
}) => {
|
|
34168
34032
|
const supabase = useSupabase();
|
|
34169
|
-
|
|
34033
|
+
React19.useEffect(() => {
|
|
34034
|
+
console.log("[ShiftsView] Component mounted/re-rendered", {
|
|
34035
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
34036
|
+
lineIds: lineIds.length
|
|
34037
|
+
});
|
|
34038
|
+
return () => {
|
|
34039
|
+
console.log("[ShiftsView] Component unmounting");
|
|
34040
|
+
};
|
|
34041
|
+
}, []);
|
|
34170
34042
|
const [lineConfigs, setLineConfigs] = React19.useState(
|
|
34171
34043
|
() => lineIds.map((id3) => ({
|
|
34172
34044
|
id: id3,
|
|
@@ -34264,7 +34136,7 @@ var ShiftsView = ({
|
|
|
34264
34136
|
}
|
|
34265
34137
|
};
|
|
34266
34138
|
fetchShiftConfigs();
|
|
34267
|
-
}, [
|
|
34139
|
+
}, [lineIds, showToast]);
|
|
34268
34140
|
React19.useCallback((lineId) => {
|
|
34269
34141
|
setLineConfigs((prev) => {
|
|
34270
34142
|
const typedPrev = prev;
|
|
@@ -34457,7 +34329,6 @@ var ShiftsView = ({
|
|
|
34457
34329
|
}));
|
|
34458
34330
|
}, []);
|
|
34459
34331
|
const handleSaveShifts = React19.useCallback(async (lineId) => {
|
|
34460
|
-
if (!auth.user?.id && false) ;
|
|
34461
34332
|
setLineConfigs((prev) => prev.map(
|
|
34462
34333
|
(config) => config.id === lineId ? { ...config, isSaving: true, saveSuccess: false } : config
|
|
34463
34334
|
));
|
|
@@ -34504,7 +34375,7 @@ var ShiftsView = ({
|
|
|
34504
34375
|
(config) => config.id === lineId ? { ...config, isSaving: false, saveSuccess: false } : config
|
|
34505
34376
|
));
|
|
34506
34377
|
}
|
|
34507
|
-
}, [
|
|
34378
|
+
}, [lineConfigs, supabase, showToast]);
|
|
34508
34379
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `min-h-screen bg-slate-50 ${className}`, children: [
|
|
34509
34380
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "sticky top-0 z-10 bg-white border-b border-gray-200/80 shadow-sm", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-4 sm:px-8 py-4", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center relative", children: [
|
|
34510
34381
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
@@ -34612,6 +34483,7 @@ var ShiftsView = ({
|
|
|
34612
34483
|
] })
|
|
34613
34484
|
] });
|
|
34614
34485
|
};
|
|
34486
|
+
var AuthenticatedShiftsView = withAuth(React19__namespace.default.memo(ShiftsView));
|
|
34615
34487
|
var ShiftsView_default = ShiftsView;
|
|
34616
34488
|
|
|
34617
34489
|
// src/lib/constants/actions.ts
|
|
@@ -35399,6 +35271,7 @@ var TargetsViewUI = ({
|
|
|
35399
35271
|
isLoading,
|
|
35400
35272
|
lineWorkspaces,
|
|
35401
35273
|
lineNames,
|
|
35274
|
+
dropdownStates,
|
|
35402
35275
|
savingLines,
|
|
35403
35276
|
saveSuccess,
|
|
35404
35277
|
selectedShift,
|
|
@@ -35484,13 +35357,13 @@ var TargetsViewUI = ({
|
|
|
35484
35357
|
{
|
|
35485
35358
|
onClick: () => onToggleLineDropdown(lineId),
|
|
35486
35359
|
className: "flex items-center gap-3 text-lg font-medium transition-colors duration-200 \n focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 rounded-lg \n hover:bg-blue-50 px-3 py-2 group",
|
|
35487
|
-
"aria-expanded":
|
|
35360
|
+
"aria-expanded": dropdownStates[lineId],
|
|
35488
35361
|
"aria-controls": `line-${lineId}-content`,
|
|
35489
35362
|
children: [
|
|
35490
35363
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
35491
35364
|
lucideReact.ChevronDown,
|
|
35492
35365
|
{
|
|
35493
|
-
className: `w-5 h-5 text-blue-500 transform transition-transform duration-200 ${
|
|
35366
|
+
className: `w-5 h-5 text-blue-500 transform transition-transform duration-200 ${dropdownStates[lineId] ? "rotate-180" : ""}`
|
|
35494
35367
|
}
|
|
35495
35368
|
),
|
|
35496
35369
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2.5", children: [
|
|
@@ -35537,7 +35410,7 @@ var TargetsViewUI = ({
|
|
|
35537
35410
|
)
|
|
35538
35411
|
] })
|
|
35539
35412
|
] }) }),
|
|
35540
|
-
|
|
35413
|
+
dropdownStates[lineId] && /* @__PURE__ */ jsxRuntime.jsxs("div", { id: `line-${lineId}-content`, className: "border-t border-gray-200", children: [
|
|
35541
35414
|
skuEnabled && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-6 py-4 border-b border-gray-200 bg-gray-50/50", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-4", children: [
|
|
35542
35415
|
/* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: `sku-${lineId}`, className: "text-sm font-medium text-gray-700", children: "Select SKU:" }),
|
|
35543
35416
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 max-w-md", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -35574,68 +35447,71 @@ var TargetsViewUI = ({
|
|
|
35574
35447
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-gray-400", children: "pieces per day" })
|
|
35575
35448
|
] })
|
|
35576
35449
|
] }) }),
|
|
35577
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "divide-y divide-gray-100", children: line.workspaces.map((workspace) =>
|
|
35578
|
-
|
|
35579
|
-
|
|
35580
|
-
|
|
35581
|
-
|
|
35582
|
-
|
|
35583
|
-
/* @__PURE__ */ jsxRuntime.
|
|
35584
|
-
"
|
|
35585
|
-
{
|
|
35586
|
-
|
|
35587
|
-
|
|
35588
|
-
|
|
35589
|
-
|
|
35590
|
-
|
|
35591
|
-
|
|
35592
|
-
|
|
35593
|
-
|
|
35594
|
-
|
|
35595
|
-
|
|
35596
|
-
|
|
35597
|
-
|
|
35598
|
-
|
|
35599
|
-
|
|
35600
|
-
|
|
35601
|
-
{
|
|
35602
|
-
|
|
35603
|
-
|
|
35604
|
-
|
|
35605
|
-
|
|
35606
|
-
|
|
35607
|
-
|
|
35608
|
-
|
|
35609
|
-
|
|
35610
|
-
|
|
35611
|
-
|
|
35612
|
-
|
|
35613
|
-
{
|
|
35614
|
-
|
|
35615
|
-
|
|
35616
|
-
|
|
35617
|
-
|
|
35618
|
-
|
|
35619
|
-
|
|
35620
|
-
|
|
35621
|
-
|
|
35622
|
-
|
|
35623
|
-
|
|
35624
|
-
|
|
35625
|
-
{
|
|
35626
|
-
|
|
35627
|
-
|
|
35628
|
-
|
|
35629
|
-
|
|
35630
|
-
|
|
35631
|
-
|
|
35632
|
-
|
|
35633
|
-
|
|
35634
|
-
|
|
35635
|
-
|
|
35636
|
-
|
|
35637
|
-
|
|
35638
|
-
|
|
35450
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "divide-y divide-gray-100", children: line.workspaces.map((workspace) => {
|
|
35451
|
+
const formattedName = formatWorkspaceName(workspace.name, lineId);
|
|
35452
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
35453
|
+
"div",
|
|
35454
|
+
{
|
|
35455
|
+
className: "px-6 py-4 hover:bg-gray-50 transition-all duration-200",
|
|
35456
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-12 gap-6 items-center", children: [
|
|
35457
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "col-span-2", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium text-gray-900", children: formattedName }) }),
|
|
35458
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "col-span-2", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
35459
|
+
"select",
|
|
35460
|
+
{
|
|
35461
|
+
value: workspace.actionType,
|
|
35462
|
+
onChange: (e) => {
|
|
35463
|
+
const newActionType = e.target.value;
|
|
35464
|
+
onActionTypeChange(lineId, workspace.id, newActionType);
|
|
35465
|
+
},
|
|
35466
|
+
className: "w-full p-2 border border-gray-300 rounded-md shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm",
|
|
35467
|
+
"aria-label": `Action type for ${formattedName}`,
|
|
35468
|
+
children: [
|
|
35469
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "assembly", className: "py-2", children: "Assembly" }),
|
|
35470
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "packaging", className: "py-2", children: "Packaging" })
|
|
35471
|
+
]
|
|
35472
|
+
}
|
|
35473
|
+
) }),
|
|
35474
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "col-span-3", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
35475
|
+
"input",
|
|
35476
|
+
{
|
|
35477
|
+
type: "number",
|
|
35478
|
+
value: workspace.targetCycleTime === 0 ? "" : workspace.targetCycleTime,
|
|
35479
|
+
onChange: (e) => onUpdateWorkspaceTarget(lineId, workspace.id, "targetCycleTime", Number(e.target.value) || ""),
|
|
35480
|
+
className: "block w-full rounded-lg border border-gray-300 bg-white px-3 py-2 text-sm\n shadow-sm focus:border-blue-500 focus:ring-blue-500 \n transition-all duration-200 hover:border-gray-400",
|
|
35481
|
+
min: "0",
|
|
35482
|
+
step: "0.01",
|
|
35483
|
+
placeholder: "Enter cycle time"
|
|
35484
|
+
}
|
|
35485
|
+
) }),
|
|
35486
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "col-span-3", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
35487
|
+
"input",
|
|
35488
|
+
{
|
|
35489
|
+
type: "number",
|
|
35490
|
+
value: workspace.targetPPH === 0 ? "" : workspace.targetPPH,
|
|
35491
|
+
onChange: (e) => onUpdateWorkspaceTarget(lineId, workspace.id, "targetPPH", Number(e.target.value) || ""),
|
|
35492
|
+
className: "block w-full rounded-lg border border-gray-300 bg-white px-3 py-2 text-sm\n shadow-sm focus:border-blue-500 focus:ring-blue-500 \n transition-all duration-200 hover:border-gray-400 \n placeholder:text-gray-400",
|
|
35493
|
+
min: "0",
|
|
35494
|
+
step: "0.1",
|
|
35495
|
+
placeholder: "Enter PPH"
|
|
35496
|
+
}
|
|
35497
|
+
) }),
|
|
35498
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "col-span-2", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
35499
|
+
"input",
|
|
35500
|
+
{
|
|
35501
|
+
type: "number",
|
|
35502
|
+
value: workspace.targetDayOutput === 0 ? "" : workspace.targetDayOutput,
|
|
35503
|
+
onChange: (e) => onUpdateWorkspaceTarget(lineId, workspace.id, "targetDayOutput", Number(e.target.value) || ""),
|
|
35504
|
+
className: "block w-full rounded-lg border border-gray-300 bg-white px-3 py-2 text-sm\n shadow-sm focus:border-blue-500 focus:ring-blue-500 \n transition-all duration-200 hover:border-gray-400 \n placeholder:text-gray-400",
|
|
35505
|
+
min: "0",
|
|
35506
|
+
step: "1",
|
|
35507
|
+
placeholder: "Enter day output"
|
|
35508
|
+
}
|
|
35509
|
+
) })
|
|
35510
|
+
] })
|
|
35511
|
+
},
|
|
35512
|
+
workspace.id
|
|
35513
|
+
);
|
|
35514
|
+
}) })
|
|
35639
35515
|
] })
|
|
35640
35516
|
]
|
|
35641
35517
|
},
|
|
@@ -35668,7 +35544,6 @@ var TargetsView = ({
|
|
|
35668
35544
|
return lineIds.reduce((acc, lineId) => ({
|
|
35669
35545
|
...acc,
|
|
35670
35546
|
[lineId]: {
|
|
35671
|
-
isOpen: getStoredLineState2(lineId),
|
|
35672
35547
|
productId: "",
|
|
35673
35548
|
shiftStartTime: "08:00",
|
|
35674
35549
|
shiftEndTime: "19:00",
|
|
@@ -35681,6 +35556,12 @@ var TargetsView = ({
|
|
|
35681
35556
|
}
|
|
35682
35557
|
}), {});
|
|
35683
35558
|
}, [lineIds]);
|
|
35559
|
+
const [dropdownStates, setDropdownStates] = React19.useState(() => {
|
|
35560
|
+
return lineIds.reduce((acc, lineId) => ({
|
|
35561
|
+
...acc,
|
|
35562
|
+
[lineId]: getStoredLineState2(lineId)
|
|
35563
|
+
}), {});
|
|
35564
|
+
});
|
|
35684
35565
|
const [allShiftsData, setAllShiftsData] = React19.useState({
|
|
35685
35566
|
0: initialLineWorkspaces,
|
|
35686
35567
|
// Day shift
|
|
@@ -35698,6 +35579,8 @@ var TargetsView = ({
|
|
|
35698
35579
|
const [isBulkConfigureOpen, setIsBulkConfigureOpen] = React19.useState(false);
|
|
35699
35580
|
const [selectedWorkspaces, setSelectedWorkspaces] = React19.useState([]);
|
|
35700
35581
|
const [selectedShift, setSelectedShift] = React19.useState(0);
|
|
35582
|
+
const [dbValues, setDbValues] = React19.useState({ 0: {}, 1: {} });
|
|
35583
|
+
const [userEditedFields, setUserEditedFields] = React19.useState(/* @__PURE__ */ new Set());
|
|
35701
35584
|
const lineWorkspaces = allShiftsData[selectedShift] || initialLineWorkspaces;
|
|
35702
35585
|
const setLineWorkspaces = React19.useCallback((updater) => {
|
|
35703
35586
|
setAllShiftsData((prev) => ({
|
|
@@ -35706,18 +35589,123 @@ var TargetsView = ({
|
|
|
35706
35589
|
}));
|
|
35707
35590
|
}, [selectedShift]);
|
|
35708
35591
|
const supabase = useSupabase();
|
|
35709
|
-
const
|
|
35710
|
-
userId || auth?.user?.id;
|
|
35592
|
+
const effectiveUserId = userId || "6bf6f271-1e55-4a95-9b89-1c3820b58739";
|
|
35711
35593
|
const dashboardConfig = useDashboardConfig();
|
|
35712
35594
|
const { skus, isLoading: skusLoading } = useSKUs(companyId);
|
|
35713
35595
|
const skuEnabled = dashboardConfig?.skuConfig?.enabled || false;
|
|
35596
|
+
const loadOperatingHours = React19.useCallback(async (lineId, shiftId) => {
|
|
35597
|
+
try {
|
|
35598
|
+
if (!supabase) return null;
|
|
35599
|
+
const { data, error } = await supabase.from("line_operating_hours").select("start_time, end_time, breaks").eq("line_id", lineId).eq("shift_id", shiftId).maybeSingle();
|
|
35600
|
+
if (error) {
|
|
35601
|
+
if (error.code === "PGRST116") {
|
|
35602
|
+
console.log(`No operating hours found for line ${lineId}, shift ${shiftId}`);
|
|
35603
|
+
return {
|
|
35604
|
+
startTime: "08:00",
|
|
35605
|
+
// Default values
|
|
35606
|
+
endTime: "19:00",
|
|
35607
|
+
breaks: []
|
|
35608
|
+
};
|
|
35609
|
+
} else {
|
|
35610
|
+
console.error("Error fetching operating hours:", error);
|
|
35611
|
+
return null;
|
|
35612
|
+
}
|
|
35613
|
+
}
|
|
35614
|
+
let breaks = [];
|
|
35615
|
+
if (data?.breaks) {
|
|
35616
|
+
if (Array.isArray(data.breaks)) {
|
|
35617
|
+
breaks = data.breaks.map((breakItem) => {
|
|
35618
|
+
const startTime = breakItem.start || breakItem.startTime || "00:00";
|
|
35619
|
+
const endTime = breakItem.end || breakItem.endTime || "00:00";
|
|
35620
|
+
const calculateDuration = (start, end) => {
|
|
35621
|
+
const [startHour, startMinute] = start.split(":").map(Number);
|
|
35622
|
+
const [endHour, endMinute] = end.split(":").map(Number);
|
|
35623
|
+
let startMinutes = startHour * 60 + startMinute;
|
|
35624
|
+
let endMinutes = endHour * 60 + endMinute;
|
|
35625
|
+
if (endMinutes < startMinutes) {
|
|
35626
|
+
endMinutes += 24 * 60;
|
|
35627
|
+
}
|
|
35628
|
+
return endMinutes - startMinutes;
|
|
35629
|
+
};
|
|
35630
|
+
return {
|
|
35631
|
+
startTime,
|
|
35632
|
+
endTime,
|
|
35633
|
+
duration: breakItem.duration || calculateDuration(startTime, endTime)
|
|
35634
|
+
};
|
|
35635
|
+
});
|
|
35636
|
+
} else if (typeof data.breaks === "object" && data.breaks.breaks) {
|
|
35637
|
+
breaks = data.breaks.breaks.map((breakItem) => {
|
|
35638
|
+
const startTime = breakItem.start || breakItem.startTime || "00:00";
|
|
35639
|
+
const endTime = breakItem.end || breakItem.endTime || "00:00";
|
|
35640
|
+
const calculateDuration = (start, end) => {
|
|
35641
|
+
const [startHour, startMinute] = start.split(":").map(Number);
|
|
35642
|
+
const [endHour, endMinute] = end.split(":").map(Number);
|
|
35643
|
+
let startMinutes = startHour * 60 + startMinute;
|
|
35644
|
+
let endMinutes = endHour * 60 + endMinute;
|
|
35645
|
+
if (endMinutes < startMinutes) {
|
|
35646
|
+
endMinutes += 24 * 60;
|
|
35647
|
+
}
|
|
35648
|
+
return endMinutes - startMinutes;
|
|
35649
|
+
};
|
|
35650
|
+
return {
|
|
35651
|
+
startTime,
|
|
35652
|
+
endTime,
|
|
35653
|
+
duration: breakItem.duration || calculateDuration(startTime, endTime)
|
|
35654
|
+
};
|
|
35655
|
+
});
|
|
35656
|
+
} else if (typeof data.breaks === "string") {
|
|
35657
|
+
try {
|
|
35658
|
+
const parsedBreaks = JSON.parse(data.breaks);
|
|
35659
|
+
if (Array.isArray(parsedBreaks)) {
|
|
35660
|
+
breaks = parsedBreaks.map((breakItem) => ({
|
|
35661
|
+
startTime: breakItem.start || breakItem.startTime || "00:00",
|
|
35662
|
+
endTime: breakItem.end || breakItem.endTime || "00:00",
|
|
35663
|
+
duration: breakItem.duration || 0
|
|
35664
|
+
}));
|
|
35665
|
+
} else if (parsedBreaks.breaks && Array.isArray(parsedBreaks.breaks)) {
|
|
35666
|
+
breaks = parsedBreaks.breaks.map((breakItem) => ({
|
|
35667
|
+
startTime: breakItem.start || breakItem.startTime || "00:00",
|
|
35668
|
+
endTime: breakItem.end || breakItem.endTime || "00:00",
|
|
35669
|
+
duration: breakItem.duration || 0
|
|
35670
|
+
}));
|
|
35671
|
+
}
|
|
35672
|
+
} catch (e) {
|
|
35673
|
+
console.error("Error parsing breaks data:", e);
|
|
35674
|
+
}
|
|
35675
|
+
}
|
|
35676
|
+
}
|
|
35677
|
+
return {
|
|
35678
|
+
startTime: data?.start_time || "08:00",
|
|
35679
|
+
endTime: data?.end_time || "19:00",
|
|
35680
|
+
breaks
|
|
35681
|
+
};
|
|
35682
|
+
} catch (e) {
|
|
35683
|
+
console.error("Exception when loading operating hours:", e);
|
|
35684
|
+
return {
|
|
35685
|
+
startTime: "08:00",
|
|
35686
|
+
endTime: "19:00",
|
|
35687
|
+
breaks: []
|
|
35688
|
+
};
|
|
35689
|
+
}
|
|
35690
|
+
}, [supabase]);
|
|
35691
|
+
React19.useEffect(() => {
|
|
35692
|
+
console.log("[TargetsView] Component mounted/re-rendered", {
|
|
35693
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
35694
|
+
lineIds: lineIds.length,
|
|
35695
|
+
effectiveUserId
|
|
35696
|
+
});
|
|
35697
|
+
return () => {
|
|
35698
|
+
console.log("[TargetsView] Component unmounting");
|
|
35699
|
+
};
|
|
35700
|
+
}, []);
|
|
35714
35701
|
React19.useEffect(() => {
|
|
35715
35702
|
let timeoutId;
|
|
35716
35703
|
let retryCount = 0;
|
|
35717
35704
|
const MAX_RETRIES2 = 2;
|
|
35718
35705
|
const LOADING_TIMEOUT = 15e3;
|
|
35719
35706
|
const fetchInitialData = async () => {
|
|
35720
|
-
if (
|
|
35707
|
+
if (lineIds.length === 0) return;
|
|
35708
|
+
console.log("[TargetsView] Starting fetchInitialData");
|
|
35721
35709
|
setIsLoading(true);
|
|
35722
35710
|
timeoutId = setTimeout(() => {
|
|
35723
35711
|
console.error("Loading timeout reached");
|
|
@@ -35781,10 +35769,32 @@ var TargetsView = ({
|
|
|
35781
35769
|
const actionThresholds = await workspaceService.getActionThresholds(
|
|
35782
35770
|
lineId,
|
|
35783
35771
|
currentDate,
|
|
35784
|
-
|
|
35772
|
+
0
|
|
35773
|
+
// Always use day shift for initial load
|
|
35785
35774
|
);
|
|
35775
|
+
const operatingHoursData = await loadOperatingHours(lineId, 0);
|
|
35776
|
+
if (operatingHoursData) {
|
|
35777
|
+
updatedLineWorkspaces[lineId].shiftStartTime = operatingHoursData.startTime;
|
|
35778
|
+
updatedLineWorkspaces[lineId].shiftEndTime = operatingHoursData.endTime;
|
|
35779
|
+
updatedLineWorkspaces[lineId].breaks = operatingHoursData.breaks;
|
|
35780
|
+
updatedLineWorkspaces[lineId].shiftHours = calculateShiftHours2(
|
|
35781
|
+
operatingHoursData.startTime,
|
|
35782
|
+
operatingHoursData.endTime,
|
|
35783
|
+
operatingHoursData.breaks
|
|
35784
|
+
);
|
|
35785
|
+
}
|
|
35786
35786
|
const mappedWorkspaces = enabledWorkspaces.map((ws) => {
|
|
35787
35787
|
const threshold = actionThresholds.find((t) => t.workspace_id === ws.id);
|
|
35788
|
+
if (!dbValues[0][lineId]) {
|
|
35789
|
+
dbValues[0][lineId] = {};
|
|
35790
|
+
}
|
|
35791
|
+
if (threshold) {
|
|
35792
|
+
dbValues[0][lineId][ws.id] = {
|
|
35793
|
+
targetPPH: threshold.pph_threshold,
|
|
35794
|
+
targetCycleTime: threshold.ideal_cycle_time,
|
|
35795
|
+
targetDayOutput: threshold.total_day_output
|
|
35796
|
+
};
|
|
35797
|
+
}
|
|
35788
35798
|
return {
|
|
35789
35799
|
id: ws.id,
|
|
35790
35800
|
name: ws.workspace_id,
|
|
@@ -35825,90 +35835,7 @@ var TargetsView = ({
|
|
|
35825
35835
|
return () => {
|
|
35826
35836
|
clearTimeout(timeoutId);
|
|
35827
35837
|
};
|
|
35828
|
-
}, [
|
|
35829
|
-
React19.useCallback(async (shiftId) => {
|
|
35830
|
-
try {
|
|
35831
|
-
if (!supabase) return;
|
|
35832
|
-
const currentDate = getOperationalDate();
|
|
35833
|
-
const updatedLineWorkspaces = { ...lineWorkspaces };
|
|
35834
|
-
let hasUpdates = false;
|
|
35835
|
-
for (const lineId of lineIds) {
|
|
35836
|
-
const lineState = lineWorkspaces[lineId];
|
|
35837
|
-
if (!lineState || !lineState.factoryId) {
|
|
35838
|
-
console.warn(`Skipping line thresholds for ${lineId} as factoryId is not yet available.`);
|
|
35839
|
-
continue;
|
|
35840
|
-
}
|
|
35841
|
-
const currentFactoryId = lineState.factoryId;
|
|
35842
|
-
try {
|
|
35843
|
-
const { data: lineThresholdsRows, error: thresholdError } = await supabase.from("line_thresholds").select("product_code").eq("line_id", lineId).eq("date", currentDate).eq("shift_id", selectedShift).eq("factory_id", currentFactoryId);
|
|
35844
|
-
if (thresholdError) {
|
|
35845
|
-
console.error(`Error fetching line threshold for line ${lineId}, factory ${currentFactoryId}:`, thresholdError);
|
|
35846
|
-
continue;
|
|
35847
|
-
}
|
|
35848
|
-
let determinedProductId = updatedLineWorkspaces[lineId]?.productId || "";
|
|
35849
|
-
if (lineThresholdsRows && lineThresholdsRows.length > 0) {
|
|
35850
|
-
if (lineThresholdsRows.length > 1) {
|
|
35851
|
-
console.warn(
|
|
35852
|
-
`Multiple line_thresholds records found for line ${lineId}, factory ${currentFactoryId}, date ${currentDate}, shift ${selectedShift}. Using product_code from the first record. Rows:`,
|
|
35853
|
-
lineThresholdsRows
|
|
35854
|
-
);
|
|
35855
|
-
}
|
|
35856
|
-
determinedProductId = lineThresholdsRows[0].product_code;
|
|
35857
|
-
} else {
|
|
35858
|
-
console.log(
|
|
35859
|
-
`No line_thresholds record found for line ${lineId}, factory ${currentFactoryId}, date ${currentDate}, shift ${selectedShift}. Using existing/default product ID.`
|
|
35860
|
-
);
|
|
35861
|
-
}
|
|
35862
|
-
const { data: operatingHours, error: hoursError } = await supabase.from("line_operating_hours").select("start_time, end_time, breaks").eq("line_id", lineId).eq("shift_id", selectedShift).maybeSingle();
|
|
35863
|
-
if (hoursError) {
|
|
35864
|
-
console.error(`Error fetching operating hours for line ${lineId}:`, hoursError);
|
|
35865
|
-
continue;
|
|
35866
|
-
}
|
|
35867
|
-
const startTime = operatingHours?.start_time || updatedLineWorkspaces[lineId]?.shiftStartTime || "08:00";
|
|
35868
|
-
const endTime = operatingHours?.end_time || updatedLineWorkspaces[lineId]?.shiftEndTime || "19:00";
|
|
35869
|
-
let breaks = [];
|
|
35870
|
-
if (operatingHours?.breaks) {
|
|
35871
|
-
if (Array.isArray(operatingHours.breaks)) {
|
|
35872
|
-
breaks = operatingHours.breaks.map((breakItem) => ({
|
|
35873
|
-
startTime: breakItem.start || breakItem.startTime || "00:00",
|
|
35874
|
-
endTime: breakItem.end || breakItem.endTime || "00:00",
|
|
35875
|
-
duration: breakItem.duration || calculateShiftHours2(breakItem.start || breakItem.startTime || "00:00", breakItem.end || breakItem.endTime || "00:00", []) * 60
|
|
35876
|
-
}));
|
|
35877
|
-
} else if (typeof operatingHours.breaks === "object" && operatingHours.breaks.breaks) {
|
|
35878
|
-
breaks = operatingHours.breaks.breaks.map((breakItem) => ({
|
|
35879
|
-
startTime: breakItem.start || breakItem.startTime || "00:00",
|
|
35880
|
-
endTime: breakItem.end || breakItem.endTime || "00:00",
|
|
35881
|
-
duration: breakItem.duration || calculateShiftHours2(breakItem.start || breakItem.startTime || "00:00", breakItem.end || breakItem.endTime || "00:00", []) * 60
|
|
35882
|
-
}));
|
|
35883
|
-
}
|
|
35884
|
-
}
|
|
35885
|
-
const shiftHours = calculateShiftHours2(startTime, endTime, breaks);
|
|
35886
|
-
const currentLineStateFromLoop = updatedLineWorkspaces[lineId];
|
|
35887
|
-
if (determinedProductId !== currentLineStateFromLoop?.productId || startTime !== currentLineStateFromLoop?.shiftStartTime || endTime !== currentLineStateFromLoop?.shiftEndTime || shiftHours !== currentLineStateFromLoop?.shiftHours || JSON.stringify(breaks) !== JSON.stringify(currentLineStateFromLoop?.breaks)) {
|
|
35888
|
-
updatedLineWorkspaces[lineId] = {
|
|
35889
|
-
...currentLineStateFromLoop || {},
|
|
35890
|
-
factoryId: currentFactoryId,
|
|
35891
|
-
// Ensure factoryId is preserved
|
|
35892
|
-
productId: determinedProductId,
|
|
35893
|
-
shiftStartTime: startTime,
|
|
35894
|
-
shiftEndTime: endTime,
|
|
35895
|
-
breaks,
|
|
35896
|
-
shiftHours: Number(shiftHours),
|
|
35897
|
-
workspaces: currentLineStateFromLoop?.workspaces || []
|
|
35898
|
-
};
|
|
35899
|
-
hasUpdates = true;
|
|
35900
|
-
}
|
|
35901
|
-
} catch (lineError) {
|
|
35902
|
-
console.error(`Error processing line ${lineId}:`, lineError);
|
|
35903
|
-
}
|
|
35904
|
-
}
|
|
35905
|
-
if (hasUpdates) {
|
|
35906
|
-
setLineWorkspaces(updatedLineWorkspaces);
|
|
35907
|
-
}
|
|
35908
|
-
} catch (error) {
|
|
35909
|
-
console.error("Error in fetchLineThresholds outer try-catch:", error);
|
|
35910
|
-
}
|
|
35911
|
-
}, [selectedShift, supabase, lineIds, lineWorkspaces, allShiftsData]);
|
|
35838
|
+
}, [lineIds, companyId, loadOperatingHours]);
|
|
35912
35839
|
const fetchAllShiftsData = React19.useCallback(async (currentWorkspaces) => {
|
|
35913
35840
|
if (!supabase) return;
|
|
35914
35841
|
const currentDate = getOperationalDate();
|
|
@@ -35918,32 +35845,25 @@ var TargetsView = ({
|
|
|
35918
35845
|
1: JSON.parse(JSON.stringify(currentWorkspaces))
|
|
35919
35846
|
// Deep clone for night shift
|
|
35920
35847
|
};
|
|
35848
|
+
const newDbValues = { 0: {}, 1: {} };
|
|
35921
35849
|
for (const shiftId of [0, 1]) {
|
|
35922
35850
|
for (const lineId of lineIds) {
|
|
35923
35851
|
try {
|
|
35924
|
-
const
|
|
35925
|
-
if (
|
|
35926
|
-
console.
|
|
35852
|
+
const operatingHoursData = await loadOperatingHours(lineId, shiftId);
|
|
35853
|
+
if (!operatingHoursData) {
|
|
35854
|
+
console.warn(`No operating hours for line ${lineId}, shift ${shiftId} - using defaults`);
|
|
35927
35855
|
continue;
|
|
35928
35856
|
}
|
|
35929
|
-
|
|
35930
|
-
if (operatingHours?.breaks) {
|
|
35931
|
-
if (Array.isArray(operatingHours.breaks)) {
|
|
35932
|
-
breaks = operatingHours.breaks.map((breakItem) => ({
|
|
35933
|
-
startTime: breakItem.start || breakItem.startTime || "00:00",
|
|
35934
|
-
endTime: breakItem.end || breakItem.endTime || "00:00",
|
|
35935
|
-
duration: breakItem.duration || calculateShiftHours2(breakItem.start || breakItem.startTime || "00:00", breakItem.end || breakItem.endTime || "00:00", []) * 60
|
|
35936
|
-
}));
|
|
35937
|
-
}
|
|
35938
|
-
}
|
|
35939
|
-
const startTime = operatingHours?.start_time || "08:00";
|
|
35940
|
-
const endTime = operatingHours?.end_time || "19:00";
|
|
35857
|
+
const { startTime, endTime, breaks } = operatingHoursData;
|
|
35941
35858
|
const shiftHours = calculateShiftHours2(startTime, endTime, breaks);
|
|
35942
35859
|
const actionThresholds = await workspaceService.getActionThresholds(
|
|
35943
35860
|
lineId,
|
|
35944
35861
|
currentDate,
|
|
35945
35862
|
shiftId
|
|
35946
35863
|
);
|
|
35864
|
+
if (!newDbValues[shiftId][lineId]) {
|
|
35865
|
+
newDbValues[shiftId][lineId] = {};
|
|
35866
|
+
}
|
|
35947
35867
|
const existingLine = newAllShiftsData[shiftId][lineId];
|
|
35948
35868
|
if (existingLine) {
|
|
35949
35869
|
newAllShiftsData[shiftId][lineId] = {
|
|
@@ -35955,6 +35875,11 @@ var TargetsView = ({
|
|
|
35955
35875
|
workspaces: existingLine.workspaces.map((ws) => {
|
|
35956
35876
|
const threshold = actionThresholds.find((t) => t.workspace_id === ws.id);
|
|
35957
35877
|
if (threshold) {
|
|
35878
|
+
newDbValues[shiftId][lineId][ws.id] = {
|
|
35879
|
+
targetPPH: threshold.pph_threshold,
|
|
35880
|
+
targetCycleTime: threshold.ideal_cycle_time,
|
|
35881
|
+
targetDayOutput: threshold.total_day_output
|
|
35882
|
+
};
|
|
35958
35883
|
return {
|
|
35959
35884
|
...ws,
|
|
35960
35885
|
targetPPH: threshold.pph_threshold,
|
|
@@ -35972,114 +35897,17 @@ var TargetsView = ({
|
|
|
35972
35897
|
}
|
|
35973
35898
|
}
|
|
35974
35899
|
setAllShiftsData(newAllShiftsData);
|
|
35975
|
-
|
|
35976
|
-
|
|
35977
|
-
try {
|
|
35978
|
-
if (!supabase) return null;
|
|
35979
|
-
const { data, error } = await supabase.from("line_operating_hours").select("start_time, end_time, breaks").eq("line_id", lineId).eq("shift_id", shiftId).maybeSingle();
|
|
35980
|
-
if (error) {
|
|
35981
|
-
if (error.code === "PGRST116") {
|
|
35982
|
-
console.log(`No operating hours found for line ${lineId}, shift ${shiftId}`);
|
|
35983
|
-
return {
|
|
35984
|
-
startTime: "08:00",
|
|
35985
|
-
// Default values
|
|
35986
|
-
endTime: "19:00",
|
|
35987
|
-
breaks: []
|
|
35988
|
-
};
|
|
35989
|
-
} else {
|
|
35990
|
-
console.error("Error fetching operating hours:", error);
|
|
35991
|
-
return null;
|
|
35992
|
-
}
|
|
35993
|
-
}
|
|
35994
|
-
let breaks = [];
|
|
35995
|
-
if (data?.breaks) {
|
|
35996
|
-
if (Array.isArray(data.breaks)) {
|
|
35997
|
-
breaks = data.breaks.map((breakItem) => {
|
|
35998
|
-
const startTime = breakItem.start || breakItem.startTime || "00:00";
|
|
35999
|
-
const endTime = breakItem.end || breakItem.endTime || "00:00";
|
|
36000
|
-
const calculateDuration = (start, end) => {
|
|
36001
|
-
const [startHour, startMinute] = start.split(":").map(Number);
|
|
36002
|
-
const [endHour, endMinute] = end.split(":").map(Number);
|
|
36003
|
-
let startMinutes = startHour * 60 + startMinute;
|
|
36004
|
-
let endMinutes = endHour * 60 + endMinute;
|
|
36005
|
-
if (endMinutes < startMinutes) {
|
|
36006
|
-
endMinutes += 24 * 60;
|
|
36007
|
-
}
|
|
36008
|
-
return endMinutes - startMinutes;
|
|
36009
|
-
};
|
|
36010
|
-
return {
|
|
36011
|
-
startTime,
|
|
36012
|
-
endTime,
|
|
36013
|
-
duration: breakItem.duration || calculateDuration(startTime, endTime)
|
|
36014
|
-
};
|
|
36015
|
-
});
|
|
36016
|
-
} else if (typeof data.breaks === "object" && data.breaks.breaks) {
|
|
36017
|
-
breaks = data.breaks.breaks.map((breakItem) => {
|
|
36018
|
-
const startTime = breakItem.start || breakItem.startTime || "00:00";
|
|
36019
|
-
const endTime = breakItem.end || breakItem.endTime || "00:00";
|
|
36020
|
-
const calculateDuration = (start, end) => {
|
|
36021
|
-
const [startHour, startMinute] = start.split(":").map(Number);
|
|
36022
|
-
const [endHour, endMinute] = end.split(":").map(Number);
|
|
36023
|
-
let startMinutes = startHour * 60 + startMinute;
|
|
36024
|
-
let endMinutes = endHour * 60 + endMinute;
|
|
36025
|
-
if (endMinutes < startMinutes) {
|
|
36026
|
-
endMinutes += 24 * 60;
|
|
36027
|
-
}
|
|
36028
|
-
return endMinutes - startMinutes;
|
|
36029
|
-
};
|
|
36030
|
-
return {
|
|
36031
|
-
startTime,
|
|
36032
|
-
endTime,
|
|
36033
|
-
duration: breakItem.duration || calculateDuration(startTime, endTime)
|
|
36034
|
-
};
|
|
36035
|
-
});
|
|
36036
|
-
} else if (typeof data.breaks === "string") {
|
|
36037
|
-
try {
|
|
36038
|
-
const parsedBreaks = JSON.parse(data.breaks);
|
|
36039
|
-
if (Array.isArray(parsedBreaks)) {
|
|
36040
|
-
breaks = parsedBreaks.map((breakItem) => ({
|
|
36041
|
-
startTime: breakItem.start || breakItem.startTime || "00:00",
|
|
36042
|
-
endTime: breakItem.end || breakItem.endTime || "00:00",
|
|
36043
|
-
duration: breakItem.duration || 0
|
|
36044
|
-
}));
|
|
36045
|
-
} else if (parsedBreaks.breaks && Array.isArray(parsedBreaks.breaks)) {
|
|
36046
|
-
breaks = parsedBreaks.breaks.map((breakItem) => ({
|
|
36047
|
-
startTime: breakItem.start || breakItem.startTime || "00:00",
|
|
36048
|
-
endTime: breakItem.end || breakItem.endTime || "00:00",
|
|
36049
|
-
duration: breakItem.duration || 0
|
|
36050
|
-
}));
|
|
36051
|
-
}
|
|
36052
|
-
} catch (e) {
|
|
36053
|
-
console.error("Error parsing breaks data:", e);
|
|
36054
|
-
}
|
|
36055
|
-
}
|
|
36056
|
-
}
|
|
36057
|
-
return {
|
|
36058
|
-
startTime: data?.start_time || "08:00",
|
|
36059
|
-
endTime: data?.end_time || "19:00",
|
|
36060
|
-
breaks
|
|
36061
|
-
};
|
|
36062
|
-
} catch (e) {
|
|
36063
|
-
console.error("Exception when loading operating hours:", e);
|
|
36064
|
-
return {
|
|
36065
|
-
startTime: "08:00",
|
|
36066
|
-
endTime: "19:00",
|
|
36067
|
-
breaks: []
|
|
36068
|
-
};
|
|
36069
|
-
}
|
|
36070
|
-
}, [supabase]);
|
|
35900
|
+
setDbValues(newDbValues);
|
|
35901
|
+
}, [supabase, lineIds, loadOperatingHours]);
|
|
36071
35902
|
const toggleLineDropdown = React19.useCallback((lineId) => {
|
|
36072
|
-
|
|
36073
|
-
const newIsOpen = !prev[lineId]
|
|
35903
|
+
setDropdownStates((prev) => {
|
|
35904
|
+
const newIsOpen = !prev[lineId];
|
|
36074
35905
|
if (typeof window !== "undefined") {
|
|
36075
35906
|
localStorage.setItem(`line_${lineId}_open`, JSON.stringify(newIsOpen));
|
|
36076
35907
|
}
|
|
36077
35908
|
return {
|
|
36078
35909
|
...prev,
|
|
36079
|
-
[lineId]:
|
|
36080
|
-
...prev[lineId],
|
|
36081
|
-
isOpen: newIsOpen
|
|
36082
|
-
}
|
|
35910
|
+
[lineId]: newIsOpen
|
|
36083
35911
|
};
|
|
36084
35912
|
});
|
|
36085
35913
|
}, []);
|
|
@@ -36128,6 +35956,8 @@ var TargetsView = ({
|
|
|
36128
35956
|
}
|
|
36129
35957
|
};
|
|
36130
35958
|
const updateWorkspaceTarget = (lineId, workspaceId, field, value) => {
|
|
35959
|
+
const fieldKey = `${lineId}-${workspaceId}-${field}`;
|
|
35960
|
+
setUserEditedFields((prev) => new Set(prev).add(fieldKey));
|
|
36131
35961
|
setLineWorkspaces((prev) => {
|
|
36132
35962
|
const shiftHours = prev[lineId].shiftHours;
|
|
36133
35963
|
return {
|
|
@@ -36152,11 +35982,7 @@ var TargetsView = ({
|
|
|
36152
35982
|
} else if (field === "targetDayOutput") {
|
|
36153
35983
|
updates.targetDayOutput = value;
|
|
36154
35984
|
if (value !== "") {
|
|
36155
|
-
const
|
|
36156
|
-
const totalBreakMinutes = breaks.reduce((total, b) => total + b.duration, 0);
|
|
36157
|
-
const totalBreakHours = totalBreakMinutes / 60;
|
|
36158
|
-
const realWorkHours = shiftHours - totalBreakHours;
|
|
36159
|
-
const calculatedPPH = Math.round(value / realWorkHours);
|
|
35985
|
+
const calculatedPPH = Math.round(value / shiftHours);
|
|
36160
35986
|
updates.targetPPH = calculatedPPH;
|
|
36161
35987
|
} else {
|
|
36162
35988
|
updates.targetPPH = "";
|
|
@@ -36171,62 +35997,35 @@ var TargetsView = ({
|
|
|
36171
35997
|
};
|
|
36172
35998
|
const handleShiftChange = (shiftId) => {
|
|
36173
35999
|
setSelectedShift(shiftId);
|
|
36174
|
-
|
|
36175
|
-
|
|
36176
|
-
|
|
36177
|
-
|
|
36178
|
-
|
|
36179
|
-
|
|
36180
|
-
|
|
36181
|
-
|
|
36182
|
-
|
|
36183
|
-
|
|
36184
|
-
|
|
36185
|
-
|
|
36186
|
-
|
|
36187
|
-
|
|
36188
|
-
|
|
36189
|
-
|
|
36190
|
-
|
|
36191
|
-
shiftHours: Number(shiftHours),
|
|
36192
|
-
workspaces: updatedLineWorkspaces[lineId].workspaces.map((ws) => {
|
|
36193
|
-
let updatedPPH = ws.targetPPH;
|
|
36194
|
-
if (ws.targetCycleTime !== "") {
|
|
36195
|
-
const idealPPH = calculatePPH(
|
|
36196
|
-
ws.targetCycleTime,
|
|
36197
|
-
operatingHours.breaks,
|
|
36198
|
-
Number(shiftHours)
|
|
36199
|
-
);
|
|
36200
|
-
const shouldUpdatePPH = typeof ws.targetPPH === "string" ? ws.targetPPH === "" : ws.targetPPH === 0 || !ws.targetPPH;
|
|
36201
|
-
if (shouldUpdatePPH) {
|
|
36202
|
-
updatedPPH = idealPPH;
|
|
36000
|
+
setUserEditedFields(/* @__PURE__ */ new Set());
|
|
36001
|
+
if (dbValues[shiftId] && Object.keys(dbValues[shiftId]).length > 0) {
|
|
36002
|
+
setAllShiftsData((prev) => {
|
|
36003
|
+
const updatedShiftData = { ...prev[shiftId] };
|
|
36004
|
+
for (const lineId of Object.keys(updatedShiftData)) {
|
|
36005
|
+
if (dbValues[shiftId][lineId]) {
|
|
36006
|
+
updatedShiftData[lineId] = {
|
|
36007
|
+
...updatedShiftData[lineId],
|
|
36008
|
+
workspaces: updatedShiftData[lineId].workspaces.map((ws) => {
|
|
36009
|
+
const dbValue = dbValues[shiftId][lineId][ws.id];
|
|
36010
|
+
if (dbValue) {
|
|
36011
|
+
return {
|
|
36012
|
+
...ws,
|
|
36013
|
+
targetPPH: dbValue.targetPPH,
|
|
36014
|
+
targetCycleTime: dbValue.targetCycleTime,
|
|
36015
|
+
targetDayOutput: dbValue.targetDayOutput
|
|
36016
|
+
};
|
|
36203
36017
|
}
|
|
36204
|
-
|
|
36205
|
-
|
|
36206
|
-
|
|
36207
|
-
|
|
36208
|
-
operatingHours.breaks
|
|
36209
|
-
);
|
|
36210
|
-
return {
|
|
36211
|
-
...ws,
|
|
36212
|
-
targetPPH: updatedPPH,
|
|
36213
|
-
targetDayOutput: updatedDayOutput
|
|
36214
|
-
};
|
|
36215
|
-
})
|
|
36216
|
-
};
|
|
36217
|
-
hasUpdates = true;
|
|
36218
|
-
} catch (e) {
|
|
36219
|
-
console.error(`Exception when loading shift hours for line ${lineId}:`, e);
|
|
36018
|
+
return ws;
|
|
36019
|
+
})
|
|
36020
|
+
};
|
|
36021
|
+
}
|
|
36220
36022
|
}
|
|
36221
|
-
|
|
36222
|
-
if (hasUpdates) {
|
|
36223
|
-
setAllShiftsData((prev) => ({
|
|
36023
|
+
return {
|
|
36224
36024
|
...prev,
|
|
36225
|
-
[shiftId]:
|
|
36226
|
-
}
|
|
36227
|
-
}
|
|
36228
|
-
}
|
|
36229
|
-
loadShiftHours();
|
|
36025
|
+
[shiftId]: updatedShiftData
|
|
36026
|
+
};
|
|
36027
|
+
});
|
|
36028
|
+
}
|
|
36230
36029
|
};
|
|
36231
36030
|
const handleActionTypeChange = React19.useCallback((lineId, workspaceId, newActionType) => {
|
|
36232
36031
|
if (!actionIds) return;
|
|
@@ -36316,6 +36115,31 @@ var TargetsView = ({
|
|
|
36316
36115
|
throw lineUpsertError;
|
|
36317
36116
|
}
|
|
36318
36117
|
console.log(`[handleSaveLine] Successfully upserted line_thresholds for ${lineId}`);
|
|
36118
|
+
setDbValues((prev) => ({
|
|
36119
|
+
...prev,
|
|
36120
|
+
[selectedShift]: {
|
|
36121
|
+
...prev[selectedShift],
|
|
36122
|
+
[lineId]: lineDataToSave.workspaces.reduce((acc, ws) => ({
|
|
36123
|
+
...acc,
|
|
36124
|
+
[ws.id]: {
|
|
36125
|
+
targetPPH: ws.targetPPH,
|
|
36126
|
+
targetCycleTime: ws.targetCycleTime,
|
|
36127
|
+
targetDayOutput: ws.targetDayOutput
|
|
36128
|
+
}
|
|
36129
|
+
}), {})
|
|
36130
|
+
}
|
|
36131
|
+
}));
|
|
36132
|
+
console.log(`[handleSaveLine] Updated dbValues for line ${lineId}, shift ${selectedShift}`);
|
|
36133
|
+
setUserEditedFields((prev) => {
|
|
36134
|
+
const newSet = new Set(prev);
|
|
36135
|
+
lineDataToSave.workspaces.forEach((ws) => {
|
|
36136
|
+
newSet.delete(`${lineId}-${ws.id}-targetPPH`);
|
|
36137
|
+
newSet.delete(`${lineId}-${ws.id}-targetCycleTime`);
|
|
36138
|
+
newSet.delete(`${lineId}-${ws.id}-targetDayOutput`);
|
|
36139
|
+
});
|
|
36140
|
+
return newSet;
|
|
36141
|
+
});
|
|
36142
|
+
console.log(`[handleSaveLine] Cleared user edited fields for line ${lineId}`);
|
|
36319
36143
|
setSaveSuccess((prev) => ({ ...prev, [lineId]: true }));
|
|
36320
36144
|
sonner.toast.success(`${lineNames[lineId] || lineId} targets saved successfully`);
|
|
36321
36145
|
if (onSaveChanges) onSaveChanges(lineId);
|
|
@@ -36329,7 +36153,7 @@ var TargetsView = ({
|
|
|
36329
36153
|
setSavingLines((prev) => ({ ...prev, [lineId]: false }));
|
|
36330
36154
|
console.log(`[handleSaveLine] Set savingLines to false for ${lineId} in finally block`);
|
|
36331
36155
|
}
|
|
36332
|
-
}, [supabase, lineWorkspaces, selectedShift, lineNames, onSaveChanges]);
|
|
36156
|
+
}, [supabase, lineWorkspaces, selectedShift, lineNames, onSaveChanges, skuEnabled, dashboardConfig]);
|
|
36333
36157
|
const handleBulkConfigure = async (updates) => {
|
|
36334
36158
|
if (!actionIds) return;
|
|
36335
36159
|
if (updates.productId !== void 0) {
|
|
@@ -36377,6 +36201,7 @@ var TargetsView = ({
|
|
|
36377
36201
|
isLoading: isLoading || skusLoading,
|
|
36378
36202
|
lineWorkspaces,
|
|
36379
36203
|
lineNames,
|
|
36204
|
+
dropdownStates,
|
|
36380
36205
|
savingLines,
|
|
36381
36206
|
saveSuccess,
|
|
36382
36207
|
selectedShift,
|
|
@@ -36401,7 +36226,7 @@ var TargetsView = ({
|
|
|
36401
36226
|
};
|
|
36402
36227
|
var TargetsViewWithDisplayNames = withAllWorkspaceDisplayNames(TargetsView);
|
|
36403
36228
|
var TargetsView_default = TargetsViewWithDisplayNames;
|
|
36404
|
-
var AuthenticatedTargetsView = withAuth(TargetsViewWithDisplayNames);
|
|
36229
|
+
var AuthenticatedTargetsView = withAuth(React19__namespace.default.memo(TargetsViewWithDisplayNames));
|
|
36405
36230
|
|
|
36406
36231
|
// src/views/workspace-detail-view.utils.ts
|
|
36407
36232
|
var formatISTDate2 = (date = /* @__PURE__ */ new Date(), options) => {
|
|
@@ -37881,6 +37706,7 @@ exports.AuthProvider = AuthProvider;
|
|
|
37881
37706
|
exports.AuthenticatedFactoryView = AuthenticatedFactoryView;
|
|
37882
37707
|
exports.AuthenticatedHelpView = AuthenticatedHelpView;
|
|
37883
37708
|
exports.AuthenticatedHomeView = AuthenticatedHomeView;
|
|
37709
|
+
exports.AuthenticatedShiftsView = AuthenticatedShiftsView;
|
|
37884
37710
|
exports.AuthenticatedTargetsView = AuthenticatedTargetsView;
|
|
37885
37711
|
exports.BarChart = BarChart;
|
|
37886
37712
|
exports.BaseHistoryCalendar = BaseHistoryCalendar;
|
|
@@ -38020,7 +37846,6 @@ exports.apiUtils = apiUtils;
|
|
|
38020
37846
|
exports.authCoreService = authCoreService;
|
|
38021
37847
|
exports.authOTPService = authOTPService;
|
|
38022
37848
|
exports.authRateLimitService = authRateLimitService;
|
|
38023
|
-
exports.cacheService = cacheService;
|
|
38024
37849
|
exports.checkRateLimit = checkRateLimit2;
|
|
38025
37850
|
exports.clearAllRateLimits = clearAllRateLimits2;
|
|
38026
37851
|
exports.clearRateLimit = clearRateLimit2;
|