@j3m-quantum/ui 1.6.1 → 1.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var React17 = require('react');
3
+ var React22 = require('react');
4
4
  var reactSlot = require('@radix-ui/react-slot');
5
5
  var classVarianceAuthority = require('class-variance-authority');
6
6
  var clsx = require('clsx');
@@ -63,7 +63,7 @@ function _interopNamespace(e) {
63
63
  return Object.freeze(n);
64
64
  }
65
65
 
66
- var React17__namespace = /*#__PURE__*/_interopNamespace(React17);
66
+ var React22__namespace = /*#__PURE__*/_interopNamespace(React22);
67
67
  var SeparatorPrimitive__namespace = /*#__PURE__*/_interopNamespace(SeparatorPrimitive);
68
68
  var CheckboxPrimitive__namespace = /*#__PURE__*/_interopNamespace(CheckboxPrimitive);
69
69
  var RadioGroupPrimitive__namespace = /*#__PURE__*/_interopNamespace(RadioGroupPrimitive);
@@ -96,8 +96,8 @@ var ResizablePrimitive__namespace = /*#__PURE__*/_interopNamespace(ResizablePrim
96
96
  // src/hooks/use-mobile.ts
97
97
  var MOBILE_BREAKPOINT = 768;
98
98
  function useIsMobile() {
99
- const [isMobile, setIsMobile] = React17__namespace.useState(void 0);
100
- React17__namespace.useEffect(() => {
99
+ const [isMobile, setIsMobile] = React22__namespace.useState(void 0);
100
+ React22__namespace.useEffect(() => {
101
101
  const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);
102
102
  const onChange = () => {
103
103
  setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
@@ -138,7 +138,7 @@ var buttonVariants = classVarianceAuthority.cva(
138
138
  }
139
139
  }
140
140
  );
141
- var Button = React17__namespace.forwardRef(
141
+ var Button = React22__namespace.forwardRef(
142
142
  ({ className, variant, size, asChild = false, ...props }, ref) => {
143
143
  const Comp = asChild ? reactSlot.Slot : "button";
144
144
  return /* @__PURE__ */ jsxRuntime.jsx(
@@ -502,7 +502,7 @@ function Slider({
502
502
  max = 100,
503
503
  ...props
504
504
  }) {
505
- const _values = React17__namespace.useMemo(
505
+ const _values = React22__namespace.useMemo(
506
506
  () => Array.isArray(value) ? value : Array.isArray(defaultValue) ? defaultValue : [min, max],
507
507
  [value, defaultValue, min, max]
508
508
  );
@@ -788,7 +788,7 @@ function Toggle({
788
788
  }
789
789
  );
790
790
  }
791
- var ToggleGroupContext = React17__namespace.createContext({
791
+ var ToggleGroupContext = React22__namespace.createContext({
792
792
  size: "default",
793
793
  variant: "default",
794
794
  spacing: 0
@@ -825,7 +825,7 @@ function ToggleGroupItem({
825
825
  size,
826
826
  ...props
827
827
  }) {
828
- const context = React17__namespace.useContext(ToggleGroupContext);
828
+ const context = React22__namespace.useContext(ToggleGroupContext);
829
829
  return /* @__PURE__ */ jsxRuntime.jsx(
830
830
  ToggleGroupPrimitive__namespace.Item,
831
831
  {
@@ -855,7 +855,7 @@ function ThemeSwitch({
855
855
  className,
856
856
  size = "default"
857
857
  }) {
858
- const [isChecked, setIsChecked] = React17__namespace.useState(defaultChecked);
858
+ const [isChecked, setIsChecked] = React22__namespace.useState(defaultChecked);
859
859
  const isControlled = checked !== void 0;
860
860
  const currentChecked = isControlled ? checked : isChecked;
861
861
  const handleClick = () => {
@@ -1275,7 +1275,7 @@ function Label2({
1275
1275
  );
1276
1276
  }
1277
1277
  var Form = reactHookForm.FormProvider;
1278
- var FormFieldContext = React17__namespace.createContext(
1278
+ var FormFieldContext = React22__namespace.createContext(
1279
1279
  {}
1280
1280
  );
1281
1281
  var FormField = ({
@@ -1284,8 +1284,8 @@ var FormField = ({
1284
1284
  return /* @__PURE__ */ jsxRuntime.jsx(FormFieldContext.Provider, { value: { name: props.name }, children: /* @__PURE__ */ jsxRuntime.jsx(reactHookForm.Controller, { ...props }) });
1285
1285
  };
1286
1286
  var useFormField = () => {
1287
- const fieldContext = React17__namespace.useContext(FormFieldContext);
1288
- const itemContext = React17__namespace.useContext(FormItemContext);
1287
+ const fieldContext = React22__namespace.useContext(FormFieldContext);
1288
+ const itemContext = React22__namespace.useContext(FormItemContext);
1289
1289
  const { getFieldState } = reactHookForm.useFormContext();
1290
1290
  const formState = reactHookForm.useFormState({ name: fieldContext.name });
1291
1291
  const fieldState = getFieldState(fieldContext.name, formState);
@@ -1302,11 +1302,11 @@ var useFormField = () => {
1302
1302
  ...fieldState
1303
1303
  };
1304
1304
  };
1305
- var FormItemContext = React17__namespace.createContext(
1305
+ var FormItemContext = React22__namespace.createContext(
1306
1306
  {}
1307
1307
  );
1308
1308
  function FormItem({ className, ...props }) {
1309
- const id = React17__namespace.useId();
1309
+ const id = React22__namespace.useId();
1310
1310
  return /* @__PURE__ */ jsxRuntime.jsx(FormItemContext.Provider, { value: { id }, children: /* @__PURE__ */ jsxRuntime.jsx(
1311
1311
  "div",
1312
1312
  {
@@ -1554,7 +1554,7 @@ function FieldError({
1554
1554
  errors,
1555
1555
  ...props
1556
1556
  }) {
1557
- const content = React17.useMemo(() => {
1557
+ const content = React22.useMemo(() => {
1558
1558
  if (children) {
1559
1559
  return children;
1560
1560
  }
@@ -2408,8 +2408,8 @@ function CalendarDayButton({
2408
2408
  modifiers,
2409
2409
  ...props
2410
2410
  }) {
2411
- const ref = React17__namespace.useRef(null);
2412
- React17__namespace.useEffect(() => {
2411
+ const ref = React22__namespace.useRef(null);
2412
+ React22__namespace.useEffect(() => {
2413
2413
  if (modifiers.focused) ref.current?.focus();
2414
2414
  }, [modifiers.focused]);
2415
2415
  return /* @__PURE__ */ jsxRuntime.jsx(
@@ -2430,9 +2430,9 @@ function CalendarDayButton({
2430
2430
  }
2431
2431
  );
2432
2432
  }
2433
- var CarouselContext = React17__namespace.createContext(null);
2433
+ var CarouselContext = React22__namespace.createContext(null);
2434
2434
  function useCarousel() {
2435
- const context = React17__namespace.useContext(CarouselContext);
2435
+ const context = React22__namespace.useContext(CarouselContext);
2436
2436
  if (!context) {
2437
2437
  throw new Error("useCarousel must be used within a <Carousel />");
2438
2438
  }
@@ -2454,20 +2454,20 @@ function Carousel({
2454
2454
  },
2455
2455
  plugins
2456
2456
  );
2457
- const [canScrollPrev, setCanScrollPrev] = React17__namespace.useState(false);
2458
- const [canScrollNext, setCanScrollNext] = React17__namespace.useState(false);
2459
- const onSelect = React17__namespace.useCallback((api2) => {
2457
+ const [canScrollPrev, setCanScrollPrev] = React22__namespace.useState(false);
2458
+ const [canScrollNext, setCanScrollNext] = React22__namespace.useState(false);
2459
+ const onSelect = React22__namespace.useCallback((api2) => {
2460
2460
  if (!api2) return;
2461
2461
  setCanScrollPrev(api2.canScrollPrev());
2462
2462
  setCanScrollNext(api2.canScrollNext());
2463
2463
  }, []);
2464
- const scrollPrev = React17__namespace.useCallback(() => {
2464
+ const scrollPrev = React22__namespace.useCallback(() => {
2465
2465
  api?.scrollPrev();
2466
2466
  }, [api]);
2467
- const scrollNext = React17__namespace.useCallback(() => {
2467
+ const scrollNext = React22__namespace.useCallback(() => {
2468
2468
  api?.scrollNext();
2469
2469
  }, [api]);
2470
- const handleKeyDown = React17__namespace.useCallback(
2470
+ const handleKeyDown = React22__namespace.useCallback(
2471
2471
  (event) => {
2472
2472
  if (event.key === "ArrowLeft") {
2473
2473
  event.preventDefault();
@@ -2479,11 +2479,11 @@ function Carousel({
2479
2479
  },
2480
2480
  [scrollPrev, scrollNext]
2481
2481
  );
2482
- React17__namespace.useEffect(() => {
2482
+ React22__namespace.useEffect(() => {
2483
2483
  if (!api || !setApi) return;
2484
2484
  setApi(api);
2485
2485
  }, [api, setApi]);
2486
- React17__namespace.useEffect(() => {
2486
+ React22__namespace.useEffect(() => {
2487
2487
  if (!api) return;
2488
2488
  onSelect(api);
2489
2489
  api.on("reInit", onSelect);
@@ -2616,9 +2616,9 @@ function CarouselNext({
2616
2616
  );
2617
2617
  }
2618
2618
  var THEMES = { light: "", dark: ".dark" };
2619
- var ChartContext = React17__namespace.createContext(null);
2619
+ var ChartContext = React22__namespace.createContext(null);
2620
2620
  function useChart() {
2621
- const context = React17__namespace.useContext(ChartContext);
2621
+ const context = React22__namespace.useContext(ChartContext);
2622
2622
  if (!context) {
2623
2623
  throw new Error("useChart must be used within a <ChartContainer />");
2624
2624
  }
@@ -2631,7 +2631,7 @@ function ChartContainer({
2631
2631
  config,
2632
2632
  ...props
2633
2633
  }) {
2634
- const uniqueId = React17__namespace.useId();
2634
+ const uniqueId = React22__namespace.useId();
2635
2635
  const chartId = `chart-${id || uniqueId.replace(/:/g, "")}`;
2636
2636
  return /* @__PURE__ */ jsxRuntime.jsx(ChartContext.Provider, { value: { config }, children: /* @__PURE__ */ jsxRuntime.jsxs(
2637
2637
  "div",
@@ -2692,7 +2692,7 @@ function ChartTooltipContent({
2692
2692
  labelKey
2693
2693
  }) {
2694
2694
  const { config } = useChart();
2695
- const tooltipLabel = React17__namespace.useMemo(() => {
2695
+ const tooltipLabel = React22__namespace.useMemo(() => {
2696
2696
  if (hideLabel || !payload?.length) {
2697
2697
  return null;
2698
2698
  }
@@ -3348,6 +3348,105 @@ function Progress({
3348
3348
  }
3349
3349
  );
3350
3350
  }
3351
+ function CircularProgress({
3352
+ className,
3353
+ value,
3354
+ size = 80,
3355
+ strokeWidth = 8,
3356
+ variant = "default",
3357
+ showCheckmark = true,
3358
+ children,
3359
+ ...props
3360
+ }) {
3361
+ const clampedValue = Math.min(100, Math.max(0, value));
3362
+ const isComplete = clampedValue >= 100;
3363
+ const radius = (size - strokeWidth) / 2;
3364
+ const circumference = 2 * Math.PI * radius;
3365
+ const strokeDashoffset = circumference - clampedValue / 100 * circumference;
3366
+ const center = size / 2;
3367
+ const getVariantColors = () => {
3368
+ switch (variant) {
3369
+ case "success":
3370
+ return {
3371
+ track: "stroke-green-500/20",
3372
+ progress: "stroke-green-500",
3373
+ text: "text-green-600 dark:text-green-400"
3374
+ };
3375
+ case "warning":
3376
+ return {
3377
+ track: "stroke-amber-500/20",
3378
+ progress: "stroke-amber-500",
3379
+ text: "text-amber-600 dark:text-amber-400"
3380
+ };
3381
+ case "destructive":
3382
+ return {
3383
+ track: "stroke-red-500/20",
3384
+ progress: "stroke-red-500",
3385
+ text: "text-red-600 dark:text-red-400"
3386
+ };
3387
+ default:
3388
+ return {
3389
+ track: "stroke-primary/20",
3390
+ progress: "stroke-primary",
3391
+ text: "text-primary"
3392
+ };
3393
+ }
3394
+ };
3395
+ const colors = getVariantColors();
3396
+ return /* @__PURE__ */ jsxRuntime.jsxs(
3397
+ "div",
3398
+ {
3399
+ "data-slot": "circular-progress",
3400
+ "data-value": clampedValue,
3401
+ "data-complete": isComplete,
3402
+ className: cn("relative inline-flex items-center justify-center", className),
3403
+ style: { width: size, height: size },
3404
+ ...props,
3405
+ children: [
3406
+ /* @__PURE__ */ jsxRuntime.jsxs(
3407
+ "svg",
3408
+ {
3409
+ className: "transform -rotate-90",
3410
+ width: size,
3411
+ height: size,
3412
+ viewBox: `0 0 ${size} ${size}`,
3413
+ children: [
3414
+ /* @__PURE__ */ jsxRuntime.jsx(
3415
+ "circle",
3416
+ {
3417
+ className: cn("transition-all", colors.track),
3418
+ cx: center,
3419
+ cy: center,
3420
+ r: radius,
3421
+ fill: "none",
3422
+ strokeWidth
3423
+ }
3424
+ ),
3425
+ /* @__PURE__ */ jsxRuntime.jsx(
3426
+ "circle",
3427
+ {
3428
+ className: cn("transition-all duration-300 ease-out", colors.progress),
3429
+ cx: center,
3430
+ cy: center,
3431
+ r: radius,
3432
+ fill: "none",
3433
+ strokeWidth,
3434
+ strokeLinecap: "round",
3435
+ strokeDasharray: circumference,
3436
+ strokeDashoffset
3437
+ }
3438
+ )
3439
+ ]
3440
+ }
3441
+ ),
3442
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 flex items-center justify-center", children: children ? children : isComplete && showCheckmark ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: cn("h-6 w-6", colors.text) }) : /* @__PURE__ */ jsxRuntime.jsxs("span", { className: cn("text-sm font-semibold tabular-nums", colors.text), children: [
3443
+ Math.round(clampedValue),
3444
+ "%"
3445
+ ] }) })
3446
+ ]
3447
+ }
3448
+ );
3449
+ }
3351
3450
  function TooltipProvider({
3352
3451
  delayDuration = 0,
3353
3452
  ...props
@@ -3395,8 +3494,8 @@ function TooltipContent({
3395
3494
  ) });
3396
3495
  }
3397
3496
  function useDetectTheme() {
3398
- const [theme, setTheme] = React17__namespace.useState("light");
3399
- React17__namespace.useEffect(() => {
3497
+ const [theme, setTheme] = React22__namespace.useState("light");
3498
+ React22__namespace.useEffect(() => {
3400
3499
  const isDark = document.documentElement.classList.contains("dark");
3401
3500
  setTheme(isDark ? "dark" : "light");
3402
3501
  const observer = new MutationObserver((mutations) => {
@@ -4045,7 +4144,7 @@ function CommandShortcut({
4045
4144
  }
4046
4145
  );
4047
4146
  }
4048
- var SearchTrigger = React17__namespace.forwardRef(
4147
+ var SearchTrigger = React22__namespace.forwardRef(
4049
4148
  ({
4050
4149
  className,
4051
4150
  placeholder = "Search...",
@@ -4081,7 +4180,7 @@ var SearchTrigger = React17__namespace.forwardRef(
4081
4180
  );
4082
4181
  SearchTrigger.displayName = "SearchTrigger";
4083
4182
  function useSearchShortcut(onOpen, key = "k") {
4084
- React17__namespace.useEffect(() => {
4183
+ React22__namespace.useEffect(() => {
4085
4184
  const down = (e) => {
4086
4185
  if (e.key.toLowerCase() === key.toLowerCase() && (e.metaKey || e.ctrlKey)) {
4087
4186
  e.preventDefault();
@@ -5056,9 +5155,9 @@ var SIDEBAR_WIDTH = "16rem";
5056
5155
  var SIDEBAR_WIDTH_MOBILE = "18rem";
5057
5156
  var SIDEBAR_WIDTH_ICON = "3rem";
5058
5157
  var SIDEBAR_KEYBOARD_SHORTCUT = "b";
5059
- var SidebarContext = React17__namespace.createContext(null);
5158
+ var SidebarContext = React22__namespace.createContext(null);
5060
5159
  function useSidebar() {
5061
- const context = React17__namespace.useContext(SidebarContext);
5160
+ const context = React22__namespace.useContext(SidebarContext);
5062
5161
  if (!context) {
5063
5162
  throw new Error("useSidebar must be used within a SidebarProvider.");
5064
5163
  }
@@ -5074,10 +5173,10 @@ function SidebarProvider({
5074
5173
  ...props
5075
5174
  }) {
5076
5175
  const isMobile = useIsMobile();
5077
- const [openMobile, setOpenMobile] = React17__namespace.useState(false);
5078
- const [_open, _setOpen] = React17__namespace.useState(defaultOpen);
5176
+ const [openMobile, setOpenMobile] = React22__namespace.useState(false);
5177
+ const [_open, _setOpen] = React22__namespace.useState(defaultOpen);
5079
5178
  const open = openProp ?? _open;
5080
- const setOpen = React17__namespace.useCallback(
5179
+ const setOpen = React22__namespace.useCallback(
5081
5180
  (value) => {
5082
5181
  const openState = typeof value === "function" ? value(open) : value;
5083
5182
  if (setOpenProp) {
@@ -5089,10 +5188,10 @@ function SidebarProvider({
5089
5188
  },
5090
5189
  [setOpenProp, open]
5091
5190
  );
5092
- const toggleSidebar = React17__namespace.useCallback(() => {
5191
+ const toggleSidebar = React22__namespace.useCallback(() => {
5093
5192
  return isMobile ? setOpenMobile((open2) => !open2) : setOpen((open2) => !open2);
5094
5193
  }, [isMobile, setOpen, setOpenMobile]);
5095
- React17__namespace.useEffect(() => {
5194
+ React22__namespace.useEffect(() => {
5096
5195
  const handleKeyDown = (event) => {
5097
5196
  if (event.key === SIDEBAR_KEYBOARD_SHORTCUT && (event.metaKey || event.ctrlKey)) {
5098
5197
  event.preventDefault();
@@ -5103,7 +5202,7 @@ function SidebarProvider({
5103
5202
  return () => window.removeEventListener("keydown", handleKeyDown);
5104
5203
  }, [toggleSidebar]);
5105
5204
  const state = open ? "expanded" : "collapsed";
5106
- const contextValue = React17__namespace.useMemo(
5205
+ const contextValue = React22__namespace.useMemo(
5107
5206
  () => ({
5108
5207
  state,
5109
5208
  open,
@@ -5561,7 +5660,7 @@ function SidebarMenuSkeleton({
5561
5660
  showIcon = false,
5562
5661
  ...props
5563
5662
  }) {
5564
- const width = React17__namespace.useMemo(() => {
5663
+ const width = React22__namespace.useMemo(() => {
5565
5664
  return `${Math.floor(Math.random() * 40) + 50}%`;
5566
5665
  }, []);
5567
5666
  return /* @__PURE__ */ jsxRuntime.jsxs(
@@ -5704,7 +5803,7 @@ var sectionVariants = classVarianceAuthority.cva(
5704
5803
  }
5705
5804
  );
5706
5805
  var isGlassVariant = (variant) => variant?.startsWith("glass-") ?? false;
5707
- var Section = React17__namespace.forwardRef(
5806
+ var Section = React22__namespace.forwardRef(
5708
5807
  ({ className, variant, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
5709
5808
  "section",
5710
5809
  {
@@ -5716,7 +5815,7 @@ var Section = React17__namespace.forwardRef(
5716
5815
  )
5717
5816
  );
5718
5817
  Section.displayName = "Section";
5719
- var SectionHeader = React17__namespace.forwardRef(
5818
+ var SectionHeader = React22__namespace.forwardRef(
5720
5819
  ({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
5721
5820
  "div",
5722
5821
  {
@@ -5731,7 +5830,7 @@ var SectionHeader = React17__namespace.forwardRef(
5731
5830
  )
5732
5831
  );
5733
5832
  SectionHeader.displayName = "SectionHeader";
5734
- var SectionTitle = React17__namespace.forwardRef(
5833
+ var SectionTitle = React22__namespace.forwardRef(
5735
5834
  ({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
5736
5835
  "h2",
5737
5836
  {
@@ -5745,7 +5844,7 @@ var SectionTitle = React17__namespace.forwardRef(
5745
5844
  )
5746
5845
  );
5747
5846
  SectionTitle.displayName = "SectionTitle";
5748
- var SectionDescription = React17__namespace.forwardRef(
5847
+ var SectionDescription = React22__namespace.forwardRef(
5749
5848
  ({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
5750
5849
  "p",
5751
5850
  {
@@ -5759,7 +5858,7 @@ var SectionDescription = React17__namespace.forwardRef(
5759
5858
  )
5760
5859
  );
5761
5860
  SectionDescription.displayName = "SectionDescription";
5762
- var SectionContent = React17__namespace.forwardRef(
5861
+ var SectionContent = React22__namespace.forwardRef(
5763
5862
  ({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
5764
5863
  "div",
5765
5864
  {
@@ -5773,7 +5872,7 @@ var SectionContent = React17__namespace.forwardRef(
5773
5872
  )
5774
5873
  );
5775
5874
  SectionContent.displayName = "SectionContent";
5776
- var SectionFooter = React17__namespace.forwardRef(
5875
+ var SectionFooter = React22__namespace.forwardRef(
5777
5876
  ({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
5778
5877
  "div",
5779
5878
  {
@@ -5998,7 +6097,7 @@ function SiteHeader({
5998
6097
  children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex h-[var(--header-height,3.5rem)] w-full items-center gap-[var(--j3m-spacing-s)] px-[var(--j3m-spacing-m)]", children: [
5999
6098
  trigger,
6000
6099
  trigger && /* @__PURE__ */ jsxRuntime.jsx(Separator, { orientation: "vertical", className: "mr-[var(--j3m-spacing-s)] h-4" }),
6001
- /* @__PURE__ */ jsxRuntime.jsx(Breadcrumb, { className: "hidden sm:block", children: /* @__PURE__ */ jsxRuntime.jsx(BreadcrumbList, { children: breadcrumbs.map((item, index) => /* @__PURE__ */ jsxRuntime.jsxs(React17__namespace.Fragment, { children: [
6100
+ /* @__PURE__ */ jsxRuntime.jsx(Breadcrumb, { className: "hidden sm:block", children: /* @__PURE__ */ jsxRuntime.jsx(BreadcrumbList, { children: breadcrumbs.map((item, index) => /* @__PURE__ */ jsxRuntime.jsxs(React22__namespace.Fragment, { children: [
6002
6101
  index > 0 && /* @__PURE__ */ jsxRuntime.jsx(BreadcrumbSeparator, {}),
6003
6102
  /* @__PURE__ */ jsxRuntime.jsx(BreadcrumbItem, { children: item.href ? /* @__PURE__ */ jsxRuntime.jsx(BreadcrumbLink, { href: item.href, children: item.label }) : /* @__PURE__ */ jsxRuntime.jsx(BreadcrumbPage, { children: item.label }) })
6004
6103
  ] }, index)) }) }),
@@ -6186,46 +6285,44 @@ function PlanningTableToolbar({
6186
6285
  );
6187
6286
  }
6188
6287
  function getBadgeVariant(badgeType) {
6189
- const variantMap = {
6190
- Welded: "secondary",
6191
- Painted: "secondary",
6192
- Glazed: "secondary",
6193
- Delivered: "secondary",
6194
- Cured: "secondary",
6195
- Assembled: "secondary",
6196
- Tested: "secondary",
6197
- Sealed: "secondary"
6198
- };
6199
- return variantMap[badgeType] || "secondary";
6288
+ return "outline";
6200
6289
  }
6201
6290
  function SupplierCell({
6202
6291
  className,
6203
6292
  supplier,
6204
6293
  ...props
6205
6294
  }) {
6206
- return /* @__PURE__ */ jsxRuntime.jsxs(
6295
+ const spacingClasses = "px-[var(--j3m-spacing-xs)] pt-[var(--j3m-spacing-s)] pb-2";
6296
+ return /* @__PURE__ */ jsxRuntime.jsx(
6207
6297
  "div",
6208
6298
  {
6209
6299
  "data-slot": "supplier-cell",
6210
6300
  className: cn(
6211
- "flex flex-col justify-center gap-1 py-3 px-4 w-[200px] h-[72px]",
6301
+ // Same height as WeekCell (80px) for row alignment
6302
+ "flex flex-col justify-center gap-1.5 min-w-[200px] h-[80px]",
6303
+ // White background for Y-axis legend cells
6304
+ "bg-background",
6305
+ spacingClasses,
6212
6306
  className
6213
6307
  ),
6214
6308
  ...props,
6215
- children: [
6216
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-semibold leading-tight text-foreground", children: supplier.name }),
6217
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
6218
- /* @__PURE__ */ jsxRuntime.jsx(
6219
- Badge,
6220
- {
6221
- variant: getBadgeVariant(supplier.badgeType),
6222
- className: "text-[10px] px-1.5 py-0 h-5 font-normal",
6223
- children: supplier.badgeType
6224
- }
6225
- ),
6309
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-2", children: [
6310
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col min-w-0 flex-1", children: [
6311
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-bold leading-tight text-foreground truncate", children: supplier.name }),
6226
6312
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground", children: supplier.scope })
6227
- ] })
6228
- ]
6313
+ ] }),
6314
+ /* @__PURE__ */ jsxRuntime.jsxs(
6315
+ Badge,
6316
+ {
6317
+ variant: getBadgeVariant(supplier.badgeType),
6318
+ className: "text-[10px] px-2 py-0.5 h-[19px] font-medium shrink-0 gap-1 bg-background border-border",
6319
+ children: [
6320
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Flag, { className: "h-2.5 w-2.5" }),
6321
+ supplier.badgeType
6322
+ ]
6323
+ }
6324
+ )
6325
+ ] })
6229
6326
  }
6230
6327
  );
6231
6328
  }
@@ -6246,18 +6343,18 @@ function getRowStatus(status) {
6246
6343
  if (status === "delayed") return "warning";
6247
6344
  return "normal";
6248
6345
  }
6249
- var riskColorClasses = {
6346
+ var statusFillClasses = {
6250
6347
  normal: {
6251
- border: "border-l-green-500",
6252
- bg: "bg-green-50 dark:bg-green-950/50"
6348
+ border: "border-l-[3px] border-l-green-500",
6349
+ bg: "bg-green-50/50 dark:bg-green-950/30"
6253
6350
  },
6254
6351
  warning: {
6255
- border: "border-l-amber-500",
6256
- bg: "bg-amber-50 dark:bg-amber-950/50"
6352
+ border: "border-l-[3px] border-l-amber-500",
6353
+ bg: "bg-amber-50/50 dark:bg-amber-950/30"
6257
6354
  },
6258
6355
  critical: {
6259
- border: "border-l-red-500",
6260
- bg: "bg-red-50 dark:bg-red-950/50"
6356
+ border: "border-l-[3px] border-l-red-500",
6357
+ bg: "bg-red-50/50 dark:bg-red-950/30"
6261
6358
  }
6262
6359
  };
6263
6360
  var statusColors = {
@@ -6286,6 +6383,24 @@ function WeekCell({
6286
6383
  onCellClick,
6287
6384
  ...props
6288
6385
  }) {
6386
+ const combinedRisk = data.type === "data" ? getCombinedRiskLevel(data) : "normal";
6387
+ const statusClasses = statusFillClasses[combinedRisk];
6388
+ const productionProgress = data.production?.progress ?? data.progress ?? 0;
6389
+ const productionStatus = getRowStatus(data.production?.status);
6390
+ const productionColors = statusColors[productionStatus];
6391
+ const deliveryCount = data.deliveries?.length ?? 0;
6392
+ const worstDeliveryStatus = data.deliveries?.some((d) => d.status === "critical") ? "critical" : data.deliveries?.some((d) => d.status === "delayed") ? "warning" : "normal";
6393
+ const deliveryColors = statusColors[worstDeliveryStatus];
6394
+ const getDeliveryStatusColor = (status) => {
6395
+ switch (status) {
6396
+ case "critical":
6397
+ return "bg-red-500";
6398
+ case "delayed":
6399
+ return "bg-amber-500";
6400
+ default:
6401
+ return "bg-green-500";
6402
+ }
6403
+ };
6289
6404
  const handleClick = () => {
6290
6405
  if (onCellClick && data.type !== "empty") {
6291
6406
  onCellClick();
@@ -6297,14 +6412,7 @@ function WeekCell({
6297
6412
  onCellClick();
6298
6413
  }
6299
6414
  };
6300
- const combinedRisk = data.type === "data" ? getCombinedRiskLevel(data) : "normal";
6301
- const cardColors = riskColorClasses[combinedRisk];
6302
- const productionProgress = data.production?.progress ?? data.progress ?? 0;
6303
- const productionStatus = getRowStatus(data.production?.status);
6304
- const productionColors = statusColors[productionStatus];
6305
- const deliveryCount = data.deliveries?.length ?? 0;
6306
- const worstDeliveryStatus = data.deliveries?.some((d) => d.status === "critical") ? "critical" : data.deliveries?.some((d) => d.status === "delayed") ? "warning" : "normal";
6307
- const deliveryColors = statusColors[worstDeliveryStatus];
6415
+ const spacingClasses = "px-[var(--j3m-spacing-xs)] pt-[var(--j3m-spacing-s)] pb-2";
6308
6416
  if (data.type === "empty") {
6309
6417
  return /* @__PURE__ */ jsxRuntime.jsx(
6310
6418
  "div",
@@ -6313,8 +6421,9 @@ function WeekCell({
6313
6421
  "data-state": "empty",
6314
6422
  "data-current-week": isCurrentWeek,
6315
6423
  className: cn(
6316
- "flex w-[120px] h-[72px] items-center justify-center cursor-default",
6317
- isCurrentWeek && "bg-primary/5",
6424
+ "flex h-[80px] items-center justify-center cursor-default",
6425
+ "bg-background",
6426
+ spacingClasses,
6318
6427
  className
6319
6428
  ),
6320
6429
  ...props,
@@ -6323,7 +6432,7 @@ function WeekCell({
6323
6432
  );
6324
6433
  }
6325
6434
  if (data.type === "no-logistics") {
6326
- return /* @__PURE__ */ jsxRuntime.jsx(
6435
+ return /* @__PURE__ */ jsxRuntime.jsxs(
6327
6436
  "div",
6328
6437
  {
6329
6438
  "data-slot": "week-cell",
@@ -6334,44 +6443,36 @@ function WeekCell({
6334
6443
  role: "button",
6335
6444
  tabIndex: 0,
6336
6445
  className: cn(
6337
- "flex flex-col w-[120px] h-[72px] justify-center p-1",
6338
- "cursor-pointer",
6339
- isCurrentWeek && "bg-primary/5",
6446
+ "flex flex-col h-[80px] justify-center gap-2",
6447
+ "cursor-pointer bg-background",
6448
+ "border-l-[3px] border-l-muted-foreground/30",
6449
+ spacingClasses,
6450
+ // Hover lift effect
6451
+ "transition-all duration-200 ease-out",
6452
+ "hover:-translate-y-0.5 hover:shadow-[var(--j3m-shadow-md)]",
6340
6453
  className
6341
6454
  ),
6342
6455
  ...props,
6343
- children: /* @__PURE__ */ jsxRuntime.jsxs(
6344
- "div",
6345
- {
6346
- className: cn(
6347
- "flex flex-col w-full h-full justify-center gap-1.5 rounded-md border-l-[3px] px-2 py-1.5",
6348
- "border-l-muted-foreground/30 bg-muted/50",
6349
- // Hover lift effect with shadow
6350
- "transition-all duration-200 ease-out",
6351
- "hover:-translate-y-0.5 hover:shadow-md hover:bg-muted/70"
6352
- ),
6353
- children: [
6354
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
6355
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Factory, { className: "h-3.5 w-3.5 shrink-0 text-muted-foreground" }),
6356
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 h-1.5 bg-muted-foreground/20 rounded-full overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx(
6357
- "div",
6358
- {
6359
- className: "h-full bg-muted-foreground/40 rounded-full",
6360
- style: { width: `${productionProgress}%` }
6361
- }
6362
- ) })
6363
- ] }),
6364
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5 text-muted-foreground", children: [
6365
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Truck, { className: "h-3.5 w-3.5 shrink-0" }),
6366
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px]", children: "No logistics" })
6367
- ] })
6368
- ]
6369
- }
6370
- )
6456
+ children: [
6457
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
6458
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Factory, { className: "h-3.5 w-3.5 shrink-0 text-muted-foreground" }),
6459
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 h-1.5 bg-muted-foreground/20 rounded-full overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx(
6460
+ "div",
6461
+ {
6462
+ className: "h-full bg-muted-foreground/40 rounded-full",
6463
+ style: { width: `${productionProgress}%` }
6464
+ }
6465
+ ) })
6466
+ ] }),
6467
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-muted-foreground", children: [
6468
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Truck, { className: "h-3.5 w-3.5 shrink-0" }),
6469
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px]", children: "No logistics" })
6470
+ ] })
6471
+ ]
6371
6472
  }
6372
6473
  );
6373
6474
  }
6374
- return /* @__PURE__ */ jsxRuntime.jsx(
6475
+ return /* @__PURE__ */ jsxRuntime.jsxs(
6375
6476
  "div",
6376
6477
  {
6377
6478
  "data-slot": "week-cell",
@@ -6383,80 +6484,150 @@ function WeekCell({
6383
6484
  role: "button",
6384
6485
  tabIndex: 0,
6385
6486
  className: cn(
6386
- "flex flex-col w-[120px] h-[72px] justify-center p-1",
6487
+ "flex flex-col h-[80px] justify-center gap-2",
6387
6488
  "cursor-pointer",
6388
- isCurrentWeek && "bg-primary/5",
6489
+ // Edge-to-edge status fill (no inset card)
6490
+ statusClasses.border,
6491
+ statusClasses.bg,
6492
+ spacingClasses,
6493
+ // Hover lift effect
6494
+ "transition-all duration-200 ease-out",
6495
+ "hover:-translate-y-0.5 hover:shadow-[var(--j3m-shadow-md)]",
6389
6496
  className
6390
6497
  ),
6391
6498
  ...props,
6392
- children: /* @__PURE__ */ jsxRuntime.jsxs(
6393
- "div",
6394
- {
6395
- className: cn(
6396
- "flex flex-col w-full h-full justify-center gap-1.5 rounded-md border-l-[3px] px-2 py-1.5",
6397
- cardColors.border,
6398
- cardColors.bg,
6399
- // Hover lift effect with shadow
6400
- "transition-all duration-200 ease-out",
6401
- "hover:-translate-y-0.5 hover:shadow-md"
6402
- ),
6403
- children: [
6404
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
6405
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Factory, { className: cn("h-3.5 w-3.5 shrink-0", productionColors.icon) }),
6406
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 h-1.5 bg-black/10 dark:bg-white/10 rounded-full overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx(
6407
- "div",
6408
- {
6409
- className: cn("h-full rounded-full transition-all", productionColors.progress),
6410
- style: { width: `${productionProgress}%` }
6411
- }
6412
- ) })
6413
- ] }),
6414
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
6415
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Truck, { className: cn("h-3.5 w-3.5 shrink-0", deliveryColors.icon) }),
6416
- deliveryCount > 0 ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: cn("text-[10px] font-medium", deliveryColors.text), children: [
6417
- deliveryCount,
6418
- "x delivery"
6419
- ] }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] text-muted-foreground", children: "\u2014" })
6420
- ] })
6421
- ]
6422
- }
6423
- )
6499
+ children: [
6500
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
6501
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Factory, { className: cn("h-3.5 w-3.5 shrink-0", productionColors.icon) }),
6502
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 h-1.5 bg-black/10 dark:bg-white/10 rounded-full overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx(
6503
+ "div",
6504
+ {
6505
+ className: cn("h-full rounded-full transition-all", productionColors.progress),
6506
+ style: { width: `${productionProgress}%` }
6507
+ }
6508
+ ) })
6509
+ ] }),
6510
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
6511
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Truck, { className: cn("h-3.5 w-3.5 shrink-0", deliveryColors.icon) }),
6512
+ deliveryCount > 0 ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: cn("text-[10px] font-medium", deliveryColors.text), children: [
6513
+ deliveryCount,
6514
+ "x delivery"
6515
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] text-muted-foreground", children: "\u2014" })
6516
+ ] }),
6517
+ deliveryCount > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1", children: [
6518
+ data.deliveries?.slice(0, 5).map((delivery, index) => {
6519
+ const deliveryProgress = delivery.progress ?? (delivery.status === "on-time" ? 100 : delivery.status === "delayed" ? 50 : 25);
6520
+ return /* @__PURE__ */ jsxRuntime.jsx(
6521
+ "div",
6522
+ {
6523
+ className: "flex-1 max-w-[24px]",
6524
+ title: delivery.label || `Delivery ${index + 1}`,
6525
+ children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-1 bg-black/10 dark:bg-white/10 rounded-full overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx(
6526
+ "div",
6527
+ {
6528
+ className: cn("h-full rounded-full transition-all", getDeliveryStatusColor(delivery.status)),
6529
+ style: { width: `${deliveryProgress}%` }
6530
+ }
6531
+ ) })
6532
+ },
6533
+ delivery.id || index
6534
+ );
6535
+ }),
6536
+ deliveryCount > 5 && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-[8px] text-muted-foreground", children: [
6537
+ "+",
6538
+ deliveryCount - 5
6539
+ ] })
6540
+ ] })
6541
+ ]
6424
6542
  }
6425
6543
  );
6426
6544
  }
6427
- function WeekHeader({
6545
+ function CommentButton({
6428
6546
  className,
6429
- week,
6547
+ commentCount = 0,
6548
+ size = "default",
6430
6549
  ...props
6431
6550
  }) {
6551
+ const hasComments = commentCount > 0;
6552
+ const sizeClasses = size === "sm" ? "h-6 w-6" : "h-7 w-7";
6553
+ const iconSize = size === "sm" ? "h-3.5 w-3.5" : "h-4 w-4";
6432
6554
  return /* @__PURE__ */ jsxRuntime.jsxs(
6433
- "div",
6555
+ Button,
6434
6556
  {
6435
- "data-slot": "week-header",
6436
- "data-current-week": week.isCurrentWeek,
6557
+ variant: "outline",
6558
+ size: "icon",
6437
6559
  className: cn(
6438
- "flex flex-col justify-center gap-0.5 w-[120px] text-left",
6560
+ sizeClasses,
6561
+ "rounded-full shrink-0 relative",
6562
+ "border-border bg-background hover:bg-muted",
6563
+ "shadow-[var(--j3m-shadow-sm)]",
6564
+ hasComments && "border-primary/50",
6439
6565
  className
6440
6566
  ),
6441
6567
  ...props,
6442
6568
  children: [
6443
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
6444
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn(
6445
- "text-sm font-medium",
6446
- week.isCurrentWeek ? "text-primary" : "text-foreground"
6447
- ), children: week.label }),
6448
- week.isCurrentWeek && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "relative flex h-2 w-2", children: [
6449
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "animate-ping absolute inline-flex h-full w-full rounded-full bg-primary opacity-75" }),
6450
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "relative inline-flex rounded-full h-2 w-2 bg-primary" })
6451
- ] })
6452
- ] }),
6453
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[11px] text-muted-foreground whitespace-nowrap", children: week.dateRange })
6569
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MessageSquare, { className: cn(iconSize, hasComments && "text-primary") }),
6570
+ hasComments && /* @__PURE__ */ jsxRuntime.jsx(
6571
+ "span",
6572
+ {
6573
+ className: cn(
6574
+ "absolute -top-0.5 -right-0.5",
6575
+ "h-2.5 w-2.5 rounded-full",
6576
+ "bg-primary",
6577
+ "border border-background"
6578
+ // Subtle outline for contrast
6579
+ ),
6580
+ "aria-hidden": "true"
6581
+ }
6582
+ ),
6583
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: hasComments ? `${commentCount} comment${commentCount > 1 ? "s" : ""}` : "Add comment" })
6454
6584
  ]
6455
6585
  }
6456
6586
  );
6457
6587
  }
6458
6588
 
6459
6589
  // src/blocks/planning-table/types.ts
6590
+ function getCommentLocationLabel(location) {
6591
+ if (location.type === "production") {
6592
+ return location.supplierName ? `Production - ${location.supplierName}` : "Production";
6593
+ }
6594
+ if (location.type === "delivery") {
6595
+ return location.deliveryLabel || `Delivery ${location.deliveryId || ""}`;
6596
+ }
6597
+ return "Unknown";
6598
+ }
6599
+ function getElementShipmentStatus(element, currentDeliveryId) {
6600
+ if (element.shipmentStatus) {
6601
+ return element.shipmentStatus;
6602
+ }
6603
+ if (element.isProduced) {
6604
+ if (element.actualDeliveryId && element.actualDeliveryId !== currentDeliveryId) {
6605
+ return "moved";
6606
+ }
6607
+ return "sent";
6608
+ }
6609
+ if (element.originalDeliveryId && element.originalDeliveryId !== currentDeliveryId) {
6610
+ return "addon";
6611
+ }
6612
+ return "not-sent";
6613
+ }
6614
+ function getShipmentStatusLabel(status) {
6615
+ switch (status) {
6616
+ case "sent":
6617
+ return "Sent";
6618
+ case "not-sent":
6619
+ return "Missing";
6620
+ // Neutral tone, not "Not sent"
6621
+ case "moved":
6622
+ return "Moved to another delivery";
6623
+ case "addon":
6624
+ return "Add-on";
6625
+ case "planned":
6626
+ return "Planned";
6627
+ default:
6628
+ return status;
6629
+ }
6630
+ }
6460
6631
  function getWeekKey(date) {
6461
6632
  const year = date.getFullYear();
6462
6633
  const weekNumber = getISOWeek(date);
@@ -6517,18 +6688,325 @@ function formatProductionUnit(unit) {
6517
6688
  };
6518
6689
  return unitLabels[unit] || unit;
6519
6690
  }
6520
- function SupplierColumnHeader({
6521
- column
6691
+ function LocationIcon({ type }) {
6692
+ if (type === "production") {
6693
+ return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Factory, { className: "h-3 w-3" });
6694
+ }
6695
+ return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Truck, { className: "h-3 w-3" });
6696
+ }
6697
+ function PlanningWeekCommentPopover({
6698
+ comments,
6699
+ weekLabel,
6700
+ weekKey,
6701
+ locationOptions,
6702
+ onAddComment,
6703
+ onCommentClick,
6704
+ open,
6705
+ onOpenChange
6706
+ }) {
6707
+ const [newCommentText, setNewCommentText] = React22__namespace.useState("");
6708
+ const [selectedLocationId, setSelectedLocationId] = React22__namespace.useState("");
6709
+ const [viewCommentsOpen, setViewCommentsOpen] = React22__namespace.useState(true);
6710
+ const [showAddForm, setShowAddForm] = React22__namespace.useState(false);
6711
+ const selectedLocation = React22__namespace.useMemo(() => {
6712
+ return locationOptions.find((opt) => opt.id === selectedLocationId);
6713
+ }, [locationOptions, selectedLocationId]);
6714
+ const handleSubmit = () => {
6715
+ if (newCommentText.trim() && selectedLocation && onAddComment) {
6716
+ const location = {
6717
+ type: selectedLocation.type,
6718
+ weekKey,
6719
+ supplierId: selectedLocation.supplierId,
6720
+ supplierName: selectedLocation.supplierName,
6721
+ deliveryId: selectedLocation.deliveryId,
6722
+ deliveryLabel: selectedLocation.deliveryLabel
6723
+ };
6724
+ onAddComment(newCommentText.trim(), location);
6725
+ setNewCommentText("");
6726
+ setSelectedLocationId("");
6727
+ setShowAddForm(false);
6728
+ setViewCommentsOpen(true);
6729
+ }
6730
+ };
6731
+ const handleKeyDown = (e) => {
6732
+ if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) {
6733
+ e.preventDefault();
6734
+ handleSubmit();
6735
+ }
6736
+ if (e.key === "Escape") {
6737
+ setShowAddForm(false);
6738
+ setSelectedLocationId("");
6739
+ setNewCommentText("");
6740
+ }
6741
+ };
6742
+ const handleCommentClick = (comment) => {
6743
+ if (comment.location && onCommentClick) {
6744
+ onCommentClick(comment);
6745
+ }
6746
+ };
6747
+ const formatDate2 = (date) => {
6748
+ return new Intl.DateTimeFormat("en-US", {
6749
+ month: "short",
6750
+ day: "numeric",
6751
+ hour: "numeric",
6752
+ minute: "2-digit"
6753
+ }).format(date);
6754
+ };
6755
+ const prevOpenRef = React22__namespace.useRef(open);
6756
+ React22__namespace.useEffect(() => {
6757
+ const wasOpen = prevOpenRef.current;
6758
+ prevOpenRef.current = open;
6759
+ if (wasOpen && !open) {
6760
+ setShowAddForm(false);
6761
+ setNewCommentText("");
6762
+ setSelectedLocationId("");
6763
+ }
6764
+ }, [open]);
6765
+ return /* @__PURE__ */ jsxRuntime.jsxs(Popover, { open, onOpenChange, children: [
6766
+ /* @__PURE__ */ jsxRuntime.jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(CommentButton, { size: "sm", commentCount: comments.length }) }),
6767
+ /* @__PURE__ */ jsxRuntime.jsxs(
6768
+ PopoverContent,
6769
+ {
6770
+ className: "w-80 p-0 z-[100]",
6771
+ align: "end",
6772
+ sideOffset: 8,
6773
+ collisionPadding: 16,
6774
+ children: [
6775
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-4 py-3 border-b border-border", children: [
6776
+ /* @__PURE__ */ jsxRuntime.jsx("h4", { className: "text-sm font-semibold", children: "Comments" }),
6777
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: weekLabel })
6778
+ ] }),
6779
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-2 space-y-2 max-h-[400px] overflow-y-auto", children: [
6780
+ /* @__PURE__ */ jsxRuntime.jsxs(Collapsible, { open: viewCommentsOpen, onOpenChange: setViewCommentsOpen, children: [
6781
+ /* @__PURE__ */ jsxRuntime.jsx(CollapsibleTrigger2, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(Button, { variant: "ghost", size: "sm", className: "w-full justify-between h-8 px-2", children: [
6782
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs font-medium", children: [
6783
+ "Comments ",
6784
+ comments.length > 0 && `(${comments.length})`
6785
+ ] }),
6786
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { className: cn(
6787
+ "h-4 w-4 transition-transform duration-200",
6788
+ viewCommentsOpen && "rotate-180"
6789
+ ) })
6790
+ ] }) }),
6791
+ /* @__PURE__ */ jsxRuntime.jsx(CollapsibleContent2, { className: "space-y-2 pt-2", children: comments.length > 0 ? comments.map((comment) => {
6792
+ const hasLocation = !!comment.location;
6793
+ const locationLabel = comment.location ? getCommentLocationLabel(comment.location) : null;
6794
+ return /* @__PURE__ */ jsxRuntime.jsxs(
6795
+ "div",
6796
+ {
6797
+ className: cn(
6798
+ "rounded-lg bg-muted/50 p-3 space-y-2",
6799
+ hasLocation && "cursor-pointer hover:bg-muted/70 transition-colors"
6800
+ ),
6801
+ onClick: () => handleCommentClick(comment),
6802
+ role: hasLocation ? "button" : void 0,
6803
+ tabIndex: hasLocation ? 0 : void 0,
6804
+ onKeyDown: hasLocation ? (e) => {
6805
+ if (e.key === "Enter" || e.key === " ") {
6806
+ e.preventDefault();
6807
+ handleCommentClick(comment);
6808
+ }
6809
+ } : void 0,
6810
+ children: [
6811
+ locationLabel && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
6812
+ /* @__PURE__ */ jsxRuntime.jsxs(
6813
+ Badge,
6814
+ {
6815
+ variant: "outline",
6816
+ className: "text-[10px] px-2 py-0 h-5 font-medium bg-background gap-1",
6817
+ children: [
6818
+ /* @__PURE__ */ jsxRuntime.jsx(LocationIcon, { type: comment.location.type }),
6819
+ locationLabel
6820
+ ]
6821
+ }
6822
+ ),
6823
+ hasLocation && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { className: "h-3 w-3 text-muted-foreground" })
6824
+ ] }),
6825
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
6826
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium", children: comment.author }),
6827
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] text-muted-foreground", children: formatDate2(comment.createdAt) })
6828
+ ] }),
6829
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-foreground", children: comment.text })
6830
+ ]
6831
+ },
6832
+ comment.id
6833
+ );
6834
+ }) : /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground text-center py-2", children: "No comments yet" }) })
6835
+ ] }),
6836
+ /* @__PURE__ */ jsxRuntime.jsx(Separator, { className: "my-2" }),
6837
+ !showAddForm ? /* @__PURE__ */ jsxRuntime.jsxs(
6838
+ Button,
6839
+ {
6840
+ variant: "outline",
6841
+ size: "sm",
6842
+ className: "w-full justify-center gap-2 h-8",
6843
+ onClick: () => setShowAddForm(true),
6844
+ disabled: locationOptions.length === 0,
6845
+ children: [
6846
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, { className: "h-3.5 w-3.5" }),
6847
+ locationOptions.length === 0 ? "No suppliers available" : "Add comment"
6848
+ ]
6849
+ }
6850
+ ) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn(
6851
+ "space-y-3 p-3 rounded-lg border border-border bg-muted/30",
6852
+ "animate-in fade-in-0 slide-in-from-top-2 duration-200"
6853
+ ), children: [
6854
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1.5", children: [
6855
+ /* @__PURE__ */ jsxRuntime.jsxs(Label2, { htmlFor: "supplier-prefix-select", className: "text-xs font-medium", children: [
6856
+ "Supplier / Prefix ",
6857
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-destructive", children: "*" })
6858
+ ] }),
6859
+ /* @__PURE__ */ jsxRuntime.jsxs(Select, { value: selectedLocationId, onValueChange: setSelectedLocationId, children: [
6860
+ /* @__PURE__ */ jsxRuntime.jsx(SelectTrigger, { id: "supplier-prefix-select", size: "sm", className: "w-full", children: /* @__PURE__ */ jsxRuntime.jsx(SelectValue, { placeholder: "Select supplier / prefix..." }) }),
6861
+ /* @__PURE__ */ jsxRuntime.jsx(SelectContent, { children: locationOptions.map((option) => /* @__PURE__ */ jsxRuntime.jsx(SelectItem, { value: option.id, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
6862
+ /* @__PURE__ */ jsxRuntime.jsx(LocationIcon, { type: option.type }),
6863
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: option.label })
6864
+ ] }) }, option.id)) })
6865
+ ] })
6866
+ ] }),
6867
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1.5", children: [
6868
+ /* @__PURE__ */ jsxRuntime.jsx(Label2, { htmlFor: "comment-text", className: "text-xs font-medium", children: "Comment" }),
6869
+ /* @__PURE__ */ jsxRuntime.jsx(
6870
+ Textarea,
6871
+ {
6872
+ id: "comment-text",
6873
+ placeholder: "Type your comment...",
6874
+ value: newCommentText,
6875
+ onChange: (e) => setNewCommentText(e.target.value),
6876
+ onKeyDown: handleKeyDown,
6877
+ className: "min-h-[80px] text-sm resize-none",
6878
+ autoFocus: true
6879
+ }
6880
+ )
6881
+ ] }),
6882
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
6883
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] text-muted-foreground", children: "\u2318+Enter to send \xB7 Esc to cancel" }),
6884
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
6885
+ /* @__PURE__ */ jsxRuntime.jsx(
6886
+ Button,
6887
+ {
6888
+ variant: "ghost",
6889
+ size: "sm",
6890
+ className: "h-7",
6891
+ onClick: () => {
6892
+ setShowAddForm(false);
6893
+ setNewCommentText("");
6894
+ setSelectedLocationId("");
6895
+ },
6896
+ children: "Cancel"
6897
+ }
6898
+ ),
6899
+ /* @__PURE__ */ jsxRuntime.jsxs(
6900
+ Button,
6901
+ {
6902
+ size: "sm",
6903
+ className: "h-7 gap-1",
6904
+ onClick: handleSubmit,
6905
+ disabled: !newCommentText.trim() || !selectedLocationId,
6906
+ children: [
6907
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Send, { className: "h-3 w-3" }),
6908
+ "Save"
6909
+ ]
6910
+ }
6911
+ )
6912
+ ] })
6913
+ ] })
6914
+ ] })
6915
+ ] })
6916
+ ]
6917
+ }
6918
+ )
6919
+ ] });
6920
+ }
6921
+ function generateLocationOptions(suppliers, weekKey) {
6922
+ const options = [];
6923
+ for (const supplier of suppliers) {
6924
+ const weekData = supplier.weeks[weekKey];
6925
+ options.push({
6926
+ id: `${supplier.id}-production`,
6927
+ label: `${supplier.name} - Production`,
6928
+ type: "production",
6929
+ supplierId: supplier.id,
6930
+ supplierName: supplier.name
6931
+ });
6932
+ if (weekData?.deliveries) {
6933
+ for (const delivery of weekData.deliveries) {
6934
+ options.push({
6935
+ id: `${supplier.id}-delivery-${delivery.id}`,
6936
+ label: `${supplier.name} - ${delivery.label || `Delivery ${delivery.id}`}`,
6937
+ type: "delivery",
6938
+ supplierId: supplier.id,
6939
+ supplierName: supplier.name,
6940
+ deliveryId: delivery.id,
6941
+ deliveryLabel: delivery.label || `Delivery ${delivery.id}`
6942
+ });
6943
+ }
6944
+ }
6945
+ }
6946
+ return options;
6947
+ }
6948
+ function WeekHeader({
6949
+ className,
6950
+ week,
6951
+ weekKey,
6952
+ comments = [],
6953
+ showCommentButton = true,
6954
+ locationOptions = [],
6955
+ onAddComment,
6956
+ onCommentClick,
6957
+ ...props
6522
6958
  }) {
6523
6959
  return /* @__PURE__ */ jsxRuntime.jsxs(
6524
- Button,
6960
+ "div",
6525
6961
  {
6526
- variant: "ghost",
6527
- size: "sm",
6528
- className: "-ml-3 h-8 data-[state=open]:bg-accent",
6529
- onClick: () => column.toggleSorting(column.getIsSorted() === "asc"),
6530
- children: [
6531
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: "Supplier / Scope" }),
6962
+ "data-slot": "week-header",
6963
+ "data-current-week": week.isCurrentWeek,
6964
+ className: cn(
6965
+ "flex items-center justify-between gap-2 min-w-[140px] text-left",
6966
+ className
6967
+ ),
6968
+ ...props,
6969
+ children: [
6970
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-0.5", children: [
6971
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
6972
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn(
6973
+ "text-sm font-semibold tracking-tight",
6974
+ week.isCurrentWeek ? "text-primary" : "text-foreground"
6975
+ ), children: week.label }),
6976
+ week.isCurrentWeek && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "relative flex h-2 w-2", children: [
6977
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "animate-ping absolute inline-flex h-full w-full rounded-full bg-primary opacity-75" }),
6978
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "relative inline-flex rounded-full h-2 w-2 bg-primary" })
6979
+ ] })
6980
+ ] }),
6981
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] font-normal text-muted-foreground/60 whitespace-nowrap", children: week.dateRange })
6982
+ ] }),
6983
+ showCommentButton && weekKey && /* @__PURE__ */ jsxRuntime.jsx(
6984
+ PlanningWeekCommentPopover,
6985
+ {
6986
+ comments,
6987
+ weekLabel: week.label,
6988
+ weekKey,
6989
+ locationOptions,
6990
+ onAddComment,
6991
+ onCommentClick
6992
+ }
6993
+ )
6994
+ ]
6995
+ }
6996
+ );
6997
+ }
6998
+ function SupplierColumnHeader({
6999
+ column
7000
+ }) {
7001
+ return /* @__PURE__ */ jsxRuntime.jsxs(
7002
+ Button,
7003
+ {
7004
+ variant: "ghost",
7005
+ size: "sm",
7006
+ className: "-ml-3 h-8 data-[state=open]:bg-accent",
7007
+ onClick: () => column.toggleSorting(column.getIsSorted() === "asc"),
7008
+ children: [
7009
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: "Supplier / Scope" }),
6532
7010
  /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowUpDown, { className: "ml-2 h-4 w-4" })
6533
7011
  ]
6534
7012
  }
@@ -6544,13 +7022,50 @@ function getSupplierColumn() {
6544
7022
  enableHiding: false
6545
7023
  };
6546
7024
  }
6547
- function generateWeekColumns(weeks, config) {
7025
+ function WeekHeaderWithComments({
7026
+ week,
7027
+ weekKey,
7028
+ config,
7029
+ suppliers
7030
+ }) {
7031
+ const weekComments = config?.weekComments?.[weekKey] ?? [];
7032
+ let filteredSuppliers = suppliers;
7033
+ if (config?.userRole === "supplier" && config?.currentSupplierId) {
7034
+ filteredSuppliers = suppliers.filter((s) => s.id === config.currentSupplierId);
7035
+ }
7036
+ const locationOptions = generateLocationOptions(filteredSuppliers, weekKey);
7037
+ const handleAddComment = config?.onAddWeekComment ? (text, location) => {
7038
+ config.onAddWeekComment?.(weekKey, text, location);
7039
+ } : void 0;
7040
+ const handleCommentClick = config?.onCommentClick;
7041
+ return /* @__PURE__ */ jsxRuntime.jsx(
7042
+ WeekHeader,
7043
+ {
7044
+ week,
7045
+ weekKey,
7046
+ comments: weekComments,
7047
+ showCommentButton: true,
7048
+ locationOptions,
7049
+ onAddComment: handleAddComment,
7050
+ onCommentClick: handleCommentClick
7051
+ }
7052
+ );
7053
+ }
7054
+ function generateWeekColumns(weeks, config, suppliers) {
6548
7055
  return weeks.map((week) => {
6549
7056
  const weekKey = getWeekKey(week.startDate);
6550
7057
  return {
6551
7058
  id: weekKey,
6552
7059
  accessorFn: (supplier) => supplier.weeks[weekKey],
6553
- header: () => /* @__PURE__ */ jsxRuntime.jsx(WeekHeader, { week }),
7060
+ header: () => /* @__PURE__ */ jsxRuntime.jsx(
7061
+ WeekHeaderWithComments,
7062
+ {
7063
+ week,
7064
+ weekKey,
7065
+ config,
7066
+ suppliers: suppliers ?? []
7067
+ }
7068
+ ),
6554
7069
  cell: ({ row }) => {
6555
7070
  const supplier = row.original;
6556
7071
  const data = supplier.weeks[weekKey] || { type: "empty" };
@@ -6570,10 +7085,10 @@ function generateWeekColumns(weeks, config) {
6570
7085
  };
6571
7086
  });
6572
7087
  }
6573
- function generateColumns(weeks, config) {
7088
+ function generateColumns(weeks, config, suppliers) {
6574
7089
  return [
6575
7090
  getSupplierColumn(),
6576
- ...generateWeekColumns(weeks, config)
7091
+ ...generateWeekColumns(weeks, config, suppliers)
6577
7092
  ];
6578
7093
  }
6579
7094
  function PlanningTable({
@@ -6592,22 +7107,22 @@ function PlanningTable({
6592
7107
  stickySupplierColumn = true,
6593
7108
  maxHeight = "600px"
6594
7109
  } = config;
6595
- const weeks = React17__namespace.useMemo(
7110
+ const weeks = React22__namespace.useMemo(
6596
7111
  () => generateWeeks(startDate, weekCount),
6597
7112
  [startDate, weekCount]
6598
7113
  );
6599
- const currentWeekKey = React17__namespace.useMemo(() => {
7114
+ const currentWeekKey = React22__namespace.useMemo(() => {
6600
7115
  const currentWeek = weeks.find((w) => w.isCurrentWeek);
6601
7116
  return currentWeek ? getWeekKey(currentWeek.startDate) : null;
6602
7117
  }, [weeks]);
6603
- const columns = React17__namespace.useMemo(
6604
- () => generateColumns(weeks, config),
6605
- [weeks, config]
6606
- );
6607
- const [sorting, setSorting] = React17__namespace.useState([]);
6608
- const [columnFilters, setColumnFilters] = React17__namespace.useState([]);
6609
- const [columnVisibility, setColumnVisibility] = React17__namespace.useState({});
6610
- const [rowSelection, setRowSelection] = React17__namespace.useState({});
7118
+ const columns = React22__namespace.useMemo(
7119
+ () => generateColumns(weeks, config, suppliers),
7120
+ [weeks, config, suppliers]
7121
+ );
7122
+ const [sorting, setSorting] = React22__namespace.useState([]);
7123
+ const [columnFilters, setColumnFilters] = React22__namespace.useState([]);
7124
+ const [columnVisibility, setColumnVisibility] = React22__namespace.useState({});
7125
+ const [rowSelection, setRowSelection] = React22__namespace.useState({});
6611
7126
  const table = reactTable.useReactTable({
6612
7127
  data: suppliers,
6613
7128
  columns,
@@ -6638,29 +7153,32 @@ function PlanningTable({
6638
7153
  className: cn("flex flex-col gap-4", className),
6639
7154
  children: [
6640
7155
  showToolbar && /* @__PURE__ */ jsxRuntime.jsx(PlanningTableToolbar, { table }),
6641
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-lg border bg-card shadow-md", children: /* @__PURE__ */ jsxRuntime.jsxs(
7156
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-xl border bg-background shadow-sm overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsxs(
6642
7157
  ScrollArea,
6643
7158
  {
6644
7159
  className: "w-full",
6645
7160
  style: { maxHeight },
6646
7161
  children: [
6647
- /* @__PURE__ */ jsxRuntime.jsxs("table", { className: "w-full caption-bottom text-sm border-collapse", children: [
6648
- /* @__PURE__ */ jsxRuntime.jsx("thead", { className: "[&_tr]:border-b bg-sidebar sticky top-0 z-20", children: table.getHeaderGroups().map((headerGroup) => /* @__PURE__ */ jsxRuntime.jsx(
7162
+ /* @__PURE__ */ jsxRuntime.jsxs("table", { className: "w-full border-collapse", children: [
7163
+ /* @__PURE__ */ jsxRuntime.jsx("thead", { className: "sticky top-0 z-20", children: table.getHeaderGroups().map((headerGroup) => /* @__PURE__ */ jsxRuntime.jsx(
6649
7164
  "tr",
6650
7165
  {
6651
- className: "border-b transition-colors",
6652
7166
  children: headerGroup.headers.map((header, index) => {
6653
7167
  const isCurrentWeekColumn = header.id === currentWeekKey;
6654
7168
  return /* @__PURE__ */ jsxRuntime.jsx(
6655
7169
  "th",
6656
7170
  {
6657
7171
  className: cn(
6658
- "h-14 px-4 text-left align-middle font-medium text-muted-foreground border-r border-border last:border-r-0",
7172
+ "h-14 px-3 text-left align-middle font-semibold text-xs text-muted-foreground uppercase tracking-wide",
7173
+ "border-r border-b border-border last:border-r-0 bg-sidebar",
7174
+ // First column: sticky with right-edge shadow (Quantum token)
6659
7175
  index === 0 && stickySupplierColumn && [
6660
- "sticky left-0 z-30 bg-sidebar min-w-[200px]"
7176
+ "sticky left-0 z-30 min-w-[200px]",
7177
+ "shadow-[var(--j3m-shadow-sticky-edge)]"
6661
7178
  ],
6662
- index > 0 && "min-w-[120px] w-[120px]",
6663
- isCurrentWeekColumn && "bg-primary/10 border-t-2 border-t-primary"
7179
+ index > 0 && "min-w-[140px]",
7180
+ // Current week: only highlight text/dot, not full background
7181
+ isCurrentWeekColumn && highlightCurrentWeek && "text-primary"
6664
7182
  ),
6665
7183
  children: header.isPlaceholder ? null : reactTable.flexRender(
6666
7184
  header.column.columnDef.header,
@@ -6673,23 +7191,23 @@ function PlanningTable({
6673
7191
  },
6674
7192
  headerGroup.id
6675
7193
  )) }),
6676
- /* @__PURE__ */ jsxRuntime.jsx("tbody", { className: "[&_tr:last-child]:border-0 bg-background", children: table.getRowModel().rows?.length ? table.getRowModel().rows.map((row) => /* @__PURE__ */ jsxRuntime.jsx(
7194
+ /* @__PURE__ */ jsxRuntime.jsx("tbody", { className: "bg-background", children: table.getRowModel().rows?.length ? table.getRowModel().rows.map((row) => /* @__PURE__ */ jsxRuntime.jsx(
6677
7195
  "tr",
6678
7196
  {
6679
7197
  "data-state": row.getIsSelected() && "selected",
6680
- className: "border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted",
7198
+ className: "border-b border-border last:border-b-0",
6681
7199
  children: row.getVisibleCells().map((cell, index) => {
6682
- const isCurrentWeekColumn = cell.column.id === currentWeekKey;
6683
7200
  return /* @__PURE__ */ jsxRuntime.jsx(
6684
7201
  "td",
6685
7202
  {
6686
7203
  className: cn(
6687
- "p-0 align-middle border-r border-border last:border-r-0",
7204
+ "p-0 align-top border-r border-border last:border-r-0 bg-background",
7205
+ // First column: sticky WHITE with right-edge shadow (Quantum token)
6688
7206
  index === 0 && stickySupplierColumn && [
6689
- "sticky left-0 z-10 bg-background min-w-[200px]"
7207
+ "sticky left-0 z-10 min-w-[200px]",
7208
+ "shadow-[var(--j3m-shadow-sticky-edge)]"
6690
7209
  ],
6691
- index > 0 && "min-w-[120px] w-[120px]",
6692
- isCurrentWeekColumn && "bg-primary/5"
7210
+ index > 0 && "min-w-[140px]"
6693
7211
  ),
6694
7212
  children: reactTable.flexRender(
6695
7213
  cell.column.columnDef.cell,
@@ -6705,7 +7223,7 @@ function PlanningTable({
6705
7223
  "td",
6706
7224
  {
6707
7225
  colSpan: columns.length,
6708
- className: "h-24 text-center",
7226
+ className: "h-24 text-center text-muted-foreground bg-background",
6709
7227
  children: "No suppliers found."
6710
7228
  }
6711
7229
  ) }) })
@@ -6731,7 +7249,6 @@ function getStatusBadgeVariant(status) {
6731
7249
  switch (status) {
6732
7250
  case "on-time":
6733
7251
  return "outline";
6734
- // Green text with outline
6735
7252
  case "delayed":
6736
7253
  return "secondary";
6737
7254
  case "critical":
@@ -6748,7 +7265,6 @@ function getStatusBadgeClasses(status) {
6748
7265
  return "border-amber-500 text-amber-600 bg-amber-50 dark:bg-amber-950/50";
6749
7266
  case "critical":
6750
7267
  return "";
6751
- // Use default destructive
6752
7268
  default:
6753
7269
  return "";
6754
7270
  }
@@ -6767,134 +7283,566 @@ function getStatusLabel(status) {
6767
7283
  return status;
6768
7284
  }
6769
7285
  }
6770
- function DeliveryCard({ delivery, index }) {
6771
- const [isOpen, setIsOpen] = React17__namespace.useState(false);
6772
- const hasElements = delivery.elements && delivery.elements.length > 0;
6773
- const elementsAtRisk = delivery.elementsAtRisk ?? delivery.elements?.filter((e) => !e.isProduced).length ?? 0;
6774
- return /* @__PURE__ */ jsxRuntime.jsx(Collapsible, { open: isOpen, onOpenChange: setIsOpen, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border overflow-hidden bg-card", children: [
6775
- /* @__PURE__ */ jsxRuntime.jsx(CollapsibleTrigger2, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
6776
- "button",
7286
+ function getProgressVariant(status) {
7287
+ switch (status) {
7288
+ case "on-time":
7289
+ return "success";
7290
+ case "delayed":
7291
+ return "warning";
7292
+ case "critical":
7293
+ return "destructive";
7294
+ default:
7295
+ return "default";
7296
+ }
7297
+ }
7298
+ function getShipmentStatusBadgeClasses(status) {
7299
+ switch (status) {
7300
+ case "sent":
7301
+ return "border-green-500 text-green-600 bg-green-50 dark:bg-green-950/50";
7302
+ case "not-sent":
7303
+ return "border-muted-foreground/50 text-muted-foreground bg-muted/50";
7304
+ case "moved":
7305
+ return "border-blue-500 text-blue-600 bg-blue-50 dark:bg-blue-950/50";
7306
+ case "addon":
7307
+ return "border-purple-500 text-purple-600 bg-purple-50 dark:bg-purple-950/50";
7308
+ case "planned":
7309
+ default:
7310
+ return "border-muted-foreground/50 text-muted-foreground";
7311
+ }
7312
+ }
7313
+ function getShipmentStatusRowBg(status) {
7314
+ switch (status) {
7315
+ case "sent":
7316
+ return "bg-green-50/30 dark:bg-green-950/10";
7317
+ case "not-sent":
7318
+ return "bg-muted/30";
7319
+ case "moved":
7320
+ return "bg-blue-50/30 dark:bg-blue-950/10";
7321
+ case "addon":
7322
+ return "bg-purple-50/30 dark:bg-purple-950/10";
7323
+ default:
7324
+ return "";
7325
+ }
7326
+ }
7327
+ function DeliveryCommentPopover({
7328
+ comments = [],
7329
+ onAddComment,
7330
+ deliveryLabel
7331
+ }) {
7332
+ const [open, setOpen] = React22__namespace.useState(false);
7333
+ const [newCommentText, setNewCommentText] = React22__namespace.useState("");
7334
+ const [viewCommentsOpen, setViewCommentsOpen] = React22__namespace.useState(true);
7335
+ const [showAddForm, setShowAddForm] = React22__namespace.useState(false);
7336
+ const handleSubmit = () => {
7337
+ if (newCommentText.trim() && onAddComment) {
7338
+ onAddComment(newCommentText.trim());
7339
+ setNewCommentText("");
7340
+ setShowAddForm(false);
7341
+ setViewCommentsOpen(true);
7342
+ }
7343
+ };
7344
+ const handleKeyDown = (e) => {
7345
+ if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) {
7346
+ e.preventDefault();
7347
+ handleSubmit();
7348
+ }
7349
+ if (e.key === "Escape") {
7350
+ setShowAddForm(false);
7351
+ setNewCommentText("");
7352
+ }
7353
+ };
7354
+ const formatDate2 = (date) => {
7355
+ return new Intl.DateTimeFormat("en-US", {
7356
+ month: "short",
7357
+ day: "numeric",
7358
+ hour: "numeric",
7359
+ minute: "2-digit"
7360
+ }).format(date);
7361
+ };
7362
+ const prevOpenRef = React22__namespace.useRef(open);
7363
+ React22__namespace.useEffect(() => {
7364
+ const wasOpen = prevOpenRef.current;
7365
+ prevOpenRef.current = open;
7366
+ if (wasOpen && !open) {
7367
+ setShowAddForm(false);
7368
+ setNewCommentText("");
7369
+ }
7370
+ }, [open]);
7371
+ return /* @__PURE__ */ jsxRuntime.jsxs(Popover, { open, onOpenChange: setOpen, children: [
7372
+ /* @__PURE__ */ jsxRuntime.jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(CommentButton, { size: "sm", commentCount: comments.length }) }),
7373
+ /* @__PURE__ */ jsxRuntime.jsxs(
7374
+ PopoverContent,
6777
7375
  {
6778
- className: cn(
6779
- "w-full flex items-center justify-between p-3 text-left",
6780
- "hover:bg-muted/50 transition-colors",
6781
- hasElements && "cursor-pointer"
6782
- ),
6783
- disabled: !hasElements,
7376
+ className: "w-80 p-0 z-[100]",
7377
+ align: "end",
7378
+ sideOffset: 8,
7379
+ collisionPadding: 16,
6784
7380
  children: [
6785
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
6786
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Truck, { className: "h-4 w-4 text-muted-foreground" }),
6787
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
6788
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm font-medium", children: delivery.label || `Delivery ${index + 1}` }),
6789
- delivery.destination && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-xs text-muted-foreground", children: [
6790
- "\u2192 ",
6791
- delivery.destination
6792
- ] })
6793
- ] })
7381
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-4 py-3 border-b border-border", children: [
7382
+ /* @__PURE__ */ jsxRuntime.jsx("h4", { className: "text-sm font-semibold", children: "Comments" }),
7383
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: deliveryLabel })
6794
7384
  ] }),
6795
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
6796
- /* @__PURE__ */ jsxRuntime.jsx(
6797
- Badge,
7385
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-2 space-y-2 max-h-[400px] overflow-y-auto", children: [
7386
+ /* @__PURE__ */ jsxRuntime.jsxs(Collapsible, { open: viewCommentsOpen, onOpenChange: setViewCommentsOpen, children: [
7387
+ /* @__PURE__ */ jsxRuntime.jsx(CollapsibleTrigger2, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(Button, { variant: "ghost", size: "sm", className: "w-full justify-between h-8 px-2", children: [
7388
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs font-medium", children: [
7389
+ "Comments ",
7390
+ comments.length > 0 && `(${comments.length})`
7391
+ ] }),
7392
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { className: cn(
7393
+ "h-4 w-4 transition-transform duration-200",
7394
+ viewCommentsOpen && "rotate-180"
7395
+ ) })
7396
+ ] }) }),
7397
+ /* @__PURE__ */ jsxRuntime.jsx(CollapsibleContent2, { className: "space-y-2 pt-2", children: comments.length > 0 ? comments.map((comment) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg bg-muted/50 p-3 space-y-2", children: [
7398
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
7399
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium", children: comment.author }),
7400
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] text-muted-foreground", children: formatDate2(comment.createdAt) })
7401
+ ] }),
7402
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-foreground", children: comment.text })
7403
+ ] }, comment.id)) : /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground text-center py-2", children: "No comments yet" }) })
7404
+ ] }),
7405
+ /* @__PURE__ */ jsxRuntime.jsx(Separator, { className: "my-2" }),
7406
+ !showAddForm ? /* @__PURE__ */ jsxRuntime.jsxs(
7407
+ Button,
6798
7408
  {
6799
- variant: getStatusBadgeVariant(delivery.status),
6800
- className: cn("text-xs", getStatusBadgeClasses(delivery.status)),
6801
- children: getStatusLabel(delivery.status)
7409
+ variant: "outline",
7410
+ size: "sm",
7411
+ className: "w-full justify-center gap-2 h-8",
7412
+ onClick: () => setShowAddForm(true),
7413
+ children: [
7414
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, { className: "h-3.5 w-3.5" }),
7415
+ "Add comment"
7416
+ ]
6802
7417
  }
6803
- ),
6804
- hasElements && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { className: cn(
6805
- "h-4 w-4 text-muted-foreground transition-transform",
6806
- isOpen && "rotate-180"
6807
- ) })
7418
+ ) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn(
7419
+ "space-y-3 p-3 rounded-lg border border-border bg-muted/30",
7420
+ "animate-in fade-in-0 slide-in-from-top-2 duration-200"
7421
+ ), children: [
7422
+ /* @__PURE__ */ jsxRuntime.jsx(
7423
+ Textarea,
7424
+ {
7425
+ placeholder: "Type your comment...",
7426
+ value: newCommentText,
7427
+ onChange: (e) => setNewCommentText(e.target.value),
7428
+ onKeyDown: handleKeyDown,
7429
+ className: "min-h-[80px] text-sm resize-none",
7430
+ autoFocus: true
7431
+ }
7432
+ ),
7433
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
7434
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] text-muted-foreground", children: "\u2318+Enter to send \xB7 Esc to cancel" }),
7435
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
7436
+ /* @__PURE__ */ jsxRuntime.jsx(
7437
+ Button,
7438
+ {
7439
+ variant: "ghost",
7440
+ size: "sm",
7441
+ className: "h-7",
7442
+ onClick: () => {
7443
+ setShowAddForm(false);
7444
+ setNewCommentText("");
7445
+ },
7446
+ children: "Cancel"
7447
+ }
7448
+ ),
7449
+ /* @__PURE__ */ jsxRuntime.jsxs(
7450
+ Button,
7451
+ {
7452
+ size: "sm",
7453
+ className: "h-7 gap-1",
7454
+ onClick: handleSubmit,
7455
+ disabled: !newCommentText.trim(),
7456
+ children: [
7457
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Send, { className: "h-3 w-3" }),
7458
+ "Save"
7459
+ ]
7460
+ }
7461
+ )
7462
+ ] })
7463
+ ] })
7464
+ ] })
7465
+ ] })
7466
+ ]
7467
+ }
7468
+ )
7469
+ ] });
7470
+ }
7471
+ function ProductionCommentSection({
7472
+ comments = [],
7473
+ onAddComment
7474
+ }) {
7475
+ const [showAddForm, setShowAddForm] = React22__namespace.useState(false);
7476
+ const [newComment, setNewComment] = React22__namespace.useState("");
7477
+ const handleSubmit = () => {
7478
+ if (newComment.trim() && onAddComment) {
7479
+ onAddComment(newComment.trim());
7480
+ setNewComment("");
7481
+ setShowAddForm(false);
7482
+ }
7483
+ };
7484
+ const handleKeyDown = (e) => {
7485
+ if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) {
7486
+ e.preventDefault();
7487
+ handleSubmit();
7488
+ }
7489
+ if (e.key === "Escape") {
7490
+ setShowAddForm(false);
7491
+ setNewComment("");
7492
+ }
7493
+ };
7494
+ const formatDate2 = (date) => {
7495
+ return new Intl.DateTimeFormat("en-US", {
7496
+ month: "short",
7497
+ day: "numeric",
7498
+ hour: "numeric",
7499
+ minute: "2-digit"
7500
+ }).format(date);
7501
+ };
7502
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
7503
+ comments.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-2", children: comments.map((comment) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg bg-muted/50 p-2.5 space-y-1", children: [
7504
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
7505
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium", children: comment.author }),
7506
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] text-muted-foreground", children: formatDate2(comment.createdAt) })
7507
+ ] }),
7508
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-foreground", children: comment.text })
7509
+ ] }, comment.id)) }),
7510
+ !showAddForm ? /* @__PURE__ */ jsxRuntime.jsxs(
7511
+ Button,
7512
+ {
7513
+ variant: "ghost",
7514
+ size: "sm",
7515
+ className: "w-full justify-start gap-2 h-8 text-muted-foreground",
7516
+ onClick: () => setShowAddForm(true),
7517
+ children: [
7518
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MessageSquare, { className: "h-3.5 w-3.5" }),
7519
+ comments.length > 0 ? "Add another comment" : "Add a comment..."
7520
+ ]
7521
+ }
7522
+ ) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2 animate-in fade-in-0 slide-in-from-top-2 duration-200", children: [
7523
+ /* @__PURE__ */ jsxRuntime.jsx(
7524
+ Textarea,
7525
+ {
7526
+ placeholder: "Add a comment...",
7527
+ value: newComment,
7528
+ onChange: (e) => setNewComment(e.target.value),
7529
+ onKeyDown: handleKeyDown,
7530
+ className: "min-h-[60px] text-sm resize-none",
7531
+ autoFocus: true
7532
+ }
7533
+ ),
7534
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
7535
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] text-muted-foreground", children: "\u2318+Enter to send" }),
7536
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
7537
+ /* @__PURE__ */ jsxRuntime.jsx(
7538
+ Button,
7539
+ {
7540
+ variant: "ghost",
7541
+ size: "sm",
7542
+ className: "h-7",
7543
+ onClick: () => {
7544
+ setShowAddForm(false);
7545
+ setNewComment("");
7546
+ },
7547
+ children: "Cancel"
7548
+ }
7549
+ ),
7550
+ /* @__PURE__ */ jsxRuntime.jsxs(
7551
+ Button,
7552
+ {
7553
+ size: "sm",
7554
+ className: "h-7 gap-1",
7555
+ onClick: handleSubmit,
7556
+ disabled: !newComment.trim(),
7557
+ children: [
7558
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Send, { className: "h-3 w-3" }),
7559
+ "Save"
7560
+ ]
7561
+ }
7562
+ )
7563
+ ] })
7564
+ ] })
7565
+ ] })
7566
+ ] });
7567
+ }
7568
+ function DeliveryListItem({
7569
+ delivery,
7570
+ index,
7571
+ onClick
7572
+ }) {
7573
+ const hasComments = (delivery.comments?.length ?? 0) > 0;
7574
+ return /* @__PURE__ */ jsxRuntime.jsxs(
7575
+ "button",
7576
+ {
7577
+ onClick,
7578
+ className: cn(
7579
+ "w-full flex items-center justify-between p-3 rounded-lg",
7580
+ "bg-card border hover:bg-muted/50 transition-colors cursor-pointer",
7581
+ "text-left"
7582
+ ),
7583
+ children: [
7584
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
7585
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn(
7586
+ "flex items-center justify-center h-8 w-8 rounded-lg",
7587
+ delivery.status === "on-time" && "bg-green-100 dark:bg-green-950/50",
7588
+ delivery.status === "delayed" && "bg-amber-100 dark:bg-amber-950/50",
7589
+ delivery.status === "critical" && "bg-red-100 dark:bg-red-950/50"
7590
+ ), children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Truck, { className: cn(
7591
+ "h-4 w-4",
7592
+ delivery.status === "on-time" && "text-green-600 dark:text-green-400",
7593
+ delivery.status === "delayed" && "text-amber-600 dark:text-amber-400",
7594
+ delivery.status === "critical" && "text-red-600 dark:text-red-400"
7595
+ ) }) }),
7596
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
7597
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
7598
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-medium", children: delivery.label || `Delivery ${index + 1}` }),
7599
+ hasComments && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
7600
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MessageSquare, { className: "h-3 w-3 text-muted-foreground" }),
7601
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute -top-0.5 -right-0.5 h-1.5 w-1.5 rounded-full bg-primary" })
7602
+ ] })
7603
+ ] }),
7604
+ delivery.destination && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-xs text-muted-foreground", children: [
7605
+ "\u2192 ",
7606
+ delivery.destination
7607
+ ] })
6808
7608
  ] })
