@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.js CHANGED
@@ -1,4 +1,4 @@
1
- import * as React17 from 'react';
1
+ import * as React22 from 'react';
2
2
  import { useMemo } from 'react';
3
3
  import { Slot } from '@radix-ui/react-slot';
4
4
  import { cva } from 'class-variance-authority';
@@ -7,7 +7,7 @@ import { twMerge } from 'tailwind-merge';
7
7
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
8
8
  import * as SeparatorPrimitive from '@radix-ui/react-separator';
9
9
  import * as CheckboxPrimitive from '@radix-ui/react-checkbox';
10
- import { SearchIcon, CheckIcon, CircleIcon, ChevronDownIcon, ChevronUpIcon, ChevronRightIcon, ChevronLeftIcon, ArrowLeft, ArrowRight, Loader2Icon, OctagonXIcon, TriangleAlertIcon, InfoIcon, CircleCheckIcon, ChevronRight, MoreHorizontal, MoreHorizontalIcon, XIcon, GripVerticalIcon, PanelLeftIcon, ArrowDown, ArrowUp, ChevronsUpDown, EyeOff, ChevronsLeft, ChevronLeft, ChevronsRight, Settings2, FolderIcon, ShareIcon, TrashIcon, ChevronsUpDownIcon, SparklesIcon, BadgeCheckIcon, CreditCardIcon, BellIcon, LogOutIcon, X, Factory, Truck, Calendar as Calendar$1, Package, AlertTriangle, User, Clock, CalendarX2, List, Columns, Grid2x2, Grid3x3, CalendarRange, Settings, Plus, Info, Moon, ArrowUpDown, ChevronDown, CheckCircle2, XCircle } from 'lucide-react';
10
+ import { SearchIcon, CheckIcon, CircleIcon, ChevronDownIcon, ChevronUpIcon, ChevronRightIcon, ChevronLeftIcon, ArrowLeft, ArrowRight, Check, Loader2Icon, OctagonXIcon, TriangleAlertIcon, InfoIcon, CircleCheckIcon, ChevronRight, MoreHorizontal, MoreHorizontalIcon, XIcon, GripVerticalIcon, PanelLeftIcon, ArrowDown, ArrowUp, ChevronsUpDown, EyeOff, ChevronsLeft, ChevronLeft, ChevronsRight, Settings2, FolderIcon, ShareIcon, TrashIcon, ChevronsUpDownIcon, SparklesIcon, BadgeCheckIcon, CreditCardIcon, BellIcon, LogOutIcon, X, Flag, Factory, Truck, MessageSquare, ChevronDown, Plus, Send, MessageSquarePlus, AlertTriangle, CheckCircle, Calendar as Calendar$1, User, Clock, CalendarX2, List, Columns, Grid2x2, Grid3x3, CalendarRange, Settings, Info, Moon, ArrowUpDown, CheckCircle2, XCircle, Package } from 'lucide-react';
11
11
  import * as RadioGroupPrimitive from '@radix-ui/react-radio-group';
12
12
  import * as SwitchPrimitive from '@radix-ui/react-switch';
13
13
  import * as SliderPrimitive from '@radix-ui/react-slider';
