@optifye/dashboard-core 6.12.19 → 6.12.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/dist/index.js +142 -57
  2. package/dist/index.mjs +142 -57
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -19916,6 +19916,9 @@ function useNavigation(customNavigate) {
19916
19916
  await router$1.push(path, void 0, { shallow: options?.shallow ?? false });
19917
19917
  }
19918
19918
  } catch (error) {
19919
+ if (error?.cancelled || error?.message?.includes("Route change aborted")) {
19920
+ return;
19921
+ }
19919
19922
  if (error.message?.includes("Page not compiled") && retryCount < MAX_RETRIES) {
19920
19923
  setTimeout(() => attemptNavigation(retryCount + 1), RETRY_DELAY);
19921
19924
  } else if (retryCount >= MAX_RETRIES) {
@@ -54907,27 +54910,34 @@ var WorkspaceGrid = React144__namespace.default.memo(({
54907
54910
  [viewMode, workspaces]
54908
54911
  );
54909
54912
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `flex flex-col w-full h-full overflow-hidden bg-slate-50/50 ${className}`, children: [
54910
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-none px-4 py-3 z-20 flex flex-row items-center justify-between gap-4", children: [
54911
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "hidden sm:block", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "inline-flex bg-white/95 rounded-lg shadow-sm px-4 py-2 border border-slate-200/60 backdrop-blur-sm", children: /* @__PURE__ */ jsxRuntime.jsx(Legend5, { legend, metricLabel: legendMetricLabel }) }) }),
54912
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-end gap-3 shrink-0", children: [
54913
- toolbarRightContent,
54914
- mapViewEnabled && /* @__PURE__ */ jsxRuntime.jsx(
54915
- "button",
54916
- {
54917
- onClick: handleViewModeToggle,
54918
- className: "flex items-center gap-2 px-3 py-1.5 bg-white border border-slate-200 rounded-md shadow-sm hover:bg-slate-50 transition-colors duration-200 text-slate-700",
54919
- title: viewMode === "video" ? "Switch to Map View" : "Switch to Video View",
54920
- children: viewMode === "video" ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
54921
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Map, { className: "w-4 h-4 text-slate-500" }),
54922
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "hidden sm:inline text-sm font-medium", children: "Map View" })
54923
- ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
54924
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Video, { className: "w-4 h-4 text-slate-500" }),
54925
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "hidden sm:inline text-sm font-medium", children: "Video View" })
54926
- ] })
54927
- }
54928
- )
54929
- ] })
54930
- ] }),
54913
+ /* @__PURE__ */ jsxRuntime.jsxs(
54914
+ "div",
54915
+ {
54916
+ "data-testid": "workspace-grid-toolbar",
54917
+ className: "relative z-[100] flex-none px-4 py-3 flex flex-row items-center justify-between gap-4",
54918
+ children: [
54919
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "hidden sm:block", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "inline-flex bg-white/95 rounded-lg shadow-sm px-4 py-2 border border-slate-200/60 backdrop-blur-sm", children: /* @__PURE__ */ jsxRuntime.jsx(Legend5, { legend, metricLabel: legendMetricLabel }) }) }),
54920
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-end gap-3 shrink-0", children: [
54921
+ toolbarRightContent,
54922
+ mapViewEnabled && /* @__PURE__ */ jsxRuntime.jsx(
54923
+ "button",
54924
+ {
54925
+ onClick: handleViewModeToggle,
54926
+ className: "flex items-center gap-2 px-3 py-1.5 bg-white border border-slate-200 rounded-md shadow-sm hover:bg-slate-50 transition-colors duration-200 text-slate-700",
54927
+ title: viewMode === "video" ? "Switch to Map View" : "Switch to Video View",
54928
+ children: viewMode === "video" ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
54929
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Map, { className: "w-4 h-4 text-slate-500" }),
54930
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "hidden sm:inline text-sm font-medium", children: "Map View" })
54931
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
54932
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Video, { className: "w-4 h-4 text-slate-500" }),
54933
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "hidden sm:inline text-sm font-medium", children: "Video View" })
54934
+ ] })
54935
+ }
54936
+ )
54937
+ ] })
54938
+ ]
54939
+ }
54940
+ ),
54931
54941
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "sm:hidden px-3 py-2 bg-white border-b border-slate-200/60 z-10", children: /* @__PURE__ */ jsxRuntime.jsx(Legend5, { legend, metricLabel: legendMetricLabel }) }),
54932
54942
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 relative overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx(AnimatePresence, { mode: "wait", children: viewMode === "video" ? /* @__PURE__ */ jsxRuntime.jsx(
54933
54943
  motion.div,
@@ -72340,6 +72350,46 @@ var ClipsCostView = () => {
72340
72350
  ] });
72341
72351
  };
72342
72352
  var ClipsCostView_default = ClipsCostView;