7609
+ ] }),
7610
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
7611
+ /* @__PURE__ */ jsxRuntime.jsx(
7612
+ Badge,
7613
+ {
7614
+ variant: getStatusBadgeVariant(delivery.status),
7615
+ className: cn("text-xs", getStatusBadgeClasses(delivery.status)),
7616
+ children: getStatusLabel(delivery.status)
7617
+ }
7618
+ ),
7619
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { className: "h-4 w-4 text-muted-foreground" })
7620
+ ] })
7621
+ ]
7622
+ }
7623
+ );
7624
+ }
7625
+ function DeliveryDetailsView({
7626
+ delivery,
7627
+ week,
7628
+ onBack,
7629
+ onAddComment
7630
+ }) {
7631
+ const elements = delivery.elements ?? [];
7632
+ const categorizedElements = React22__namespace.useMemo(() => {
7633
+ const sent = [];
7634
+ const notSent = [];
7635
+ const moved = [];
7636
+ const addons = [];
7637
+ elements.forEach((element) => {
7638
+ const status = getElementShipmentStatus(element, delivery.id);
7639
+ switch (status) {
7640
+ case "sent":
7641
+ sent.push(element);
7642
+ break;
7643
+ case "not-sent":
7644
+ notSent.push(element);
7645
+ break;
7646
+ case "moved":
7647
+ moved.push(element);
7648
+ break;
7649
+ case "addon":
7650
+ addons.push(element);
7651
+ break;
7652
+ default:
7653
+ notSent.push(element);
7654
+ }
7655
+ });
7656
+ return { sent, notSent, moved, addons };
7657
+ }, [elements, delivery.id]);
7658
+ const totalCount = elements.length;
7659
+ const sentCount = categorizedElements.sent.length;
7660
+ (delivery.comments?.length ?? 0) > 0;
7661
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col h-full animate-in slide-in-from-right-4 duration-200", children: [
7662
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-2 px-6 py-3 border-b", children: /* @__PURE__ */ jsxRuntime.jsxs(
7663
+ Button,
7664
+ {
7665
+ variant: "ghost",
7666
+ size: "sm",
7667
+ className: "gap-1 -ml-2",
7668
+ onClick: onBack,
7669
+ children: [
7670
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronLeft, { className: "h-4 w-4" }),
7671
+ "Back"
6809
7672
  ]
6810
7673
  }