@@ -47,8 +47,8 @@ export { areIntervalsOverlapping, format, getDay, isSameDay, isSameMonth, isToda
47
47
  // src/hooks/use-mobile.ts
48
48
  var MOBILE_BREAKPOINT = 768;
49
49
  function useIsMobile() {
50
- const [isMobile, setIsMobile] = React17.useState(void 0);
51
- React17.useEffect(() => {
50
+ const [isMobile, setIsMobile] = React22.useState(void 0);
51
+ React22.useEffect(() => {
52
52
  const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);
53
53
  const onChange = () => {
54
54
  setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
@@ -89,7 +89,7 @@ var buttonVariants = cva(
89
89
  }
90
90
  }
91
91
  );
92
- var Button = React17.forwardRef(
92
+ var Button = React22.forwardRef(
93
93
  ({ className, variant, size, asChild = false, ...props }, ref) => {
94
94
  const Comp = asChild ? Slot : "button";
95
95
  return /* @__PURE__ */ jsx(
@@ -453,7 +453,7 @@ function Slider({
453
453
  max = 100,
454
454
  ...props
455
455
  }) {
456
- const _values = React17.useMemo(
456
+ const _values = React22.useMemo(
457
457
  () => Array.isArray(value) ? value : Array.isArray(defaultValue) ? defaultValue : [min, max],
458
458
  [value, defaultValue, min, max]
459
459
  );
@@ -739,7 +739,7 @@ function Toggle({
739
739
  }
740
740
  );
741
741
  }
742
- var ToggleGroupContext = React17.createContext({
742
+ var ToggleGroupContext = React22.createContext({
743
743
  size: "default",
744
744
  variant: "default",
745
745
  spacing: 0
@@ -776,7 +776,7 @@ function ToggleGroupItem({
776
776
  size,
777
777
  ...props
778
778
  }) {
779
- const context = React17.useContext(ToggleGroupContext);
779
+ const context = React22.useContext(ToggleGroupContext);
780
780
  return /* @__PURE__ */ jsx(
781
781
  ToggleGroupPrimitive.Item,
782
782
  {
@@ -806,7 +806,7 @@ function ThemeSwitch({
806
806
  className,
807
807
  size = "default"
808
808
  }) {
809
- const [isChecked, setIsChecked] = React17.useState(defaultChecked);
809
+ const [isChecked, setIsChecked] = React22.useState(defaultChecked);
810
810
  const isControlled = checked !== void 0;
811
811
  const currentChecked = isControlled ? checked : isChecked;
812
812
  const handleClick = () => {
@@ -1226,7 +1226,7 @@ function Label2({
1226
1226
  );
1227
1227
  }
1228
1228
  var Form = FormProvider;
1229
- var FormFieldContext = React17.createContext(
1229
+ var FormFieldContext = React22.createContext(
1230
1230
  {}
1231
1231
  );
1232
1232
  var FormField = ({
@@ -1235,8 +1235,8 @@ var FormField = ({
1235
1235
  return /* @__PURE__ */ jsx(FormFieldContext.Provider, { value: { name: props.name }, children: /* @__PURE__ */ jsx(Controller, { ...props }) });
1236
1236
  };
1237
1237
  var useFormField = () => {
1238
- const fieldContext = React17.useContext(FormFieldContext);
1239
- const itemContext = React17.useContext(FormItemContext);
1238
+ const fieldContext = React22.useContext(FormFieldContext);
1239
+ const itemContext = React22.useContext(FormItemContext);
1240
1240
  const { getFieldState } = useFormContext();
1241
1241
  const formState = useFormState({ name: fieldContext.name });
1242
1242
  const fieldState = getFieldState(fieldContext.name, formState);
@@ -1253,11 +1253,11 @@ var useFormField = () => {
1253
1253
  ...fieldState
1254
1254
  };
1255
1255
  };
1256
- var FormItemContext = React17.createContext(
1256
+ var FormItemContext = React22.createContext(
1257
1257
  {}
1258
1258
  );
1259
1259
  function FormItem({ className, ...props }) {
1260
- const id = React17.useId();
1260
+ const id = React22.useId();
1261
1261
  return /* @__PURE__ */ jsx(FormItemContext.Provider, { value: { id }, children: /* @__PURE__ */ jsx(
1262
1262
  "div",
1263
1263
  {
@@ -2359,8 +2359,8 @@ function CalendarDayButton({
2359
2359
  modifiers,
2360
2360
  ...props
2361
2361
  }) {
2362
- const ref = React17.useRef(null);
2363
- React17.useEffect(() => {
2362
+ const ref = React22.useRef(null);
2363
+ React22.useEffect(() => {
2364
2364
  if (modifiers.focused) ref.current?.focus();
2365
2365
  }, [modifiers.focused]);
2366
2366
  return /* @__PURE__ */ jsx(
@@ -2381,9 +2381,9 @@ function CalendarDayButton({
2381
2381
  }
2382
2382
  );
2383
2383
  }
2384
- var CarouselContext = React17.createContext(null);
2384
+ var CarouselContext = React22.createContext(null);
2385
2385
  function useCarousel() {
2386
- const context = React17.useContext(CarouselContext);
2386
+ const context = React22.useContext(CarouselContext);
2387
2387
  if (!context) {
2388
2388
  throw new Error("useCarousel must be used within a <Carousel />");
2389
2389
  }
@@ -2405,20 +2405,20 @@ function Carousel({
2405
2405
  },
2406
2406
  plugins
2407
2407
  );
2408
- const [canScrollPrev, setCanScrollPrev] = React17.useState(false);
2409
- const [canScrollNext, setCanScrollNext] = React17.useState(false);
2410
- const onSelect = React17.useCallback((api2) => {
2408
+ const [canScrollPrev, setCanScrollPrev] = React22.useState(false);
2409
+ const [canScrollNext, setCanScrollNext] = React22.useState(false);
2410
+ const onSelect = React22.useCallback((api2) => {
2411
2411
  if (!api2) return;
2412
2412
  setCanScrollPrev(api2.canScrollPrev());
2413
2413
  setCanScrollNext(api2.canScrollNext());
2414
2414
  }, []);
2415
- const scrollPrev = React17.useCallback(() => {
2415
+ const scrollPrev = React22.useCallback(() => {
2416
2416
  api?.scrollPrev();
2417
2417
  }, [api]);
2418
- const scrollNext = React17.useCallback(() => {
2418
+ const scrollNext = React22.useCallback(() => {
2419
2419
  api?.scrollNext();
2420
2420
  }, [api]);
2421
- const handleKeyDown = React17.useCallback(
2421
+ const handleKeyDown = React22.useCallback(
2422
2422
  (event) => {
2423
2423
  if (event.key === "ArrowLeft") {
2424
2424
  event.preventDefault();
@@ -2430,11 +2430,11 @@ function Carousel({
2430
2430
  },
2431
2431
  [scrollPrev, scrollNext]
2432
2432
  );
2433
- React17.useEffect(() => {
2433
+ React22.useEffect(() => {
2434
2434
  if (!api || !setApi) return;
2435
2435
  setApi(api);
2436
2436
  }, [api, setApi]);
2437
- React17.useEffect(() => {
2437
+ React22.useEffect(() => {
2438
2438
  if (!api) return;
2439
2439
  onSelect(api);
2440
2440
  api.on("reInit", onSelect);
@@ -2567,9 +2567,9 @@ function CarouselNext({
2567
2567
  );
2568
2568
  }
2569
2569
  var THEMES = { light: "", dark: ".dark" };
2570
- var ChartContext = React17.createContext(null);
2570
+ var ChartContext = React22.createContext(null);
2571
2571
  function useChart() {
2572
- const context = React17.useContext(ChartContext);
2572
+ const context = React22.useContext(ChartContext);
2573
2573
  if (!context) {
2574
2574
  throw new Error("useChart must be used within a <ChartContainer />");
2575
2575
  }
@@ -2582,7 +2582,7 @@ function ChartContainer({
2582
2582
  config,
2583
2583
  ...props
2584
2584
  }) {
2585
- const uniqueId = React17.useId();
2585
+ const uniqueId = React22.useId();
2586
2586
  const chartId = `chart-${id || uniqueId.replace(/:/g, "")}`;
2587
2587
  return /* @__PURE__ */ jsx(ChartContext.Provider, { value: { config }, children: /* @__PURE__ */ jsxs(
2588
2588
  "div",
@@ -2643,7 +2643,7 @@ function ChartTooltipContent({
2643
2643
  labelKey
2644
2644
  }) {
2645
2645
  const { config } = useChart();
2646
- const tooltipLabel = React17.useMemo(() => {
2646
+ const tooltipLabel = React22.useMemo(() => {
2647
2647
  if (hideLabel || !payload?.length) {
2648
2648
  return null;
2649
2649
  }
@@ -3299,6 +3299,105 @@ function Progress({
3299
3299
  }
3300
3300
  );
3301
3301
  }
3302
+ function CircularProgress({
3303
+ className,
3304
+ value,
3305
+ size = 80,
3306
+ strokeWidth = 8,
3307
+ variant = "default",
3308
+ showCheckmark = true,
3309
+ children,
3310
+ ...props
3311
+ }) {
3312
+ const clampedValue = Math.min(100, Math.max(0, value));
3313
+ const isComplete = clampedValue >= 100;
3314
+ const radius = (size - strokeWidth) / 2;
3315
+ const circumference = 2 * Math.PI * radius;
3316
+ const strokeDashoffset = circumference - clampedValue / 100 * circumference;
3317
+ const center = size / 2;
3318
+ const getVariantColors = () => {
3319
+ switch (variant) {
3320
+ case "success":
3321
+ return {
3322
+ track: "stroke-green-500/20",
3323
+ progress: "stroke-green-500",
3324
+ text: "text-green-600 dark:text-green-400"
3325
+ };
3326
+ case "warning":
3327
+ return {
3328
+ track: "stroke-amber-500/20",
3329
+ progress: "stroke-amber-500",
3330
+ text: "text-amber-600 dark:text-amber-400"
3331
+ };
3332
+ case "destructive":
3333
+ return {
3334
+ track: "stroke-red-500/20",
3335
+ progress: "stroke-red-500",
3336
+ text: "text-red-600 dark:text-red-400"
3337
+ };
3338
+ default:
3339
+ return {
3340
+ track: "stroke-primary/20",
3341
+ progress: "stroke-primary",
3342
+ text: "text-primary"
3343
+ };
3344
+ }
3345
+ };
3346
+ const colors = getVariantColors();
3347
+ return /* @__PURE__ */ jsxs(
3348
+ "div",
3349
+ {
3350
+ "data-slot": "circular-progress",
3351
+ "data-value": clampedValue,
3352
+ "data-complete": isComplete,
3353
+ className: cn("relative inline-flex items-center justify-center", className),
3354
+ style: { width: size, height: size },
3355
+ ...props,
3356
+ children: [
3357
+ /* @__PURE__ */ jsxs(
3358
+ "svg",
3359
+ {
3360
+ className: "transform -rotate-90",
3361
+ width: size,
3362
+ height: size,
3363
+ viewBox: `0 0 ${size} ${size}`,
3364
+ children: [
3365
+ /* @__PURE__ */ jsx(
3366
+ "circle",
3367
+ {
3368
+ className: cn("transition-all", colors.track),
3369
+ cx: center,
3370
+ cy: center,
3371
+ r: radius,
3372
+ fill: "none",
3373
+ strokeWidth
3374
+ }
3375
+ ),
3376
+ /* @__PURE__ */ jsx(
3377
+ "circle",
3378
+ {
3379
+ className: cn("transition-all duration-300 ease-out", colors.progress),
3380
+ cx: center,
3381
+ cy: center,
3382
+ r: radius,
3383
+ fill: "none",
3384
+ strokeWidth,
3385
+ strokeLinecap: "round",
3386
+ strokeDasharray: circumference,
3387
+ strokeDashoffset
3388
+ }
3389
+ )
3390
+ ]
3391
+ }
3392
+ ),
3393
+ /* @__PURE__ */ jsx("div", { className: "absolute inset-0 flex items-center justify-center", children: children ? children : isComplete && showCheckmark ? /* @__PURE__ */ jsx(Check, { className: cn("h-6 w-6", colors.text) }) : /* @__PURE__ */ jsxs("span", { className: cn("text-sm font-semibold tabular-nums", colors.text), children: [
3394
+ Math.round(clampedValue),
3395
+ "%"
3396
+ ] }) })
3397
+ ]
3398
+ }
3399
+ );
3400
+ }
3302
3401
  function TooltipProvider({
3303
3402
  delayDuration = 0,
3304
3403
  ...props
@@ -3346,8 +3445,8 @@ function TooltipContent({
3346
3445
  ) });
3347
3446
  }
3348
3447
  function useDetectTheme() {
3349
- const [theme, setTheme] = React17.useState("light");
3350
- React17.useEffect(() => {
3448
+ const [theme, setTheme] = React22.useState("light");
3449
+ React22.useEffect(() => {
3351
3450
  const isDark = document.documentElement.classList.contains("dark");
3352
3451
  setTheme(isDark ? "dark" : "light");
3353
3452
  const observer = new MutationObserver((mutations) => {
@@ -3996,7 +4095,7 @@ function CommandShortcut({
3996
4095
  }
3997
4096
  );
3998
4097
  }
3999
- var SearchTrigger = React17.forwardRef(
4098
+ var SearchTrigger = React22.forwardRef(
4000
4099
  ({
4001
4100
  className,
4002
4101
  placeholder = "Search...",
@@ -4032,7 +4131,7 @@ var SearchTrigger = React17.forwardRef(
4032
4131
  );
4033
4132
  SearchTrigger.displayName = "SearchTrigger";
4034
4133
  function useSearchShortcut(onOpen, key = "k") {
4035
- React17.useEffect(() => {
4134
+ React22.useEffect(() => {
4036
4135
  const down = (e) => {
4037
4136
  if (e.key.toLowerCase() === key.toLowerCase() && (e.metaKey || e.ctrlKey)) {
4038
4137
  e.preventDefault();
@@ -5007,9 +5106,9 @@ var SIDEBAR_WIDTH = "16rem";
5007
5106
  var SIDEBAR_WIDTH_MOBILE = "18rem";
5008
5107
  var SIDEBAR_WIDTH_ICON = "3rem";
5009
5108
  var SIDEBAR_KEYBOARD_SHORTCUT = "b";
5010
- var SidebarContext = React17.createContext(null);
5109
+ var SidebarContext = React22.createContext(null);
5011
5110
  function useSidebar() {
5012
- const context = React17.useContext(SidebarContext);
5111
+ const context = React22.useContext(SidebarContext);
5013
5112
  if (!context) {
5014
5113
  throw new Error("useSidebar must be used within a SidebarProvider.");
5015
5114
  }
@@ -5025,10 +5124,10 @@ function SidebarProvider({
5025
5124
  ...props
5026
5125
  }) {
5027
5126
  const isMobile = useIsMobile();
5028
- const [openMobile, setOpenMobile] = React17.useState(false);
5029
- const [_open, _setOpen] = React17.useState(defaultOpen);
5127
+ const [openMobile, setOpenMobile] = React22.useState(false);
5128
+ const [_open, _setOpen] = React22.useState(defaultOpen);
5030
5129
  const open = openProp ?? _open;
5031
- const setOpen = React17.useCallback(
5130
+ const setOpen = React22.useCallback(
5032
5131
  (value) => {
5033
5132
  const openState = typeof value === "function" ? value(open) : value;
5034
5133
  if (setOpenProp) {
@@ -5040,10 +5139,10 @@ function SidebarProvider({
5040
5139
  },
5041
5140
  [setOpenProp, open]
5042
5141
  );
5043
- const toggleSidebar = React17.useCallback(() => {
5142
+ const toggleSidebar = React22.useCallback(() => {
5044
5143
  return isMobile ? setOpenMobile((open2) => !open2) : setOpen((open2) => !open2);
5045
5144
  }, [isMobile, setOpen, setOpenMobile]);
5046
- React17.useEffect(() => {
5145
+ React22.useEffect(() => {
5047
5146
  const handleKeyDown = (event) => {
5048
5147
  if (event.key === SIDEBAR_KEYBOARD_SHORTCUT && (event.metaKey || event.ctrlKey)) {
5049
5148
  event.preventDefault();
@@ -5054,7 +5153,7 @@ function SidebarProvider({
5054
5153
  return () => window.removeEventListener("keydown", handleKeyDown);
5055
5154
  }, [toggleSidebar]);
5056
5155
  const state = open ? "expanded" : "collapsed";
5057
- const contextValue = React17.useMemo(
5156
+ const contextValue = React22.useMemo(
5058
5157
  () => ({
5059
5158
  state,
5060
5159
  open,
@@ -5512,7 +5611,7 @@ function SidebarMenuSkeleton({
5512
5611
  showIcon = false,
5513
5612
  ...props
5514
5613
  }) {
5515
- const width = React17.useMemo(() => {
5614
+ const width = React22.useMemo(() => {
5516
5615
  return `${Math.floor(Math.random() * 40) + 50}%`;
5517
5616
  }, []);
5518
5617
  return /* @__PURE__ */ jsxs(
@@ -5655,7 +5754,7 @@ var sectionVariants = cva(
5655
5754
  }
5656
5755
  );
5657
5756
  var isGlassVariant = (variant) => variant?.startsWith("glass-") ?? false;
5658
- var Section = React17.forwardRef(
5757
+ var Section = React22.forwardRef(
5659
5758
  ({ className, variant, ...props }, ref) => /* @__PURE__ */ jsx(
5660
5759
  "section",
5661
5760
  {
@@ -5667,7 +5766,7 @@ var Section = React17.forwardRef(
5667
5766
  )
5668
5767
  );
5669
5768
  Section.displayName = "Section";
5670
- var SectionHeader = React17.forwardRef(
5769
+ var SectionHeader = React22.forwardRef(
5671
5770
  ({ className, ...props }, ref) => /* @__PURE__ */ jsx(
5672
5771
  "div",
5673
5772
  {
@@ -5682,7 +5781,7 @@ var SectionHeader = React17.forwardRef(
5682
5781
  )
5683
5782
  );
5684
5783
  SectionHeader.displayName = "SectionHeader";
5685
- var SectionTitle = React17.forwardRef(
5784
+ var SectionTitle = React22.forwardRef(
5686
5785
  ({ className, ...props }, ref) => /* @__PURE__ */ jsx(
5687
5786
  "h2",
5688
5787
  {
@@ -5696,7 +5795,7 @@ var SectionTitle = React17.forwardRef(
5696
5795
  )
5697
5796
  );
5698
5797
  SectionTitle.displayName = "SectionTitle";
5699
- var SectionDescription = React17.forwardRef(
5798
+ var SectionDescription = React22.forwardRef(
5700
5799
  ({ className, ...props }, ref) => /* @__PURE__ */ jsx(
5701
5800
  "p",
5702
5801
  {
@@ -5710,7 +5809,7 @@ var SectionDescription = React17.forwardRef(
5710
5809
  )
5711
5810
  );
5712
5811
  SectionDescription.displayName = "SectionDescription";
5713
- var SectionContent = React17.forwardRef(
5812
+ var SectionContent = React22.forwardRef(
5714
5813
  ({ className, ...props }, ref) => /* @__PURE__ */ jsx(
5715
5814
  "div",
5716
5815
  {
@@ -5724,7 +5823,7 @@ var SectionContent = React17.forwardRef(
5724
5823
  )
5725
5824
  );
5726
5825
  SectionContent.displayName = "SectionContent";
5727
- var SectionFooter = React17.forwardRef(
5826
+ var SectionFooter = React22.forwardRef(
5728
5827
  ({ className, ...props }, ref) => /* @__PURE__ */ jsx(
5729
5828
  "div",
5730
5829
  {
@@ -5949,7 +6048,7 @@ function SiteHeader({
5949
6048
  children: /* @__PURE__ */ 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: [
5950
6049
  trigger,
5951
6050
  trigger && /* @__PURE__ */ jsx(Separator, { orientation: "vertical", className: "mr-[var(--j3m-spacing-s)] h-4" }),
5952
- /* @__PURE__ */ jsx(Breadcrumb, { className: "hidden sm:block", children: /* @__PURE__ */ jsx(BreadcrumbList, { children: breadcrumbs.map((item, index) => /* @__PURE__ */ jsxs(React17.Fragment, { children: [
6051
+ /* @__PURE__ */ jsx(Breadcrumb, { className: "hidden sm:block", children: /* @__PURE__ */ jsx(BreadcrumbList, { children: breadcrumbs.map((item, index) => /* @__PURE__ */ jsxs(React22.Fragment, { children: [
5953
6052
  index > 0 && /* @__PURE__ */ jsx(BreadcrumbSeparator, {}),
5954
6053
  /* @__PURE__ */ jsx(BreadcrumbItem, { children: item.href ? /* @__PURE__ */ jsx(BreadcrumbLink, { href: item.href, children: item.label }) : /* @__PURE__ */ jsx(BreadcrumbPage, { children: item.label }) })
5955
6054
  ] }, index)) }) }),
@@ -6137,46 +6236,44 @@ function PlanningTableToolbar({
6137
6236
  );
6138
6237
  }
6139
6238
  function getBadgeVariant(badgeType) {
6140
- const variantMap = {
6141
- Welded: "secondary",
6142
- Painted: "secondary",
6143
- Glazed: "secondary",
6144
- Delivered: "secondary",
6145
- Cured: "secondary",
6146
- Assembled: "secondary",
6147
- Tested: "secondary",
6148
- Sealed: "secondary"
6149
- };
6150
- return variantMap[badgeType] || "secondary";
6239
+ return "outline";
6151
6240
  }
6152
6241
  function SupplierCell({
6153
6242
  className,
6154
6243
  supplier,
6155
6244
  ...props
6156
6245
  }) {
6157
- return /* @__PURE__ */ jsxs(
6246
+ const spacingClasses = "px-[var(--j3m-spacing-xs)] pt-[var(--j3m-spacing-s)] pb-2";
6247
+ return /* @__PURE__ */ jsx(
6158
6248
  "div",
6159
6249
  {
6160
6250
  "data-slot": "supplier-cell",
6161
6251
  className: cn(
6162
- "flex flex-col justify-center gap-1 py-3 px-4 w-[200px] h-[72px]",
6252
+ // Same height as WeekCell (80px) for row alignment
6253
+ "flex flex-col justify-center gap-1.5 min-w-[200px] h-[80px]",
6254
+ // White background for Y-axis legend cells
6255
+ "bg-background",
6256
+ spacingClasses,
6163
6257
  className
6164
6258
  ),
6165
6259
  ...props,
6166
- children: [
6167
- /* @__PURE__ */ jsx("span", { className: "text-sm font-semibold leading-tight text-foreground", children: supplier.name }),
6168
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
6169
- /* @__PURE__ */ jsx(
6170
- Badge,
6171
- {
6172
- variant: getBadgeVariant(supplier.badgeType),
6173
- className: "text-[10px] px-1.5 py-0 h-5 font-normal",
6174
- children: supplier.badgeType
6175
- }
6176
- ),
6260
+ children: /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-2", children: [
6261
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col min-w-0 flex-1", children: [
6262
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-bold leading-tight text-foreground truncate", children: supplier.name }),
6177
6263
  /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: supplier.scope })
6178
- ] })
6179
- ]
6264
+ ] }),
6265
+ /* @__PURE__ */ jsxs(
6266
+ Badge,
6267
+ {
6268
+ variant: getBadgeVariant(supplier.badgeType),
6269
+ className: "text-[10px] px-2 py-0.5 h-[19px] font-medium shrink-0 gap-1 bg-background border-border",
6270
+ children: [
6271
+ /* @__PURE__ */ jsx(Flag, { className: "h-2.5 w-2.5" }),
6272
+ supplier.badgeType
6273
+ ]
6274
+ }
6275
+ )
6276
+ ] })
6180
6277
  }
6181
6278
  );
6182
6279
  }
@@ -6197,18 +6294,18 @@ function getRowStatus(status) {
6197
6294
  if (status === "delayed") return "warning";
6198
6295
  return "normal";
6199
6296
  }
6200
- var riskColorClasses = {
6297
+ var statusFillClasses = {
6201
6298
  normal: {
6202
- border: "border-l-green-500",
6203
- bg: "bg-green-50 dark:bg-green-950/50"
6299
+ border: "border-l-[3px] border-l-green-500",
6300
+ bg: "bg-green-50/50 dark:bg-green-950/30"
6204
6301
  },
6205
6302
  warning: {
6206
- border: "border-l-amber-500",
6207
- bg: "bg-amber-50 dark:bg-amber-950/50"
6303
+ border: "border-l-[3px] border-l-amber-500",
6304
+ bg: "bg-amber-50/50 dark:bg-amber-950/30"
6208
6305
  },
6209
6306
  critical: {
6210
- border: "border-l-red-500",
6211
- bg: "bg-red-50 dark:bg-red-950/50"
6307
+ border: "border-l-[3px] border-l-red-500",
6308
+ bg: "bg-red-50/50 dark:bg-red-950/30"
6212
6309
  }
6213
6310
  };
6214
6311
  var statusColors = {
@@ -6237,6 +6334,24 @@ function WeekCell({
6237
6334
  onCellClick,
6238
6335
  ...props
6239
6336
  }) {
6337
+ const combinedRisk = data.type === "data" ? getCombinedRiskLevel(data) : "normal";
6338
+ const statusClasses = statusFillClasses[combinedRisk];
6339
+ const productionProgress = data.production?.progress ?? data.progress ?? 0;
6340
+ const productionStatus = getRowStatus(data.production?.status);
6341
+ const productionColors = statusColors[productionStatus];
6342
+ const deliveryCount = data.deliveries?.length ?? 0;
6343
+ const worstDeliveryStatus = data.deliveries?.some((d) => d.status === "critical") ? "critical" : data.deliveries?.some((d) => d.status === "delayed") ? "warning" : "normal";
6344
+ const deliveryColors = statusColors[worstDeliveryStatus];
6345
+ const getDeliveryStatusColor = (status) => {
6346
+ switch (status) {
6347
+ case "critical":
6348
+ return "bg-red-500";
6349
+ case "delayed":
6350
+ return "bg-amber-500";
6351
+ default:
6352
+ return "bg-green-500";
6353
+ }
6354
+ };
6240
6355
  const handleClick = () => {
6241
6356
  if (onCellClick && data.type !== "empty") {
6242
6357
  onCellClick();
@@ -6248,14 +6363,7 @@ function WeekCell({
6248
6363
  onCellClick();
6249
6364
  }
6250
6365
  };
6251
- const combinedRisk = data.type === "data" ? getCombinedRiskLevel(data) : "normal";
6252
- const cardColors = riskColorClasses[combinedRisk];
6253
- const productionProgress = data.production?.progress ?? data.progress ?? 0;
6254
- const productionStatus = getRowStatus(data.production?.status);
6255
- const productionColors = statusColors[productionStatus];
6256
- const deliveryCount = data.deliveries?.length ?? 0;
6257
- const worstDeliveryStatus = data.deliveries?.some((d) => d.status === "critical") ? "critical" : data.deliveries?.some((d) => d.status === "delayed") ? "warning" : "normal";
6258
- const deliveryColors = statusColors[worstDeliveryStatus];
6366
+ const spacingClasses = "px-[var(--j3m-spacing-xs)] pt-[var(--j3m-spacing-s)] pb-2";
6259
6367
  if (data.type === "empty") {
6260
6368
  return /* @__PURE__ */ jsx(
6261
6369
  "div",
@@ -6264,8 +6372,9 @@ function WeekCell({
6264
6372
  "data-state": "empty",
6265
6373
  "data-current-week": isCurrentWeek,
6266
6374
  className: cn(
6267
- "flex w-[120px] h-[72px] items-center justify-center cursor-default",
6268
- isCurrentWeek && "bg-primary/5",
6375
+ "flex h-[80px] items-center justify-center cursor-default",
6376
+ "bg-background",
6377
+ spacingClasses,
6269
6378
  className
6270
6379
  ),
6271
6380
  ...props,
@@ -6274,7 +6383,7 @@ function WeekCell({
6274
6383
  );
6275
6384
  }
6276
6385
  if (data.type === "no-logistics") {
6277
- return /* @__PURE__ */ jsx(
6386
+ return /* @__PURE__ */ jsxs(
6278
6387
  "div",
6279
6388
  {
6280
6389
  "data-slot": "week-cell",
@@ -6285,44 +6394,36 @@ function WeekCell({
6285
6394
  role: "button",
6286
6395
  tabIndex: 0,
6287
6396
  className: cn(
6288
- "flex flex-col w-[120px] h-[72px] justify-center p-1",
6289
- "cursor-pointer",
6290
- isCurrentWeek && "bg-primary/5",
6397
+ "flex flex-col h-[80px] justify-center gap-2",
6398
+ "cursor-pointer bg-background",
6399
+ "border-l-[3px] border-l-muted-foreground/30",
6400
+ spacingClasses,
6401
+ // Hover lift effect
6402
+ "transition-all duration-200 ease-out",
6403
+ "hover:-translate-y-0.5 hover:shadow-[var(--j3m-shadow-md)]",
6291
6404
  className
6292
6405
  ),
6293
6406
  ...props,
6294
- children: /* @__PURE__ */ jsxs(
6295
- "div",
6296
- {
6297
- className: cn(
6298
- "flex flex-col w-full h-full justify-center gap-1.5 rounded-md border-l-[3px] px-2 py-1.5",
6299
- "border-l-muted-foreground/30 bg-muted/50",
6300
- // Hover lift effect with shadow
6301
- "transition-all duration-200 ease-out",
6302
- "hover:-translate-y-0.5 hover:shadow-md hover:bg-muted/70"
6303
- ),
6304
- children: [
6305
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
6306
- /* @__PURE__ */ jsx(Factory, { className: "h-3.5 w-3.5 shrink-0 text-muted-foreground" }),
6307
- /* @__PURE__ */ jsx("div", { className: "flex-1 h-1.5 bg-muted-foreground/20 rounded-full overflow-hidden", children: /* @__PURE__ */ jsx(
6308
- "div",
6309
- {
6310
- className: "h-full bg-muted-foreground/40 rounded-full",
6311
- style: { width: `${productionProgress}%` }
6312
- }
6313
- ) })
6314
- ] }),
6315
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 text-muted-foreground", children: [
6316
- /* @__PURE__ */ jsx(Truck, { className: "h-3.5 w-3.5 shrink-0" }),
6317
- /* @__PURE__ */ jsx("span", { className: "text-[10px]", children: "No logistics" })
6318
- ] })
6319
- ]
6320
- }
6321
- )
6407
+ children: [
6408
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
6409
+ /* @__PURE__ */ jsx(Factory, { className: "h-3.5 w-3.5 shrink-0 text-muted-foreground" }),
6410
+ /* @__PURE__ */ jsx("div", { className: "flex-1 h-1.5 bg-muted-foreground/20 rounded-full overflow-hidden", children: /* @__PURE__ */ jsx(
6411
+ "div",
6412
+ {
6413
+ className: "h-full bg-muted-foreground/40 rounded-full",
6414
+ style: { width: `${productionProgress}%` }
6415
+ }
6416
+ ) })
6417
+ ] }),
6418
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-muted-foreground", children: [
6419
+ /* @__PURE__ */ jsx(Truck, { className: "h-3.5 w-3.5 shrink-0" }),
6420
+ /* @__PURE__ */ jsx("span", { className: "text-[10px]", children: "No logistics" })
6421
+ ] })
6422
+ ]
6322
6423
  }
6323
6424
  );
6324
6425
  }
6325
- return /* @__PURE__ */ jsx(
6426
+ return /* @__PURE__ */ jsxs(
6326
6427
  "div",
6327
6428
  {
6328
6429
  "data-slot": "week-cell",
@@ -6334,80 +6435,150 @@ function WeekCell({
6334
6435
  role: "button",
6335
6436
  tabIndex: 0,
6336
6437
  className: cn(
6337
- "flex flex-col w-[120px] h-[72px] justify-center p-1",
6438
+ "flex flex-col h-[80px] justify-center gap-2",
6338
6439
  "cursor-pointer",
6339
- isCurrentWeek && "bg-primary/5",
6440
+ // Edge-to-edge status fill (no inset card)
6441
+ statusClasses.border,
6442
+ statusClasses.bg,
6443
+ spacingClasses,
6444
+ // Hover lift effect
6445
+ "transition-all duration-200 ease-out",
6446
+ "hover:-translate-y-0.5 hover:shadow-[var(--j3m-shadow-md)]",
6340
6447
  className
6341
6448
  ),
6342
6449
  ...props,
6343
- children: /* @__PURE__ */ 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
- cardColors.border,
6349
- cardColors.bg,
6350
- // Hover lift effect with shadow
6351
- "transition-all duration-200 ease-out",
6352
- "hover:-translate-y-0.5 hover:shadow-md"
6353
- ),
6354
- children: [
6355
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
6356
- /* @__PURE__ */ jsx(Factory, { className: cn("h-3.5 w-3.5 shrink-0", productionColors.icon) }),
6357
- /* @__PURE__ */ jsx("div", { className: "flex-1 h-1.5 bg-black/10 dark:bg-white/10 rounded-full overflow-hidden", children: /* @__PURE__ */ jsx(
6358
- "div",
6359
- {
6360
- className: cn("h-full rounded-full transition-all", productionColors.progress),
6361
- style: { width: `${productionProgress}%` }
6362
- }
6363
- ) })
6364
- ] }),
6365
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
6366
- /* @__PURE__ */ jsx(Truck, { className: cn("h-3.5 w-3.5 shrink-0", deliveryColors.icon) }),
6367
- deliveryCount > 0 ? /* @__PURE__ */ jsxs("span", { className: cn("text-[10px] font-medium", deliveryColors.text), children: [
6368
- deliveryCount,
6369
- "x delivery"
6370
- ] }) : /* @__PURE__ */ jsx("span", { className: "text-[10px] text-muted-foreground", children: "\u2014" })
6371
- ] })
6372
- ]
6373
- }
6374
- )
6450
+ children: [
6451
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
6452
+ /* @__PURE__ */ jsx(Factory, { className: cn("h-3.5 w-3.5 shrink-0", productionColors.icon) }),
6453
+ /* @__PURE__ */ jsx("div", { className: "flex-1 h-1.5 bg-black/10 dark:bg-white/10 rounded-full overflow-hidden", children: /* @__PURE__ */ jsx(
6454
+ "div",
6455
+ {
6456
+ className: cn("h-full rounded-full transition-all", productionColors.progress),
6457
+ style: { width: `${productionProgress}%` }
6458
+ }
6459
+ ) })
6460
+ ] }),
6461
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
6462
+ /* @__PURE__ */ jsx(Truck, { className: cn("h-3.5 w-3.5 shrink-0", deliveryColors.icon) }),
6463
+ deliveryCount > 0 ? /* @__PURE__ */ jsxs("span", { className: cn("text-[10px] font-medium", deliveryColors.text), children: [
6464
+ deliveryCount,
6465
+ "x delivery"
6466
+ ] }) : /* @__PURE__ */ jsx("span", { className: "text-[10px] text-muted-foreground", children: "\u2014" })
6467
+ ] }),
6468
+ deliveryCount > 0 && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
6469
+ data.deliveries?.slice(0, 5).map((delivery, index) => {
6470
+ const deliveryProgress = delivery.progress ?? (delivery.status === "on-time" ? 100 : delivery.status === "delayed" ? 50 : 25);
6471
+ return /* @__PURE__ */ jsx(
6472
+ "div",
6473
+ {
6474
+ className: "flex-1 max-w-[24px]",
6475
+ title: delivery.label || `Delivery ${index + 1}`,
6476
+ children: /* @__PURE__ */ jsx("div", { className: "h-1 bg-black/10 dark:bg-white/10 rounded-full overflow-hidden", children: /* @__PURE__ */ jsx(
6477
+ "div",
6478
+ {
6479
+ className: cn("h-full rounded-full transition-all", getDeliveryStatusColor(delivery.status)),
6480
+ style: { width: `${deliveryProgress}%` }
6481
+ }
6482
+ ) })
6483
+ },
6484
+ delivery.id || index
6485
+ );
6486
+ }),
6487
+ deliveryCount > 5 && /* @__PURE__ */ jsxs("span", { className: "text-[8px] text-muted-foreground", children: [
6488
+ "+",
6489
+ deliveryCount - 5
6490
+ ] })
6491
+ ] })
6492
+ ]
6375
6493
  }
6376
6494
  );
6377
6495
  }
6378
- function WeekHeader({
6496
+ function CommentButton({
6379
6497
  className,
6380
- week,
6498
+ commentCount = 0,
6499
+ size = "default",
6381
6500
  ...props
6382
6501
  }) {
6502
+ const hasComments = commentCount > 0;
6503
+ const sizeClasses = size === "sm" ? "h-6 w-6" : "h-7 w-7";
6504
+ const iconSize = size === "sm" ? "h-3.5 w-3.5" : "h-4 w-4";
6383
6505
  return /* @__PURE__ */ jsxs(
6384
- "div",
6506
+ Button,
6385
6507
  {
6386
- "data-slot": "week-header",
6387
- "data-current-week": week.isCurrentWeek,
6508
+ variant: "outline",
6509
+ size: "icon",
6388
6510
  className: cn(
6389
- "flex flex-col justify-center gap-0.5 w-[120px] text-left",
6511
+ sizeClasses,
6512
+ "rounded-full shrink-0 relative",
6513
+ "border-border bg-background hover:bg-muted",
6514
+ "shadow-[var(--j3m-shadow-sm)]",
6515
+ hasComments && "border-primary/50",
6390
6516
  className
6391
6517
  ),
6392
6518
  ...props,
6393
6519
  children: [
6394
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
6395
- /* @__PURE__ */ jsx("span", { className: cn(
6396
- "text-sm font-medium",
6397
- week.isCurrentWeek ? "text-primary" : "text-foreground"
6398
- ), children: week.label }),
6399
- week.isCurrentWeek && /* @__PURE__ */ jsxs("span", { className: "relative flex h-2 w-2", children: [
6400
- /* @__PURE__ */ jsx("span", { className: "animate-ping absolute inline-flex h-full w-full rounded-full bg-primary opacity-75" }),
6401
- /* @__PURE__ */ jsx("span", { className: "relative inline-flex rounded-full h-2 w-2 bg-primary" })
6402
- ] })
6403
- ] }),
6404
- /* @__PURE__ */ jsx("span", { className: "text-[11px] text-muted-foreground whitespace-nowrap", children: week.dateRange })
6520
+ /* @__PURE__ */ jsx(MessageSquare, { className: cn(iconSize, hasComments && "text-primary") }),
6521
+ hasComments && /* @__PURE__ */ jsx(
6522
+ "span",
6523
+ {
6524
+ className: cn(
6525
+ "absolute -top-0.5 -right-0.5",
6526
+ "h-2.5 w-2.5 rounded-full",
6527
+ "bg-primary",
6528
+ "border border-background"
6529
+ // Subtle outline for contrast
6530
+ ),
6531
+ "aria-hidden": "true"
6532
+ }
6533
+ ),
6534
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: hasComments ? `${commentCount} comment${commentCount > 1 ? "s" : ""}` : "Add comment" })
6405
6535
  ]
6406
6536
  }
6407
6537
  );
6408
6538
  }
6409
6539
 
6410
6540
  // src/blocks/planning-table/types.ts
6541
+ function getCommentLocationLabel(location) {
6542
+ if (location.type === "production") {
6543
+ return location.supplierName ? `Production - ${location.supplierName}` : "Production";
6544
+ }
6545
+ if (location.type === "delivery") {
6546
+ return location.deliveryLabel || `Delivery ${location.deliveryId || ""}`;
6547
+ }
6548
+ return "Unknown";
6549
+ }
6550
+ function getElementShipmentStatus(element, currentDeliveryId) {
6551
+ if (element.shipmentStatus) {
6552
+ return element.shipmentStatus;
6553
+ }
6554
+ if (element.isProduced) {
6555
+ if (element.actualDeliveryId && element.actualDeliveryId !== currentDeliveryId) {
6556
+ return "moved";
6557
+ }
6558
+ return "sent";
6559
+ }
6560
+ if (element.originalDeliveryId && element.originalDeliveryId !== currentDeliveryId) {
6561
+ return "addon";
6562
+ }
6563
+ return "not-sent";
6564
+ }
6565
+ function getShipmentStatusLabel(status) {
6566
+ switch (status) {
6567
+ case "sent":
6568
+ return "Sent";
6569
+ case "not-sent":
6570
+ return "Missing";
6571
+ // Neutral tone, not "Not sent"
6572
+ case "moved":
6573
+ return "Moved to another delivery";
6574
+ case "addon":
6575
+ return "Add-on";
6576
+ case "planned":
6577
+ return "Planned";
6578
+ default:
6579
+ return status;
6580
+ }
6581
+ }
6411
6582
  function getWeekKey(date) {
6412
6583
  const year = date.getFullYear();
6413
6584
  const weekNumber = getISOWeek(date);
@@ -6468,18 +6639,325 @@ function formatProductionUnit(unit) {
6468
6639
  };
6469
6640
  return unitLabels[unit] || unit;
6470
6641
  }
6471
- function SupplierColumnHeader({
6472
- column
6642
+ function LocationIcon({ type }) {
6643
+ if (type === "production") {
6644
+ return /* @__PURE__ */ jsx(Factory, { className: "h-3 w-3" });
6645
+ }
6646
+ return /* @__PURE__ */ jsx(Truck, { className: "h-3 w-3" });
6647
+ }
6648
+ function PlanningWeekCommentPopover({
6649
+ comments,
6650
+ weekLabel,
6651
+ weekKey,
6652
+ locationOptions,
6653
+ onAddComment,
6654
+ onCommentClick,
6655
+ open,
6656
+ onOpenChange
6657
+ }) {
6658
+ const [newCommentText, setNewCommentText] = React22.useState("");
6659
+ const [selectedLocationId, setSelectedLocationId] = React22.useState("");
6660
+ const [viewCommentsOpen, setViewCommentsOpen] = React22.useState(true);
6661
+ const [showAddForm, setShowAddForm] = React22.useState(false);
6662
+ const selectedLocation = React22.useMemo(() => {
6663
+ return locationOptions.find((opt) => opt.id === selectedLocationId);
6664
+ }, [locationOptions, selectedLocationId]);
6665
+ const handleSubmit = () => {
6666
+ if (newCommentText.trim() && selectedLocation && onAddComment) {
6667
+ const location = {
6668
+ type: selectedLocation.type,
6669
+ weekKey,
6670
+ supplierId: selectedLocation.supplierId,
6671
+ supplierName: selectedLocation.supplierName,
6672
+ deliveryId: selectedLocation.deliveryId,
6673
+ deliveryLabel: selectedLocation.deliveryLabel
6674
+ };
6675
+ onAddComment(newCommentText.trim(), location);
6676
+ setNewCommentText("");
6677
+ setSelectedLocationId("");
6678
+ setShowAddForm(false);
6679
+ setViewCommentsOpen(true);
6680
+ }
6681
+ };
6682
+ const handleKeyDown = (e) => {
6683
+ if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) {
6684
+ e.preventDefault();
6685
+ handleSubmit();
6686
+ }
6687
+ if (e.key === "Escape") {
6688
+ setShowAddForm(false);
6689
+ setSelectedLocationId("");
6690
+ setNewCommentText("");
6691
+ }
6692
+ };
6693
+ const handleCommentClick = (comment) => {
6694
+ if (comment.location && onCommentClick) {
6695
+ onCommentClick(comment);
6696
+ }
6697
+ };
6698
+ const formatDate2 = (date) => {
6699
+ return new Intl.DateTimeFormat("en-US", {
6700
+ month: "short",
6701
+ day: "numeric",
6702
+ hour: "numeric",
6703
+ minute: "2-digit"
6704
+ }).format(date);
6705
+ };
6706
+ const prevOpenRef = React22.useRef(open);
6707
+ React22.useEffect(() => {
6708
+ const wasOpen = prevOpenRef.current;
6709
+ prevOpenRef.current = open;
6710
+ if (wasOpen && !open) {
6711
+ setShowAddForm(false);
6712
+ setNewCommentText("");
6713
+ setSelectedLocationId("");
6714
+ }
6715
+ }, [open]);
6716
+ return /* @__PURE__ */ jsxs(Popover, { open, onOpenChange, children: [
6717
+ /* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx(CommentButton, { size: "sm", commentCount: comments.length }) }),
6718
+ /* @__PURE__ */ jsxs(
6719
+ PopoverContent,
6720
+ {
6721
+ className: "w-80 p-0 z-[100]",
6722
+ align: "end",
6723
+ sideOffset: 8,
6724
+ collisionPadding: 16,
6725
+ children: [
6726
+ /* @__PURE__ */ jsxs("div", { className: "px-4 py-3 border-b border-border", children: [
6727
+ /* @__PURE__ */ jsx("h4", { className: "text-sm font-semibold", children: "Comments" }),
6728
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: weekLabel })
6729
+ ] }),
6730
+ /* @__PURE__ */ jsxs("div", { className: "p-2 space-y-2 max-h-[400px] overflow-y-auto", children: [
6731
+ /* @__PURE__ */ jsxs(Collapsible, { open: viewCommentsOpen, onOpenChange: setViewCommentsOpen, children: [
6732
+ /* @__PURE__ */ jsx(CollapsibleTrigger2, { asChild: true, children: /* @__PURE__ */ jsxs(Button, { variant: "ghost", size: "sm", className: "w-full justify-between h-8 px-2", children: [
6733
+ /* @__PURE__ */ jsxs("span", { className: "text-xs font-medium", children: [
6734
+ "Comments ",
6735
+ comments.length > 0 && `(${comments.length})`
6736
+ ] }),
6737
+ /* @__PURE__ */ jsx(ChevronDown, { className: cn(
6738
+ "h-4 w-4 transition-transform duration-200",
6739
+ viewCommentsOpen && "rotate-180"
6740
+ ) })
6741
+ ] }) }),
6742
+ /* @__PURE__ */ jsx(CollapsibleContent2, { className: "space-y-2 pt-2", children: comments.length > 0 ? comments.map((comment) => {
6743
+ const hasLocation = !!comment.location;
6744
+ const locationLabel = comment.location ? getCommentLocationLabel(comment.location) : null;
6745
+ return /* @__PURE__ */ jsxs(
6746
+ "div",
6747
+ {
6748
+ className: cn(
6749
+ "rounded-lg bg-muted/50 p-3 space-y-2",
6750
+ hasLocation && "cursor-pointer hover:bg-muted/70 transition-colors"
6751
+ ),
6752
+ onClick: () => handleCommentClick(comment),
6753
+ role: hasLocation ? "button" : void 0,
6754
+ tabIndex: hasLocation ? 0 : void 0,
6755
+ onKeyDown: hasLocation ? (e) => {
6756
+ if (e.key === "Enter" || e.key === " ") {
6757
+ e.preventDefault();
6758
+ handleCommentClick(comment);
6759
+ }
6760
+ } : void 0,
6761
+ children: [
6762
+ locationLabel && /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
6763
+ /* @__PURE__ */ jsxs(
6764
+ Badge,
6765
+ {
6766
+ variant: "outline",
6767
+ className: "text-[10px] px-2 py-0 h-5 font-medium bg-background gap-1",
6768
+ children: [
6769
+ /* @__PURE__ */ jsx(LocationIcon, { type: comment.location.type }),
6770
+ locationLabel
6771
+ ]
6772
+ }
6773
+ ),
6774
+ hasLocation && /* @__PURE__ */ jsx(ChevronRight, { className: "h-3 w-3 text-muted-foreground" })
6775
+ ] }),
6776
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
6777
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-medium", children: comment.author }),
6778
+ /* @__PURE__ */ jsx("span", { className: "text-[10px] text-muted-foreground", children: formatDate2(comment.createdAt) })
6779
+ ] }),
6780
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-foreground", children: comment.text })
6781
+ ]
6782
+ },
6783
+ comment.id
6784
+ );
6785
+ }) : /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground text-center py-2", children: "No comments yet" }) })
6786
+ ] }),
6787
+ /* @__PURE__ */ jsx(Separator, { className: "my-2" }),
6788
+ !showAddForm ? /* @__PURE__ */ jsxs(
6789
+ Button,
6790
+ {
6791
+ variant: "outline",
6792
+ size: "sm",
6793
+ className: "w-full justify-center gap-2 h-8",
6794
+ onClick: () => setShowAddForm(true),
6795
+ disabled: locationOptions.length === 0,
6796
+ children: [
6797
+ /* @__PURE__ */ jsx(Plus, { className: "h-3.5 w-3.5" }),
6798
+ locationOptions.length === 0 ? "No suppliers available" : "Add comment"
6799
+ ]
6800
+ }
6801
+ ) : /* @__PURE__ */ jsxs("div", { className: cn(
6802
+ "space-y-3 p-3 rounded-lg border border-border bg-muted/30",
6803
+ "animate-in fade-in-0 slide-in-from-top-2 duration-200"
6804
+ ), children: [
6805
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
6806
+ /* @__PURE__ */ jsxs(Label2, { htmlFor: "supplier-prefix-select", className: "text-xs font-medium", children: [
6807
+ "Supplier / Prefix ",
6808
+ /* @__PURE__ */ jsx("span", { className: "text-destructive", children: "*" })
6809
+ ] }),
6810
+ /* @__PURE__ */ jsxs(Select, { value: selectedLocationId, onValueChange: setSelectedLocationId, children: [
6811
+ /* @__PURE__ */ jsx(SelectTrigger, { id: "supplier-prefix-select", size: "sm", className: "w-full", children: /* @__PURE__ */ jsx(SelectValue, { placeholder: "Select supplier / prefix..." }) }),
6812
+ /* @__PURE__ */ jsx(SelectContent, { children: locationOptions.map((option) => /* @__PURE__ */ jsx(SelectItem, { value: option.id, children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
6813
+ /* @__PURE__ */ jsx(LocationIcon, { type: option.type }),
6814
+ /* @__PURE__ */ jsx("span", { children: option.label })
6815
+ ] }) }, option.id)) })
6816
+ ] })
6817
+ ] }),
6818
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
6819
+ /* @__PURE__ */ jsx(Label2, { htmlFor: "comment-text", className: "text-xs font-medium", children: "Comment" }),
6820
+ /* @__PURE__ */ jsx(
6821
+ Textarea,
6822
+ {
6823
+ id: "comment-text",
6824
+ placeholder: "Type your comment...",
6825
+ value: newCommentText,
6826
+ onChange: (e) => setNewCommentText(e.target.value),
6827
+ onKeyDown: handleKeyDown,
6828
+ className: "min-h-[80px] text-sm resize-none",
6829
+ autoFocus: true
6830
+ }
6831
+ )
6832
+ ] }),
6833
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
6834
+ /* @__PURE__ */ jsx("span", { className: "text-[10px] text-muted-foreground", children: "\u2318+Enter to send \xB7 Esc to cancel" }),
6835
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
6836
+ /* @__PURE__ */ jsx(
6837
+ Button,
6838
+ {
6839
+ variant: "ghost",
6840
+ size: "sm",
6841
+ className: "h-7",
6842
+ onClick: () => {
6843
+ setShowAddForm(false);
6844
+ setNewCommentText("");
6845
+ setSelectedLocationId("");
6846
+ },
6847
+ children: "Cancel"
6848
+ }
6849
+ ),
6850
+ /* @__PURE__ */ jsxs(
6851
+ Button,
6852
+ {
6853
+ size: "sm",
6854
+ className: "h-7 gap-1",
6855
+ onClick: handleSubmit,
6856
+ disabled: !newCommentText.trim() || !selectedLocationId,
6857
+ children: [
6858
+ /* @__PURE__ */ jsx(Send, { className: "h-3 w-3" }),
6859
+ "Save"
6860
+ ]
6861
+ }
6862
+ )
6863
+ ] })
6864
+ ] })
6865
+ ] })
6866
+ ] })
6867
+ ]
6868
+ }
6869
+ )
6870
+ ] });
6871
+ }
6872
+ function generateLocationOptions(suppliers, weekKey) {
6873
+ const options = [];
6874
+ for (const supplier of suppliers) {
6875
+ const weekData = supplier.weeks[weekKey];
6876
+ options.push({
6877
+ id: `${supplier.id}-production`,
6878
+ label: `${supplier.name} - Production`,
6879
+ type: "production",
6880
+ supplierId: supplier.id,
6881
+ supplierName: supplier.name
6882
+ });
6883
+ if (weekData?.deliveries) {
6884
+ for (const delivery of weekData.deliveries) {
6885
+ options.push({
6886
+ id: `${supplier.id}-delivery-${delivery.id}`,
6887
+ label: `${supplier.name} - ${delivery.label || `Delivery ${delivery.id}`}`,
6888
+ type: "delivery",
6889
+ supplierId: supplier.id,
6890
+ supplierName: supplier.name,
6891
+ deliveryId: delivery.id,
6892
+ deliveryLabel: delivery.label || `Delivery ${delivery.id}`
6893
+ });
6894
+ }
6895
+ }
6896
+ }
6897
+ return options;
6898
+ }
6899
+ function WeekHeader({
6900
+ className,
6901
+ week,
6902
+ weekKey,
6903
+ comments = [],
6904
+ showCommentButton = true,
6905
+ locationOptions = [],
6906
+ onAddComment,
6907
+ onCommentClick,
6908
+ ...props
6473
6909
  }) {
6474
6910
  return /* @__PURE__ */ jsxs(
6475
- Button,
6911
+ "div",
6476
6912
  {
6477
- variant: "ghost",
6478
- size: "sm",
6479
- className: "-ml-3 h-8 data-[state=open]:bg-accent",
6480
- onClick: () => column.toggleSorting(column.getIsSorted() === "asc"),
6481
- children: [
6482
- /* @__PURE__ */ jsx("span", { className: "font-medium", children: "Supplier / Scope" }),
6913
+ "data-slot": "week-header",
6914
+ "data-current-week": week.isCurrentWeek,
6915
+ className: cn(
6916
+ "flex items-center justify-between gap-2 min-w-[140px] text-left",
6917
+ className
6918
+ ),
6919
+ ...props,
6920
+ children: [
6921
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-0.5", children: [
6922
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
6923
+ /* @__PURE__ */ jsx("span", { className: cn(
6924
+ "text-sm font-semibold tracking-tight",
6925
+ week.isCurrentWeek ? "text-primary" : "text-foreground"
6926
+ ), children: week.label }),
6927
+ week.isCurrentWeek && /* @__PURE__ */ jsxs("span", { className: "relative flex h-2 w-2", children: [
6928
+ /* @__PURE__ */ jsx("span", { className: "animate-ping absolute inline-flex h-full w-full rounded-full bg-primary opacity-75" }),
6929
+ /* @__PURE__ */ jsx("span", { className: "relative inline-flex rounded-full h-2 w-2 bg-primary" })
6930
+ ] })
6931
+ ] }),
6932
+ /* @__PURE__ */ jsx("span", { className: "text-[10px] font-normal text-muted-foreground/60 whitespace-nowrap", children: week.dateRange })
6933
+ ] }),
6934
+ showCommentButton && weekKey && /* @__PURE__ */ jsx(
6935
+ PlanningWeekCommentPopover,
6936
+ {
6937
+ comments,
6938
+ weekLabel: week.label,
6939
+ weekKey,
6940
+ locationOptions,
6941
+ onAddComment,
6942
+ onCommentClick
6943
+ }
6944
+ )
6945
+ ]
6946
+ }
6947
+ );
6948
+ }
6949
+ function SupplierColumnHeader({
6950
+ column
6951
+ }) {
6952
+ return /* @__PURE__ */ jsxs(
6953
+ Button,
6954
+ {
6955
+ variant: "ghost",
6956
+ size: "sm",
6957
+ className: "-ml-3 h-8 data-[state=open]:bg-accent",
6958
+ onClick: () => column.toggleSorting(column.getIsSorted() === "asc"),
6959
+ children: [
6960
+ /* @__PURE__ */ jsx("span", { className: "font-medium", children: "Supplier / Scope" }),
6483
6961
  /* @__PURE__ */ jsx(ArrowUpDown, { className: "ml-2 h-4 w-4" })
6484
6962
  ]
6485
6963
  }
@@ -6495,13 +6973,50 @@ function getSupplierColumn() {
6495
6973
  enableHiding: false
6496
6974
  };
6497
6975
  }
6498
- function generateWeekColumns(weeks, config) {
6976
+ function WeekHeaderWithComments({
6977
+ week,
6978
+ weekKey,
6979
+ config,
6980
+ suppliers
6981
+ }) {
6982
+ const weekComments = config?.weekComments?.[weekKey] ?? [];
6983
+ let filteredSuppliers = suppliers;
6984
+ if (config?.userRole === "supplier" && config?.currentSupplierId) {
6985
+ filteredSuppliers = suppliers.filter((s) => s.id === config.currentSupplierId);
6986
+ }
6987
+ const locationOptions = generateLocationOptions(filteredSuppliers, weekKey);
6988
+ const handleAddComment = config?.onAddWeekComment ? (text, location) => {
6989
+ config.onAddWeekComment?.(weekKey, text, location);
6990
+ } : void 0;
6991
+ const handleCommentClick = config?.onCommentClick;
6992
+ return /* @__PURE__ */ jsx(
6993
+ WeekHeader,
6994
+ {
6995
+ week,
6996
+ weekKey,
6997
+ comments: weekComments,
6998
+ showCommentButton: true,
6999
+ locationOptions,
7000
+ onAddComment: handleAddComment,
7001
+ onCommentClick: handleCommentClick
7002
+ }
7003
+ );
7004
+ }
7005
+ function generateWeekColumns(weeks, config, suppliers) {
6499
7006
  return weeks.map((week) => {
6500
7007
  const weekKey = getWeekKey(week.startDate);
6501
7008
  return {
6502
7009
  id: weekKey,
6503
7010
  accessorFn: (supplier) => supplier.weeks[weekKey],
6504
- header: () => /* @__PURE__ */ jsx(WeekHeader, { week }),
7011
+ header: () => /* @__PURE__ */ jsx(
7012
+ WeekHeaderWithComments,
7013
+ {
7014
+ week,
7015
+ weekKey,
7016
+ config,
7017
+ suppliers: suppliers ?? []
7018
+ }
7019
+ ),
6505
7020
  cell: ({ row }) => {
6506
7021
  const supplier = row.original;
6507
7022
  const data = supplier.weeks[weekKey] || { type: "empty" };
@@ -6521,10 +7036,10 @@ function generateWeekColumns(weeks, config) {
6521
7036
  };
6522
7037
  });
6523
7038
  }
6524
- function generateColumns(weeks, config) {
7039
+ function generateColumns(weeks, config, suppliers) {
6525
7040
  return [
6526
7041
  getSupplierColumn(),
6527
- ...generateWeekColumns(weeks, config)
7042
+ ...generateWeekColumns(weeks, config, suppliers)
6528
7043
  ];
6529
7044
  }
6530
7045
  function PlanningTable({
@@ -6543,22 +7058,22 @@ function PlanningTable({
6543
7058
  stickySupplierColumn = true,
6544
7059
  maxHeight = "600px"
6545
7060
  } = config;
6546
- const weeks = React17.useMemo(
7061
+ const weeks = React22.useMemo(
6547
7062
  () => generateWeeks(startDate, weekCount),
6548
7063
  [startDate, weekCount]
6549
7064
  );
6550
- const currentWeekKey = React17.useMemo(() => {
7065
+ const currentWeekKey = React22.useMemo(() => {
6551
7066
  const currentWeek = weeks.find((w) => w.isCurrentWeek);
6552
7067
  return currentWeek ? getWeekKey(currentWeek.startDate) : null;
6553
7068
  }, [weeks]);
6554
- const columns = React17.useMemo(
6555
- () => generateColumns(weeks, config),
6556
- [weeks, config]
6557
- );
6558
- const [sorting, setSorting] = React17.useState([]);
6559
- const [columnFilters, setColumnFilters] = React17.useState([]);
6560
- const [columnVisibility, setColumnVisibility] = React17.useState({});
6561
- const [rowSelection, setRowSelection] = React17.useState({});
7069
+ const columns = React22.useMemo(
7070
+ () => generateColumns(weeks, config, suppliers),
7071
+ [weeks, config, suppliers]
7072
+ );
7073
+ const [sorting, setSorting] = React22.useState([]);
7074
+ const [columnFilters, setColumnFilters] = React22.useState([]);
7075
+ const [columnVisibility, setColumnVisibility] = React22.useState({});
7076
+ const [rowSelection, setRowSelection] = React22.useState({});
6562
7077
  const table = useReactTable({
6563
7078
  data: suppliers,
6564
7079
  columns,
@@ -6589,29 +7104,32 @@ function PlanningTable({
6589
7104
  className: cn("flex flex-col gap-4", className),
6590
7105
  children: [
6591
7106
  showToolbar && /* @__PURE__ */ jsx(PlanningTableToolbar, { table }),
6592
- /* @__PURE__ */ jsx("div", { className: "rounded-lg border bg-card shadow-md", children: /* @__PURE__ */ jsxs(
7107
+ /* @__PURE__ */ jsx("div", { className: "rounded-xl border bg-background shadow-sm overflow-hidden", children: /* @__PURE__ */ jsxs(
6593
7108
  ScrollArea,
6594
7109
  {
6595
7110
  className: "w-full",
6596
7111
  style: { maxHeight },
6597
7112
  children: [
6598
- /* @__PURE__ */ jsxs("table", { className: "w-full caption-bottom text-sm border-collapse", children: [
6599
- /* @__PURE__ */ jsx("thead", { className: "[&_tr]:border-b bg-sidebar sticky top-0 z-20", children: table.getHeaderGroups().map((headerGroup) => /* @__PURE__ */ jsx(
7113
+ /* @__PURE__ */ jsxs("table", { className: "w-full border-collapse", children: [
7114
+ /* @__PURE__ */ jsx("thead", { className: "sticky top-0 z-20", children: table.getHeaderGroups().map((headerGroup) => /* @__PURE__ */ jsx(
6600
7115
  "tr",
6601
7116
  {
6602
- className: "border-b transition-colors",
6603
7117
  children: headerGroup.headers.map((header, index) => {
6604
7118
  const isCurrentWeekColumn = header.id === currentWeekKey;
6605
7119
  return /* @__PURE__ */ jsx(
6606
7120
  "th",
6607
7121
  {
6608
7122
  className: cn(
6609
- "h-14 px-4 text-left align-middle font-medium text-muted-foreground border-r border-border last:border-r-0",
7123
+ "h-14 px-3 text-left align-middle font-semibold text-xs text-muted-foreground uppercase tracking-wide",
7124
+ "border-r border-b border-border last:border-r-0 bg-sidebar",
7125
+ // First column: sticky with right-edge shadow (Quantum token)
6610
7126
  index === 0 && stickySupplierColumn && [
6611
- "sticky left-0 z-30 bg-sidebar min-w-[200px]"
7127
+ "sticky left-0 z-30 min-w-[200px]",
7128
+ "shadow-[var(--j3m-shadow-sticky-edge)]"
6612
7129
  ],
6613
- index > 0 && "min-w-[120px] w-[120px]",
6614
- isCurrentWeekColumn && "bg-primary/10 border-t-2 border-t-primary"
7130
+ index > 0 && "min-w-[140px]",
7131
+ // Current week: only highlight text/dot, not full background
7132
+ isCurrentWeekColumn && highlightCurrentWeek && "text-primary"
6615
7133
  ),
6616
7134
  children: header.isPlaceholder ? null : flexRender(
6617
7135
  header.column.columnDef.header,
@@ -6624,23 +7142,23 @@ function PlanningTable({
6624
7142
  },
6625
7143
  headerGroup.id
6626
7144
  )) }),
6627
- /* @__PURE__ */ jsx("tbody", { className: "[&_tr:last-child]:border-0 bg-background", children: table.getRowModel().rows?.length ? table.getRowModel().rows.map((row) => /* @__PURE__ */ jsx(
7145
+ /* @__PURE__ */ jsx("tbody", { className: "bg-background", children: table.getRowModel().rows?.length ? table.getRowModel().rows.map((row) => /* @__PURE__ */ jsx(
6628
7146
  "tr",
6629
7147
  {
6630
7148
  "data-state": row.getIsSelected() && "selected",
6631
- className: "border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted",
7149
+ className: "border-b border-border last:border-b-0",
6632
7150
  children: row.getVisibleCells().map((cell, index) => {
6633
- const isCurrentWeekColumn = cell.column.id === currentWeekKey;
6634
7151
  return /* @__PURE__ */ jsx(
6635
7152
  "td",
6636
7153
  {
6637
7154
  className: cn(
6638
- "p-0 align-middle border-r border-border last:border-r-0",
7155
+ "p-0 align-top border-r border-border last:border-r-0 bg-background",
7156
+ // First column: sticky WHITE with right-edge shadow (Quantum token)
6639
7157
  index === 0 && stickySupplierColumn && [
6640
- "sticky left-0 z-10 bg-background min-w-[200px]"
7158
+ "sticky left-0 z-10 min-w-[200px]",
7159
+ "shadow-[var(--j3m-shadow-sticky-edge)]"
6641
7160
  ],
6642
- index > 0 && "min-w-[120px] w-[120px]",
6643
- isCurrentWeekColumn && "bg-primary/5"
7161
+ index > 0 && "min-w-[140px]"
6644
7162
  ),
6645
7163
  children: flexRender(
6646
7164
  cell.column.columnDef.cell,
@@ -6656,7 +7174,7 @@ function PlanningTable({
6656
7174
  "td",
6657
7175
  {
6658
7176
  colSpan: columns.length,
6659
- className: "h-24 text-center",
7177
+ className: "h-24 text-center text-muted-foreground bg-background",
6660
7178
  children: "No suppliers found."
6661
7179
  }
6662
7180
  ) }) })
@@ -6682,7 +7200,6 @@ function getStatusBadgeVariant(status) {
6682
7200
  switch (status) {
6683
7201
  case "on-time":
6684
7202
  return "outline";
6685
- // Green text with outline
6686
7203
  case "delayed":
6687
7204
  return "secondary";
6688
7205
  case "critical":
@@ -6699,7 +7216,6 @@ function getStatusBadgeClasses(status) {
6699
7216
  return "border-amber-500 text-amber-600 bg-amber-50 dark:bg-amber-950/50";
6700
7217
  case "critical":
6701
7218
  return "";
6702
- // Use default destructive
6703
7219
  default:
6704
7220
  return "";
6705
7221
  }
@@ -6718,134 +7234,566 @@ function getStatusLabel(status) {
6718
7234
  return status;
6719
7235
  }
6720
7236
  }
6721
- function DeliveryCard({ delivery, index }) {
6722
- const [isOpen, setIsOpen] = React17.useState(false);
6723
- const hasElements = delivery.elements && delivery.elements.length > 0;
6724
- const elementsAtRisk = delivery.elementsAtRisk ?? delivery.elements?.filter((e) => !e.isProduced).length ?? 0;
6725
- return /* @__PURE__ */ jsx(Collapsible, { open: isOpen, onOpenChange: setIsOpen, children: /* @__PURE__ */ jsxs("div", { className: "rounded-lg border overflow-hidden bg-card", children: [
6726
- /* @__PURE__ */ jsx(CollapsibleTrigger2, { asChild: true, children: /* @__PURE__ */ jsxs(
6727
- "button",
7237
+ function getProgressVariant(status) {
7238
+ switch (status) {
7239
+ case "on-time":
7240
+ return "success";
7241
+ case "delayed":
7242
+ return "warning";
7243
+ case "critical":
7244
+ return "destructive";
7245
+ default:
7246
+ return "default";
7247
+ }
7248
+ }
7249
+ function getShipmentStatusBadgeClasses(status) {
7250
+ switch (status) {
7251
+ case "sent":
7252
+ return "border-green-500 text-green-600 bg-green-50 dark:bg-green-950/50";
7253
+ case "not-sent":
7254
+ return "border-muted-foreground/50 text-muted-foreground bg-muted/50";
7255
+ case "moved":
7256
+ return "border-blue-500 text-blue-600 bg-blue-50 dark:bg-blue-950/50";
7257
+ case "addon":
7258
+ return "border-purple-500 text-purple-600 bg-purple-50 dark:bg-purple-950/50";
7259
+ case "planned":
7260
+ default:
7261
+ return "border-muted-foreground/50 text-muted-foreground";
7262
+ }
7263
+ }
7264
+ function getShipmentStatusRowBg(status) {
7265
+ switch (status) {
7266
+ case "sent":
7267
+ return "bg-green-50/30 dark:bg-green-950/10";
7268
+ case "not-sent":
7269
+ return "bg-muted/30";
7270
+ case "moved":
7271
+ return "bg-blue-50/30 dark:bg-blue-950/10";
7272
+ case "addon":
7273
+ return "bg-purple-50/30 dark:bg-purple-950/10";
7274
+ default:
7275
+ return "";
7276
+ }
7277
+ }
7278
+ function DeliveryCommentPopover({
7279
+ comments = [],
7280
+ onAddComment,
7281
+ deliveryLabel
7282
+ }) {
7283
+ const [open, setOpen] = React22.useState(false);
7284
+ const [newCommentText, setNewCommentText] = React22.useState("");
7285
+ const [viewCommentsOpen, setViewCommentsOpen] = React22.useState(true);
7286
+ const [showAddForm, setShowAddForm] = React22.useState(false);
7287
+ const handleSubmit = () => {
7288
+ if (newCommentText.trim() && onAddComment) {
7289
+ onAddComment(newCommentText.trim());
7290
+ setNewCommentText("");
7291
+ setShowAddForm(false);
7292
+ setViewCommentsOpen(true);
7293
+ }
7294
+ };
7295
+ const handleKeyDown = (e) => {
7296
+ if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) {
7297
+ e.preventDefault();
7298
+ handleSubmit();
7299
+ }
7300
+ if (e.key === "Escape") {
7301
+ setShowAddForm(false);
7302
+ setNewCommentText("");
7303
+ }
7304
+ };
7305
+ const formatDate2 = (date) => {
7306
+ return new Intl.DateTimeFormat("en-US", {
7307
+ month: "short",
7308
+ day: "numeric",
7309
+ hour: "numeric",
7310
+ minute: "2-digit"
7311
+ }).format(date);
7312
+ };
7313
+ const prevOpenRef = React22.useRef(open);
7314
+ React22.useEffect(() => {
7315
+ const wasOpen = prevOpenRef.current;
7316
+ prevOpenRef.current = open;
7317
+ if (wasOpen && !open) {
7318
+ setShowAddForm(false);
7319
+ setNewCommentText("");
7320
+ }
7321
+ }, [open]);
7322
+ return /* @__PURE__ */ jsxs(Popover, { open, onOpenChange: setOpen, children: [
7323
+ /* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx(CommentButton, { size: "sm", commentCount: comments.length }) }),
7324
+ /* @__PURE__ */ jsxs(
7325
+ PopoverContent,
6728
7326
  {
6729
- className: cn(
6730
- "w-full flex items-center justify-between p-3 text-left",
6731
- "hover:bg-muted/50 transition-colors",
6732
- hasElements && "cursor-pointer"
6733
- ),
6734
- disabled: !hasElements,
7327
+ className: "w-80 p-0 z-[100]",
7328
+ align: "end",
7329
+ sideOffset: 8,
7330
+ collisionPadding: 16,
6735
7331
  children: [
6736
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
6737
- /* @__PURE__ */ jsx(Truck, { className: "h-4 w-4 text-muted-foreground" }),
6738
- /* @__PURE__ */ jsxs("div", { children: [
6739
- /* @__PURE__ */ jsx("div", { className: "text-sm font-medium", children: delivery.label || `Delivery ${index + 1}` }),
6740
- delivery.destination && /* @__PURE__ */ jsxs("div", { className: "text-xs text-muted-foreground", children: [
6741
- "\u2192 ",
6742
- delivery.destination
6743
- ] })
6744
- ] })
7332
+ /* @__PURE__ */ jsxs("div", { className: "px-4 py-3 border-b border-border", children: [
7333
+ /* @__PURE__ */ jsx("h4", { className: "text-sm font-semibold", children: "Comments" }),
7334
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: deliveryLabel })
6745
7335
  ] }),
6746
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
6747
- /* @__PURE__ */ jsx(
6748
- Badge,
7336
+ /* @__PURE__ */ jsxs("div", { className: "p-2 space-y-2 max-h-[400px] overflow-y-auto", children: [
7337
+ /* @__PURE__ */ jsxs(Collapsible, { open: viewCommentsOpen, onOpenChange: setViewCommentsOpen, children: [
7338
+ /* @__PURE__ */ jsx(CollapsibleTrigger2, { asChild: true, children: /* @__PURE__ */ jsxs(Button, { variant: "ghost", size: "sm", className: "w-full justify-between h-8 px-2", children: [
7339
+ /* @__PURE__ */ jsxs("span", { className: "text-xs font-medium", children: [
7340
+ "Comments ",
7341
+ comments.length > 0 && `(${comments.length})`
7342
+ ] }),
7343
+ /* @__PURE__ */ jsx(ChevronDown, { className: cn(
7344
+ "h-4 w-4 transition-transform duration-200",
7345
+ viewCommentsOpen && "rotate-180"
7346
+ ) })
7347
+ ] }) }),
7348
+ /* @__PURE__ */ jsx(CollapsibleContent2, { className: "space-y-2 pt-2", children: comments.length > 0 ? comments.map((comment) => /* @__PURE__ */ jsxs("div", { className: "rounded-lg bg-muted/50 p-3 space-y-2", children: [
7349
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
7350
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-medium", children: comment.author }),
7351
+ /* @__PURE__ */ jsx("span", { className: "text-[10px] text-muted-foreground", children: formatDate2(comment.createdAt) })
7352
+ ] }),
7353
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-foreground", children: comment.text })
7354
+ ] }, comment.id)) : /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground text-center py-2", children: "No comments yet" }) })
7355
+ ] }),
7356
+ /* @__PURE__ */ jsx(Separator, { className: "my-2" }),
7357
+ !showAddForm ? /* @__PURE__ */ jsxs(
7358
+ Button,
6749
7359
  {
6750
- variant: getStatusBadgeVariant(delivery.status),
6751
- className: cn("text-xs", getStatusBadgeClasses(delivery.status)),
6752
- children: getStatusLabel(delivery.status)
7360
+ variant: "outline",
7361
+ size: "sm",
7362
+ className: "w-full justify-center gap-2 h-8",
7363
+ onClick: () => setShowAddForm(true),
7364
+ children: [
7365
+ /* @__PURE__ */ jsx(Plus, { className: "h-3.5 w-3.5" }),
7366
+ "Add comment"
7367
+ ]
6753
7368
  }
6754
- ),
6755
- hasElements && /* @__PURE__ */ jsx(ChevronDown, { className: cn(
6756
- "h-4 w-4 text-muted-foreground transition-transform",
6757
- isOpen && "rotate-180"
6758
- ) })
7369
+ ) : /* @__PURE__ */ jsxs("div", { className: cn(
7370
+ "space-y-3 p-3 rounded-lg border border-border bg-muted/30",
7371
+ "animate-in fade-in-0 slide-in-from-top-2 duration-200"
7372
+ ), children: [
7373
+ /* @__PURE__ */ jsx(
7374
+ Textarea,
7375
+ {
7376
+ placeholder: "Type your comment...",
7377
+ value: newCommentText,
7378
+ onChange: (e) => setNewCommentText(e.target.value),
7379
+ onKeyDown: handleKeyDown,
7380
+ className: "min-h-[80px] text-sm resize-none",
7381
+ autoFocus: true
7382
+ }
7383
+ ),
7384
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
7385
+ /* @__PURE__ */ jsx("span", { className: "text-[10px] text-muted-foreground", children: "\u2318+Enter to send \xB7 Esc to cancel" }),
7386
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
7387
+ /* @__PURE__ */ jsx(
7388
+ Button,
7389
+ {
7390
+ variant: "ghost",
7391
+ size: "sm",
7392
+ className: "h-7",
7393
+ onClick: () => {
7394
+ setShowAddForm(false);
7395
+ setNewCommentText("");
7396
+ },
7397
+ children: "Cancel"
7398
+ }
7399
+ ),
7400
+ /* @__PURE__ */ jsxs(
7401
+ Button,
7402
+ {
7403
+ size: "sm",
7404
+ className: "h-7 gap-1",
7405
+ onClick: handleSubmit,
7406
+ disabled: !newCommentText.trim(),
7407
+ children: [
7408
+ /* @__PURE__ */ jsx(Send, { className: "h-3 w-3" }),
7409
+ "Save"
7410
+ ]
7411
+ }
7412
+ )
7413
+ ] })
7414
+ ] })
7415
+ ] })
7416
+ ] })
7417
+ ]
7418
+ }
7419
+ )
7420
+ ] });
7421
+ }
7422
+ function ProductionCommentSection({
7423
+ comments = [],
7424
+ onAddComment
7425
+ }) {
7426
+ const [showAddForm, setShowAddForm] = React22.useState(false);
7427
+ const [newComment, setNewComment] = React22.useState("");
7428
+ const handleSubmit = () => {
7429
+ if (newComment.trim() && onAddComment) {
7430
+ onAddComment(newComment.trim());
7431
+ setNewComment("");
7432
+ setShowAddForm(false);
7433
+ }
7434
+ };
7435
+ const handleKeyDown = (e) => {
7436
+ if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) {
7437
+ e.preventDefault();
7438
+ handleSubmit();
7439
+ }
7440
+ if (e.key === "Escape") {
7441
+ setShowAddForm(false);
7442
+ setNewComment("");
7443
+ }
7444
+ };
7445
+ const formatDate2 = (date) => {
7446
+ return new Intl.DateTimeFormat("en-US", {
7447
+ month: "short",
7448
+ day: "numeric",
7449
+ hour: "numeric",
7450
+ minute: "2-digit"
7451
+ }).format(date);
7452
+ };
7453
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
7454
+ comments.length > 0 && /* @__PURE__ */ jsx("div", { className: "space-y-2", children: comments.map((comment) => /* @__PURE__ */ jsxs("div", { className: "rounded-lg bg-muted/50 p-2.5 space-y-1", children: [
7455
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
7456
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-medium", children: comment.author }),
7457
+ /* @__PURE__ */ jsx("span", { className: "text-[10px] text-muted-foreground", children: formatDate2(comment.createdAt) })
7458
+ ] }),
7459
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-foreground", children: comment.text })
7460
+ ] }, comment.id)) }),
7461
+ !showAddForm ? /* @__PURE__ */ jsxs(
7462
+ Button,
7463
+ {
7464
+ variant: "ghost",
7465
+ size: "sm",
7466
+ className: "w-full justify-start gap-2 h-8 text-muted-foreground",
7467
+ onClick: () => setShowAddForm(true),
7468
+ children: [
7469
+ /* @__PURE__ */ jsx(MessageSquare, { className: "h-3.5 w-3.5" }),
7470
+ comments.length > 0 ? "Add another comment" : "Add a comment..."
7471
+ ]
7472
+ }
7473
+ ) : /* @__PURE__ */ jsxs("div", { className: "space-y-2 animate-in fade-in-0 slide-in-from-top-2 duration-200", children: [
7474
+ /* @__PURE__ */ jsx(
7475
+ Textarea,
7476
+ {
7477
+ placeholder: "Add a comment...",
7478
+ value: newComment,
7479
+ onChange: (e) => setNewComment(e.target.value),
7480
+ onKeyDown: handleKeyDown,
7481
+ className: "min-h-[60px] text-sm resize-none",
7482
+ autoFocus: true
7483
+ }
7484
+ ),
7485
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
7486
+ /* @__PURE__ */ jsx("span", { className: "text-[10px] text-muted-foreground", children: "\u2318+Enter to send" }),
7487
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
7488
+ /* @__PURE__ */ jsx(
7489
+ Button,
7490
+ {
7491
+ variant: "ghost",
7492
+ size: "sm",
7493
+ className: "h-7",
7494
+ onClick: () => {
7495
+ setShowAddForm(false);
7496
+ setNewComment("");
7497
+ },
7498
+ children: "Cancel"
7499
+ }
7500
+ ),
7501
+ /* @__PURE__ */ jsxs(
7502
+ Button,
7503
+ {
7504
+ size: "sm",
7505
+ className: "h-7 gap-1",
7506
+ onClick: handleSubmit,
7507
+ disabled: !newComment.trim(),
7508
+ children: [
7509
+ /* @__PURE__ */ jsx(Send, { className: "h-3 w-3" }),
7510
+ "Save"
7511
+ ]
7512
+ }
7513
+ )
7514
+ ] })
7515
+ ] })
7516
+ ] })
7517
+ ] });
7518
+ }
7519
+ function DeliveryListItem({
7520
+ delivery,
7521
+ index,
7522
+ onClick
7523
+ }) {
7524
+ const hasComments = (delivery.comments?.length ?? 0) > 0;
7525
+ return /* @__PURE__ */ jsxs(
7526
+ "button",
7527
+ {
7528
+ onClick,
7529
+ className: cn(
7530
+ "w-full flex items-center justify-between p-3 rounded-lg",
7531
+ "bg-card border hover:bg-muted/50 transition-colors cursor-pointer",
7532
+ "text-left"
7533
+ ),
7534
+ children: [
7535
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
7536
+ /* @__PURE__ */ jsx("div", { className: cn(
7537
+ "flex items-center justify-center h-8 w-8 rounded-lg",
7538
+ delivery.status === "on-time" && "bg-green-100 dark:bg-green-950/50",
7539
+ delivery.status === "delayed" && "bg-amber-100 dark:bg-amber-950/50",
7540
+ delivery.status === "critical" && "bg-red-100 dark:bg-red-950/50"
7541
+ ), children: /* @__PURE__ */ jsx(Truck, { className: cn(
7542
+ "h-4 w-4",
7543
+ delivery.status === "on-time" && "text-green-600 dark:text-green-400",
7544
+ delivery.status === "delayed" && "text-amber-600 dark:text-amber-400",
7545
+ delivery.status === "critical" && "text-red-600 dark:text-red-400"
7546
+ ) }) }),
7547
+ /* @__PURE__ */ jsxs("div", { children: [
7548
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
7549
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-medium", children: delivery.label || `Delivery ${index + 1}` }),
7550
+ hasComments && /* @__PURE__ */ jsxs("div", { className: "relative", children: [
7551
+ /* @__PURE__ */ jsx(MessageSquare, { className: "h-3 w-3 text-muted-foreground" }),
7552
+ /* @__PURE__ */ jsx("span", { className: "absolute -top-0.5 -right-0.5 h-1.5 w-1.5 rounded-full bg-primary" })
7553
+ ] })
7554
+ ] }),
7555
+ delivery.destination && /* @__PURE__ */ jsxs("div", { className: "text-xs text-muted-foreground", children: [
7556
+ "\u2192 ",
7557
+ delivery.destination
7558
+ ] })
6759
7559
  ] })
7560
+ ] }),
7561
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
7562
+ /* @__PURE__ */ jsx(
7563
+ Badge,
7564
+ {
7565
+ variant: getStatusBadgeVariant(delivery.status),
7566
+ className: cn("text-xs", getStatusBadgeClasses(delivery.status)),
7567
+ children: getStatusLabel(delivery.status)
7568
+ }
7569
+ ),
7570
+ /* @__PURE__ */ jsx(ChevronRight, { className: "h-4 w-4 text-muted-foreground" })
7571
+ ] })
7572
+ ]
7573
+ }
7574
+ );
7575
+ }
7576
+ function DeliveryDetailsView({
7577
+ delivery,
7578
+ week,
7579
+ onBack,
7580
+ onAddComment
7581
+ }) {
7582
+ const elements = delivery.elements ?? [];
7583
+ const categorizedElements = React22.useMemo(() => {
7584
+ const sent = [];
7585
+ const notSent = [];
7586
+ const moved = [];
7587
+ const addons = [];
7588
+ elements.forEach((element) => {
7589
+ const status = getElementShipmentStatus(element, delivery.id);
7590
+ switch (status) {
7591
+ case "sent":
7592
+ sent.push(element);
7593
+ break;
7594
+ case "not-sent":
7595
+ notSent.push(element);
7596
+ break;
7597
+ case "moved":
7598
+ moved.push(element);
7599
+ break;
7600
+ case "addon":
7601
+ addons.push(element);
7602
+ break;
7603
+ default:
7604
+ notSent.push(element);
7605
+ }
7606
+ });
7607
+ return { sent, notSent, moved, addons };
7608
+ }, [elements, delivery.id]);
7609
+ const totalCount = elements.length;
7610
+ const sentCount = categorizedElements.sent.length;
7611
+ (delivery.comments?.length ?? 0) > 0;
7612
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col h-full animate-in slide-in-from-right-4 duration-200", children: [
7613
+ /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2 px-6 py-3 border-b", children: /* @__PURE__ */ jsxs(
7614
+ Button,
7615
+ {
7616
+ variant: "ghost",
7617
+ size: "sm",
7618
+ className: "gap-1 -ml-2",
7619
+ onClick: onBack,
7620
+ children: [
7621
+ /* @__PURE__ */ jsx(ChevronLeft, { className: "h-4 w-4" }),
7622
+ "Back"
6760
7623
  ]
6761
7624
  }
6762
7625
  ) }),
6763
- hasElements && /* @__PURE__ */ jsxs(CollapsibleContent2, { children: [
6764
- /* @__PURE__ */ jsx(Separator, {}),
6765
- /* @__PURE__ */ jsxs("div", { className: "p-3 space-y-2", children: [
6766
- elementsAtRisk > 0 && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-xs text-amber-600 dark:text-amber-400 mb-2", children: [
6767
- /* @__PURE__ */ jsx(AlertTriangle, { className: "h-3.5 w-3.5" }),
7626
+ /* @__PURE__ */ jsxs("div", { className: "px-6 py-4 space-y-2", children: [
7627
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
7628
+ /* @__PURE__ */ jsx("h3", { className: "text-lg font-semibold", children: delivery.label || "Delivery Details" }),
7629
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
7630
+ /* @__PURE__ */ jsx(
7631
+ DeliveryCommentPopover,
7632
+ {
7633
+ comments: delivery.comments,
7634
+ onAddComment,
7635
+ deliveryLabel: delivery.label || "Delivery"
7636
+ }
7637
+ ),
7638
+ /* @__PURE__ */ jsx(
7639
+ Badge,
7640
+ {
7641
+ variant: getStatusBadgeVariant(delivery.status),
7642
+ className: cn("text-xs", getStatusBadgeClasses(delivery.status)),
7643
+ children: getStatusLabel(delivery.status)
7644
+ }
7645
+ )
7646
+ ] })
7647
+ ] }),
7648
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-4 text-sm text-muted-foreground", children: [
7649
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
7650
+ /* @__PURE__ */ jsx(Calendar$1, { className: "h-3.5 w-3.5" }),
7651
+ /* @__PURE__ */ jsxs("span", { children: [
7652
+ week.label,
7653
+ " \u2022 ",
7654
+ week.dateRange
7655
+ ] })
7656
+ ] }),
7657
+ delivery.destination && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
7658
+ /* @__PURE__ */ jsx(Truck, { className: "h-3.5 w-3.5" }),
6768
7659
  /* @__PURE__ */ jsxs("span", { children: [
6769
- elementsAtRisk,
6770
- " element(s) probably not all produced"
7660
+ "\u2192 ",
7661
+ delivery.destination
7662
+ ] })
7663
+ ] })
7664
+ ] })
7665
+ ] }),
7666
+ /* @__PURE__ */ jsx(ScrollArea, { className: "flex-1 px-6 pb-6", children: /* @__PURE__ */ jsxs("div", { className: "space-y-6", children: [
7667
+ totalCount > 0 && /* @__PURE__ */ jsxs("div", { className: "rounded-lg bg-muted/50 p-4", children: [
7668
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between mb-2", children: [
7669
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-medium", children: "Shipment Progress" }),
7670
+ /* @__PURE__ */ jsxs("span", { className: "text-sm font-semibold tabular-nums", children: [
7671
+ "Shipped ",
7672
+ sentCount,
7673
+ " / ",
7674
+ totalCount
6771
7675
  ] })
6772
7676
  ] }),
6773
- /* @__PURE__ */ jsx("div", { className: "space-y-1.5", children: delivery.elements?.map((element) => /* @__PURE__ */ jsxs(
7677
+ /* @__PURE__ */ jsx("div", { className: "h-2 bg-black/10 dark:bg-white/10 rounded-full overflow-hidden", children: /* @__PURE__ */ jsx(
6774
7678
  "div",
6775
7679
  {
6776
7680
  className: cn(
6777
- "flex items-center justify-between text-xs p-2 rounded",
6778
- element.isProduced ? "bg-muted/30" : "bg-amber-50/50 dark:bg-amber-950/30"
7681
+ "h-full rounded-full transition-all",
7682
+ sentCount === totalCount ? "bg-green-500" : "bg-primary"
6779
7683
  ),
6780
- children: [
6781
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
6782
- element.isProduced ? /* @__PURE__ */ jsx(CheckCircle2, { className: "h-3.5 w-3.5 text-green-600" }) : /* @__PURE__ */ jsx(XCircle, { className: "h-3.5 w-3.5 text-amber-600" }),
6783
- /* @__PURE__ */ jsx("span", { className: element.isProduced ? "text-foreground" : "text-amber-700 dark:text-amber-300", children: element.name })
6784
- ] }),
6785
- element.quantity && /* @__PURE__ */ jsxs("span", { className: "text-muted-foreground", children: [
6786
- element.quantity,
6787
- " ",
6788
- element.unit ? formatProductionUnit(element.unit) : "pcs"
6789
- ] })
6790
- ]
6791
- },
6792
- element.id
6793
- )) })
7684
+ style: { width: `${totalCount > 0 ? sentCount / totalCount * 100 : 0}%` }
7685
+ }
7686
+ ) }),
7687
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 mt-3 flex-wrap", children: [
7688
+ categorizedElements.sent.length > 0 && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 text-xs", children: [
7689
+ /* @__PURE__ */ jsx(CheckCircle2, { className: "h-3 w-3 text-green-600" }),
7690
+ /* @__PURE__ */ jsxs("span", { className: "text-green-700 dark:text-green-300", children: [
7691
+ categorizedElements.sent.length,
7692
+ " Sent"
7693
+ ] })
7694
+ ] }),
7695
+ categorizedElements.notSent.length > 0 && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 text-xs", children: [
7696
+ /* @__PURE__ */ jsx(XCircle, { className: "h-3 w-3 text-amber-600" }),
7697
+ /* @__PURE__ */ jsxs("span", { className: "text-amber-700 dark:text-amber-300", children: [
7698
+ categorizedElements.notSent.length,
7699
+ " Not sent"
7700
+ ] })
7701
+ ] }),
7702
+ categorizedElements.moved.length > 0 && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 text-xs", children: [
7703
+ /* @__PURE__ */ jsx(ArrowRight, { className: "h-3 w-3 text-blue-600" }),
7704
+ /* @__PURE__ */ jsxs("span", { className: "text-blue-700 dark:text-blue-300", children: [
7705
+ categorizedElements.moved.length,
7706
+ " Moved"
7707
+ ] })
7708
+ ] }),
7709
+ categorizedElements.addons.length > 0 && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 text-xs", children: [
7710
+ /* @__PURE__ */ jsx(Plus, { className: "h-3 w-3 text-purple-600" }),
7711
+ /* @__PURE__ */ jsxs("span", { className: "text-purple-700 dark:text-purple-300", children: [
7712
+ categorizedElements.addons.length,
7713
+ " Add-on"
7714
+ ] })
7715
+ ] })
7716
+ ] })
7717
+ ] }),
7718
+ elements.length > 0 && /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
7719
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-medium", children: "Elements" }),
7720
+ /* @__PURE__ */ jsx("div", { className: "rounded-lg border overflow-hidden", children: /* @__PURE__ */ jsxs(Table, { children: [
7721
+ /* @__PURE__ */ jsx(TableHeader, { children: /* @__PURE__ */ jsxs(TableRow, { className: "bg-sidebar hover:bg-sidebar", children: [
7722
+ /* @__PURE__ */ jsx(TableHead, { className: "font-semibold", children: "Prefix" }),
7723
+ /* @__PURE__ */ jsx(TableHead, { className: "font-semibold", children: "Type" }),
7724
+ /* @__PURE__ */ jsx(TableHead, { className: "font-semibold text-right", children: "Weight" }),
7725
+ /* @__PURE__ */ jsx(TableHead, { className: "font-semibold text-right", children: "Size (m\xB2)" }),
7726
+ /* @__PURE__ */ jsx(TableHead, { className: "font-semibold text-center", children: "Status" })
7727
+ ] }) }),
7728
+ /* @__PURE__ */ jsx(TableBody, { children: elements.map((element) => {
7729
+ const shipmentStatus = getElementShipmentStatus(element, delivery.id);
7730
+ const statusLabel = getShipmentStatusLabel(shipmentStatus);
7731
+ return /* @__PURE__ */ jsxs(
7732
+ TableRow,
7733
+ {
7734
+ className: getShipmentStatusRowBg(shipmentStatus),
7735
+ children: [
7736
+ /* @__PURE__ */ jsx(TableCell, { className: "font-medium", children: element.prefix || "\u2014" }),
7737
+ /* @__PURE__ */ jsx(TableCell, { children: element.type || element.name || "\u2014" }),
7738
+ /* @__PURE__ */ jsx(TableCell, { className: "text-right tabular-nums", children: element.weight ? /* @__PURE__ */ jsxs("span", { children: [
7739
+ element.weight,
7740
+ " ",
7741
+ element.weightUnit || "kg"
7742
+ ] }) : "\u2014" }),
7743
+ /* @__PURE__ */ jsx(TableCell, { className: "text-right tabular-nums", children: element.sizeSqm ? /* @__PURE__ */ jsx("span", { children: element.sizeSqm }) : "\u2014" }),
7744
+ /* @__PURE__ */ jsx(TableCell, { children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-1", children: [
7745
+ /* @__PURE__ */ jsx(
7746
+ Badge,
7747
+ {
7748
+ variant: "outline",
7749
+ className: cn(
7750
+ "text-[10px] h-5",
7751
+ getShipmentStatusBadgeClasses(shipmentStatus)
7752
+ ),
7753
+ children: statusLabel
7754
+ }
7755
+ ),
7756
+ shipmentStatus === "moved" && element.actualDeliveryLabel && /* @__PURE__ */ jsxs("span", { className: "text-[9px] text-blue-600 dark:text-blue-400", children: [
7757
+ "\u2192 ",
7758
+ element.actualDeliveryLabel
7759
+ ] }),
7760
+ shipmentStatus === "addon" && element.originalDeliveryLabel && /* @__PURE__ */ jsxs("span", { className: "text-[9px] text-purple-600 dark:text-purple-400", children: [
7761
+ "from ",
7762
+ element.originalDeliveryLabel
7763
+ ] })
7764
+ ] }) })
7765
+ ]
7766
+ },
7767
+ element.id
7768
+ );
7769
+ }) })
7770
+ ] }) })
7771
+ ] }),
7772
+ elements.length === 0 && /* @__PURE__ */ jsxs("div", { className: "text-center py-8 text-muted-foreground", children: [
7773
+ /* @__PURE__ */ jsx(Package, { className: "h-8 w-8 mx-auto mb-2 opacity-50" }),
7774
+ /* @__PURE__ */ jsx("p", { className: "text-sm", children: "No elements in this delivery" })
6794
7775
  ] })
6795
- ] })
6796
- ] }) });
7776
+ ] }) })
7777
+ ] });
6797
7778
  }
6798
- function WeekDetailDialog({
6799
- open,
6800
- onOpenChange,
7779
+ function MainView({
6801
7780
  supplier,
6802
7781
  week,
6803
7782
  data,
6804
- onProgressUpdate
7783
+ producedValue,
7784
+ hasChanges,
7785
+ onProducedChange,
7786
+ onSave,
7787
+ onSelectDelivery,
7788
+ onAddProductionComment
6805
7789
  }) {
6806
7790
  const production = data?.production;
6807
- const initialProgress = production?.progress ?? data?.progress ?? 0;
6808
- const initialProduced = production?.produced ?? 0;
6809
- const [progressValue, setProgressValue] = React17.useState(initialProgress.toString());
6810
- const [producedValue, setProducedValue] = React17.useState(initialProduced.toString());
6811
- const [hasChanges, setHasChanges] = React17.useState(false);
6812
- React17.useEffect(() => {
6813
- const newProgress = data?.production?.progress ?? data?.progress ?? 0;
6814
- const newProduced = data?.production?.produced ?? 0;
6815
- setProgressValue(newProgress.toString());
6816
- setProducedValue(newProduced.toString());
6817
- setHasChanges(false);
6818
- }, [data]);
6819
- const handleProgressChange = (e) => {
6820
- const value = e.target.value;
6821
- setProgressValue(value);
6822
- setHasChanges(true);
6823
- };
6824
- const handleProducedChange = (e) => {
6825
- const value = e.target.value;
6826
- setProducedValue(value);
6827
- if (production?.target) {
6828
- const produced = parseFloat(value) || 0;
6829
- const calculatedProgress = Math.round(produced / production.target * 100);
6830
- setProgressValue(Math.min(100, calculatedProgress).toString());
6831
- }
6832
- setHasChanges(true);
6833
- };
6834
- const handleSave = () => {
6835
- if (!supplier || !week || !onProgressUpdate) return;
6836
- const newProgress = Math.min(100, Math.max(0, parseFloat(progressValue) || 0));
6837
- const newProduced = parseFloat(producedValue) || 0;
6838
- const weekKey = `${week.year}-W${week.weekNumber.toString().padStart(2, "0")}`;
6839
- onProgressUpdate(supplier.id, weekKey, newProgress, production ? newProduced : void 0);
6840
- setHasChanges(false);
6841
- };
6842
- if (!supplier || !week || !data) {
6843
- return null;
6844
- }
6845
- const productionProgress = parseFloat(progressValue) || 0;
7791
+ const productionProgress = production ? Math.min(100, Math.round(production.produced / production.target * 100)) : data?.progress ?? 0;
6846
7792
  const productionStatus = production?.status ?? "on-time";
6847
- return /* @__PURE__ */ jsx(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxs(DialogContent, { className: "max-w-lg max-h-[80vh] overflow-y-auto", children: [
6848
- /* @__PURE__ */ jsxs(DialogHeader, { children: [
7793
+ const isComplete = productionProgress >= 100;
7794
+ const hasProductionComments = (production?.comments?.length ?? 0) > 0;
7795
+ return /* @__PURE__ */ jsxs("div", { className: "animate-in fade-in-0 duration-200", children: [
7796
+ /* @__PURE__ */ jsxs(DialogHeader, { className: "px-6 pt-6 pb-4", children: [
6849
7797
  /* @__PURE__ */ jsxs(DialogTitle, { className: "flex items-center gap-2", children: [
6850
7798
  supplier.name,
6851
7799
  /* @__PURE__ */ jsx(Badge, { variant: "secondary", className: "text-xs font-normal", children: supplier.badgeType })
@@ -6857,174 +7805,1319 @@ function WeekDetailDialog({
6857
7805
  week.dateRange
6858
7806
  ] })
6859
7807
  ] }),
6860
- /* @__PURE__ */ jsxs("div", { className: "space-y-4 mt-2", children: [
6861
- /* @__PURE__ */ jsxs("div", { className: "text-sm text-muted-foreground", children: [
6862
- "Scope: ",
6863
- /* @__PURE__ */ jsx("span", { className: "text-foreground", children: supplier.scope })
6864
- ] }),
6865
- data.type !== "empty" && /* @__PURE__ */ jsxs(Fragment, { children: [
6866
- /* @__PURE__ */ jsx(Separator, {}),
6867
- /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
6868
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
6869
- /* @__PURE__ */ jsx(Factory, { className: "h-4 w-4 text-muted-foreground" }),
6870
- /* @__PURE__ */ jsx("span", { className: "text-sm font-medium", children: "Production Progress" }),
6871
- /* @__PURE__ */ jsx(
6872
- Badge,
6873
- {
6874
- variant: getStatusBadgeVariant(productionStatus),
6875
- className: cn("text-xs ml-auto", getStatusBadgeClasses(productionStatus)),
6876
- children: getStatusLabel(productionStatus)
6877
- }
6878
- )
6879
- ] }),
6880
- /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
6881
- /* @__PURE__ */ jsxs("div", { className: "flex justify-between text-xs text-muted-foreground", children: [
6882
- /* @__PURE__ */ jsx("span", { children: "Progress" }),
6883
- /* @__PURE__ */ jsxs("span", { children: [
6884
- Math.round(productionProgress),
6885
- "%"
6886
- ] })
6887
- ] }),
6888
- /* @__PURE__ */ jsx("div", { className: "w-full h-2 bg-muted rounded-full overflow-hidden", children: /* @__PURE__ */ jsx(
6889
- "div",
6890
- {
6891
- className: cn(
6892
- "h-full rounded-full transition-all",
6893
- productionStatus === "critical" ? "bg-red-500" : productionStatus === "delayed" ? "bg-amber-500" : "bg-green-500"
6894
- ),
6895
- style: { width: `${productionProgress}%` }
6896
- }
6897
- ) })
6898
- ] }),
6899
- /* @__PURE__ */ jsxs("div", { className: cn(
6900
- "p-3 rounded-lg border bg-card space-y-3"
6901
- ), children: [
6902
- /* @__PURE__ */ jsx("div", { className: "text-xs font-medium text-muted-foreground uppercase tracking-wide", children: "Update Progress" }),
6903
- production ? (
6904
- // If we have production data, show produced amount input
6905
- /* @__PURE__ */ jsxs("div", { className: "grid gap-3", children: [
6906
- /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
6907
- /* @__PURE__ */ jsxs(Label2, { htmlFor: "produced", className: "text-xs", children: [
6908
- "Produced (",
6909
- formatProductionUnit(production.unit),
6910
- ")"
6911
- ] }),
6912
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
6913
- /* @__PURE__ */ jsx(
6914
- Input,
6915
- {
6916
- id: "produced",
6917
- type: "number",
6918
- min: "0",
6919
- max: production.target,
6920
- value: producedValue,
6921
- onChange: handleProducedChange,
6922
- className: "h-8 text-sm"
6923
- }
6924
- ),
6925
- /* @__PURE__ */ jsxs("span", { className: "text-sm text-muted-foreground whitespace-nowrap", children: [
6926
- "/ ",
6927
- production.target,
6928
- " ",
6929
- formatProductionUnit(production.unit)
6930
- ] })
6931
- ] })
6932
- ] }),
6933
- /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
6934
- /* @__PURE__ */ jsx(Label2, { htmlFor: "progress", className: "text-xs", children: "Progress (%)" }),
6935
- /* @__PURE__ */ jsx(
6936
- Input,
6937
- {
6938
- id: "progress",
6939
- type: "number",
6940
- min: "0",
6941
- max: "100",
6942
- value: progressValue,
6943
- onChange: handleProgressChange,
6944
- className: "h-8 text-sm"
6945
- }
6946
- )
7808
+ /* @__PURE__ */ jsx(ScrollArea, { className: "flex-1 px-6 pb-6", children: /* @__PURE__ */ jsxs("div", { className: "space-y-8", children: [
7809
+ data.type !== "empty" && /* @__PURE__ */ jsxs("section", { className: "space-y-4", children: [
7810
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
7811
+ /* @__PURE__ */ jsx(Factory, { className: "h-4 w-4 text-muted-foreground" }),
7812
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-semibold", children: "Production" }),
7813
+ /* @__PURE__ */ jsx(
7814
+ Badge,
7815
+ {
7816
+ variant: getStatusBadgeVariant(productionStatus),
7817
+ className: cn("text-xs ml-auto", getStatusBadgeClasses(productionStatus)),
7818
+ children: getStatusLabel(productionStatus)
7819
+ }
7820
+ )
7821
+ ] }),
7822
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-6", children: [
7823
+ /* @__PURE__ */ jsx(
7824
+ CircularProgress,
7825
+ {
7826
+ value: productionProgress,
7827
+ size: 100,
7828
+ strokeWidth: 10,
7829
+ variant: getProgressVariant(productionStatus),
7830
+ showCheckmark: isComplete,
7831
+ children: isComplete ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center", children: [
7832
+ /* @__PURE__ */ jsx(Check, { className: "h-6 w-6 text-green-600" }),
7833
+ /* @__PURE__ */ jsxs("span", { className: "text-xs font-semibold text-green-600", children: [
7834
+ production?.produced ?? 0,
7835
+ " ",
7836
+ production ? formatProductionUnit(production.unit) : ""
7837
+ ] })
7838
+ ] }) : /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center", children: [
7839
+ /* @__PURE__ */ jsx("span", { className: "text-lg font-bold tabular-nums", children: production?.produced ?? 0 }),
7840
+ /* @__PURE__ */ jsxs("span", { className: "text-[10px] text-muted-foreground", children: [
7841
+ "/ ",
7842
+ production?.target ?? 0,
7843
+ " ",
7844
+ production ? formatProductionUnit(production.unit) : ""
6947
7845
  ] })
6948
7846
  ] })
6949
- ) : (
6950
- // Simple progress input if no production data
6951
- /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
6952
- /* @__PURE__ */ jsx(Label2, { htmlFor: "progress", className: "text-xs", children: "Progress (%)" }),
6953
- /* @__PURE__ */ jsx(
6954
- Input,
6955
- {
6956
- id: "progress",
6957
- type: "number",
6958
- min: "0",
6959
- max: "100",
6960
- value: progressValue,
6961
- onChange: handleProgressChange,
6962
- className: "h-8 text-sm"
6963
- }
6964
- )
7847
+ }
7848
+ ),
7849
+ production && /* @__PURE__ */ jsxs("div", { className: "flex-1 space-y-3", children: [
7850
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
7851
+ /* @__PURE__ */ jsxs(Label2, { htmlFor: "produced", className: "text-xs", children: [
7852
+ "Produced Amount (",
7853
+ formatProductionUnit(production.unit),
7854
+ ")"
7855
+ ] }),
7856
+ /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2", children: /* @__PURE__ */ jsx(
7857
+ Input,
7858
+ {
7859
+ id: "produced",
7860
+ type: "number",
7861
+ min: "0",
7862
+ max: production.target * 2,
7863
+ value: producedValue,
7864
+ onChange: onProducedChange,
7865
+ className: "h-9"
7866
+ }
7867
+ ) }),
7868
+ /* @__PURE__ */ jsxs("p", { className: "text-[10px] text-muted-foreground", children: [
7869
+ "Target: ",
7870
+ production.target,
7871
+ " ",
7872
+ formatProductionUnit(production.unit)
6965
7873
  ] })
6966
- ),
6967
- onProgressUpdate && /* @__PURE__ */ jsx(
7874
+ ] }),
7875
+ /* @__PURE__ */ jsx(
6968
7876
  Button,
6969
7877
  {
6970
7878
  size: "sm",
6971
7879
  className: "w-full",
6972
7880
  disabled: !hasChanges,
6973
- onClick: handleSave,
7881
+ onClick: onSave,
6974
7882
  children: hasChanges ? "Save Progress" : "No Changes"
6975
7883
  }
6976
7884
  )
6977
- ] }),
6978
- production && /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between p-3 rounded-lg border bg-muted/30", children: [
6979
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
6980
- /* @__PURE__ */ jsx(Package, { className: "h-4 w-4 text-muted-foreground" }),
6981
- /* @__PURE__ */ jsx("span", { className: "text-sm", children: "Target" })
6982
- ] }),
6983
- /* @__PURE__ */ jsxs("span", { className: "text-sm font-medium", children: [
6984
- production.target,
6985
- " ",
6986
- formatProductionUnit(production.unit)
6987
- ] })
6988
7885
  ] })
6989
- ] })
6990
- ] }),
6991
- data.deliveries && data.deliveries.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
6992
- /* @__PURE__ */ jsx(Separator, {}),
6993
- /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
7886
+ ] }),
7887
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
6994
7888
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
6995
- /* @__PURE__ */ jsx(Truck, { className: "h-4 w-4 text-muted-foreground" }),
6996
- /* @__PURE__ */ jsx("span", { className: "text-sm font-medium", children: "Deliveries" }),
6997
- /* @__PURE__ */ jsxs("span", { className: "text-xs text-muted-foreground ml-auto", children: [
6998
- data.deliveries.length,
6999
- " scheduled"
7889
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-muted-foreground", children: "Comments" }),
7890
+ hasProductionComments && /* @__PURE__ */ jsxs("span", { className: "text-[10px] text-muted-foreground", children: [
7891
+ "(",
7892
+ production?.comments?.length,
7893
+ ")"
7000
7894
  ] })
7001
7895
  ] }),
7002
- /* @__PURE__ */ jsx("div", { className: "space-y-2", children: data.deliveries.map((delivery, index) => /* @__PURE__ */ jsx(DeliveryCard, { delivery, index }, delivery.id)) })
7896
+ /* @__PURE__ */ jsx(
7897
+ ProductionCommentSection,
7898
+ {
7899
+ comments: production?.comments,
7900
+ onAddComment: onAddProductionComment
7901
+ }
7902
+ )
7003
7903
  ] })
7004
7904
  ] }),
7005
- data.type === "no-logistics" && /* @__PURE__ */ jsxs(Fragment, { children: [
7006
- /* @__PURE__ */ jsx(Separator, {}),
7007
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-muted-foreground p-3 bg-muted/50 rounded-lg", children: [
7008
- /* @__PURE__ */ jsx(Truck, { className: "h-4 w-4" }),
7009
- /* @__PURE__ */ jsx("span", { className: "text-sm", children: "No logistics scheduled for this week" })
7010
- ] })
7905
+ data.deliveries && data.deliveries.length > 0 && /* @__PURE__ */ jsxs("section", { className: "space-y-4", children: [
7906
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
7907
+ /* @__PURE__ */ jsx(Truck, { className: "h-4 w-4 text-muted-foreground" }),
7908
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-semibold", children: "Deliveries" }),
7909
+ /* @__PURE__ */ jsxs("span", { className: "text-xs text-muted-foreground ml-auto", children: [
7910
+ data.deliveries.length,
7911
+ " scheduled"
7912
+ ] })
7913
+ ] }),
7914
+ /* @__PURE__ */ jsx("div", { className: "space-y-2", children: data.deliveries.map((delivery, index) => /* @__PURE__ */ jsx(
7915
+ DeliveryListItem,
7916
+ {
7917
+ delivery,
7918
+ index,
7919
+ onClick: () => onSelectDelivery(delivery)
7920
+ },
7921
+ delivery.id
7922
+ )) })
7011
7923
  ] }),
7012
- data.hasWarning && data.warningMessage && /* @__PURE__ */ jsxs(Fragment, { children: [
7013
- /* @__PURE__ */ jsx(Separator, {}),
7014
- /* @__PURE__ */ 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: [
7015
- /* @__PURE__ */ jsx(AlertTriangle, { className: "h-4 w-4 mt-0.5 shrink-0" }),
7016
- /* @__PURE__ */ jsx("div", { className: "text-sm", children: data.warningMessage })
7017
- ] })
7924
+ data.type === "no-logistics" && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-muted-foreground p-3 bg-muted/50 rounded-lg", children: [
7925
+ /* @__PURE__ */ jsx(Truck, { className: "h-4 w-4" }),
7926
+ /* @__PURE__ */ jsx("span", { className: "text-sm", children: "No logistics scheduled for this week" })
7018
7927
  ] }),
7019
- data.notes && /* @__PURE__ */ jsxs(Fragment, { children: [
7020
- /* @__PURE__ */ jsx(Separator, {}),
7021
- /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
7022
- /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: "Notes" }),
7023
- /* @__PURE__ */ jsx("p", { className: "text-sm", children: data.notes })
7024
- ] })
7928
+ data.hasWarning && data.warningMessage && /* @__PURE__ */ 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: [
7929
+ /* @__PURE__ */ jsx(AlertTriangle, { className: "h-4 w-4 mt-0.5 shrink-0" }),
7930
+ /* @__PURE__ */ jsx("div", { className: "text-sm", children: data.warningMessage })
7931
+ ] }),
7932
+ data.notes && /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
7933
+ /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: "Notes" }),
7934
+ /* @__PURE__ */ jsx("p", { className: "text-sm", children: data.notes })
7025
7935
  ] })
7026
- ] })
7027
- ] }) });
7936
+ ] }) })
7937
+ ] });
7938
+ }
7939
+ function WeekDetailDialog({
7940
+ open,
7941
+ onOpenChange,
7942
+ supplier,
7943
+ week,
7944
+ data,
7945
+ onProgressUpdate,
7946
+ onAddProductionComment,
7947
+ onAddDeliveryComment
7948
+ }) {
7949
+ const production = data?.production;
7950
+ const initialProduced = production?.produced ?? 0;
7951
+ const [producedValue, setProducedValue] = React22.useState(initialProduced.toString());
7952
+ const [hasChanges, setHasChanges] = React22.useState(false);
7953
+ const [selectedDelivery, setSelectedDelivery] = React22.useState(null);
7954
+ React22.useEffect(() => {
7955
+ const newProduced = data?.production?.produced ?? 0;
7956
+ setProducedValue(newProduced.toString());
7957
+ setHasChanges(false);
7958
+ }, [data]);
7959
+ React22.useEffect(() => {
7960
+ if (!open) {
7961
+ setSelectedDelivery(null);
7962
+ }
7963
+ }, [open]);
7964
+ const handleProducedChange = (e) => {
7965
+ const value = e.target.value;
7966
+ setProducedValue(value);
7967
+ setHasChanges(true);
7968
+ };
7969
+ const handleSave = () => {
7970
+ if (!supplier || !week || !onProgressUpdate) return;
7971
+ const newProduced = parseFloat(producedValue) || 0;
7972
+ const target = production?.target || 100;
7973
+ const newProgress = Math.min(100, Math.round(newProduced / target * 100));
7974
+ const weekKey = `${week.year}-W${week.weekNumber.toString().padStart(2, "0")}`;
7975
+ onProgressUpdate(supplier.id, weekKey, newProgress, newProduced);
7976
+ setHasChanges(false);
7977
+ };
7978
+ if (!supplier || !week || !data) {
7979
+ return null;
7980
+ }
7981
+ return /* @__PURE__ */ jsx(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsx(DialogContent, { className: "max-w-lg max-h-[85vh] p-0 gap-0 overflow-hidden", children: selectedDelivery ? /* @__PURE__ */ jsx(
7982
+ DeliveryDetailsView,
7983
+ {
7984
+ delivery: selectedDelivery,
7985
+ week,
7986
+ onBack: () => setSelectedDelivery(null),
7987
+ onAddComment: onAddDeliveryComment ? (text) => {
7988
+ const weekKey = `${week.year}-W${week.weekNumber.toString().padStart(2, "0")}`;
7989
+ onAddDeliveryComment(supplier.id, weekKey, selectedDelivery.id, text);
7990
+ } : void 0
7991
+ }
7992
+ ) : /* @__PURE__ */ jsx(
7993
+ MainView,
7994
+ {
7995
+ supplier,
7996
+ week,
7997
+ data,
7998
+ producedValue,
7999
+ hasChanges,
8000
+ onProducedChange: handleProducedChange,
8001
+ onSave: handleSave,
8002
+ onSelectDelivery: setSelectedDelivery,
8003
+ onAddProductionComment: onAddProductionComment ? (text) => {
8004
+ const weekKey = `${week.year}-W${week.weekNumber.toString().padStart(2, "0")}`;
8005
+ onAddProductionComment(supplier.id, weekKey, text);
8006
+ } : void 0
8007
+ }
8008
+ ) }) });
8009
+ }
8010
+ function RowHeaderCell({
8011
+ className,
8012
+ data,
8013
+ showProgress = true,
8014
+ ...props
8015
+ }) {
8016
+ const progressPercent = data.totalRequired > 0 ? Math.min(data.totalBooked / data.totalRequired * 100, 100) : 0;
8017
+ return /* @__PURE__ */ jsxs(
8018
+ "div",
8019
+ {
8020
+ "data-slot": "row-header-cell",
8021
+ className: cn(
8022
+ "flex flex-col justify-center gap-1.5 py-2 px-3 min-w-[200px] h-[100px] bg-background",
8023
+ className
8024
+ ),
8025
+ ...props,
8026
+ children: [
8027
+ /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-2", children: [
8028
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col min-w-0 flex-1", children: [
8029
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-bold leading-tight text-foreground truncate", children: data.name }),
8030
+ /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: data.typeCode })
8031
+ ] }),
8032
+ /* @__PURE__ */ jsxs(
8033
+ Badge,
8034
+ {
8035
+ variant: "outline",
8036
+ className: "text-[10px] px-2 py-0.5 h-[19px] font-medium shrink-0 gap-1 bg-background border-border",
8037
+ children: [
8038
+ /* @__PURE__ */ jsx(Flag, { className: "h-2.5 w-2.5" }),
8039
+ "Paint"
8040
+ ]
8041
+ }
8042
+ )
8043
+ ] }),
8044
+ showProgress && /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
8045
+ /* @__PURE__ */ jsx("div", { className: "h-1.5 bg-black/10 dark:bg-white/10 rounded-full overflow-hidden", children: /* @__PURE__ */ jsx(
8046
+ "div",
8047
+ {
8048
+ className: "h-full bg-primary rounded-full transition-all",
8049
+ style: { width: `${progressPercent}%` }
8050
+ }
8051
+ ) }),
8052
+ /* @__PURE__ */ jsxs("span", { className: "text-[10px] font-medium text-primary", children: [
8053
+ data.totalBooked.toLocaleString(),
8054
+ " / ",
8055
+ data.totalRequired.toLocaleString(),
8056
+ " Booked"
8057
+ ] })
8058
+ ] })
8059
+ ]
8060
+ }
8061
+ );
8062
+ }
8063
+ function NetBadge({
8064
+ className,
8065
+ net,
8066
+ status,
8067
+ compact = false,
8068
+ ...props
8069
+ }) {
8070
+ const statusStyles = {
8071
+ pending: {
8072
+ container: "bg-muted border-border/50",
8073
+ text: "text-muted-foreground",
8074
+ icon: "text-muted-foreground"
8075
+ },
8076
+ valid: {
8077
+ container: "bg-green-100/50 border-green-500 dark:bg-green-950/30 dark:border-green-400",
8078
+ text: "text-green-700 dark:text-green-400",
8079
+ icon: "text-green-600 dark:text-green-400"
8080
+ },
8081
+ shortfall: {
8082
+ container: "bg-red-100/30 border-red-400/50 dark:bg-red-950/30 dark:border-red-400/50",
8083
+ text: "text-red-700 dark:text-red-400",
8084
+ icon: "text-red-600 dark:text-red-400"
8085
+ }
8086
+ };
8087
+ const styles = statusStyles[status];
8088
+ return /* @__PURE__ */ jsxs(
8089
+ "div",
8090
+ {
8091
+ "data-slot": "net-badge",
8092
+ "data-status": status,
8093
+ className: cn(
8094
+ "inline-flex items-center gap-1.5 px-3 py-0.5 rounded-full border",
8095
+ styles.container,
8096
+ className
8097
+ ),
8098
+ ...props,
8099
+ children: [
8100
+ status === "valid" && /* @__PURE__ */ jsx(Check, { className: cn("h-3 w-3", styles.icon) }),
8101
+ /* @__PURE__ */ jsx("span", { className: cn(
8102
+ "text-xs font-bold leading-none",
8103
+ styles.text
8104
+ ), children: net >= 0 ? net : net }),
8105
+ !compact && /* @__PURE__ */ jsx("span", { className: cn(
8106
+ "text-[10px] font-light opacity-80",
8107
+ styles.text
8108
+ ), children: "net" })
8109
+ ]
8110
+ }
8111
+ );
8112
+ }
8113
+
8114
+ // src/blocks/calibration-table/types.ts
8115
+ function formatCalibrationUnit(unit) {
8116
+ const unitLabels = {
8117
+ ton: "tons",
8118
+ pcs: "pcs",
8119
+ m2: "m\xB2",
8120
+ kg: "kg",
8121
+ m: "m"
8122
+ };
8123
+ return unitLabels[unit] || unit;
8124
+ }
8125
+ function calculateCalibrationCells(weeks) {
8126
+ const result = {};
8127
+ let accumulatedPlanned = 0;
8128
+ let accumulatedEntered = 0;
8129
+ for (const week of weeks) {
8130
+ accumulatedPlanned += week.planned;
8131
+ accumulatedEntered += week.entered ?? 0;
8132
+ const net = accumulatedEntered - accumulatedPlanned;
8133
+ let status = "pending";
8134
+ if (week.entered !== null) {
8135
+ status = net >= 0 ? "valid" : "shortfall";
8136
+ }
8137
+ result[week.weekKey] = {
8138
+ planned: week.planned,
8139
+ entered: week.entered,
8140
+ accumulatedPlanned,
8141
+ accumulatedEntered,
8142
+ net,
8143
+ status,
8144
+ isEditable: true
8145
+ };
8146
+ }
8147
+ return result;
8148
+ }
8149
+ function canSubmitCalibration(prefixes) {
8150
+ let shortfallCount = 0;
8151
+ let pendingCount = 0;
8152
+ for (const prefix of prefixes) {
8153
+ for (const weekKey in prefix.weeks) {
8154
+ const cell = prefix.weeks[weekKey];
8155
+ if (cell.status === "shortfall") shortfallCount++;
8156
+ if (cell.status === "pending") pendingCount++;
8157
+ }
8158
+ }
8159
+ const canSubmit = shortfallCount === 0 && pendingCount === 0;
8160
+ let message = "";
8161
+ if (shortfallCount > 0) {
8162
+ message = `Resolve ${shortfallCount} shortfall${shortfallCount > 1 ? "s" : ""} to submit`;
8163
+ } else if (pendingCount > 0) {
8164
+ message = `Enter production amounts for ${pendingCount} week${pendingCount > 1 ? "s" : ""}`;
8165
+ } else {
8166
+ message = "Ready to submit";
8167
+ }
8168
+ return { canSubmit, shortfallCount, pendingCount, message };
8169
+ }
8170
+ function CalibrationWeekCell({
8171
+ className,
8172
+ data,
8173
+ unit,
8174
+ onValueChange,
8175
+ isFocused,
8176
+ forcedRed = false,
8177
+ isEmpty = false,
8178
+ onAddClick,
8179
+ ...props
8180
+ }) {
8181
+ const inputRef = React22.useRef(null);
8182
+ const [localValue, setLocalValue] = React22.useState(
8183
+ data.entered !== null ? String(data.entered) : ""
8184
+ );
8185
+ const [isHovered, setIsHovered] = React22.useState(false);
8186
+ const [isEditing, setIsEditing] = React22.useState(false);
8187
+ React22.useEffect(() => {
8188
+ setLocalValue(data.entered !== null ? String(data.entered) : "");
8189
+ }, [data.entered]);
8190
+ const unitLabel = formatCalibrationUnit(unit);
8191
+ const effectiveStatus = forcedRed ? "forcedRed" : data.status;
8192
+ const handleInputChange = (e) => {
8193
+ const val = e.target.value;
8194
+ setLocalValue(val);
8195
+ if (val === "" || val === "-") {
8196
+ onValueChange?.(null);
8197
+ } else {
8198
+ const numVal = parseFloat(val);
8199
+ if (!isNaN(numVal)) {
8200
+ onValueChange?.(numVal);
8201
+ }
8202
+ }
8203
+ };
8204
+ const handleBlur = () => {
8205
+ setIsEditing(false);
8206
+ if (localValue === "" || localValue === "-") {
8207
+ setLocalValue("");
8208
+ onValueChange?.(null);
8209
+ } else {
8210
+ const numVal = parseFloat(localValue);
8211
+ if (!isNaN(numVal)) {
8212
+ setLocalValue(String(numVal));
8213
+ onValueChange?.(numVal);
8214
+ }
8215
+ }
8216
+ };
8217
+ const handleAddClick = () => {
8218
+ setIsEditing(true);
8219
+ onAddClick?.();
8220
+ setTimeout(() => {
8221
+ inputRef.current?.focus();
8222
+ }, 0);
8223
+ };
8224
+ const getContainerStyles = () => {
8225
+ switch (effectiveStatus) {
8226
+ case "valid":
8227
+ return "border-l-2 border-l-green-500 bg-green-50/50 dark:bg-green-950/30";
8228
+ case "shortfall":
8229
+ case "forcedRed":
8230
+ return "border-l-2 border-l-red-500 bg-red-50/50 dark:bg-red-950/30";
8231
+ case "pending":
8232
+ default:
8233
+ return cn(
8234
+ "bg-background",
8235
+ isHovered ? "border-l-2 border-l-border" : "border-l-2 border-l-transparent"
8236
+ );
8237
+ }
8238
+ };
8239
+ const getInputStyles = () => {
8240
+ switch (effectiveStatus) {
8241
+ case "valid":
8242
+ return "text-green-700 dark:text-green-400";
8243
+ case "shortfall":
8244
+ case "forcedRed":
8245
+ return "text-red-700 dark:text-red-400 font-semibold";
8246
+ default:
8247
+ return "text-foreground";
8248
+ }
8249
+ };
8250
+ const showAddButton = isEmpty && effectiveStatus === "pending" && !isEditing && data.entered === null;
8251
+ if (showAddButton) {
8252
+ return /* @__PURE__ */ jsx(
8253
+ "div",
8254
+ {
8255
+ "data-slot": "calibration-week-cell",
8256
+ "data-status": "empty",
8257
+ className: cn(
8258
+ "flex items-center justify-center h-[100px]",
8259
+ "transition-all duration-200 ease-out",
8260
+ "hover:-translate-y-0.5 hover:shadow-[var(--j3m-shadow-md)]",
8261
+ "bg-background",
8262
+ isHovered ? "border-l-2 border-l-border" : "border-l-2 border-l-transparent",
8263
+ className
8264
+ ),
8265
+ onMouseEnter: () => setIsHovered(true),
8266
+ onMouseLeave: () => setIsHovered(false),
8267
+ ...props,
8268
+ children: /* @__PURE__ */ jsxs(
8269
+ Button,
8270
+ {
8271
+ variant: "ghost",
8272
+ size: "icon",
8273
+ className: cn(
8274
+ "h-10 w-10 rounded-full",
8275
+ "text-muted-foreground/40 hover:text-muted-foreground hover:bg-muted/50",
8276
+ "transition-all duration-200",
8277
+ "shadow-[var(--j3m-shadow-sm)]"
8278
+ ),
8279
+ onClick: handleAddClick,
8280
+ children: [
8281
+ /* @__PURE__ */ jsx(Plus, { className: "h-5 w-5" }),
8282
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Add production amount" })
8283
+ ]
8284
+ }
8285
+ )
8286
+ }
8287
+ );
8288
+ }
8289
+ if (isEmpty && forcedRed) {
8290
+ return /* @__PURE__ */ jsxs(
8291
+ "div",
8292
+ {
8293
+ "data-slot": "calibration-week-cell",
8294
+ "data-status": "forcedRed",
8295
+ className: cn(
8296
+ "flex flex-col items-center justify-center gap-2 h-[100px] px-3 py-2",
8297
+ "transition-all duration-200 ease-out",
8298
+ "hover:-translate-y-0.5 hover:shadow-[var(--j3m-shadow-md)]",
8299
+ "border-l-2 border-l-red-500 bg-red-50/50 dark:bg-red-950/30",
8300
+ className
8301
+ ),
8302
+ onMouseEnter: () => setIsHovered(true),
8303
+ onMouseLeave: () => setIsHovered(false),
8304
+ ...props,
8305
+ children: [
8306
+ /* @__PURE__ */ jsx("span", { className: "text-[10px] font-medium text-red-600 dark:text-red-400 text-center", children: "Behind schedule" }),
8307
+ /* @__PURE__ */ jsx(NetBadge, { net: data.net, status: "shortfall" })
8308
+ ]
8309
+ }
8310
+ );
8311
+ }
8312
+ return /* @__PURE__ */ jsxs(
8313
+ "div",
8314
+ {
8315
+ "data-slot": "calibration-week-cell",
8316
+ "data-status": effectiveStatus,
8317
+ className: cn(
8318
+ "flex flex-col gap-2 px-3 py-2 h-[100px]",
8319
+ // Hover lift effect with shadow (like planning table)
8320
+ "transition-all duration-200 ease-out",
8321
+ "hover:-translate-y-0.5 hover:shadow-[var(--j3m-shadow-md)]",
8322
+ getContainerStyles(),
8323
+ className
8324
+ ),
8325
+ onMouseEnter: () => setIsHovered(true),
8326
+ onMouseLeave: () => setIsHovered(false),
8327
+ ...props,
8328
+ children: [
8329
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
8330
+ /* @__PURE__ */ jsx("span", { className: "text-[10px] font-medium text-muted-foreground tracking-wide", children: "Accumulated" }),
8331
+ /* @__PURE__ */ jsx(NetBadge, { net: data.net, status: forcedRed ? "shortfall" : data.status })
8332
+ ] }),
8333
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
8334
+ /* @__PURE__ */ jsx("span", { className: "text-[10px] font-medium text-muted-foreground tracking-wide", children: "Planned" }),
8335
+ /* @__PURE__ */ jsx("div", { className: "inline-flex items-center justify-center px-2 py-0 bg-card border border-border rounded-full", children: /* @__PURE__ */ jsx("span", { className: "text-[10px] font-medium text-muted-foreground", children: data.planned }) })
8336
+ ] }),
8337
+ /* @__PURE__ */ jsxs("div", { className: "relative", children: [
8338
+ /* @__PURE__ */ jsx(
8339
+ Input,
8340
+ {
8341
+ ref: inputRef,
8342
+ type: "text",
8343
+ inputMode: "decimal",
8344
+ value: localValue,
8345
+ onChange: handleInputChange,
8346
+ onBlur: handleBlur,
8347
+ onFocus: () => setIsEditing(true),
8348
+ disabled: !data.isEditable,
8349
+ placeholder: "Enter amount",
8350
+ className: cn(
8351
+ "h-8 pl-3 pr-12 rounded-full text-sm font-semibold bg-background border-border",
8352
+ // Placeholder: smaller, lighter, lower contrast
8353
+ "placeholder:text-xs placeholder:font-normal placeholder:text-muted-foreground/50",
8354
+ getInputStyles(),
8355
+ !data.isEditable && "opacity-50 cursor-not-allowed"
8356
+ )
8357
+ }
8358
+ ),
8359
+ /* @__PURE__ */ jsx("span", { className: "absolute right-4 top-1/2 -translate-y-1/2 text-[10px] text-muted-foreground/70 pointer-events-none", children: unitLabel })
8360
+ ] })
8361
+ ]
8362
+ }
8363
+ );
8364
+ }
8365
+ function CommentPopover({
8366
+ comments,
8367
+ weekLabel,
8368
+ availablePrefixes,
8369
+ onAddComment,
8370
+ open,
8371
+ onOpenChange
8372
+ }) {
8373
+ const [newCommentText, setNewCommentText] = React22.useState("");
8374
+ const [selectedPrefixId, setSelectedPrefixId] = React22.useState("");
8375
+ const [viewCommentsOpen, setViewCommentsOpen] = React22.useState(true);
8376
+ const [showAddForm, setShowAddForm] = React22.useState(false);
8377
+ const selectedPrefixName = React22.useMemo(() => {
8378
+ const prefix = availablePrefixes.find((p) => p.id === selectedPrefixId);
8379
+ return prefix?.name ?? "";
8380
+ }, [availablePrefixes, selectedPrefixId]);
8381
+ const handleSubmit = () => {
8382
+ if (newCommentText.trim() && selectedPrefixId) {
8383
+ onAddComment?.(newCommentText.trim(), selectedPrefixId, selectedPrefixName);
8384
+ setNewCommentText("");
8385
+ setSelectedPrefixId("");
8386
+ setShowAddForm(false);
8387
+ setViewCommentsOpen(true);
8388
+ }
8389
+ };
8390
+ const handleKeyDown = (e) => {
8391
+ if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) {
8392
+ e.preventDefault();
8393
+ handleSubmit();
8394
+ }
8395
+ if (e.key === "Escape") {
8396
+ setShowAddForm(false);
8397
+ setSelectedPrefixId("");
8398
+ setNewCommentText("");
8399
+ }
8400
+ };
8401
+ const formatDate2 = (date) => {
8402
+ return new Intl.DateTimeFormat("en-US", {
8403
+ month: "short",
8404
+ day: "numeric",
8405
+ hour: "numeric",
8406
+ minute: "2-digit"
8407
+ }).format(date);
8408
+ };
8409
+ const prevOpenRef = React22.useRef(open);
8410
+ React22.useEffect(() => {
8411
+ const wasOpen = prevOpenRef.current;
8412
+ prevOpenRef.current = open;
8413
+ if (wasOpen && !open) {
8414
+ setShowAddForm(false);
8415
+ setNewCommentText("");
8416
+ setSelectedPrefixId("");
8417
+ }
8418
+ }, [open]);
8419
+ return /* @__PURE__ */ jsxs(Popover, { open, onOpenChange, children: [
8420
+ /* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx(CommentButton, { commentCount: comments.length }) }),
8421
+ /* @__PURE__ */ jsxs(
8422
+ PopoverContent,
8423
+ {
8424
+ className: "w-80 p-0 z-[100]",
8425
+ align: "end",
8426
+ sideOffset: 8,
8427
+ collisionPadding: 16,
8428
+ children: [
8429
+ /* @__PURE__ */ jsxs("div", { className: "px-4 py-3 border-b border-border", children: [
8430
+ /* @__PURE__ */ jsx("h4", { className: "text-sm font-semibold", children: "Comments" }),
8431
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: weekLabel })
8432
+ ] }),
8433
+ /* @__PURE__ */ jsxs("div", { className: "p-2 space-y-2 max-h-[400px] overflow-y-auto", children: [
8434
+ /* @__PURE__ */ jsxs(Collapsible, { open: viewCommentsOpen, onOpenChange: setViewCommentsOpen, children: [
8435
+ /* @__PURE__ */ jsx(CollapsibleTrigger2, { asChild: true, children: /* @__PURE__ */ jsxs(
8436
+ Button,
8437
+ {
8438
+ variant: "ghost",
8439
+ size: "sm",
8440
+ className: "w-full justify-between h-8 px-2",
8441
+ children: [
8442
+ /* @__PURE__ */ jsxs("span", { className: "text-xs font-medium", children: [
8443
+ "Comments ",
8444
+ comments.length > 0 && `(${comments.length})`
8445
+ ] }),
8446
+ /* @__PURE__ */ jsx(ChevronDown, { className: cn(
8447
+ "h-4 w-4 transition-transform duration-200",
8448
+ viewCommentsOpen && "rotate-180"
8449
+ ) })
8450
+ ]
8451
+ }
8452
+ ) }),
8453
+ /* @__PURE__ */ jsx(CollapsibleContent2, { className: "space-y-2 pt-2", children: comments.length > 0 ? comments.map((comment) => /* @__PURE__ */ jsxs(
8454
+ "div",
8455
+ {
8456
+ className: "rounded-lg bg-muted/50 p-3 space-y-2",
8457
+ "aria-label": `Comment by ${comment.author} about ${comment.prefixName}`,
8458
+ children: [
8459
+ /* @__PURE__ */ jsx(
8460
+ Badge,
8461
+ {
8462
+ variant: "outline",
8463
+ className: "text-[10px] px-2 py-0 h-5 font-medium bg-background",
8464
+ children: comment.prefixName
8465
+ }
8466
+ ),
8467
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
8468
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-medium", children: comment.author }),
8469
+ /* @__PURE__ */ jsx("span", { className: "text-[10px] text-muted-foreground", children: formatDate2(comment.createdAt) })
8470
+ ] }),
8471
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-foreground", children: comment.text })
8472
+ ]
8473
+ },
8474
+ comment.id
8475
+ )) : /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground text-center py-2", children: "No comments yet" }) })
8476
+ ] }),
8477
+ /* @__PURE__ */ jsx(Separator, { className: "my-2" }),
8478
+ /* @__PURE__ */ jsx("div", { className: "overflow-hidden", children: !showAddForm ? (
8479
+ /* Add comment Button */
8480
+ /* @__PURE__ */ jsxs(
8481
+ Button,
8482
+ {
8483
+ variant: "outline",
8484
+ size: "sm",
8485
+ className: "w-full justify-center gap-2 h-8",
8486
+ onClick: () => setShowAddForm(true),
8487
+ children: [
8488
+ /* @__PURE__ */ jsx(Plus, { className: "h-3.5 w-3.5" }),
8489
+ "Add comment"
8490
+ ]
8491
+ }
8492
+ )
8493
+ ) : (
8494
+ /* Comment input form with smooth expand animation */
8495
+ /* @__PURE__ */ jsxs(
8496
+ "div",
8497
+ {
8498
+ className: cn(
8499
+ "space-y-3 p-3 rounded-lg border border-border bg-muted/30",
8500
+ "animate-in fade-in-0 slide-in-from-top-2 duration-200"
8501
+ ),
8502
+ children: [
8503
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
8504
+ /* @__PURE__ */ jsxs(Label2, { htmlFor: "prefix-select", className: "text-xs font-medium", children: [
8505
+ "Applies to ",
8506
+ /* @__PURE__ */ jsx("span", { className: "text-destructive", children: "*" })
8507
+ ] }),
8508
+ /* @__PURE__ */ jsxs(Select, { value: selectedPrefixId, onValueChange: setSelectedPrefixId, children: [
8509
+ /* @__PURE__ */ jsx(SelectTrigger, { id: "prefix-select", size: "sm", className: "w-full", children: /* @__PURE__ */ jsx(SelectValue, { placeholder: "Select row/type..." }) }),
8510
+ /* @__PURE__ */ jsx(SelectContent, { children: availablePrefixes.map((prefix) => /* @__PURE__ */ jsx(SelectItem, { value: prefix.id, children: prefix.name }, prefix.id)) })
8511
+ ] })
8512
+ ] }),
8513
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
8514
+ /* @__PURE__ */ jsx(Label2, { htmlFor: "comment-text", className: "text-xs font-medium", children: "Comment" }),
8515
+ /* @__PURE__ */ jsx(
8516
+ Textarea,
8517
+ {
8518
+ id: "comment-text",
8519
+ placeholder: "Type your comment...",
8520
+ value: newCommentText,
8521
+ onChange: (e) => setNewCommentText(e.target.value),
8522
+ onKeyDown: handleKeyDown,
8523
+ className: "min-h-[80px] text-sm resize-none",
8524
+ autoFocus: true
8525
+ }
8526
+ )
8527
+ ] }),
8528
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
8529
+ /* @__PURE__ */ jsx("span", { className: "text-[10px] text-muted-foreground", children: "\u2318+Enter to send \xB7 Esc to cancel" }),
8530
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
8531
+ /* @__PURE__ */ jsx(
8532
+ Button,
8533
+ {
8534
+ variant: "ghost",
8535
+ size: "sm",
8536
+ className: "h-7",
8537
+ onClick: () => {
8538
+ setShowAddForm(false);
8539
+ setNewCommentText("");
8540
+ setSelectedPrefixId("");
8541
+ },
8542
+ children: "Cancel"
8543
+ }
8544
+ ),
8545
+ /* @__PURE__ */ jsxs(
8546
+ Button,
8547
+ {
8548
+ size: "sm",
8549
+ className: "h-7 gap-1",
8550
+ onClick: handleSubmit,
8551
+ disabled: !newCommentText.trim() || !selectedPrefixId,
8552
+ children: [
8553
+ /* @__PURE__ */ jsx(Send, { className: "h-3 w-3" }),
8554
+ "Save"
8555
+ ]
8556
+ }
8557
+ )
8558
+ ] })
8559
+ ] })
8560
+ ]
8561
+ }
8562
+ )
8563
+ ) })
8564
+ ] })
8565
+ ]
8566
+ }
8567
+ )
8568
+ ] });
8569
+ }
8570
+ function CalibrationWeekHeader({
8571
+ className,
8572
+ week,
8573
+ comments = [],
8574
+ showCommentButton = true,
8575
+ availablePrefixes = [],
8576
+ onAddComment,
8577
+ ...props
8578
+ }) {
8579
+ return /* @__PURE__ */ jsxs(
8580
+ "div",
8581
+ {
8582
+ "data-slot": "calibration-week-header",
8583
+ "data-current-week": week.isCurrentWeek,
8584
+ className: cn(
8585
+ "flex items-center justify-between gap-2 px-2 py-2 min-w-[200px]",
8586
+ className
8587
+ ),
8588
+ ...props,
8589
+ children: [
8590
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-0.5", children: [
8591
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
8592
+ /* @__PURE__ */ jsx("span", { className: cn(
8593
+ "text-sm font-semibold tracking-tight",
8594
+ week.isCurrentWeek ? "text-primary" : "text-foreground"
8595
+ ), children: week.label }),
8596
+ week.isCurrentWeek && /* @__PURE__ */ jsxs("span", { className: "relative flex h-2 w-2", children: [
8597
+ /* @__PURE__ */ jsx("span", { className: "animate-ping absolute inline-flex h-full w-full rounded-full bg-primary opacity-75" }),
8598
+ /* @__PURE__ */ jsx("span", { className: "relative inline-flex rounded-full h-2 w-2 bg-primary" })
8599
+ ] })
8600
+ ] }),
8601
+ /* @__PURE__ */ jsx("span", { className: "text-[10px] font-normal text-muted-foreground/60", children: week.dateRange })
8602
+ ] }),
8603
+ showCommentButton && availablePrefixes.length > 0 && /* @__PURE__ */ jsx(
8604
+ CommentPopover,
8605
+ {
8606
+ comments,
8607
+ weekLabel: week.label,
8608
+ availablePrefixes,
8609
+ onAddComment
8610
+ }
8611
+ )
8612
+ ]
8613
+ }
8614
+ );
8615
+ }
8616
+ function CalibrationTable({
8617
+ className,
8618
+ prefixes,
8619
+ supplierName,
8620
+ status = "draft",
8621
+ config = {}
8622
+ }) {
8623
+ const {
8624
+ weekCount = 8,
8625
+ startDate,
8626
+ allowTimelineExtension = true,
8627
+ maxEarlierWeeks = 4,
8628
+ showToolbar = true,
8629
+ showPagination = true,
8630
+ pageSizeOptions = [10, 20, 30],
8631
+ defaultPageSize = 10,
8632
+ stickyRowHeader = true,
8633
+ maxHeight = "500px",
8634
+ onCellChange,
8635
+ onSubmit,
8636
+ onAddComment,
8637
+ onAddEarlierWeek
8638
+ } = config;
8639
+ const calculatedStartDate = React22.useMemo(() => {
8640
+ if (startDate) return startDate;
8641
+ let earliest = null;
8642
+ for (const prefix of prefixes) {
8643
+ for (const weekKey in prefix.weeks) {
8644
+ const cell = prefix.weeks[weekKey];
8645
+ if (cell.planned > 0) {
8646
+ const match = weekKey.match(/(\d{4})-W(\d{2})/);
8647
+ if (match) {
8648
+ const year = parseInt(match[1]);
8649
+ const week = parseInt(match[2]);
8650
+ const date = new Date(year, 0, 1 + (week - 1) * 7);
8651
+ if (earliest === null || date < earliest) {
8652
+ earliest = date;
8653
+ }
8654
+ }
8655
+ }
8656
+ }
8657
+ }
8658
+ return earliest ?? /* @__PURE__ */ new Date();
8659
+ }, [startDate, prefixes]);
8660
+ const [additionalWeeks, setAdditionalWeeks] = React22.useState(0);
8661
+ const weeks = React22.useMemo(() => {
8662
+ const start = new Date(calculatedStartDate);
8663
+ start.setDate(start.getDate() - additionalWeeks * 7);
8664
+ return generateWeeks(start, weekCount + additionalWeeks);
8665
+ }, [calculatedStartDate, weekCount, additionalWeeks]);
8666
+ React22.useMemo(() => {
8667
+ const currentWeek = weeks.find((w) => w.isCurrentWeek);
8668
+ return currentWeek ? getWeekKey(currentWeek.startDate) : null;
8669
+ }, [weeks]);
8670
+ const [currentPage, setCurrentPage] = React22.useState(0);
8671
+ const [pageSize, setPageSize] = React22.useState(defaultPageSize);
8672
+ const [searchQuery, setSearchQuery] = React22.useState("");
8673
+ const filteredPrefixes = React22.useMemo(() => {
8674
+ if (!searchQuery) return prefixes;
8675
+ const query = searchQuery.toLowerCase();
8676
+ return prefixes.filter(
8677
+ (p) => p.name.toLowerCase().includes(query) || p.typeCode.toLowerCase().includes(query)
8678
+ );
8679
+ }, [prefixes, searchQuery]);
8680
+ const paginatedPrefixes = React22.useMemo(() => {
8681
+ const start = currentPage * pageSize;
8682
+ return filteredPrefixes.slice(start, start + pageSize);
8683
+ }, [filteredPrefixes, currentPage, pageSize]);
8684
+ React22.useMemo(
8685
+ () => canSubmitCalibration(prefixes),
8686
+ [prefixes]
8687
+ );
8688
+ const handleAddEarlierWeek = () => {
8689
+ if (additionalWeeks < maxEarlierWeeks) {
8690
+ setAdditionalWeeks((prev) => prev + 1);
8691
+ onAddEarlierWeek?.();
8692
+ }
8693
+ };
8694
+ const handleCellChange = (prefixId, weekKey, value) => {
8695
+ onCellChange?.(prefixId, weekKey, value);
8696
+ };
8697
+ const handleAddWeekComment = (weekKey, text, prefixId, prefixName) => {
8698
+ onAddComment?.(prefixId, weekKey, text);
8699
+ };
8700
+ const getWeekComments = (weekKey) => {
8701
+ const allComments = [];
8702
+ for (const prefix of prefixes) {
8703
+ const weekComments = prefix.comments?.filter((c) => c.weekKey === weekKey) ?? [];
8704
+ allComments.push(...weekComments);
8705
+ }
8706
+ return allComments;
8707
+ };
8708
+ const availablePrefixes = React22.useMemo(
8709
+ () => prefixes.map((p) => ({ id: p.id, name: p.name })),
8710
+ [prefixes]
8711
+ );
8712
+ return /* @__PURE__ */ jsxs(
8713
+ "div",
8714
+ {
8715
+ "data-slot": "calibration-table",
8716
+ className: cn("flex flex-col gap-4", className),
8717
+ children: [
8718
+ /* @__PURE__ */ jsx("div", { className: "flex items-start justify-between gap-4", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
8719
+ /* @__PURE__ */ jsx("h2", { className: "text-2xl font-semibold tracking-tight", children: "Weekly Production Calibration" }),
8720
+ /* @__PURE__ */ jsx("p", { className: "text-muted-foreground", children: "Review required weekly production and confirm achievable output at the selected checkpoint." })
8721
+ ] }) }),
8722
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
8723
+ showToolbar && /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2", children: [
8724
+ /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2", children: /* @__PURE__ */ jsx(
8725
+ Input,
8726
+ {
8727
+ placeholder: "Search prefixes...",
8728
+ value: searchQuery,
8729
+ onChange: (e) => setSearchQuery(e.target.value),
8730
+ className: "h-8 w-[200px] lg:w-[300px]"
8731
+ }
8732
+ ) }),
8733
+ /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2", children: allowTimelineExtension && additionalWeeks < maxEarlierWeeks && /* @__PURE__ */ jsxs(
8734
+ Button,
8735
+ {
8736
+ variant: "outline",
8737
+ size: "sm",
8738
+ className: "gap-2",
8739
+ onClick: handleAddEarlierWeek,
8740
+ children: [
8741
+ /* @__PURE__ */ jsx(Plus, { className: "h-4 w-4" }),
8742
+ "Add earlier week"
8743
+ ]
8744
+ }
8745
+ ) })
8746
+ ] }),
8747
+ /* @__PURE__ */ jsx("div", { className: "rounded-xl border bg-background shadow-sm overflow-hidden", children: /* @__PURE__ */ jsxs(
8748
+ ScrollArea,
8749
+ {
8750
+ className: "w-full",
8751
+ style: { maxHeight },
8752
+ children: [
8753
+ /* @__PURE__ */ jsxs("table", { className: "w-full border-collapse", children: [
8754
+ /* @__PURE__ */ jsx("thead", { className: "sticky top-0 z-20", children: /* @__PURE__ */ jsxs("tr", { children: [
8755
+ /* @__PURE__ */ jsx("th", { className: cn(
8756
+ "h-14 px-3 text-left align-middle font-semibold text-xs text-muted-foreground uppercase tracking-wide",
8757
+ "border-r border-b border-border bg-sidebar",
8758
+ stickyRowHeader && "sticky left-0 z-30 min-w-[200px]",
8759
+ // Right shadow using Quantum token
8760
+ stickyRowHeader && "shadow-[var(--j3m-shadow-sticky-edge)]"
8761
+ ), children: "Supplier / Scope" }),
8762
+ weeks.map((week) => {
8763
+ const weekKey = getWeekKey(week.startDate);
8764
+ const weekComments = getWeekComments(weekKey);
8765
+ return /* @__PURE__ */ jsx(
8766
+ "th",
8767
+ {
8768
+ className: "h-14 px-2 text-left align-middle border-r border-b border-border last:border-r-0 min-w-[220px] bg-sidebar",
8769
+ children: /* @__PURE__ */ jsx(
8770
+ CalibrationWeekHeader,
8771
+ {
8772
+ week,
8773
+ comments: weekComments,
8774
+ showCommentButton: true,
8775
+ availablePrefixes,
8776
+ onAddComment: (text, prefixId, prefixName) => handleAddWeekComment(weekKey, text, prefixId)
8777
+ }
8778
+ )
8779
+ },
8780
+ weekKey
8781
+ );
8782
+ })
8783
+ ] }) }),
8784
+ /* @__PURE__ */ jsx("tbody", { className: "bg-background", children: paginatedPrefixes.length > 0 ? paginatedPrefixes.map((prefix) => {
8785
+ const sortedWeekKeys = weeks.map((w) => getWeekKey(w.startDate));
8786
+ let hasDeficit = false;
8787
+ const forcedRedMap = {};
8788
+ for (const weekKey of sortedWeekKeys) {
8789
+ const cellData = prefix.weeks[weekKey];
8790
+ if (hasDeficit) {
8791
+ forcedRedMap[weekKey] = true;
8792
+ } else if (cellData && cellData.status === "shortfall") {
8793
+ hasDeficit = true;
8794
+ forcedRedMap[weekKey] = false;
8795
+ } else {
8796
+ forcedRedMap[weekKey] = false;
8797
+ }
8798
+ }
8799
+ return /* @__PURE__ */ jsxs("tr", { className: "border-b border-border last:border-b-0", children: [
8800
+ /* @__PURE__ */ jsx(
8801
+ "td",
8802
+ {
8803
+ className: cn(
8804
+ "p-0 align-top border-r border-border bg-background",
8805
+ stickyRowHeader && "sticky left-0 z-10 min-w-[200px]",
8806
+ // Right shadow using Quantum token
8807
+ stickyRowHeader && "shadow-[var(--j3m-shadow-sticky-edge)]"
8808
+ ),
8809
+ children: /* @__PURE__ */ jsx(RowHeaderCell, { data: prefix, showProgress: true })
8810
+ }
8811
+ ),
8812
+ weeks.map((week) => {
8813
+ const weekKey = getWeekKey(week.startDate);
8814
+ const cellData = prefix.weeks[weekKey];
8815
+ const isForcedRed = forcedRedMap[weekKey] ?? false;
8816
+ const isEmpty = !cellData || cellData.planned === 0;
8817
+ const effectiveCellData = cellData ?? {
8818
+ planned: 0,
8819
+ entered: null,
8820
+ accumulatedPlanned: 0,
8821
+ accumulatedEntered: 0,
8822
+ net: 0,
8823
+ status: "pending",
8824
+ isEditable: true
8825
+ };
8826
+ return /* @__PURE__ */ jsx(
8827
+ "td",
8828
+ {
8829
+ className: "p-0 align-top border-r border-border last:border-r-0 min-w-[220px] bg-background",
8830
+ children: /* @__PURE__ */ jsx(
8831
+ CalibrationWeekCell,
8832
+ {
8833
+ data: effectiveCellData,
8834
+ unit: prefix.unit,
8835
+ onValueChange: (value) => handleCellChange(prefix.id, weekKey, value),
8836
+ forcedRed: isForcedRed,
8837
+ isEmpty,
8838
+ onAddClick: () => {
8839
+ }
8840
+ }
8841
+ )
8842
+ },
8843
+ weekKey
8844
+ );
8845
+ })
8846
+ ] }, prefix.id);
8847
+ }) : /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx(
8848
+ "td",
8849
+ {
8850
+ colSpan: weeks.length + 1,
8851
+ className: "h-24 text-center text-muted-foreground bg-background",
8852
+ children: "No prefixes found."
8853
+ }
8854
+ ) }) })
8855
+ ] }),
8856
+ /* @__PURE__ */ jsx(ScrollBar, { orientation: "horizontal" }),
8857
+ /* @__PURE__ */ jsx(ScrollBar, { orientation: "vertical" })
8858
+ ]
8859
+ }
8860
+ ) })
8861
+ ] }),
8862
+ showPagination && filteredPrefixes.length > pageSize && /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-2", children: [
8863
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-sm text-muted-foreground", children: [
8864
+ /* @__PURE__ */ jsx("span", { children: "Rows per page" }),
8865
+ /* @__PURE__ */ jsx(
8866
+ "select",
8867
+ {
8868
+ value: pageSize,
8869
+ onChange: (e) => {
8870
+ setPageSize(Number(e.target.value));
8871
+ setCurrentPage(0);
8872
+ },
8873
+ className: "h-8 w-16 rounded-md border bg-background px-2 text-sm",
8874
+ children: pageSizeOptions.map((size) => /* @__PURE__ */ jsx("option", { value: size, children: size }, size))
8875
+ }
8876
+ )
8877
+ ] }),
8878
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-sm text-muted-foreground", children: [
8879
+ /* @__PURE__ */ jsxs("span", { children: [
8880
+ "Page ",
8881
+ currentPage + 1,
8882
+ " of ",
8883
+ Math.ceil(filteredPrefixes.length / pageSize)
8884
+ ] }),
8885
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
8886
+ /* @__PURE__ */ jsx(
8887
+ Button,
8888
+ {
8889
+ variant: "outline",
8890
+ size: "icon",
8891
+ className: "h-8 w-8",
8892
+ disabled: currentPage === 0,
8893
+ onClick: () => setCurrentPage(0),
8894
+ children: "\xAB\xAB"
8895
+ }
8896
+ ),
8897
+ /* @__PURE__ */ jsx(
8898
+ Button,
8899
+ {
8900
+ variant: "outline",
8901
+ size: "icon",
8902
+ className: "h-8 w-8",
8903
+ disabled: currentPage === 0,
8904
+ onClick: () => setCurrentPage((prev) => prev - 1),
8905
+ children: "\xAB"
8906
+ }
8907
+ ),
8908
+ /* @__PURE__ */ jsx(
8909
+ Button,
8910
+ {
8911
+ variant: "outline",
8912
+ size: "icon",
8913
+ className: "h-8 w-8",
8914
+ disabled: currentPage >= Math.ceil(filteredPrefixes.length / pageSize) - 1,
8915
+ onClick: () => setCurrentPage((prev) => prev + 1),
8916
+ children: "\xBB"
8917
+ }
8918
+ ),
8919
+ /* @__PURE__ */ jsx(
8920
+ Button,
8921
+ {
8922
+ variant: "outline",
8923
+ size: "icon",
8924
+ className: "h-8 w-8",
8925
+ disabled: currentPage >= Math.ceil(filteredPrefixes.length / pageSize) - 1,
8926
+ onClick: () => setCurrentPage(Math.ceil(filteredPrefixes.length / pageSize) - 1),
8927
+ children: "\xBB\xBB"
8928
+ }
8929
+ )
8930
+ ] })
8931
+ ] })
8932
+ ] })
8933
+ ]
8934
+ }
8935
+ );
8936
+ }
8937
+ function CommentDialog({
8938
+ prefixes,
8939
+ weeks,
8940
+ onAddComment,
8941
+ triggerVariant = "outline",
8942
+ open,
8943
+ onOpenChange
8944
+ }) {
8945
+ const [selectedPrefixId, setSelectedPrefixId] = React22.useState("");
8946
+ const [selectedWeekKey, setSelectedWeekKey] = React22.useState("");
8947
+ const [commentText, setCommentText] = React22.useState("");
8948
+ const currentWeek = React22.useMemo(
8949
+ () => weeks.find((w) => w.isCurrentWeek),
8950
+ [weeks]
8951
+ );
8952
+ React22.useEffect(() => {
8953
+ if (open) {
8954
+ setSelectedPrefixId(prefixes[0]?.id ?? "");
8955
+ setSelectedWeekKey(currentWeek ? getWeekKey(currentWeek.startDate) : weeks[0] ? getWeekKey(weeks[0].startDate) : "");
8956
+ setCommentText("");
8957
+ }
8958
+ }, [open, prefixes, weeks, currentWeek]);
8959
+ const handleSave = () => {
8960
+ if (selectedPrefixId && selectedWeekKey && commentText.trim()) {
8961
+ onAddComment?.(selectedPrefixId, selectedWeekKey, commentText.trim());
8962
+ onOpenChange?.(false);
8963
+ }
8964
+ };
8965
+ const isValid = selectedPrefixId && selectedWeekKey && commentText.trim();
8966
+ return /* @__PURE__ */ jsxs(Dialog, { open, onOpenChange, children: [
8967
+ /* @__PURE__ */ jsx(DialogTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(Button, { variant: triggerVariant, size: "sm", className: "gap-2", children: [
8968
+ /* @__PURE__ */ jsx(MessageSquarePlus, { className: "h-4 w-4" }),
8969
+ "Add comment"
8970
+ ] }) }),
8971
+ /* @__PURE__ */ jsxs(DialogContent, { className: "sm:max-w-[425px]", children: [
8972
+ /* @__PURE__ */ jsxs(DialogHeader, { children: [
8973
+ /* @__PURE__ */ jsx(DialogTitle, { children: "Add Comment" }),
8974
+ /* @__PURE__ */ jsx(DialogDescription, { children: "Add a comment to a specific prefix and week. Comments help communicate production updates and issues." })
8975
+ ] }),
8976
+ /* @__PURE__ */ jsxs("div", { className: "grid gap-4 py-4", children: [
8977
+ /* @__PURE__ */ jsxs("div", { className: "grid gap-2", children: [
8978
+ /* @__PURE__ */ jsx(Label2, { htmlFor: "prefix-select", children: "Prefix / Element Type" }),
8979
+ /* @__PURE__ */ jsxs(Select, { value: selectedPrefixId, onValueChange: setSelectedPrefixId, children: [
8980
+ /* @__PURE__ */ jsx(SelectTrigger, { id: "prefix-select", children: /* @__PURE__ */ jsx(SelectValue, { placeholder: "Select prefix..." }) }),
8981
+ /* @__PURE__ */ jsx(SelectContent, { children: prefixes.map((prefix) => /* @__PURE__ */ jsx(SelectItem, { value: prefix.id, children: /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-2", children: [
8982
+ /* @__PURE__ */ jsx("span", { className: "font-medium", children: prefix.name }),
8983
+ /* @__PURE__ */ jsxs("span", { className: "text-muted-foreground text-xs", children: [
8984
+ "(",
8985
+ prefix.typeCode,
8986
+ ")"
8987
+ ] })
8988
+ ] }) }, prefix.id)) })
8989
+ ] })
8990
+ ] }),
8991
+ /* @__PURE__ */ jsxs("div", { className: "grid gap-2", children: [
8992
+ /* @__PURE__ */ jsx(Label2, { htmlFor: "week-select", children: "Week" }),
8993
+ /* @__PURE__ */ jsxs(Select, { value: selectedWeekKey, onValueChange: setSelectedWeekKey, children: [
8994
+ /* @__PURE__ */ jsx(SelectTrigger, { id: "week-select", children: /* @__PURE__ */ jsx(SelectValue, { placeholder: "Select week..." }) }),
8995
+ /* @__PURE__ */ jsx(SelectContent, { children: weeks.map((week) => {
8996
+ const weekKey = getWeekKey(week.startDate);
8997
+ return /* @__PURE__ */ jsx(SelectItem, { value: weekKey, children: /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-2", children: [
8998
+ /* @__PURE__ */ jsx("span", { className: cn(
8999
+ "font-medium",
9000
+ week.isCurrentWeek && "text-primary"
9001
+ ), children: week.label }),
9002
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground text-xs", children: week.dateRange }),
9003
+ week.isCurrentWeek && /* @__PURE__ */ jsx("span", { className: "text-[10px] text-primary font-medium", children: "(Current)" })
9004
+ ] }) }, weekKey);
9005
+ }) })
9006
+ ] })
9007
+ ] }),
9008
+ /* @__PURE__ */ jsxs("div", { className: "grid gap-2", children: [
9009
+ /* @__PURE__ */ jsx(Label2, { htmlFor: "comment-text", children: "Comment" }),
9010
+ /* @__PURE__ */ jsx(
9011
+ Textarea,
9012
+ {
9013
+ id: "comment-text",
9014
+ placeholder: "Enter your comment...",
9015
+ value: commentText,
9016
+ onChange: (e) => setCommentText(e.target.value),
9017
+ className: "min-h-[100px] resize-none"
9018
+ }
9019
+ )
9020
+ ] })
9021
+ ] }),
9022
+ /* @__PURE__ */ jsxs(DialogFooter, { children: [
9023
+ /* @__PURE__ */ jsx(Button, { variant: "outline", onClick: () => onOpenChange?.(false), children: "Cancel" }),
9024
+ /* @__PURE__ */ jsx(Button, { onClick: handleSave, disabled: !isValid, children: "Save comment" })
9025
+ ] })
9026
+ ] })
9027
+ ] });
9028
+ }
9029
+ function getStatusBadge(status) {
9030
+ switch (status) {
9031
+ case "draft":
9032
+ return { variant: "secondary", label: "DRAFT", color: "bg-blue-500" };
9033
+ case "submitted":
9034
+ return { variant: "secondary", label: "SUBMITTED", color: "bg-amber-500" };
9035
+ case "approved":
9036
+ return { variant: "secondary", label: "APPROVED", color: "bg-green-500" };
9037
+ case "rejected":
9038
+ return { variant: "destructive", label: "REJECTED", color: "bg-red-500" };
9039
+ }
9040
+ }
9041
+ function formatDate(date) {
9042
+ return date.toLocaleDateString("en-US", {
9043
+ month: "short",
9044
+ day: "2-digit",
9045
+ year: "numeric"
9046
+ });
9047
+ }
9048
+ function SubmitCalibrationBar({
9049
+ className,
9050
+ status,
9051
+ lastSaved,
9052
+ canSubmit,
9053
+ shortfallCount,
9054
+ pendingCount,
9055
+ message,
9056
+ onSubmit,
9057
+ onSaveDraft,
9058
+ ...props
9059
+ }) {
9060
+ const statusBadge = getStatusBadge(status);
9061
+ return /* @__PURE__ */ jsxs(
9062
+ "div",
9063
+ {
9064
+ "data-slot": "submit-calibration-bar",
9065
+ className: cn(
9066
+ "flex items-center justify-between gap-4 px-4 py-4",
9067
+ "bg-background",
9068
+ className
9069
+ ),
9070
+ ...props,
9071
+ children: [
9072
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
9073
+ !canSubmit && (shortfallCount > 0 || pendingCount > 0) && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-sm", children: [
9074
+ /* @__PURE__ */ jsx(AlertTriangle, { className: "h-4 w-4 text-amber-500" }),
9075
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: message })
9076
+ ] }),
9077
+ canSubmit && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-sm", children: [
9078
+ /* @__PURE__ */ jsx(CheckCircle, { className: "h-4 w-4 text-green-500" }),
9079
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: message })
9080
+ ] })
9081
+ ] }),
9082
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
9083
+ /* @__PURE__ */ jsxs(
9084
+ Badge,
9085
+ {
9086
+ variant: statusBadge.variant,
9087
+ className: "flex items-center gap-2 px-3 py-1 rounded-full",
9088
+ children: [
9089
+ /* @__PURE__ */ jsx("span", { className: cn("h-2 w-2 rounded-full", statusBadge.color) }),
9090
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-medium", children: statusBadge.label })
9091
+ ]
9092
+ }
9093
+ ),
9094
+ lastSaved && /* @__PURE__ */ jsxs(
9095
+ Button,
9096
+ {
9097
+ variant: "outline",
9098
+ size: "sm",
9099
+ className: "gap-2 rounded-full",
9100
+ disabled: true,
9101
+ children: [
9102
+ /* @__PURE__ */ jsx(Calendar$1, { className: "h-4 w-4" }),
9103
+ /* @__PURE__ */ jsx("span", { children: formatDate(lastSaved) })
9104
+ ]
9105
+ }
9106
+ ),
9107
+ /* @__PURE__ */ jsx(
9108
+ Button,
9109
+ {
9110
+ size: "sm",
9111
+ className: "rounded-full px-4 min-w-[140px]",
9112
+ disabled: !canSubmit || status === "submitted" || status === "approved",
9113
+ onClick: onSubmit,
9114
+ children: status === "submitted" ? "Submitted" : status === "approved" ? "Approved" : "Submit calibration"
9115
+ }
9116
+ )
9117
+ ] })
9118
+ ]
9119
+ }
9120
+ );
7028
9121
  }
