@optifye/dashboard-core 6.3.5 → 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 -9
- package/dist/index.d.ts +137 -9
- package/dist/index.js +629 -508
- package/dist/index.mjs +637 -517
- 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");
|
|
@@ -3956,20 +3961,36 @@ var S3ClipsService = class {
|
|
|
3956
3961
|
return null;
|
|
3957
3962
|
}
|
|
3958
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
|
+
}
|
|
3959
3971
|
/**
|
|
3960
3972
|
* Fetches full metadata including timestamps with deduplication
|
|
3961
3973
|
*/
|
|
3962
3974
|
async getFullMetadata(playlistUri) {
|
|
3963
|
-
if (this.isIndexBuilding) {
|
|
3964
|
-
console.warn(`[S3ClipsService] Skipping metadata fetch
|
|
3975
|
+
if (this.isIndexBuilding || this.isPrefetching) {
|
|
3976
|
+
console.warn(`[S3ClipsService] Skipping metadata fetch - building: ${this.isIndexBuilding}, prefetching: ${this.isPrefetching}`);
|
|
3965
3977
|
return null;
|
|
3966
3978
|
}
|
|
3967
|
-
|
|
3968
|
-
|
|
3969
|
-
|
|
3970
|
-
|
|
3971
|
-
|
|
3972
|
-
|
|
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
|
+
}
|
|
3973
3994
|
}
|
|
3974
3995
|
/**
|
|
3975
3996
|
* Internal implementation of full metadata fetching
|
|
@@ -4471,7 +4492,8 @@ var S3ClipsService = class {
|
|
|
4471
4492
|
date,
|
|
4472
4493
|
shiftId.toString(),
|
|
4473
4494
|
includeCycleTime || false,
|
|
4474
|
-
includeMetadata ||
|
|
4495
|
+
includeMetadata || false
|
|
4496
|
+
// Never fetch metadata for timestamp filtering to prevent flooding
|
|
4475
4497
|
);
|
|
4476
4498
|
});
|
|
4477
4499
|
const videoResults = await Promise.all(videoPromises);
|
|
@@ -4542,6 +4564,7 @@ var VideoPrefetchManager = class extends events.EventEmitter {
|
|
|
4542
4564
|
}
|
|
4543
4565
|
/**
|
|
4544
4566
|
* Get or create S3 service instance for dashboard config
|
|
4567
|
+
* Public method to allow sharing the same S3Service instance across components
|
|
4545
4568
|
*/
|
|
4546
4569
|
getS3Service(dashboardConfig) {
|
|
4547
4570
|
const configKey = JSON.stringify(dashboardConfig.s3Config);
|
|
@@ -4611,75 +4634,80 @@ var VideoPrefetchManager = class extends events.EventEmitter {
|
|
|
4611
4634
|
* Perform the actual prefetch work
|
|
4612
4635
|
*/
|
|
4613
4636
|
async performPrefetchWork(key, params, s3Service, buildIndex) {
|
|
4614
|
-
|
|
4615
|
-
|
|
4616
|
-
|
|
4617
|
-
|
|
4618
|
-
|
|
4619
|
-
|
|
4620
|
-
|
|
4621
|
-
|
|
4622
|
-
|
|
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(
|
|
4623
4671
|
params.workspaceId,
|
|
4624
4672
|
params.date,
|
|
4625
|
-
params.shift
|
|
4673
|
+
params.shift,
|
|
4674
|
+
true
|
|
4626
4675
|
);
|
|
4627
|
-
if (typeof
|
|
4628
|
-
const
|
|
4629
|
-
|
|
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,
|
|
4630
4692
|
videoIndex: {
|
|
4631
4693
|
byCategory: /* @__PURE__ */ new Map(),
|
|
4632
4694
|
allVideos: [],
|
|
4633
|
-
counts:
|
|
4695
|
+
counts: countsResult,
|
|
4634
4696
|
workspaceId: params.workspaceId,
|
|
4635
4697
|
date: params.date,
|
|
4636
4698
|
shiftId: params.shift,
|
|
4637
4699
|
lastUpdated: /* @__PURE__ */ new Date(),
|
|
4638
|
-
_debugId: `
|
|
4700
|
+
_debugId: `vid_FALLBACK_${Date.now()}_${Math.random().toString(36).substring(7)}`
|
|
4639
4701
|
}
|
|
4640
4702
|
};
|
|
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`);
|
|
4703
|
+
this.updateRequestStatus(key, "render_ready" /* RENDER_READY */, fallbackData);
|
|
4704
|
+
return fallbackData;
|
|
4655
4705
|
} 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");
|
|
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);
|
|
4683
4711
|
}
|
|
4684
4712
|
}
|
|
4685
4713
|
/**
|
|
@@ -4942,9 +4970,13 @@ var AuthProvider = ({ children }) => {
|
|
|
4942
4970
|
const [loading, setLoading] = React19.useState(true);
|
|
4943
4971
|
const [error, setError] = React19.useState(null);
|
|
4944
4972
|
const router$1 = router.useRouter();
|
|
4945
|
-
|
|
4946
|
-
|
|
4973
|
+
authConfig?.userProfileTable;
|
|
4974
|
+
authConfig?.roleColumn || "role";
|
|
4947
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
|
+
});
|
|
4948
4980
|
if (!supabaseUser) return null;
|
|
4949
4981
|
const basicUser = {
|
|
4950
4982
|
id: supabaseUser.id,
|
|
@@ -4953,42 +4985,34 @@ var AuthProvider = ({ children }) => {
|
|
|
4953
4985
|
if (!supabase) return basicUser;
|
|
4954
4986
|
try {
|
|
4955
4987
|
const timeoutPromise = new Promise(
|
|
4956
|
-
(_, reject) => setTimeout(() =>
|
|
4988
|
+
(_, reject) => setTimeout(() => {
|
|
4989
|
+
console.log("[fetchUserDetails] Timeout triggered after 2 seconds");
|
|
4990
|
+
reject(new Error("Profile fetch timeout"));
|
|
4991
|
+
}, 2e3)
|
|
4957
4992
|
);
|
|
4958
4993
|
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
|
-
})
|
|
4994
|
+
const roleResult = await Promise.race([
|
|
4995
|
+
rolePromise,
|
|
4996
|
+
timeoutPromise
|
|
4997
|
+
// Fixed: removed .then() which was causing the bug
|
|
4971
4998
|
]);
|
|
4972
4999
|
let roleLevel = void 0;
|
|
4973
5000
|
if (roleResult && !roleResult.error && roleResult.data) {
|
|
4974
5001
|
roleLevel = roleResult.data.role_level;
|
|
4975
|
-
} else if (roleResult?.error) {
|
|
5002
|
+
} else if (roleResult?.error && roleResult.error.code !== "PGRST116") {
|
|
4976
5003
|
console.log("Error fetching role_level:", roleResult.error.message);
|
|
4977
5004
|
}
|
|
4978
|
-
let roleValue = void 0;
|
|
4979
|
-
if (profileResult && !profileResult.error && profileResult.data) {
|
|
4980
|
-
roleValue = profileResult.data[roleColumn];
|
|
4981
|
-
}
|
|
4982
5005
|
return {
|
|
4983
5006
|
...basicUser,
|
|
4984
|
-
role: roleValue,
|
|
4985
5007
|
role_level: roleLevel
|
|
4986
5008
|
};
|
|
4987
5009
|
} catch (err) {
|
|
4988
|
-
|
|
5010
|
+
if (err instanceof Error && err.message.includes("timeout")) {
|
|
5011
|
+
console.warn("Auth fetch timeout - using basic user info");
|
|
5012
|
+
}
|
|
4989
5013
|
return basicUser;
|
|
4990
5014
|
}
|
|
4991
|
-
}, [supabase
|
|
5015
|
+
}, [supabase]);
|
|
4992
5016
|
React19.useEffect(() => {
|
|
4993
5017
|
if (!supabase) return;
|
|
4994
5018
|
let mounted = true;
|
|
@@ -4999,6 +5023,7 @@ var AuthProvider = ({ children }) => {
|
|
|
4999
5023
|
}
|
|
5000
5024
|
}, 1e4);
|
|
5001
5025
|
const initializeAuth = async () => {
|
|
5026
|
+
const startTime = performance.now();
|
|
5002
5027
|
try {
|
|
5003
5028
|
const { data: { session: initialSession }, error: sessionError } = await supabase.auth.getSession();
|
|
5004
5029
|
if (!mounted) return;
|
|
@@ -5041,12 +5066,38 @@ var AuthProvider = ({ children }) => {
|
|
|
5041
5066
|
if (mounted) {
|
|
5042
5067
|
setLoading(false);
|
|
5043
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
|
+
}
|
|
5044
5075
|
}
|
|
5045
5076
|
}
|
|
5046
5077
|
};
|
|
5047
5078
|
initializeAuth();
|
|
5048
|
-
const { data: { subscription } } = supabase.auth.onAuthStateChange(async (
|
|
5079
|
+
const { data: { subscription } } = supabase.auth.onAuthStateChange(async (event, currentSession) => {
|
|
5049
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
|
+
}
|
|
5050
5101
|
setSession(currentSession);
|
|
5051
5102
|
setUser(null);
|
|
5052
5103
|
setLoading(false);
|
|
@@ -6967,16 +7018,12 @@ var useTargets = (options) => {
|
|
|
6967
7018
|
};
|
|
6968
7019
|
var DEFAULT_SHIFTS_TABLE_NAME = "shift_configurations";
|
|
6969
7020
|
var useShifts = () => {
|
|
6970
|
-
const { supabaseUrl, supabaseKey } = useDashboardConfig();
|
|
6971
7021
|
const { companyId } = useEntityConfig();
|
|
6972
7022
|
const { tables } = useDatabaseConfig();
|
|
7023
|
+
const supabase = useSupabase();
|
|
6973
7024
|
const [shifts, setShifts] = React19.useState([]);
|
|
6974
7025
|
const [isLoading, setIsLoading] = React19.useState(true);
|
|
6975
7026
|
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
7027
|
const shiftsTable = tables?.shiftConfigurations || DEFAULT_SHIFTS_TABLE_NAME;
|
|
6981
7028
|
const fetchData = React19.useCallback(async () => {
|
|
6982
7029
|
if (!supabase) {
|
|
@@ -7675,6 +7722,7 @@ var runtimeWorkspaceDisplayNames = {};
|
|
|
7675
7722
|
var isInitialized = false;
|
|
7676
7723
|
var isInitializing = false;
|
|
7677
7724
|
var initializedWithLineIds = [];
|
|
7725
|
+
var initializationPromise = null;
|
|
7678
7726
|
function getCurrentLineIds() {
|
|
7679
7727
|
try {
|
|
7680
7728
|
const config = _getDashboardConfigInstance();
|
|
@@ -7695,52 +7743,79 @@ function getCurrentLineIds() {
|
|
|
7695
7743
|
}
|
|
7696
7744
|
async function initializeWorkspaceDisplayNames(explicitLineId) {
|
|
7697
7745
|
console.log("\u{1F504} initializeWorkspaceDisplayNames called", { isInitialized, isInitializing, explicitLineId });
|
|
7698
|
-
if (isInitialized
|
|
7699
|
-
|
|
7700
|
-
|
|
7701
|
-
|
|
7702
|
-
|
|
7703
|
-
|
|
7704
|
-
|
|
7705
|
-
|
|
7706
|
-
|
|
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;
|
|
7707
7791
|
}
|
|
7708
|
-
|
|
7709
|
-
|
|
7710
|
-
|
|
7711
|
-
|
|
7712
|
-
|
|
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 {
|
|
7713
7802
|
const lineDisplayNamesMap = await workspaceService.getWorkspaceDisplayNames(void 0, lineId);
|
|
7714
7803
|
runtimeWorkspaceDisplayNames[lineId] = {};
|
|
7715
7804
|
lineDisplayNamesMap.forEach((displayName, workspaceId) => {
|
|
7716
7805
|
runtimeWorkspaceDisplayNames[lineId][workspaceId] = displayName;
|
|
7717
7806
|
});
|
|
7718
|
-
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);
|
|
7719
7810
|
}
|
|
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
7811
|
}
|
|
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;
|
|
7812
|
+
return;
|
|
7736
7813
|
}
|
|
7737
|
-
|
|
7738
|
-
|
|
7739
|
-
|
|
7740
|
-
if (isInitialized || isInitializing) {
|
|
7741
|
-
console.log("\u{1F504} Already initialized or initializing");
|
|
7814
|
+
if (initializationPromise) {
|
|
7815
|
+
console.log("\u{1F504} Already initializing, waiting for completion...");
|
|
7816
|
+
await initializationPromise;
|
|
7742
7817
|
if (lineId && !runtimeWorkspaceDisplayNames[lineId]) {
|
|
7743
|
-
console.log(`\u{1F504} Line ${lineId} not in cache, fetching...`);
|
|
7818
|
+
console.log(`\u{1F504} Line ${lineId} not in cache after init, fetching...`);
|
|
7744
7819
|
try {
|
|
7745
7820
|
const lineDisplayNamesMap = await workspaceService.getWorkspaceDisplayNames(void 0, lineId);
|
|
7746
7821
|
runtimeWorkspaceDisplayNames[lineId] = {};
|
|
@@ -7758,7 +7833,12 @@ var preInitializeWorkspaceDisplayNames = async (lineId) => {
|
|
|
7758
7833
|
};
|
|
7759
7834
|
var forceRefreshWorkspaceDisplayNames = async (lineId) => {
|
|
7760
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
|
+
}
|
|
7761
7840
|
clearWorkspaceDisplayNamesCache();
|
|
7841
|
+
initializationPromise = null;
|
|
7762
7842
|
await initializeWorkspaceDisplayNames(lineId);
|
|
7763
7843
|
};
|
|
7764
7844
|
console.log("\u{1F504} Module loaded, will initialize lazily when first function is called");
|
|
@@ -7906,6 +7986,7 @@ var clearWorkspaceDisplayNamesCache = () => {
|
|
|
7906
7986
|
isInitialized = false;
|
|
7907
7987
|
isInitializing = false;
|
|
7908
7988
|
initializedWithLineIds = [];
|
|
7989
|
+
initializationPromise = null;
|
|
7909
7990
|
};
|
|
7910
7991
|
|
|
7911
7992
|
// src/lib/hooks/useWorkspaceDisplayNames.ts
|
|
@@ -19546,11 +19627,13 @@ var withAuth = (WrappedComponent2, options) => {
|
|
|
19546
19627
|
requireAuth: true,
|
|
19547
19628
|
...options
|
|
19548
19629
|
};
|
|
19549
|
-
|
|
19630
|
+
const WithAuthComponent = React19__namespace.memo(function WithAuthComponent2(props) {
|
|
19550
19631
|
const { session, loading } = useAuth();
|
|
19551
19632
|
const router$1 = router.useRouter();
|
|
19552
19633
|
React19__namespace.useEffect(() => {
|
|
19553
|
-
|
|
19634
|
+
if (process.env.NODE_ENV === "development" && process.env.DEBUG_AUTH === "true") {
|
|
19635
|
+
console.log("withAuth state:", { loading, hasSession: !!session, requireAuth: defaultOptions.requireAuth });
|
|
19636
|
+
}
|
|
19554
19637
|
}, [session, loading]);
|
|
19555
19638
|
React19__namespace.useEffect(() => {
|
|
19556
19639
|
if (!loading && defaultOptions.requireAuth && !session) {
|
|
@@ -19565,7 +19648,9 @@ var withAuth = (WrappedComponent2, options) => {
|
|
|
19565
19648
|
return null;
|
|
19566
19649
|
}
|
|
19567
19650
|
return /* @__PURE__ */ jsxRuntime.jsx(WrappedComponent2, { ...props });
|
|
19568
|
-
};
|
|
19651
|
+
});
|
|
19652
|
+
WithAuthComponent.displayName = `withAuth(${WrappedComponent2.displayName || WrappedComponent2.name || "Component"})`;
|
|
19653
|
+
return WithAuthComponent;
|
|
19569
19654
|
};
|
|
19570
19655
|
var LoginPage = ({
|
|
19571
19656
|
onRateLimitCheck,
|
|
@@ -26153,7 +26238,7 @@ var BottlenecksContent = ({
|
|
|
26153
26238
|
const [duration, setDuration] = React19.useState(0);
|
|
26154
26239
|
const [currentIndex, setCurrentIndex] = React19.useState(0);
|
|
26155
26240
|
const [activeFilter, setActiveFilter] = React19.useState(initialFilter);
|
|
26156
|
-
const previousFilterRef = React19.useRef(
|
|
26241
|
+
const previousFilterRef = React19.useRef("");
|
|
26157
26242
|
const [allVideos, setAllVideos] = React19.useState([]);
|
|
26158
26243
|
const [isLoading, setIsLoading] = React19.useState(true);
|
|
26159
26244
|
const [isCategoryLoading, setIsCategoryLoading] = React19.useState(false);
|
|
@@ -26203,7 +26288,7 @@ var BottlenecksContent = ({
|
|
|
26203
26288
|
console.warn("S3 configuration not found in dashboard config");
|
|
26204
26289
|
return null;
|
|
26205
26290
|
}
|
|
26206
|
-
return
|
|
26291
|
+
return videoPrefetchManager.getS3Service(dashboardConfig);
|
|
26207
26292
|
}, [dashboardConfig]);
|
|
26208
26293
|
const {
|
|
26209
26294
|
data: prefetchData,
|
|
@@ -26310,8 +26395,8 @@ var BottlenecksContent = ({
|
|
|
26310
26395
|
index,
|
|
26311
26396
|
true,
|
|
26312
26397
|
// includeCycleTime - OK for preloading
|
|
26313
|
-
|
|
26314
|
-
// includeMetadata -
|
|
26398
|
+
false
|
|
26399
|
+
// includeMetadata - NO metadata during bulk preloading to prevent flooding
|
|
26315
26400
|
);
|
|
26316
26401
|
}
|
|
26317
26402
|
if (!video) {
|
|
@@ -26325,8 +26410,8 @@ var BottlenecksContent = ({
|
|
|
26325
26410
|
index,
|
|
26326
26411
|
true,
|
|
26327
26412
|
// includeCycleTime - OK for preloading
|
|
26328
|
-
|
|
26329
|
-
// includeMetadata -
|
|
26413
|
+
false
|
|
26414
|
+
// includeMetadata - NO metadata during bulk preloading to prevent flooding
|
|
26330
26415
|
);
|
|
26331
26416
|
}
|
|
26332
26417
|
if (video && isMountedRef.current) {
|
|
@@ -26386,8 +26471,16 @@ var BottlenecksContent = ({
|
|
|
26386
26471
|
);
|
|
26387
26472
|
if (firstVideo) {
|
|
26388
26473
|
console.log(`[BottlenecksContent] Successfully loaded first video via direct S3 method`);
|
|
26389
|
-
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
|
+
});
|
|
26390
26481
|
preloadVideoUrl(firstVideo.src);
|
|
26482
|
+
setIsLoading(false);
|
|
26483
|
+
setHasInitialLoad(true);
|
|
26391
26484
|
loadingCategoryRef.current = null;
|
|
26392
26485
|
setIsCategoryLoading(false);
|
|
26393
26486
|
return;
|
|
@@ -26410,7 +26503,13 @@ var BottlenecksContent = ({
|
|
|
26410
26503
|
);
|
|
26411
26504
|
if (firstVideo && isMountedRef.current) {
|
|
26412
26505
|
console.log(`[BottlenecksContent] Successfully loaded first video via video index`);
|
|
26413
|
-
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
|
+
});
|
|
26414
26513
|
preloadVideoUrl(firstVideo.src);
|
|
26415
26514
|
setIsCategoryLoading(false);
|
|
26416
26515
|
return;
|
|
@@ -26435,15 +26534,17 @@ var BottlenecksContent = ({
|
|
|
26435
26534
|
}
|
|
26436
26535
|
}, [workspaceId, date, s3ClipsService, clipCounts, videoIndex, shift, updateClipCounts, updateVideoIndex]);
|
|
26437
26536
|
React19.useEffect(() => {
|
|
26438
|
-
if (s3ClipsService) {
|
|
26537
|
+
if (s3ClipsService && !prefetchData) {
|
|
26439
26538
|
fetchClipCounts();
|
|
26440
26539
|
}
|
|
26441
|
-
}, [workspaceId, date, shift, s3ClipsService, fetchClipCounts, updateClipCounts, updateVideoIndex]);
|
|
26540
|
+
}, [workspaceId, date, shift, s3ClipsService, fetchClipCounts, updateClipCounts, updateVideoIndex, prefetchData]);
|
|
26442
26541
|
React19.useEffect(() => {
|
|
26443
26542
|
if (prefetchData) {
|
|
26444
26543
|
console.log(`[BottlenecksContent] Received prefetch update - status: ${prefetchStatus}, videos: ${prefetchData.videoIndex.allVideos.length}, ID: ${prefetchData.videoIndex._debugId || "NO_ID"}`);
|
|
26445
26544
|
updateClipCounts(prefetchData.counts);
|
|
26446
|
-
|
|
26545
|
+
if (prefetchData.videoIndex.allVideos.length > 0) {
|
|
26546
|
+
updateVideoIndex(prefetchData.videoIndex);
|
|
26547
|
+
}
|
|
26447
26548
|
if (!hasInitialLoad && prefetchData.videoIndex.allVideos.length > 0) {
|
|
26448
26549
|
setIsLoading(false);
|
|
26449
26550
|
setHasInitialLoad(true);
|
|
@@ -26451,12 +26552,45 @@ var BottlenecksContent = ({
|
|
|
26451
26552
|
}
|
|
26452
26553
|
}, [prefetchData, prefetchStatus, updateClipCounts, updateVideoIndex, hasInitialLoad]);
|
|
26453
26554
|
React19.useEffect(() => {
|
|
26454
|
-
if (s3ClipsService &&
|
|
26455
|
-
|
|
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) {
|
|
26456
26588
|
loadFirstVideoForCategory(activeFilter);
|
|
26589
|
+
} else {
|
|
26590
|
+
setIsCategoryLoading(false);
|
|
26457
26591
|
}
|
|
26458
26592
|
}
|
|
26459
|
-
}, [activeFilter, s3ClipsService, videoIndex, clipCounts, loadFirstVideoForCategory, allVideos
|
|
26593
|
+
}, [activeFilter, s3ClipsService, videoIndex, clipCounts, loadFirstVideoForCategory, allVideos, sopCategories]);
|
|
26460
26594
|
React19.useEffect(() => {
|
|
26461
26595
|
if (previousFilterRef.current !== activeFilter) {
|
|
26462
26596
|
console.log(`Filter changed from ${previousFilterRef.current} to ${activeFilter} - resetting to first video`);
|
|
@@ -26639,14 +26773,39 @@ var BottlenecksContent = ({
|
|
|
26639
26773
|
}
|
|
26640
26774
|
}
|
|
26641
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]);
|
|
26642
26782
|
const handleVideoReady = React19.useCallback((player) => {
|
|
26643
26783
|
console.log("Video.js player ready");
|
|
26644
26784
|
}, []);
|
|
26645
|
-
const handleVideoPlay = React19.useCallback((player) => {
|
|
26785
|
+
const handleVideoPlay = React19.useCallback(async (player) => {
|
|
26646
26786
|
setIsPlaying(true);
|
|
26647
26787
|
const currentIdx = currentIndexRef.current;
|
|
26648
26788
|
ensureVideosLoaded(currentIdx);
|
|
26649
|
-
|
|
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]);
|
|
26650
26809
|
const handleVideoPause = React19.useCallback((player) => {
|
|
26651
26810
|
setIsPlaying(false);
|
|
26652
26811
|
}, []);
|
|
@@ -26673,13 +26832,6 @@ var BottlenecksContent = ({
|
|
|
26673
26832
|
fetchInProgressRef.current.clear();
|
|
26674
26833
|
setIsCategoryLoading(false);
|
|
26675
26834
|
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
26835
|
};
|
|
26684
26836
|
}, [s3ClipsService]);
|
|
26685
26837
|
React19.useEffect(() => {
|
|
@@ -26720,12 +26872,6 @@ var BottlenecksContent = ({
|
|
|
26720
26872
|
counts.bottlenecks = counts.bottleneck || counts.bottlenecks || 0;
|
|
26721
26873
|
return counts;
|
|
26722
26874
|
}, [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
26875
|
const getClipTypeLabel = (video) => {
|
|
26730
26876
|
if (!video) return "";
|
|
26731
26877
|
switch (video.type) {
|
|
@@ -26960,8 +27106,8 @@ var BottlenecksContent = ({
|
|
|
26960
27106
|
] }),
|
|
26961
27107
|
/* Priority 1: Show loading if initial load hasn't completed yet */
|
|
26962
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..." }) }) }) }) : (
|
|
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..." }) }) }) }) : (
|
|
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..." }) }) }) }) : (
|
|
26965
27111
|
/* Priority 3: Show loading if navigating and current video not available */
|
|
26966
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..." }) }) }) }) : (
|
|
26967
27113
|
/* Priority 4: Show video if we have filtered videos and current video */
|
|
@@ -31759,9 +31905,25 @@ function withWorkspaceDisplayNames(Component3, options = {}) {
|
|
|
31759
31905
|
return function WithWorkspaceDisplayNamesWrapper(props) {
|
|
31760
31906
|
const [isInitialized2, setIsInitialized] = React19.useState(false);
|
|
31761
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]);
|
|
31762
31920
|
React19.useEffect(() => {
|
|
31763
|
-
|
|
31764
|
-
|
|
31921
|
+
if (initKey === lastInitKey && isInitialized2) {
|
|
31922
|
+
return;
|
|
31923
|
+
}
|
|
31924
|
+
if (initKey !== lastInitKey) {
|
|
31925
|
+
setError(null);
|
|
31926
|
+
}
|
|
31765
31927
|
const initializeDisplayNames = async () => {
|
|
31766
31928
|
try {
|
|
31767
31929
|
const { lineIds, selectedLineId, factoryViewId } = props;
|
|
@@ -31787,20 +31949,17 @@ function withWorkspaceDisplayNames(Component3, options = {}) {
|
|
|
31787
31949
|
await preInitializeWorkspaceDisplayNames();
|
|
31788
31950
|
}
|
|
31789
31951
|
setIsInitialized(true);
|
|
31952
|
+
setLastInitKey(initKey);
|
|
31790
31953
|
} catch (err) {
|
|
31791
31954
|
console.error("Failed to initialize workspace display names:", err);
|
|
31792
31955
|
setError(err);
|
|
31793
31956
|
setIsInitialized(true);
|
|
31957
|
+
setLastInitKey(initKey);
|
|
31794
31958
|
}
|
|
31795
31959
|
};
|
|
31796
31960
|
initializeDisplayNames();
|
|
31797
|
-
}, [
|
|
31798
|
-
|
|
31799
|
-
props.selectedLineId,
|
|
31800
|
-
props.factoryViewId,
|
|
31801
|
-
initializeFor
|
|
31802
|
-
]);
|
|
31803
|
-
if (!isInitialized2 && showLoading) {
|
|
31961
|
+
}, [initKey]);
|
|
31962
|
+
if (!isInitialized2 && showLoading && lastInitKey === "") {
|
|
31804
31963
|
return /* @__PURE__ */ jsxRuntime.jsx(LoadingPage, { message: loadingMessage });
|
|
31805
31964
|
}
|
|
31806
31965
|
if (error && showLoading) {
|
|
@@ -33871,7 +34030,15 @@ var ShiftsView = ({
|
|
|
33871
34030
|
className = ""
|
|
33872
34031
|
}) => {
|
|
33873
34032
|
const supabase = useSupabase();
|
|
33874
|
-
|
|
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
|
+
}, []);
|
|
33875
34042
|
const [lineConfigs, setLineConfigs] = React19.useState(
|
|
33876
34043
|
() => lineIds.map((id3) => ({
|
|
33877
34044
|
id: id3,
|
|
@@ -33969,7 +34136,7 @@ var ShiftsView = ({
|
|
|
33969
34136
|
}
|
|
33970
34137
|
};
|
|
33971
34138
|
fetchShiftConfigs();
|
|
33972
|
-
}, [
|
|
34139
|
+
}, [lineIds, showToast]);
|
|
33973
34140
|
React19.useCallback((lineId) => {
|
|
33974
34141
|
setLineConfigs((prev) => {
|
|
33975
34142
|
const typedPrev = prev;
|
|
@@ -34162,7 +34329,6 @@ var ShiftsView = ({
|
|
|
34162
34329
|
}));
|
|
34163
34330
|
}, []);
|
|
34164
34331
|
const handleSaveShifts = React19.useCallback(async (lineId) => {
|
|
34165
|
-
if (!auth.user?.id && false) ;
|
|
34166
34332
|
setLineConfigs((prev) => prev.map(
|
|
34167
34333
|
(config) => config.id === lineId ? { ...config, isSaving: true, saveSuccess: false } : config
|
|
34168
34334
|
));
|
|
@@ -34209,7 +34375,7 @@ var ShiftsView = ({
|
|
|
34209
34375
|
(config) => config.id === lineId ? { ...config, isSaving: false, saveSuccess: false } : config
|
|
34210
34376
|
));
|
|
34211
34377
|
}
|
|
34212
|
-
}, [
|
|
34378
|
+
}, [lineConfigs, supabase, showToast]);
|
|
34213
34379
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `min-h-screen bg-slate-50 ${className}`, children: [
|
|
34214
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: [
|
|
34215
34381
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
@@ -34317,6 +34483,7 @@ var ShiftsView = ({
|
|
|
34317
34483
|
] })
|
|
34318
34484
|
] });
|
|
34319
34485
|
};
|
|
34486
|
+
var AuthenticatedShiftsView = withAuth(React19__namespace.default.memo(ShiftsView));
|
|
34320
34487
|
var ShiftsView_default = ShiftsView;
|
|
34321
34488
|
|
|
34322
34489
|
// src/lib/constants/actions.ts
|
|
@@ -35104,6 +35271,7 @@ var TargetsViewUI = ({
|
|
|
35104
35271
|
isLoading,
|
|
35105
35272
|
lineWorkspaces,
|
|
35106
35273
|
lineNames,
|
|
35274
|
+
dropdownStates,
|
|
35107
35275
|
savingLines,
|
|
35108
35276
|
saveSuccess,
|
|
35109
35277
|
selectedShift,
|
|
@@ -35189,13 +35357,13 @@ var TargetsViewUI = ({
|
|
|
35189
35357
|
{
|
|
35190
35358
|
onClick: () => onToggleLineDropdown(lineId),
|
|
35191
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",
|
|
35192
|
-
"aria-expanded":
|
|
35360
|
+
"aria-expanded": dropdownStates[lineId],
|
|
35193
35361
|
"aria-controls": `line-${lineId}-content`,
|
|
35194
35362
|
children: [
|
|
35195
35363
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
35196
35364
|
lucideReact.ChevronDown,
|
|
35197
35365
|
{
|
|
35198
|
-
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" : ""}`
|
|
35199
35367
|
}
|
|
35200
35368
|
),
|
|
35201
35369
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2.5", children: [
|
|
@@ -35242,7 +35410,7 @@ var TargetsViewUI = ({
|
|
|
35242
35410
|
)
|
|
35243
35411
|
] })
|
|
35244
35412
|
] }) }),
|
|
35245
|
-
|
|
35413
|
+
dropdownStates[lineId] && /* @__PURE__ */ jsxRuntime.jsxs("div", { id: `line-${lineId}-content`, className: "border-t border-gray-200", children: [
|
|
35246
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: [
|
|
35247
35415
|
/* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: `sku-${lineId}`, className: "text-sm font-medium text-gray-700", children: "Select SKU:" }),
|
|
35248
35416
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 max-w-md", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -35279,68 +35447,71 @@ var TargetsViewUI = ({
|
|
|
35279
35447
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-gray-400", children: "pieces per day" })
|
|
35280
35448
|
] })
|
|
35281
35449
|
] }) }),
|
|
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
|
-
|
|
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
|
+
}) })
|
|
35344
35515
|
] })
|
|
35345
35516
|
]
|
|
35346
35517
|
},
|
|
@@ -35373,7 +35544,6 @@ var TargetsView = ({
|
|
|
35373
35544
|
return lineIds.reduce((acc, lineId) => ({
|
|
35374
35545
|
...acc,
|
|
35375
35546
|
[lineId]: {
|
|
35376
|
-
isOpen: getStoredLineState2(lineId),
|
|
35377
35547
|
productId: "",
|
|
35378
35548
|
shiftStartTime: "08:00",
|
|
35379
35549
|
shiftEndTime: "19:00",
|
|
@@ -35386,6 +35556,12 @@ var TargetsView = ({
|
|
|
35386
35556
|
}
|
|
35387
35557
|
}), {});
|
|
35388
35558
|
}, [lineIds]);
|
|
35559
|
+
const [dropdownStates, setDropdownStates] = React19.useState(() => {
|
|
35560
|
+
return lineIds.reduce((acc, lineId) => ({
|
|
35561
|
+
...acc,
|
|
35562
|
+
[lineId]: getStoredLineState2(lineId)
|
|
35563
|
+
}), {});
|
|
35564
|
+
});
|
|
35389
35565
|
const [allShiftsData, setAllShiftsData] = React19.useState({
|
|
35390
35566
|
0: initialLineWorkspaces,
|
|
35391
35567
|
// Day shift
|
|
@@ -35403,6 +35579,8 @@ var TargetsView = ({
|
|
|
35403
35579
|
const [isBulkConfigureOpen, setIsBulkConfigureOpen] = React19.useState(false);
|
|
35404
35580
|
const [selectedWorkspaces, setSelectedWorkspaces] = React19.useState([]);
|
|
35405
35581
|
const [selectedShift, setSelectedShift] = React19.useState(0);
|
|
35582
|
+
const [dbValues, setDbValues] = React19.useState({ 0: {}, 1: {} });
|
|
35583
|
+
const [userEditedFields, setUserEditedFields] = React19.useState(/* @__PURE__ */ new Set());
|
|
35406
35584
|
const lineWorkspaces = allShiftsData[selectedShift] || initialLineWorkspaces;
|
|
35407
35585
|
const setLineWorkspaces = React19.useCallback((updater) => {
|
|
35408
35586
|
setAllShiftsData((prev) => ({
|
|
@@ -35411,18 +35589,123 @@ var TargetsView = ({
|
|
|
35411
35589
|
}));
|
|
35412
35590
|
}, [selectedShift]);
|
|
35413
35591
|
const supabase = useSupabase();
|
|
35414
|
-
const
|
|
35415
|
-
userId || auth?.user?.id;
|
|
35592
|
+
const effectiveUserId = userId || "6bf6f271-1e55-4a95-9b89-1c3820b58739";
|
|
35416
35593
|
const dashboardConfig = useDashboardConfig();
|
|
35417
35594
|
const { skus, isLoading: skusLoading } = useSKUs(companyId);
|
|
35418
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
|
+
}, []);
|
|
35419
35701
|
React19.useEffect(() => {
|
|
35420
35702
|
let timeoutId;
|
|
35421
35703
|
let retryCount = 0;
|
|
35422
35704
|
const MAX_RETRIES2 = 2;
|
|
35423
35705
|
const LOADING_TIMEOUT = 15e3;
|
|
35424
35706
|
const fetchInitialData = async () => {
|
|
35425
|
-
if (
|
|
35707
|
+
if (lineIds.length === 0) return;
|
|
35708
|
+
console.log("[TargetsView] Starting fetchInitialData");
|
|
35426
35709
|
setIsLoading(true);
|
|
35427
35710
|
timeoutId = setTimeout(() => {
|
|
35428
35711
|
console.error("Loading timeout reached");
|
|
@@ -35486,10 +35769,32 @@ var TargetsView = ({
|
|
|
35486
35769
|
const actionThresholds = await workspaceService.getActionThresholds(
|
|
35487
35770
|
lineId,
|
|
35488
35771
|
currentDate,
|
|
35489
|
-
|
|
35772
|
+
0
|
|
35773
|
+
// Always use day shift for initial load
|
|
35490
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
|
+
}
|
|
35491
35786
|
const mappedWorkspaces = enabledWorkspaces.map((ws) => {
|
|
35492
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
|
+
}
|
|
35493
35798
|
return {
|
|
35494
35799
|
id: ws.id,
|
|
35495
35800
|
name: ws.workspace_id,
|
|
@@ -35530,90 +35835,7 @@ var TargetsView = ({
|
|
|
35530
35835
|
return () => {
|
|
35531
35836
|
clearTimeout(timeoutId);
|
|
35532
35837
|
};
|
|
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]);
|
|
35838
|
+
}, [lineIds, companyId, loadOperatingHours]);
|
|
35617
35839
|
const fetchAllShiftsData = React19.useCallback(async (currentWorkspaces) => {
|
|
35618
35840
|
if (!supabase) return;
|
|
35619
35841
|
const currentDate = getOperationalDate();
|
|
@@ -35623,32 +35845,25 @@ var TargetsView = ({
|
|
|
35623
35845
|
1: JSON.parse(JSON.stringify(currentWorkspaces))
|
|
35624
35846
|
// Deep clone for night shift
|
|
35625
35847
|
};
|
|
35848
|
+
const newDbValues = { 0: {}, 1: {} };
|
|
35626
35849
|
for (const shiftId of [0, 1]) {
|
|
35627
35850
|
for (const lineId of lineIds) {
|
|
35628
35851
|
try {
|
|
35629
|
-
const
|
|
35630
|
-
if (
|
|
35631
|
-
console.
|
|
35852
|
+
const operatingHoursData = await loadOperatingHours(lineId, shiftId);
|
|
35853
|
+
if (!operatingHoursData) {
|
|
35854
|
+
console.warn(`No operating hours for line ${lineId}, shift ${shiftId} - using defaults`);
|
|
35632
35855
|
continue;
|
|
35633
35856
|
}
|
|
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";
|
|
35857
|
+
const { startTime, endTime, breaks } = operatingHoursData;
|
|
35646
35858
|
const shiftHours = calculateShiftHours2(startTime, endTime, breaks);
|
|
35647
35859
|
const actionThresholds = await workspaceService.getActionThresholds(
|
|
35648
35860
|
lineId,
|
|
35649
35861
|
currentDate,
|
|
35650
35862
|
shiftId
|
|
35651
35863
|
);
|
|
35864
|
+
if (!newDbValues[shiftId][lineId]) {
|
|
35865
|
+
newDbValues[shiftId][lineId] = {};
|
|
35866
|
+
}
|
|
35652
35867
|
const existingLine = newAllShiftsData[shiftId][lineId];
|
|
35653
35868
|
if (existingLine) {
|
|
35654
35869
|
newAllShiftsData[shiftId][lineId] = {
|
|
@@ -35660,6 +35875,11 @@ var TargetsView = ({
|
|
|
35660
35875
|
workspaces: existingLine.workspaces.map((ws) => {
|
|
35661
35876
|
const threshold = actionThresholds.find((t) => t.workspace_id === ws.id);
|
|
35662
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
|
+
};
|
|
35663
35883
|
return {
|
|
35664
35884
|
...ws,
|
|
35665
35885
|
targetPPH: threshold.pph_threshold,
|
|
@@ -35677,114 +35897,17 @@ var TargetsView = ({
|
|
|
35677
35897
|
}
|
|
35678
35898
|
}
|
|
35679
35899
|
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]);
|
|
35900
|
+
setDbValues(newDbValues);
|
|
35901
|
+
}, [supabase, lineIds, loadOperatingHours]);
|
|
35776
35902
|
const toggleLineDropdown = React19.useCallback((lineId) => {
|
|
35777
|
-
|
|
35778
|
-
const newIsOpen = !prev[lineId]
|
|
35903
|
+
setDropdownStates((prev) => {
|
|
35904
|
+
const newIsOpen = !prev[lineId];
|
|
35779
35905
|
if (typeof window !== "undefined") {
|
|
35780
35906
|
localStorage.setItem(`line_${lineId}_open`, JSON.stringify(newIsOpen));
|
|
35781
35907
|
}
|
|
35782
35908
|
return {
|
|
35783
35909
|
...prev,
|
|
35784
|
-
[lineId]:
|
|
35785
|
-
...prev[lineId],
|
|
35786
|
-
isOpen: newIsOpen
|
|
35787
|
-
}
|
|
35910
|
+
[lineId]: newIsOpen
|
|
35788
35911
|
};
|
|
35789
35912
|
});
|
|
35790
35913
|
}, []);
|
|
@@ -35833,6 +35956,8 @@ var TargetsView = ({
|
|
|
35833
35956
|
}
|
|
35834
35957
|
};
|
|
35835
35958
|
const updateWorkspaceTarget = (lineId, workspaceId, field, value) => {
|
|
35959
|
+
const fieldKey = `${lineId}-${workspaceId}-${field}`;
|
|
35960
|
+
setUserEditedFields((prev) => new Set(prev).add(fieldKey));
|
|
35836
35961
|
setLineWorkspaces((prev) => {
|
|
35837
35962
|
const shiftHours = prev[lineId].shiftHours;
|
|
35838
35963
|
return {
|
|
@@ -35857,11 +35982,7 @@ var TargetsView = ({
|
|
|
35857
35982
|
} else if (field === "targetDayOutput") {
|
|
35858
35983
|
updates.targetDayOutput = value;
|
|
35859
35984
|
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);
|
|
35985
|
+
const calculatedPPH = Math.round(value / shiftHours);
|
|
35865
35986
|
updates.targetPPH = calculatedPPH;
|
|
35866
35987
|
} else {
|
|
35867
35988
|
updates.targetPPH = "";
|
|
@@ -35876,62 +35997,35 @@ var TargetsView = ({
|
|
|
35876
35997
|
};
|
|
35877
35998
|
const handleShiftChange = (shiftId) => {
|
|
35878
35999
|
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;
|
|
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
|
+
};
|
|
35908
36017
|
}
|
|
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);
|
|
36018
|
+
return ws;
|
|
36019
|
+
})
|
|
36020
|
+
};
|
|
36021
|
+
}
|
|
35925
36022
|
}
|
|
35926
|
-
|
|
35927
|
-
if (hasUpdates) {
|
|
35928
|
-
setAllShiftsData((prev) => ({
|
|
36023
|
+
return {
|
|
35929
36024
|
...prev,
|
|
35930
|
-
[shiftId]:
|
|
35931
|
-
}
|
|
35932
|
-
}
|
|
35933
|
-
}
|
|
35934
|
-
loadShiftHours();
|
|
36025
|
+
[shiftId]: updatedShiftData
|
|
36026
|
+
};
|
|
36027
|
+
});
|
|
36028
|
+
}
|
|
35935
36029
|
};
|
|
35936
36030
|
const handleActionTypeChange = React19.useCallback((lineId, workspaceId, newActionType) => {
|
|
35937
36031
|
if (!actionIds) return;
|
|
@@ -36021,6 +36115,31 @@ var TargetsView = ({
|
|
|
36021
36115
|
throw lineUpsertError;
|
|
36022
36116
|
}
|
|
36023
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}`);
|
|
36024
36143
|
setSaveSuccess((prev) => ({ ...prev, [lineId]: true }));
|
|
36025
36144
|
sonner.toast.success(`${lineNames[lineId] || lineId} targets saved successfully`);
|
|
36026
36145
|
if (onSaveChanges) onSaveChanges(lineId);
|
|
@@ -36034,7 +36153,7 @@ var TargetsView = ({
|
|
|
36034
36153
|
setSavingLines((prev) => ({ ...prev, [lineId]: false }));
|
|
36035
36154
|
console.log(`[handleSaveLine] Set savingLines to false for ${lineId} in finally block`);
|
|
36036
36155
|
}
|
|
36037
|
-
}, [supabase, lineWorkspaces, selectedShift, lineNames, onSaveChanges]);
|
|
36156
|
+
}, [supabase, lineWorkspaces, selectedShift, lineNames, onSaveChanges, skuEnabled, dashboardConfig]);
|
|
36038
36157
|
const handleBulkConfigure = async (updates) => {
|
|
36039
36158
|
if (!actionIds) return;
|
|
36040
36159
|
if (updates.productId !== void 0) {
|
|
@@ -36082,6 +36201,7 @@ var TargetsView = ({
|
|
|
36082
36201
|
isLoading: isLoading || skusLoading,
|
|
36083
36202
|
lineWorkspaces,
|
|
36084
36203
|
lineNames,
|
|
36204
|
+
dropdownStates,
|
|
36085
36205
|
savingLines,
|
|
36086
36206
|
saveSuccess,
|
|
36087
36207
|
selectedShift,
|
|
@@ -36106,7 +36226,7 @@ var TargetsView = ({
|
|
|
36106
36226
|
};
|
|
36107
36227
|
var TargetsViewWithDisplayNames = withAllWorkspaceDisplayNames(TargetsView);
|
|
36108
36228
|
var TargetsView_default = TargetsViewWithDisplayNames;
|
|
36109
|
-
var AuthenticatedTargetsView = withAuth(TargetsViewWithDisplayNames);
|
|
36229
|
+
var AuthenticatedTargetsView = withAuth(React19__namespace.default.memo(TargetsViewWithDisplayNames));
|
|
36110
36230
|
|
|
36111
36231
|
// src/views/workspace-detail-view.utils.ts
|
|
36112
36232
|
var formatISTDate2 = (date = /* @__PURE__ */ new Date(), options) => {
|
|
@@ -37586,6 +37706,7 @@ exports.AuthProvider = AuthProvider;
|
|
|
37586
37706
|
exports.AuthenticatedFactoryView = AuthenticatedFactoryView;
|
|
37587
37707
|
exports.AuthenticatedHelpView = AuthenticatedHelpView;
|
|
37588
37708
|
exports.AuthenticatedHomeView = AuthenticatedHomeView;
|
|
37709
|
+
exports.AuthenticatedShiftsView = AuthenticatedShiftsView;
|
|
37589
37710
|
exports.AuthenticatedTargetsView = AuthenticatedTargetsView;
|
|
37590
37711
|
exports.BarChart = BarChart;
|
|
37591
37712
|
exports.BaseHistoryCalendar = BaseHistoryCalendar;
|