6811
7674
  ) }),
6812
- hasElements && /* @__PURE__ */ jsxRuntime.jsxs(CollapsibleContent2, { children: [
6813
- /* @__PURE__ */ jsxRuntime.jsx(Separator, {}),
6814
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-3 space-y-2", children: [
6815
- elementsAtRisk > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-xs text-amber-600 dark:text-amber-400 mb-2", children: [
6816
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertTriangle, { className: "h-3.5 w-3.5" }),
7675
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-6 py-4 space-y-2", children: [
7676
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
7677
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-lg font-semibold", children: delivery.label || "Delivery Details" }),
7678
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
7679
+ /* @__PURE__ */ jsxRuntime.jsx(
7680
+ DeliveryCommentPopover,
7681
+ {
7682
+ comments: delivery.comments,
7683
+ onAddComment,
7684
+ deliveryLabel: delivery.label || "Delivery"
7685
+ }
7686
+ ),
7687
+ /* @__PURE__ */ jsxRuntime.jsx(
7688
+ Badge,
7689
+ {
7690
+ variant: getStatusBadgeVariant(delivery.status),
7691
+ className: cn("text-xs", getStatusBadgeClasses(delivery.status)),
7692
+ children: getStatusLabel(delivery.status)
7693
+ }
7694
+ )
7695
+ ] })
7696
+ ] }),
7697
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-4 text-sm text-muted-foreground", children: [
7698
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
7699
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Calendar, { className: "h-3.5 w-3.5" }),
7700
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
7701
+ week.label,
7702
+ " \u2022 ",
7703
+ week.dateRange
7704
+ ] })
7705
+ ] }),
7706
+ delivery.destination && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
7707
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Truck, { className: "h-3.5 w-3.5" }),
6817
7708
  /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
