@optifye/dashboard-core 6.3.5 → 6.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +137 -9
- package/dist/index.d.ts +137 -9
- package/dist/index.js +680 -519
- package/dist/index.mjs +688 -528
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -3809,6 +3809,11 @@ var S3ClipsService = class {
|
|
|
3809
3809
|
this.requestCache = new RequestDeduplicationCache();
|
|
3810
3810
|
// Flag to prevent metadata fetching during index building
|
|
3811
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;
|
|
3812
3817
|
this.config = config;
|
|
3813
3818
|
if (!config.s3Config) {
|
|
3814
3819
|
throw new Error("S3 configuration is required");
|
|
@@ -3854,7 +3859,12 @@ var S3ClipsService = class {
|
|
|
3854
3859
|
*/
|
|
3855
3860
|
async listS3Clips(params) {
|
|
3856
3861
|
const { workspaceId, date, shiftId, maxKeys } = params;
|
|
3862
|
+
if (!isValidShiftId(shiftId)) {
|
|
3863
|
+
console.error(`[S3ClipsService] Invalid shift ID: ${shiftId}. Must be 0 (day) or 1 (night)`);
|
|
3864
|
+
return [];
|
|
3865
|
+
}
|
|
3857
3866
|
const prefix = `sop_violations/${workspaceId}/${date}/${shiftId}/`;
|
|
3867
|
+
console.log(`[S3ClipsService] Listing clips for workspace: ${workspaceId}, date: ${date}, shift: ${shiftId}`);
|
|
3858
3868
|
const deduplicationKey = `list-s3-clips:${prefix}:${maxKeys || "all"}`;
|
|
3859
3869
|
return this.requestCache.deduplicate(
|
|
3860
3870
|
deduplicationKey,
|
|
@@ -3956,20 +3966,36 @@ var S3ClipsService = class {
|
|
|
3956
3966
|
return null;
|
|
3957
3967
|
}
|
|
3958
3968
|
}
|
|
3969
|
+
/**
|
|
3970
|
+
* Control prefetch mode to prevent metadata fetching during background operations
|
|
3971
|
+
*/
|
|
3972
|
+
setPrefetchMode(enabled) {
|
|
3973
|
+
this.isPrefetching = enabled;
|
|
3974
|
+
console.log(`[S3ClipsService] Prefetch mode ${enabled ? "enabled" : "disabled"} - metadata fetching ${enabled ? "blocked" : "allowed"}`);
|
|
3975
|
+
}
|
|
3959
3976
|
/**
|
|
3960
3977
|
* Fetches full metadata including timestamps with deduplication
|
|
3961
3978
|
*/
|
|
3962
3979
|
async getFullMetadata(playlistUri) {
|
|
3963
|
-
if (this.isIndexBuilding) {
|
|
3964
|
-
console.warn(`[S3ClipsService] Skipping metadata fetch
|
|
3980
|
+
if (this.isIndexBuilding || this.isPrefetching) {
|
|
3981
|
+
console.warn(`[S3ClipsService] Skipping metadata fetch - building: ${this.isIndexBuilding}, prefetching: ${this.isPrefetching}`);
|
|
3965
3982
|
return null;
|
|
3966
3983
|
}
|
|
3967
|
-
|
|
3968
|
-
|
|
3969
|
-
|
|
3970
|
-
|
|
3971
|
-
|
|
3972
|
-
|
|
3984
|
+
if (this.currentMetadataFetches >= this.MAX_CONCURRENT_METADATA) {
|
|
3985
|
+
console.warn(`[S3ClipsService] Skipping metadata - max concurrent fetches (${this.MAX_CONCURRENT_METADATA}) reached`);
|
|
3986
|
+
return null;
|
|
3987
|
+
}
|
|
3988
|
+
this.currentMetadataFetches++;
|
|
3989
|
+
try {
|
|
3990
|
+
const deduplicationKey = `full-metadata:${playlistUri}`;
|
|
3991
|
+
return await this.requestCache.deduplicate(
|
|
3992
|
+
deduplicationKey,
|
|
3993
|
+
() => this.executeGetFullMetadata(playlistUri),
|
|
3994
|
+
"FullMetadata"
|
|
3995
|
+
);
|
|
3996
|
+
} finally {
|
|
3997
|
+
this.currentMetadataFetches--;
|
|
3998
|
+
}
|
|
3973
3999
|
}
|
|
3974
4000
|
/**
|
|
3975
4001
|
* Internal implementation of full metadata fetching
|
|
@@ -4019,6 +4045,10 @@ var S3ClipsService = class {
|
|
|
4019
4045
|
return sopConfig.default;
|
|
4020
4046
|
}
|
|
4021
4047
|
async getClipCounts(workspaceId, date, shiftId, buildIndex) {
|
|
4048
|
+
if (!isValidShiftId(shiftId)) {
|
|
4049
|
+
console.error(`[S3ClipsService] getClipCounts - Invalid shift ID: ${shiftId}. Must be 0 (day) or 1 (night)`);
|
|
4050
|
+
return buildIndex ? { counts: {}, videoIndex: { byCategory: /* @__PURE__ */ new Map(), allVideos: [], counts: {}, workspaceId, date, shiftId: "0", lastUpdated: /* @__PURE__ */ new Date() } } : {};
|
|
4051
|
+
}
|
|
4022
4052
|
const deduplicationKey = `clip-counts:${workspaceId}:${date}:${shiftId}:${buildIndex ? "with-index" : "counts-only"}`;
|
|
4023
4053
|
return this.requestCache.deduplicate(
|
|
4024
4054
|
deduplicationKey,
|
|
@@ -4048,7 +4078,8 @@ var S3ClipsService = class {
|
|
|
4048
4078
|
"cycle_completion",
|
|
4049
4079
|
"bottleneck"
|
|
4050
4080
|
];
|
|
4051
|
-
|
|
4081
|
+
const shiftName = shiftId === 0 || shiftId === "0" ? "Day" : "Night";
|
|
4082
|
+
console.log(`[S3ClipsService] ${buildIndex ? "Building video index and counting" : "Fast counting"} clips for ${workspaceId} on ${date}, shift ${shiftId} (${shiftName} Shift)`);
|
|
4052
4083
|
const startTime = performance.now();
|
|
4053
4084
|
const videoIndex = buildIndex ? {
|
|
4054
4085
|
byCategory: /* @__PURE__ */ new Map(),
|
|
@@ -4195,6 +4226,10 @@ var S3ClipsService = class {
|
|
|
4195
4226
|
* Get first clip for a specific category with deduplication
|
|
4196
4227
|
*/
|
|
4197
4228
|
async getFirstClipForCategory(workspaceId, date, shiftId, category) {
|
|
4229
|
+
if (!isValidShiftId(shiftId)) {
|
|
4230
|
+
console.error(`[S3ClipsService] getFirstClipForCategory - Invalid shift ID: ${shiftId}. Must be 0 (day) or 1 (night)`);
|
|
4231
|
+
return null;
|
|
4232
|
+
}
|
|
4198
4233
|
const deduplicationKey = `first-clip:${workspaceId}:${date}:${shiftId}:${category}`;
|
|
4199
4234
|
return this.requestCache.deduplicate(
|
|
4200
4235
|
deduplicationKey,
|
|
@@ -4471,7 +4506,8 @@ var S3ClipsService = class {
|
|
|
4471
4506
|
date,
|
|
4472
4507
|
shiftId.toString(),
|
|
4473
4508
|
includeCycleTime || false,
|
|
4474
|
-
includeMetadata ||
|
|
4509
|
+
includeMetadata || false
|
|
4510
|
+
// Never fetch metadata for timestamp filtering to prevent flooding
|
|
4475
4511
|
);
|
|
4476
4512
|
});
|
|
4477
4513
|
const videoResults = await Promise.all(videoPromises);
|
|
@@ -4542,6 +4578,7 @@ var VideoPrefetchManager = class extends events.EventEmitter {
|
|
|
4542
4578
|
}
|
|
4543
4579
|
/**
|
|
4544
4580
|
* Get or create S3 service instance for dashboard config
|
|
4581
|
+
* Public method to allow sharing the same S3Service instance across components
|
|
4545
4582
|
*/
|
|
4546
4583
|
getS3Service(dashboardConfig) {
|
|
4547
4584
|
const configKey = JSON.stringify(dashboardConfig.s3Config);
|
|
@@ -4611,75 +4648,80 @@ var VideoPrefetchManager = class extends events.EventEmitter {
|
|
|
4611
4648
|
* Perform the actual prefetch work
|
|
4612
4649
|
*/
|
|
4613
4650
|
async performPrefetchWork(key, params, s3Service, buildIndex) {
|
|
4614
|
-
|
|
4615
|
-
|
|
4616
|
-
|
|
4617
|
-
|
|
4618
|
-
|
|
4619
|
-
|
|
4620
|
-
|
|
4621
|
-
|
|
4622
|
-
|
|
4651
|
+
s3Service.setPrefetchMode(true);
|
|
4652
|
+
try {
|
|
4653
|
+
const cacheKey = `clip-counts:${params.workspaceId}:${params.date}:${params.shift}`;
|
|
4654
|
+
const cachedResult = await smartVideoCache.getClipCounts(cacheKey);
|
|
4655
|
+
if (cachedResult) {
|
|
4656
|
+
console.log(`[VideoPrefetchManager] Found cached data for ${key}`);
|
|
4657
|
+
this.updateRequestStatus(key, "fully_indexed" /* FULLY_INDEXED */, cachedResult);
|
|
4658
|
+
return cachedResult;
|
|
4659
|
+
}
|
|
4660
|
+
if (buildIndex) {
|
|
4661
|
+
const countsOnly = await s3Service.getClipCounts(
|
|
4662
|
+
params.workspaceId,
|
|
4663
|
+
params.date,
|
|
4664
|
+
params.shift
|
|
4665
|
+
);
|
|
4666
|
+
if (typeof countsOnly === "object" && countsOnly !== null) {
|
|
4667
|
+
const renderReadyData = {
|
|
4668
|
+
counts: countsOnly,
|
|
4669
|
+
videoIndex: {
|
|
4670
|
+
byCategory: /* @__PURE__ */ new Map(),
|
|
4671
|
+
allVideos: [],
|
|
4672
|
+
counts: countsOnly,
|
|
4673
|
+
workspaceId: params.workspaceId,
|
|
4674
|
+
date: params.date,
|
|
4675
|
+
shiftId: params.shift,
|
|
4676
|
+
lastUpdated: /* @__PURE__ */ new Date(),
|
|
4677
|
+
_debugId: `vid_RENDER_READY_${Date.now()}_${Math.random().toString(36).substring(7)}`
|
|
4678
|
+
}
|
|
4679
|
+
};
|
|
4680
|
+
this.updateRequestStatus(key, "render_ready" /* RENDER_READY */, renderReadyData);
|
|
4681
|
+
console.log(`[VideoPrefetchManager] Render ready, building full index for ${key}`);
|
|
4682
|
+
}
|
|
4683
|
+
}
|
|
4684
|
+
const fullResult = await s3Service.getClipCountsCacheFirst(
|
|
4623
4685
|
params.workspaceId,
|
|
4624
4686
|
params.date,
|
|
4625
|
-
params.shift
|
|
4687
|
+
params.shift,
|
|
4688
|
+
true
|
|
4626
4689
|
);
|
|
4627
|
-
if (typeof
|
|
4628
|
-
const
|
|
4629
|
-
|
|
4690
|
+
if (fullResult && typeof fullResult === "object" && "videoIndex" in fullResult) {
|
|
4691
|
+
const clipCountsWithIndex = fullResult;
|
|
4692
|
+
if (clipCountsWithIndex.videoIndex.allVideos.length > 0) {
|
|
4693
|
+
console.log(`[VideoPrefetchManager] Video index properly populated with ${clipCountsWithIndex.videoIndex.allVideos.length} videos`);
|
|
4694
|
+
} else {
|
|
4695
|
+
console.warn(`[VideoPrefetchManager] Video index is empty, but counts available:`, clipCountsWithIndex.counts);
|
|
4696
|
+
}
|
|
4697
|
+
await smartVideoCache.setClipCounts(cacheKey, clipCountsWithIndex, 5 * 60);
|
|
4698
|
+
this.updateRequestStatus(key, "fully_indexed" /* FULLY_INDEXED */, clipCountsWithIndex);
|
|
4699
|
+
console.log(`[VideoPrefetchManager] Fully indexed: ${key} (${clipCountsWithIndex.videoIndex.allVideos.length} videos)`);
|
|
4700
|
+
return clipCountsWithIndex;
|
|
4701
|
+
} else if (fullResult && typeof fullResult === "object") {
|
|
4702
|
+
console.log(`[VideoPrefetchManager] Received counts only, building fallback data structure`);
|
|
4703
|
+
const countsResult = fullResult;
|
|
4704
|
+
const fallbackData = {
|
|
4705
|
+
counts: countsResult,
|
|
4630
4706
|
videoIndex: {
|
|
4631
4707
|
byCategory: /* @__PURE__ */ new Map(),
|
|
4632
4708
|
allVideos: [],
|
|
4633
|
-
counts:
|
|
4709
|
+
counts: countsResult,
|
|
4634
4710
|
workspaceId: params.workspaceId,
|
|
4635
4711
|
date: params.date,
|
|
4636
4712
|
shiftId: params.shift,
|
|
4637
4713
|
lastUpdated: /* @__PURE__ */ new Date(),
|
|
4638
|
-
_debugId: `
|
|
4714
|
+
_debugId: `vid_FALLBACK_${Date.now()}_${Math.random().toString(36).substring(7)}`
|
|
4639
4715
|
}
|
|
4640
4716
|
};
|
|
4641
|
-
this.updateRequestStatus(key, "render_ready" /* RENDER_READY */,
|
|
4642
|
-
|
|
4643
|
-
}
|
|
4644
|
-
}
|
|
4645
|
-
const fullResult = await s3Service.getClipCountsCacheFirst(
|
|
4646
|
-
params.workspaceId,
|
|
4647
|
-
params.date,
|
|
4648
|
-
params.shift,
|
|
4649
|
-
true
|
|
4650
|
-
);
|
|
4651
|
-
if (fullResult && typeof fullResult === "object" && "videoIndex" in fullResult) {
|
|
4652
|
-
const clipCountsWithIndex = fullResult;
|
|
4653
|
-
if (clipCountsWithIndex.videoIndex.allVideos.length > 0) {
|
|
4654
|
-
console.log(`[VideoPrefetchManager] Video index properly populated with ${clipCountsWithIndex.videoIndex.allVideos.length} videos`);
|
|
4717
|
+
this.updateRequestStatus(key, "render_ready" /* RENDER_READY */, fallbackData);
|
|
4718
|
+
return fallbackData;
|
|
4655
4719
|
} else {
|
|
4656
|
-
console.
|
|
4657
|
-
|
|
4658
|
-
|
|
4659
|
-
|
|
4660
|
-
|
|
4661
|
-
return clipCountsWithIndex;
|
|
4662
|
-
} else if (fullResult && typeof fullResult === "object") {
|
|
4663
|
-
console.log(`[VideoPrefetchManager] Received counts only, building fallback data structure`);
|
|
4664
|
-
const countsResult = fullResult;
|
|
4665
|
-
const fallbackData = {
|
|
4666
|
-
counts: countsResult,
|
|
4667
|
-
videoIndex: {
|
|
4668
|
-
byCategory: /* @__PURE__ */ new Map(),
|
|
4669
|
-
allVideos: [],
|
|
4670
|
-
counts: countsResult,
|
|
4671
|
-
workspaceId: params.workspaceId,
|
|
4672
|
-
date: params.date,
|
|
4673
|
-
shiftId: params.shift,
|
|
4674
|
-
lastUpdated: /* @__PURE__ */ new Date(),
|
|
4675
|
-
_debugId: `vid_FALLBACK_${Date.now()}_${Math.random().toString(36).substring(7)}`
|
|
4676
|
-
}
|
|
4677
|
-
};
|
|
4678
|
-
this.updateRequestStatus(key, "render_ready" /* RENDER_READY */, fallbackData);
|
|
4679
|
-
return fallbackData;
|
|
4680
|
-
} else {
|
|
4681
|
-
console.error(`[VideoPrefetchManager] Received null/undefined result from S3 service`);
|
|
4682
|
-
throw new Error("Failed to fetch clip counts from S3 service");
|
|
4720
|
+
console.error(`[VideoPrefetchManager] Received null/undefined result from S3 service`);
|
|
4721
|
+
throw new Error("Failed to fetch clip counts from S3 service");
|
|
4722
|
+
}
|
|
4723
|
+
} finally {
|
|
4724
|
+
s3Service.setPrefetchMode(false);
|
|
4683
4725
|
}
|
|
4684
4726
|
}
|
|
4685
4727
|
/**
|
|
@@ -4942,9 +4984,13 @@ var AuthProvider = ({ children }) => {
|
|
|
4942
4984
|
const [loading, setLoading] = React19.useState(true);
|
|
4943
4985
|
const [error, setError] = React19.useState(null);
|
|
4944
4986
|
const router$1 = router.useRouter();
|
|
4945
|
-
|
|
4946
|
-
|
|
4987
|
+
authConfig?.userProfileTable;
|
|
4988
|
+
authConfig?.roleColumn || "role";
|
|
4947
4989
|
const fetchUserDetails = React19.useCallback(async (supabaseUser) => {
|
|
4990
|
+
console.log("[fetchUserDetails] Called for user:", supabaseUser.id, {
|
|
4991
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4992
|
+
stackTrace: new Error().stack?.split("\n").slice(1, 4).join(" -> ")
|
|
4993
|
+
});
|
|
4948
4994
|
if (!supabaseUser) return null;
|
|
4949
4995
|
const basicUser = {
|
|
4950
4996
|
id: supabaseUser.id,
|
|
@@ -4953,42 +4999,34 @@ var AuthProvider = ({ children }) => {
|
|
|
4953
4999
|
if (!supabase) return basicUser;
|
|
4954
5000
|
try {
|
|
4955
5001
|
const timeoutPromise = new Promise(
|
|
4956
|
-
(_, reject) => setTimeout(() =>
|
|
5002
|
+
(_, reject) => setTimeout(() => {
|
|
5003
|
+
console.log("[fetchUserDetails] Timeout triggered after 2 seconds");
|
|
5004
|
+
reject(new Error("Profile fetch timeout"));
|
|
5005
|
+
}, 2e3)
|
|
4957
5006
|
);
|
|
4958
5007
|
const rolePromise = supabase.from("user_roles").select("role_level").eq("user_id", supabaseUser.id).single();
|
|
4959
|
-
|
|
4960
|
-
|
|
4961
|
-
|
|
4962
|
-
|
|
4963
|
-
const [roleResult, profileResult] = await Promise.race([
|
|
4964
|
-
Promise.all([
|
|
4965
|
-
rolePromise,
|
|
4966
|
-
profilePromise || Promise.resolve(null)
|
|
4967
|
-
]),
|
|
4968
|
-
timeoutPromise.then(() => {
|
|
4969
|
-
throw new Error("Timeout");
|
|
4970
|
-
})
|
|
5008
|
+
const roleResult = await Promise.race([
|
|
5009
|
+
rolePromise,
|
|
5010
|
+
timeoutPromise
|
|
5011
|
+
// Fixed: removed .then() which was causing the bug
|
|
4971
5012
|
]);
|
|
4972
5013
|
let roleLevel = void 0;
|
|
4973
5014
|
if (roleResult && !roleResult.error && roleResult.data) {
|
|
4974
5015
|
roleLevel = roleResult.data.role_level;
|
|
4975
|
-
} else if (roleResult?.error) {
|
|
5016
|
+
} else if (roleResult?.error && roleResult.error.code !== "PGRST116") {
|
|
4976
5017
|
console.log("Error fetching role_level:", roleResult.error.message);
|
|
4977
5018
|
}
|
|
4978
|
-
let roleValue = void 0;
|
|
4979
|
-
if (profileResult && !profileResult.error && profileResult.data) {
|
|
4980
|
-
roleValue = profileResult.data[roleColumn];
|
|
4981
|
-
}
|
|
4982
5019
|
return {
|
|
4983
5020
|
...basicUser,
|
|
4984
|
-
role: roleValue,
|
|
4985
5021
|
role_level: roleLevel
|
|
4986
5022
|
};
|
|
4987
5023
|
} catch (err) {
|
|
4988
|
-
|
|
5024
|
+
if (err instanceof Error && err.message.includes("timeout")) {
|
|
5025
|
+
console.warn("Auth fetch timeout - using basic user info");
|
|
5026
|
+
}
|
|
4989
5027
|
return basicUser;
|
|
4990
5028
|
}
|
|
4991
|
-
}, [supabase
|
|
5029
|
+
}, [supabase]);
|
|
4992
5030
|
React19.useEffect(() => {
|
|
4993
5031
|
if (!supabase) return;
|
|
4994
5032
|
let mounted = true;
|
|
@@ -4999,6 +5037,7 @@ var AuthProvider = ({ children }) => {
|
|
|
4999
5037
|
}
|
|
5000
5038
|
}, 1e4);
|
|
5001
5039
|
const initializeAuth = async () => {
|
|
5040
|
+
const startTime = performance.now();
|
|
5002
5041
|
try {
|
|
5003
5042
|
const { data: { session: initialSession }, error: sessionError } = await supabase.auth.getSession();
|
|
5004
5043
|
if (!mounted) return;
|
|
@@ -5041,12 +5080,38 @@ var AuthProvider = ({ children }) => {
|
|
|
5041
5080
|
if (mounted) {
|
|
5042
5081
|
setLoading(false);
|
|
5043
5082
|
clearTimeout(safetyTimeout);
|
|
5083
|
+
const duration = performance.now() - startTime;
|
|
5084
|
+
if (duration > 3e3) {
|
|
5085
|
+
console.warn(`[Auth] Initialization took ${duration.toFixed(0)}ms - consider optimization`);
|
|
5086
|
+
} else if (process.env.NODE_ENV === "development") {
|
|
5087
|
+
console.log(`[Auth] Initialized in ${duration.toFixed(0)}ms`);
|
|
5088
|
+
}
|
|
5044
5089
|
}
|
|
5045
5090
|
}
|
|
5046
5091
|
};
|
|
5047
5092
|
initializeAuth();
|
|
5048
|
-
const { data: { subscription } } = supabase.auth.onAuthStateChange(async (
|
|
5093
|
+
const { data: { subscription } } = supabase.auth.onAuthStateChange(async (event, currentSession) => {
|
|
5049
5094
|
if (!mounted) return;
|
|
5095
|
+
console.log("[AuthContext] Auth event fired:", {
|
|
5096
|
+
event,
|
|
5097
|
+
sessionId: currentSession?.user?.id,
|
|
5098
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
5099
|
+
currentPath: typeof window !== "undefined" ? window.location.pathname : "unknown"
|
|
5100
|
+
});
|
|
5101
|
+
if (event === "TOKEN_REFRESHED") {
|
|
5102
|
+
if (session?.user?.id === currentSession?.user?.id && session?.user?.email === currentSession?.user?.email) {
|
|
5103
|
+
console.log("[AuthContext] Skipping TOKEN_REFRESHED - session unchanged");
|
|
5104
|
+
return;
|
|
5105
|
+
}
|
|
5106
|
+
}
|
|
5107
|
+
if (event !== "TOKEN_REFRESHED" && currentSession?.user) {
|
|
5108
|
+
console.log("[AuthContext] Non-TOKEN_REFRESHED event will trigger fetchUserDetails:", event);
|
|
5109
|
+
}
|
|
5110
|
+
const sessionChanged = session?.user?.id !== currentSession?.user?.id || session?.user?.email !== currentSession?.user?.email;
|
|
5111
|
+
if (!sessionChanged && user) {
|
|
5112
|
+
console.log("[AuthContext] Session and user unchanged, skipping update");
|
|
5113
|
+
return;
|
|
5114
|
+
}
|
|
5050
5115
|
setSession(currentSession);
|
|
5051
5116
|
setUser(null);
|
|
5052
5117
|
setLoading(false);
|
|
@@ -6967,16 +7032,12 @@ var useTargets = (options) => {
|
|
|
6967
7032
|
};
|
|
6968
7033
|
var DEFAULT_SHIFTS_TABLE_NAME = "shift_configurations";
|
|
6969
7034
|
var useShifts = () => {
|
|
6970
|
-
const { supabaseUrl, supabaseKey } = useDashboardConfig();
|
|
6971
7035
|
const { companyId } = useEntityConfig();
|
|
6972
7036
|
const { tables } = useDatabaseConfig();
|
|
7037
|
+
const supabase = useSupabase();
|
|
6973
7038
|
const [shifts, setShifts] = React19.useState([]);
|
|
6974
7039
|
const [isLoading, setIsLoading] = React19.useState(true);
|
|
6975
7040
|
const [error, setError] = React19.useState(null);
|
|
6976
|
-
const supabase = React19.useMemo(() => {
|
|
6977
|
-
if (!supabaseUrl || !supabaseKey) return null;
|
|
6978
|
-
return supabaseJs.createClient(supabaseUrl, supabaseKey);
|
|
6979
|
-
}, [supabaseUrl, supabaseKey]);
|
|
6980
7041
|
const shiftsTable = tables?.shiftConfigurations || DEFAULT_SHIFTS_TABLE_NAME;
|
|
6981
7042
|
const fetchData = React19.useCallback(async () => {
|
|
6982
7043
|
if (!supabase) {
|
|
@@ -7675,6 +7736,7 @@ var runtimeWorkspaceDisplayNames = {};
|
|
|
7675
7736
|
var isInitialized = false;
|
|
7676
7737
|
var isInitializing = false;
|
|
7677
7738
|
var initializedWithLineIds = [];
|
|
7739
|
+
var initializationPromise = null;
|
|
7678
7740
|
function getCurrentLineIds() {
|
|
7679
7741
|
try {
|
|
7680
7742
|
const config = _getDashboardConfigInstance();
|
|
@@ -7695,52 +7757,79 @@ function getCurrentLineIds() {
|
|
|
7695
7757
|
}
|
|
7696
7758
|
async function initializeWorkspaceDisplayNames(explicitLineId) {
|
|
7697
7759
|
console.log("\u{1F504} initializeWorkspaceDisplayNames called", { isInitialized, isInitializing, explicitLineId });
|
|
7698
|
-
if (isInitialized
|
|
7699
|
-
|
|
7700
|
-
|
|
7701
|
-
|
|
7702
|
-
|
|
7703
|
-
|
|
7704
|
-
|
|
7705
|
-
|
|
7706
|
-
|
|
7760
|
+
if (isInitialized) return;
|
|
7761
|
+
if (initializationPromise) {
|
|
7762
|
+
console.log("\u{1F504} Already initializing, waiting for existing initialization...");
|
|
7763
|
+
await initializationPromise;
|
|
7764
|
+
return;
|
|
7765
|
+
}
|
|
7766
|
+
initializationPromise = (async () => {
|
|
7767
|
+
isInitializing = true;
|
|
7768
|
+
try {
|
|
7769
|
+
console.log("\u{1F504} Starting Supabase workspace display names initialization...");
|
|
7770
|
+
let targetLineIds = [];
|
|
7771
|
+
if (explicitLineId) {
|
|
7772
|
+
targetLineIds = [explicitLineId];
|
|
7773
|
+
} else {
|
|
7774
|
+
targetLineIds = getCurrentLineIds();
|
|
7775
|
+
}
|
|
7776
|
+
console.log("\u{1F504} Target line IDs for workspace filtering:", targetLineIds);
|
|
7777
|
+
runtimeWorkspaceDisplayNames = {};
|
|
7778
|
+
if (targetLineIds.length > 0) {
|
|
7779
|
+
for (const lineId of targetLineIds) {
|
|
7780
|
+
console.log(`\u{1F504} Fetching workspaces for line: ${lineId}`);
|
|
7781
|
+
const lineDisplayNamesMap = await workspaceService.getWorkspaceDisplayNames(void 0, lineId);
|
|
7782
|
+
runtimeWorkspaceDisplayNames[lineId] = {};
|
|
7783
|
+
lineDisplayNamesMap.forEach((displayName, workspaceId) => {
|
|
7784
|
+
runtimeWorkspaceDisplayNames[lineId][workspaceId] = displayName;
|
|
7785
|
+
});
|
|
7786
|
+
console.log(`\u2705 Stored ${lineDisplayNamesMap.size} workspaces for line ${lineId}`);
|
|
7787
|
+
}
|
|
7788
|
+
} else {
|
|
7789
|
+
console.warn("\u26A0\uFE0F No line IDs found, fetching all workspaces (less efficient)");
|
|
7790
|
+
const allWorkspacesMap = await workspaceService.getWorkspaceDisplayNames();
|
|
7791
|
+
runtimeWorkspaceDisplayNames["global"] = {};
|
|
7792
|
+
allWorkspacesMap.forEach((displayName, workspaceId) => {
|
|
7793
|
+
runtimeWorkspaceDisplayNames["global"][workspaceId] = displayName;
|
|
7794
|
+
});
|
|
7795
|
+
}
|
|
7796
|
+
isInitialized = true;
|
|
7797
|
+
initializedWithLineIds = targetLineIds;
|
|
7798
|
+
console.log("\u2705 Workspace display names initialized from Supabase:", runtimeWorkspaceDisplayNames);
|
|
7799
|
+
console.log("\u2705 Initialized with line IDs:", initializedWithLineIds);
|
|
7800
|
+
} catch (error) {
|
|
7801
|
+
console.error("\u274C Failed to initialize workspace display names from Supabase:", error);
|
|
7802
|
+
} finally {
|
|
7803
|
+
isInitializing = false;
|
|
7804
|
+
initializationPromise = null;
|
|
7707
7805
|
}
|
|
7708
|
-
|
|
7709
|
-
|
|
7710
|
-
|
|
7711
|
-
|
|
7712
|
-
|
|
7806
|
+
})();
|
|
7807
|
+
await initializationPromise;
|
|
7808
|
+
}
|
|
7809
|
+
var preInitializeWorkspaceDisplayNames = async (lineId) => {
|
|
7810
|
+
console.log("\u{1F504} preInitializeWorkspaceDisplayNames called for lineId:", lineId);
|
|
7811
|
+
if (isInitialized) {
|
|
7812
|
+
console.log("\u{1F504} Already initialized");
|
|
7813
|
+
if (lineId && !runtimeWorkspaceDisplayNames[lineId]) {
|
|
7814
|
+
console.log(`\u{1F504} Line ${lineId} not in cache, fetching...`);
|
|
7815
|
+
try {
|
|
7713
7816
|
const lineDisplayNamesMap = await workspaceService.getWorkspaceDisplayNames(void 0, lineId);
|
|
7714
7817
|
runtimeWorkspaceDisplayNames[lineId] = {};
|
|
7715
7818
|
lineDisplayNamesMap.forEach((displayName, workspaceId) => {
|
|
7716
7819
|
runtimeWorkspaceDisplayNames[lineId][workspaceId] = displayName;
|
|
7717
7820
|
});
|
|
7718
|
-
console.log(`\u2705
|
|
7821
|
+
console.log(`\u2705 Added ${lineDisplayNamesMap.size} workspaces for line ${lineId}`);
|
|
7822
|
+
} catch (error) {
|
|
7823
|
+
console.error(`\u274C Failed to fetch workspaces for line ${lineId}:`, error);
|
|
7719
7824
|
}
|
|
7720
|
-
} else {
|
|
7721
|
-
console.warn("\u26A0\uFE0F No line IDs found, fetching all workspaces (less efficient)");
|
|
7722
|
-
const allWorkspacesMap = await workspaceService.getWorkspaceDisplayNames();
|
|
7723
|
-
runtimeWorkspaceDisplayNames["global"] = {};
|
|
7724
|
-
allWorkspacesMap.forEach((displayName, workspaceId) => {
|
|
7725
|
-
runtimeWorkspaceDisplayNames["global"][workspaceId] = displayName;
|
|
7726
|
-
});
|
|
7727
7825
|
}
|
|
7728
|
-
|
|
7729
|
-
initializedWithLineIds = targetLineIds;
|
|
7730
|
-
console.log("\u2705 Workspace display names initialized from Supabase:", runtimeWorkspaceDisplayNames);
|
|
7731
|
-
console.log("\u2705 Initialized with line IDs:", initializedWithLineIds);
|
|
7732
|
-
} catch (error) {
|
|
7733
|
-
console.error("\u274C Failed to initialize workspace display names from Supabase:", error);
|
|
7734
|
-
} finally {
|
|
7735
|
-
isInitializing = false;
|
|
7826
|
+
return;
|
|
7736
7827
|
}
|
|
7737
|
-
|
|
7738
|
-
|
|
7739
|
-
|
|
7740
|
-
if (isInitialized || isInitializing) {
|
|
7741
|
-
console.log("\u{1F504} Already initialized or initializing");
|
|
7828
|
+
if (initializationPromise) {
|
|
7829
|
+
console.log("\u{1F504} Already initializing, waiting for completion...");
|
|
7830
|
+
await initializationPromise;
|
|
7742
7831
|
if (lineId && !runtimeWorkspaceDisplayNames[lineId]) {
|
|
7743
|
-
console.log(`\u{1F504} Line ${lineId} not in cache, fetching...`);
|
|
7832
|
+
console.log(`\u{1F504} Line ${lineId} not in cache after init, fetching...`);
|
|
7744
7833
|
try {
|
|
7745
7834
|
const lineDisplayNamesMap = await workspaceService.getWorkspaceDisplayNames(void 0, lineId);
|
|
7746
7835
|
runtimeWorkspaceDisplayNames[lineId] = {};
|
|
@@ -7758,7 +7847,12 @@ var preInitializeWorkspaceDisplayNames = async (lineId) => {
|
|
|
7758
7847
|
};
|
|
7759
7848
|
var forceRefreshWorkspaceDisplayNames = async (lineId) => {
|
|
7760
7849
|
console.log("\u{1F504} forceRefreshWorkspaceDisplayNames called for lineId:", lineId);
|
|
7850
|
+
if (initializationPromise) {
|
|
7851
|
+
console.log("\u{1F504} Waiting for existing initialization to complete before refresh...");
|
|
7852
|
+
await initializationPromise;
|
|
7853
|
+
}
|
|
7761
7854
|
clearWorkspaceDisplayNamesCache();
|
|
7855
|
+
initializationPromise = null;
|
|
7762
7856
|
await initializeWorkspaceDisplayNames(lineId);
|
|
7763
7857
|
};
|
|
7764
7858
|
console.log("\u{1F504} Module loaded, will initialize lazily when first function is called");
|
|
@@ -7906,6 +8000,7 @@ var clearWorkspaceDisplayNamesCache = () => {
|
|
|
7906
8000
|
isInitialized = false;
|
|
7907
8001
|
isInitializing = false;
|
|
7908
8002
|
initializedWithLineIds = [];
|
|
8003
|
+
initializationPromise = null;
|
|
7909
8004
|
};
|
|
7910
8005
|
|
|
7911
8006
|
// src/lib/hooks/useWorkspaceDisplayNames.ts
|
|
@@ -11542,7 +11637,18 @@ var usePrefetchClipCounts = ({
|
|
|
11542
11637
|
}, [subscriberId]);
|
|
11543
11638
|
const prefetchParams = React19.useMemo(() => {
|
|
11544
11639
|
const operationalDate = date || getOperationalDate();
|
|
11545
|
-
|
|
11640
|
+
let shiftStr;
|
|
11641
|
+
if (shift !== void 0 && shift !== null) {
|
|
11642
|
+
shiftStr = shift.toString();
|
|
11643
|
+
console.log(`[usePrefetchClipCounts] Using provided shift: ${shiftStr} for date: ${operationalDate}`);
|
|
11644
|
+
} else if (date) {
|
|
11645
|
+
shiftStr = "0";
|
|
11646
|
+
console.log(`[usePrefetchClipCounts] No shift provided for historical date ${date}, defaulting to day shift (0)`);
|
|
11647
|
+
} else {
|
|
11648
|
+
const currentShift = getCurrentShift2();
|
|
11649
|
+
shiftStr = currentShift.shiftId.toString();
|
|
11650
|
+
console.log(`[usePrefetchClipCounts] Using current operational shift: ${shiftStr} (${currentShift.shiftName})`);
|
|
11651
|
+
}
|
|
11546
11652
|
return {
|
|
11547
11653
|
workspaceId: workspaceId || "",
|
|
11548
11654
|
date: operationalDate,
|
|
@@ -19546,11 +19652,13 @@ var withAuth = (WrappedComponent2, options) => {
|
|
|
19546
19652
|
requireAuth: true,
|
|
19547
19653
|
...options
|
|
19548
19654
|
};
|
|
19549
|
-
|
|
19655
|
+
const WithAuthComponent = React19__namespace.memo(function WithAuthComponent2(props) {
|
|
19550
19656
|
const { session, loading } = useAuth();
|
|
19551
19657
|
const router$1 = router.useRouter();
|
|
19552
19658
|
React19__namespace.useEffect(() => {
|
|
19553
|
-
|
|
19659
|
+
if (process.env.NODE_ENV === "development" && process.env.DEBUG_AUTH === "true") {
|
|
19660
|
+
console.log("withAuth state:", { loading, hasSession: !!session, requireAuth: defaultOptions.requireAuth });
|
|
19661
|
+
}
|
|
19554
19662
|
}, [session, loading]);
|
|
19555
19663
|
React19__namespace.useEffect(() => {
|
|
19556
19664
|
if (!loading && defaultOptions.requireAuth && !session) {
|
|
@@ -19565,7 +19673,9 @@ var withAuth = (WrappedComponent2, options) => {
|
|
|
19565
19673
|
return null;
|
|
19566
19674
|
}
|
|
19567
19675
|
return /* @__PURE__ */ jsxRuntime.jsx(WrappedComponent2, { ...props });
|
|
19568
|
-
};
|
|
19676
|
+
});
|
|
19677
|
+
WithAuthComponent.displayName = `withAuth(${WrappedComponent2.displayName || WrappedComponent2.name || "Component"})`;
|
|
19678
|
+
return WithAuthComponent;
|
|
19569
19679
|
};
|
|
19570
19680
|
var LoginPage = ({
|
|
19571
19681
|
onRateLimitCheck,
|
|
@@ -26153,7 +26263,7 @@ var BottlenecksContent = ({
|
|
|
26153
26263
|
const [duration, setDuration] = React19.useState(0);
|
|
26154
26264
|
const [currentIndex, setCurrentIndex] = React19.useState(0);
|
|
26155
26265
|
const [activeFilter, setActiveFilter] = React19.useState(initialFilter);
|
|
26156
|
-
const previousFilterRef = React19.useRef(
|
|
26266
|
+
const previousFilterRef = React19.useRef("");
|
|
26157
26267
|
const [allVideos, setAllVideos] = React19.useState([]);
|
|
26158
26268
|
const [isLoading, setIsLoading] = React19.useState(true);
|
|
26159
26269
|
const [isCategoryLoading, setIsCategoryLoading] = React19.useState(false);
|
|
@@ -26203,8 +26313,23 @@ var BottlenecksContent = ({
|
|
|
26203
26313
|
console.warn("S3 configuration not found in dashboard config");
|
|
26204
26314
|
return null;
|
|
26205
26315
|
}
|
|
26206
|
-
return
|
|
26316
|
+
return videoPrefetchManager.getS3Service(dashboardConfig);
|
|
26207
26317
|
}, [dashboardConfig]);
|
|
26318
|
+
const effectiveShift = React19.useMemo(() => {
|
|
26319
|
+
if (shift !== void 0 && shift !== null) {
|
|
26320
|
+
const shiftStr = shift.toString();
|
|
26321
|
+
console.log(`[BottlenecksContent] Using provided shift: ${shiftStr} for date: ${date}`);
|
|
26322
|
+
return shiftStr;
|
|
26323
|
+
}
|
|
26324
|
+
if (date) {
|
|
26325
|
+
console.log(`[BottlenecksContent] No shift provided for historical date ${date}, defaulting to day shift (0)`);
|
|
26326
|
+
return "0";
|
|
26327
|
+
} else {
|
|
26328
|
+
const currentShift = getCurrentShift2();
|
|
26329
|
+
console.log(`[BottlenecksContent] Using current operational shift: ${currentShift.shiftId} (${currentShift.shiftName})`);
|
|
26330
|
+
return currentShift.shiftId.toString();
|
|
26331
|
+
}
|
|
26332
|
+
}, [shift, date]);
|
|
26208
26333
|
const {
|
|
26209
26334
|
data: prefetchData,
|
|
26210
26335
|
isFullyIndexed,
|
|
@@ -26213,7 +26338,7 @@ var BottlenecksContent = ({
|
|
|
26213
26338
|
} = usePrefetchClipCounts({
|
|
26214
26339
|
workspaceId,
|
|
26215
26340
|
date: date || getOperationalDate(),
|
|
26216
|
-
shift:
|
|
26341
|
+
shift: effectiveShift,
|
|
26217
26342
|
enabled: !!workspaceId && !!s3ClipsService,
|
|
26218
26343
|
buildIndex: true
|
|
26219
26344
|
});
|
|
@@ -26227,7 +26352,7 @@ var BottlenecksContent = ({
|
|
|
26227
26352
|
fetchInProgressRef.current.add(operationKey);
|
|
26228
26353
|
try {
|
|
26229
26354
|
const operationalDate = date || getOperationalDate();
|
|
26230
|
-
const shiftStr =
|
|
26355
|
+
const shiftStr = effectiveShift;
|
|
26231
26356
|
console.log(`[BottlenecksContent] Fetching clip counts directly for ${workspaceId}`);
|
|
26232
26357
|
const cacheKey = `clip-counts:${workspaceId}:${operationalDate}:${shiftStr}`;
|
|
26233
26358
|
const cachedResult = await smartVideoCache.getClipCounts(cacheKey);
|
|
@@ -26268,7 +26393,7 @@ var BottlenecksContent = ({
|
|
|
26268
26393
|
} finally {
|
|
26269
26394
|
fetchInProgressRef.current.delete(operationKey);
|
|
26270
26395
|
}
|
|
26271
|
-
}, [workspaceId, date, s3ClipsService,
|
|
26396
|
+
}, [workspaceId, date, s3ClipsService, effectiveShift, dashboardConfig, updateClipCounts, updateVideoIndex]);
|
|
26272
26397
|
const loadingCategoryRef = React19.useRef(null);
|
|
26273
26398
|
const videoRetryCountRef = React19.useRef(0);
|
|
26274
26399
|
const loadingVideosRef = React19.useRef(/* @__PURE__ */ new Set());
|
|
@@ -26310,13 +26435,13 @@ var BottlenecksContent = ({
|
|
|
26310
26435
|
index,
|
|
26311
26436
|
true,
|
|
26312
26437
|
// includeCycleTime - OK for preloading
|
|
26313
|
-
|
|
26314
|
-
// includeMetadata -
|
|
26438
|
+
false
|
|
26439
|
+
// includeMetadata - NO metadata during bulk preloading to prevent flooding
|
|
26315
26440
|
);
|
|
26316
26441
|
}
|
|
26317
26442
|
if (!video) {
|
|
26318
26443
|
const operationalDate = date || getOperationalDate();
|
|
26319
|
-
const shiftStr =
|
|
26444
|
+
const shiftStr = effectiveShift;
|
|
26320
26445
|
video = await s3ClipsService.getClipByIndex(
|
|
26321
26446
|
workspaceId,
|
|
26322
26447
|
operationalDate,
|
|
@@ -26325,8 +26450,8 @@ var BottlenecksContent = ({
|
|
|
26325
26450
|
index,
|
|
26326
26451
|
true,
|
|
26327
26452
|
// includeCycleTime - OK for preloading
|
|
26328
|
-
|
|
26329
|
-
// includeMetadata -
|
|
26453
|
+
false
|
|
26454
|
+
// includeMetadata - NO metadata during bulk preloading to prevent flooding
|
|
26330
26455
|
);
|
|
26331
26456
|
}
|
|
26332
26457
|
if (video && isMountedRef.current) {
|
|
@@ -26349,7 +26474,7 @@ var BottlenecksContent = ({
|
|
|
26349
26474
|
Promise.all(loadPromises).catch((err) => {
|
|
26350
26475
|
console.warn("[ensureVideosLoaded] Some videos failed to preload:", err);
|
|
26351
26476
|
});
|
|
26352
|
-
}, [s3ClipsService, workspaceId, clipCounts, sopCategories, date,
|
|
26477
|
+
}, [s3ClipsService, workspaceId, clipCounts, sopCategories, date, effectiveShift]);
|
|
26353
26478
|
const loadFirstVideoForCategory = React19.useCallback(async (category) => {
|
|
26354
26479
|
if (!workspaceId || !s3ClipsService || !isMountedRef.current) return;
|
|
26355
26480
|
const targetCategory = category || activeFilterRef.current;
|
|
@@ -26365,7 +26490,7 @@ var BottlenecksContent = ({
|
|
|
26365
26490
|
}
|
|
26366
26491
|
try {
|
|
26367
26492
|
const operationalDate = date || getOperationalDate();
|
|
26368
|
-
const shiftStr =
|
|
26493
|
+
const shiftStr = effectiveShift;
|
|
26369
26494
|
if (!clipCounts[targetCategory] && !videoIndex) {
|
|
26370
26495
|
const cacheKey = `clip-counts:${workspaceId}:${operationalDate}:${shiftStr}`;
|
|
26371
26496
|
const cachedResult = await smartVideoCache.getClipCounts(cacheKey);
|
|
@@ -26386,8 +26511,16 @@ var BottlenecksContent = ({
|
|
|
26386
26511
|
);
|
|
26387
26512
|
if (firstVideo) {
|
|
26388
26513
|
console.log(`[BottlenecksContent] Successfully loaded first video via direct S3 method`);
|
|
26389
|
-
setAllVideos(
|
|
26514
|
+
setAllVideos((prev) => {
|
|
26515
|
+
const exists = prev.some((v) => v.id === firstVideo.id);
|
|
26516
|
+
if (!exists) {
|
|
26517
|
+
return [...prev, firstVideo];
|
|
26518
|
+
}
|
|
26519
|
+
return prev;
|
|
26520
|
+
});
|
|
26390
26521
|
preloadVideoUrl(firstVideo.src);
|
|
26522
|
+
setIsLoading(false);
|
|
26523
|
+
setHasInitialLoad(true);
|
|
26391
26524
|
loadingCategoryRef.current = null;
|
|
26392
26525
|
setIsCategoryLoading(false);
|
|
26393
26526
|
return;
|
|
@@ -26410,7 +26543,13 @@ var BottlenecksContent = ({
|
|
|
26410
26543
|
);
|
|
26411
26544
|
if (firstVideo && isMountedRef.current) {
|
|
26412
26545
|
console.log(`[BottlenecksContent] Successfully loaded first video via video index`);
|
|
26413
|
-
setAllVideos(
|
|
26546
|
+
setAllVideos((prev) => {
|
|
26547
|
+
const exists = prev.some((v) => v.id === firstVideo.id);
|
|
26548
|
+
if (!exists) {
|
|
26549
|
+
return [...prev, firstVideo];
|
|
26550
|
+
}
|
|
26551
|
+
return prev;
|
|
26552
|
+
});
|
|
26414
26553
|
preloadVideoUrl(firstVideo.src);
|
|
26415
26554
|
setIsCategoryLoading(false);
|
|
26416
26555
|
return;
|
|
@@ -26433,17 +26572,19 @@ var BottlenecksContent = ({
|
|
|
26433
26572
|
loadingCategoryRef.current = null;
|
|
26434
26573
|
fetchInProgressRef.current.delete(operationKey);
|
|
26435
26574
|
}
|
|
26436
|
-
}, [workspaceId, date, s3ClipsService, clipCounts, videoIndex,
|
|
26575
|
+
}, [workspaceId, date, s3ClipsService, clipCounts, videoIndex, effectiveShift, updateClipCounts, updateVideoIndex]);
|
|
26437
26576
|
React19.useEffect(() => {
|
|
26438
|
-
if (s3ClipsService) {
|
|
26577
|
+
if (s3ClipsService && !prefetchData) {
|
|
26439
26578
|
fetchClipCounts();
|
|
26440
26579
|
}
|
|
26441
|
-
}, [workspaceId, date,
|
|
26580
|
+
}, [workspaceId, date, effectiveShift, s3ClipsService, fetchClipCounts, updateClipCounts, updateVideoIndex, prefetchData]);
|
|
26442
26581
|
React19.useEffect(() => {
|
|
26443
26582
|
if (prefetchData) {
|
|
26444
26583
|
console.log(`[BottlenecksContent] Received prefetch update - status: ${prefetchStatus}, videos: ${prefetchData.videoIndex.allVideos.length}, ID: ${prefetchData.videoIndex._debugId || "NO_ID"}`);
|
|
26445
26584
|
updateClipCounts(prefetchData.counts);
|
|
26446
|
-
|
|
26585
|
+
if (prefetchData.videoIndex.allVideos.length > 0) {
|
|
26586
|
+
updateVideoIndex(prefetchData.videoIndex);
|
|
26587
|
+
}
|
|
26447
26588
|
if (!hasInitialLoad && prefetchData.videoIndex.allVideos.length > 0) {
|
|
26448
26589
|
setIsLoading(false);
|
|
26449
26590
|
setHasInitialLoad(true);
|
|
@@ -26451,12 +26592,45 @@ var BottlenecksContent = ({
|
|
|
26451
26592
|
}
|
|
26452
26593
|
}, [prefetchData, prefetchStatus, updateClipCounts, updateVideoIndex, hasInitialLoad]);
|
|
26453
26594
|
React19.useEffect(() => {
|
|
26454
|
-
if (s3ClipsService &&
|
|
26455
|
-
|
|
26595
|
+
if (s3ClipsService && clipCounts[activeFilter] > 0) {
|
|
26596
|
+
const hasVideosForCurrentFilter = allVideos.some((video) => {
|
|
26597
|
+
if (sopCategories && sopCategories.length > 0) {
|
|
26598
|
+
const selectedCategory = sopCategories.find((cat) => cat.id === activeFilter);
|
|
26599
|
+
if (selectedCategory) {
|
|
26600
|
+
return video.type === selectedCategory.id;
|
|
26601
|
+
}
|
|
26602
|
+
}
|
|
26603
|
+
if (activeFilter === "all") return true;
|
|
26604
|
+
if (activeFilter === "low_value") {
|
|
26605
|
+
return video.type === "low_value";
|
|
26606
|
+
}
|
|
26607
|
+
if (activeFilter === "idle_time") {
|
|
26608
|
+
return video.type === "idle_time";
|
|
26609
|
+
}
|
|
26610
|
+
if (activeFilter === "sop_deviations") {
|
|
26611
|
+
return video.type === "missing_quality_check";
|
|
26612
|
+
}
|
|
26613
|
+
if (activeFilter === "best_cycle_time") {
|
|
26614
|
+
return video.type === "best_cycle_time";
|
|
26615
|
+
}
|
|
26616
|
+
if (activeFilter === "worst_cycle_time") {
|
|
26617
|
+
return video.type === "worst_cycle_time";
|
|
26618
|
+
}
|
|
26619
|
+
if (activeFilter === "cycle_completion") {
|
|
26620
|
+
return video.type === "cycle_completion";
|
|
26621
|
+
}
|
|
26622
|
+
if (activeFilter === "long_cycle_time") {
|
|
26623
|
+
return video.type === "long_cycle_time";
|
|
26624
|
+
}
|
|
26625
|
+
return video.type === "bottleneck" && video.severity === activeFilter;
|
|
26626
|
+
});
|
|
26627
|
+
if (!hasVideosForCurrentFilter) {
|
|
26456
26628
|
loadFirstVideoForCategory(activeFilter);
|
|
26629
|
+
} else {
|
|
26630
|
+
setIsCategoryLoading(false);
|
|
26457
26631
|
}
|
|
26458
26632
|
}
|
|
26459
|
-
}, [activeFilter, s3ClipsService, videoIndex, clipCounts, loadFirstVideoForCategory, allVideos
|
|
26633
|
+
}, [activeFilter, s3ClipsService, videoIndex, clipCounts, loadFirstVideoForCategory, allVideos, sopCategories]);
|
|
26460
26634
|
React19.useEffect(() => {
|
|
26461
26635
|
if (previousFilterRef.current !== activeFilter) {
|
|
26462
26636
|
console.log(`Filter changed from ${previousFilterRef.current} to ${activeFilter} - resetting to first video`);
|
|
@@ -26590,7 +26764,7 @@ var BottlenecksContent = ({
|
|
|
26590
26764
|
}
|
|
26591
26765
|
if (!video && s3ClipsService) {
|
|
26592
26766
|
const operationalDate = date || getOperationalDate();
|
|
26593
|
-
const shiftStr =
|
|
26767
|
+
const shiftStr = effectiveShift;
|
|
26594
26768
|
video = await s3ClipsService.getClipByIndex(
|
|
26595
26769
|
workspaceId,
|
|
26596
26770
|
operationalDate,
|
|
@@ -26626,7 +26800,7 @@ var BottlenecksContent = ({
|
|
|
26626
26800
|
}
|
|
26627
26801
|
}
|
|
26628
26802
|
}
|
|
26629
|
-
}, [clipCounts, filteredVideos.length, s3ClipsService, workspaceId, date,
|
|
26803
|
+
}, [clipCounts, filteredVideos.length, s3ClipsService, workspaceId, date, effectiveShift]);
|
|
26630
26804
|
const handlePrevious = React19.useCallback(() => {
|
|
26631
26805
|
if (!isMountedRef.current) return;
|
|
26632
26806
|
const currentIdx = currentIndexRef.current;
|
|
@@ -26639,14 +26813,39 @@ var BottlenecksContent = ({
|
|
|
26639
26813
|
}
|
|
26640
26814
|
}
|
|
26641
26815
|
}, [filteredVideos.length]);
|
|
26816
|
+
const currentVideo = React19.useMemo(() => {
|
|
26817
|
+
if (!filteredVideos || filteredVideos.length === 0 || currentIndex >= filteredVideos.length) {
|
|
26818
|
+
return null;
|
|
26819
|
+
}
|
|
26820
|
+
return filteredVideos[currentIndex];
|
|
26821
|
+
}, [filteredVideos, currentIndex]);
|
|
26642
26822
|
const handleVideoReady = React19.useCallback((player) => {
|
|
26643
26823
|
console.log("Video.js player ready");
|
|
26644
26824
|
}, []);
|
|
26645
|
-
const handleVideoPlay = React19.useCallback((player) => {
|
|
26825
|
+
const handleVideoPlay = React19.useCallback(async (player) => {
|
|
26646
26826
|
setIsPlaying(true);
|
|
26647
26827
|
const currentIdx = currentIndexRef.current;
|
|
26648
26828
|
ensureVideosLoaded(currentIdx);
|
|
26649
|
-
|
|
26829
|
+
if (currentVideo && !currentVideo.creation_timestamp && s3ClipsService) {
|
|
26830
|
+
try {
|
|
26831
|
+
const originalUri = currentVideo.originalUri || currentVideo.src;
|
|
26832
|
+
if (originalUri && originalUri.includes("s3://")) {
|
|
26833
|
+
const metadata = await s3ClipsService.getFullMetadata(originalUri);
|
|
26834
|
+
if (metadata && isMountedRef.current) {
|
|
26835
|
+
setAllVideos((prev) => prev.map(
|
|
26836
|
+
(v) => v.id === currentVideo.id ? {
|
|
26837
|
+
...v,
|
|
26838
|
+
creation_timestamp: metadata.upload_timestamp || metadata.original_task_metadata?.timestamp || metadata.creation_timestamp,
|
|
26839
|
+
cycle_time_seconds: metadata.original_task_metadata?.cycle_time || v.cycle_time_seconds
|
|
26840
|
+
} : v
|
|
26841
|
+
));
|
|
26842
|
+
}
|
|
26843
|
+
}
|
|
26844
|
+
} catch (error2) {
|
|
26845
|
+
console.warn("[BottlenecksContent] Failed to load metadata for current video:", error2);
|
|
26846
|
+
}
|
|
26847
|
+
}
|
|
26848
|
+
}, [currentVideo, s3ClipsService]);
|
|
26650
26849
|
const handleVideoPause = React19.useCallback((player) => {
|
|
26651
26850
|
setIsPlaying(false);
|
|
26652
26851
|
}, []);
|
|
@@ -26673,13 +26872,6 @@ var BottlenecksContent = ({
|
|
|
26673
26872
|
fetchInProgressRef.current.clear();
|
|
26674
26873
|
setIsCategoryLoading(false);
|
|
26675
26874
|
setIsNavigating(false);
|
|
26676
|
-
if (s3ClipsService) {
|
|
26677
|
-
try {
|
|
26678
|
-
s3ClipsService.dispose();
|
|
26679
|
-
} catch (error2) {
|
|
26680
|
-
console.warn("[BottlenecksContent] Error disposing S3 service:", error2);
|
|
26681
|
-
}
|
|
26682
|
-
}
|
|
26683
26875
|
};
|
|
26684
26876
|
}, [s3ClipsService]);
|
|
26685
26877
|
React19.useEffect(() => {
|
|
@@ -26720,12 +26912,6 @@ var BottlenecksContent = ({
|
|
|
26720
26912
|
counts.bottlenecks = counts.bottleneck || counts.bottlenecks || 0;
|
|
26721
26913
|
return counts;
|
|
26722
26914
|
}, [clipCounts]);
|
|
26723
|
-
const currentVideo = React19.useMemo(() => {
|
|
26724
|
-
if (!filteredVideos || filteredVideos.length === 0 || currentIndex >= filteredVideos.length) {
|
|
26725
|
-
return null;
|
|
26726
|
-
}
|
|
26727
|
-
return filteredVideos[currentIndex];
|
|
26728
|
-
}, [filteredVideos, currentIndex]);
|
|
26729
26915
|
const getClipTypeLabel = (video) => {
|
|
26730
26916
|
if (!video) return "";
|
|
26731
26917
|
switch (video.type) {
|
|
@@ -26960,8 +27146,8 @@ var BottlenecksContent = ({
|
|
|
26960
27146
|
] }),
|
|
26961
27147
|
/* Priority 1: Show loading if initial load hasn't completed yet */
|
|
26962
27148
|
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..." }) }) }) }) : (
|
|
26963
|
-
/* Priority 2: Show loading if category is loading
|
|
26964
|
-
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..." }) }) }) }) : (
|
|
27149
|
+
/* Priority 2: Show loading if category is loading BUT only if no video is available */
|
|
27150
|
+
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..." }) }) }) }) : (
|
|
26965
27151
|
/* Priority 3: Show loading if navigating and current video not available */
|
|
26966
27152
|
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..." }) }) }) }) : (
|
|
26967
27153
|
/* Priority 4: Show video if we have filtered videos and current video */
|
|
@@ -31759,9 +31945,25 @@ function withWorkspaceDisplayNames(Component3, options = {}) {
|
|
|
31759
31945
|
return function WithWorkspaceDisplayNamesWrapper(props) {
|
|
31760
31946
|
const [isInitialized2, setIsInitialized] = React19.useState(false);
|
|
31761
31947
|
const [error, setError] = React19.useState(null);
|
|
31948
|
+
const [lastInitKey, setLastInitKey] = React19.useState("");
|
|
31949
|
+
const lineIdsKey = React19.useMemo(() => {
|
|
31950
|
+
if (!props.lineIds) return "";
|
|
31951
|
+
if (Array.isArray(props.lineIds)) {
|
|
31952
|
+
return props.lineIds.sort().join(",");
|
|
31953
|
+
}
|
|
31954
|
+
const values = Object.values(props.lineIds).filter(Boolean);
|
|
31955
|
+
return values.sort().join(",");
|
|
31956
|
+
}, [props.lineIds]);
|
|
31957
|
+
const initKey = React19.useMemo(() => {
|
|
31958
|
+
return `${lineIdsKey}-${props.selectedLineId || ""}-${props.factoryViewId || ""}-${initializeFor}`;
|
|
31959
|
+
}, [lineIdsKey, props.selectedLineId, props.factoryViewId]);
|
|
31762
31960
|
React19.useEffect(() => {
|
|
31763
|
-
|
|
31764
|
-
|
|
31961
|
+
if (initKey === lastInitKey && isInitialized2) {
|
|
31962
|
+
return;
|
|
31963
|
+
}
|
|
31964
|
+
if (initKey !== lastInitKey) {
|
|
31965
|
+
setError(null);
|
|
31966
|
+
}
|
|
31765
31967
|
const initializeDisplayNames = async () => {
|
|
31766
31968
|
try {
|
|
31767
31969
|
const { lineIds, selectedLineId, factoryViewId } = props;
|
|
@@ -31787,20 +31989,17 @@ function withWorkspaceDisplayNames(Component3, options = {}) {
|
|
|
31787
31989
|
await preInitializeWorkspaceDisplayNames();
|
|
31788
31990
|
}
|
|
31789
31991
|
setIsInitialized(true);
|
|
31992
|
+
setLastInitKey(initKey);
|
|
31790
31993
|
} catch (err) {
|
|
31791
31994
|
console.error("Failed to initialize workspace display names:", err);
|
|
31792
31995
|
setError(err);
|
|
31793
31996
|
setIsInitialized(true);
|
|
31997
|
+
setLastInitKey(initKey);
|
|
31794
31998
|
}
|
|
31795
31999
|
};
|
|
31796
32000
|
initializeDisplayNames();
|
|
31797
|
-
}, [
|
|
31798
|
-
|
|
31799
|
-
props.selectedLineId,
|
|
31800
|
-
props.factoryViewId,
|
|
31801
|
-
initializeFor
|
|
31802
|
-
]);
|
|
31803
|
-
if (!isInitialized2 && showLoading) {
|
|
32001
|
+
}, [initKey]);
|
|
32002
|
+
if (!isInitialized2 && showLoading && lastInitKey === "") {
|
|
31804
32003
|
return /* @__PURE__ */ jsxRuntime.jsx(LoadingPage, { message: loadingMessage });
|
|
31805
32004
|
}
|
|
31806
32005
|
if (error && showLoading) {
|
|
@@ -33871,7 +34070,15 @@ var ShiftsView = ({
|
|
|
33871
34070
|
className = ""
|
|
33872
34071
|
}) => {
|
|
33873
34072
|
const supabase = useSupabase();
|
|
33874
|
-
|
|
34073
|
+
React19.useEffect(() => {
|
|
34074
|
+
console.log("[ShiftsView] Component mounted/re-rendered", {
|
|
34075
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
34076
|
+
lineIds: lineIds.length
|
|
34077
|
+
});
|
|
34078
|
+
return () => {
|
|
34079
|
+
console.log("[ShiftsView] Component unmounting");
|
|
34080
|
+
};
|
|
34081
|
+
}, []);
|
|
33875
34082
|
const [lineConfigs, setLineConfigs] = React19.useState(
|
|
33876
34083
|
() => lineIds.map((id3) => ({
|
|
33877
34084
|
id: id3,
|
|
@@ -33969,7 +34176,7 @@ var ShiftsView = ({
|
|
|
33969
34176
|
}
|
|
33970
34177
|
};
|
|
33971
34178
|
fetchShiftConfigs();
|
|
33972
|
-
}, [
|
|
34179
|
+
}, [lineIds, showToast]);
|
|
33973
34180
|
React19.useCallback((lineId) => {
|
|
33974
34181
|
setLineConfigs((prev) => {
|
|
33975
34182
|
const typedPrev = prev;
|
|
@@ -34162,7 +34369,6 @@ var ShiftsView = ({
|
|
|
34162
34369
|
}));
|
|
34163
34370
|
}, []);
|
|
34164
34371
|
const handleSaveShifts = React19.useCallback(async (lineId) => {
|
|
34165
|
-
if (!auth.user?.id && false) ;
|
|
34166
34372
|
setLineConfigs((prev) => prev.map(
|
|
34167
34373
|
(config) => config.id === lineId ? { ...config, isSaving: true, saveSuccess: false } : config
|
|
34168
34374
|
));
|
|
@@ -34209,7 +34415,7 @@ var ShiftsView = ({
|
|
|
34209
34415
|
(config) => config.id === lineId ? { ...config, isSaving: false, saveSuccess: false } : config
|
|
34210
34416
|
));
|
|
34211
34417
|
}
|
|
34212
|
-
}, [
|
|
34418
|
+
}, [lineConfigs, supabase, showToast]);
|
|
34213
34419
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `min-h-screen bg-slate-50 ${className}`, children: [
|
|
34214
34420
|
/* @__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: [
|
|
34215
34421
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
@@ -34317,6 +34523,7 @@ var ShiftsView = ({
|
|
|
34317
34523
|
] })
|
|
34318
34524
|
] });
|
|
34319
34525
|
};
|
|
34526
|
+
var AuthenticatedShiftsView = withAuth(React19__namespace.default.memo(ShiftsView));
|
|
34320
34527
|
var ShiftsView_default = ShiftsView;
|
|
34321
34528
|
|
|
34322
34529
|
// src/lib/constants/actions.ts
|
|
@@ -35104,6 +35311,7 @@ var TargetsViewUI = ({
|
|
|
35104
35311
|
isLoading,
|
|
35105
35312
|
lineWorkspaces,
|
|
35106
35313
|
lineNames,
|
|
35314
|
+
dropdownStates,
|
|
35107
35315
|
savingLines,
|
|
35108
35316
|
saveSuccess,
|
|
35109
35317
|
selectedShift,
|
|
@@ -35189,13 +35397,13 @@ var TargetsViewUI = ({
|
|
|
35189
35397
|
{
|
|
35190
35398
|
onClick: () => onToggleLineDropdown(lineId),
|
|
35191
35399
|
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",
|
|
35192
|
-
"aria-expanded":
|
|
35400
|
+
"aria-expanded": dropdownStates[lineId],
|
|
35193
35401
|
"aria-controls": `line-${lineId}-content`,
|
|
35194
35402
|
children: [
|
|
35195
35403
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
35196
35404
|
lucideReact.ChevronDown,
|
|
35197
35405
|
{
|
|
35198
|
-
className: `w-5 h-5 text-blue-500 transform transition-transform duration-200 ${
|
|
35406
|
+
className: `w-5 h-5 text-blue-500 transform transition-transform duration-200 ${dropdownStates[lineId] ? "rotate-180" : ""}`
|
|
35199
35407
|
}
|
|
35200
35408
|
),
|
|
35201
35409
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2.5", children: [
|
|
@@ -35242,7 +35450,7 @@ var TargetsViewUI = ({
|
|
|
35242
35450
|
)
|
|
35243
35451
|
] })
|
|
35244
35452
|
] }) }),
|
|
35245
|
-
|
|
35453
|
+
dropdownStates[lineId] && /* @__PURE__ */ jsxRuntime.jsxs("div", { id: `line-${lineId}-content`, className: "border-t border-gray-200", children: [
|
|
35246
35454
|
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: [
|
|
35247
35455
|
/* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: `sku-${lineId}`, className: "text-sm font-medium text-gray-700", children: "Select SKU:" }),
|
|
35248
35456
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 max-w-md", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -35279,68 +35487,71 @@ var TargetsViewUI = ({
|
|
|
35279
35487
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-gray-400", children: "pieces per day" })
|
|
35280
35488
|
] })
|
|
35281
35489
|
] }) }),
|
|
35282
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "divide-y divide-gray-100", children: line.workspaces.map((workspace) =>
|
|
35283
|
-
|
|
35284
|
-
|
|
35285
|
-
|
|
35286
|
-
|
|
35287
|
-
|
|
35288
|
-
/* @__PURE__ */ jsxRuntime.
|
|
35289
|
-
"
|
|
35290
|
-
{
|
|
35291
|
-
|
|
35292
|
-
|
|
35293
|
-
|
|
35294
|
-
|
|
35295
|
-
|
|
35296
|
-
|
|
35297
|
-
|
|
35298
|
-
|
|
35299
|
-
|
|
35300
|
-
|
|
35301
|
-
|
|
35302
|
-
|
|
35303
|
-
|
|
35304
|
-
|
|
35305
|
-
|
|
35306
|
-
{
|
|
35307
|
-
|
|
35308
|
-
|
|
35309
|
-
|
|
35310
|
-
|
|
35311
|
-
|
|
35312
|
-
|
|
35313
|
-
|
|
35314
|
-
|
|
35315
|
-
|
|
35316
|
-
|
|
35317
|
-
|
|
35318
|
-
{
|
|
35319
|
-
|
|
35320
|
-
|
|
35321
|
-
|
|
35322
|
-
|
|
35323
|
-
|
|
35324
|
-
|
|
35325
|
-
|
|
35326
|
-
|
|
35327
|
-
|
|
35328
|
-
|
|
35329
|
-
|
|
35330
|
-
{
|
|
35331
|
-
|
|
35332
|
-
|
|
35333
|
-
|
|
35334
|
-
|
|
35335
|
-
|
|
35336
|
-
|
|
35337
|
-
|
|
35338
|
-
|
|
35339
|
-
|
|
35340
|
-
|
|
35341
|
-
|
|
35342
|
-
|
|
35343
|
-
|
|
35490
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "divide-y divide-gray-100", children: line.workspaces.map((workspace) => {
|
|
35491
|
+
const formattedName = formatWorkspaceName(workspace.name, lineId);
|
|
35492
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
35493
|
+
"div",
|
|
35494
|
+
{
|
|
35495
|
+
className: "px-6 py-4 hover:bg-gray-50 transition-all duration-200",
|
|
35496
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-12 gap-6 items-center", children: [
|
|
35497
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "col-span-2", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium text-gray-900", children: formattedName }) }),
|
|
35498
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "col-span-2", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
35499
|
+
"select",
|
|
35500
|
+
{
|
|
35501
|
+
value: workspace.actionType,
|
|
35502
|
+
onChange: (e) => {
|
|
35503
|
+
const newActionType = e.target.value;
|
|
35504
|
+
onActionTypeChange(lineId, workspace.id, newActionType);
|
|
35505
|
+
},
|
|
35506
|
+
className: "w-full p-2 border border-gray-300 rounded-md shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm",
|
|
35507
|
+
"aria-label": `Action type for ${formattedName}`,
|
|
35508
|
+
children: [
|
|
35509
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "assembly", className: "py-2", children: "Assembly" }),
|
|
35510
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "packaging", className: "py-2", children: "Packaging" })
|
|
35511
|
+
]
|
|
35512
|
+
}
|
|
35513
|
+
) }),
|
|
35514
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "col-span-3", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
35515
|
+
"input",
|
|
35516
|
+
{
|
|
35517
|
+
type: "number",
|
|
35518
|
+
value: workspace.targetCycleTime === 0 ? "" : workspace.targetCycleTime,
|
|
35519
|
+
onChange: (e) => onUpdateWorkspaceTarget(lineId, workspace.id, "targetCycleTime", Number(e.target.value) || ""),
|
|
35520
|
+
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",
|
|
35521
|
+
min: "0",
|
|
35522
|
+
step: "0.01",
|
|
35523
|
+
placeholder: "Enter cycle time"
|
|
35524
|
+
}
|
|
35525
|
+
) }),
|
|
35526
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "col-span-3", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
35527
|
+
"input",
|
|
35528
|
+
{
|
|
35529
|
+
type: "number",
|
|
35530
|
+
value: workspace.targetPPH === 0 ? "" : workspace.targetPPH,
|
|
35531
|
+
onChange: (e) => onUpdateWorkspaceTarget(lineId, workspace.id, "targetPPH", Number(e.target.value) || ""),
|
|
35532
|
+
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",
|
|
35533
|
+
min: "0",
|
|
35534
|
+
step: "0.1",
|
|
35535
|
+
placeholder: "Enter PPH"
|
|
35536
|
+
}
|
|
35537
|
+
) }),
|
|
35538
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "col-span-2", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
35539
|
+
"input",
|
|
35540
|
+
{
|
|
35541
|
+
type: "number",
|
|
35542
|
+
value: workspace.targetDayOutput === 0 ? "" : workspace.targetDayOutput,
|
|
35543
|
+
onChange: (e) => onUpdateWorkspaceTarget(lineId, workspace.id, "targetDayOutput", Number(e.target.value) || ""),
|
|
35544
|
+
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",
|
|
35545
|
+
min: "0",
|
|
35546
|
+
step: "1",
|
|
35547
|
+
placeholder: "Enter day output"
|
|
35548
|
+
}
|
|
35549
|
+
) })
|
|
35550
|
+
] })
|
|
35551
|
+
},
|
|
35552
|
+
workspace.id
|
|
35553
|
+
);
|
|
35554
|
+
}) })
|
|
35344
35555
|
] })
|
|
35345
35556
|
]
|
|
35346
35557
|
},
|
|
@@ -35373,7 +35584,6 @@ var TargetsView = ({
|
|
|
35373
35584
|
return lineIds.reduce((acc, lineId) => ({
|
|
35374
35585
|
...acc,
|
|
35375
35586
|
[lineId]: {
|
|
35376
|
-
isOpen: getStoredLineState2(lineId),
|
|
35377
35587
|
productId: "",
|
|
35378
35588
|
shiftStartTime: "08:00",
|
|
35379
35589
|
shiftEndTime: "19:00",
|
|
@@ -35386,6 +35596,12 @@ var TargetsView = ({
|
|
|
35386
35596
|
}
|
|
35387
35597
|
}), {});
|
|
35388
35598
|
}, [lineIds]);
|
|
35599
|
+
const [dropdownStates, setDropdownStates] = React19.useState(() => {
|
|
35600
|
+
return lineIds.reduce((acc, lineId) => ({
|
|
35601
|
+
...acc,
|
|
35602
|
+
[lineId]: getStoredLineState2(lineId)
|
|
35603
|
+
}), {});
|
|
35604
|
+
});
|
|
35389
35605
|
const [allShiftsData, setAllShiftsData] = React19.useState({
|
|
35390
35606
|
0: initialLineWorkspaces,
|
|
35391
35607
|
// Day shift
|
|
@@ -35403,6 +35619,8 @@ var TargetsView = ({
|
|
|
35403
35619
|
const [isBulkConfigureOpen, setIsBulkConfigureOpen] = React19.useState(false);
|
|
35404
35620
|
const [selectedWorkspaces, setSelectedWorkspaces] = React19.useState([]);
|
|
35405
35621
|
const [selectedShift, setSelectedShift] = React19.useState(0);
|
|
35622
|
+
const [dbValues, setDbValues] = React19.useState({ 0: {}, 1: {} });
|
|
35623
|
+
const [userEditedFields, setUserEditedFields] = React19.useState(/* @__PURE__ */ new Set());
|
|
35406
35624
|
const lineWorkspaces = allShiftsData[selectedShift] || initialLineWorkspaces;
|
|
35407
35625
|
const setLineWorkspaces = React19.useCallback((updater) => {
|
|
35408
35626
|
setAllShiftsData((prev) => ({
|
|
@@ -35411,18 +35629,123 @@ var TargetsView = ({
|
|
|
35411
35629
|
}));
|
|
35412
35630
|
}, [selectedShift]);
|
|
35413
35631
|
const supabase = useSupabase();
|
|
35414
|
-
const
|
|
35415
|
-
userId || auth?.user?.id;
|
|
35632
|
+
const effectiveUserId = userId || "6bf6f271-1e55-4a95-9b89-1c3820b58739";
|
|
35416
35633
|
const dashboardConfig = useDashboardConfig();
|
|
35417
35634
|
const { skus, isLoading: skusLoading } = useSKUs(companyId);
|
|
35418
35635
|
const skuEnabled = dashboardConfig?.skuConfig?.enabled || false;
|
|
35636
|
+
const loadOperatingHours = React19.useCallback(async (lineId, shiftId) => {
|
|
35637
|
+
try {
|
|
35638
|
+
if (!supabase) return null;
|
|
35639
|
+
const { data, error } = await supabase.from("line_operating_hours").select("start_time, end_time, breaks").eq("line_id", lineId).eq("shift_id", shiftId).maybeSingle();
|
|
35640
|
+
if (error) {
|
|
35641
|
+
if (error.code === "PGRST116") {
|
|
35642
|
+
console.log(`No operating hours found for line ${lineId}, shift ${shiftId}`);
|
|
35643
|
+
return {
|
|
35644
|
+
startTime: "08:00",
|
|
35645
|
+
// Default values
|
|
35646
|
+
endTime: "19:00",
|
|
35647
|
+
breaks: []
|
|
35648
|
+
};
|
|
35649
|
+
} else {
|
|
35650
|
+
console.error("Error fetching operating hours:", error);
|
|
35651
|
+
return null;
|
|
35652
|
+
}
|
|
35653
|
+
}
|
|
35654
|
+
let breaks = [];
|
|
35655
|
+
if (data?.breaks) {
|
|
35656
|
+
if (Array.isArray(data.breaks)) {
|
|
35657
|
+
breaks = data.breaks.map((breakItem) => {
|
|
35658
|
+
const startTime = breakItem.start || breakItem.startTime || "00:00";
|
|
35659
|
+
const endTime = breakItem.end || breakItem.endTime || "00:00";
|
|
35660
|
+
const calculateDuration = (start, end) => {
|
|
35661
|
+
const [startHour, startMinute] = start.split(":").map(Number);
|
|
35662
|
+
const [endHour, endMinute] = end.split(":").map(Number);
|
|
35663
|
+
let startMinutes = startHour * 60 + startMinute;
|
|
35664
|
+
let endMinutes = endHour * 60 + endMinute;
|
|
35665
|
+
if (endMinutes < startMinutes) {
|
|
35666
|
+
endMinutes += 24 * 60;
|
|
35667
|
+
}
|
|
35668
|
+
return endMinutes - startMinutes;
|
|
35669
|
+
};
|
|
35670
|
+
return {
|
|
35671
|
+
startTime,
|
|
35672
|
+
endTime,
|
|
35673
|
+
duration: breakItem.duration || calculateDuration(startTime, endTime)
|
|
35674
|
+
};
|
|
35675
|
+
});
|
|
35676
|
+
} else if (typeof data.breaks === "object" && data.breaks.breaks) {
|
|
35677
|
+
breaks = data.breaks.breaks.map((breakItem) => {
|
|
35678
|
+
const startTime = breakItem.start || breakItem.startTime || "00:00";
|
|
35679
|
+
const endTime = breakItem.end || breakItem.endTime || "00:00";
|
|
35680
|
+
const calculateDuration = (start, end) => {
|
|
35681
|
+
const [startHour, startMinute] = start.split(":").map(Number);
|
|
35682
|
+
const [endHour, endMinute] = end.split(":").map(Number);
|
|
35683
|
+
let startMinutes = startHour * 60 + startMinute;
|
|
35684
|
+
let endMinutes = endHour * 60 + endMinute;
|
|
35685
|
+
if (endMinutes < startMinutes) {
|
|
35686
|
+
endMinutes += 24 * 60;
|
|
35687
|
+
}
|
|
35688
|
+
return endMinutes - startMinutes;
|
|
35689
|
+
};
|
|
35690
|
+
return {
|
|
35691
|
+
startTime,
|
|
35692
|
+
endTime,
|
|
35693
|
+
duration: breakItem.duration || calculateDuration(startTime, endTime)
|
|
35694
|
+
};
|
|
35695
|
+
});
|
|
35696
|
+
} else if (typeof data.breaks === "string") {
|
|
35697
|
+
try {
|
|
35698
|
+
const parsedBreaks = JSON.parse(data.breaks);
|
|
35699
|
+
if (Array.isArray(parsedBreaks)) {
|
|
35700
|
+
breaks = parsedBreaks.map((breakItem) => ({
|
|
35701
|
+
startTime: breakItem.start || breakItem.startTime || "00:00",
|
|
35702
|
+
endTime: breakItem.end || breakItem.endTime || "00:00",
|
|
35703
|
+
duration: breakItem.duration || 0
|
|
35704
|
+
}));
|
|
35705
|
+
} else if (parsedBreaks.breaks && Array.isArray(parsedBreaks.breaks)) {
|
|
35706
|
+
breaks = parsedBreaks.breaks.map((breakItem) => ({
|
|
35707
|
+
startTime: breakItem.start || breakItem.startTime || "00:00",
|
|
35708
|
+
endTime: breakItem.end || breakItem.endTime || "00:00",
|
|
35709
|
+
duration: breakItem.duration || 0
|
|
35710
|
+
}));
|
|
35711
|
+
}
|
|
35712
|
+
} catch (e) {
|
|
35713
|
+
console.error("Error parsing breaks data:", e);
|
|
35714
|
+
}
|
|
35715
|
+
}
|
|
35716
|
+
}
|
|
35717
|
+
return {
|
|
35718
|
+
startTime: data?.start_time || "08:00",
|
|
35719
|
+
endTime: data?.end_time || "19:00",
|
|
35720
|
+
breaks
|
|
35721
|
+
};
|
|
35722
|
+
} catch (e) {
|
|
35723
|
+
console.error("Exception when loading operating hours:", e);
|
|
35724
|
+
return {
|
|
35725
|
+
startTime: "08:00",
|
|
35726
|
+
endTime: "19:00",
|
|
35727
|
+
breaks: []
|
|
35728
|
+
};
|
|
35729
|
+
}
|
|
35730
|
+
}, [supabase]);
|
|
35731
|
+
React19.useEffect(() => {
|
|
35732
|
+
console.log("[TargetsView] Component mounted/re-rendered", {
|
|
35733
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
35734
|
+
lineIds: lineIds.length,
|
|
35735
|
+
effectiveUserId
|
|
35736
|
+
});
|
|
35737
|
+
return () => {
|
|
35738
|
+
console.log("[TargetsView] Component unmounting");
|
|
35739
|
+
};
|
|
35740
|
+
}, []);
|
|
35419
35741
|
React19.useEffect(() => {
|
|
35420
35742
|
let timeoutId;
|
|
35421
35743
|
let retryCount = 0;
|
|
35422
35744
|
const MAX_RETRIES2 = 2;
|
|
35423
35745
|
const LOADING_TIMEOUT = 15e3;
|
|
35424
35746
|
const fetchInitialData = async () => {
|
|
35425
|
-
if (
|
|
35747
|
+
if (lineIds.length === 0) return;
|
|
35748
|
+
console.log("[TargetsView] Starting fetchInitialData");
|
|
35426
35749
|
setIsLoading(true);
|
|
35427
35750
|
timeoutId = setTimeout(() => {
|
|
35428
35751
|
console.error("Loading timeout reached");
|
|
@@ -35486,10 +35809,32 @@ var TargetsView = ({
|
|
|
35486
35809
|
const actionThresholds = await workspaceService.getActionThresholds(
|
|
35487
35810
|
lineId,
|
|
35488
35811
|
currentDate,
|
|
35489
|
-
|
|
35812
|
+
0
|
|
35813
|
+
// Always use day shift for initial load
|
|
35490
35814
|
);
|
|
35815
|
+
const operatingHoursData = await loadOperatingHours(lineId, 0);
|
|
35816
|
+
if (operatingHoursData) {
|
|
35817
|
+
updatedLineWorkspaces[lineId].shiftStartTime = operatingHoursData.startTime;
|
|
35818
|
+
updatedLineWorkspaces[lineId].shiftEndTime = operatingHoursData.endTime;
|
|
35819
|
+
updatedLineWorkspaces[lineId].breaks = operatingHoursData.breaks;
|
|
35820
|
+
updatedLineWorkspaces[lineId].shiftHours = calculateShiftHours2(
|
|
35821
|
+
operatingHoursData.startTime,
|
|
35822
|
+
operatingHoursData.endTime,
|
|
35823
|
+
operatingHoursData.breaks
|
|
35824
|
+
);
|
|
35825
|
+
}
|
|
35491
35826
|
const mappedWorkspaces = enabledWorkspaces.map((ws) => {
|
|
35492
35827
|
const threshold = actionThresholds.find((t) => t.workspace_id === ws.id);
|
|
35828
|
+
if (!dbValues[0][lineId]) {
|
|
35829
|
+
dbValues[0][lineId] = {};
|
|
35830
|
+
}
|
|
35831
|
+
if (threshold) {
|
|
35832
|
+
dbValues[0][lineId][ws.id] = {
|
|
35833
|
+
targetPPH: threshold.pph_threshold,
|
|
35834
|
+
targetCycleTime: threshold.ideal_cycle_time,
|
|
35835
|
+
targetDayOutput: threshold.total_day_output
|
|
35836
|
+
};
|
|
35837
|
+
}
|
|
35493
35838
|
return {
|
|
35494
35839
|
id: ws.id,
|
|
35495
35840
|
name: ws.workspace_id,
|
|
@@ -35530,90 +35875,7 @@ var TargetsView = ({
|
|
|
35530
35875
|
return () => {
|
|
35531
35876
|
clearTimeout(timeoutId);
|
|
35532
35877
|
};
|
|
35533
|
-
}, [
|
|
35534
|
-
React19.useCallback(async (shiftId) => {
|
|
35535
|
-
try {
|
|
35536
|
-
if (!supabase) return;
|
|
35537
|
-
const currentDate = getOperationalDate();
|
|
35538
|
-
const updatedLineWorkspaces = { ...lineWorkspaces };
|
|
35539
|
-
let hasUpdates = false;
|
|
35540
|
-
for (const lineId of lineIds) {
|
|
35541
|
-
const lineState = lineWorkspaces[lineId];
|
|
35542
|
-
if (!lineState || !lineState.factoryId) {
|
|
35543
|
-
console.warn(`Skipping line thresholds for ${lineId} as factoryId is not yet available.`);
|
|
35544
|
-
continue;
|
|
35545
|
-
}
|
|
35546
|
-
const currentFactoryId = lineState.factoryId;
|
|
35547
|
-
try {
|
|
35548
|
-
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);
|
|
35549
|
-
if (thresholdError) {
|
|
35550
|
-
console.error(`Error fetching line threshold for line ${lineId}, factory ${currentFactoryId}:`, thresholdError);
|
|
35551
|
-
continue;
|
|
35552
|
-
}
|
|
35553
|
-
let determinedProductId = updatedLineWorkspaces[lineId]?.productId || "";
|
|
35554
|
-
if (lineThresholdsRows && lineThresholdsRows.length > 0) {
|
|
35555
|
-
if (lineThresholdsRows.length > 1) {
|
|
35556
|
-
console.warn(
|
|
35557
|
-
`Multiple line_thresholds records found for line ${lineId}, factory ${currentFactoryId}, date ${currentDate}, shift ${selectedShift}. Using product_code from the first record. Rows:`,
|
|
35558
|
-
lineThresholdsRows
|
|
35559
|
-
);
|
|
35560
|
-
}
|
|
35561
|
-
determinedProductId = lineThresholdsRows[0].product_code;
|
|
35562
|
-
} else {
|
|
35563
|
-
console.log(
|
|
35564
|
-
`No line_thresholds record found for line ${lineId}, factory ${currentFactoryId}, date ${currentDate}, shift ${selectedShift}. Using existing/default product ID.`
|
|
35565
|
-
);
|
|
35566
|
-
}
|
|
35567
|
-
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();
|
|
35568
|
-
if (hoursError) {
|
|
35569
|
-
console.error(`Error fetching operating hours for line ${lineId}:`, hoursError);
|
|
35570
|
-
continue;
|
|
35571
|
-
}
|
|
35572
|
-
const startTime = operatingHours?.start_time || updatedLineWorkspaces[lineId]?.shiftStartTime || "08:00";
|
|
35573
|
-
const endTime = operatingHours?.end_time || updatedLineWorkspaces[lineId]?.shiftEndTime || "19:00";
|
|
35574
|
-
let breaks = [];
|
|
35575
|
-
if (operatingHours?.breaks) {
|
|
35576
|
-
if (Array.isArray(operatingHours.breaks)) {
|
|
35577
|
-
breaks = operatingHours.breaks.map((breakItem) => ({
|
|
35578
|
-
startTime: breakItem.start || breakItem.startTime || "00:00",
|
|
35579
|
-
endTime: breakItem.end || breakItem.endTime || "00:00",
|
|
35580
|
-
duration: breakItem.duration || calculateShiftHours2(breakItem.start || breakItem.startTime || "00:00", breakItem.end || breakItem.endTime || "00:00", []) * 60
|
|
35581
|
-
}));
|
|
35582
|
-
} else if (typeof operatingHours.breaks === "object" && operatingHours.breaks.breaks) {
|
|
35583
|
-
breaks = operatingHours.breaks.breaks.map((breakItem) => ({
|
|
35584
|
-
startTime: breakItem.start || breakItem.startTime || "00:00",
|
|
35585
|
-
endTime: breakItem.end || breakItem.endTime || "00:00",
|
|
35586
|
-
duration: breakItem.duration || calculateShiftHours2(breakItem.start || breakItem.startTime || "00:00", breakItem.end || breakItem.endTime || "00:00", []) * 60
|
|
35587
|
-
}));
|
|
35588
|
-
}
|
|
35589
|
-
}
|
|
35590
|
-
const shiftHours = calculateShiftHours2(startTime, endTime, breaks);
|
|
35591
|
-
const currentLineStateFromLoop = updatedLineWorkspaces[lineId];
|
|
35592
|
-
if (determinedProductId !== currentLineStateFromLoop?.productId || startTime !== currentLineStateFromLoop?.shiftStartTime || endTime !== currentLineStateFromLoop?.shiftEndTime || shiftHours !== currentLineStateFromLoop?.shiftHours || JSON.stringify(breaks) !== JSON.stringify(currentLineStateFromLoop?.breaks)) {
|
|
35593
|
-
updatedLineWorkspaces[lineId] = {
|
|
35594
|
-
...currentLineStateFromLoop || {},
|
|
35595
|
-
factoryId: currentFactoryId,
|
|
35596
|
-
// Ensure factoryId is preserved
|
|
35597
|
-
productId: determinedProductId,
|
|
35598
|
-
shiftStartTime: startTime,
|
|
35599
|
-
shiftEndTime: endTime,
|
|
35600
|
-
breaks,
|
|
35601
|
-
shiftHours: Number(shiftHours),
|
|
35602
|
-
workspaces: currentLineStateFromLoop?.workspaces || []
|
|
35603
|
-
};
|
|
35604
|
-
hasUpdates = true;
|
|
35605
|
-
}
|
|
35606
|
-
} catch (lineError) {
|
|
35607
|
-
console.error(`Error processing line ${lineId}:`, lineError);
|
|
35608
|
-
}
|
|
35609
|
-
}
|
|
35610
|
-
if (hasUpdates) {
|
|
35611
|
-
setLineWorkspaces(updatedLineWorkspaces);
|
|
35612
|
-
}
|
|
35613
|
-
} catch (error) {
|
|
35614
|
-
console.error("Error in fetchLineThresholds outer try-catch:", error);
|
|
35615
|
-
}
|
|
35616
|
-
}, [selectedShift, supabase, lineIds, lineWorkspaces, allShiftsData]);
|
|
35878
|
+
}, [lineIds, companyId, loadOperatingHours]);
|
|
35617
35879
|
const fetchAllShiftsData = React19.useCallback(async (currentWorkspaces) => {
|
|
35618
35880
|
if (!supabase) return;
|
|
35619
35881
|
const currentDate = getOperationalDate();
|
|
@@ -35623,32 +35885,25 @@ var TargetsView = ({
|
|
|
35623
35885
|
1: JSON.parse(JSON.stringify(currentWorkspaces))
|
|
35624
35886
|
// Deep clone for night shift
|
|
35625
35887
|
};
|
|
35888
|
+
const newDbValues = { 0: {}, 1: {} };
|
|
35626
35889
|
for (const shiftId of [0, 1]) {
|
|
35627
35890
|
for (const lineId of lineIds) {
|
|
35628
35891
|
try {
|
|
35629
|
-
const
|
|
35630
|
-
if (
|
|
35631
|
-
console.
|
|
35892
|
+
const operatingHoursData = await loadOperatingHours(lineId, shiftId);
|
|
35893
|
+
if (!operatingHoursData) {
|
|
35894
|
+
console.warn(`No operating hours for line ${lineId}, shift ${shiftId} - using defaults`);
|
|
35632
35895
|
continue;
|
|
35633
35896
|
}
|
|
35634
|
-
|
|
35635
|
-
if (operatingHours?.breaks) {
|
|
35636
|
-
if (Array.isArray(operatingHours.breaks)) {
|
|
35637
|
-
breaks = operatingHours.breaks.map((breakItem) => ({
|
|
35638
|
-
startTime: breakItem.start || breakItem.startTime || "00:00",
|
|
35639
|
-
endTime: breakItem.end || breakItem.endTime || "00:00",
|
|
35640
|
-
duration: breakItem.duration || calculateShiftHours2(breakItem.start || breakItem.startTime || "00:00", breakItem.end || breakItem.endTime || "00:00", []) * 60
|
|
35641
|
-
}));
|
|
35642
|
-
}
|
|
35643
|
-
}
|
|
35644
|
-
const startTime = operatingHours?.start_time || "08:00";
|
|
35645
|
-
const endTime = operatingHours?.end_time || "19:00";
|
|
35897
|
+
const { startTime, endTime, breaks } = operatingHoursData;
|
|
35646
35898
|
const shiftHours = calculateShiftHours2(startTime, endTime, breaks);
|
|
35647
35899
|
const actionThresholds = await workspaceService.getActionThresholds(
|
|
35648
35900
|
lineId,
|
|
35649
35901
|
currentDate,
|
|
35650
35902
|
shiftId
|
|
35651
35903
|
);
|
|
35904
|
+
if (!newDbValues[shiftId][lineId]) {
|
|
35905
|
+
newDbValues[shiftId][lineId] = {};
|
|
35906
|
+
}
|
|
35652
35907
|
const existingLine = newAllShiftsData[shiftId][lineId];
|
|
35653
35908
|
if (existingLine) {
|
|
35654
35909
|
newAllShiftsData[shiftId][lineId] = {
|
|
@@ -35660,6 +35915,11 @@ var TargetsView = ({
|
|
|
35660
35915
|
workspaces: existingLine.workspaces.map((ws) => {
|
|
35661
35916
|
const threshold = actionThresholds.find((t) => t.workspace_id === ws.id);
|
|
35662
35917
|
if (threshold) {
|
|
35918
|
+
newDbValues[shiftId][lineId][ws.id] = {
|
|
35919
|
+
targetPPH: threshold.pph_threshold,
|
|
35920
|
+
targetCycleTime: threshold.ideal_cycle_time,
|
|
35921
|
+
targetDayOutput: threshold.total_day_output
|
|
35922
|
+
};
|
|
35663
35923
|
return {
|
|
35664
35924
|
...ws,
|
|
35665
35925
|
targetPPH: threshold.pph_threshold,
|
|
@@ -35677,114 +35937,17 @@ var TargetsView = ({
|
|
|
35677
35937
|
}
|
|
35678
35938
|
}
|
|
35679
35939
|
setAllShiftsData(newAllShiftsData);
|
|
35680
|
-
|
|
35681
|
-
|
|
35682
|
-
try {
|
|
35683
|
-
if (!supabase) return null;
|
|
35684
|
-
const { data, error } = await supabase.from("line_operating_hours").select("start_time, end_time, breaks").eq("line_id", lineId).eq("shift_id", shiftId).maybeSingle();
|
|
35685
|
-
if (error) {
|
|
35686
|
-
if (error.code === "PGRST116") {
|
|
35687
|
-
console.log(`No operating hours found for line ${lineId}, shift ${shiftId}`);
|
|
35688
|
-
return {
|
|
35689
|
-
startTime: "08:00",
|
|
35690
|
-
// Default values
|
|
35691
|
-
endTime: "19:00",
|
|
35692
|
-
breaks: []
|
|
35693
|
-
};
|
|
35694
|
-
} else {
|
|
35695
|
-
console.error("Error fetching operating hours:", error);
|
|
35696
|
-
return null;
|
|
35697
|
-
}
|
|
35698
|
-
}
|
|
35699
|
-
let breaks = [];
|
|
35700
|
-
if (data?.breaks) {
|
|
35701
|
-
if (Array.isArray(data.breaks)) {
|
|
35702
|
-
breaks = data.breaks.map((breakItem) => {
|
|
35703
|
-
const startTime = breakItem.start || breakItem.startTime || "00:00";
|
|
35704
|
-
const endTime = breakItem.end || breakItem.endTime || "00:00";
|
|
35705
|
-
const calculateDuration = (start, end) => {
|
|
35706
|
-
const [startHour, startMinute] = start.split(":").map(Number);
|
|
35707
|
-
const [endHour, endMinute] = end.split(":").map(Number);
|
|
35708
|
-
let startMinutes = startHour * 60 + startMinute;
|
|
35709
|
-
let endMinutes = endHour * 60 + endMinute;
|
|
35710
|
-
if (endMinutes < startMinutes) {
|
|
35711
|
-
endMinutes += 24 * 60;
|
|
35712
|
-
}
|
|
35713
|
-
return endMinutes - startMinutes;
|
|
35714
|
-
};
|
|
35715
|
-
return {
|
|
35716
|
-
startTime,
|
|
35717
|
-
endTime,
|
|
35718
|
-
duration: breakItem.duration || calculateDuration(startTime, endTime)
|
|
35719
|
-
};
|
|
35720
|
-
});
|
|
35721
|
-
} else if (typeof data.breaks === "object" && data.breaks.breaks) {
|
|
35722
|
-
breaks = data.breaks.breaks.map((breakItem) => {
|
|
35723
|
-
const startTime = breakItem.start || breakItem.startTime || "00:00";
|
|
35724
|
-
const endTime = breakItem.end || breakItem.endTime || "00:00";
|
|
35725
|
-
const calculateDuration = (start, end) => {
|
|
35726
|
-
const [startHour, startMinute] = start.split(":").map(Number);
|
|
35727
|
-
const [endHour, endMinute] = end.split(":").map(Number);
|
|
35728
|
-
let startMinutes = startHour * 60 + startMinute;
|
|
35729
|
-
let endMinutes = endHour * 60 + endMinute;
|
|
35730
|
-
if (endMinutes < startMinutes) {
|
|
35731
|
-
endMinutes += 24 * 60;
|
|
35732
|
-
}
|
|
35733
|
-
return endMinutes - startMinutes;
|
|
35734
|
-
};
|
|
35735
|
-
return {
|
|
35736
|
-
startTime,
|
|
35737
|
-
endTime,
|
|
35738
|
-
duration: breakItem.duration || calculateDuration(startTime, endTime)
|
|
35739
|
-
};
|
|
35740
|
-
});
|
|
35741
|
-
} else if (typeof data.breaks === "string") {
|
|
35742
|
-
try {
|
|
35743
|
-
const parsedBreaks = JSON.parse(data.breaks);
|
|
35744
|
-
if (Array.isArray(parsedBreaks)) {
|
|
35745
|
-
breaks = parsedBreaks.map((breakItem) => ({
|
|
35746
|
-
startTime: breakItem.start || breakItem.startTime || "00:00",
|
|
35747
|
-
endTime: breakItem.end || breakItem.endTime || "00:00",
|
|
35748
|
-
duration: breakItem.duration || 0
|
|
35749
|
-
}));
|
|
35750
|
-
} else if (parsedBreaks.breaks && Array.isArray(parsedBreaks.breaks)) {
|
|
35751
|
-
breaks = parsedBreaks.breaks.map((breakItem) => ({
|
|
35752
|
-
startTime: breakItem.start || breakItem.startTime || "00:00",
|
|
35753
|
-
endTime: breakItem.end || breakItem.endTime || "00:00",
|
|
35754
|
-
duration: breakItem.duration || 0
|
|
35755
|
-
}));
|
|
35756
|
-
}
|
|
35757
|
-
} catch (e) {
|
|
35758
|
-
console.error("Error parsing breaks data:", e);
|
|
35759
|
-
}
|
|
35760
|
-
}
|
|
35761
|
-
}
|
|
35762
|
-
return {
|
|
35763
|
-
startTime: data?.start_time || "08:00",
|
|
35764
|
-
endTime: data?.end_time || "19:00",
|
|
35765
|
-
breaks
|
|
35766
|
-
};
|
|
35767
|
-
} catch (e) {
|
|
35768
|
-
console.error("Exception when loading operating hours:", e);
|
|
35769
|
-
return {
|
|
35770
|
-
startTime: "08:00",
|
|
35771
|
-
endTime: "19:00",
|
|
35772
|
-
breaks: []
|
|
35773
|
-
};
|
|
35774
|
-
}
|
|
35775
|
-
}, [supabase]);
|
|
35940
|
+
setDbValues(newDbValues);
|
|
35941
|
+
}, [supabase, lineIds, loadOperatingHours]);
|
|
35776
35942
|
const toggleLineDropdown = React19.useCallback((lineId) => {
|
|
35777
|
-
|
|
35778
|
-
const newIsOpen = !prev[lineId]
|
|
35943
|
+
setDropdownStates((prev) => {
|
|
35944
|
+
const newIsOpen = !prev[lineId];
|
|
35779
35945
|
if (typeof window !== "undefined") {
|
|
35780
35946
|
localStorage.setItem(`line_${lineId}_open`, JSON.stringify(newIsOpen));
|
|
35781
35947
|
}
|
|
35782
35948
|
return {
|
|
35783
35949
|
...prev,
|
|
35784
|
-
[lineId]:
|
|
35785
|
-
...prev[lineId],
|
|
35786
|
-
isOpen: newIsOpen
|
|
35787
|
-
}
|
|
35950
|
+
[lineId]: newIsOpen
|
|
35788
35951
|
};
|
|
35789
35952
|
});
|
|
35790
35953
|
}, []);
|
|
@@ -35833,6 +35996,8 @@ var TargetsView = ({
|
|
|
35833
35996
|
}
|
|
35834
35997
|
};
|
|
35835
35998
|
const updateWorkspaceTarget = (lineId, workspaceId, field, value) => {
|
|
35999
|
+
const fieldKey = `${lineId}-${workspaceId}-${field}`;
|
|
36000
|
+
setUserEditedFields((prev) => new Set(prev).add(fieldKey));
|
|
35836
36001
|
setLineWorkspaces((prev) => {
|
|
35837
36002
|
const shiftHours = prev[lineId].shiftHours;
|
|
35838
36003
|
return {
|
|
@@ -35857,11 +36022,7 @@ var TargetsView = ({
|
|
|
35857
36022
|
} else if (field === "targetDayOutput") {
|
|
35858
36023
|
updates.targetDayOutput = value;
|
|
35859
36024
|
if (value !== "") {
|
|
35860
|
-
const
|
|
35861
|
-
const totalBreakMinutes = breaks.reduce((total, b) => total + b.duration, 0);
|
|
35862
|
-
const totalBreakHours = totalBreakMinutes / 60;
|
|
35863
|
-
const realWorkHours = shiftHours - totalBreakHours;
|
|
35864
|
-
const calculatedPPH = Math.round(value / realWorkHours);
|
|
36025
|
+
const calculatedPPH = Math.round(value / shiftHours);
|
|
35865
36026
|
updates.targetPPH = calculatedPPH;
|
|
35866
36027
|
} else {
|
|
35867
36028
|
updates.targetPPH = "";
|
|
@@ -35876,62 +36037,35 @@ var TargetsView = ({
|
|
|
35876
36037
|
};
|
|
35877
36038
|
const handleShiftChange = (shiftId) => {
|
|
35878
36039
|
setSelectedShift(shiftId);
|
|
35879
|
-
|
|
35880
|
-
|
|
35881
|
-
|
|
35882
|
-
|
|
35883
|
-
|
|
35884
|
-
|
|
35885
|
-
|
|
35886
|
-
|
|
35887
|
-
|
|
35888
|
-
|
|
35889
|
-
|
|
35890
|
-
|
|
35891
|
-
|
|
35892
|
-
|
|
35893
|
-
|
|
35894
|
-
|
|
35895
|
-
|
|
35896
|
-
shiftHours: Number(shiftHours),
|
|
35897
|
-
workspaces: updatedLineWorkspaces[lineId].workspaces.map((ws) => {
|
|
35898
|
-
let updatedPPH = ws.targetPPH;
|
|
35899
|
-
if (ws.targetCycleTime !== "") {
|
|
35900
|
-
const idealPPH = calculatePPH(
|
|
35901
|
-
ws.targetCycleTime,
|
|
35902
|
-
operatingHours.breaks,
|
|
35903
|
-
Number(shiftHours)
|
|
35904
|
-
);
|
|
35905
|
-
const shouldUpdatePPH = typeof ws.targetPPH === "string" ? ws.targetPPH === "" : ws.targetPPH === 0 || !ws.targetPPH;
|
|
35906
|
-
if (shouldUpdatePPH) {
|
|
35907
|
-
updatedPPH = idealPPH;
|
|
36040
|
+
setUserEditedFields(/* @__PURE__ */ new Set());
|
|
36041
|
+
if (dbValues[shiftId] && Object.keys(dbValues[shiftId]).length > 0) {
|
|
36042
|
+
setAllShiftsData((prev) => {
|
|
36043
|
+
const updatedShiftData = { ...prev[shiftId] };
|
|
36044
|
+
for (const lineId of Object.keys(updatedShiftData)) {
|
|
36045
|
+
if (dbValues[shiftId][lineId]) {
|
|
36046
|
+
updatedShiftData[lineId] = {
|
|
36047
|
+
...updatedShiftData[lineId],
|
|
36048
|
+
workspaces: updatedShiftData[lineId].workspaces.map((ws) => {
|
|
36049
|
+
const dbValue = dbValues[shiftId][lineId][ws.id];
|
|
36050
|
+
if (dbValue) {
|
|
36051
|
+
return {
|
|
36052
|
+
...ws,
|
|
36053
|
+
targetPPH: dbValue.targetPPH,
|
|
36054
|
+
targetCycleTime: dbValue.targetCycleTime,
|
|
36055
|
+
targetDayOutput: dbValue.targetDayOutput
|
|
36056
|
+
};
|
|
35908
36057
|
}
|
|
35909
|
-
|
|
35910
|
-
|
|
35911
|
-
|
|
35912
|
-
|
|
35913
|
-
operatingHours.breaks
|
|
35914
|
-
);
|
|
35915
|
-
return {
|
|
35916
|
-
...ws,
|
|
35917
|
-
targetPPH: updatedPPH,
|
|
35918
|
-
targetDayOutput: updatedDayOutput
|
|
35919
|
-
};
|
|
35920
|
-
})
|
|
35921
|
-
};
|
|
35922
|
-
hasUpdates = true;
|
|
35923
|
-
} catch (e) {
|
|
35924
|
-
console.error(`Exception when loading shift hours for line ${lineId}:`, e);
|
|
36058
|
+
return ws;
|
|
36059
|
+
})
|
|
36060
|
+
};
|
|
36061
|
+
}
|
|
35925
36062
|
}
|
|
35926
|
-
|
|
35927
|
-
if (hasUpdates) {
|
|
35928
|
-
setAllShiftsData((prev) => ({
|
|
36063
|
+
return {
|
|
35929
36064
|
...prev,
|
|
35930
|
-
[shiftId]:
|
|
35931
|
-
}
|
|
35932
|
-
}
|
|
35933
|
-
}
|
|
35934
|
-
loadShiftHours();
|
|
36065
|
+
[shiftId]: updatedShiftData
|
|
36066
|
+
};
|
|
36067
|
+
});
|
|
36068
|
+
}
|
|
35935
36069
|
};
|
|
35936
36070
|
const handleActionTypeChange = React19.useCallback((lineId, workspaceId, newActionType) => {
|
|
35937
36071
|
if (!actionIds) return;
|
|
@@ -36021,6 +36155,31 @@ var TargetsView = ({
|
|
|
36021
36155
|
throw lineUpsertError;
|
|
36022
36156
|
}
|
|
36023
36157
|
console.log(`[handleSaveLine] Successfully upserted line_thresholds for ${lineId}`);
|
|
36158
|
+
setDbValues((prev) => ({
|
|
36159
|
+
...prev,
|
|
36160
|
+
[selectedShift]: {
|
|
36161
|
+
...prev[selectedShift],
|
|
36162
|
+
[lineId]: lineDataToSave.workspaces.reduce((acc, ws) => ({
|
|
36163
|
+
...acc,
|
|
36164
|
+
[ws.id]: {
|
|
36165
|
+
targetPPH: ws.targetPPH,
|
|
36166
|
+
targetCycleTime: ws.targetCycleTime,
|
|
36167
|
+
targetDayOutput: ws.targetDayOutput
|
|
36168
|
+
}
|
|
36169
|
+
}), {})
|
|
36170
|
+
}
|
|
36171
|
+
}));
|
|
36172
|
+
console.log(`[handleSaveLine] Updated dbValues for line ${lineId}, shift ${selectedShift}`);
|
|
36173
|
+
setUserEditedFields((prev) => {
|
|
36174
|
+
const newSet = new Set(prev);
|
|
36175
|
+
lineDataToSave.workspaces.forEach((ws) => {
|
|
36176
|
+
newSet.delete(`${lineId}-${ws.id}-targetPPH`);
|
|
36177
|
+
newSet.delete(`${lineId}-${ws.id}-targetCycleTime`);
|
|
36178
|
+
newSet.delete(`${lineId}-${ws.id}-targetDayOutput`);
|
|
36179
|
+
});
|
|
36180
|
+
return newSet;
|
|
36181
|
+
});
|
|
36182
|
+
console.log(`[handleSaveLine] Cleared user edited fields for line ${lineId}`);
|
|
36024
36183
|
setSaveSuccess((prev) => ({ ...prev, [lineId]: true }));
|
|
36025
36184
|
sonner.toast.success(`${lineNames[lineId] || lineId} targets saved successfully`);
|
|
36026
36185
|
if (onSaveChanges) onSaveChanges(lineId);
|
|
@@ -36034,7 +36193,7 @@ var TargetsView = ({
|
|
|
36034
36193
|
setSavingLines((prev) => ({ ...prev, [lineId]: false }));
|
|
36035
36194
|
console.log(`[handleSaveLine] Set savingLines to false for ${lineId} in finally block`);
|
|
36036
36195
|
}
|
|
36037
|
-
}, [supabase, lineWorkspaces, selectedShift, lineNames, onSaveChanges]);
|
|
36196
|
+
}, [supabase, lineWorkspaces, selectedShift, lineNames, onSaveChanges, skuEnabled, dashboardConfig]);
|
|
36038
36197
|
const handleBulkConfigure = async (updates) => {
|
|
36039
36198
|
if (!actionIds) return;
|
|
36040
36199
|
if (updates.productId !== void 0) {
|
|
@@ -36082,6 +36241,7 @@ var TargetsView = ({
|
|
|
36082
36241
|
isLoading: isLoading || skusLoading,
|
|
36083
36242
|
lineWorkspaces,
|
|
36084
36243
|
lineNames,
|
|
36244
|
+
dropdownStates,
|
|
36085
36245
|
savingLines,
|
|
36086
36246
|
saveSuccess,
|
|
36087
36247
|
selectedShift,
|
|
@@ -36106,7 +36266,7 @@ var TargetsView = ({
|
|
|
36106
36266
|
};
|
|
36107
36267
|
var TargetsViewWithDisplayNames = withAllWorkspaceDisplayNames(TargetsView);
|
|
36108
36268
|
var TargetsView_default = TargetsViewWithDisplayNames;
|
|
36109
|
-
var AuthenticatedTargetsView = withAuth(TargetsViewWithDisplayNames);
|
|
36269
|
+
var AuthenticatedTargetsView = withAuth(React19__namespace.default.memo(TargetsViewWithDisplayNames));
|
|
36110
36270
|
|
|
36111
36271
|
// src/views/workspace-detail-view.utils.ts
|
|
36112
36272
|
var formatISTDate2 = (date = /* @__PURE__ */ new Date(), options) => {
|
|
@@ -37586,6 +37746,7 @@ exports.AuthProvider = AuthProvider;
|
|
|
37586
37746
|
exports.AuthenticatedFactoryView = AuthenticatedFactoryView;
|
|
37587
37747
|
exports.AuthenticatedHelpView = AuthenticatedHelpView;
|
|
37588
37748
|
exports.AuthenticatedHomeView = AuthenticatedHomeView;
|
|
37749
|
+
exports.AuthenticatedShiftsView = AuthenticatedShiftsView;
|
|
37589
37750
|
exports.AuthenticatedTargetsView = AuthenticatedTargetsView;
|
|
37590
37751
|
exports.BarChart = BarChart;
|
|
37591
37752
|
exports.BaseHistoryCalendar = BaseHistoryCalendar;
|