7029
9122
 
7030
9123
  // src/components/event-calendar/types.ts
@@ -7089,7 +9182,7 @@ var BADGE_VARIANT_LABELS = {
7089
9182
  colored: "Colored",
7090
9183
  mixed: "Mixed"
7091
9184
  };
7092
- var CalendarContext = React17.createContext(null);
9185
+ var CalendarContext = React22.createContext(null);
7093
9186
  function EventCalendarProvider({
7094
9187
  children,
7095
9188
  events: initialEvents = [],
@@ -7104,38 +9197,38 @@ function EventCalendarProvider({
7104
9197
  onEventUpdate,
7105
9198
  onEventDelete
7106
9199
  }) {
7107
- const [selectedDate, setSelectedDate] = React17.useState(defaultDate);
7108
- const [selectedUserId, setSelectedUserId] = React17.useState(defaultUserId);
7109
- const [events, setEventsState] = React17.useState(initialEvents);
7110
- const [users] = React17.useState(initialUsers);
7111
- const [badgeVariant, setBadgeVariant] = React17.useState(defaultBadgeVariant);
7112
- const [view, setView] = React17.useState(defaultView);
7113
- const [workingHours, setWorkingHours] = React17.useState(defaultWorkingHours);
7114
- const [visibleHours, setVisibleHours] = React17.useState(defaultVisibleHours);
7115
- React17.useEffect(() => {
9200
+ const [selectedDate, setSelectedDate] = React22.useState(defaultDate);
9201
+ const [selectedUserId, setSelectedUserId] = React22.useState(defaultUserId);
9202
+ const [events, setEventsState] = React22.useState(initialEvents);
9203
+ const [users] = React22.useState(initialUsers);
9204
+ const [badgeVariant, setBadgeVariant] = React22.useState(defaultBadgeVariant);
9205
+ const [view, setView] = React22.useState(defaultView);
9206
+ const [workingHours, setWorkingHours] = React22.useState(defaultWorkingHours);
9207
+ const [visibleHours, setVisibleHours] = React22.useState(defaultVisibleHours);
9208
+ React22.useEffect(() => {
7116
9209
  setEventsState(initialEvents);
7117
9210
  }, [initialEvents]);
7118
- const setEvents = React17.useCallback((newEvents) => {
9211
+ const setEvents = React22.useCallback((newEvents) => {
7119
9212
  setEventsState(newEvents);
7120
9213
  }, []);
7121
- const addEvent = React17.useCallback((event) => {
9214
+ const addEvent = React22.useCallback((event) => {
7122
9215
  setEventsState((prev) => [...prev, event]);
7123
9216
  onEventAdd?.(event);
7124
9217
  }, [onEventAdd]);
7125
- const updateEvent = React17.useCallback((event) => {
9218
+ const updateEvent = React22.useCallback((event) => {
7126
9219
  setEventsState(
7127
9220
  (prev) => prev.map((e) => e.id === event.id ? event : e)
7128
9221
  );
7129
9222
  onEventUpdate?.(event);
7130
9223
  }, [onEventUpdate]);
7131
- const deleteEvent = React17.useCallback((eventId) => {
9224
+ const deleteEvent = React22.useCallback((eventId) => {
7132
9225
  setEventsState((prev) => prev.filter((e) => e.id !== eventId));
7133
9226
  onEventDelete?.(eventId);
7134
9227
  }, [onEventDelete]);
7135
- const goToToday = React17.useCallback(() => {
9228
+ const goToToday = React22.useCallback(() => {
7136
9229
  setSelectedDate(/* @__PURE__ */ new Date());
7137
9230
  }, []);
7138
- const goToPrevious = React17.useCallback(() => {
9231
+ const goToPrevious = React22.useCallback(() => {
7139
9232
  setSelectedDate((current) => {
7140
9233
  switch (view) {
7141
9234
  case "day":
@@ -7153,7 +9246,7 @@ function EventCalendarProvider({
7153
9246
  }
7154
9247
  });
7155
9248
  }, [view]);
7156
- const goToNext = React17.useCallback(() => {
9249
+ const goToNext = React22.useCallback(() => {
7157
9250
  setSelectedDate((current) => {
7158
9251
  switch (view) {
7159
9252
  case "day":
@@ -7171,7 +9264,7 @@ function EventCalendarProvider({
7171
9264
  }
7172
9265
  });
7173
9266
  }, [view]);
7174
- const contextValue = React17.useMemo(
9267
+ const contextValue = React22.useMemo(
7175
9268
  () => ({
7176
9269
  // State
7177
9270
  selectedDate,
@@ -7218,7 +9311,7 @@ function EventCalendarProvider({
7218
9311
  return /* @__PURE__ */ jsx(CalendarContext.Provider, { value: contextValue, children });
7219
9312
  }
7220
9313
  function useEventCalendar() {
7221
- const context = React17.useContext(CalendarContext);
9314
+ const context = React22.useContext(CalendarContext);
7222
9315
  if (!context) {
7223
9316
  throw new Error("useEventCalendar must be used within an EventCalendarProvider");
7224
9317
  }
@@ -7226,14 +9319,14 @@ function useEventCalendar() {
7226
9319
  }
7227
9320
  function useFilteredEvents() {
7228
9321
  const { events, selectedUserId } = useEventCalendar();
7229
- return React17.useMemo(() => {
9322
+ return React22.useMemo(() => {
7230
9323
  if (!selectedUserId) return events;
7231
9324
  return events.filter((event) => event.user.id === selectedUserId);
7232
9325
  }, [events, selectedUserId]);
7233
9326
  }
7234
9327
  function useEventsInRange(startDate, endDate) {
7235
9328
  const filteredEvents = useFilteredEvents();
7236
- return React17.useMemo(() => {
9329
+ return React22.useMemo(() => {
7237
9330
  return filteredEvents.filter((event) => {
7238
9331
  const eventStart = new Date(event.startDate);
7239
9332
  const eventEnd = new Date(event.endDate);
@@ -7791,8 +9884,8 @@ function MoreEvents({ count, onClick, className }) {
7791
9884
  );
7792
9885
  }
7793
9886
  function TimeIndicator({ className }) {
7794
- const [now, setNow] = React17.useState(/* @__PURE__ */ new Date());
7795
- React17.useEffect(() => {
9887
+ const [now, setNow] = React22.useState(/* @__PURE__ */ new Date());
9888
+ React22.useEffect(() => {
7796
9889
  const interval = setInterval(() => setNow(/* @__PURE__ */ new Date()), 6e4);
7797
9890
  return () => clearInterval(interval);
7798
9891
  }, []);
@@ -7829,24 +9922,24 @@ function DateBadge({ date, className }) {
7829
9922
  }
7830
9923
  );
7831
9924
  }
7832
- var DragContext = React17.createContext(null);
9925
+ var DragContext = React22.createContext(null);
7833
9926
  function DragProvider({
7834
9927
  children,
7835
9928
  snapMinutes = 15,
7836
9929
  onDragStart,
7837
9930
  onDragEnd
7838
9931
  }) {
7839
- const [draggedEvent, setDraggedEventState] = React17.useState(null);
7840
- const [isDragging, setIsDragging] = React17.useState(false);
9932
+ const [draggedEvent, setDraggedEventState] = React22.useState(null);
9933
+ const [isDragging, setIsDragging] = React22.useState(false);
7841
9934
  const { updateEvent } = useEventCalendar();
7842
- const setDraggedEvent = React17.useCallback((event) => {
9935
+ const setDraggedEvent = React22.useCallback((event) => {
7843
9936
  setDraggedEventState(event);
7844
9937
  setIsDragging(!!event);
7845
9938
  if (event) {
7846
9939
  onDragStart?.(event);
7847
9940
  }
7848
9941
  }, [onDragStart]);
7849
- const handleDrop = React17.useCallback((newStartDate) => {
9942
+ const handleDrop = React22.useCallback((newStartDate) => {
7850
9943
  if (!draggedEvent) return;
7851
9944
  const snappedDate = snapToInterval(newStartDate, snapMinutes);
7852
9945
  const { startDate, endDate } = calculateDropDates(draggedEvent, snappedDate);
@@ -7859,7 +9952,7 @@ function DragProvider({
7859
9952
  onDragEnd?.(updatedEvent, new Date(startDate), new Date(endDate));
7860
9953
  setDraggedEvent(null);
7861
9954
  }, [draggedEvent, snapMinutes, updateEvent, onDragEnd, setDraggedEvent]);
7862
- const contextValue = React17.useMemo(
9955
+ const contextValue = React22.useMemo(
7863
9956
  () => ({
7864
9957
  draggedEvent,
7865
9958
  setDraggedEvent,
@@ -7870,7 +9963,7 @@ function DragProvider({
7870
9963
  return /* @__PURE__ */ jsx(DragContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx(DragDropHandler, { onDrop: handleDrop, children }) });
7871
9964
  }
7872
9965
  function useDrag() {
7873
- const context = React17.useContext(DragContext);
9966
+ const context = React22.useContext(DragContext);
7874
9967
  if (!context) {
7875
9968
  throw new Error("useDrag must be used within a DragProvider");
7876
9969
  }
@@ -7915,7 +10008,7 @@ function DroppableZone({
7915
10008
  }) {
7916
10009
  const { draggedEvent, setDraggedEvent } = useDrag();
7917
10010
  const { updateEvent } = useEventCalendar();
7918
- const [isOver, setIsOver] = React17.useState(false);
10011
+ const [isOver, setIsOver] = React22.useState(false);
7919
10012
  const handleDragOver = (e) => {
7920
10013
  e.preventDefault();
7921
10014
  e.dataTransfer.dropEffect = "move";
@@ -7953,23 +10046,23 @@ function DroppableZone({
7953
10046
  function useDroppable({ date, hour, minute = 0, onDrop }) {
7954
10047
  const { draggedEvent, setDraggedEvent } = useDrag();
7955
10048
  const { updateEvent } = useEventCalendar();
7956
- const [isOver, setIsOver] = React17.useState(false);
7957
- const dropTargetDate = React17.useMemo(() => {
10049
+ const [isOver, setIsOver] = React22.useState(false);
10050
+ const dropTargetDate = React22.useMemo(() => {
7958
10051
  const targetDate = new Date(date);
7959
10052
  if (hour !== void 0) {
7960
10053
  targetDate.setHours(hour, minute, 0, 0);
7961
10054
  }
7962
10055
  return targetDate;
7963
10056
  }, [date, hour, minute]);
7964
- const handleDragOver = React17.useCallback((e) => {
10057
+ const handleDragOver = React22.useCallback((e) => {
7965
10058
  e.preventDefault();
7966
10059
  e.dataTransfer.dropEffect = "move";
7967
10060
  if (!isOver) setIsOver(true);
7968
10061
  }, [isOver]);
7969
- const handleDragLeave = React17.useCallback(() => {
10062
+ const handleDragLeave = React22.useCallback(() => {
7970
10063
  setIsOver(false);
7971
10064
  }, []);
7972
- const handleDrop = React17.useCallback((e) => {
10065
+ const handleDrop = React22.useCallback((e) => {
7973
10066
  e.preventDefault();
7974
10067
  setIsOver(false);
7975
10068
  if (!draggedEvent) return;
@@ -7996,13 +10089,13 @@ function useDroppable({ date, hour, minute = 0, onDrop }) {
7996
10089
  function useDraggable(event, disabled = false) {
7997
10090
  const { setDraggedEvent, draggedEvent } = useDrag();
7998
10091
  const isDragged = draggedEvent?.id === event.id;
7999
- const handleDragStart = React17.useCallback((e) => {
10092
+ const handleDragStart = React22.useCallback((e) => {
8000
10093
  if (disabled) return;
8001
10094
  e.dataTransfer.effectAllowed = "move";
8002
10095
  e.dataTransfer.setData("text/plain", event.id);
8003
10096
  setDraggedEvent(event);
8004
10097
  }, [disabled, event, setDraggedEvent]);
8005
- const handleDragEnd = React17.useCallback(() => {
10098
+ const handleDragEnd = React22.useCallback(() => {
8006
10099
  setDraggedEvent(null);
8007
10100
  }, [setDraggedEvent]);
8008
10101
  return {
@@ -8043,15 +10136,15 @@ function MonthView({
8043
10136
  }) {
8044
10137
  const { selectedDate, badgeVariant, setSelectedDate, setView } = useEventCalendar();
8045
10138
  const filteredEvents = useFilteredEvents();
8046
- const { singleDayEvents, multiDayEvents } = React17.useMemo(
10139
+ const { singleDayEvents, multiDayEvents } = React22.useMemo(
8047
10140
  () => splitEventsByDuration(filteredEvents),
8048
10141
  [filteredEvents]
8049
10142
  );
8050
- const cells = React17.useMemo(
10143
+ const cells = React22.useMemo(
8051
10144
  () => getCalendarCells(selectedDate),
8052
10145
  [selectedDate]
8053
10146
  );
8054
- const eventPositions = React17.useMemo(
10147
+ const eventPositions = React22.useMemo(
8055
10148
  () => calculateMonthEventPositions(multiDayEvents, singleDayEvents, selectedDate),
8056
10149
  [multiDayEvents, singleDayEvents, selectedDate]
8057
10150
  );
@@ -8233,7 +10326,7 @@ function WeekView({
8233
10326
  visibleHours
8234
10327
  } = useEventCalendar();
8235
10328
  const filteredEvents = useFilteredEvents();
8236
- const { singleDayEvents, multiDayEvents } = React17.useMemo(
10329
+ const { singleDayEvents, multiDayEvents } = React22.useMemo(
8237
10330
  () => splitEventsByDuration(filteredEvents),
8238
10331
  [filteredEvents]
8239
10332
  );
@@ -8439,8 +10532,8 @@ function CalendarTimeline({
8439
10532
  firstVisibleHour,
8440
10533
  lastVisibleHour
8441
10534
  }) {
8442
- const [currentTime, setCurrentTime] = React17.useState(/* @__PURE__ */ new Date());
8443
- React17.useEffect(() => {
10535
+ const [currentTime, setCurrentTime] = React22.useState(/* @__PURE__ */ new Date());
10536
+ React22.useEffect(() => {
8444
10537
  const interval = setInterval(() => {
8445
10538
  setCurrentTime(/* @__PURE__ */ new Date());
8446
10539
  }, 6e4);
@@ -8523,7 +10616,7 @@ function DayView({
8523
10616
  visibleHours
8524
10617
  } = useEventCalendar();
8525
10618
  const filteredEvents = useFilteredEvents();
8526
- const { singleDayEvents, multiDayEvents } = React17.useMemo(
10619
+ const { singleDayEvents, multiDayEvents } = React22.useMemo(
8527
10620
  () => splitEventsByDuration(filteredEvents),
8528
10621
  [filteredEvents]
8529
10622
  );
@@ -8531,7 +10624,7 @@ function DayView({
8531
10624
  visibleHours,
8532
10625
  singleDayEvents
8533
10626
  );
8534
- const currentEvents = React17.useMemo(() => {
10627
+ const currentEvents = React22.useMemo(() => {
8535
10628
  if (!isToday(selectedDate)) return [];
8536
10629
  return getCurrentEvents(singleDayEvents);
8537
10630
  }, [singleDayEvents, selectedDate]);
@@ -8755,8 +10848,8 @@ function CalendarTimeline2({
8755
10848
  firstVisibleHour,
8756
10849
  lastVisibleHour
8757
10850
  }) {
8758
- const [currentTime, setCurrentTime] = React17.useState(/* @__PURE__ */ new Date());
8759
- React17.useEffect(() => {
10851
+ const [currentTime, setCurrentTime] = React22.useState(/* @__PURE__ */ new Date());
10852
+ React22.useEffect(() => {
8760
10853
  const interval = setInterval(() => {
8761
10854
  setCurrentTime(/* @__PURE__ */ new Date());
8762
10855
  }, 6e4);
@@ -8790,7 +10883,7 @@ function YearView({
8790
10883
  }) {
8791
10884
  const { selectedDate, setSelectedDate, setView } = useEventCalendar();
8792
10885
  const filteredEvents = useFilteredEvents();
8793
- const months = React17.useMemo(() => {
10886
+ const months = React22.useMemo(() => {
8794
10887
  const yearStart = startOfYear(selectedDate);
8795
10888
  return Array.from({ length: 12 }, (_, i) => addMonths(yearStart, i));
8796
10889
  }, [selectedDate]);
@@ -8913,11 +11006,11 @@ function AgendaView({
8913
11006
  }) {
8914
11007
  const { selectedDate, setSelectedDate, setView } = useEventCalendar();
8915
11008
  const filteredEvents = useFilteredEvents();
8916
- const { singleDayEvents, multiDayEvents } = React17.useMemo(
11009
+ const { singleDayEvents, multiDayEvents } = React22.useMemo(
8917
11010
  () => splitEventsByDuration(filteredEvents),
8918
11011
  [filteredEvents]
8919
11012
  );
8920
- const eventsByDay = React17.useMemo(() => {
11013
+ const eventsByDay = React22.useMemo(() => {
8921
11014
  const allDates = /* @__PURE__ */ new Map();
8922
11015
  singleDayEvents.forEach((event) => {
8923
11016
  const eventDate = parseISO(event.startDate);
@@ -9382,16 +11475,16 @@ function EventDialog({
9382
11475
  defaultUserId
9383
11476
  }) {
9384
11477
  const { addEvent, updateEvent, deleteEvent, users } = useEventCalendar();
9385
- const [title, setTitle] = React17.useState("");
9386
- const [description, setDescription] = React17.useState("");
9387
- const [startDate, setStartDate] = React17.useState("");
9388
- const [startTime, setStartTime] = React17.useState("");
9389
- const [endDate, setEndDate] = React17.useState("");
9390
- const [endTime, setEndTime] = React17.useState("");
9391
- const [color, setColor] = React17.useState("blue");
9392
- const [userId, setUserId] = React17.useState("");
9393
- const [isSubmitting, setIsSubmitting] = React17.useState(false);
9394
- React17.useEffect(() => {
11478
+ const [title, setTitle] = React22.useState("");
11479
+ const [description, setDescription] = React22.useState("");
11480
+ const [startDate, setStartDate] = React22.useState("");
11481
+ const [startTime, setStartTime] = React22.useState("");
11482
+ const [endDate, setEndDate] = React22.useState("");
11483
+ const [endTime, setEndTime] = React22.useState("");
11484
+ const [color, setColor] = React22.useState("blue");
11485
+ const [userId, setUserId] = React22.useState("");
11486
+ const [isSubmitting, setIsSubmitting] = React22.useState(false);
11487
+ React22.useEffect(() => {
9395
11488
  if (open) {
9396
11489
  if (mode === "edit" && event) {
9397
11490
  const start = parseISO(event.startDate);
@@ -9614,7 +11707,7 @@ function QuickAddEvent({
9614
11707
  onOpenDialog,
9615
11708
  onClose
9616
11709
  }) {
9617
- const [title, setTitle] = React17.useState("");
11710
+ const [title, setTitle] = React22.useState("");
9618
11711
  const { users } = useEventCalendar();
9619
11712
  const handleSubmit = (e) => {
9620
11713
  e.preventDefault();
@@ -9681,8 +11774,8 @@ var HOUR_OPTIONS = Array.from({ length: 25 }, (_, i) => {
9681
11774
  });
9682
11775
  function ChangeVisibleHoursInput() {
9683
11776
  const { visibleHours, setVisibleHours } = useEventCalendar();
9684
- const [from, setFrom] = React17.useState(visibleHours.from);
9685
- const [to, setTo] = React17.useState(visibleHours.to);
11777
+ const [from, setFrom] = React22.useState(visibleHours.from);
11778
+ const [to, setTo] = React22.useState(visibleHours.to);
9686
11779
  const handleApply = () => {
9687
11780
  const toHour = to === 0 ? 24 : to;
9688
11781
  setVisibleHours({ from, to: toHour });
@@ -9728,7 +11821,7 @@ var HOUR_OPTIONS2 = Array.from({ length: 25 }, (_, i) => {
9728
11821
  });
9729
11822
  function ChangeWorkingHoursInput() {
9730
11823
  const { workingHours, setWorkingHours } = useEventCalendar();
9731
- const [localWorkingHours, setLocalWorkingHours] = React17.useState({
11824
+ const [localWorkingHours, setLocalWorkingHours] = React22.useState({
9732
11825
  ...workingHours
9733
11826
  });
9734
11827
  const handleToggleDay = (dayId) => {
@@ -9877,8 +11970,8 @@ function CalendarSettingsButton({
9877
11970
  );
9878
11971
  }
9879
11972
  function useMediaQuery(query) {
9880
- const [matches, setMatches] = React17.useState(false);
9881
- React17.useEffect(() => {
11973
+ const [matches, setMatches] = React22.useState(false);
11974
+ React22.useEffect(() => {
9882
11975
  const media = window.matchMedia(query);
9883
11976
  setMatches(media.matches);
9884
11977
  const listener = (event) => {
@@ -9930,11 +12023,11 @@ function BigCalendarInner({
9930
12023
  maxEventsPerDay
9931
12024
  }) {
9932
12025
  const { view, setView } = useEventCalendar();
9933
- const [dialogOpen, setDialogOpen] = React17.useState(false);
9934
- const [settingsDialogOpen, setSettingsDialogOpen] = React17.useState(false);
9935
- const [selectedEvent, setSelectedEvent] = React17.useState(null);
9936
- const [dialogMode, setDialogMode] = React17.useState("add");
9937
- const [defaultDate, setDefaultDate] = React17.useState(/* @__PURE__ */ new Date());
12026
+ const [dialogOpen, setDialogOpen] = React22.useState(false);
12027
+ const [settingsDialogOpen, setSettingsDialogOpen] = React22.useState(false);
12028
+ const [selectedEvent, setSelectedEvent] = React22.useState(null);
12029
+ const [dialogMode, setDialogMode] = React22.useState("add");
12030
+ const [defaultDate, setDefaultDate] = React22.useState(/* @__PURE__ */ new Date());
9938
12031
  const isMobile = useMediaQuery("(max-width: 768px)");
9939
12032
  const isCompact = compact === "auto" ? isMobile : compact;
9940
12033
  const handleAddClick = () => {
@@ -10093,6 +12186,6 @@ function CalendarView({
10093
12186
  }
10094
12187
  }
10095
12188
 
10096
- export { Accordion, AccordionContent, AccordionItem, AccordionTrigger, AgendaView, Alert, AlertDescription, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, AlertTitle, AspectRatio, Avatar, AvatarFallback, AvatarImage, BADGE_VARIANT_LABELS, Badge, BigCalendar, Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, Button, ButtonGroup, ButtonGroupSeparator, ButtonGroupText, Calendar, CalendarContext, CalendarDayButton, CalendarHeader, CalendarHeaderCompact, CalendarSettingsButton, CalendarSettingsContent, CalendarSettingsDialog, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Carousel, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious, ChangeBadgeVariantInput, ChangeVisibleHoursInput, ChangeWorkingHoursInput, ChartContainer, ChartLegend, ChartLegendContent, ChartStyle, ChartTooltip, ChartTooltipContent, Checkbox, Collapsible, CollapsibleContent2 as CollapsibleContent, CollapsibleTrigger2 as CollapsibleTrigger, Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, CommandShortcut, ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuPortal, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger, DEFAULT_VISIBLE_HOURS, DEFAULT_WORKING_HOURS, DataTableColumnHeader, DataTablePagination, DataTableViewOptions, DateBadge, DayView, DeliveryIndicator, DeliveryIndicators, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DragContext, DragProvider, DraggableEvent, Drawer, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerOverlay, DrawerPortal, DrawerTitle, DrawerTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, DroppableZone, EVENT_COLORS, Empty, EmptyContent, EmptyDescription, EmptyHeader, EmptyMedia, EmptyTitle, EventBadge, EventCalendarProvider, EventDialog, Field, FieldContent, FieldDescription, FieldError, FieldGroup, FieldLabel, FieldLegend, FieldSeparator, FieldSet, FieldTitle, Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, HoverCard, HoverCardContent, HoverCardTrigger, Input, InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput, InputGroupText, InputGroupTextarea, Item6 as Item, ItemActions, ItemContent, ItemDescription, ItemFooter, ItemGroup, ItemHeader, ItemMedia, ItemSeparator, ItemTitle, Kbd, KbdGroup, Label2 as Label, Menubar, MenubarCheckboxItem, MenubarContent, MenubarGroup, MenubarItem, MenubarLabel, MenubarMenu, MenubarPortal, MenubarRadioGroup, MenubarRadioItem, MenubarSeparator, MenubarShortcut, MenubarSub, MenubarSubContent, MenubarSubTrigger, MenubarTrigger, MonthView, MoreEvents, NativeSelect, NativeSelectOptGroup, NativeSelectOption, NavMain, NavProjects, NavSecondary, NavUser, NavigationMenu, NavigationMenuContent, NavigationMenuIndicator, NavigationMenuItem, NavigationMenuLink, NavigationMenuList, NavigationMenuTrigger, NavigationMenuViewport, Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious, PlanningTable, PlanningTableToolbar, PlayerCanvas, PlayerCanvasActionButton, PlayerCanvasControls, PlayerCanvasDivider, PlayerCanvasInfo, PlayerCanvasLabel, PlayerCanvasPlayButton, PlayerCanvasProgress, PlayerCanvasSkipButton, PlayerCanvasTitle, Popover, PopoverAnchor, PopoverContent, PopoverTrigger, Progress, QuickAddEvent, RadioGroup, RadioGroupItem, ResizableHandle, ResizablePanel, ResizablePanelGroup, ScrollArea, ScrollBar, SearchForm, SearchTrigger, Section, SectionContent, SectionDescription, SectionFooter, SectionHeader, SectionTitle, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator, Sheet, SheetBody, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetTitle, SheetTrigger, Sidebar, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupAction, SidebarGroupContent, SidebarGroupLabel, SidebarHeader, SidebarInput, SidebarInset, SidebarMenu, SidebarMenuAction, SidebarMenuBadge, SidebarMenuButton, SidebarMenuItem, SidebarMenuSkeleton, SidebarMenuSub, SidebarMenuSubButton, SidebarMenuSubItem, SidebarProvider, SidebarRail, SidebarSeparator, SidebarTrigger, SiteHeader, Skeleton, Slider, Spinner, SupplierCell, Switch, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Textarea, ThemeSwitch, TimeIndicator, Toaster, Toggle, ToggleGroup, ToggleGroupItem, ToolBarCanvas, ToolBarCanvasButton, ToolBarCanvasDivider, ToolBarCanvasGroup, Tooltip2 as Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, UserAvatarsDropdown, VIEW_LABELS, WeekCell, WeekDetailDialog, WeekHeader, WeekView, YearView, badgeVariants, buttonGroupVariants, buttonVariants, calculateDropDates, calculateMonthEventPositions, cardVariants, createDefaultEvent, deliveryIndicatorVariants, formatDateRange2 as formatDateRange, formatProductionUnit, formatTime, generateColumns, generateEventId, generateWeekColumns, generateWeeks, getCalendarCells, getCurrentEvents, getDayHours, getEventBlockStyle, getEventDuration, getEventDurationMinutes, getEventsCount, getEventsForDate, getEventsInRange, getHeaderLabel, getISOWeek, getMonthCellEvents, getMonthDays, getSupplierColumn, getTimeHeight, getTimePosition, getViewDateRange, getVisibleHours, getWeekDayNames, getWeekDays, getWeekKey, getYearMonths, groupEvents, isMultiDayEvent, isWorkingHour, navigateDate, navigationMenuTriggerStyle, playerCanvasPlayButtonVariants, playerCanvasSkipButtonVariants, rangeText, sectionVariants, snapToInterval, sortEvents, splitEventsByDuration, toggleVariants, toolBarCanvasButtonVariants, useDrag, useDraggable, useDroppable, useEventCalendar, useEventsInRange, useFilteredEvents, useFormField, useIsMobile, useSearchShortcut, useSidebar };
12189
+ export { Accordion, AccordionContent, AccordionItem, AccordionTrigger, AgendaView, Alert, AlertDescription, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, AlertTitle, AspectRatio, Avatar, AvatarFallback, AvatarImage, BADGE_VARIANT_LABELS, Badge, BigCalendar, Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, Button, ButtonGroup, ButtonGroupSeparator, ButtonGroupText, Calendar, CalendarContext, CalendarDayButton, CalendarHeader, CalendarHeaderCompact, CalendarSettingsButton, CalendarSettingsContent, CalendarSettingsDialog, CalibrationTable, CalibrationWeekCell, CalibrationWeekHeader, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Carousel, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious, ChangeBadgeVariantInput, ChangeVisibleHoursInput, ChangeWorkingHoursInput, ChartContainer, ChartLegend, ChartLegendContent, ChartStyle, ChartTooltip, ChartTooltipContent, Checkbox, CircularProgress, Collapsible, CollapsibleContent2 as CollapsibleContent, CollapsibleTrigger2 as CollapsibleTrigger, Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, CommandShortcut, CommentButton, CommentDialog, CommentPopover, ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuPortal, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger, DEFAULT_VISIBLE_HOURS, DEFAULT_WORKING_HOURS, DataTableColumnHeader, DataTablePagination, DataTableViewOptions, DateBadge, DayView, DeliveryIndicator, DeliveryIndicators, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DragContext, DragProvider, DraggableEvent, Drawer, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerOverlay, DrawerPortal, DrawerTitle, DrawerTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, DroppableZone, EVENT_COLORS, Empty, EmptyContent, EmptyDescription, EmptyHeader, EmptyMedia, EmptyTitle, EventBadge, EventCalendarProvider, EventDialog, Field, FieldContent, FieldDescription, FieldError, FieldGroup, FieldLabel, FieldLegend, FieldSeparator, FieldSet, FieldTitle, Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, HoverCard, HoverCardContent, HoverCardTrigger, Input, InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput, InputGroupText, InputGroupTextarea, Item6 as Item, ItemActions, ItemContent, ItemDescription, ItemFooter, ItemGroup, ItemHeader, ItemMedia, ItemSeparator, ItemTitle, Kbd, KbdGroup, Label2 as Label, Menubar, MenubarCheckboxItem, MenubarContent, MenubarGroup, MenubarItem, MenubarLabel, MenubarMenu, MenubarPortal, MenubarRadioGroup, MenubarRadioItem, MenubarSeparator, MenubarShortcut, MenubarSub, MenubarSubContent, MenubarSubTrigger, MenubarTrigger, MonthView, MoreEvents, NativeSelect, NativeSelectOptGroup, NativeSelectOption, NavMain, NavProjects, NavSecondary, NavUser, NavigationMenu, NavigationMenuContent, NavigationMenuIndicator, NavigationMenuItem, NavigationMenuLink, NavigationMenuList, NavigationMenuTrigger, NavigationMenuViewport, NetBadge, Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious, PlanningTable, PlanningTableToolbar, PlanningWeekCommentPopover, PlayerCanvas, PlayerCanvasActionButton, PlayerCanvasControls, PlayerCanvasDivider, PlayerCanvasInfo, PlayerCanvasLabel, PlayerCanvasPlayButton, PlayerCanvasProgress, PlayerCanvasSkipButton, PlayerCanvasTitle, Popover, PopoverAnchor, PopoverContent, PopoverTrigger, Progress, QuickAddEvent, RadioGroup, RadioGroupItem, ResizableHandle, ResizablePanel, ResizablePanelGroup, RowHeaderCell, ScrollArea, ScrollBar, SearchForm, SearchTrigger, Section, SectionContent, SectionDescription, SectionFooter, SectionHeader, SectionTitle, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator, Sheet, SheetBody, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetTitle, SheetTrigger, Sidebar, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupAction, SidebarGroupContent, SidebarGroupLabel, SidebarHeader, SidebarInput, SidebarInset, SidebarMenu, SidebarMenuAction, SidebarMenuBadge, SidebarMenuButton, SidebarMenuItem, SidebarMenuSkeleton, SidebarMenuSub, SidebarMenuSubButton, SidebarMenuSubItem, SidebarProvider, SidebarRail, SidebarSeparator, SidebarTrigger, SiteHeader, Skeleton, Slider, Spinner, SubmitCalibrationBar, SupplierCell, Switch, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Textarea, ThemeSwitch, TimeIndicator, Toaster, Toggle, ToggleGroup, ToggleGroupItem, ToolBarCanvas, ToolBarCanvasButton, ToolBarCanvasDivider, ToolBarCanvasGroup, Tooltip2 as Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, UserAvatarsDropdown, VIEW_LABELS, WeekCell, WeekDetailDialog, WeekHeader, WeekView, YearView, badgeVariants, buttonGroupVariants, buttonVariants, calculateCalibrationCells, calculateDropDates, calculateMonthEventPositions, canSubmitCalibration, cardVariants, createDefaultEvent, deliveryIndicatorVariants, formatCalibrationUnit, formatDateRange2 as formatDateRange, formatProductionUnit, formatTime, generateColumns, generateEventId, generateLocationOptions, generateWeekColumns, generateWeeks, getCalendarCells, getCommentLocationLabel, getCurrentEvents, getDayHours, getElementShipmentStatus, getEventBlockStyle, getEventDuration, getEventDurationMinutes, getEventsCount, getEventsForDate, getEventsInRange, getHeaderLabel, getISOWeek, getMonthCellEvents, getMonthDays, getShipmentStatusLabel, getSupplierColumn, getTimeHeight, getTimePosition, getViewDateRange, getVisibleHours, getWeekDayNames, getWeekDays, getWeekKey, getYearMonths, groupEvents, isMultiDayEvent, isWorkingHour, navigateDate, navigationMenuTriggerStyle, playerCanvasPlayButtonVariants, playerCanvasSkipButtonVariants, rangeText, sectionVariants, snapToInterval, sortEvents, splitEventsByDuration, toggleVariants, toolBarCanvasButtonVariants, useDrag, useDraggable, useDroppable, useEventCalendar, useEventsInRange, useFilteredEvents, useFormField, useIsMobile, useSearchShortcut, useSidebar };
10097
12190
  //# sourceMappingURL=index.js.map
10098
12191
  //# sourceMappingURL=index.js.map