6818
- elementsAtRisk,
6819
- " element(s) probably not all produced"
7709
+ "\u2192 ",
7710
+ delivery.destination
7711
+ ] })
7712
+ ] })
7713
+ ] })
7714
+ ] }),
7715
+ /* @__PURE__ */ jsxRuntime.jsx(ScrollArea, { className: "flex-1 px-6 pb-6", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-6", children: [
7716
+ totalCount > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg bg-muted/50 p-4", children: [
7717
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between mb-2", children: [
7718
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-medium", children: "Shipment Progress" }),
7719
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-sm font-semibold tabular-nums", children: [
7720
+ "Shipped ",
7721
+ sentCount,
7722
+ " / ",
7723
+ totalCount
6820
7724
  ] })
6821
7725
  ] }),
6822
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-1.5", children: delivery.elements?.map((element) => /* @__PURE__ */ jsxRuntime.jsxs(
7726
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-2 bg-black/10 dark:bg-white/10 rounded-full overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx(
6823
7727
  "div",
6824
7728
  {
6825
7729
  className: cn(
6826
- "flex items-center justify-between text-xs p-2 rounded",
6827
- element.isProduced ? "bg-muted/30" : "bg-amber-50/50 dark:bg-amber-950/30"
7730
+ "h-full rounded-full transition-all",
7731
+ sentCount === totalCount ? "bg-green-500" : "bg-primary"
6828
7732
  ),
6829
- children: [
6830
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
6831
- element.isProduced ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CheckCircle2, { className: "h-3.5 w-3.5 text-green-600" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.XCircle, { className: "h-3.5 w-3.5 text-amber-600" }),
6832
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: element.isProduced ? "text-foreground" : "text-amber-700 dark:text-amber-300", children: element.name })
6833
- ] }),
6834
- element.quantity && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-muted-foreground", children: [
6835
- element.quantity,
6836
- " ",
6837
- element.unit ? formatProductionUnit(element.unit) : "pcs"
6838
- ] })
6839
- ]
6840
- },
6841
- element.id
6842
- )) })
7733
+ style: { width: `${totalCount > 0 ? sentCount / totalCount * 100 : 0}%` }
7734
+ }
7735
+ ) }),
7736
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 mt-3 flex-wrap", children: [
7737
+ categorizedElements.sent.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5 text-xs", children: [
7738
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CheckCircle2, { className: "h-3 w-3 text-green-600" }),
7739
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-green-700 dark:text-green-300", children: [
7740
+ categorizedElements.sent.length,
7741
+ " Sent"
7742
+ ] })
7743
+ ] }),
7744
+ categorizedElements.notSent.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5 text-xs", children: [
7745
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.XCircle, { className: "h-3 w-3 text-amber-600" }),
7746
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-amber-700 dark:text-amber-300", children: [
7747
+ categorizedElements.notSent.length,
7748
+ " Not sent"
7749
+ ] })
7750
+ ] }),
7751
+ categorizedElements.moved.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5 text-xs", children: [
7752
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowRight, { className: "h-3 w-3 text-blue-600" }),
7753
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-blue-700 dark:text-blue-300", children: [
7754
+ categorizedElements.moved.length,
7755
+ " Moved"
7756
+ ] })
7757
+ ] }),
7758
+ categorizedElements.addons.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5 text-xs", children: [
7759
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, { className: "h-3 w-3 text-purple-600" }),
7760
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-purple-700 dark:text-purple-300", children: [
7761
+ categorizedElements.addons.length,
7762
+ " Add-on"
7763
+ ] })
7764
+ ] })
7765
+ ] })
7766
+ ] }),
7767
+ elements.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3", children: [
7768
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-medium", children: "Elements" }),
7769
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-lg border overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsxs(Table, { children: [
7770
+ /* @__PURE__ */ jsxRuntime.jsx(TableHeader, { children: /* @__PURE__ */ jsxRuntime.jsxs(TableRow, { className: "bg-sidebar hover:bg-sidebar", children: [
7771
+ /* @__PURE__ */ jsxRuntime.jsx(TableHead, { className: "font-semibold", children: "Prefix" }),
7772
+ /* @__PURE__ */ jsxRuntime.jsx(TableHead, { className: "font-semibold", children: "Type" }),
7773
+ /* @__PURE__ */ jsxRuntime.jsx(TableHead, { className: "font-semibold text-right", children: "Weight" }),
7774
+ /* @__PURE__ */ jsxRuntime.jsx(TableHead, { className: "font-semibold text-right", children: "Size (m\xB2)" }),
7775
+ /* @__PURE__ */ jsxRuntime.jsx(TableHead, { className: "font-semibold text-center", children: "Status" })
7776
+ ] }) }),
7777
+ /* @__PURE__ */ jsxRuntime.jsx(TableBody, { children: elements.map((element) => {
7778
+ const shipmentStatus = getElementShipmentStatus(element, delivery.id);
7779
+ const statusLabel = getShipmentStatusLabel(shipmentStatus);
7780
+ return /* @__PURE__ */ jsxRuntime.jsxs(
7781
+ TableRow,
7782
+ {
7783
+ className: getShipmentStatusRowBg(shipmentStatus),
7784
+ children: [
7785
+ /* @__PURE__ */ jsxRuntime.jsx(TableCell, { className: "font-medium", children: element.prefix || "\u2014" }),
7786
+ /* @__PURE__ */ jsxRuntime.jsx(TableCell, { children: element.type || element.name || "\u2014" }),
7787
+ /* @__PURE__ */ jsxRuntime.jsx(TableCell, { className: "text-right tabular-nums", children: element.weight ? /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
7788
+ element.weight,
7789
+ " ",
7790
+ element.weightUnit || "kg"
7791
+ ] }) : "\u2014" }),
7792
+ /* @__PURE__ */ jsxRuntime.jsx(TableCell, { className: "text-right tabular-nums", children: element.sizeSqm ? /* @__PURE__ */ jsxRuntime.jsx("span", { children: element.sizeSqm }) : "\u2014" }),
7793
+ /* @__PURE__ */ jsxRuntime.jsx(TableCell, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center gap-1", children: [
7794
+ /* @__PURE__ */ jsxRuntime.jsx(
7795
+ Badge,
7796
+ {
7797
+ variant: "outline",
7798
+ className: cn(
7799
+ "text-[10px] h-5",
7800
+ getShipmentStatusBadgeClasses(shipmentStatus)
7801
+ ),
7802
+ children: statusLabel
7803
+ }
7804
+ ),
7805
+ shipmentStatus === "moved" && element.actualDeliveryLabel && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-[9px] text-blue-600 dark:text-blue-400", children: [
7806
+ "\u2192 ",
7807
+ element.actualDeliveryLabel
7808
+ ] }),
7809
+ shipmentStatus === "addon" && element.originalDeliveryLabel && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-[9px] text-purple-600 dark:text-purple-400", children: [
7810
+ "from ",
7811
+ element.originalDeliveryLabel
7812
+ ] })
7813
+ ] }) })
7814
+ ]
7815
+ },
7816
+ element.id
7817
+ );
7818
+ }) })
7819
+ ] }) })
7820
+ ] }),
7821
+ elements.length === 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center py-8 text-muted-foreground", children: [
7822
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Package, { className: "h-8 w-8 mx-auto mb-2 opacity-50" }),
7823
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm", children: "No elements in this delivery" })
6843
7824
  ] })
6844
- ] })
6845
- ] }) });
7825
+ ] }) })
7826
+ ] });
6846
7827
  }