72353
+ var DEFAULT_UNSAVED_CHANGES_MESSAGE = "You have unsaved changes. Leave this page and lose them?";
72354
+ var useUnsavedChangesPrompt = (shouldBlock, message = DEFAULT_UNSAVED_CHANGES_MESSAGE) => {
72355
+ const router$1 = router.useRouter();
72356
+ React144.useEffect(() => {
72357
+ if (!shouldBlock || typeof window === "undefined") {
72358
+ return;
72359
+ }
72360
+ const handleBeforeUnload = (event) => {
72361
+ event.preventDefault();
72362
+ event.returnValue = message;
72363
+ return message;
72364
+ };
72365
+ window.addEventListener("beforeunload", handleBeforeUnload);
72366
+ return () => {
72367
+ window.removeEventListener("beforeunload", handleBeforeUnload);
72368
+ };
72369
+ }, [message, shouldBlock]);
72370
+ React144.useEffect(() => {
72371
+ if (!shouldBlock || !router$1?.events || typeof window === "undefined") {
72372
+ return;
72373
+ }
72374
+ const handleRouteChangeStart = (url) => {
72375
+ const currentUrl = router$1.asPath || window.location.pathname;
72376
+ if (url === currentUrl) {
72377
+ return;
72378
+ }
72379
+ if (window.confirm(message)) {
72380
+ return;
72381
+ }
72382
+ const routeChangeError = new Error("Route change aborted due to unsaved changes");
72383
+ routeChangeError.cancelled = true;
72384
+ router$1.events.emit("routeChangeError", routeChangeError, url, { shallow: false });
72385
+ throw routeChangeError;
72386
+ };
72387
+ router$1.events.on("routeChangeStart", handleRouteChangeStart);
72388
+ return () => {
72389
+ router$1.events.off("routeChangeStart", handleRouteChangeStart);
72390
+ };
72391
+ }, [message, router$1, shouldBlock]);
72392
+ };
72343
72393
  var calculateShiftHours = (startTime, endTime, breaks = []) => {
72344
72394
  if (!startTime || !endTime) return 8;
72345
72395
  const [startHour, startMinute] = startTime.split(":").map(Number);
@@ -72669,6 +72719,11 @@ var ShiftsView = ({
72669
72719
  className = ""
72670
72720
  }) => {
72671
72721
  const supabase = useSupabase();
72722
+ const lineIdsKey = React144.useMemo(() => lineIds.join("|"), [lineIds]);
72723
+ const stableLineIds = React144.useMemo(
72724
+ () => lineIdsKey.split("|").filter(Boolean),
72725
+ [lineIdsKey]
72726
+ );
72672
72727
  const { lines: dbLines } = useLines();
72673
72728
  const mergedLineNames = React144.useMemo(() => {
72674
72729
  const merged = { ...lineNames };
@@ -72682,14 +72737,14 @@ var ShiftsView = ({
72682
72737
  React144.useEffect(() => {
72683
72738
  console.log("[ShiftsView] Component mounted/re-rendered", {
72684
72739
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
72685
- lineIds: lineIds.length
72740
+ lineIds: stableLineIds.length
72686
72741
  });
72687
72742
  return () => {
72688
72743
  console.log("[ShiftsView] Component unmounting");
72689
72744
  };
72690
- }, []);
72745
+ }, [stableLineIds.length]);
72691
72746
  const [lineConfigs, setLineConfigs] = React144.useState(
72692
- () => lineIds.map((id3) => ({
72747
+ () => stableLineIds.map((id3) => ({
72693
72748
  id: id3,
72694
72749
  name: lineNames[id3] || `Line ${id3.substring(0, 4)}`,
72695
72750
  timezone: "Asia/Kolkata",
@@ -72703,8 +72758,18 @@ var ShiftsView = ({
72703
72758
  const [loading, setLoading] = React144.useState(true);
72704
72759
  const [error, setError] = React144.useState(null);
72705
72760
  const [saveStatusMessages, setSaveStatusMessages] = React144.useState(
72706
- () => lineIds.reduce((acc, id3) => ({ ...acc, [id3]: null }), {})
72761
+ () => stableLineIds.reduce((acc, id3) => ({ ...acc, [id3]: null }), {})
72707
72762
  );
72763
+ const [dirtyLineIds, setDirtyLineIds] = React144.useState(/* @__PURE__ */ new Set());
72764
+ useUnsavedChangesPrompt(dirtyLineIds.size > 0);
72765
+ const markLineDirty = React144.useCallback((lineId) => {
72766
+ setDirtyLineIds((prev) => {
72767
+ if (prev.has(lineId)) return prev;
72768
+ const next = new Set(prev);
72769
+ next.add(lineId);
72770
+ return next;
72771
+ });
72772
+ }, []);
72708
72773
  const showToast = React144.useCallback((type, message) => {
72709
72774
  if (onToast) {
72710
72775
  try {
@@ -72724,7 +72789,7 @@ var ShiftsView = ({
72724
72789
  try {
72725
72790
  setLoading(true);
72726
72791
  setError(null);
72727
- const { data: enabledLines, error: linesError } = await supabase.from("lines").select("id, enable").in("id", lineIds).eq("enable", true);
72792
+ const { data: enabledLines, error: linesError } = await supabase.from("lines").select("id, enable").in("id", stableLineIds).eq("enable", true);
72728
72793
  if (linesError) {
72729
72794
  console.error("Error fetching enabled lines:", linesError);
72730
72795
  showToast("error", "Error loading lines");
@@ -72756,18 +72821,21 @@ var ShiftsView = ({
72756
72821
  return acc;
72757
72822
  }, {});
72758
72823
  setLineConfigs((prev) => {
72759
- const enabledConfigs = prev.filter((config) => enabledLineIds.includes(config.id));
72760
- return enabledConfigs.map((config) => {
72761
- const rows = shiftsByLine[config.id] || [];
72824
+ const previousByLineId = new Map(prev.map((config) => [config.id, config]));
72825
+ return enabledLineIds.map((lineId) => {
72826
+ const existingConfig = previousByLineId.get(lineId);
72827
+ const rows = shiftsByLine[lineId] || [];
72762
72828
  const builtConfig = buildShiftConfigFromOperatingHoursRows(rows);
72763
- const lineName = lineNameMap[config.id] || mergedLineNames[config.id] || `Line ${config.id.substring(0, 4)}`;
72829
+ const lineName = lineNameMap[lineId] || mergedLineNames[lineId] || `Line ${lineId.substring(0, 4)}`;
72764
72830
  const sortedShifts = [...builtConfig.shifts || []].sort((a, b) => a.shiftId - b.shiftId);
72765
72831
  return {
72766
- ...config,
72832
+ id: lineId,
72767
72833
  name: lineName,
72834
+ timezone: builtConfig.timezone || existingConfig?.timezone || "Asia/Kolkata",
72768
72835
  shifts: sortedShifts,
72769
- timezone: builtConfig.timezone || config.timezone,
72770
- isOpen: config.isOpen ?? getStoredLineState(config.id)
72836
+ isSaving: existingConfig?.isSaving ?? false,
72837
+ saveSuccess: existingConfig?.saveSuccess ?? false,
72838
+ isOpen: existingConfig?.isOpen ?? getStoredLineState(lineId)
72771
72839
  };
72772
72840
  });
72773
72841
  });
@@ -72780,7 +72848,7 @@ var ShiftsView = ({
72780
72848
  }
72781
72849
  };
72782
72850
  fetchShiftConfigs();
72783
- }, [lineIds, showToast]);
72851
+ }, [stableLineIds, showToast]);
72784
72852
  React144.useCallback((lineId) => {
72785
72853
  setLineConfigs((prev) => {
72786
72854
  const typedPrev = prev;
@@ -72792,6 +72860,7 @@ var ShiftsView = ({
72792
72860
  });
72793
72861
  }, []);
72794
72862
  const updateShiftTime = React144.useCallback((lineId, shiftIndex, field, value) => {
72863
+ markLineDirty(lineId);
72795
72864
  setLineConfigs((prev) => prev.map((config) => {
72796
72865
  if (config.id === lineId && config.shifts) {
72797
72866
  const newShifts = [...config.shifts];
@@ -72802,8 +72871,9 @@ var ShiftsView = ({
72802
72871
  }
72803
72872
  return config;
72804
72873
  }));
72805
- }, []);
72874
+ }, [markLineDirty]);
72806
72875
  const addShiftBreak = React144.useCallback((lineId, shiftIndex) => {
72876
+ markLineDirty(lineId);
72807
72877
  setLineConfigs((prev) => prev.map((config) => {
72808
72878
  if (config.id === lineId && config.shifts) {
72809
72879
  const newShifts = [...config.shifts];
@@ -72824,8 +72894,9 @@ var ShiftsView = ({
72824
72894
  }
72825
72895
  return config;
72826
72896
  }));
72827
- }, []);
72897
+ }, [markLineDirty]);
72828
72898
  const updateShiftBreak = React144.useCallback((lineId, shiftIndex, breakIndex, field, value) => {
72899
+ markLineDirty(lineId);
72829
72900
  setLineConfigs((prev) => prev.map((config) => {
72830
72901
  if (config.id === lineId && config.shifts) {
72831
72902
  const newShifts = [...config.shifts];
@@ -72851,8 +72922,9 @@ var ShiftsView = ({
72851
72922
  }
72852
72923
  return config;
72853
72924
  }));
72854
- }, []);
72925
+ }, [markLineDirty]);
72855
72926
  const removeShiftBreak = React144.useCallback((lineId, shiftIndex, breakIndex) => {
72927
+ markLineDirty(lineId);
72856
72928
  setLineConfigs((prev) => prev.map((config) => {
72857
72929
  if (config.id === lineId && config.shifts) {
72858
72930
  const newShifts = [...config.shifts];
@@ -72867,7 +72939,7 @@ var ShiftsView = ({
72867
72939
  }
72868
72940
  return config;
72869
72941
  }));
72870
- }, []);
72942
+ }, [markLineDirty]);
72871
72943
  const getOperationalDateForLine = React144.useCallback((lineConfig) => {
72872
72944
  const sortedShifts = [...lineConfig.shifts || []].sort((a, b) => a.shiftId - b.shiftId);
72873
72945
  const dayBoundaryStart = sortedShifts[0]?.startTime || "06:00";
@@ -73152,6 +73224,11 @@ var ShiftsView = ({
73152
73224
  setLineConfigs((prev) => prev.map(
73153
73225
  (config) => config.id === lineId ? { ...config, isSaving: false, saveSuccess: true } : config
73154
73226
  ));
73227
+ setDirtyLineIds((prev) => {
73228
+ const next = new Set(prev);
73229
+ next.delete(lineId);
73230
+ return next;
73231
+ });
73155
73232
  let successMessage = "Shift configurations saved successfully.";
73156
73233
  if (changedShiftCount > 0 && recalculatedTargetsCount > 0) {
73157
73234
  successMessage = `Shift configurations saved. Targets updated successfully for ${recalculatedTargetsCount} workspace${recalculatedTargetsCount === 1 ? "" : "s"}.`;
@@ -74236,8 +74313,13 @@ var TargetsView = ({
74236
74313
  onSaveChanges
74237
74314
  }) => {
74238
74315
  const timezone = useAppTimezone();
74316
+ const lineIdsKey = React144.useMemo(() => lineIds.join("|"), [lineIds]);
74317
+ const stableLineIds = React144.useMemo(
74318
+ () => lineIdsKey.split("|").filter(Boolean),
74319
+ [lineIdsKey]
74320
+ );
74239
74321
  React144.useMemo(() => {
74240
- return lineIds.reduce((acc, lineId) => ({
74322
+ return stableLineIds.reduce((acc, lineId) => ({
74241
74323
  ...acc,
74242
74324
  [lineId]: {
74243
74325
  productId: "",
@@ -74251,9 +74333,9 @@ var TargetsView = ({
74251
74333
  // Initialize factoryId
74252
74334
  }
74253
74335
  }), {});
74254
- }, [lineIds]);
74336
+ }, [stableLineIds]);
74255
74337
  const [dropdownStates, setDropdownStates] = React144.useState(() => {
74256
- return lineIds.reduce((acc, lineId) => ({
74338
+ return stableLineIds.reduce((acc, lineId) => ({
74257
74339
  ...acc,
74258
74340
  [lineId]: getStoredLineState2(lineId)
74259
74341
  }), {});
@@ -74261,10 +74343,10 @@ var TargetsView = ({
74261
74343
  const [allShiftsData, setAllShiftsData] = React144.useState({});
74262
74344
  const [actionIds, setActionIds] = React144.useState(null);
74263
74345
  const [savingLines, setSavingLines] = React144.useState(
74264
- () => lineIds.reduce((acc, id3) => ({ ...acc, [id3]: false }), {})
74346
+ () => stableLineIds.reduce((acc, id3) => ({ ...acc, [id3]: false }), {})
74265
74347
  );
74266
74348
  const [saveSuccess, setSaveSuccess] = React144.useState(
74267
- () => lineIds.reduce((acc, id3) => ({ ...acc, [id3]: false }), {})
74349
+ () => stableLineIds.reduce((acc, id3) => ({ ...acc, [id3]: false }), {})
74268
74350
  );
74269
74351
  const [isLoading, setIsLoading] = React144.useState(true);
74270
74352
  const [isConfigureLegendOpen, setIsConfigureLegendOpen] = React144.useState(false);
@@ -74274,6 +74356,8 @@ var TargetsView = ({
74274
74356
  const canSaveTargets = useCanSaveTargets();
74275
74357
  const [dbValues, setDbValues] = React144.useState({ 0: {}, 1: {} });
74276
74358
  const [userEditedFields, setUserEditedFields] = React144.useState(/* @__PURE__ */ new Set());
74359
+ const hasUnsavedChanges = userEditedFields.size > 0;
74360
+ useUnsavedChangesPrompt(hasUnsavedChanges);
74277
74361
  const lineWorkspaces = allShiftsData[selectedShift] || {};
74278
74362
  const setLineWorkspaces = React144.useCallback((updater) => {
74279
74363
  setAllShiftsData((prev) => ({
@@ -74290,13 +74374,13 @@ var TargetsView = ({
74290
74374
  dbLines.forEach((line) => {
74291
74375
  merged[line.id] = line.line_name;
74292
74376
  });
74293
- lineIds.forEach((lineId) => {
74377
+ stableLineIds.forEach((lineId) => {
74294
74378
  if (!merged[lineId]) {
74295
74379
  merged[lineId] = `Line ${lineId.substring(0, 4)}`;
74296
74380
  }
74297
74381
  });
74298
74382
  return merged;
74299
- }, [lineNames, dbLines, lineIds]);
74383
+ }, [lineNames, dbLines, stableLineIds]);
74300
74384
  const { legend, updateLegend } = useEfficiencyLegend(companyId);
74301
74385
  const { skus, isLoading: skusLoading } = useSKUs(companyId);
74302
74386
  const { skus: skuCatalog, isLoading: skuCatalogLoading } = useSKUs(companyId, {
@@ -74355,22 +74439,22 @@ var TargetsView = ({
74355
74439
  React144.useEffect(() => {
74356
74440
  console.log("[TargetsView] Component mounted/re-rendered", {
74357
74441
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
74358
- lineIds: lineIds.length,
74442
+ lineIds: stableLineIds.length,
74359
74443
  effectiveUserId
74360
74444
  });
74361
74445
  return () => {
74362
74446
  console.log("[TargetsView] Component unmounting");
74363
74447
  };
74364
- }, []);
74448
+ }, [effectiveUserId, stableLineIds.length]);
74365
74449
  React144.useEffect(() => {
74366
74450
  const fetchInitialData = async () => {
74367
- if (lineIds.length === 0 || !companyId) return;
74451
+ if (stableLineIds.length === 0 || !companyId) return;
74368
74452
  if (skuCatalogLoading) return;
74369
74453
  console.log("[TargetsView] Starting optimized fetchInitialData with bulk endpoint");
74370
74454
  setIsLoading(true);
74371
74455
  try {
74372
74456
  const currentDate = getOperationalDate(timezone);
74373
- const { data: shiftsData, error: shiftsError } = await supabase.from("line_operating_hours").select("line_id, shift_id, shift_name").in("line_id", lineIds);
74457
+ const { data: shiftsData, error: shiftsError } = await supabase.from("line_operating_hours").select("line_id, shift_id, shift_name").in("line_id", stableLineIds);
74374
74458
  if (shiftsError) {
74375
74459
  console.warn("[TargetsView] Error fetching shift definitions, falling back to defaults", shiftsError);
74376
74460
  }
@@ -74388,7 +74472,7 @@ var TargetsView = ({
74388
74472
  setSelectedShift(defaultShiftId);
74389
74473
  const bulkResponse = await workspaceService.fetchBulkTargets({
74390
74474
  companyId,
74391
- lineIds,
74475
+ lineIds: stableLineIds,
74392
74476
  date: currentDate,
74393
74477
  shifts: effectiveShiftOptions.map((s) => s.id),
74394
74478
  // Fetch all configured shifts
@@ -74533,7 +74617,7 @@ var TargetsView = ({
74533
74617
  });
74534
74618
  });
74535
74619
  effectiveShiftOptions.forEach(({ id: shiftId }) => {
74536
- lineIds.forEach((lineId) => {
74620
+ stableLineIds.forEach((lineId) => {
74537
74621
  if (!newAllShiftsData[shiftId][lineId]) {
74538
74622
  const lineData = data.lines[lineId];
74539
74623
  const shift0Data = newAllShiftsData[0]?.[lineId];
@@ -74603,7 +74687,7 @@ var TargetsView = ({
74603
74687
  });
74604
74688
  effectiveShiftOptions.forEach(({ id: shiftId }) => {
74605
74689
  const orderedLineWorkspaces = {};
74606
- lineIds.forEach((lineId) => {
74690
+ stableLineIds.forEach((lineId) => {
74607
74691
  if (newAllShiftsData[shiftId][lineId]) {
74608
74692
  orderedLineWorkspaces[lineId] = newAllShiftsData[shiftId][lineId];
74609
74693
  }
@@ -74625,7 +74709,7 @@ var TargetsView = ({
74625
74709
  }
74626
74710
  };
74627
74711
  fetchInitialData();
74628
- }, [lineIds, companyId, timezone, skuEnabled, skuCatalogLoading]);
74712
+ }, [stableLineIds, companyId, timezone, skuEnabled, skuCatalogLoading]);
74629
74713
  const toggleLineDropdown = React144.useCallback((lineId) => {
74630
74714
  setDropdownStates((prev) => {
74631
74715
  const newIsOpen = !prev[lineId];
@@ -74800,6 +74884,7 @@ var TargetsView = ({
74800
74884
  };
74801
74885
  const handleActionTypeChange = React144.useCallback((lineId, workspaceId, newActionType) => {
74802
74886
  if (!actionIds) return;
74887
+ setUserEditedFields((prev) => new Set(prev).add(`${lineId}-${workspaceId}-actionType`));
74803
74888
  setLineWorkspaces((prev) => {
74804
74889
  const currentLineData = prev?.[lineId];
74805
74890
  if (!currentLineData?.workspaces) {
@@ -74997,10 +75082,10 @@ var TargetsView = ({
74997
75082
  console.log(`[handleSaveLine] Updated dbValues for line ${lineId}, shift ${selectedShift}`);
74998
75083
  setUserEditedFields((prev) => {
74999
75084
  const newSet = new Set(prev);
75000
- lineDataToSave.workspaces.forEach((ws) => {
75001
- newSet.delete(`${lineId}-${ws.id}-targetPPH`);
75002
- newSet.delete(`${lineId}-${ws.id}-targetCycleTime`);
75003
- newSet.delete(`${lineId}-${ws.id}-targetDayOutput`);
75085
+ Array.from(newSet).forEach((fieldKey) => {
75086
+ if (fieldKey.startsWith(`${lineId}-`)) {
75087
+ newSet.delete(fieldKey);
75088
+ }
75004
75089
  });
75005
75090
  return newSet;
75006
75091
  });
package/dist/index.mjs CHANGED
@@ -19887,6 +19887,9 @@ function useNavigation(customNavigate) {
19887
19887
  await router.push(path, void 0, { shallow: options?.shallow ?? false });
19888
19888
  }
19889
19889
  } catch (error) {
19890
+ if (error?.cancelled || error?.message?.includes("Route change aborted")) {
19891
+ return;
19892
+ }
19890
19893
  if (error.message?.includes("Page not compiled") && retryCount < MAX_RETRIES) {
19891
19894
  setTimeout(() => attemptNavigation(retryCount + 1), RETRY_DELAY);
19892
19895
  } else if (retryCount >= MAX_RETRIES) {
@@ -54878,27 +54881,34 @@ var WorkspaceGrid = React144__default.memo(({
54878
54881
  [viewMode, workspaces]
54879
54882
  );
54880
54883
  return /* @__PURE__ */ jsxs("div", { className: `flex flex-col w-full h-full overflow-hidden bg-slate-50/50 ${className}`, children: [
54881
- /* @__PURE__ */ jsxs("div", { className: "flex-none px-4 py-3 z-20 flex flex-row items-center justify-between gap-4", children: [
54882
- /* @__PURE__ */ jsx("div", { className: "hidden sm:block", children: /* @__PURE__ */ jsx("div", { className: "inline-flex bg-white/95 rounded-lg shadow-sm px-4 py-2 border border-slate-200/60 backdrop-blur-sm", children: /* @__PURE__ */ jsx(Legend5, { legend, metricLabel: legendMetricLabel }) }) }),
54883
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-3 shrink-0", children: [
54884
- toolbarRightContent,
54885
- mapViewEnabled && /* @__PURE__ */ jsx(
54886
- "button",
54887
- {
54888
- onClick: handleViewModeToggle,
54889
- className: "flex items-center gap-2 px-3 py-1.5 bg-white border border-slate-200 rounded-md shadow-sm hover:bg-slate-50 transition-colors duration-200 text-slate-700",
54890
- title: viewMode === "video" ? "Switch to Map View" : "Switch to Video View",
54891
- children: viewMode === "video" ? /* @__PURE__ */ jsxs(Fragment, { children: [
54892
- /* @__PURE__ */ jsx(Map$1, { className: "w-4 h-4 text-slate-500" }),
54893
- /* @__PURE__ */ jsx("span", { className: "hidden sm:inline text-sm font-medium", children: "Map View" })
54894
- ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
54895
- /* @__PURE__ */ jsx(Video, { className: "w-4 h-4 text-slate-500" }),
54896
- /* @__PURE__ */ jsx("span", { className: "hidden sm:inline text-sm font-medium", children: "Video View" })
54897
- ] })
54898
- }
54899
- )
54900
- ] })
54901
- ] }),
54884
+ /* @__PURE__ */ jsxs(
54885
+ "div",
54886
+ {
54887
+ "data-testid": "workspace-grid-toolbar",
54888
+ className: "relative z-[100] flex-none px-4 py-3 flex flex-row items-center justify-between gap-4",
54889
+ children: [
54890
+ /* @__PURE__ */ jsx("div", { className: "hidden sm:block", children: /* @__PURE__ */ jsx("div", { className: "inline-flex bg-white/95 rounded-lg shadow-sm px-4 py-2 border border-slate-200/60 backdrop-blur-sm", children: /* @__PURE__ */ jsx(Legend5, { legend, metricLabel: legendMetricLabel }) }) }),
54891
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-3 shrink-0", children: [
54892
+ toolbarRightContent,
54893
+ mapViewEnabled && /* @__PURE__ */ jsx(
54894
+ "button",
54895
+ {
54896
+ onClick: handleViewModeToggle,
54897
+ className: "flex items-center gap-2 px-3 py-1.5 bg-white border border-slate-200 rounded-md shadow-sm hover:bg-slate-50 transition-colors duration-200 text-slate-700",
54898
+ title: viewMode === "video" ? "Switch to Map View" : "Switch to Video View",
54899
+ children: viewMode === "video" ? /* @__PURE__ */ jsxs(Fragment, { children: [
54900
+ /* @__PURE__ */ jsx(Map$1, { className: "w-4 h-4 text-slate-500" }),
54901
+ /* @__PURE__ */ jsx("span", { className: "hidden sm:inline text-sm font-medium", children: "Map View" })
54902
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
54903
+ /* @__PURE__ */ jsx(Video, { className: "w-4 h-4 text-slate-500" }),
54904
+ /* @__PURE__ */ jsx("span", { className: "hidden sm:inline text-sm font-medium", children: "Video View" })
54905
+ ] })
54906
+ }
54907
+ )
54908
+ ] })
54909
+ ]
54910
+ }
54911
+ ),
54902
54912
  /* @__PURE__ */ jsx("div", { className: "sm:hidden px-3 py-2 bg-white border-b border-slate-200/60 z-10", children: /* @__PURE__ */ jsx(Legend5, { legend, metricLabel: legendMetricLabel }) }),
54903
54913
  /* @__PURE__ */ jsx("div", { className: "flex-1 relative overflow-hidden", children: /* @__PURE__ */ jsx(AnimatePresence, { mode: "wait", children: viewMode === "video" ? /* @__PURE__ */ jsx(
54904
54914
  motion.div,
@@ -72311,6 +72321,46 @@ var ClipsCostView = () => {
72311
72321
  ] });
72312
72322
  };
72313
72323
  var ClipsCostView_default = ClipsCostView;
72324
+ var DEFAULT_UNSAVED_CHANGES_MESSAGE = "You have unsaved changes. Leave this page and lose them?";
72325
+ var useUnsavedChangesPrompt = (shouldBlock, message = DEFAULT_UNSAVED_CHANGES_MESSAGE) => {
72326
+ const router = useRouter();
72327
+ useEffect(() => {
72328
+ if (!shouldBlock || typeof window === "undefined") {
72329
+ return;
72330
+ }
72331
+ const handleBeforeUnload = (event) => {
72332
+ event.preventDefault();
72333
+ event.returnValue = message;
72334
+ return message;
72335
+ };
72336
+ window.addEventListener("beforeunload", handleBeforeUnload);
72337
+ return () => {
72338
+ window.removeEventListener("beforeunload", handleBeforeUnload);
72339
+ };
72340
+ }, [message, shouldBlock]);
72341
+ useEffect(() => {
72342
+ if (!shouldBlock || !router?.events || typeof window === "undefined") {
72343
+ return;
72344
+ }
72345
+ const handleRouteChangeStart = (url) => {
72346
+ const currentUrl = router.asPath || window.location.pathname;
72347
+ if (url === currentUrl) {
72348
+ return;
72349
+ }
72350
+ if (window.confirm(message)) {
72351
+ return;
72352
+ }
72353
+ const routeChangeError = new Error("Route change aborted due to unsaved changes");
72354
+ routeChangeError.cancelled = true;
72355
+ router.events.emit("routeChangeError", routeChangeError, url, { shallow: false });
72356
+ throw routeChangeError;
72357
+ };
72358
+ router.events.on("routeChangeStart", handleRouteChangeStart);
72359
+ return () => {
72360
+ router.events.off("routeChangeStart", handleRouteChangeStart);
72361
+ };
72362
+ }, [message, router, shouldBlock]);
72363
+ };
72314
72364
  var calculateShiftHours = (startTime, endTime, breaks = []) => {
72315
72365
  if (!startTime || !endTime) return 8;
72316
72366
  const [startHour, startMinute] = startTime.split(":").map(Number);
@@ -72640,6 +72690,11 @@ var ShiftsView = ({
72640
72690
  className = ""
72641
72691
  }) => {
72642
72692
  const supabase = useSupabase();
72693
+ const lineIdsKey = useMemo(() => lineIds.join("|"), [lineIds]);
72694
+ const stableLineIds = useMemo(
72695
+ () => lineIdsKey.split("|").filter(Boolean),
72696
+ [lineIdsKey]
72697
+ );
72643
72698
  const { lines: dbLines } = useLines();
72644
72699
  const mergedLineNames = useMemo(() => {
72645
72700
  const merged = { ...lineNames };
@@ -72653,14 +72708,14 @@ var ShiftsView = ({
72653
72708
  useEffect(() => {
72654
72709
  console.log("[ShiftsView] Component mounted/re-rendered", {
72655
72710
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
72656
- lineIds: lineIds.length
72711
+ lineIds: stableLineIds.length
72657
72712
  });
72658
72713
  return () => {
72659
72714
  console.log("[ShiftsView] Component unmounting");
72660
72715
  };
72661
- }, []);
72716
+ }, [stableLineIds.length]);
72662
72717
  const [lineConfigs, setLineConfigs] = useState(
72663
- () => lineIds.map((id3) => ({
72718
+ () => stableLineIds.map((id3) => ({
72664
72719
  id: id3,
72665
72720
  name: lineNames[id3] || `Line ${id3.substring(0, 4)}`,
72666
72721
  timezone: "Asia/Kolkata",
@@ -72674,8 +72729,18 @@ var ShiftsView = ({
72674
72729
  const [loading, setLoading] = useState(true);
72675
72730
  const [error, setError] = useState(null);
72676
72731
  const [saveStatusMessages, setSaveStatusMessages] = useState(
72677
- () => lineIds.reduce((acc, id3) => ({ ...acc, [id3]: null }), {})
72732
+ () => stableLineIds.reduce((acc, id3) => ({ ...acc, [id3]: null }), {})
72678
72733
  );
72734
+ const [dirtyLineIds, setDirtyLineIds] = useState(/* @__PURE__ */ new Set());
72735
+ useUnsavedChangesPrompt(dirtyLineIds.size > 0);
72736
+ const markLineDirty = useCallback((lineId) => {
72737
+ setDirtyLineIds((prev) => {
72738
+ if (prev.has(lineId)) return prev;
72739
+ const next = new Set(prev);
72740
+ next.add(lineId);
72741
+ return next;
72742
+ });
72743
+ }, []);
72679
72744
  const showToast = useCallback((type, message) => {
72680
72745
  if (onToast) {
72681
72746
  try {
@@ -72695,7 +72760,7 @@ var ShiftsView = ({
72695
72760
  try {
72696
72761
  setLoading(true);
72697
72762
  setError(null);
72698
- const { data: enabledLines, error: linesError } = await supabase.from("lines").select("id, enable").in("id", lineIds).eq("enable", true);
72763
+ const { data: enabledLines, error: linesError } = await supabase.from("lines").select("id, enable").in("id", stableLineIds).eq("enable", true);
72699
72764
  if (linesError) {
72700
72765
  console.error("Error fetching enabled lines:", linesError);
72701
72766
  showToast("error", "Error loading lines");
@@ -72727,18 +72792,21 @@ var ShiftsView = ({
72727
72792
  return acc;
72728
72793
  }, {});
72729
72794
  setLineConfigs((prev) => {
72730
- const enabledConfigs = prev.filter((config) => enabledLineIds.includes(config.id));
72731
- return enabledConfigs.map((config) => {
72732
- const rows = shiftsByLine[config.id] || [];
72795
+ const previousByLineId = new Map(prev.map((config) => [config.id, config]));
72796
+ return enabledLineIds.map((lineId) => {
72797
+ const existingConfig = previousByLineId.get(lineId);
72798
+ const rows = shiftsByLine[lineId] || [];
72733
72799
  const builtConfig = buildShiftConfigFromOperatingHoursRows(rows);
72734
- const lineName = lineNameMap[config.id] || mergedLineNames[config.id] || `Line ${config.id.substring(0, 4)}`;
72800
+ const lineName = lineNameMap[lineId] || mergedLineNames[lineId] || `Line ${lineId.substring(0, 4)}`;
72735
72801
  const sortedShifts = [...builtConfig.shifts || []].sort((a, b) => a.shiftId - b.shiftId);
72736
72802
  return {
72737
- ...config,
72803
+ id: lineId,
72738
72804
  name: lineName,
72805
+ timezone: builtConfig.timezone || existingConfig?.timezone || "Asia/Kolkata",
72739
72806
  shifts: sortedShifts,
72740
- timezone: builtConfig.timezone || config.timezone,
72741
- isOpen: config.isOpen ?? getStoredLineState(config.id)
72807
+ isSaving: existingConfig?.isSaving ?? false,
72808
+ saveSuccess: existingConfig?.saveSuccess ?? false,
72809
+ isOpen: existingConfig?.isOpen ?? getStoredLineState(lineId)
72742
72810
  };
72743
72811
  });
72744
72812
  });
@@ -72751,7 +72819,7 @@ var ShiftsView = ({
72751
72819
  }
72752
72820
  };
72753
72821
  fetchShiftConfigs();
72754
- }, [lineIds, showToast]);
72822
+ }, [stableLineIds, showToast]);
72755
72823
  useCallback((lineId) => {
72756
72824
  setLineConfigs((prev) => {
72757
72825
  const typedPrev = prev;
@@ -72763,6 +72831,7 @@ var ShiftsView = ({
72763
72831
  });
72764
72832
  }, []);
72765
72833
  const updateShiftTime = useCallback((lineId, shiftIndex, field, value) => {
72834
+ markLineDirty(lineId);
72766
72835
  setLineConfigs((prev) => prev.map((config) => {
72767
72836
  if (config.id === lineId && config.shifts) {
72768
72837
  const newShifts = [...config.shifts];
@@ -72773,8 +72842,9 @@ var ShiftsView = ({
72773
72842
  }
72774
72843
  return config;
72775
72844
  }));
72776
- }, []);
72845
+ }, [markLineDirty]);
72777
72846
  const addShiftBreak = useCallback((lineId, shiftIndex) => {
72847
+ markLineDirty(lineId);
72778
72848
  setLineConfigs((prev) => prev.map((config) => {
72779
72849
  if (config.id === lineId && config.shifts) {
72780
72850
  const newShifts = [...config.shifts];
@@ -72795,8 +72865,9 @@ var ShiftsView = ({
72795
72865
  }
72796
72866
  return config;
72797
72867
  }));
72798
- }, []);
72868
+ }, [markLineDirty]);
72799
72869
  const updateShiftBreak = useCallback((lineId, shiftIndex, breakIndex, field, value) => {
72870
+ markLineDirty(lineId);
72800
72871
  setLineConfigs((prev) => prev.map((config) => {
72801
72872
  if (config.id === lineId && config.shifts) {
72802
72873
  const newShifts = [...config.shifts];
@@ -72822,8 +72893,9 @@ var ShiftsView = ({
72822
72893
  }
72823
72894
  return config;
72824
72895
  }));
72825
- }, []);
72896
+ }, [markLineDirty]);
72826
72897
  const removeShiftBreak = useCallback((lineId, shiftIndex, breakIndex) => {
72898
+ markLineDirty(lineId);
72827
72899
  setLineConfigs((prev) => prev.map((config) => {
72828
72900
  if (config.id === lineId && config.shifts) {
72829
72901
  const newShifts = [...config.shifts];
@@ -72838,7 +72910,7 @@ var ShiftsView = ({
72838
72910
  }
72839
72911
  return config;
72840
72912
  }));
72841
- }, []);
72913
+ }, [markLineDirty]);
72842
72914
  const getOperationalDateForLine = useCallback((lineConfig) => {
72843
72915
  const sortedShifts = [...lineConfig.shifts || []].sort((a, b) => a.shiftId - b.shiftId);
72844
72916
  const dayBoundaryStart = sortedShifts[0]?.startTime || "06:00";
@@ -73123,6 +73195,11 @@ var ShiftsView = ({
73123
73195
  setLineConfigs((prev) => prev.map(
73124
73196
  (config) => config.id === lineId ? { ...config, isSaving: false, saveSuccess: true } : config
73125
73197
  ));
73198
+ setDirtyLineIds((prev) => {
73199
+ const next = new Set(prev);
73200
+ next.delete(lineId);
73201
+ return next;
73202
+ });
73126
73203
  let successMessage = "Shift configurations saved successfully.";
73127
73204
  if (changedShiftCount > 0 && recalculatedTargetsCount > 0) {
73128
73205
  successMessage = `Shift configurations saved. Targets updated successfully for ${recalculatedTargetsCount} workspace${recalculatedTargetsCount === 1 ? "" : "s"}.`;
@@ -74207,8 +74284,13 @@ var TargetsView = ({
74207
74284
  onSaveChanges
74208
74285
  }) => {
74209
74286
  const timezone = useAppTimezone();
74287
+ const lineIdsKey = useMemo(() => lineIds.join("|"), [lineIds]);
74288
+ const stableLineIds = useMemo(
74289
+ () => lineIdsKey.split("|").filter(Boolean),
74290
+ [lineIdsKey]
74291
+ );
74210
74292
  useMemo(() => {
74211
- return lineIds.reduce((acc, lineId) => ({
74293
+ return stableLineIds.reduce((acc, lineId) => ({
74212
74294
  ...acc,
74213
74295
  [lineId]: {
74214
74296
  productId: "",
@@ -74222,9 +74304,9 @@ var TargetsView = ({
74222
74304
  // Initialize factoryId
74223
74305
  }
74224
74306
  }), {});
74225
- }, [lineIds]);
74307
+ }, [stableLineIds]);
74226
74308
  const [dropdownStates, setDropdownStates] = useState(() => {
74227
- return lineIds.reduce((acc, lineId) => ({
74309
+ return stableLineIds.reduce((acc, lineId) => ({
74228
74310
  ...acc,
74229
74311
  [lineId]: getStoredLineState2(lineId)
74230
74312
  }), {});
@@ -74232,10 +74314,10 @@ var TargetsView = ({
74232
74314
  const [allShiftsData, setAllShiftsData] = useState({});
74233
74315
  const [actionIds, setActionIds] = useState(null);
74234
74316
  const [savingLines, setSavingLines] = useState(
74235
- () => lineIds.reduce((acc, id3) => ({ ...acc, [id3]: false }), {})
74317
+ () => stableLineIds.reduce((acc, id3) => ({ ...acc, [id3]: false }), {})
74236
74318
  );
74237
74319
  const [saveSuccess, setSaveSuccess] = useState(
74238
- () => lineIds.reduce((acc, id3) => ({ ...acc, [id3]: false }), {})
74320
+ () => stableLineIds.reduce((acc, id3) => ({ ...acc, [id3]: false }), {})
74239
74321
  );
74240
74322
  const [isLoading, setIsLoading] = useState(true);
74241
74323
  const [isConfigureLegendOpen, setIsConfigureLegendOpen] = useState(false);
@@ -74245,6 +74327,8 @@ var TargetsView = ({
74245
74327
  const canSaveTargets = useCanSaveTargets();
74246
74328
  const [dbValues, setDbValues] = useState({ 0: {}, 1: {} });
74247
74329
  const [userEditedFields, setUserEditedFields] = useState(/* @__PURE__ */ new Set());
74330
+ const hasUnsavedChanges = userEditedFields.size > 0;
74331
+ useUnsavedChangesPrompt(hasUnsavedChanges);
74248
74332
  const lineWorkspaces = allShiftsData[selectedShift] || {};
74249
74333
  const setLineWorkspaces = useCallback((updater) => {
74250
74334
  setAllShiftsData((prev) => ({
@@ -74261,13 +74345,13 @@ var TargetsView = ({
74261
74345
  dbLines.forEach((line) => {
74262
74346
  merged[line.id] = line.line_name;
74263
74347
  });
74264
- lineIds.forEach((lineId) => {
74348
+ stableLineIds.forEach((lineId) => {
74265
74349
  if (!merged[lineId]) {
74266
74350
  merged[lineId] = `Line ${lineId.substring(0, 4)}`;
74267
74351
  }
74268
74352
  });
74269
74353
  return merged;
74270
- }, [lineNames, dbLines, lineIds]);
74354
+ }, [lineNames, dbLines, stableLineIds]);
74271
74355
  const { legend, updateLegend } = useEfficiencyLegend(companyId);
74272
74356
  const { skus, isLoading: skusLoading } = useSKUs(companyId);
74273
74357
  const { skus: skuCatalog, isLoading: skuCatalogLoading } = useSKUs(companyId, {
@@ -74326,22 +74410,22 @@ var TargetsView = ({
74326
74410
  useEffect(() => {
74327
74411
  console.log("[TargetsView] Component mounted/re-rendered", {
74328
74412
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
74329
- lineIds: lineIds.length,
74413
+ lineIds: stableLineIds.length,
74330
74414
  effectiveUserId
74331
74415
  });
74332
74416
  return () => {
74333
74417
  console.log("[TargetsView] Component unmounting");
74334
74418
  };
74335
- }, []);
74419
+ }, [effectiveUserId, stableLineIds.length]);
74336
74420
  useEffect(() => {
74337
74421
  const fetchInitialData = async () => {
74338
- if (lineIds.length === 0 || !companyId) return;
74422
+ if (stableLineIds.length === 0 || !companyId) return;
74339
74423
  if (skuCatalogLoading) return;
74340
74424
  console.log("[TargetsView] Starting optimized fetchInitialData with bulk endpoint");
74341
74425
  setIsLoading(true);
74342
74426
  try {
74343
74427
  const currentDate = getOperationalDate(timezone);
74344
- const { data: shiftsData, error: shiftsError } = await supabase.from("line_operating_hours").select("line_id, shift_id, shift_name").in("line_id", lineIds);
74428
+ const { data: shiftsData, error: shiftsError } = await supabase.from("line_operating_hours").select("line_id, shift_id, shift_name").in("line_id", stableLineIds);
74345
74429
  if (shiftsError) {
74346
74430
  console.warn("[TargetsView] Error fetching shift definitions, falling back to defaults", shiftsError);
74347
74431
  }
@@ -74359,7 +74443,7 @@ var TargetsView = ({
74359
74443
  setSelectedShift(defaultShiftId);
74360
74444
  const bulkResponse = await workspaceService.fetchBulkTargets({
74361
74445
  companyId,
74362
- lineIds,
74446
+ lineIds: stableLineIds,
74363
74447
  date: currentDate,
74364
74448
  shifts: effectiveShiftOptions.map((s) => s.id),
74365
74449
  // Fetch all configured shifts
@@ -74504,7 +74588,7 @@ var TargetsView = ({
74504
74588
  });
74505
74589
  });
74506
74590
  effectiveShiftOptions.forEach(({ id: shiftId }) => {
74507
- lineIds.forEach((lineId) => {
74591
+ stableLineIds.forEach((lineId) => {
74508
74592
  if (!newAllShiftsData[shiftId][lineId]) {
74509
74593
  const lineData = data.lines[lineId];
74510
74594
  const shift0Data = newAllShiftsData[0]?.[lineId];
@@ -74574,7 +74658,7 @@ var TargetsView = ({
74574
74658
  });
74575
74659
  effectiveShiftOptions.forEach(({ id: shiftId }) => {
74576
74660
  const orderedLineWorkspaces = {};
74577
- lineIds.forEach((lineId) => {
74661
+ stableLineIds.forEach((lineId) => {
74578
74662
  if (newAllShiftsData[shiftId][lineId]) {
74579
74663
  orderedLineWorkspaces[lineId] = newAllShiftsData[shiftId][lineId];
74580
74664
  }
@@ -74596,7 +74680,7 @@ var TargetsView = ({
74596
74680
  }
74597
74681
  };
74598
74682
  fetchInitialData();
74599
- }, [lineIds, companyId, timezone, skuEnabled, skuCatalogLoading]);
74683
+ }, [stableLineIds, companyId, timezone, skuEnabled, skuCatalogLoading]);
74600
74684
  const toggleLineDropdown = useCallback((lineId) => {
74601
74685
  setDropdownStates((prev) => {
74602
74686
  const newIsOpen = !prev[lineId];
@@ -74771,6 +74855,7 @@ var TargetsView = ({
74771
74855
  };
74772
74856
  const handleActionTypeChange = useCallback((lineId, workspaceId, newActionType) => {
74773
74857
  if (!actionIds) return;
74858
+ setUserEditedFields((prev) => new Set(prev).add(`${lineId}-${workspaceId}-actionType`));
74774
74859
  setLineWorkspaces((prev) => {
74775
74860
  const currentLineData = prev?.[lineId];
74776
74861
  if (!currentLineData?.workspaces) {
@@ -74968,10 +75053,10 @@ var TargetsView = ({
74968
75053
  console.log(`[handleSaveLine] Updated dbValues for line ${lineId}, shift ${selectedShift}`);
74969
75054
  setUserEditedFields((prev) => {
74970
75055
  const newSet = new Set(prev);
74971
- lineDataToSave.workspaces.forEach((ws) => {
74972
- newSet.delete(`${lineId}-${ws.id}-targetPPH`);
74973
- newSet.delete(`${lineId}-${ws.id}-targetCycleTime`);
74974
- newSet.delete(`${lineId}-${ws.id}-targetDayOutput`);
75056
+ Array.from(newSet).forEach((fieldKey) => {
75057
+ if (fieldKey.startsWith(`${lineId}-`)) {
75058
+ newSet.delete(fieldKey);
75059
+ }
74975
75060
  });
74976
75061
  return newSet;
74977
75062
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@optifye/dashboard-core",
3
- "version": "6.12.19",
3
+ "version": "6.12.21",
4
4
  "description": "Reusable UI & logic for Optifye dashboard",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",