@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.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 during index building for: ${playlistUri}`);
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
- const deduplicationKey = `full-metadata:${playlistUri}`;
3968
- return this.requestCache.deduplicate(
3969
- deduplicationKey,
3970
- () => this.executeGetFullMetadata(playlistUri),
3971
- "FullMetadata"
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
- console.log(`[S3ClipsService] ${buildIndex ? "Building video index and counting" : "Fast counting"} clips for ${workspaceId} on ${date}, shift ${shiftId}`);
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 || (!!timestampStart || !!timestampEnd)
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
- const cacheKey = `clip-counts:${params.workspaceId}:${params.date}:${params.shift}`;
4615
- const cachedResult = await smartVideoCache.getClipCounts(cacheKey);
4616
- if (cachedResult) {
4617
- console.log(`[VideoPrefetchManager] Found cached data for ${key}`);
4618
- this.updateRequestStatus(key, "fully_indexed" /* FULLY_INDEXED */, cachedResult);
4619
- return cachedResult;
4620
- }
4621
- if (buildIndex) {
4622
- const countsOnly = await s3Service.getClipCounts(
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 countsOnly === "object" && countsOnly !== null) {
4628
- const renderReadyData = {
4629
- counts: countsOnly,
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: countsOnly,
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: `vid_RENDER_READY_${Date.now()}_${Math.random().toString(36).substring(7)}`
4714
+ _debugId: `vid_FALLBACK_${Date.now()}_${Math.random().toString(36).substring(7)}`
4639
4715
  }
4640
4716
  };
4641
- this.updateRequestStatus(key, "render_ready" /* RENDER_READY */, renderReadyData);
4642
- console.log(`[VideoPrefetchManager] Render ready, building full index for ${key}`);
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.warn(`[VideoPrefetchManager] Video index is empty, but counts available:`, clipCountsWithIndex.counts);
4657
- }
4658
- await smartVideoCache.setClipCounts(cacheKey, clipCountsWithIndex, 5 * 60);
4659
- this.updateRequestStatus(key, "fully_indexed" /* FULLY_INDEXED */, clipCountsWithIndex);
4660
- console.log(`[VideoPrefetchManager] Fully indexed: ${key} (${clipCountsWithIndex.videoIndex.allVideos.length} videos)`);
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
- const userProfileTable = authConfig?.userProfileTable;
4946
- const roleColumn = authConfig?.roleColumn || "role";
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(() => reject(new Error("Profile fetch timeout")), 5e3)
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
- let profilePromise = null;
4960
- if (userProfileTable) {
4961
- profilePromise = supabase.from(userProfileTable).select(roleColumn).eq("id", supabaseUser.id).single();
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
- console.error("Error fetching user details:", err);
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, userProfileTable, roleColumn]);
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 (_event, currentSession) => {
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 || isInitializing) return;
7699
- isInitializing = true;
7700
- try {
7701
- console.log("\u{1F504} Starting Supabase workspace display names initialization...");
7702
- let targetLineIds = [];
7703
- if (explicitLineId) {
7704
- targetLineIds = [explicitLineId];
7705
- } else {
7706
- targetLineIds = getCurrentLineIds();
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
- console.log("\u{1F504} Target line IDs for workspace filtering:", targetLineIds);
7709
- runtimeWorkspaceDisplayNames = {};
7710
- if (targetLineIds.length > 0) {
7711
- for (const lineId of targetLineIds) {
7712
- console.log(`\u{1F504} Fetching workspaces for line: ${lineId}`);
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 Stored ${lineDisplayNamesMap.size} workspaces for line ${lineId}`);
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
- isInitialized = true;
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
- var preInitializeWorkspaceDisplayNames = async (lineId) => {
7739
- console.log("\u{1F504} preInitializeWorkspaceDisplayNames called for lineId:", lineId);
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
- const shiftStr = shift?.toString() || "0";
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
- return function WithAuthComponent(props) {
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
- console.log("withAuth state:", { loading, hasSession: !!session, requireAuth: defaultOptions.requireAuth });
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(initialFilter);
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 new S3ClipsService(dashboardConfig);
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: shift?.toString() || "0",
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 = shift?.toString() || "0";
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, shift, dashboardConfig, updateClipCounts, updateVideoIndex]);
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
- true
26314
- // includeMetadata - OK for just +3/-1 videos, not ALL videos
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 = shift?.toString() || "0";
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
- true
26329
- // includeMetadata - OK for just +3/-1 videos, not ALL videos
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, shift]);
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 = shift?.toString() || "0";
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([firstVideo]);
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([firstVideo]);
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, shift, updateClipCounts, updateVideoIndex]);
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, shift, s3ClipsService, fetchClipCounts, updateClipCounts, updateVideoIndex]);
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
- updateVideoIndex(prefetchData.videoIndex);
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 && videoIndex && clipCounts[activeFilter] > 0) {
26455
- if (allVideos.length === 0) {
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.length]);
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 = shift?.toString() || "0";
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, shift]);
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 (prevents "no matching clips" flash) */
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
- setIsInitialized(false);
31764
- setError(null);
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
- Array.isArray(props.lineIds) ? props.lineIds.join(",") : JSON.stringify(props.lineIds),
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
- const auth = useAuth();
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
- }, [supabase, lineIds, showToast]);
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
- }, [auth.user?.id, lineConfigs, supabase, showToast]);
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": line.isOpen,
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 ${line.isOpen ? "rotate-180" : ""}`
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
- line.isOpen && /* @__PURE__ */ jsxRuntime.jsxs("div", { id: `line-${lineId}-content`, className: "border-t border-gray-200", children: [
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) => /* @__PURE__ */ jsxRuntime.jsx(
35283
- "div",
35284
- {
35285
- className: "px-6 py-4 hover:bg-gray-50 transition-all duration-200",
35286
- children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-12 gap-6 items-center", children: [
35287
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "col-span-2", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium text-gray-900", children: formatWorkspaceName(workspace.name, lineId) }) }),
35288
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "col-span-2", children: /* @__PURE__ */ jsxRuntime.jsxs(
35289
- "select",
35290
- {
35291
- value: workspace.actionType,
35292
- onChange: (e) => {
35293
- const newActionType = e.target.value;
35294
- onActionTypeChange(lineId, workspace.id, newActionType);
35295
- },
35296
- className: "w-full p-2 border border-gray-300 rounded-md shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm",
35297
- "aria-label": `Action type for ${formatWorkspaceName(workspace.name, lineId)}`,
35298
- children: [
35299
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "assembly", className: "py-2", children: "Assembly" }),
35300
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "packaging", className: "py-2", children: "Packaging" })
35301
- ]
35302
- }
35303
- ) }),
35304
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "col-span-3", children: /* @__PURE__ */ jsxRuntime.jsx(
35305
- "input",
35306
- {
35307
- type: "number",
35308
- value: workspace.targetCycleTime === 0 ? "" : workspace.targetCycleTime,
35309
- onChange: (e) => onUpdateWorkspaceTarget(lineId, workspace.id, "targetCycleTime", Number(e.target.value) || ""),
35310
- 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",
35311
- min: "0",
35312
- step: "0.01",
35313
- placeholder: "Enter cycle time"
35314
- }
35315
- ) }),
35316
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "col-span-3", children: /* @__PURE__ */ jsxRuntime.jsx(
35317
- "input",
35318
- {
35319
- type: "number",
35320
- value: workspace.targetPPH === 0 ? "" : workspace.targetPPH,
35321
- onChange: (e) => onUpdateWorkspaceTarget(lineId, workspace.id, "targetPPH", Number(e.target.value) || ""),
35322
- 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",
35323
- min: "0",
35324
- step: "0.1",
35325
- placeholder: "Enter PPH"
35326
- }
35327
- ) }),
35328
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "col-span-2", children: /* @__PURE__ */ jsxRuntime.jsx(
35329
- "input",
35330
- {
35331
- type: "number",
35332
- value: workspace.targetDayOutput === 0 ? "" : workspace.targetDayOutput,
35333
- onChange: (e) => onUpdateWorkspaceTarget(lineId, workspace.id, "targetDayOutput", Number(e.target.value) || ""),
35334
- 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",
35335
- min: "0",
35336
- step: "1",
35337
- placeholder: "Enter day output"
35338
- }
35339
- ) })
35340
- ] })
35341
- },
35342
- workspace.id
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 auth = useAuth();
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 (!supabase || lineIds.length === 0) return;
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
- selectedShift
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
- }, [supabase, lineIds, companyId]);
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 { data: operatingHours, error: hoursError } = await supabase.from("line_operating_hours").select("start_time, end_time, breaks").eq("line_id", lineId).eq("shift_id", shiftId).maybeSingle();
35630
- if (hoursError) {
35631
- console.error(`Error fetching operating hours for line ${lineId}, shift ${shiftId}:`, hoursError);
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
- let breaks = [];
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
- }, [supabase, lineIds]);
35681
- const loadOperatingHours = React19.useCallback(async (lineId, shiftId) => {
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
- setLineWorkspaces((prev) => {
35778
- const newIsOpen = !prev[lineId].isOpen;
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 breaks = prev[lineId].breaks;
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
- const loadShiftHours = async () => {
35880
- const updatedLineWorkspaces = { ...allShiftsData[shiftId] };
35881
- let hasUpdates = false;
35882
- for (const lineId of lineIds) {
35883
- try {
35884
- const operatingHours = await loadOperatingHours(lineId, shiftId);
35885
- if (!operatingHours) continue;
35886
- const shiftHours = calculateShiftHours2(
35887
- operatingHours.startTime,
35888
- operatingHours.endTime,
35889
- operatingHours.breaks
35890
- );
35891
- updatedLineWorkspaces[lineId] = {
35892
- ...updatedLineWorkspaces[lineId],
35893
- shiftStartTime: operatingHours.startTime,
35894
- shiftEndTime: operatingHours.endTime,
35895
- breaks: operatingHours.breaks,
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
- const updatedDayOutput = calculateDayOutput(
35911
- updatedPPH,
35912
- Number(shiftHours),
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]: updatedLineWorkspaces
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;