6847
- function WeekDetailDialog({
6848
- open,
6849
- onOpenChange,
7828
+ function MainView({
6850
7829
  supplier,
6851
7830
  week,
6852
7831
  data,
6853
- onProgressUpdate
7832
+ producedValue,
7833
+ hasChanges,
7834
+ onProducedChange,
7835
+ onSave,
7836
+ onSelectDelivery,
7837
+ onAddProductionComment
6854
7838
  }) {
6855
7839
  const production = data?.production;
6856
- const initialProgress = production?.progress ?? data?.progress ?? 0;
6857
- const initialProduced = production?.produced ?? 0;
6858
- const [progressValue, setProgressValue] = React17__namespace.useState(initialProgress.toString());
6859
- const [producedValue, setProducedValue] = React17__namespace.useState(initialProduced.toString());
6860
- const [hasChanges, setHasChanges] = React17__namespace.useState(false);
6861
- React17__namespace.useEffect(() => {
6862
- const newProgress = data?.production?.progress ?? data?.progress ?? 0;
6863
- const newProduced = data?.production?.produced ?? 0;
6864
- setProgressValue(newProgress.toString());
6865
- setProducedValue(newProduced.toString());
6866
- setHasChanges(false);
6867
- }, [data]);
6868
- const handleProgressChange = (e) => {
6869
- const value = e.target.value;
6870
- setProgressValue(value);
6871
- setHasChanges(true);
6872
- };
6873
- const handleProducedChange = (e) => {
6874
- const value = e.target.value;
6875
- setProducedValue(value);
6876
- if (production?.target) {
6877
- const produced = parseFloat(value) || 0;
6878
- const calculatedProgress = Math.round(produced / production.target * 100);
6879
- setProgressValue(Math.min(100, calculatedProgress).toString());
6880
- }
6881
- setHasChanges(true);
6882
- };
6883
- const handleSave = () => {
6884
- if (!supplier || !week || !onProgressUpdate) return;
6885
- const newProgress = Math.min(100, Math.max(0, parseFloat(progressValue) || 0));
6886
- const newProduced = parseFloat(producedValue) || 0;
6887
- const weekKey = `${week.year}-W${week.weekNumber.toString().padStart(2, "0")}`;
6888
- onProgressUpdate(supplier.id, weekKey, newProgress, production ? newProduced : void 0);
6889
- setHasChanges(false);
6890
- };
6891
- if (!supplier || !week || !data) {
6892
- return null;
6893
- }
6894
- const productionProgress = parseFloat(progressValue) || 0;
7840
+ const productionProgress = production ? Math.min(100, Math.round(production.produced / production.target * 100)) : data?.progress ?? 0;
6895
7841
  const productionStatus = production?.status ?? "on-time";
6896
- return /* @__PURE__ */ jsxRuntime.jsx(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxRuntime.jsxs(DialogContent, { className: "max-w-lg max-h-[80vh] overflow-y-auto", children: [
6897
- /* @__PURE__ */ jsxRuntime.jsxs(DialogHeader, { children: [
7842
+ const isComplete = productionProgress >= 100;
7843
+ const hasProductionComments = (production?.comments?.length ?? 0) > 0;
7844
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "animate-in fade-in-0 duration-200", children: [
7845
+ /* @__PURE__ */ jsxRuntime.jsxs(DialogHeader, { className: "px-6 pt-6 pb-4", children: [
6898
7846
  /* @__PURE__ */ jsxRuntime.jsxs(DialogTitle, { className: "flex items-center gap-2", children: [
6899
7847
  supplier.name,
6900
7848
  /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: "secondary", className: "text-xs font-normal", children: supplier.badgeType })
@@ -6906,174 +7854,1319 @@ function WeekDetailDialog({
6906
7854
  week.dateRange
6907
7855
  ] })
6908
7856
  ] }),
6909
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4 mt-2", children: [
6910
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-sm text-muted-foreground", children: [
6911
- "Scope: ",
6912
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-foreground", children: supplier.scope })
6913
- ] }),
6914
- data.type !== "empty" && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
6915
- /* @__PURE__ */ jsxRuntime.jsx(Separator, {}),
6916
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3", children: [
6917
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
6918
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Factory, { className: "h-4 w-4 text-muted-foreground" }),
6919
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-medium", children: "Production Progress" }),
6920
- /* @__PURE__ */ jsxRuntime.jsx(
6921
- Badge,
6922
- {
6923
- variant: getStatusBadgeVariant(productionStatus),
6924
- className: cn("text-xs ml-auto", getStatusBadgeClasses(productionStatus)),
6925
- children: getStatusLabel(productionStatus)
6926
- }
6927
- )
6928
- ] }),
6929
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1.5", children: [
6930
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-between text-xs text-muted-foreground", children: [
6931
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Progress" }),
6932
- /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
6933
- Math.round(productionProgress),
6934
- "%"
6935
- ] })
6936
- ] }),
6937
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full h-2 bg-muted rounded-full overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx(
6938
- "div",
6939
- {
6940
- className: cn(
6941
- "h-full rounded-full transition-all",
6942
- productionStatus === "critical" ? "bg-red-500" : productionStatus === "delayed" ? "bg-amber-500" : "bg-green-500"
6943
- ),
6944
- style: { width: `${productionProgress}%` }
6945
- }
6946
- ) })
6947
- ] }),
6948
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn(
6949
- "p-3 rounded-lg border bg-card space-y-3"
6950
- ), children: [
6951
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs font-medium text-muted-foreground uppercase tracking-wide", children: "Update Progress" }),
6952
- production ? (
6953
- // If we have production data, show produced amount input
6954
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-3", children: [
6955
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1.5", children: [
6956
- /* @__PURE__ */ jsxRuntime.jsxs(Label2, { htmlFor: "produced", className: "text-xs", children: [
6957
- "Produced (",
6958
- formatProductionUnit(production.unit),
6959
- ")"
6960
- ] }),
6961
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
6962
- /* @__PURE__ */ jsxRuntime.jsx(
6963
- Input,
6964
- {
6965
- id: "produced",
6966
- type: "number",
6967
- min: "0",
6968
- max: production.target,
6969
- value: producedValue,
6970
- onChange: handleProducedChange,
6971
- className: "h-8 text-sm"
6972
- }
6973
- ),
6974
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-sm text-muted-foreground whitespace-nowrap", children: [
6975
- "/ ",
6976
- production.target,
6977
- " ",
6978
- formatProductionUnit(production.unit)
6979
- ] })
6980
- ] })
6981
- ] }),
6982
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1.5", children: [
6983
- /* @__PURE__ */ jsxRuntime.jsx(Label2, { htmlFor: "progress", className: "text-xs", children: "Progress (%)" }),
6984
- /* @__PURE__ */ jsxRuntime.jsx(
6985
- Input,
6986
- {
6987
- id: "progress",
6988
- type: "number",
6989
- min: "0",
6990
- max: "100",
6991
- value: progressValue,
6992
- onChange: handleProgressChange,
6993
- className: "h-8 text-sm"
6994
- }
6995
- )
7857
+ /* @__PURE__ */ jsxRuntime.jsx(ScrollArea, { className: "flex-1 px-6 pb-6", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-8", children: [
7858
+ data.type !== "empty" && /* @__PURE__ */ jsxRuntime.jsxs("section", { className: "space-y-4", children: [
7859
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
7860
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Factory, { className: "h-4 w-4 text-muted-foreground" }),
7861
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-semibold", children: "Production" }),
7862
+ /* @__PURE__ */ jsxRuntime.jsx(
7863
+ Badge,
7864
+ {
7865
+ variant: getStatusBadgeVariant(productionStatus),
7866
+ className: cn("text-xs ml-auto", getStatusBadgeClasses(productionStatus)),
7867
+ children: getStatusLabel(productionStatus)
7868
+ }
7869
+ )
7870
+ ] }),
7871
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-6", children: [
7872
+ /* @__PURE__ */ jsxRuntime.jsx(
7873
+ CircularProgress,
7874
+ {
7875
+ value: productionProgress,
7876
+ size: 100,
7877
+ strokeWidth: 10,
7878
+ variant: getProgressVariant(productionStatus),
7879
+ showCheckmark: isComplete,
7880
+ children: isComplete ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center", children: [
7881
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "h-6 w-6 text-green-600" }),
7882
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs font-semibold text-green-600", children: [
7883
+ production?.produced ?? 0,
7884
+ " ",
7885
+ production ? formatProductionUnit(production.unit) : ""
7886
+ ] })
7887
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center", children: [
7888
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-lg font-bold tabular-nums", children: production?.produced ?? 0 }),
7889
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-[10px] text-muted-foreground", children: [
7890
+ "/ ",
7891
+ production?.target ?? 0,
7892
+ " ",
7893
+ production ? formatProductionUnit(production.unit) : ""
6996
7894
  ] })
6997
7895
  ] })
6998
- ) : (
6999
- // Simple progress input if no production data
7000
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1.5", children: [
7001
- /* @__PURE__ */ jsxRuntime.jsx(Label2, { htmlFor: "progress", className: "text-xs", children: "Progress (%)" }),
7002
- /* @__PURE__ */ jsxRuntime.jsx(
7003
- Input,
7004
- {
7005
- id: "progress",
7006
- type: "number",
7007
- min: "0",
7008
- max: "100",
7009
- value: progressValue,
7010
- onChange: handleProgressChange,
7011
- className: "h-8 text-sm"
7012
- }
7013
- )
7896
+ }
7897
+ ),
7898
+ production && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 space-y-3", children: [
7899
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1.5", children: [
7900
+ /* @__PURE__ */ jsxRuntime.jsxs(Label2, { htmlFor: "produced", className: "text-xs", children: [
7901
+ "Produced Amount (",
7902
+ formatProductionUnit(production.unit),
7903
+ ")"
7904
+ ] }),
7905
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-2", children: /* @__PURE__ */ jsxRuntime.jsx(
7906
+ Input,
7907
+ {
7908
+ id: "produced",
7909
+ type: "number",
7910
+ min: "0",
7911
+ max: production.target * 2,
7912
+ value: producedValue,
7913
+ onChange: onProducedChange,
7914
+ className: "h-9"
7915
+ }
7916
+ ) }),
7917
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-[10px] text-muted-foreground", children: [
7918
+ "Target: ",
7919
+ production.target,
7920
+ " ",
7921
+ formatProductionUnit(production.unit)
7014
7922
  ] })
7015
- ),
7016
- onProgressUpdate && /* @__PURE__ */ jsxRuntime.jsx(
7923
+ ] }),
7924
+ /* @__PURE__ */ jsxRuntime.jsx(
7017
7925
  Button,
7018
7926
  {
7019
7927
  size: "sm",
7020
7928
  className: "w-full",
7021
7929
  disabled: !hasChanges,
7022
- onClick: handleSave,
7930
+ onClick: onSave,
7023
7931
  children: hasChanges ? "Save Progress" : "No Changes"
7024
7932
  }
7025
7933
  )
7026
- ] }),
7027
- production && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between p-3 rounded-lg border bg-muted/30", children: [
7028
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
7029
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Package, { className: "h-4 w-4 text-muted-foreground" }),
7030
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm", children: "Target" })
7031
- ] }),
7032
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-sm font-medium", children: [
7033
- production.target,
7034
- " ",
7035
- formatProductionUnit(production.unit)
7036
- ] })
7037
7934
  ] })
7038
- ] })
7039
- ] }),
7040
- data.deliveries && data.deliveries.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
7041
- /* @__PURE__ */ jsxRuntime.jsx(Separator, {}),
7042
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3", children: [
7935
+ ] }),
7936
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
7043
7937
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
7044
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Truck, { className: "h-4 w-4 text-muted-foreground" }),
7045
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-medium", children: "Deliveries" }),
7046
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-muted-foreground ml-auto", children: [
7047
- data.deliveries.length,
7048
- " scheduled"
7938
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-muted-foreground", children: "Comments" }),
7939
+ hasProductionComments && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-[10px] text-muted-foreground", children: [
7940
+ "(",
7941
+ production?.comments?.length,
7942
+ ")"
7049
7943
  ] })
7050
7944
  ] }),
7051
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-2", children: data.deliveries.map((delivery, index) => /* @__PURE__ */ jsxRuntime.jsx(DeliveryCard, { delivery, index }, delivery.id)) })
7945
+ /* @__PURE__ */ jsxRuntime.jsx(
7946
+ ProductionCommentSection,
7947
+ {
7948
+ comments: production?.comments,
7949
+ onAddComment: onAddProductionComment
7950
+ }
7951
+ )
7052
7952
  ] })
7053
7953
  ] }),
7054
- data.type === "no-logistics" && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
7055
- /* @__PURE__ */ jsxRuntime.jsx(Separator, {}),
7056
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-muted-foreground p-3 bg-muted/50 rounded-lg", children: [
7057
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Truck, { className: "h-4 w-4" }),
7058
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm", children: "No logistics scheduled for this week" })
7059
- ] })
7954
+ data.deliveries && data.deliveries.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("section", { className: "space-y-4", children: [
7955
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
7956
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Truck, { className: "h-4 w-4 text-muted-foreground" }),
7957
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-semibold", children: "Deliveries" }),
7958
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-muted-foreground ml-auto", children: [
7959
+ data.deliveries.length,
7960
+ " scheduled"
7961
+ ] })
7962
+ ] }),
7963
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-2", children: data.deliveries.map((delivery, index) => /* @__PURE__ */ jsxRuntime.jsx(
7964
+ DeliveryListItem,
7965
+ {
7966
+ delivery,
7967
+ index,
7968
+ onClick: () => onSelectDelivery(delivery)
7969
+ },
7970
+ delivery.id
7971
+ )) })
7060
7972
  ] }),
7061
- data.hasWarning && data.warningMessage && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
7062
- /* @__PURE__ */ jsxRuntime.jsx(Separator, {}),
7063
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-2 rounded-lg bg-amber-50 dark:bg-amber-950/50 p-3 text-amber-700 dark:text-amber-300", children: [
7064
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertTriangle, { className: "h-4 w-4 mt-0.5 shrink-0" }),
7065
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm", children: data.warningMessage })
7066
- ] })
7973
+ data.type === "no-logistics" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-muted-foreground p-3 bg-muted/50 rounded-lg", children: [
7974
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Truck, { className: "h-4 w-4" }),
7975
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm", children: "No logistics scheduled for this week" })
7067
7976
  ] }),
7068
- data.notes && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
7069
- /* @__PURE__ */ jsxRuntime.jsx(Separator, {}),
7070
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1.5", children: [
7071
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground", children: "Notes" }),
7072
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm", children: data.notes })
7073
- ] })
7977
+ data.hasWarning && data.warningMessage && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-2 rounded-lg bg-amber-50 dark:bg-amber-950/50 p-3 text-amber-700 dark:text-amber-300", children: [
7978
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertTriangle, { className: "h-4 w-4 mt-0.5 shrink-0" }),
7979
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm", children: data.warningMessage })
7980
+ ] }),
7981
+ data.notes && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1.5", children: [
7982
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground", children: "Notes" }),
7983
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm", children: data.notes })
7074
7984
  ] })
7075
- ] })
7076
- ] }) });
7985
+ ] }) })
7986
+ ] });
7987
+ }
7988
+ function WeekDetailDialog({
7989
+ open,
7990
+ onOpenChange,
7991
+ supplier,
7992
+ week,
7993
+ data,
7994
+ onProgressUpdate,
7995
+ onAddProductionComment,
7996
+ onAddDeliveryComment
7997
+ }) {
7998
+ const production = data?.production;
7999
+ const initialProduced = production?.produced ?? 0;
8000
+ const [producedValue, setProducedValue] = React22__namespace.useState(initialProduced.toString());
8001
+ const [hasChanges, setHasChanges] = React22__namespace.useState(false);
8002
+ const [selectedDelivery, setSelectedDelivery] = React22__namespace.useState(null);
8003
+ React22__namespace.useEffect(() => {
8004
+ const newProduced = data?.production?.produced ?? 0;
8005
+ setProducedValue(newProduced.toString());
8006
+ setHasChanges(false);
8007
+ }, [data]);
8008
+ React22__namespace.useEffect(() => {
8009
+ if (!open) {
8010
+ setSelectedDelivery(null);
8011
+ }
8012
+ }, [open]);
8013
+ const handleProducedChange = (e) => {
8014
+ const value = e.target.value;
8015
+ setProducedValue(value);
8016
+ setHasChanges(true);
8017
+ };
8018
+ const handleSave = () => {
8019
+ if (!supplier || !week || !onProgressUpdate) return;
8020
+ const newProduced = parseFloat(producedValue) || 0;
8021
+ const target = production?.target || 100;
8022
+ const newProgress = Math.min(100, Math.round(newProduced / target * 100));
8023
+ const weekKey = `${week.year}-W${week.weekNumber.toString().padStart(2, "0")}`;
8024
+ onProgressUpdate(supplier.id, weekKey, newProgress, newProduced);
8025
+ setHasChanges(false);
8026
+ };
8027
+ if (!supplier || !week || !data) {
8028
+ return null;
8029
+ }
8030
+ return /* @__PURE__ */ jsxRuntime.jsx(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxRuntime.jsx(DialogContent, { className: "max-w-lg max-h-[85vh] p-0 gap-0 overflow-hidden", children: selectedDelivery ? /* @__PURE__ */ jsxRuntime.jsx(
8031
+ DeliveryDetailsView,
8032
+ {
8033
+ delivery: selectedDelivery,
8034
+ week,
8035
+ onBack: () => setSelectedDelivery(null),
8036
+ onAddComment: onAddDeliveryComment ? (text) => {
8037
+ const weekKey = `${week.year}-W${week.weekNumber.toString().padStart(2, "0")}`;
8038
+ onAddDeliveryComment(supplier.id, weekKey, selectedDelivery.id, text);
8039
+ } : void 0
8040
+ }
8041
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
8042
+ MainView,
8043
+ {
8044
+ supplier,
8045
+ week,
8046
+ data,
8047
+ producedValue,
8048
+ hasChanges,
8049
+ onProducedChange: handleProducedChange,
8050
+ onSave: handleSave,
8051
+ onSelectDelivery: setSelectedDelivery,
8052
+ onAddProductionComment: onAddProductionComment ? (text) => {
8053
+ const weekKey = `${week.year}-W${week.weekNumber.toString().padStart(2, "0")}`;
8054
+ onAddProductionComment(supplier.id, weekKey, text);
8055
+ } : void 0
8056
+ }
8057
+ ) }) });
8058
+ }
8059
+ function RowHeaderCell({
8060
+ className,
8061
+ data,
8062
+ showProgress = true,
8063
+ ...props
8064
+ }) {
8065
+ const progressPercent = data.totalRequired > 0 ? Math.min(data.totalBooked / data.totalRequired * 100, 100) : 0;
8066
+ return /* @__PURE__ */ jsxRuntime.jsxs(
8067
+ "div",
8068
+ {
8069
+ "data-slot": "row-header-cell",
8070
+ className: cn(
8071
+ "flex flex-col justify-center gap-1.5 py-2 px-3 min-w-[200px] h-[100px] bg-background",
8072
+ className
8073
+ ),
8074
+ ...props,
8075
+ children: [
8076
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-2", children: [
8077
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col min-w-0 flex-1", children: [
8078
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-bold leading-tight text-foreground truncate", children: data.name }),
8079
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground", children: data.typeCode })
8080
+ ] }),
8081
+ /* @__PURE__ */ jsxRuntime.jsxs(
8082
+ Badge,
8083
+ {
8084
+ variant: "outline",
8085
+ className: "text-[10px] px-2 py-0.5 h-[19px] font-medium shrink-0 gap-1 bg-background border-border",
8086
+ children: [
8087
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Flag, { className: "h-2.5 w-2.5" }),
8088
+ "Paint"
8089
+ ]
8090
+ }
8091
+ )
8092
+ ] }),
8093
+ showProgress && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1", children: [
8094
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-1.5 bg-black/10 dark:bg-white/10 rounded-full overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx(
8095
+ "div",
8096
+ {
8097
+ className: "h-full bg-primary rounded-full transition-all",
8098
+ style: { width: `${progressPercent}%` }
8099
+ }
8100
+ ) }),
8101
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-[10px] font-medium text-primary", children: [
8102
+ data.totalBooked.toLocaleString(),
8103
+ " / ",
8104
+ data.totalRequired.toLocaleString(),
8105
+ " Booked"
8106
+ ] })
8107
+ ] })
8108
+ ]
8109
+ }
8110
+ );
8111
+ }
8112
+ function NetBadge({
8113
+ className,
8114
+ net,
8115
+ status,
8116
+ compact = false,
8117
+ ...props
8118
+ }) {
8119
+ const statusStyles = {
8120
+ pending: {
8121
+ container: "bg-muted border-border/50",
8122
+ text: "text-muted-foreground",
8123
+ icon: "text-muted-foreground"
8124
+ },
8125
+ valid: {
8126
+ container: "bg-green-100/50 border-green-500 dark:bg-green-950/30 dark:border-green-400",
8127
+ text: "text-green-700 dark:text-green-400",
8128
+ icon: "text-green-600 dark:text-green-400"
8129
+ },
8130
+ shortfall: {
8131
+ container: "bg-red-100/30 border-red-400/50 dark:bg-red-950/30 dark:border-red-400/50",
8132
+ text: "text-red-700 dark:text-red-400",
8133
+ icon: "text-red-600 dark:text-red-400"
8134
+ }
8135
+ };
8136
+ const styles = statusStyles[status];
8137
+ return /* @__PURE__ */ jsxRuntime.jsxs(
8138
+ "div",
8139
+ {
8140
+ "data-slot": "net-badge",
8141
+ "data-status": status,
8142
+ className: cn(
8143
+ "inline-flex items-center gap-1.5 px-3 py-0.5 rounded-full border",
8144
+ styles.container,
8145
+ className
8146
+ ),
8147
+ ...props,
8148
+ children: [
8149
+ status === "valid" && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: cn("h-3 w-3", styles.icon) }),
8150
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn(
8151
+ "text-xs font-bold leading-none",
8152
+ styles.text
8153
+ ), children: net >= 0 ? net : net }),
8154
+ !compact && /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn(
8155
+ "text-[10px] font-light opacity-80",
8156
+ styles.text
8157
+ ), children: "net" })
8158
+ ]
8159
+ }
8160
+ );
8161
+ }
8162
+
8163
+ // src/blocks/calibration-table/types.ts
8164
+ function formatCalibrationUnit(unit) {
8165
+ const unitLabels = {
8166
+ ton: "tons",
8167
+ pcs: "pcs",
8168
+ m2: "m\xB2",
8169
+ kg: "kg",
8170
+ m: "m"
8171
+ };
8172
+ return unitLabels[unit] || unit;
8173
+ }
8174
+ function calculateCalibrationCells(weeks) {
8175
+ const result = {};
8176
+ let accumulatedPlanned = 0;
8177
+ let accumulatedEntered = 0;
8178
+ for (const week of weeks) {
8179
+ accumulatedPlanned += week.planned;
8180
+ accumulatedEntered += week.entered ?? 0;
8181
+ const net = accumulatedEntered - accumulatedPlanned;
8182
+ let status = "pending";
8183
+ if (week.entered !== null) {
8184
+ status = net >= 0 ? "valid" : "shortfall";
8185
+ }
8186
+ result[week.weekKey] = {
8187
+ planned: week.planned,
8188
+ entered: week.entered,
8189
+ accumulatedPlanned,
8190
+ accumulatedEntered,
8191
+ net,
8192
+ status,
8193
+ isEditable: true
8194
+ };
8195
+ }
8196
+ return result;
8197
+ }
8198
+ function canSubmitCalibration(prefixes) {
8199
+ let shortfallCount = 0;
8200
+ let pendingCount = 0;
8201
+ for (const prefix of prefixes) {
8202
+ for (const weekKey in prefix.weeks) {
8203
+ const cell = prefix.weeks[weekKey];
8204
+ if (cell.status === "shortfall") shortfallCount++;
8205
+ if (cell.status === "pending") pendingCount++;
8206
+ }
8207
+ }
8208
+ const canSubmit = shortfallCount === 0 && pendingCount === 0;
8209
+ let message = "";
8210
+ if (shortfallCount > 0) {
8211
+ message = `Resolve ${shortfallCount} shortfall${shortfallCount > 1 ? "s" : ""} to submit`;
8212
+ } else if (pendingCount > 0) {
8213
+ message = `Enter production amounts for ${pendingCount} week${pendingCount > 1 ? "s" : ""}`;
8214
+ } else {
8215
+ message = "Ready to submit";
8216
+ }
8217
+ return { canSubmit, shortfallCount, pendingCount, message };
8218
+ }
8219
+ function CalibrationWeekCell({
8220
+ className,
8221
+ data,
8222
+ unit,
8223
+ onValueChange,
8224
+ isFocused,
8225
+ forcedRed = false,
8226
+ isEmpty = false,
8227
+ onAddClick,
8228
+ ...props
8229
+ }) {
8230
+ const inputRef = React22__namespace.useRef(null);
8231
+ const [localValue, setLocalValue] = React22__namespace.useState(
8232
+ data.entered !== null ? String(data.entered) : ""
8233
+ );
8234
+ const [isHovered, setIsHovered] = React22__namespace.useState(false);
8235
+ const [isEditing, setIsEditing] = React22__namespace.useState(false);
8236
+ React22__namespace.useEffect(() => {
8237
+ setLocalValue(data.entered !== null ? String(data.entered) : "");
8238
+ }, [data.entered]);
8239
+ const unitLabel = formatCalibrationUnit(unit);
8240
+ const effectiveStatus = forcedRed ? "forcedRed" : data.status;
8241
+ const handleInputChange = (e) => {
8242
+ const val = e.target.value;
8243
+ setLocalValue(val);
8244
+ if (val === "" || val === "-") {
8245
+ onValueChange?.(null);
8246
+ } else {
8247
+ const numVal = parseFloat(val);
8248
+ if (!isNaN(numVal)) {
8249
+ onValueChange?.(numVal);
8250
+ }
8251
+ }
8252
+ };
8253
+ const handleBlur = () => {
8254
+ setIsEditing(false);
8255
+ if (localValue === "" || localValue === "-") {
8256
+ setLocalValue("");
8257
+ onValueChange?.(null);
8258
+ } else {
8259
+ const numVal = parseFloat(localValue);
8260
+ if (!isNaN(numVal)) {
8261
+ setLocalValue(String(numVal));
8262
+ onValueChange?.(numVal);
8263
+ }
8264
+ }
8265
+ };
8266
+ const handleAddClick = () => {
8267
+ setIsEditing(true);
8268
+ onAddClick?.();
8269
+ setTimeout(() => {
8270
+ inputRef.current?.focus();
8271
+ }, 0);
8272
+ };
8273
+ const getContainerStyles = () => {
8274
+ switch (effectiveStatus) {
8275
+ case "valid":
8276
+ return "border-l-2 border-l-green-500 bg-green-50/50 dark:bg-green-950/30";
8277
+ case "shortfall":
8278
+ case "forcedRed":
8279
+ return "border-l-2 border-l-red-500 bg-red-50/50 dark:bg-red-950/30";
8280
+ case "pending":
8281
+ default:
8282
+ return cn(
8283
+ "bg-background",
8284
+ isHovered ? "border-l-2 border-l-border" : "border-l-2 border-l-transparent"
8285
+ );
8286
+ }
8287
+ };
8288
+ const getInputStyles = () => {
8289
+ switch (effectiveStatus) {
8290
+ case "valid":
8291
+ return "text-green-700 dark:text-green-400";
8292
+ case "shortfall":
8293
+ case "forcedRed":
8294
+ return "text-red-700 dark:text-red-400 font-semibold";
8295
+ default:
8296
+ return "text-foreground";
8297
+ }
8298
+ };
8299
+ const showAddButton = isEmpty && effectiveStatus === "pending" && !isEditing && data.entered === null;
8300
+ if (showAddButton) {
8301
+ return /* @__PURE__ */ jsxRuntime.jsx(
8302
+ "div",
8303
+ {
8304
+ "data-slot": "calibration-week-cell",
8305
+ "data-status": "empty",
8306
+ className: cn(
8307
+ "flex items-center justify-center h-[100px]",
8308
+ "transition-all duration-200 ease-out",
8309
+ "hover:-translate-y-0.5 hover:shadow-[var(--j3m-shadow-md)]",
8310
+ "bg-background",
8311
+ isHovered ? "border-l-2 border-l-border" : "border-l-2 border-l-transparent",
8312
+ className
8313
+ ),
8314
+ onMouseEnter: () => setIsHovered(true),
8315
+ onMouseLeave: () => setIsHovered(false),
8316
+ ...props,
8317
+ children: /* @__PURE__ */ jsxRuntime.jsxs(
8318
+ Button,
8319
+ {
8320
+ variant: "ghost",
8321
+ size: "icon",
8322
+ className: cn(
8323
+ "h-10 w-10 rounded-full",
8324
+ "text-muted-foreground/40 hover:text-muted-foreground hover:bg-muted/50",
8325
+ "transition-all duration-200",
8326
+ "shadow-[var(--j3m-shadow-sm)]"
8327
+ ),
8328
+ onClick: handleAddClick,
8329
+ children: [
8330
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, { className: "h-5 w-5" }),
8331
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Add production amount" })
8332
+ ]
8333
+ }
8334
+ )
8335
+ }
8336
+ );
8337
+ }
8338
+ if (isEmpty && forcedRed) {
8339
+ return /* @__PURE__ */ jsxRuntime.jsxs(
8340
+ "div",
8341
+ {
8342
+ "data-slot": "calibration-week-cell",
8343
+ "data-status": "forcedRed",
8344
+ className: cn(
8345
+ "flex flex-col items-center justify-center gap-2 h-[100px] px-3 py-2",
8346
+ "transition-all duration-200 ease-out",
8347
+ "hover:-translate-y-0.5 hover:shadow-[var(--j3m-shadow-md)]",
8348
+ "border-l-2 border-l-red-500 bg-red-50/50 dark:bg-red-950/30",
8349
+ className
8350
+ ),
8351
+ onMouseEnter: () => setIsHovered(true),
8352
+ onMouseLeave: () => setIsHovered(false),
8353
+ ...props,
8354
+ children: [
8355
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] font-medium text-red-600 dark:text-red-400 text-center", children: "Behind schedule" }),
8356
+ /* @__PURE__ */ jsxRuntime.jsx(NetBadge, { net: data.net, status: "shortfall" })
8357
+ ]
8358
+ }
8359
+ );
8360
+ }
8361
+ return /* @__PURE__ */ jsxRuntime.jsxs(
8362
+ "div",
8363
+ {
8364
+ "data-slot": "calibration-week-cell",
8365
+ "data-status": effectiveStatus,
8366
+ className: cn(
8367
+ "flex flex-col gap-2 px-3 py-2 h-[100px]",
8368
+ // Hover lift effect with shadow (like planning table)
8369
+ "transition-all duration-200 ease-out",
8370
+ "hover:-translate-y-0.5 hover:shadow-[var(--j3m-shadow-md)]",
8371
+ getContainerStyles(),
8372
+ className
8373
+ ),
8374
+ onMouseEnter: () => setIsHovered(true),
8375
+ onMouseLeave: () => setIsHovered(false),
8376
+ ...props,
8377
+ children: [
8378
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
8379
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] font-medium text-muted-foreground tracking-wide", children: "Accumulated" }),
8380
+ /* @__PURE__ */ jsxRuntime.jsx(NetBadge, { net: data.net, status: forcedRed ? "shortfall" : data.status })
8381
+ ] }),
8382
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
8383
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] font-medium text-muted-foreground tracking-wide", children: "Planned" }),
8384
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "inline-flex items-center justify-center px-2 py-0 bg-card border border-border rounded-full", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] font-medium text-muted-foreground", children: data.planned }) })
8385
+ ] }),
8386
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
8387
+ /* @__PURE__ */ jsxRuntime.jsx(
8388
+ Input,
8389
+ {
8390
+ ref: inputRef,
8391
+ type: "text",
8392
+ inputMode: "decimal",
8393
+ value: localValue,
8394
+ onChange: handleInputChange,
8395
+ onBlur: handleBlur,
8396
+ onFocus: () => setIsEditing(true),
8397
+ disabled: !data.isEditable,
8398
+ placeholder: "Enter amount",
8399
+ className: cn(
8400
+ "h-8 pl-3 pr-12 rounded-full text-sm font-semibold bg-background border-border",
8401
+ // Placeholder: smaller, lighter, lower contrast
8402
+ "placeholder:text-xs placeholder:font-normal placeholder:text-muted-foreground/50",
8403
+ getInputStyles(),
8404
+ !data.isEditable && "opacity-50 cursor-not-allowed"
8405
+ )
8406
+ }
8407
+ ),
8408
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute right-4 top-1/2 -translate-y-1/2 text-[10px] text-muted-foreground/70 pointer-events-none", children: unitLabel })
8409
+ ] })
8410
+ ]
8411
+ }
8412
+ );
8413
+ }
8414
+ function CommentPopover({
8415
+ comments,
8416
+ weekLabel,
8417
+ availablePrefixes,
8418
+ onAddComment,
8419
+ open,
8420
+ onOpenChange
8421
+ }) {
8422
+ const [newCommentText, setNewCommentText] = React22__namespace.useState("");
8423
+ const [selectedPrefixId, setSelectedPrefixId] = React22__namespace.useState("");
8424
+ const [viewCommentsOpen, setViewCommentsOpen] = React22__namespace.useState(true);
8425
+ const [showAddForm, setShowAddForm] = React22__namespace.useState(false);
8426
+ const selectedPrefixName = React22__namespace.useMemo(() => {
8427
+ const prefix = availablePrefixes.find((p) => p.id === selectedPrefixId);
8428
+ return prefix?.name ?? "";
8429
+ }, [availablePrefixes, selectedPrefixId]);
8430
+ const handleSubmit = () => {
8431
+ if (newCommentText.trim() && selectedPrefixId) {
8432
+ onAddComment?.(newCommentText.trim(), selectedPrefixId, selectedPrefixName);
8433
+ setNewCommentText("");
8434
+ setSelectedPrefixId("");
8435
+ setShowAddForm(false);
8436
+ setViewCommentsOpen(true);
8437
+ }
8438
+ };
8439
+ const handleKeyDown = (e) => {
8440
+ if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) {
8441
+ e.preventDefault();
8442
+ handleSubmit();
8443
+ }
8444
+ if (e.key === "Escape") {
8445
+ setShowAddForm(false);
8446
+ setSelectedPrefixId("");
8447
+ setNewCommentText("");
8448
+ }
8449
+ };
8450
+ const formatDate2 = (date) => {
8451
+ return new Intl.DateTimeFormat("en-US", {
8452
+ month: "short",
8453
+ day: "numeric",
8454
+ hour: "numeric",
8455
+ minute: "2-digit"
8456
+ }).format(date);
8457
+ };
8458
+ const prevOpenRef = React22__namespace.useRef(open);
8459
+ React22__namespace.useEffect(() => {
8460
+ const wasOpen = prevOpenRef.current;
8461
+ prevOpenRef.current = open;
8462
+ if (wasOpen && !open) {
8463
+ setShowAddForm(false);
8464
+ setNewCommentText("");
8465
+ setSelectedPrefixId("");
8466
+ }
8467
+ }, [open]);
8468
+ return /* @__PURE__ */ jsxRuntime.jsxs(Popover, { open, onOpenChange, children: [
8469
+ /* @__PURE__ */ jsxRuntime.jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(CommentButton, { commentCount: comments.length }) }),
8470
+ /* @__PURE__ */ jsxRuntime.jsxs(
8471
+ PopoverContent,
8472
+ {
8473
+ className: "w-80 p-0 z-[100]",
8474
+ align: "end",
8475
+ sideOffset: 8,
8476
+ collisionPadding: 16,
8477
+ children: [
8478
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-4 py-3 border-b border-border", children: [
8479
+ /* @__PURE__ */ jsxRuntime.jsx("h4", { className: "text-sm font-semibold", children: "Comments" }),
8480
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: weekLabel })
8481
+ ] }),
8482
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-2 space-y-2 max-h-[400px] overflow-y-auto", children: [
8483
+ /* @__PURE__ */ jsxRuntime.jsxs(Collapsible, { open: viewCommentsOpen, onOpenChange: setViewCommentsOpen, children: [
8484
+ /* @__PURE__ */ jsxRuntime.jsx(CollapsibleTrigger2, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
8485
+ Button,
8486
+ {
8487
+ variant: "ghost",
8488
+ size: "sm",
8489
+ className: "w-full justify-between h-8 px-2",
8490
+ children: [
8491
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs font-medium", children: [
8492
+ "Comments ",
8493
+ comments.length > 0 && `(${comments.length})`
8494
+ ] }),
8495
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { className: cn(
8496
+ "h-4 w-4 transition-transform duration-200",
8497
+ viewCommentsOpen && "rotate-180"
8498
+ ) })
8499
+ ]
8500
+ }
8501
+ ) }),
8502
+ /* @__PURE__ */ jsxRuntime.jsx(CollapsibleContent2, { className: "space-y-2 pt-2", children: comments.length > 0 ? comments.map((comment) => /* @__PURE__ */ jsxRuntime.jsxs(
8503
+ "div",
8504
+ {
8505
+ className: "rounded-lg bg-muted/50 p-3 space-y-2",
8506
+ "aria-label": `Comment by ${comment.author} about ${comment.prefixName}`,
8507
+ children: [
8508
+ /* @__PURE__ */ jsxRuntime.jsx(
8509
+ Badge,
8510
+ {
8511
+ variant: "outline",
8512
+ className: "text-[10px] px-2 py-0 h-5 font-medium bg-background",
8513
+ children: comment.prefixName
8514
+ }
8515
+ ),
8516
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
8517
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium", children: comment.author }),
8518
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] text-muted-foreground", children: formatDate2(comment.createdAt) })
8519
+ ] }),
8520
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-foreground", children: comment.text })
8521
+ ]
8522
+ },
8523
+ comment.id
8524
+ )) : /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground text-center py-2", children: "No comments yet" }) })
8525
+ ] }),
8526
+ /* @__PURE__ */ jsxRuntime.jsx(Separator, { className: "my-2" }),
8527
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-hidden", children: !showAddForm ? (
8528
+ /* Add comment Button */
8529
+ /* @__PURE__ */ jsxRuntime.jsxs(
8530
+ Button,
8531
+ {
8532
+ variant: "outline",
8533
+ size: "sm",
8534
+ className: "w-full justify-center gap-2 h-8",
8535
+ onClick: () => setShowAddForm(true),
8536
+ children: [
8537
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, { className: "h-3.5 w-3.5" }),
8538
+ "Add comment"
8539
+ ]
8540
+ }
8541
+ )
8542
+ ) : (
8543
+ /* Comment input form with smooth expand animation */
8544
+ /* @__PURE__ */ jsxRuntime.jsxs(
8545
+ "div",
8546
+ {
8547
+ className: cn(
8548
+ "space-y-3 p-3 rounded-lg border border-border bg-muted/30",
8549
+ "animate-in fade-in-0 slide-in-from-top-2 duration-200"
8550
+ ),
8551
+ children: [
8552
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1.5", children: [
8553
+ /* @__PURE__ */ jsxRuntime.jsxs(Label2, { htmlFor: "prefix-select", className: "text-xs font-medium", children: [
8554
+ "Applies to ",
8555
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-destructive", children: "*" })
8556
+ ] }),
8557
+ /* @__PURE__ */ jsxRuntime.jsxs(Select, { value: selectedPrefixId, onValueChange: setSelectedPrefixId, children: [
8558
+ /* @__PURE__ */ jsxRuntime.jsx(SelectTrigger, { id: "prefix-select", size: "sm", className: "w-full", children: /* @__PURE__ */ jsxRuntime.jsx(SelectValue, { placeholder: "Select row/type..." }) }),
8559
+ /* @__PURE__ */ jsxRuntime.jsx(SelectContent, { children: availablePrefixes.map((prefix) => /* @__PURE__ */ jsxRuntime.jsx(SelectItem, { value: prefix.id, children: prefix.name }, prefix.id)) })
8560
+ ] })
8561
+ ] }),
8562
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1.5", children: [
8563
+ /* @__PURE__ */ jsxRuntime.jsx(Label2, { htmlFor: "comment-text", className: "text-xs font-medium", children: "Comment" }),
8564
+ /* @__PURE__ */ jsxRuntime.jsx(
8565
+ Textarea,
8566
+ {
8567
+ id: "comment-text",
8568
+ placeholder: "Type your comment...",
8569
+ value: newCommentText,
8570
+ onChange: (e) => setNewCommentText(e.target.value),
8571
+ onKeyDown: handleKeyDown,
8572
+ className: "min-h-[80px] text-sm resize-none",
8573
+ autoFocus: true
8574
+ }
8575
+ )
8576
+ ] }),
8577
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
8578
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] text-muted-foreground", children: "\u2318+Enter to send \xB7 Esc to cancel" }),
8579
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
8580
+ /* @__PURE__ */ jsxRuntime.jsx(
8581
+ Button,
8582
+ {
8583
+ variant: "ghost",
8584
+ size: "sm",
8585
+ className: "h-7",
8586
+ onClick: () => {
8587
+ setShowAddForm(false);
8588
+ setNewCommentText("");
8589
+ setSelectedPrefixId("");
8590
+ },
8591
+ children: "Cancel"
8592
+ }
8593
+ ),
8594
+ /* @__PURE__ */ jsxRuntime.jsxs(
8595
+ Button,
8596
+ {
8597
+ size: "sm",
8598
+ className: "h-7 gap-1",
8599
+ onClick: handleSubmit,
8600
+ disabled: !newCommentText.trim() || !selectedPrefixId,
8601
+ children: [
8602
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Send, { className: "h-3 w-3" }),
8603
+ "Save"
8604
+ ]
8605
+ }
8606
+ )
8607
+ ] })
8608
+ ] })
8609
+ ]
8610
+ }
8611
+ )
8612
+ ) })
8613
+ ] })
8614
+ ]
8615
+ }
8616
+ )
8617
+ ] });
8618
+ }
8619
+ function CalibrationWeekHeader({
8620
+ className,
8621
+ week,
8622
+ comments = [],
8623
+ showCommentButton = true,
8624
+ availablePrefixes = [],
8625
+ onAddComment,
8626
+ ...props
8627
+ }) {
8628
+ return /* @__PURE__ */ jsxRuntime.jsxs(
8629
+ "div",
8630
+ {
8631
+ "data-slot": "calibration-week-header",
8632
+ "data-current-week": week.isCurrentWeek,
8633
+ className: cn(
8634
+ "flex items-center justify-between gap-2 px-2 py-2 min-w-[200px]",
8635
+ className
8636
+ ),
8637
+ ...props,
8638
+ children: [
8639
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-0.5", children: [
8640
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
8641
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn(
8642
+ "text-sm font-semibold tracking-tight",
8643
+ week.isCurrentWeek ? "text-primary" : "text-foreground"
8644
+ ), children: week.label }),
8645
+ week.isCurrentWeek && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "relative flex h-2 w-2", children: [
8646
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "animate-ping absolute inline-flex h-full w-full rounded-full bg-primary opacity-75" }),
8647
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "relative inline-flex rounded-full h-2 w-2 bg-primary" })
8648
+ ] })
8649
+ ] }),
8650
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] font-normal text-muted-foreground/60", children: week.dateRange })
8651
+ ] }),
8652
+ showCommentButton && availablePrefixes.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
8653
+ CommentPopover,
8654
+ {
8655
+ comments,
8656
+ weekLabel: week.label,
8657
+ availablePrefixes,
8658
+ onAddComment
8659
+ }
8660
+ )
8661
+ ]
8662
+ }
8663
+ );
8664
+ }
8665
+ function CalibrationTable({
8666
+ className,
8667
+ prefixes,
8668
+ supplierName,
8669
+ status = "draft",
8670
+ config = {}
8671
+ }) {
8672
+ const {
8673
+ weekCount = 8,
8674
+ startDate,
8675
+ allowTimelineExtension = true,
8676
+ maxEarlierWeeks = 4,
8677
+ showToolbar = true,
8678
+ showPagination = true,
8679
+ pageSizeOptions = [10, 20, 30],
8680
+ defaultPageSize = 10,
8681
+ stickyRowHeader = true,
8682
+ maxHeight = "500px",
8683
+ onCellChange,
8684
+ onSubmit,
8685
+ onAddComment,
8686
+ onAddEarlierWeek
8687
+ } = config;
8688
+ const calculatedStartDate = React22__namespace.useMemo(() => {
8689
+ if (startDate) return startDate;
8690
+ let earliest = null;
8691
+ for (const prefix of prefixes) {
8692
+ for (const weekKey in prefix.weeks) {
8693
+ const cell = prefix.weeks[weekKey];
8694
+ if (cell.planned > 0) {
8695
+ const match = weekKey.match(/(\d{4})-W(\d{2})/);
8696
+ if (match) {
8697
+ const year = parseInt(match[1]);
8698
+ const week = parseInt(match[2]);
8699
+ const date = new Date(year, 0, 1 + (week - 1) * 7);
8700
+ if (earliest === null || date < earliest) {
8701
+ earliest = date;
8702
+ }
8703
+ }
8704
+ }
8705
+ }
8706
+ }
8707
+ return earliest ?? /* @__PURE__ */ new Date();
8708
+ }, [startDate, prefixes]);
8709
+ const [additionalWeeks, setAdditionalWeeks] = React22__namespace.useState(0);
8710
+ const weeks = React22__namespace.useMemo(() => {
8711
+ const start = new Date(calculatedStartDate);
8712
+ start.setDate(start.getDate() - additionalWeeks * 7);
8713
+ return generateWeeks(start, weekCount + additionalWeeks);
8714
+ }, [calculatedStartDate, weekCount, additionalWeeks]);
8715
+ React22__namespace.useMemo(() => {
8716
+ const currentWeek = weeks.find((w) => w.isCurrentWeek);
8717
+ return currentWeek ? getWeekKey(currentWeek.startDate) : null;
8718
+ }, [weeks]);
8719
+ const [currentPage, setCurrentPage] = React22__namespace.useState(0);
8720
+ const [pageSize, setPageSize] = React22__namespace.useState(defaultPageSize);
8721
+ const [searchQuery, setSearchQuery] = React22__namespace.useState("");
8722
+ const filteredPrefixes = React22__namespace.useMemo(() => {
8723
+ if (!searchQuery) return prefixes;
8724
+ const query = searchQuery.toLowerCase();
8725
+ return prefixes.filter(
8726
+ (p) => p.name.toLowerCase().includes(query) || p.typeCode.toLowerCase().includes(query)
8727
+ );
8728
+ }, [prefixes, searchQuery]);
8729
+ const paginatedPrefixes = React22__namespace.useMemo(() => {
8730
+ const start = currentPage * pageSize;
8731
+ return filteredPrefixes.slice(start, start + pageSize);
8732
+ }, [filteredPrefixes, currentPage, pageSize]);
8733
+ React22__namespace.useMemo(
8734
+ () => canSubmitCalibration(prefixes),
8735
+ [prefixes]
8736
+ );
8737
+ const handleAddEarlierWeek = () => {
8738
+ if (additionalWeeks < maxEarlierWeeks) {
8739
+ setAdditionalWeeks((prev) => prev + 1);
8740
+ onAddEarlierWeek?.();
8741
+ }
8742
+ };
8743
+ const handleCellChange = (prefixId, weekKey, value) => {
8744
+ onCellChange?.(prefixId, weekKey, value);
8745
+ };
8746
+ const handleAddWeekComment = (weekKey, text, prefixId, prefixName) => {
8747
+ onAddComment?.(prefixId, weekKey, text);
8748
+ };
8749
+ const getWeekComments = (weekKey) => {
8750
+ const allComments = [];
8751
+ for (const prefix of prefixes) {
8752
+ const weekComments = prefix.comments?.filter((c) => c.weekKey === weekKey) ?? [];
8753
+ allComments.push(...weekComments);
8754
+ }
8755
+ return allComments;
8756
+ };
8757
+ const availablePrefixes = React22__namespace.useMemo(
8758
+ () => prefixes.map((p) => ({ id: p.id, name: p.name })),
8759
+ [prefixes]
8760
+ );
8761
+ return /* @__PURE__ */ jsxRuntime.jsxs(
8762
+ "div",
8763
+ {
8764
+ "data-slot": "calibration-table",
8765
+ className: cn("flex flex-col gap-4", className),
8766
+ children: [
8767
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-start justify-between gap-4", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1", children: [
8768
+ /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-2xl font-semibold tracking-tight", children: "Weekly Production Calibration" }),
8769
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-muted-foreground", children: "Review required weekly production and confirm achievable output at the selected checkpoint." })
8770
+ ] }) }),
8771
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2", children: [
8772
+ showToolbar && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-2", children: [
8773
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-2", children: /* @__PURE__ */ jsxRuntime.jsx(
8774
+ Input,
8775
+ {
8776
+ placeholder: "Search prefixes...",
8777
+ value: searchQuery,
8778
+ onChange: (e) => setSearchQuery(e.target.value),
8779
+ className: "h-8 w-[200px] lg:w-[300px]"
8780
+ }
8781
+ ) }),
8782
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-2", children: allowTimelineExtension && additionalWeeks < maxEarlierWeeks && /* @__PURE__ */ jsxRuntime.jsxs(
8783
+ Button,
8784
+ {
8785
+ variant: "outline",
8786
+ size: "sm",
8787
+ className: "gap-2",
8788
+ onClick: handleAddEarlierWeek,
8789
+ children: [
8790
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, { className: "h-4 w-4" }),
8791
+ "Add earlier week"
8792
+ ]
8793
+ }
8794
+ ) })
8795
+ ] }),
8796
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-xl border bg-background shadow-sm overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsxs(
8797
+ ScrollArea,
8798
+ {
8799
+ className: "w-full",
8800
+ style: { maxHeight },
8801
+ children: [
8802
+ /* @__PURE__ */ jsxRuntime.jsxs("table", { className: "w-full border-collapse", children: [
8803
+ /* @__PURE__ */ jsxRuntime.jsx("thead", { className: "sticky top-0 z-20", children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
8804
+ /* @__PURE__ */ jsxRuntime.jsx("th", { className: cn(
8805
+ "h-14 px-3 text-left align-middle font-semibold text-xs text-muted-foreground uppercase tracking-wide",
8806
+ "border-r border-b border-border bg-sidebar",
8807
+ stickyRowHeader && "sticky left-0 z-30 min-w-[200px]",
8808
+ // Right shadow using Quantum token
8809
+ stickyRowHeader && "shadow-[var(--j3m-shadow-sticky-edge)]"
8810
+ ), children: "Supplier / Scope" }),
8811
+ weeks.map((week) => {
8812
+ const weekKey = getWeekKey(week.startDate);
8813
+ const weekComments = getWeekComments(weekKey);
8814
+ return /* @__PURE__ */ jsxRuntime.jsx(
8815
+ "th",
8816
+ {
8817
+ className: "h-14 px-2 text-left align-middle border-r border-b border-border last:border-r-0 min-w-[220px] bg-sidebar",
8818
+ children: /* @__PURE__ */ jsxRuntime.jsx(
8819
+ CalibrationWeekHeader,
8820
+ {
8821
+ week,
8822
+ comments: weekComments,
8823
+ showCommentButton: true,
8824
+ availablePrefixes,
8825
+ onAddComment: (text, prefixId, prefixName) => handleAddWeekComment(weekKey, text, prefixId)
8826
+ }
8827
+ )
8828
+ },
8829
+ weekKey
8830
+ );
8831
+ })
8832
+ ] }) }),
8833
+ /* @__PURE__ */ jsxRuntime.jsx("tbody", { className: "bg-background", children: paginatedPrefixes.length > 0 ? paginatedPrefixes.map((prefix) => {
8834
+ const sortedWeekKeys = weeks.map((w) => getWeekKey(w.startDate));
8835
+ let hasDeficit = false;
8836
+ const forcedRedMap = {};
8837
+ for (const weekKey of sortedWeekKeys) {
8838
+ const cellData = prefix.weeks[weekKey];
8839
+ if (hasDeficit) {
8840
+ forcedRedMap[weekKey] = true;
8841
+ } else if (cellData && cellData.status === "shortfall") {
8842
+ hasDeficit = true;
8843
+ forcedRedMap[weekKey] = false;
8844
+ } else {
8845
+ forcedRedMap[weekKey] = false;
8846
+ }
8847
+ }
8848
+ return /* @__PURE__ */ jsxRuntime.jsxs("tr", { className: "border-b border-border last:border-b-0", children: [
8849
+ /* @__PURE__ */ jsxRuntime.jsx(
8850
+ "td",
8851
+ {
8852
+ className: cn(
8853
+ "p-0 align-top border-r border-border bg-background",
8854
+ stickyRowHeader && "sticky left-0 z-10 min-w-[200px]",
8855
+ // Right shadow using Quantum token
8856
+ stickyRowHeader && "shadow-[var(--j3m-shadow-sticky-edge)]"
8857
+ ),
8858
+ children: /* @__PURE__ */ jsxRuntime.jsx(RowHeaderCell, { data: prefix, showProgress: true })
8859
+ }
8860
+ ),
8861
+ weeks.map((week) => {
8862
+ const weekKey = getWeekKey(week.startDate);
8863
+ const cellData = prefix.weeks[weekKey];
8864
+ const isForcedRed = forcedRedMap[weekKey] ?? false;
8865
+ const isEmpty = !cellData || cellData.planned === 0;
8866
+ const effectiveCellData = cellData ?? {
8867
+ planned: 0,
8868
+ entered: null,
8869
+ accumulatedPlanned: 0,
8870
+ accumulatedEntered: 0,
8871
+ net: 0,
8872
+ status: "pending",
8873
+ isEditable: true
8874
+ };
8875
+ return /* @__PURE__ */ jsxRuntime.jsx(
8876
+ "td",
8877
+ {
8878
+ className: "p-0 align-top border-r border-border last:border-r-0 min-w-[220px] bg-background",
8879
+ children: /* @__PURE__ */ jsxRuntime.jsx(
8880
+ CalibrationWeekCell,
8881
+ {
8882
+ data: effectiveCellData,
8883
+ unit: prefix.unit,
8884
+ onValueChange: (value) => handleCellChange(prefix.id, weekKey, value),
8885
+ forcedRed: isForcedRed,
8886
+ isEmpty,
8887
+ onAddClick: () => {
8888
+ }
8889
+ }
8890
+ )
8891
+ },
8892
+ weekKey
8893
+ );
8894
+ })
8895
+ ] }, prefix.id);
8896
+ }) : /* @__PURE__ */ jsxRuntime.jsx("tr", { children: /* @__PURE__ */ jsxRuntime.jsx(
8897
+ "td",
8898
+ {
8899
+ colSpan: weeks.length + 1,
8900
+ className: "h-24 text-center text-muted-foreground bg-background",
8901
+ children: "No prefixes found."
8902
+ }
8903
+ ) }) })
8904
+ ] }),
8905
+ /* @__PURE__ */ jsxRuntime.jsx(ScrollBar, { orientation: "horizontal" }),
8906
+ /* @__PURE__ */ jsxRuntime.jsx(ScrollBar, { orientation: "vertical" })
8907
+ ]
8908
+ }
8909
+ ) })
8910
+ ] }),
8911
+ showPagination && filteredPrefixes.length > pageSize && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-2", children: [
8912
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-sm text-muted-foreground", children: [
8913
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Rows per page" }),
8914
+ /* @__PURE__ */ jsxRuntime.jsx(
8915
+ "select",
8916
+ {
8917
+ value: pageSize,
8918
+ onChange: (e) => {
8919
+ setPageSize(Number(e.target.value));
8920
+ setCurrentPage(0);
8921
+ },
8922
+ className: "h-8 w-16 rounded-md border bg-background px-2 text-sm",
8923
+ children: pageSizeOptions.map((size) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: size, children: size }, size))
8924
+ }
8925
+ )
8926
+ ] }),
8927
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-sm text-muted-foreground", children: [
8928
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
8929
+ "Page ",
8930
+ currentPage + 1,
8931
+ " of ",
8932
+ Math.ceil(filteredPrefixes.length / pageSize)
8933
+ ] }),
8934
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1", children: [
8935
+ /* @__PURE__ */ jsxRuntime.jsx(
8936
+ Button,
8937
+ {
8938
+ variant: "outline",
8939
+ size: "icon",
8940
+ className: "h-8 w-8",
8941
+ disabled: currentPage === 0,
8942
+ onClick: () => setCurrentPage(0),
8943
+ children: "\xAB\xAB"
8944
+ }
8945
+ ),
8946
+ /* @__PURE__ */ jsxRuntime.jsx(
8947
+ Button,
8948
+ {
8949
+ variant: "outline",
8950
+ size: "icon",
8951
+ className: "h-8 w-8",
8952
+ disabled: currentPage === 0,
8953
+ onClick: () => setCurrentPage((prev) => prev - 1),
8954
+ children: "\xAB"
8955
+ }
8956
+ ),
8957
+ /* @__PURE__ */ jsxRuntime.jsx(
8958
+ Button,
8959
+ {
8960
+ variant: "outline",
8961
+ size: "icon",
8962
+ className: "h-8 w-8",
8963
+ disabled: currentPage >= Math.ceil(filteredPrefixes.length / pageSize) - 1,
8964
+ onClick: () => setCurrentPage((prev) => prev + 1),
8965
+ children: "\xBB"
8966
+ }
8967
+ ),
8968
+ /* @__PURE__ */ jsxRuntime.jsx(
8969
+ Button,
8970
+ {
8971
+ variant: "outline",
8972
+ size: "icon",
8973
+ className: "h-8 w-8",
8974
+ disabled: currentPage >= Math.ceil(filteredPrefixes.length / pageSize) - 1,
8975
+ onClick: () => setCurrentPage(Math.ceil(filteredPrefixes.length / pageSize) - 1),
8976
+ children: "\xBB\xBB"
8977
+ }
8978
+ )
8979
+ ] })
8980
+ ] })
8981
+ ] })
8982
+ ]
8983
+ }
8984
+ );
8985
+ }
8986
+ function CommentDialog({
8987
+ prefixes,
8988
+ weeks,
8989
+ onAddComment,
8990
+ triggerVariant = "outline",
8991
+ open,
8992
+ onOpenChange
8993
+ }) {
8994
+ const [selectedPrefixId, setSelectedPrefixId] = React22__namespace.useState("");
8995
+ const [selectedWeekKey, setSelectedWeekKey] = React22__namespace.useState("");
8996
+ const [commentText, setCommentText] = React22__namespace.useState("");
8997
+ const currentWeek = React22__namespace.useMemo(
8998
+ () => weeks.find((w) => w.isCurrentWeek),
8999
+ [weeks]
9000
+ );
9001
+ React22__namespace.useEffect(() => {
9002
+ if (open) {
9003
+ setSelectedPrefixId(prefixes[0]?.id ?? "");
9004
+ setSelectedWeekKey(currentWeek ? getWeekKey(currentWeek.startDate) : weeks[0] ? getWeekKey(weeks[0].startDate) : "");
9005
+ setCommentText("");
9006
+ }
9007
+ }, [open, prefixes, weeks, currentWeek]);
9008
+ const handleSave = () => {
9009
+ if (selectedPrefixId && selectedWeekKey && commentText.trim()) {
9010
+ onAddComment?.(selectedPrefixId, selectedWeekKey, commentText.trim());
9011
+ onOpenChange?.(false);
9012
+ }
9013
+ };
9014
+ const isValid = selectedPrefixId && selectedWeekKey && commentText.trim();
9015
+ return /* @__PURE__ */ jsxRuntime.jsxs(Dialog, { open, onOpenChange, children: [
9016
+ /* @__PURE__ */ jsxRuntime.jsx(DialogTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(Button, { variant: triggerVariant, size: "sm", className: "gap-2", children: [
9017
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MessageSquarePlus, { className: "h-4 w-4" }),
9018
+ "Add comment"
9019
+ ] }) }),
9020
+ /* @__PURE__ */ jsxRuntime.jsxs(DialogContent, { className: "sm:max-w-[425px]", children: [
9021
+ /* @__PURE__ */ jsxRuntime.jsxs(DialogHeader, { children: [
9022
+ /* @__PURE__ */ jsxRuntime.jsx(DialogTitle, { children: "Add Comment" }),
9023
+ /* @__PURE__ */ jsxRuntime.jsx(DialogDescription, { children: "Add a comment to a specific prefix and week. Comments help communicate production updates and issues." })
9024
+ ] }),
9025
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-4 py-4", children: [
9026
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-2", children: [
9027
+ /* @__PURE__ */ jsxRuntime.jsx(Label2, { htmlFor: "prefix-select", children: "Prefix / Element Type" }),
9028
+ /* @__PURE__ */ jsxRuntime.jsxs(Select, { value: selectedPrefixId, onValueChange: setSelectedPrefixId, children: [
9029
+ /* @__PURE__ */ jsxRuntime.jsx(SelectTrigger, { id: "prefix-select", children: /* @__PURE__ */ jsxRuntime.jsx(SelectValue, { placeholder: "Select prefix..." }) }),
9030
+ /* @__PURE__ */ jsxRuntime.jsx(SelectContent, { children: prefixes.map((prefix) => /* @__PURE__ */ jsxRuntime.jsx(SelectItem, { value: prefix.id, children: /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center gap-2", children: [
9031
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: prefix.name }),
9032
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-muted-foreground text-xs", children: [
9033
+ "(",
9034
+ prefix.typeCode,
9035
+ ")"
9036
+ ] })
9037
+ ] }) }, prefix.id)) })
9038
+ ] })
9039
+ ] }),
9040
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-2", children: [
9041
+ /* @__PURE__ */ jsxRuntime.jsx(Label2, { htmlFor: "week-select", children: "Week" }),
9042
+ /* @__PURE__ */ jsxRuntime.jsxs(Select, { value: selectedWeekKey, onValueChange: setSelectedWeekKey, children: [
9043
+ /* @__PURE__ */ jsxRuntime.jsx(SelectTrigger, { id: "week-select", children: /* @__PURE__ */ jsxRuntime.jsx(SelectValue, { placeholder: "Select week..." }) }),
9044
+ /* @__PURE__ */ jsxRuntime.jsx(SelectContent, { children: weeks.map((week) => {
9045
+ const weekKey = getWeekKey(week.startDate);
9046
+ return /* @__PURE__ */ jsxRuntime.jsx(SelectItem, { value: weekKey, children: /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center gap-2", children: [
9047
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn(
9048
+ "font-medium",
9049
+ week.isCurrentWeek && "text-primary"
9050
+ ), children: week.label }),
9051
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground text-xs", children: week.dateRange }),
9052
+ week.isCurrentWeek && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] text-primary font-medium", children: "(Current)" })
9053
+ ] }) }, weekKey);
9054
+ }) })
9055
+ ] })
9056
+ ] }),
9057
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-2", children: [
9058
+ /* @__PURE__ */ jsxRuntime.jsx(Label2, { htmlFor: "comment-text", children: "Comment" }),
9059
+ /* @__PURE__ */ jsxRuntime.jsx(
9060
+ Textarea,
9061
+ {
9062
+ id: "comment-text",
9063
+ placeholder: "Enter your comment...",
9064
+ value: commentText,
9065
+ onChange: (e) => setCommentText(e.target.value),
9066
+ className: "min-h-[100px] resize-none"
9067
+ }
9068
+ )
9069
+ ] })
9070
+ ] }),
9071
+ /* @__PURE__ */ jsxRuntime.jsxs(DialogFooter, { children: [
9072
+ /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "outline", onClick: () => onOpenChange?.(false), children: "Cancel" }),
9073
+ /* @__PURE__ */ jsxRuntime.jsx(Button, { onClick: handleSave, disabled: !isValid, children: "Save comment" })
9074
+ ] })
9075
+ ] })
9076
+ ] });
9077
+ }
9078
+ function getStatusBadge(status) {
9079
+ switch (status) {
9080
+ case "draft":
9081
+ return { variant: "secondary", label: "DRAFT", color: "bg-blue-500" };
9082
+ case "submitted":
9083
+ return { variant: "secondary", label: "SUBMITTED", color: "bg-amber-500" };
9084
+ case "approved":
9085
+ return { variant: "secondary", label: "APPROVED", color: "bg-green-500" };
9086
+ case "rejected":
9087
+ return { variant: "destructive", label: "REJECTED", color: "bg-red-500" };
9088
+ }
9089
+ }
9090
+ function formatDate(date) {
9091
+ return date.toLocaleDateString("en-US", {
9092
+ month: "short",
9093
+ day: "2-digit",
9094
+ year: "numeric"
9095
+ });
9096
+ }
9097
+ function SubmitCalibrationBar({
9098
+ className,
9099
+ status,
9100
+ lastSaved,
9101
+ canSubmit,
9102
+ shortfallCount,
9103
+ pendingCount,
9104
+ message,
9105
+ onSubmit,
9106
+ onSaveDraft,
9107
+ ...props
9108
+ }) {
9109
+ const statusBadge = getStatusBadge(status);
9110
+ return /* @__PURE__ */ jsxRuntime.jsxs(
9111
+ "div",
9112
+ {
9113
+ "data-slot": "submit-calibration-bar",
9114
+ className: cn(
9115
+ "flex items-center justify-between gap-4 px-4 py-4",
9116
+ "bg-background",
9117
+ className
9118
+ ),
9119
+ ...props,
9120
+ children: [
9121
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
9122
+ !canSubmit && (shortfallCount > 0 || pendingCount > 0) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-sm", children: [
9123
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertTriangle, { className: "h-4 w-4 text-amber-500" }),
9124
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: message })
9125
+ ] }),
9126
+ canSubmit && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-sm", children: [
9127
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CheckCircle, { className: "h-4 w-4 text-green-500" }),
9128
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: message })
9129
+ ] })
9130
+ ] }),
9131
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
9132
+ /* @__PURE__ */ jsxRuntime.jsxs(
9133
+ Badge,
9134
+ {
9135
+ variant: statusBadge.variant,
9136
+ className: "flex items-center gap-2 px-3 py-1 rounded-full",
9137
+ children: [
9138
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("h-2 w-2 rounded-full", statusBadge.color) }),
9139
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium", children: statusBadge.label })
9140
+ ]
9141
+ }
9142
+ ),
9143
+ lastSaved && /* @__PURE__ */ jsxRuntime.jsxs(
9144
+ Button,
9145
+ {
9146
+ variant: "outline",
9147
+ size: "sm",
9148
+ className: "gap-2 rounded-full",
9149
+ disabled: true,
9150
+ children: [
9151
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Calendar, { className: "h-4 w-4" }),
9152
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: formatDate(lastSaved) })
9153
+ ]
9154
+ }
9155
+ ),
9156
+ /* @__PURE__ */ jsxRuntime.jsx(
9157
+ Button,
9158
+ {
9159
+ size: "sm",
9160
+ className: "rounded-full px-4 min-w-[140px]",
9161
+ disabled: !canSubmit || status === "submitted" || status === "approved",
9162
+ onClick: onSubmit,
9163
+ children: status === "submitted" ? "Submitted" : status === "approved" ? "Approved" : "Submit calibration"
9164
+ }
9165
+ )
9166
+ ] })
9167
+ ]
9168
+ }
9169
+ );
7077
9170
  }
7078
9171
 
7079
9172
  // src/components/event-calendar/types.ts
@@ -7138,7 +9231,7 @@ var BADGE_VARIANT_LABELS = {
7138
9231
  colored: "Colored",
7139
9232
  mixed: "Mixed"
7140
9233
  };
7141
- var CalendarContext = React17__namespace.createContext(null);
9234
+ var CalendarContext = React22__namespace.createContext(null);
7142
9235
  function EventCalendarProvider({
7143
9236
  children,
7144
9237
  events: initialEvents = [],
@@ -7153,38 +9246,38 @@ function EventCalendarProvider({
7153
9246
  onEventUpdate,
7154
9247
  onEventDelete
7155
9248
  }) {
7156
- const [selectedDate, setSelectedDate] = React17__namespace.useState(defaultDate);
7157
- const [selectedUserId, setSelectedUserId] = React17__namespace.useState(defaultUserId);
7158
- const [events, setEventsState] = React17__namespace.useState(initialEvents);
7159
- const [users] = React17__namespace.useState(initialUsers);
7160
- const [badgeVariant, setBadgeVariant] = React17__namespace.useState(defaultBadgeVariant);
7161
- const [view, setView] = React17__namespace.useState(defaultView);
7162
- const [workingHours, setWorkingHours] = React17__namespace.useState(defaultWorkingHours);
7163
- const [visibleHours, setVisibleHours] = React17__namespace.useState(defaultVisibleHours);
7164
- React17__namespace.useEffect(() => {
9249
+ const [selectedDate, setSelectedDate] = React22__namespace.useState(defaultDate);
9250
+ const [selectedUserId, setSelectedUserId] = React22__namespace.useState(defaultUserId);
9251
+ const [events, setEventsState] = React22__namespace.useState(initialEvents);
9252
+ const [users] = React22__namespace.useState(initialUsers);
9253
+ const [badgeVariant, setBadgeVariant] = React22__namespace.useState(defaultBadgeVariant);
9254
+ const [view, setView] = React22__namespace.useState(defaultView);
9255
+ const [workingHours, setWorkingHours] = React22__namespace.useState(defaultWorkingHours);
9256
+ const [visibleHours, setVisibleHours] = React22__namespace.useState(defaultVisibleHours);
9257
+ React22__namespace.useEffect(() => {
7165
9258
  setEventsState(initialEvents);
7166
9259
  }, [initialEvents]);
7167
- const setEvents = React17__namespace.useCallback((newEvents) => {
9260
+ const setEvents = React22__namespace.useCallback((newEvents) => {
7168
9261
  setEventsState(newEvents);
7169
9262
  }, []);
7170
- const addEvent = React17__namespace.useCallback((event) => {
9263
+ const addEvent = React22__namespace.useCallback((event) => {
7171
9264
  setEventsState((prev) => [...prev, event]);
7172
9265
  onEventAdd?.(event);
7173
9266
  }, [onEventAdd]);
7174
- const updateEvent = React17__namespace.useCallback((event) => {
9267
+ const updateEvent = React22__namespace.useCallback((event) => {
7175
9268
  setEventsState(
7176
9269
  (prev) => prev.map((e) => e.id === event.id ? event : e)
7177
9270
  );
7178
9271
  onEventUpdate?.(event);
7179
9272
  }, [onEventUpdate]);
7180
- const deleteEvent = React17__namespace.useCallback((eventId) => {
9273
+ const deleteEvent = React22__namespace.useCallback((eventId) => {
7181
9274
  setEventsState((prev) => prev.filter((e) => e.id !== eventId));
7182
9275
  onEventDelete?.(eventId);
7183
9276
  }, [onEventDelete]);
7184
- const goToToday = React17__namespace.useCallback(() => {
9277
+ const goToToday = React22__namespace.useCallback(() => {
7185
9278
  setSelectedDate(/* @__PURE__ */ new Date());
7186
9279
  }, []);
7187
- const goToPrevious = React17__namespace.useCallback(() => {
9280
+ const goToPrevious = React22__namespace.useCallback(() => {
7188
9281
  setSelectedDate((current) => {
7189
9282
  switch (view) {
7190
9283
  case "day":
@@ -7202,7 +9295,7 @@ function EventCalendarProvider({
7202
9295
  }
7203
9296
  });
7204
9297
  }, [view]);
7205
- const goToNext = React17__namespace.useCallback(() => {
9298
+ const goToNext = React22__namespace.useCallback(() => {
7206
9299
  setSelectedDate((current) => {
7207
9300
  switch (view) {
7208
9301
  case "day":
@@ -7220,7 +9313,7 @@ function EventCalendarProvider({
7220
9313
  }
7221
9314
  });
7222
9315
  }, [view]);
7223
- const contextValue = React17__namespace.useMemo(
9316
+ const contextValue = React22__namespace.useMemo(
7224
9317
  () => ({
7225
9318
  // State
7226
9319
  selectedDate,
@@ -7267,7 +9360,7 @@ function EventCalendarProvider({
7267
9360
  return /* @__PURE__ */ jsxRuntime.jsx(CalendarContext.Provider, { value: contextValue, children });
7268
9361
  }
7269
9362
  function useEventCalendar() {
7270
- const context = React17__namespace.useContext(CalendarContext);
9363
+ const context = React22__namespace.useContext(CalendarContext);
7271
9364
  if (!context) {
7272
9365
  throw new Error("useEventCalendar must be used within an EventCalendarProvider");
7273
9366
  }
@@ -7275,14 +9368,14 @@ function useEventCalendar() {
7275
9368
  }
7276
9369
  function useFilteredEvents() {
7277
9370
  const { events, selectedUserId } = useEventCalendar();
7278
- return React17__namespace.useMemo(() => {
9371
+ return React22__namespace.useMemo(() => {
7279
9372
  if (!selectedUserId) return events;
7280
9373
  return events.filter((event) => event.user.id === selectedUserId);
7281
9374
  }, [events, selectedUserId]);
7282
9375
  }
7283
9376
  function useEventsInRange(startDate, endDate) {
7284
9377
  const filteredEvents = useFilteredEvents();
7285
- return React17__namespace.useMemo(() => {
9378
+ return React22__namespace.useMemo(() => {
7286
9379
  return filteredEvents.filter((event) => {
7287
9380
  const eventStart = new Date(event.startDate);
7288
9381
  const eventEnd = new Date(event.endDate);
@@ -7840,8 +9933,8 @@ function MoreEvents({ count, onClick, className }) {
7840
9933
  );
7841
9934
  }
7842
9935
  function TimeIndicator({ className }) {
7843
- const [now, setNow] = React17__namespace.useState(/* @__PURE__ */ new Date());
7844
- React17__namespace.useEffect(() => {
9936
+ const [now, setNow] = React22__namespace.useState(/* @__PURE__ */ new Date());
9937
+ React22__namespace.useEffect(() => {
7845
9938
  const interval = setInterval(() => setNow(/* @__PURE__ */ new Date()), 6e4);
7846
9939
  return () => clearInterval(interval);
7847
9940
  }, []);
@@ -7878,24 +9971,24 @@ function DateBadge({ date, className }) {
7878
9971
  }
7879
9972
  );
7880
9973
  }
7881
- var DragContext = React17__namespace.createContext(null);
9974
+ var DragContext = React22__namespace.createContext(null);
7882
9975
  function DragProvider({
7883
9976
  children,
7884
9977
  snapMinutes = 15,
7885
9978
  onDragStart,
7886
9979
  onDragEnd
7887
9980
  }) {
7888
- const [draggedEvent, setDraggedEventState] = React17__namespace.useState(null);
7889
- const [isDragging, setIsDragging] = React17__namespace.useState(false);
9981
+ const [draggedEvent, setDraggedEventState] = React22__namespace.useState(null);
9982
+ const [isDragging, setIsDragging] = React22__namespace.useState(false);
7890
9983
  const { updateEvent } = useEventCalendar();
7891
- const setDraggedEvent = React17__namespace.useCallback((event) => {
9984
+ const setDraggedEvent = React22__namespace.useCallback((event) => {
7892
9985
  setDraggedEventState(event);
7893
9986
  setIsDragging(!!event);
7894
9987
  if (event) {
7895
9988
  onDragStart?.(event);
7896
9989
  }
7897
9990
  }, [onDragStart]);
7898
- const handleDrop = React17__namespace.useCallback((newStartDate) => {
9991
+ const handleDrop = React22__namespace.useCallback((newStartDate) => {
7899
9992
  if (!draggedEvent) return;
7900
9993
  const snappedDate = snapToInterval(newStartDate, snapMinutes);
7901
9994
  const { startDate, endDate } = calculateDropDates(draggedEvent, snappedDate);
@@ -7908,7 +10001,7 @@ function DragProvider({
7908
10001
  onDragEnd?.(updatedEvent, new Date(startDate), new Date(endDate));
7909
10002
  setDraggedEvent(null);
7910
10003
  }, [draggedEvent, snapMinutes, updateEvent, onDragEnd, setDraggedEvent]);
7911
- const contextValue = React17__namespace.useMemo(
10004
+ const contextValue = React22__namespace.useMemo(
7912
10005
  () => ({
7913
10006
  draggedEvent,
7914
10007
  setDraggedEvent,
@@ -7919,7 +10012,7 @@ function DragProvider({
7919
10012
  return /* @__PURE__ */ jsxRuntime.jsx(DragContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxRuntime.jsx(DragDropHandler, { onDrop: handleDrop, children }) });
7920
10013
  }
7921
10014
  function useDrag() {
7922
- const context = React17__namespace.useContext(DragContext);
10015
+ const context = React22__namespace.useContext(DragContext);
7923
10016
  if (!context) {
7924
10017
  throw new Error("useDrag must be used within a DragProvider");
7925
10018
  }
@@ -7964,7 +10057,7 @@ function DroppableZone({
7964
10057
  }) {
7965
10058
  const { draggedEvent, setDraggedEvent } = useDrag();
7966
10059
  const { updateEvent } = useEventCalendar();
7967
- const [isOver, setIsOver] = React17__namespace.useState(false);
10060
+ const [isOver, setIsOver] = React22__namespace.useState(false);
7968
10061
  const handleDragOver = (e) => {
7969
10062
  e.preventDefault();
7970
10063
  e.dataTransfer.dropEffect = "move";
@@ -8002,23 +10095,23 @@ function DroppableZone({
8002
10095
  function useDroppable({ date, hour, minute = 0, onDrop }) {
8003
10096
  const { draggedEvent, setDraggedEvent } = useDrag();
8004
10097
  const { updateEvent } = useEventCalendar();
8005
- const [isOver, setIsOver] = React17__namespace.useState(false);
8006
- const dropTargetDate = React17__namespace.useMemo(() => {
10098
+ const [isOver, setIsOver] = React22__namespace.useState(false);
10099
+ const dropTargetDate = React22__namespace.useMemo(() => {
8007
10100
  const targetDate = new Date(date);
8008
10101
  if (hour !== void 0) {
8009
10102
  targetDate.setHours(hour, minute, 0, 0);
8010
10103
  }
8011
10104
  return targetDate;
8012
10105
  }, [date, hour, minute]);
8013
- const handleDragOver = React17__namespace.useCallback((e) => {
10106
+ const handleDragOver = React22__namespace.useCallback((e) => {
8014
10107
  e.preventDefault();
8015
10108
  e.dataTransfer.dropEffect = "move";
8016
10109
  if (!isOver) setIsOver(true);
8017
10110
  }, [isOver]);
8018
- const handleDragLeave = React17__namespace.useCallback(() => {
10111
+ const handleDragLeave = React22__namespace.useCallback(() => {
8019
10112
  setIsOver(false);
8020
10113
  }, []);
8021
- const handleDrop = React17__namespace.useCallback((e) => {
10114
+ const handleDrop = React22__namespace.useCallback((e) => {
8022
10115
  e.preventDefault();
8023
10116
  setIsOver(false);
8024
10117
  if (!draggedEvent) return;
@@ -8045,13 +10138,13 @@ function useDroppable({ date, hour, minute = 0, onDrop }) {
8045
10138
  function useDraggable(event, disabled = false) {
8046
10139
  const { setDraggedEvent, draggedEvent } = useDrag();
8047
10140
  const isDragged = draggedEvent?.id === event.id;
8048
- const handleDragStart = React17__namespace.useCallback((e) => {
10141
+ const handleDragStart = React22__namespace.useCallback((e) => {
8049
10142
  if (disabled) return;
8050
10143
  e.dataTransfer.effectAllowed = "move";
8051
10144
  e.dataTransfer.setData("text/plain", event.id);
8052
10145
  setDraggedEvent(event);
8053
10146
  }, [disabled, event, setDraggedEvent]);
8054
- const handleDragEnd = React17__namespace.useCallback(() => {
10147
+ const handleDragEnd = React22__namespace.useCallback(() => {
8055
10148
  setDraggedEvent(null);
8056
10149
  }, [setDraggedEvent]);
8057
10150
  return {
@@ -8092,15 +10185,15 @@ function MonthView({
8092
10185
  }) {
8093
10186
  const { selectedDate, badgeVariant, setSelectedDate, setView } = useEventCalendar();
8094
10187
  const filteredEvents = useFilteredEvents();
8095
- const { singleDayEvents, multiDayEvents } = React17__namespace.useMemo(
10188
+ const { singleDayEvents, multiDayEvents } = React22__namespace.useMemo(
8096
10189
  () => splitEventsByDuration(filteredEvents),
8097
10190
  [filteredEvents]
8098
10191
  );
8099
- const cells = React17__namespace.useMemo(
10192
+ const cells = React22__namespace.useMemo(
8100
10193
  () => getCalendarCells(selectedDate),
8101
10194
  [selectedDate]
8102
10195
  );
8103
- const eventPositions = React17__namespace.useMemo(
10196
+ const eventPositions = React22__namespace.useMemo(
8104
10197
  () => calculateMonthEventPositions(multiDayEvents, singleDayEvents, selectedDate),
8105
10198
  [multiDayEvents, singleDayEvents, selectedDate]
8106
10199
  );
@@ -8282,7 +10375,7 @@ function WeekView({
8282
10375
  visibleHours
8283
10376
  } = useEventCalendar();
8284
10377
  const filteredEvents = useFilteredEvents();
8285
- const { singleDayEvents, multiDayEvents } = React17__namespace.useMemo(
10378
+ const { singleDayEvents, multiDayEvents } = React22__namespace.useMemo(
8286
10379
  () => splitEventsByDuration(filteredEvents),
8287
10380
  [filteredEvents]
8288
10381
  );
@@ -8488,8 +10581,8 @@ function CalendarTimeline({
8488
10581
  firstVisibleHour,
8489
10582
  lastVisibleHour
8490
10583
  }) {
8491
- const [currentTime, setCurrentTime] = React17__namespace.useState(/* @__PURE__ */ new Date());
8492
- React17__namespace.useEffect(() => {
10584
+ const [currentTime, setCurrentTime] = React22__namespace.useState(/* @__PURE__ */ new Date());
10585
+ React22__namespace.useEffect(() => {
8493
10586
  const interval = setInterval(() => {
8494
10587
  setCurrentTime(/* @__PURE__ */ new Date());
8495
10588
  }, 6e4);
@@ -8572,7 +10665,7 @@ function DayView({
8572
10665
  visibleHours
8573
10666
  } = useEventCalendar();
8574
10667
  const filteredEvents = useFilteredEvents();
8575
- const { singleDayEvents, multiDayEvents } = React17__namespace.useMemo(
10668
+ const { singleDayEvents, multiDayEvents } = React22__namespace.useMemo(
8576
10669
  () => splitEventsByDuration(filteredEvents),
8577
10670
  [filteredEvents]
8578
10671
  );
@@ -8580,7 +10673,7 @@ function DayView({
8580
10673
  visibleHours,
8581
10674
  singleDayEvents
8582
10675
  );
8583
- const currentEvents = React17__namespace.useMemo(() => {
10676
+ const currentEvents = React22__namespace.useMemo(() => {
8584
10677
  if (!dateFns.isToday(selectedDate)) return [];
8585
10678
  return getCurrentEvents(singleDayEvents);
8586
10679
  }, [singleDayEvents, selectedDate]);
@@ -8804,8 +10897,8 @@ function CalendarTimeline2({
8804
10897
  firstVisibleHour,
8805
10898
  lastVisibleHour
8806
10899
  }) {
8807
- const [currentTime, setCurrentTime] = React17__namespace.useState(/* @__PURE__ */ new Date());
8808
- React17__namespace.useEffect(() => {
10900
+ const [currentTime, setCurrentTime] = React22__namespace.useState(/* @__PURE__ */ new Date());
10901
+ React22__namespace.useEffect(() => {
8809
10902
  const interval = setInterval(() => {
8810
10903
  setCurrentTime(/* @__PURE__ */ new Date());
8811
10904
  }, 6e4);
@@ -8839,7 +10932,7 @@ function YearView({
8839
10932
  }) {
8840
10933
  const { selectedDate, setSelectedDate, setView } = useEventCalendar();
8841
10934
  const filteredEvents = useFilteredEvents();
8842
- const months = React17__namespace.useMemo(() => {
10935
+ const months = React22__namespace.useMemo(() => {
8843
10936
  const yearStart = dateFns.startOfYear(selectedDate);
8844
10937
  return Array.from({ length: 12 }, (_, i) => dateFns.addMonths(yearStart, i));
8845
10938
  }, [selectedDate]);
@@ -8962,11 +11055,11 @@ function AgendaView({
8962
11055
  }) {
8963
11056
  const { selectedDate, setSelectedDate, setView } = useEventCalendar();
8964
11057
  const filteredEvents = useFilteredEvents();
8965
- const { singleDayEvents, multiDayEvents } = React17__namespace.useMemo(
11058
+ const { singleDayEvents, multiDayEvents } = React22__namespace.useMemo(
8966
11059
  () => splitEventsByDuration(filteredEvents),
8967
11060
  [filteredEvents]
8968
11061
  );
8969
- const eventsByDay = React17__namespace.useMemo(() => {
11062
+ const eventsByDay = React22__namespace.useMemo(() => {
8970
11063
  const allDates = /* @__PURE__ */ new Map();
8971
11064
  singleDayEvents.forEach((event) => {
8972
11065
  const eventDate = dateFns.parseISO(event.startDate);
@@ -9431,16 +11524,16 @@ function EventDialog({
9431
11524
  defaultUserId
9432
11525
  }) {
9433
11526
  const { addEvent, updateEvent, deleteEvent, users } = useEventCalendar();
9434
- const [title, setTitle] = React17__namespace.useState("");
9435
- const [description, setDescription] = React17__namespace.useState("");
9436
- const [startDate, setStartDate] = React17__namespace.useState("");
9437
- const [startTime, setStartTime] = React17__namespace.useState("");
9438
- const [endDate, setEndDate] = React17__namespace.useState("");
9439
- const [endTime, setEndTime] = React17__namespace.useState("");
9440
- const [color, setColor] = React17__namespace.useState("blue");
9441
- const [userId, setUserId] = React17__namespace.useState("");
9442
- const [isSubmitting, setIsSubmitting] = React17__namespace.useState(false);
9443
- React17__namespace.useEffect(() => {
11527
+ const [title, setTitle] = React22__namespace.useState("");
11528
+ const [description, setDescription] = React22__namespace.useState("");
11529
+ const [startDate, setStartDate] = React22__namespace.useState("");
11530
+ const [startTime, setStartTime] = React22__namespace.useState("");
11531
+ const [endDate, setEndDate] = React22__namespace.useState("");
11532
+ const [endTime, setEndTime] = React22__namespace.useState("");
11533
+ const [color, setColor] = React22__namespace.useState("blue");
11534
+ const [userId, setUserId] = React22__namespace.useState("");
11535
+ const [isSubmitting, setIsSubmitting] = React22__namespace.useState(false);
11536
+ React22__namespace.useEffect(() => {
9444
11537
  if (open) {
9445
11538
  if (mode === "edit" && event) {
9446
11539
  const start = dateFns.parseISO(event.startDate);
@@ -9663,7 +11756,7 @@ function QuickAddEvent({
9663
11756
  onOpenDialog,
9664
11757
  onClose
9665
11758
  }) {
9666
- const [title, setTitle] = React17__namespace.useState("");
11759
+ const [title, setTitle] = React22__namespace.useState("");
9667
11760
  const { users } = useEventCalendar();
9668
11761
  const handleSubmit = (e) => {
9669
11762
  e.preventDefault();
@@ -9730,8 +11823,8 @@ var HOUR_OPTIONS = Array.from({ length: 25 }, (_, i) => {
9730
11823
  });
9731
11824
  function ChangeVisibleHoursInput() {
9732
11825
  const { visibleHours, setVisibleHours } = useEventCalendar();
9733
- const [from, setFrom] = React17__namespace.useState(visibleHours.from);
9734
- const [to, setTo] = React17__namespace.useState(visibleHours.to);
11826
+ const [from, setFrom] = React22__namespace.useState(visibleHours.from);
11827
+ const [to, setTo] = React22__namespace.useState(visibleHours.to);
9735
11828
  const handleApply = () => {
9736
11829
  const toHour = to === 0 ? 24 : to;
9737
11830
  setVisibleHours({ from, to: toHour });
@@ -9777,7 +11870,7 @@ var HOUR_OPTIONS2 = Array.from({ length: 25 }, (_, i) => {
9777
11870
  });
9778
11871
  function ChangeWorkingHoursInput() {
9779
11872
  const { workingHours, setWorkingHours } = useEventCalendar();
9780
- const [localWorkingHours, setLocalWorkingHours] = React17__namespace.useState({
11873
+ const [localWorkingHours, setLocalWorkingHours] = React22__namespace.useState({
9781
11874
  ...workingHours
9782
11875
  });
9783
11876
  const handleToggleDay = (dayId) => {
@@ -9926,8 +12019,8 @@ function CalendarSettingsButton({
9926
12019
  );
9927
12020
  }
9928
12021
  function useMediaQuery(query) {
9929
- const [matches, setMatches] = React17__namespace.useState(false);
9930
- React17__namespace.useEffect(() => {
12022
+ const [matches, setMatches] = React22__namespace.useState(false);
12023
+ React22__namespace.useEffect(() => {
9931
12024
  const media = window.matchMedia(query);
9932
12025
  setMatches(media.matches);
9933
12026
  const listener = (event) => {
@@ -9979,11 +12072,11 @@ function BigCalendarInner({
9979
12072
  maxEventsPerDay
9980
12073
  }) {
9981
12074
  const { view, setView } = useEventCalendar();
9982
- const [dialogOpen, setDialogOpen] = React17__namespace.useState(false);
9983
- const [settingsDialogOpen, setSettingsDialogOpen] = React17__namespace.useState(false);
9984
- const [selectedEvent, setSelectedEvent] = React17__namespace.useState(null);
9985
- const [dialogMode, setDialogMode] = React17__namespace.useState("add");
9986
- const [defaultDate, setDefaultDate] = React17__namespace.useState(/* @__PURE__ */ new Date());
12075
+ const [dialogOpen, setDialogOpen] = React22__namespace.useState(false);
12076
+ const [settingsDialogOpen, setSettingsDialogOpen] = React22__namespace.useState(false);
12077
+ const [selectedEvent, setSelectedEvent] = React22__namespace.useState(null);
12078
+ const [dialogMode, setDialogMode] = React22__namespace.useState("add");
12079
+ const [defaultDate, setDefaultDate] = React22__namespace.useState(/* @__PURE__ */ new Date());
9987
12080
  const isMobile = useMediaQuery("(max-width: 768px)");
9988
12081
  const isCompact = compact === "auto" ? isMobile : compact;
9989
12082
  const handleAddClick = () => {
@@ -10239,6 +12332,9 @@ exports.CalendarHeaderCompact = CalendarHeaderCompact;
10239
12332
  exports.CalendarSettingsButton = CalendarSettingsButton;
10240
12333
  exports.CalendarSettingsContent = CalendarSettingsContent;
10241
12334
  exports.CalendarSettingsDialog = CalendarSettingsDialog;
12335
+ exports.CalibrationTable = CalibrationTable;
12336
+ exports.CalibrationWeekCell = CalibrationWeekCell;
12337
+ exports.CalibrationWeekHeader = CalibrationWeekHeader;
10242
12338
  exports.Card = Card;
10243
12339
  exports.CardContent = CardContent;
10244
12340
  exports.CardDescription = CardDescription;
@@ -10260,6 +12356,7 @@ exports.ChartStyle = ChartStyle;
10260
12356
  exports.ChartTooltip = ChartTooltip;
10261
12357
  exports.ChartTooltipContent = ChartTooltipContent;
10262
12358
  exports.Checkbox = Checkbox;
12359
+ exports.CircularProgress = CircularProgress;
10263
12360
  exports.Collapsible = Collapsible;
10264
12361
  exports.CollapsibleContent = CollapsibleContent2;
10265
12362
  exports.CollapsibleTrigger = CollapsibleTrigger2;
@@ -10272,6 +12369,9 @@ exports.CommandItem = CommandItem;
10272
12369
  exports.CommandList = CommandList;
10273
12370
  exports.CommandSeparator = CommandSeparator;
10274
12371
  exports.CommandShortcut = CommandShortcut;
12372
+ exports.CommentButton = CommentButton;
12373
+ exports.CommentDialog = CommentDialog;
12374
+ exports.CommentPopover = CommentPopover;
10275
12375
  exports.ContextMenu = ContextMenu;
10276
12376
  exports.ContextMenuCheckboxItem = ContextMenuCheckboxItem;
10277
12377
  exports.ContextMenuContent = ContextMenuContent;
@@ -10418,6 +12518,7 @@ exports.NavigationMenuLink = NavigationMenuLink;
10418
12518
  exports.NavigationMenuList = NavigationMenuList;
10419
12519
  exports.NavigationMenuTrigger = NavigationMenuTrigger;
10420
12520
  exports.NavigationMenuViewport = NavigationMenuViewport;
12521
+ exports.NetBadge = NetBadge;
10421
12522
  exports.Pagination = Pagination;
10422
12523
  exports.PaginationContent = PaginationContent;
10423
12524
  exports.PaginationEllipsis = PaginationEllipsis;
@@ -10427,6 +12528,7 @@ exports.PaginationNext = PaginationNext;
10427
12528
  exports.PaginationPrevious = PaginationPrevious;
10428
12529
  exports.PlanningTable = PlanningTable;
10429
12530
  exports.PlanningTableToolbar = PlanningTableToolbar;
12531
+ exports.PlanningWeekCommentPopover = PlanningWeekCommentPopover;
10430
12532
  exports.PlayerCanvas = PlayerCanvas;
10431
12533
  exports.PlayerCanvasActionButton = PlayerCanvasActionButton;
10432
12534
  exports.PlayerCanvasControls = PlayerCanvasControls;
@@ -10448,6 +12550,7 @@ exports.RadioGroupItem = RadioGroupItem;
10448
12550
  exports.ResizableHandle = ResizableHandle;
10449
12551
  exports.ResizablePanel = ResizablePanel;
10450
12552
  exports.ResizablePanelGroup = ResizablePanelGroup;
12553
+ exports.RowHeaderCell = RowHeaderCell;
10451
12554
  exports.ScrollArea = ScrollArea;
10452
12555
  exports.ScrollBar = ScrollBar;
10453
12556
  exports.SearchForm = SearchForm;
@@ -10505,6 +12608,7 @@ exports.SiteHeader = SiteHeader;
10505
12608
  exports.Skeleton = Skeleton;
10506
12609
  exports.Slider = Slider;
10507
12610
  exports.Spinner = Spinner;
12611
+ exports.SubmitCalibrationBar = SubmitCalibrationBar;
10508
12612
  exports.SupplierCell = SupplierCell;
10509
12613
  exports.Switch = Switch;
10510
12614
  exports.Table = Table;
@@ -10544,21 +12648,27 @@ exports.YearView = YearView;
10544
12648
  exports.badgeVariants = badgeVariants;
10545
12649
  exports.buttonGroupVariants = buttonGroupVariants;
10546
12650
  exports.buttonVariants = buttonVariants;
12651
+ exports.calculateCalibrationCells = calculateCalibrationCells;
10547
12652
  exports.calculateDropDates = calculateDropDates;
10548
12653
  exports.calculateMonthEventPositions = calculateMonthEventPositions;
12654
+ exports.canSubmitCalibration = canSubmitCalibration;
10549
12655
  exports.cardVariants = cardVariants;
10550
12656
  exports.createDefaultEvent = createDefaultEvent;
10551
12657
  exports.deliveryIndicatorVariants = deliveryIndicatorVariants;
12658
+ exports.formatCalibrationUnit = formatCalibrationUnit;
10552
12659
  exports.formatDateRange = formatDateRange2;
10553
12660
  exports.formatProductionUnit = formatProductionUnit;
10554
12661
  exports.formatTime = formatTime;
10555
12662
  exports.generateColumns = generateColumns;
10556
12663
  exports.generateEventId = generateEventId;
12664
+ exports.generateLocationOptions = generateLocationOptions;
10557
12665
  exports.generateWeekColumns = generateWeekColumns;
10558
12666
  exports.generateWeeks = generateWeeks;
10559
12667
  exports.getCalendarCells = getCalendarCells;
12668
+ exports.getCommentLocationLabel = getCommentLocationLabel;
10560
12669
  exports.getCurrentEvents = getCurrentEvents;
10561
12670
  exports.getDayHours = getDayHours;
12671
+ exports.getElementShipmentStatus = getElementShipmentStatus;
10562
12672
  exports.getEventBlockStyle = getEventBlockStyle;
10563
12673
  exports.getEventDuration = getEventDuration;
10564
12674
  exports.getEventDurationMinutes = getEventDurationMinutes;
@@ -10569,6 +12679,7 @@ exports.getHeaderLabel = getHeaderLabel;
10569
12679
  exports.getISOWeek = getISOWeek;
10570
12680
  exports.getMonthCellEvents = getMonthCellEvents;
10571
12681
  exports.getMonthDays = getMonthDays;
12682
+ exports.getShipmentStatusLabel = getShipmentStatusLabel;
10572
12683
  exports.getSupplierColumn = getSupplierColumn;
10573
12684
  exports.getTimeHeight = getTimeHeight;
10574
12685
  exports.getTimePosition = getTimePosition;