@j3m-quantum/ui 1.5.0 → 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 React15 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, FolderIcon, ShareIcon, TrashIcon, ChevronsUpDownIcon, SparklesIcon, BadgeCheckIcon, CreditCardIcon, BellIcon, LogOutIcon, User, Calendar as Calendar$1, Clock, CalendarX2, ChevronLeft, List, Columns, Grid2x2, Grid3x3, CalendarRange, Settings, Plus, Info, Moon } 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';
@@ -39,14 +39,16 @@ import * as PopoverPrimitive from '@radix-ui/react-popover';
39
39
  import * as HoverCardPrimitive from '@radix-ui/react-hover-card';
40
40
  import * as CollapsiblePrimitive from '@radix-ui/react-collapsible';
41
41
  import * as ResizablePrimitive from 'react-resizable-panels';
42
+ import { useReactTable, getPaginationRowModel, getFilteredRowModel, getSortedRowModel, getCoreRowModel, flexRender } from '@tanstack/react-table';
43
+ export { flexRender, getCoreRowModel, getFilteredRowModel, getPaginationRowModel, getSortedRowModel, useReactTable } from '@tanstack/react-table';
42
44
  import { subMonths, subYears, subWeeks, subDays, addMonths, addYears, addWeeks, addDays, format, startOfWeek, endOfWeek, startOfMonth, endOfMonth, startOfYear, endOfYear, isSameMonth, isSameWeek, isSameDay, isSameYear, isWithinInterval, parseISO, differenceInMinutes, eachDayOfInterval, differenceInDays, startOfDay, setMinutes, setHours, eachHourOfInterval, endOfDay, getHours, getMinutes, addMinutes, isToday, areIntervalsOverlapping } from 'date-fns';
43
45
  export { areIntervalsOverlapping, format, getDay, isSameDay, isSameMonth, isToday, parseISO } from 'date-fns';
44
46
 
45
47
  // src/hooks/use-mobile.ts
46
48
  var MOBILE_BREAKPOINT = 768;
47
49
  function useIsMobile() {
48
- const [isMobile, setIsMobile] = React15.useState(void 0);
49
- React15.useEffect(() => {
50
+ const [isMobile, setIsMobile] = React22.useState(void 0);
51
+ React22.useEffect(() => {
50
52
  const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);
51
53
  const onChange = () => {
52
54
  setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
@@ -87,7 +89,7 @@ var buttonVariants = cva(
87
89
  }
88
90
  }
89
91
  );
90
- var Button = React15.forwardRef(
92
+ var Button = React22.forwardRef(
91
93
  ({ className, variant, size, asChild = false, ...props }, ref) => {
92
94
  const Comp = asChild ? Slot : "button";
93
95
  return /* @__PURE__ */ jsx(
@@ -451,7 +453,7 @@ function Slider({
451
453
  max = 100,
452
454
  ...props
453
455
  }) {
454
- const _values = React15.useMemo(
456
+ const _values = React22.useMemo(
455
457
  () => Array.isArray(value) ? value : Array.isArray(defaultValue) ? defaultValue : [min, max],
456
458
  [value, defaultValue, min, max]
457
459
  );
@@ -737,7 +739,7 @@ function Toggle({
737
739
  }
738
740
  );
739
741
  }
740
- var ToggleGroupContext = React15.createContext({
742
+ var ToggleGroupContext = React22.createContext({
741
743
  size: "default",
742
744
  variant: "default",
743
745
  spacing: 0
@@ -774,7 +776,7 @@ function ToggleGroupItem({
774
776
  size,
775
777
  ...props
776
778
  }) {
777
- const context = React15.useContext(ToggleGroupContext);
779
+ const context = React22.useContext(ToggleGroupContext);
778
780
  return /* @__PURE__ */ jsx(
779
781
  ToggleGroupPrimitive.Item,
780
782
  {
@@ -804,7 +806,7 @@ function ThemeSwitch({
804
806
  className,
805
807
  size = "default"
806
808
  }) {
807
- const [isChecked, setIsChecked] = React15.useState(defaultChecked);
809
+ const [isChecked, setIsChecked] = React22.useState(defaultChecked);
808
810
  const isControlled = checked !== void 0;
809
811
  const currentChecked = isControlled ? checked : isChecked;
810
812
  const handleClick = () => {
@@ -1224,7 +1226,7 @@ function Label2({
1224
1226
  );
1225
1227
  }
1226
1228
  var Form = FormProvider;
1227
- var FormFieldContext = React15.createContext(
1229
+ var FormFieldContext = React22.createContext(
1228
1230
  {}
1229
1231
  );
1230
1232
  var FormField = ({
@@ -1233,8 +1235,8 @@ var FormField = ({
1233
1235
  return /* @__PURE__ */ jsx(FormFieldContext.Provider, { value: { name: props.name }, children: /* @__PURE__ */ jsx(Controller, { ...props }) });
1234
1236
  };
1235
1237
  var useFormField = () => {
1236
- const fieldContext = React15.useContext(FormFieldContext);
1237
- const itemContext = React15.useContext(FormItemContext);
1238
+ const fieldContext = React22.useContext(FormFieldContext);
1239
+ const itemContext = React22.useContext(FormItemContext);
1238
1240
  const { getFieldState } = useFormContext();
1239
1241
  const formState = useFormState({ name: fieldContext.name });
1240
1242
  const fieldState = getFieldState(fieldContext.name, formState);
@@ -1251,11 +1253,11 @@ var useFormField = () => {
1251
1253
  ...fieldState
1252
1254
  };
1253
1255
  };
1254
- var FormItemContext = React15.createContext(
1256
+ var FormItemContext = React22.createContext(
1255
1257
  {}
1256
1258
  );
1257
1259
  function FormItem({ className, ...props }) {
1258
- const id = React15.useId();
1260
+ const id = React22.useId();
1259
1261
  return /* @__PURE__ */ jsx(FormItemContext.Provider, { value: { id }, children: /* @__PURE__ */ jsx(
1260
1262
  "div",
1261
1263
  {
@@ -2357,8 +2359,8 @@ function CalendarDayButton({
2357
2359
  modifiers,
2358
2360
  ...props
2359
2361
  }) {
2360
- const ref = React15.useRef(null);
2361
- React15.useEffect(() => {
2362
+ const ref = React22.useRef(null);
2363
+ React22.useEffect(() => {
2362
2364
  if (modifiers.focused) ref.current?.focus();
2363
2365
  }, [modifiers.focused]);
2364
2366
  return /* @__PURE__ */ jsx(
@@ -2379,9 +2381,9 @@ function CalendarDayButton({
2379
2381
  }
2380
2382
  );
2381
2383
  }
2382
- var CarouselContext = React15.createContext(null);
2384
+ var CarouselContext = React22.createContext(null);
2383
2385
  function useCarousel() {
2384
- const context = React15.useContext(CarouselContext);
2386
+ const context = React22.useContext(CarouselContext);
2385
2387
  if (!context) {
2386
2388
  throw new Error("useCarousel must be used within a <Carousel />");
2387
2389
  }
@@ -2403,20 +2405,20 @@ function Carousel({
2403
2405
  },
2404
2406
  plugins
2405
2407
  );
2406
- const [canScrollPrev, setCanScrollPrev] = React15.useState(false);
2407
- const [canScrollNext, setCanScrollNext] = React15.useState(false);
2408
- const onSelect = React15.useCallback((api2) => {
2408
+ const [canScrollPrev, setCanScrollPrev] = React22.useState(false);
2409
+ const [canScrollNext, setCanScrollNext] = React22.useState(false);
2410
+ const onSelect = React22.useCallback((api2) => {
2409
2411
  if (!api2) return;
2410
2412
  setCanScrollPrev(api2.canScrollPrev());
2411
2413
  setCanScrollNext(api2.canScrollNext());
2412
2414
  }, []);
2413
- const scrollPrev = React15.useCallback(() => {
2415
+ const scrollPrev = React22.useCallback(() => {
2414
2416
  api?.scrollPrev();
2415
2417
  }, [api]);
2416
- const scrollNext = React15.useCallback(() => {
2418
+ const scrollNext = React22.useCallback(() => {
2417
2419
  api?.scrollNext();
2418
2420
  }, [api]);
2419
- const handleKeyDown = React15.useCallback(
2421
+ const handleKeyDown = React22.useCallback(
2420
2422
  (event) => {
2421
2423
  if (event.key === "ArrowLeft") {
2422
2424
  event.preventDefault();
@@ -2428,11 +2430,11 @@ function Carousel({
2428
2430
  },
2429
2431
  [scrollPrev, scrollNext]
2430
2432
  );
2431
- React15.useEffect(() => {
2433
+ React22.useEffect(() => {
2432
2434
  if (!api || !setApi) return;
2433
2435
  setApi(api);
2434
2436
  }, [api, setApi]);
2435
- React15.useEffect(() => {
2437
+ React22.useEffect(() => {
2436
2438
  if (!api) return;
2437
2439
  onSelect(api);
2438
2440
  api.on("reInit", onSelect);
@@ -2565,9 +2567,9 @@ function CarouselNext({
2565
2567
  );
2566
2568
  }
2567
2569
  var THEMES = { light: "", dark: ".dark" };
2568
- var ChartContext = React15.createContext(null);
2570
+ var ChartContext = React22.createContext(null);
2569
2571
  function useChart() {
2570
- const context = React15.useContext(ChartContext);
2572
+ const context = React22.useContext(ChartContext);
2571
2573
  if (!context) {
2572
2574
  throw new Error("useChart must be used within a <ChartContainer />");
2573
2575
  }
@@ -2580,7 +2582,7 @@ function ChartContainer({
2580
2582
  config,
2581
2583
  ...props
2582
2584
  }) {
2583
- const uniqueId = React15.useId();
2585
+ const uniqueId = React22.useId();
2584
2586
  const chartId = `chart-${id || uniqueId.replace(/:/g, "")}`;
2585
2587
  return /* @__PURE__ */ jsx(ChartContext.Provider, { value: { config }, children: /* @__PURE__ */ jsxs(
2586
2588
  "div",
@@ -2641,7 +2643,7 @@ function ChartTooltipContent({
2641
2643
  labelKey
2642
2644
  }) {
2643
2645
  const { config } = useChart();
2644
- const tooltipLabel = React15.useMemo(() => {
2646
+ const tooltipLabel = React22.useMemo(() => {
2645
2647
  if (hideLabel || !payload?.length) {
2646
2648
  return null;
2647
2649
  }
@@ -3297,6 +3299,105 @@ function Progress({
3297
3299
  }
3298
3300
  );
3299
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
+ }
3300
3401
  function TooltipProvider({
3301
3402
  delayDuration = 0,
3302
3403
  ...props
@@ -3344,8 +3445,8 @@ function TooltipContent({
3344
3445
  ) });
3345
3446
  }
3346
3447
  function useDetectTheme() {
3347
- const [theme, setTheme] = React15.useState("light");
3348
- React15.useEffect(() => {
3448
+ const [theme, setTheme] = React22.useState("light");
3449
+ React22.useEffect(() => {
3349
3450
  const isDark = document.documentElement.classList.contains("dark");
3350
3451
  setTheme(isDark ? "dark" : "light");
3351
3452
  const observer = new MutationObserver((mutations) => {
@@ -3397,6 +3498,81 @@ function Spinner({ className, ...props }) {
3397
3498
  }
3398
3499
  );
3399
3500
  }
3501
+ var deliveryIndicatorVariants = cva(
3502
+ "inline-block rounded-full shrink-0",
3503
+ {
3504
+ variants: {
3505
+ status: {
3506
+ "on-time": "bg-[var(--j3m-green-9,#84EBB4)]",
3507
+ "delayed": "bg-[var(--j3m-yellow-9,#FFDB43)]",
3508
+ "critical": "bg-[var(--j3m-red-9,#FB3748)]",
3509
+ "pending": "bg-[var(--j3m-gray-6,#D2D2D2)]"
3510
+ },
3511
+ size: {
3512
+ sm: "h-1.5 w-3",
3513
+ default: "h-1.5 w-3",
3514
+ lg: "h-2 w-4"
3515
+ }
3516
+ },
3517
+ defaultVariants: {
3518
+ status: "pending",
3519
+ size: "default"
3520
+ }
3521
+ }
3522
+ );
3523
+ function DeliveryIndicator({
3524
+ className,
3525
+ status,
3526
+ size,
3527
+ label,
3528
+ showTooltip = false,
3529
+ ...props
3530
+ }) {
3531
+ const indicator = /* @__PURE__ */ jsx(
3532
+ "span",
3533
+ {
3534
+ "data-slot": "delivery-indicator",
3535
+ "data-status": status,
3536
+ className: cn(deliveryIndicatorVariants({ status, size }), className),
3537
+ "aria-label": label || `Delivery status: ${status}`,
3538
+ role: "img",
3539
+ ...props
3540
+ }
3541
+ );
3542
+ if (showTooltip && label) {
3543
+ return /* @__PURE__ */ jsxs(Tooltip2, { children: [
3544
+ /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: indicator }),
3545
+ /* @__PURE__ */ jsx(TooltipContent, { children: label })
3546
+ ] });
3547
+ }
3548
+ return indicator;
3549
+ }
3550
+ function DeliveryIndicators({
3551
+ className,
3552
+ deliveries,
3553
+ size = "default",
3554
+ showTooltips = false,
3555
+ ...props
3556
+ }) {
3557
+ return /* @__PURE__ */ jsx(
3558
+ "div",
3559
+ {
3560
+ "data-slot": "delivery-indicators",
3561
+ className: cn("flex items-center gap-1", className),
3562
+ ...props,
3563
+ children: deliveries.map((delivery, index) => /* @__PURE__ */ jsx(
3564
+ DeliveryIndicator,
3565
+ {
3566
+ status: delivery.status,
3567
+ size,
3568
+ label: delivery.label,
3569
+ showTooltip: showTooltips
3570
+ },
3571
+ index
3572
+ ))
3573
+ }
3574
+ );
3575
+ }
3400
3576
  function Breadcrumb({ ...props }) {
3401
3577
  return /* @__PURE__ */ jsx("nav", { "aria-label": "breadcrumb", "data-slot": "breadcrumb", ...props });
3402
3578
  }
@@ -3919,7 +4095,7 @@ function CommandShortcut({
3919
4095
  }
3920
4096
  );
3921
4097
  }
3922
- var SearchTrigger = React15.forwardRef(
4098
+ var SearchTrigger = React22.forwardRef(
3923
4099
  ({
3924
4100
  className,
3925
4101
  placeholder = "Search...",
@@ -3955,7 +4131,7 @@ var SearchTrigger = React15.forwardRef(
3955
4131
  );
3956
4132
  SearchTrigger.displayName = "SearchTrigger";
3957
4133
  function useSearchShortcut(onOpen, key = "k") {
3958
- React15.useEffect(() => {
4134
+ React22.useEffect(() => {
3959
4135
  const down = (e) => {
3960
4136
  if (e.key.toLowerCase() === key.toLowerCase() && (e.metaKey || e.ctrlKey)) {
3961
4137
  e.preventDefault();
@@ -4930,9 +5106,9 @@ var SIDEBAR_WIDTH = "16rem";
4930
5106
  var SIDEBAR_WIDTH_MOBILE = "18rem";
4931
5107
  var SIDEBAR_WIDTH_ICON = "3rem";
4932
5108
  var SIDEBAR_KEYBOARD_SHORTCUT = "b";
4933
- var SidebarContext = React15.createContext(null);
5109
+ var SidebarContext = React22.createContext(null);
4934
5110
  function useSidebar() {
4935
- const context = React15.useContext(SidebarContext);
5111
+ const context = React22.useContext(SidebarContext);
4936
5112
  if (!context) {
4937
5113
  throw new Error("useSidebar must be used within a SidebarProvider.");
4938
5114
  }
@@ -4948,10 +5124,10 @@ function SidebarProvider({
4948
5124
  ...props
4949
5125
  }) {
4950
5126
  const isMobile = useIsMobile();
4951
- const [openMobile, setOpenMobile] = React15.useState(false);
4952
- const [_open, _setOpen] = React15.useState(defaultOpen);
5127
+ const [openMobile, setOpenMobile] = React22.useState(false);
5128
+ const [_open, _setOpen] = React22.useState(defaultOpen);
4953
5129
  const open = openProp ?? _open;
4954
- const setOpen = React15.useCallback(
5130
+ const setOpen = React22.useCallback(
4955
5131
  (value) => {
4956
5132
  const openState = typeof value === "function" ? value(open) : value;
4957
5133
  if (setOpenProp) {
@@ -4963,10 +5139,10 @@ function SidebarProvider({
4963
5139
  },
4964
5140
  [setOpenProp, open]
4965
5141
  );
4966
- const toggleSidebar = React15.useCallback(() => {
5142
+ const toggleSidebar = React22.useCallback(() => {
4967
5143
  return isMobile ? setOpenMobile((open2) => !open2) : setOpen((open2) => !open2);
4968
5144
  }, [isMobile, setOpen, setOpenMobile]);
4969
- React15.useEffect(() => {
5145
+ React22.useEffect(() => {
4970
5146
  const handleKeyDown = (event) => {
4971
5147
  if (event.key === SIDEBAR_KEYBOARD_SHORTCUT && (event.metaKey || event.ctrlKey)) {
4972
5148
  event.preventDefault();
@@ -4977,7 +5153,7 @@ function SidebarProvider({
4977
5153
  return () => window.removeEventListener("keydown", handleKeyDown);
4978
5154
  }, [toggleSidebar]);
4979
5155
  const state = open ? "expanded" : "collapsed";
4980
- const contextValue = React15.useMemo(
5156
+ const contextValue = React22.useMemo(
4981
5157
  () => ({
4982
5158
  state,
4983
5159
  open,
@@ -5435,7 +5611,7 @@ function SidebarMenuSkeleton({
5435
5611
  showIcon = false,
5436
5612
  ...props
5437
5613
  }) {
5438
- const width = React15.useMemo(() => {
5614
+ const width = React22.useMemo(() => {
5439
5615
  return `${Math.floor(Math.random() * 40) + 50}%`;
5440
5616
  }, []);
5441
5617
  return /* @__PURE__ */ jsxs(
@@ -5578,7 +5754,7 @@ var sectionVariants = cva(
5578
5754
  }
5579
5755
  );
5580
5756
  var isGlassVariant = (variant) => variant?.startsWith("glass-") ?? false;
5581
- var Section = React15.forwardRef(
5757
+ var Section = React22.forwardRef(
5582
5758
  ({ className, variant, ...props }, ref) => /* @__PURE__ */ jsx(
5583
5759
  "section",
5584
5760
  {
@@ -5590,7 +5766,7 @@ var Section = React15.forwardRef(
5590
5766
  )
5591
5767
  );
5592
5768
  Section.displayName = "Section";
5593
- var SectionHeader = React15.forwardRef(
5769
+ var SectionHeader = React22.forwardRef(
5594
5770
  ({ className, ...props }, ref) => /* @__PURE__ */ jsx(
5595
5771
  "div",
5596
5772
  {
@@ -5605,7 +5781,7 @@ var SectionHeader = React15.forwardRef(
5605
5781
  )
5606
5782
  );
5607
5783
  SectionHeader.displayName = "SectionHeader";
5608
- var SectionTitle = React15.forwardRef(
5784
+ var SectionTitle = React22.forwardRef(
5609
5785
  ({ className, ...props }, ref) => /* @__PURE__ */ jsx(
5610
5786
  "h2",
5611
5787
  {
@@ -5619,7 +5795,7 @@ var SectionTitle = React15.forwardRef(
5619
5795
  )
5620
5796
  );
5621
5797
  SectionTitle.displayName = "SectionTitle";
5622
- var SectionDescription = React15.forwardRef(
5798
+ var SectionDescription = React22.forwardRef(
5623
5799
  ({ className, ...props }, ref) => /* @__PURE__ */ jsx(
5624
5800
  "p",
5625
5801
  {
@@ -5633,7 +5809,7 @@ var SectionDescription = React15.forwardRef(
5633
5809
  )
5634
5810
  );
5635
5811
  SectionDescription.displayName = "SectionDescription";
5636
- var SectionContent = React15.forwardRef(
5812
+ var SectionContent = React22.forwardRef(
5637
5813
  ({ className, ...props }, ref) => /* @__PURE__ */ jsx(
5638
5814
  "div",
5639
5815
  {
@@ -5647,7 +5823,7 @@ var SectionContent = React15.forwardRef(
5647
5823
  )
5648
5824
  );
5649
5825
  SectionContent.displayName = "SectionContent";
5650
- var SectionFooter = React15.forwardRef(
5826
+ var SectionFooter = React22.forwardRef(
5651
5827
  ({ className, ...props }, ref) => /* @__PURE__ */ jsx(
5652
5828
  "div",
5653
5829
  {
@@ -5663,6 +5839,180 @@ var SectionFooter = React15.forwardRef(
5663
5839
  )
5664
5840
  );
5665
5841
  SectionFooter.displayName = "SectionFooter";
5842
+ function DataTableColumnHeader({
5843
+ column,
5844
+ title,
5845
+ className
5846
+ }) {
5847
+ if (!column.getCanSort()) {
5848
+ return /* @__PURE__ */ jsx("div", { className: cn(className), children: title });
5849
+ }
5850
+ return /* @__PURE__ */ jsx("div", { className: cn("flex items-center gap-2", className), children: /* @__PURE__ */ jsxs(DropdownMenu, { children: [
5851
+ /* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
5852
+ Button,
5853
+ {
5854
+ variant: "ghost",
5855
+ size: "sm",
5856
+ className: "data-[state=open]:bg-accent -ml-3 h-8",
5857
+ children: [
5858
+ /* @__PURE__ */ jsx("span", { children: title }),
5859
+ column.getIsSorted() === "desc" ? /* @__PURE__ */ jsx(ArrowDown, {}) : column.getIsSorted() === "asc" ? /* @__PURE__ */ jsx(ArrowUp, {}) : /* @__PURE__ */ jsx(ChevronsUpDown, {})
5860
+ ]
5861
+ }
5862
+ ) }),
5863
+ /* @__PURE__ */ jsxs(DropdownMenuContent, { align: "start", children: [
5864
+ /* @__PURE__ */ jsxs(DropdownMenuItem, { onClick: () => column.toggleSorting(false), children: [
5865
+ /* @__PURE__ */ jsx(ArrowUp, {}),
5866
+ "Asc"
5867
+ ] }),
5868
+ /* @__PURE__ */ jsxs(DropdownMenuItem, { onClick: () => column.toggleSorting(true), children: [
5869
+ /* @__PURE__ */ jsx(ArrowDown, {}),
5870
+ "Desc"
5871
+ ] }),
5872
+ column.getCanHide() && /* @__PURE__ */ jsxs(Fragment, { children: [
5873
+ /* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
5874
+ /* @__PURE__ */ jsxs(DropdownMenuItem, { onClick: () => column.toggleVisibility(false), children: [
5875
+ /* @__PURE__ */ jsx(EyeOff, {}),
5876
+ "Hide"
5877
+ ] })
5878
+ ] })
5879
+ ] })
5880
+ ] }) });
5881
+ }
5882
+ function DataTablePagination({
5883
+ table,
5884
+ showRowSelection = true,
5885
+ pageSizeOptions = [10, 20, 25, 30, 40, 50]
5886
+ }) {
5887
+ return /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-2", children: [
5888
+ showRowSelection && /* @__PURE__ */ jsxs("div", { className: "text-muted-foreground flex-1 text-sm", children: [
5889
+ table.getFilteredSelectedRowModel().rows.length,
5890
+ " of",
5891
+ " ",
5892
+ table.getFilteredRowModel().rows.length,
5893
+ " row(s) selected."
5894
+ ] }),
5895
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center space-x-6 lg:space-x-8", children: [
5896
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center space-x-2", children: [
5897
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-medium", children: "Rows per page" }),
5898
+ /* @__PURE__ */ jsxs(
5899
+ Select,
5900
+ {
5901
+ value: `${table.getState().pagination.pageSize}`,
5902
+ onValueChange: (value) => {
5903
+ table.setPageSize(Number(value));
5904
+ },
5905
+ children: [
5906
+ /* @__PURE__ */ jsx(SelectTrigger, { className: "h-8 w-[70px]", children: /* @__PURE__ */ jsx(SelectValue, { placeholder: table.getState().pagination.pageSize }) }),
5907
+ /* @__PURE__ */ jsx(SelectContent, { side: "top", children: pageSizeOptions.map((pageSize) => /* @__PURE__ */ jsx(SelectItem, { value: `${pageSize}`, children: pageSize }, pageSize)) })
5908
+ ]
5909
+ }
5910
+ )
5911
+ ] }),
5912
+ /* @__PURE__ */ jsxs("div", { className: "flex w-[100px] items-center justify-center text-sm font-medium", children: [
5913
+ "Page ",
5914
+ table.getState().pagination.pageIndex + 1,
5915
+ " of",
5916
+ " ",
5917
+ table.getPageCount()
5918
+ ] }),
5919
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center space-x-2", children: [
5920
+ /* @__PURE__ */ jsxs(
5921
+ Button,
5922
+ {
5923
+ variant: "outline",
5924
+ size: "icon",
5925
+ className: "hidden size-8 lg:flex",
5926
+ onClick: () => table.setPageIndex(0),
5927
+ disabled: !table.getCanPreviousPage(),
5928
+ children: [
5929
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Go to first page" }),
5930
+ /* @__PURE__ */ jsx(ChevronsLeft, {})
5931
+ ]
5932
+ }
5933
+ ),
5934
+ /* @__PURE__ */ jsxs(
5935
+ Button,
5936
+ {
5937
+ variant: "outline",
5938
+ size: "icon",
5939
+ className: "size-8",
5940
+ onClick: () => table.previousPage(),
5941
+ disabled: !table.getCanPreviousPage(),
5942
+ children: [
5943
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Go to previous page" }),
5944
+ /* @__PURE__ */ jsx(ChevronLeft, {})
5945
+ ]
5946
+ }
5947
+ ),
5948
+ /* @__PURE__ */ jsxs(
5949
+ Button,
5950
+ {
5951
+ variant: "outline",
5952
+ size: "icon",
5953
+ className: "size-8",
5954
+ onClick: () => table.nextPage(),
5955
+ disabled: !table.getCanNextPage(),
5956
+ children: [
5957
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Go to next page" }),
5958
+ /* @__PURE__ */ jsx(ChevronRight, {})
5959
+ ]
5960
+ }
5961
+ ),
5962
+ /* @__PURE__ */ jsxs(
5963
+ Button,
5964
+ {
5965
+ variant: "outline",
5966
+ size: "icon",
5967
+ className: "hidden size-8 lg:flex",
5968
+ onClick: () => table.setPageIndex(table.getPageCount() - 1),
5969
+ disabled: !table.getCanNextPage(),
5970
+ children: [
5971
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Go to last page" }),
5972
+ /* @__PURE__ */ jsx(ChevronsRight, {})
5973
+ ]
5974
+ }
5975
+ )
5976
+ ] })
5977
+ ] })
5978
+ ] });
5979
+ }
5980
+ function DataTableViewOptions({
5981
+ table
5982
+ }) {
5983
+ return /* @__PURE__ */ jsxs(DropdownMenu, { children: [
5984
+ /* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
5985
+ Button,
5986
+ {
5987
+ variant: "outline",
5988
+ size: "sm",
5989
+ className: "ml-auto hidden h-8 lg:flex",
5990
+ children: [
5991
+ /* @__PURE__ */ jsx(Settings2, {}),
5992
+ "View"
5993
+ ]
5994
+ }
5995
+ ) }),
5996
+ /* @__PURE__ */ jsxs(DropdownMenuContent, { align: "end", className: "w-[150px]", children: [
5997
+ /* @__PURE__ */ jsx(DropdownMenuLabel, { children: "Toggle columns" }),
5998
+ /* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
5999
+ table.getAllColumns().filter(
6000
+ (column) => typeof column.accessorFn !== "undefined" && column.getCanHide()
6001
+ ).map((column) => {
6002
+ return /* @__PURE__ */ jsx(
6003
+ DropdownMenuCheckboxItem,
6004
+ {
6005
+ className: "capitalize",
6006
+ checked: column.getIsVisible(),
6007
+ onCheckedChange: (value) => column.toggleVisibility(!!value),
6008
+ children: column.id
6009
+ },
6010
+ column.id
6011
+ );
6012
+ })
6013
+ ] })
6014
+ ] });
6015
+ }
5666
6016
  function SearchForm({ ...props }) {
5667
6017
  return /* @__PURE__ */ jsx("form", { ...props, children: /* @__PURE__ */ jsxs("div", { className: "relative", children: [
5668
6018
  /* @__PURE__ */ jsx(Label2, { htmlFor: "search", className: "sr-only", children: "Search" }),
@@ -5698,7 +6048,7 @@ function SiteHeader({
5698
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: [
5699
6049
  trigger,
5700
6050
  trigger && /* @__PURE__ */ jsx(Separator, { orientation: "vertical", className: "mr-[var(--j3m-spacing-s)] h-4" }),
5701
- /* @__PURE__ */ jsx(Breadcrumb, { className: "hidden sm:block", children: /* @__PURE__ */ jsx(BreadcrumbList, { children: breadcrumbs.map((item, index) => /* @__PURE__ */ jsxs(React15.Fragment, { children: [
6051
+ /* @__PURE__ */ jsx(Breadcrumb, { className: "hidden sm:block", children: /* @__PURE__ */ jsx(BreadcrumbList, { children: breadcrumbs.map((item, index) => /* @__PURE__ */ jsxs(React22.Fragment, { children: [
5702
6052
  index > 0 && /* @__PURE__ */ jsx(BreadcrumbSeparator, {}),
5703
6053
  /* @__PURE__ */ jsx(BreadcrumbItem, { children: item.href ? /* @__PURE__ */ jsx(BreadcrumbLink, { href: item.href, children: item.label }) : /* @__PURE__ */ jsx(BreadcrumbPage, { children: item.label }) })
5704
6054
  ] }, index)) }) }),
@@ -5847,116 +6197,3038 @@ function NavUser({ user }) {
5847
6197
  )
5848
6198
  ] }) }) });
5849
6199
  }
5850
-
5851
- // src/components/event-calendar/types.ts
5852
- var DEFAULT_WORKING_HOURS = {
5853
- 0: { from: 0, to: 0 },
5854
- // Sunday - closed
5855
- 1: { from: 9, to: 17 },
5856
- // Monday
5857
- 2: { from: 9, to: 17 },
5858
- // Tuesday
5859
- 3: { from: 9, to: 17 },
5860
- // Wednesday
5861
- 4: { from: 9, to: 17 },
5862
- // Thursday
5863
- 5: { from: 9, to: 17 },
5864
- // Friday
5865
- 6: { from: 0, to: 0 }
5866
- // Saturday - closed
5867
- };
5868
- var DEFAULT_VISIBLE_HOURS = { from: 0, to: 24 };
5869
- var EVENT_COLORS = {
5870
- blue: {
5871
- bg: "bg-blue-500/20",
5872
- text: "text-blue-700 dark:text-blue-300",
5873
- border: "border-blue-500"
5874
- },
5875
- green: {
5876
- bg: "bg-green-500/20",
5877
- text: "text-green-700 dark:text-green-300",
5878
- border: "border-green-500"
6200
+ function PlanningTableToolbar({
6201
+ className,
6202
+ table,
6203
+ ...props
6204
+ }) {
6205
+ const isFiltered = table.getState().columnFilters.length > 0;
6206
+ return /* @__PURE__ */ jsxs(
6207
+ "div",
6208
+ {
6209
+ "data-slot": "planning-table-toolbar",
6210
+ className: cn("flex items-center gap-2", className),
6211
+ ...props,
6212
+ children: [
6213
+ /* @__PURE__ */ jsx(
6214
+ Input,
6215
+ {
6216
+ placeholder: "Filter suppliers...",
6217
+ value: table.getColumn("supplier")?.getFilterValue() ?? "",
6218
+ onChange: (event) => table.getColumn("supplier")?.setFilterValue(event.target.value),
6219
+ className: "h-8 w-[150px] lg:w-[250px]"
6220
+ }
6221
+ ),
6222
+ isFiltered && /* @__PURE__ */ jsxs(
6223
+ Button,
6224
+ {
6225
+ variant: "ghost",
6226
+ onClick: () => table.resetColumnFilters(),
6227
+ className: "h-8 px-2 lg:px-3",
6228
+ children: [
6229
+ "Reset",
6230
+ /* @__PURE__ */ jsx(X, { className: "ml-2 h-4 w-4" })
6231
+ ]
6232
+ }
6233
+ )
6234
+ ]
6235
+ }
6236
+ );
6237
+ }
6238
+ function getBadgeVariant(badgeType) {
6239
+ return "outline";
6240
+ }
6241
+ function SupplierCell({
6242
+ className,
6243
+ supplier,
6244
+ ...props
6245
+ }) {
6246
+ const spacingClasses = "px-[var(--j3m-spacing-xs)] pt-[var(--j3m-spacing-s)] pb-2";
6247
+ return /* @__PURE__ */ jsx(
6248
+ "div",
6249
+ {
6250
+ "data-slot": "supplier-cell",
6251
+ className: cn(
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,
6257
+ className
6258
+ ),
6259
+ ...props,
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 }),
6263
+ /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: supplier.scope })
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
+ ] })
6277
+ }
6278
+ );
6279
+ }
6280
+ function getCombinedRiskLevel(data) {
6281
+ const productionStatus = data.production?.status || "on-time";
6282
+ const hasDeliveryCritical = data.deliveries?.some((d) => d.status === "critical");
6283
+ const hasDeliveryDelayed = data.deliveries?.some((d) => d.status === "delayed");
6284
+ if (productionStatus === "critical" || hasDeliveryCritical) {
6285
+ return "critical";
6286
+ }
6287
+ if (productionStatus === "delayed" || hasDeliveryDelayed || data.hasWarning) {
6288
+ return "warning";
6289
+ }
6290
+ return "normal";
6291
+ }
6292
+ function getRowStatus(status) {
6293
+ if (status === "critical") return "critical";
6294
+ if (status === "delayed") return "warning";
6295
+ return "normal";
6296
+ }
6297
+ var statusFillClasses = {
6298
+ normal: {
6299
+ border: "border-l-[3px] border-l-green-500",
6300
+ bg: "bg-green-50/50 dark:bg-green-950/30"
5879
6301
  },
5880
- red: {
5881
- bg: "bg-red-500/20",
5882
- text: "text-red-700 dark:text-red-300",
5883
- border: "border-red-500"
6302
+ warning: {
6303
+ border: "border-l-[3px] border-l-amber-500",
6304
+ bg: "bg-amber-50/50 dark:bg-amber-950/30"
5884
6305
  },
5885
- yellow: {
5886
- bg: "bg-yellow-500/20",
5887
- text: "text-yellow-700 dark:text-yellow-300",
5888
- border: "border-yellow-500"
6306
+ critical: {
6307
+ border: "border-l-[3px] border-l-red-500",
6308
+ bg: "bg-red-50/50 dark:bg-red-950/30"
6309
+ }
6310
+ };
6311
+ var statusColors = {
6312
+ normal: {
6313
+ icon: "text-green-600 dark:text-green-400",
6314
+ progress: "bg-green-500",
6315
+ text: "text-green-700 dark:text-green-300"
5889
6316
  },
5890
- purple: {
5891
- bg: "bg-purple-500/20",
5892
- text: "text-purple-700 dark:text-purple-300",
5893
- border: "border-purple-500"
6317
+ warning: {
6318
+ icon: "text-amber-600 dark:text-amber-400",
6319
+ progress: "bg-amber-500",
6320
+ text: "text-amber-700 dark:text-amber-300"
5894
6321
  },
5895
- orange: {
5896
- bg: "bg-primary/20",
5897
- text: "text-primary dark:text-orange-300",
5898
- border: "border-primary"
6322
+ critical: {
6323
+ icon: "text-red-600 dark:text-red-400",
6324
+ progress: "bg-red-500",
6325
+ text: "text-red-700 dark:text-red-300"
5899
6326
  }
5900
6327
  };
5901
- var VIEW_LABELS = {
5902
- month: "Month",
5903
- week: "Week",
5904
- day: "Day",
5905
- year: "Year",
5906
- agenda: "Agenda"
5907
- };
5908
- var BADGE_VARIANT_LABELS = {
5909
- dot: "Dot",
5910
- colored: "Colored",
5911
- mixed: "Mixed"
5912
- };
5913
- var CalendarContext = React15.createContext(null);
5914
- function EventCalendarProvider({
5915
- children,
5916
- events: initialEvents = [],
5917
- users: initialUsers = [],
5918
- defaultDate = /* @__PURE__ */ new Date(),
5919
- defaultView = "month",
5920
- defaultBadgeVariant = "colored",
5921
- defaultUserId = null,
6328
+ function WeekCell({
6329
+ className,
6330
+ data,
6331
+ week,
6332
+ supplier,
6333
+ isCurrentWeek,
6334
+ onCellClick,
6335
+ ...props
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
+ };
6355
+ const handleClick = () => {
6356
+ if (onCellClick && data.type !== "empty") {
6357
+ onCellClick();
6358
+ }
6359
+ };
6360
+ const handleKeyDown = (e) => {
6361
+ if ((e.key === "Enter" || e.key === " ") && onCellClick && data.type !== "empty") {
6362
+ e.preventDefault();
6363
+ onCellClick();
6364
+ }
6365
+ };
6366
+ const spacingClasses = "px-[var(--j3m-spacing-xs)] pt-[var(--j3m-spacing-s)] pb-2";
6367
+ if (data.type === "empty") {
6368
+ return /* @__PURE__ */ jsx(
6369
+ "div",
6370
+ {
6371
+ "data-slot": "week-cell",
6372
+ "data-state": "empty",
6373
+ "data-current-week": isCurrentWeek,
6374
+ className: cn(
6375
+ "flex h-[80px] items-center justify-center cursor-default",
6376
+ "bg-background",
6377
+ spacingClasses,
6378
+ className
6379
+ ),
6380
+ ...props,
6381
+ children: /* @__PURE__ */ jsx("span", { className: "text-muted-foreground/30 text-xl", children: "\xB7" })
6382
+ }
6383
+ );
6384
+ }
6385
+ if (data.type === "no-logistics") {
6386
+ return /* @__PURE__ */ jsxs(
6387
+ "div",
6388
+ {
6389
+ "data-slot": "week-cell",
6390
+ "data-state": "no-logistics",
6391
+ "data-current-week": isCurrentWeek,
6392
+ onClick: handleClick,
6393
+ onKeyDown: handleKeyDown,
6394
+ role: "button",
6395
+ tabIndex: 0,
6396
+ className: cn(
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)]",
6404
+ className
6405
+ ),
6406
+ ...props,
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
+ ]
6423
+ }
6424
+ );
6425
+ }
6426
+ return /* @__PURE__ */ jsxs(
6427
+ "div",
6428
+ {
6429
+ "data-slot": "week-cell",
6430
+ "data-state": "data",
6431
+ "data-risk": combinedRisk,
6432
+ "data-current-week": isCurrentWeek,
6433
+ onClick: handleClick,
6434
+ onKeyDown: handleKeyDown,
6435
+ role: "button",
6436
+ tabIndex: 0,
6437
+ className: cn(
6438
+ "flex flex-col h-[80px] justify-center gap-2",
6439
+ "cursor-pointer",
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)]",
6447
+ className
6448
+ ),
6449
+ ...props,
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
+ ]
6493
+ }
6494
+ );
6495
+ }
6496
+ function CommentButton({
6497
+ className,
6498
+ commentCount = 0,
6499
+ size = "default",
6500
+ ...props
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";
6505
+ return /* @__PURE__ */ jsxs(
6506
+ Button,
6507
+ {
6508
+ variant: "outline",
6509
+ size: "icon",
6510
+ className: cn(
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",
6516
+ className
6517
+ ),
6518
+ ...props,
6519
+ children: [
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" })
6535
+ ]
6536
+ }
6537
+ );
6538
+ }
6539
+
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
+ }
6582
+ function getWeekKey(date) {
6583
+ const year = date.getFullYear();
6584
+ const weekNumber = getISOWeek(date);
6585
+ return `${year}-W${weekNumber.toString().padStart(2, "0")}`;
6586
+ }
6587
+ function getISOWeek(date) {
6588
+ const d = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()));
6589
+ const dayNum = d.getUTCDay() || 7;
6590
+ d.setUTCDate(d.getUTCDate() + 4 - dayNum);
6591
+ const yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1));
6592
+ return Math.ceil(((d.getTime() - yearStart.getTime()) / 864e5 + 1) / 7);
6593
+ }
6594
+ function generateWeeks(startDate, count) {
6595
+ const weeks = [];
6596
+ const current = new Date(startDate);
6597
+ const today = /* @__PURE__ */ new Date();
6598
+ const currentWeekKey = getWeekKey(today);
6599
+ const dayOfWeek = current.getDay();
6600
+ const daysToMonday = dayOfWeek === 0 ? -6 : 1 - dayOfWeek;
6601
+ current.setDate(current.getDate() + daysToMonday);
6602
+ for (let i = 0; i < count; i++) {
6603
+ const weekStart = new Date(current);
6604
+ const weekEnd = new Date(current);
6605
+ weekEnd.setDate(weekEnd.getDate() + 6);
6606
+ const weekNumber = getISOWeek(weekStart);
6607
+ const year = weekStart.getFullYear();
6608
+ const weekKey = `${year}-W${weekNumber.toString().padStart(2, "0")}`;
6609
+ weeks.push({
6610
+ weekNumber,
6611
+ year,
6612
+ startDate: weekStart,
6613
+ endDate: weekEnd,
6614
+ label: `W${weekNumber.toString().padStart(2, "0")}`,
6615
+ dateRange: formatDateRange(weekStart, weekEnd),
6616
+ isCurrentWeek: weekKey === currentWeekKey
6617
+ });
6618
+ current.setDate(current.getDate() + 7);
6619
+ }
6620
+ return weeks;
6621
+ }
6622
+ function formatDateRange(start, end) {
6623
+ const months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
6624
+ const startMonth = months[start.getMonth()];
6625
+ const endMonth = months[end.getMonth()];
6626
+ if (startMonth === endMonth) {
6627
+ return `${startMonth} ${start.getDate()} - ${end.getDate()}`;
6628
+ }
6629
+ return `${startMonth} ${start.getDate()} - ${endMonth} ${end.getDate()}`;
6630
+ }
6631
+ function formatProductionUnit(unit) {
6632
+ const unitLabels = {
6633
+ quantity: "pcs",
6634
+ kvm: "m\xB2",
6635
+ ton: "ton",
6636
+ kg: "kg",
6637
+ m: "m",
6638
+ pcs: "pcs"
6639
+ };
6640
+ return unitLabels[unit] || unit;
6641
+ }
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
6909
+ }) {
6910
+ return /* @__PURE__ */ jsxs(
6911
+ "div",
6912
+ {
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" }),
6961
+ /* @__PURE__ */ jsx(ArrowUpDown, { className: "ml-2 h-4 w-4" })
6962
+ ]
6963
+ }
6964
+ );
6965
+ }
6966
+ function getSupplierColumn() {
6967
+ return {
6968
+ id: "supplier",
6969
+ accessorKey: "name",
6970
+ header: ({ column }) => /* @__PURE__ */ jsx(SupplierColumnHeader, { column }),
6971
+ cell: ({ row }) => /* @__PURE__ */ jsx(SupplierCell, { supplier: row.original }),
6972
+ enableSorting: true,
6973
+ enableHiding: false
6974
+ };
6975
+ }
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) {
7006
+ return weeks.map((week) => {
7007
+ const weekKey = getWeekKey(week.startDate);
7008
+ return {
7009
+ id: weekKey,
7010
+ accessorFn: (supplier) => supplier.weeks[weekKey],
7011
+ header: () => /* @__PURE__ */ jsx(
7012
+ WeekHeaderWithComments,
7013
+ {
7014
+ week,
7015
+ weekKey,
7016
+ config,
7017
+ suppliers: suppliers ?? []
7018
+ }
7019
+ ),
7020
+ cell: ({ row }) => {
7021
+ const supplier = row.original;
7022
+ const data = supplier.weeks[weekKey] || { type: "empty" };
7023
+ return /* @__PURE__ */ jsx(
7024
+ WeekCell,
7025
+ {
7026
+ data,
7027
+ week,
7028
+ supplier,
7029
+ isCurrentWeek: week.isCurrentWeek,
7030
+ onCellClick: config?.onCellClick ? () => config.onCellClick?.(supplier, week, data) : void 0
7031
+ }
7032
+ );
7033
+ },
7034
+ enableSorting: false,
7035
+ enableHiding: true
7036
+ };
7037
+ });
7038
+ }
7039
+ function generateColumns(weeks, config, suppliers) {
7040
+ return [
7041
+ getSupplierColumn(),
7042
+ ...generateWeekColumns(weeks, config, suppliers)
7043
+ ];
7044
+ }
7045
+ function PlanningTable({
7046
+ className,
7047
+ suppliers,
7048
+ config = {}
7049
+ }) {
7050
+ const {
7051
+ weekCount = 12,
7052
+ startDate = /* @__PURE__ */ new Date(),
7053
+ highlightCurrentWeek = true,
7054
+ showToolbar = true,
7055
+ showPagination = true,
7056
+ pageSizeOptions = [10, 20, 30, 50],
7057
+ defaultPageSize = 10,
7058
+ stickySupplierColumn = true,
7059
+ maxHeight = "600px"
7060
+ } = config;
7061
+ const weeks = React22.useMemo(
7062
+ () => generateWeeks(startDate, weekCount),
7063
+ [startDate, weekCount]
7064
+ );
7065
+ const currentWeekKey = React22.useMemo(() => {
7066
+ const currentWeek = weeks.find((w) => w.isCurrentWeek);
7067
+ return currentWeek ? getWeekKey(currentWeek.startDate) : null;
7068
+ }, [weeks]);
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({});
7077
+ const table = useReactTable({
7078
+ data: suppliers,
7079
+ columns,
7080
+ getCoreRowModel: getCoreRowModel(),
7081
+ getSortedRowModel: getSortedRowModel(),
7082
+ getFilteredRowModel: getFilteredRowModel(),
7083
+ getPaginationRowModel: getPaginationRowModel(),
7084
+ onSortingChange: setSorting,
7085
+ onColumnFiltersChange: setColumnFilters,
7086
+ onColumnVisibilityChange: setColumnVisibility,
7087
+ onRowSelectionChange: setRowSelection,
7088
+ state: {
7089
+ sorting,
7090
+ columnFilters,
7091
+ columnVisibility,
7092
+ rowSelection
7093
+ },
7094
+ initialState: {
7095
+ pagination: {
7096
+ pageSize: defaultPageSize
7097
+ }
7098
+ }
7099
+ });
7100
+ return /* @__PURE__ */ jsxs(
7101
+ "div",
7102
+ {
7103
+ "data-slot": "planning-table",
7104
+ className: cn("flex flex-col gap-4", className),
7105
+ children: [
7106
+ showToolbar && /* @__PURE__ */ jsx(PlanningTableToolbar, { table }),
7107
+ /* @__PURE__ */ jsx("div", { className: "rounded-xl border bg-background shadow-sm overflow-hidden", children: /* @__PURE__ */ jsxs(
7108
+ ScrollArea,
7109
+ {
7110
+ className: "w-full",
7111
+ style: { maxHeight },
7112
+ children: [
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(
7115
+ "tr",
7116
+ {
7117
+ children: headerGroup.headers.map((header, index) => {
7118
+ const isCurrentWeekColumn = header.id === currentWeekKey;
7119
+ return /* @__PURE__ */ jsx(
7120
+ "th",
7121
+ {
7122
+ className: cn(
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)
7126
+ index === 0 && stickySupplierColumn && [
7127
+ "sticky left-0 z-30 min-w-[200px]",
7128
+ "shadow-[var(--j3m-shadow-sticky-edge)]"
7129
+ ],
7130
+ index > 0 && "min-w-[140px]",
7131
+ // Current week: only highlight text/dot, not full background
7132
+ isCurrentWeekColumn && highlightCurrentWeek && "text-primary"
7133
+ ),
7134
+ children: header.isPlaceholder ? null : flexRender(
7135
+ header.column.columnDef.header,
7136
+ header.getContext()
7137
+ )
7138
+ },
7139
+ header.id
7140
+ );
7141
+ })
7142
+ },
7143
+ headerGroup.id
7144
+ )) }),
7145
+ /* @__PURE__ */ jsx("tbody", { className: "bg-background", children: table.getRowModel().rows?.length ? table.getRowModel().rows.map((row) => /* @__PURE__ */ jsx(
7146
+ "tr",
7147
+ {
7148
+ "data-state": row.getIsSelected() && "selected",
7149
+ className: "border-b border-border last:border-b-0",
7150
+ children: row.getVisibleCells().map((cell, index) => {
7151
+ return /* @__PURE__ */ jsx(
7152
+ "td",
7153
+ {
7154
+ className: cn(
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)
7157
+ index === 0 && stickySupplierColumn && [
7158
+ "sticky left-0 z-10 min-w-[200px]",
7159
+ "shadow-[var(--j3m-shadow-sticky-edge)]"
7160
+ ],
7161
+ index > 0 && "min-w-[140px]"
7162
+ ),
7163
+ children: flexRender(
7164
+ cell.column.columnDef.cell,
7165
+ cell.getContext()
7166
+ )
7167
+ },
7168
+ cell.id
7169
+ );
7170
+ })
7171
+ },
7172
+ row.id
7173
+ )) : /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx(
7174
+ "td",
7175
+ {
7176
+ colSpan: columns.length,
7177
+ className: "h-24 text-center text-muted-foreground bg-background",
7178
+ children: "No suppliers found."
7179
+ }
7180
+ ) }) })
7181
+ ] }),
7182
+ /* @__PURE__ */ jsx(ScrollBar, { orientation: "horizontal" }),
7183
+ /* @__PURE__ */ jsx(ScrollBar, { orientation: "vertical" })
7184
+ ]
7185
+ }
7186
+ ) }),
7187
+ showPagination && /* @__PURE__ */ jsx(
7188
+ DataTablePagination,
7189
+ {
7190
+ table,
7191
+ showRowSelection: false,
7192
+ pageSizeOptions
7193
+ }
7194
+ )
7195
+ ]
7196
+ }
7197
+ );
7198
+ }
7199
+ function getStatusBadgeVariant(status) {
7200
+ switch (status) {
7201
+ case "on-time":
7202
+ return "outline";
7203
+ case "delayed":
7204
+ return "secondary";
7205
+ case "critical":
7206
+ return "destructive";
7207
+ default:
7208
+ return "outline";
7209
+ }
7210
+ }
7211
+ function getStatusBadgeClasses(status) {
7212
+ switch (status) {
7213
+ case "on-time":
7214
+ return "border-green-500 text-green-600 bg-green-50 dark:bg-green-950/50";
7215
+ case "delayed":
7216
+ return "border-amber-500 text-amber-600 bg-amber-50 dark:bg-amber-950/50";
7217
+ case "critical":
7218
+ return "";
7219
+ default:
7220
+ return "";
7221
+ }
7222
+ }
7223
+ function getStatusLabel(status) {
7224
+ switch (status) {
7225
+ case "on-time":
7226
+ return "On Track";
7227
+ case "delayed":
7228
+ return "At Risk";
7229
+ case "critical":
7230
+ return "Critical";
7231
+ case "pending":
7232
+ return "Pending";
7233
+ default:
7234
+ return status;
7235
+ }
7236
+ }
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,
7326
+ {
7327
+ className: "w-80 p-0 z-[100]",
7328
+ align: "end",
7329
+ sideOffset: 8,
7330
+ collisionPadding: 16,
7331
+ children: [
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 })
7335
+ ] }),
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,
7359
+ {
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
+ ]
7368
+ }
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
+ ] })
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"
7623
+ ]
7624
+ }
7625
+ ) }),
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" }),
7659
+ /* @__PURE__ */ jsxs("span", { children: [
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
7675
+ ] })
7676
+ ] }),
7677
+ /* @__PURE__ */ jsx("div", { className: "h-2 bg-black/10 dark:bg-white/10 rounded-full overflow-hidden", children: /* @__PURE__ */ jsx(
7678
+ "div",
7679
+ {
7680
+ className: cn(
7681
+ "h-full rounded-full transition-all",
7682
+ sentCount === totalCount ? "bg-green-500" : "bg-primary"
7683
+ ),
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" })
7775
+ ] })
7776
+ ] }) })
7777
+ ] });
7778
+ }
7779
+ function MainView({
7780
+ supplier,
7781
+ week,
7782
+ data,
7783
+ producedValue,
7784
+ hasChanges,
7785
+ onProducedChange,
7786
+ onSave,
7787
+ onSelectDelivery,
7788
+ onAddProductionComment
7789
+ }) {
7790
+ const production = data?.production;
7791
+ const productionProgress = production ? Math.min(100, Math.round(production.produced / production.target * 100)) : data?.progress ?? 0;
7792
+ const productionStatus = production?.status ?? "on-time";
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: [
7797
+ /* @__PURE__ */ jsxs(DialogTitle, { className: "flex items-center gap-2", children: [
7798
+ supplier.name,
7799
+ /* @__PURE__ */ jsx(Badge, { variant: "secondary", className: "text-xs font-normal", children: supplier.badgeType })
7800
+ ] }),
7801
+ /* @__PURE__ */ jsxs(DialogDescription, { className: "flex items-center gap-2", children: [
7802
+ /* @__PURE__ */ jsx(Calendar$1, { className: "h-4 w-4" }),
7803
+ week.label,
7804
+ " \u2022 ",
7805
+ week.dateRange
7806
+ ] })
7807
+ ] }),
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) : ""
7845
+ ] })
7846
+ ] })
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)
7873
+ ] })
7874
+ ] }),
7875
+ /* @__PURE__ */ jsx(
7876
+ Button,
7877
+ {
7878
+ size: "sm",
7879
+ className: "w-full",
7880
+ disabled: !hasChanges,
7881
+ onClick: onSave,
7882
+ children: hasChanges ? "Save Progress" : "No Changes"
7883
+ }
7884
+ )
7885
+ ] })
7886
+ ] }),
7887
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
7888
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
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
+ ")"
7894
+ ] })
7895
+ ] }),
7896
+ /* @__PURE__ */ jsx(
7897
+ ProductionCommentSection,
7898
+ {
7899
+ comments: production?.comments,
7900
+ onAddComment: onAddProductionComment
7901
+ }
7902
+ )
7903
+ ] })
7904
+ ] }),
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
+ )) })
7923
+ ] }),
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" })
7927
+ ] }),
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 })
7935
+ ] })
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
+ );
9121
+ }
9122
+
9123
+ // src/components/event-calendar/types.ts
9124
+ var DEFAULT_WORKING_HOURS = {
9125
+ 0: { from: 0, to: 0 },
9126
+ // Sunday - closed
9127
+ 1: { from: 9, to: 17 },
9128
+ // Monday
9129
+ 2: { from: 9, to: 17 },
9130
+ // Tuesday
9131
+ 3: { from: 9, to: 17 },
9132
+ // Wednesday
9133
+ 4: { from: 9, to: 17 },
9134
+ // Thursday
9135
+ 5: { from: 9, to: 17 },
9136
+ // Friday
9137
+ 6: { from: 0, to: 0 }
9138
+ // Saturday - closed
9139
+ };
9140
+ var DEFAULT_VISIBLE_HOURS = { from: 0, to: 24 };
9141
+ var EVENT_COLORS = {
9142
+ blue: {
9143
+ bg: "bg-blue-500/20",
9144
+ text: "text-blue-700 dark:text-blue-300",
9145
+ border: "border-blue-500"
9146
+ },
9147
+ green: {
9148
+ bg: "bg-green-500/20",
9149
+ text: "text-green-700 dark:text-green-300",
9150
+ border: "border-green-500"
9151
+ },
9152
+ red: {
9153
+ bg: "bg-red-500/20",
9154
+ text: "text-red-700 dark:text-red-300",
9155
+ border: "border-red-500"
9156
+ },
9157
+ yellow: {
9158
+ bg: "bg-yellow-500/20",
9159
+ text: "text-yellow-700 dark:text-yellow-300",
9160
+ border: "border-yellow-500"
9161
+ },
9162
+ purple: {
9163
+ bg: "bg-purple-500/20",
9164
+ text: "text-purple-700 dark:text-purple-300",
9165
+ border: "border-purple-500"
9166
+ },
9167
+ orange: {
9168
+ bg: "bg-primary/20",
9169
+ text: "text-primary dark:text-orange-300",
9170
+ border: "border-primary"
9171
+ }
9172
+ };
9173
+ var VIEW_LABELS = {
9174
+ month: "Month",
9175
+ week: "Week",
9176
+ day: "Day",
9177
+ year: "Year",
9178
+ agenda: "Agenda"
9179
+ };
9180
+ var BADGE_VARIANT_LABELS = {
9181
+ dot: "Dot",
9182
+ colored: "Colored",
9183
+ mixed: "Mixed"
9184
+ };
9185
+ var CalendarContext = React22.createContext(null);
9186
+ function EventCalendarProvider({
9187
+ children,
9188
+ events: initialEvents = [],
9189
+ users: initialUsers = [],
9190
+ defaultDate = /* @__PURE__ */ new Date(),
9191
+ defaultView = "month",
9192
+ defaultBadgeVariant = "colored",
9193
+ defaultUserId = null,
5922
9194
  defaultWorkingHours = DEFAULT_WORKING_HOURS,
5923
9195
  defaultVisibleHours = DEFAULT_VISIBLE_HOURS,
5924
9196
  onEventAdd,
5925
9197
  onEventUpdate,
5926
9198
  onEventDelete
5927
9199
  }) {
5928
- const [selectedDate, setSelectedDate] = React15.useState(defaultDate);
5929
- const [selectedUserId, setSelectedUserId] = React15.useState(defaultUserId);
5930
- const [events, setEventsState] = React15.useState(initialEvents);
5931
- const [users] = React15.useState(initialUsers);
5932
- const [badgeVariant, setBadgeVariant] = React15.useState(defaultBadgeVariant);
5933
- const [view, setView] = React15.useState(defaultView);
5934
- const [workingHours, setWorkingHours] = React15.useState(defaultWorkingHours);
5935
- const [visibleHours, setVisibleHours] = React15.useState(defaultVisibleHours);
5936
- React15.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(() => {
5937
9209
  setEventsState(initialEvents);
5938
9210
  }, [initialEvents]);
5939
- const setEvents = React15.useCallback((newEvents) => {
9211
+ const setEvents = React22.useCallback((newEvents) => {
5940
9212
  setEventsState(newEvents);
5941
9213
  }, []);
5942
- const addEvent = React15.useCallback((event) => {
9214
+ const addEvent = React22.useCallback((event) => {
5943
9215
  setEventsState((prev) => [...prev, event]);
5944
9216
  onEventAdd?.(event);
5945
9217
  }, [onEventAdd]);
5946
- const updateEvent = React15.useCallback((event) => {
9218
+ const updateEvent = React22.useCallback((event) => {
5947
9219
  setEventsState(
5948
9220
  (prev) => prev.map((e) => e.id === event.id ? event : e)
5949
9221
  );
5950
9222
  onEventUpdate?.(event);
5951
9223
  }, [onEventUpdate]);
5952
- const deleteEvent = React15.useCallback((eventId) => {
9224
+ const deleteEvent = React22.useCallback((eventId) => {
5953
9225
  setEventsState((prev) => prev.filter((e) => e.id !== eventId));
5954
9226
  onEventDelete?.(eventId);
5955
9227
  }, [onEventDelete]);
5956
- const goToToday = React15.useCallback(() => {
9228
+ const goToToday = React22.useCallback(() => {
5957
9229
  setSelectedDate(/* @__PURE__ */ new Date());
5958
9230
  }, []);
5959
- const goToPrevious = React15.useCallback(() => {
9231
+ const goToPrevious = React22.useCallback(() => {
5960
9232
  setSelectedDate((current) => {
5961
9233
  switch (view) {
5962
9234
  case "day":
@@ -5974,7 +9246,7 @@ function EventCalendarProvider({
5974
9246
  }
5975
9247
  });
5976
9248
  }, [view]);
5977
- const goToNext = React15.useCallback(() => {
9249
+ const goToNext = React22.useCallback(() => {
5978
9250
  setSelectedDate((current) => {
5979
9251
  switch (view) {
5980
9252
  case "day":
@@ -5992,7 +9264,7 @@ function EventCalendarProvider({
5992
9264
  }
5993
9265
  });
5994
9266
  }, [view]);
5995
- const contextValue = React15.useMemo(
9267
+ const contextValue = React22.useMemo(
5996
9268
  () => ({
5997
9269
  // State
5998
9270
  selectedDate,
@@ -6039,7 +9311,7 @@ function EventCalendarProvider({
6039
9311
  return /* @__PURE__ */ jsx(CalendarContext.Provider, { value: contextValue, children });
6040
9312
  }
6041
9313
  function useEventCalendar() {
6042
- const context = React15.useContext(CalendarContext);
9314
+ const context = React22.useContext(CalendarContext);
6043
9315
  if (!context) {
6044
9316
  throw new Error("useEventCalendar must be used within an EventCalendarProvider");
6045
9317
  }
@@ -6047,14 +9319,14 @@ function useEventCalendar() {
6047
9319
  }
6048
9320
  function useFilteredEvents() {
6049
9321
  const { events, selectedUserId } = useEventCalendar();
6050
- return React15.useMemo(() => {
9322
+ return React22.useMemo(() => {
6051
9323
  if (!selectedUserId) return events;
6052
9324
  return events.filter((event) => event.user.id === selectedUserId);
6053
9325
  }, [events, selectedUserId]);
6054
9326
  }
6055
9327
  function useEventsInRange(startDate, endDate) {
6056
9328
  const filteredEvents = useFilteredEvents();
6057
- return React15.useMemo(() => {
9329
+ return React22.useMemo(() => {
6058
9330
  return filteredEvents.filter((event) => {
6059
9331
  const eventStart = new Date(event.startDate);
6060
9332
  const eventEnd = new Date(event.endDate);
@@ -6428,7 +9700,7 @@ function getViewDateRange(date, view) {
6428
9700
  return { start: startOfMonth(date), end: endOfMonth(date) };
6429
9701
  }
6430
9702
  }
6431
- function formatDateRange(start, end) {
9703
+ function formatDateRange2(start, end) {
6432
9704
  if (isSameDay(start, end)) {
6433
9705
  return format(start, "MMM d, yyyy");
6434
9706
  }
@@ -6612,8 +9884,8 @@ function MoreEvents({ count, onClick, className }) {
6612
9884
  );
6613
9885
  }
6614
9886
  function TimeIndicator({ className }) {
6615
- const [now, setNow] = React15.useState(/* @__PURE__ */ new Date());
6616
- React15.useEffect(() => {
9887
+ const [now, setNow] = React22.useState(/* @__PURE__ */ new Date());
9888
+ React22.useEffect(() => {
6617
9889
  const interval = setInterval(() => setNow(/* @__PURE__ */ new Date()), 6e4);
6618
9890
  return () => clearInterval(interval);
6619
9891
  }, []);
@@ -6650,24 +9922,24 @@ function DateBadge({ date, className }) {
6650
9922
  }
6651
9923
  );
6652
9924
  }
6653
- var DragContext = React15.createContext(null);
9925
+ var DragContext = React22.createContext(null);
6654
9926
  function DragProvider({
6655
9927
  children,
6656
9928
  snapMinutes = 15,
6657
9929
  onDragStart,
6658
9930
  onDragEnd
6659
9931
  }) {
6660
- const [draggedEvent, setDraggedEventState] = React15.useState(null);
6661
- const [isDragging, setIsDragging] = React15.useState(false);
9932
+ const [draggedEvent, setDraggedEventState] = React22.useState(null);
9933
+ const [isDragging, setIsDragging] = React22.useState(false);
6662
9934
  const { updateEvent } = useEventCalendar();
6663
- const setDraggedEvent = React15.useCallback((event) => {
9935
+ const setDraggedEvent = React22.useCallback((event) => {
6664
9936
  setDraggedEventState(event);
6665
9937
  setIsDragging(!!event);
6666
9938
  if (event) {
6667
9939
  onDragStart?.(event);
6668
9940
  }
6669
9941
  }, [onDragStart]);
6670
- const handleDrop = React15.useCallback((newStartDate) => {
9942
+ const handleDrop = React22.useCallback((newStartDate) => {
6671
9943
  if (!draggedEvent) return;
6672
9944
  const snappedDate = snapToInterval(newStartDate, snapMinutes);
6673
9945
  const { startDate, endDate } = calculateDropDates(draggedEvent, snappedDate);
@@ -6680,7 +9952,7 @@ function DragProvider({
6680
9952
  onDragEnd?.(updatedEvent, new Date(startDate), new Date(endDate));
6681
9953
  setDraggedEvent(null);
6682
9954
  }, [draggedEvent, snapMinutes, updateEvent, onDragEnd, setDraggedEvent]);
6683
- const contextValue = React15.useMemo(
9955
+ const contextValue = React22.useMemo(
6684
9956
  () => ({
6685
9957
  draggedEvent,
6686
9958
  setDraggedEvent,
@@ -6691,7 +9963,7 @@ function DragProvider({
6691
9963
  return /* @__PURE__ */ jsx(DragContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx(DragDropHandler, { onDrop: handleDrop, children }) });
6692
9964
  }
6693
9965
  function useDrag() {
6694
- const context = React15.useContext(DragContext);
9966
+ const context = React22.useContext(DragContext);
6695
9967
  if (!context) {
6696
9968
  throw new Error("useDrag must be used within a DragProvider");
6697
9969
  }
@@ -6736,7 +10008,7 @@ function DroppableZone({
6736
10008
  }) {
6737
10009
  const { draggedEvent, setDraggedEvent } = useDrag();
6738
10010
  const { updateEvent } = useEventCalendar();
6739
- const [isOver, setIsOver] = React15.useState(false);
10011
+ const [isOver, setIsOver] = React22.useState(false);
6740
10012
  const handleDragOver = (e) => {
6741
10013
  e.preventDefault();
6742
10014
  e.dataTransfer.dropEffect = "move";
@@ -6774,23 +10046,23 @@ function DroppableZone({
6774
10046
  function useDroppable({ date, hour, minute = 0, onDrop }) {
6775
10047
  const { draggedEvent, setDraggedEvent } = useDrag();
6776
10048
  const { updateEvent } = useEventCalendar();
6777
- const [isOver, setIsOver] = React15.useState(false);
6778
- const dropTargetDate = React15.useMemo(() => {
10049
+ const [isOver, setIsOver] = React22.useState(false);
10050
+ const dropTargetDate = React22.useMemo(() => {
6779
10051
  const targetDate = new Date(date);
6780
10052
  if (hour !== void 0) {
6781
10053
  targetDate.setHours(hour, minute, 0, 0);
6782
10054
  }
6783
10055
  return targetDate;
6784
10056
  }, [date, hour, minute]);
6785
- const handleDragOver = React15.useCallback((e) => {
10057
+ const handleDragOver = React22.useCallback((e) => {
6786
10058
  e.preventDefault();
6787
10059
  e.dataTransfer.dropEffect = "move";
6788
10060
  if (!isOver) setIsOver(true);
6789
10061
  }, [isOver]);
6790
- const handleDragLeave = React15.useCallback(() => {
10062
+ const handleDragLeave = React22.useCallback(() => {
6791
10063
  setIsOver(false);
6792
10064
  }, []);
6793
- const handleDrop = React15.useCallback((e) => {
10065
+ const handleDrop = React22.useCallback((e) => {
6794
10066
  e.preventDefault();
6795
10067
  setIsOver(false);
6796
10068
  if (!draggedEvent) return;
@@ -6817,13 +10089,13 @@ function useDroppable({ date, hour, minute = 0, onDrop }) {
6817
10089
  function useDraggable(event, disabled = false) {
6818
10090
  const { setDraggedEvent, draggedEvent } = useDrag();
6819
10091
  const isDragged = draggedEvent?.id === event.id;
6820
- const handleDragStart = React15.useCallback((e) => {
10092
+ const handleDragStart = React22.useCallback((e) => {
6821
10093
  if (disabled) return;
6822
10094
  e.dataTransfer.effectAllowed = "move";
6823
10095
  e.dataTransfer.setData("text/plain", event.id);
6824
10096
  setDraggedEvent(event);
6825
10097
  }, [disabled, event, setDraggedEvent]);
6826
- const handleDragEnd = React15.useCallback(() => {
10098
+ const handleDragEnd = React22.useCallback(() => {
6827
10099
  setDraggedEvent(null);
6828
10100
  }, [setDraggedEvent]);
6829
10101
  return {
@@ -6864,15 +10136,15 @@ function MonthView({
6864
10136
  }) {
6865
10137
  const { selectedDate, badgeVariant, setSelectedDate, setView } = useEventCalendar();
6866
10138
  const filteredEvents = useFilteredEvents();
6867
- const { singleDayEvents, multiDayEvents } = React15.useMemo(
10139
+ const { singleDayEvents, multiDayEvents } = React22.useMemo(
6868
10140
  () => splitEventsByDuration(filteredEvents),
6869
10141
  [filteredEvents]
6870
10142
  );
6871
- const cells = React15.useMemo(
10143
+ const cells = React22.useMemo(
6872
10144
  () => getCalendarCells(selectedDate),
6873
10145
  [selectedDate]
6874
10146
  );
6875
- const eventPositions = React15.useMemo(
10147
+ const eventPositions = React22.useMemo(
6876
10148
  () => calculateMonthEventPositions(multiDayEvents, singleDayEvents, selectedDate),
6877
10149
  [multiDayEvents, singleDayEvents, selectedDate]
6878
10150
  );
@@ -7054,7 +10326,7 @@ function WeekView({
7054
10326
  visibleHours
7055
10327
  } = useEventCalendar();
7056
10328
  const filteredEvents = useFilteredEvents();
7057
- const { singleDayEvents, multiDayEvents } = React15.useMemo(
10329
+ const { singleDayEvents, multiDayEvents } = React22.useMemo(
7058
10330
  () => splitEventsByDuration(filteredEvents),
7059
10331
  [filteredEvents]
7060
10332
  );
@@ -7260,8 +10532,8 @@ function CalendarTimeline({
7260
10532
  firstVisibleHour,
7261
10533
  lastVisibleHour
7262
10534
  }) {
7263
- const [currentTime, setCurrentTime] = React15.useState(/* @__PURE__ */ new Date());
7264
- React15.useEffect(() => {
10535
+ const [currentTime, setCurrentTime] = React22.useState(/* @__PURE__ */ new Date());
10536
+ React22.useEffect(() => {
7265
10537
  const interval = setInterval(() => {
7266
10538
  setCurrentTime(/* @__PURE__ */ new Date());
7267
10539
  }, 6e4);
@@ -7344,7 +10616,7 @@ function DayView({
7344
10616
  visibleHours
7345
10617
  } = useEventCalendar();
7346
10618
  const filteredEvents = useFilteredEvents();
7347
- const { singleDayEvents, multiDayEvents } = React15.useMemo(
10619
+ const { singleDayEvents, multiDayEvents } = React22.useMemo(
7348
10620
  () => splitEventsByDuration(filteredEvents),
7349
10621
  [filteredEvents]
7350
10622
  );
@@ -7352,7 +10624,7 @@ function DayView({
7352
10624
  visibleHours,
7353
10625
  singleDayEvents
7354
10626
  );
7355
- const currentEvents = React15.useMemo(() => {
10627
+ const currentEvents = React22.useMemo(() => {
7356
10628
  if (!isToday(selectedDate)) return [];
7357
10629
  return getCurrentEvents(singleDayEvents);
7358
10630
  }, [singleDayEvents, selectedDate]);
@@ -7576,8 +10848,8 @@ function CalendarTimeline2({
7576
10848
  firstVisibleHour,
7577
10849
  lastVisibleHour
7578
10850
  }) {
7579
- const [currentTime, setCurrentTime] = React15.useState(/* @__PURE__ */ new Date());
7580
- React15.useEffect(() => {
10851
+ const [currentTime, setCurrentTime] = React22.useState(/* @__PURE__ */ new Date());
10852
+ React22.useEffect(() => {
7581
10853
  const interval = setInterval(() => {
7582
10854
  setCurrentTime(/* @__PURE__ */ new Date());
7583
10855
  }, 6e4);
@@ -7611,7 +10883,7 @@ function YearView({
7611
10883
  }) {
7612
10884
  const { selectedDate, setSelectedDate, setView } = useEventCalendar();
7613
10885
  const filteredEvents = useFilteredEvents();
7614
- const months = React15.useMemo(() => {
10886
+ const months = React22.useMemo(() => {
7615
10887
  const yearStart = startOfYear(selectedDate);
7616
10888
  return Array.from({ length: 12 }, (_, i) => addMonths(yearStart, i));
7617
10889
  }, [selectedDate]);
@@ -7734,11 +11006,11 @@ function AgendaView({
7734
11006
  }) {
7735
11007
  const { selectedDate, setSelectedDate, setView } = useEventCalendar();
7736
11008
  const filteredEvents = useFilteredEvents();
7737
- const { singleDayEvents, multiDayEvents } = React15.useMemo(
11009
+ const { singleDayEvents, multiDayEvents } = React22.useMemo(
7738
11010
  () => splitEventsByDuration(filteredEvents),
7739
11011
  [filteredEvents]
7740
11012
  );
7741
- const eventsByDay = React15.useMemo(() => {
11013
+ const eventsByDay = React22.useMemo(() => {
7742
11014
  const allDates = /* @__PURE__ */ new Map();
7743
11015
  singleDayEvents.forEach((event) => {
7744
11016
  const eventDate = parseISO(event.startDate);
@@ -7931,7 +11203,7 @@ function CalendarHeader({
7931
11203
  const filteredEvents = useFilteredEvents();
7932
11204
  const eventCount = filteredEvents.length;
7933
11205
  const { start: rangeStart, end: rangeEnd } = getViewDateRange(selectedDate, view);
7934
- const dateRangeLabel = formatDateRange(rangeStart, rangeEnd);
11206
+ const dateRangeLabel = formatDateRange2(rangeStart, rangeEnd);
7935
11207
  const getInitials = (name) => {
7936
11208
  return name.split(" ").map((n) => n[0]).join("").toUpperCase().slice(0, 2);
7937
11209
  };
@@ -8203,16 +11475,16 @@ function EventDialog({
8203
11475
  defaultUserId
8204
11476
  }) {
8205
11477
  const { addEvent, updateEvent, deleteEvent, users } = useEventCalendar();
8206
- const [title, setTitle] = React15.useState("");
8207
- const [description, setDescription] = React15.useState("");
8208
- const [startDate, setStartDate] = React15.useState("");
8209
- const [startTime, setStartTime] = React15.useState("");
8210
- const [endDate, setEndDate] = React15.useState("");
8211
- const [endTime, setEndTime] = React15.useState("");
8212
- const [color, setColor] = React15.useState("blue");
8213
- const [userId, setUserId] = React15.useState("");
8214
- const [isSubmitting, setIsSubmitting] = React15.useState(false);
8215
- React15.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(() => {
8216
11488
  if (open) {
8217
11489
  if (mode === "edit" && event) {
8218
11490
  const start = parseISO(event.startDate);
@@ -8435,7 +11707,7 @@ function QuickAddEvent({
8435
11707
  onOpenDialog,
8436
11708
  onClose
8437
11709
  }) {
8438
- const [title, setTitle] = React15.useState("");
11710
+ const [title, setTitle] = React22.useState("");
8439
11711
  const { users } = useEventCalendar();
8440
11712
  const handleSubmit = (e) => {
8441
11713
  e.preventDefault();
@@ -8502,8 +11774,8 @@ var HOUR_OPTIONS = Array.from({ length: 25 }, (_, i) => {
8502
11774
  });
8503
11775
  function ChangeVisibleHoursInput() {
8504
11776
  const { visibleHours, setVisibleHours } = useEventCalendar();
8505
- const [from, setFrom] = React15.useState(visibleHours.from);
8506
- const [to, setTo] = React15.useState(visibleHours.to);
11777
+ const [from, setFrom] = React22.useState(visibleHours.from);
11778
+ const [to, setTo] = React22.useState(visibleHours.to);
8507
11779
  const handleApply = () => {
8508
11780
  const toHour = to === 0 ? 24 : to;
8509
11781
  setVisibleHours({ from, to: toHour });
@@ -8549,7 +11821,7 @@ var HOUR_OPTIONS2 = Array.from({ length: 25 }, (_, i) => {
8549
11821
  });
8550
11822
  function ChangeWorkingHoursInput() {
8551
11823
  const { workingHours, setWorkingHours } = useEventCalendar();
8552
- const [localWorkingHours, setLocalWorkingHours] = React15.useState({
11824
+ const [localWorkingHours, setLocalWorkingHours] = React22.useState({
8553
11825
  ...workingHours
8554
11826
  });
8555
11827
  const handleToggleDay = (dayId) => {
@@ -8698,8 +11970,8 @@ function CalendarSettingsButton({
8698
11970
  );
8699
11971
  }
8700
11972
  function useMediaQuery(query) {
8701
- const [matches, setMatches] = React15.useState(false);
8702
- React15.useEffect(() => {
11973
+ const [matches, setMatches] = React22.useState(false);
11974
+ React22.useEffect(() => {
8703
11975
  const media = window.matchMedia(query);
8704
11976
  setMatches(media.matches);
8705
11977
  const listener = (event) => {
@@ -8751,11 +12023,11 @@ function BigCalendarInner({
8751
12023
  maxEventsPerDay
8752
12024
  }) {
8753
12025
  const { view, setView } = useEventCalendar();
8754
- const [dialogOpen, setDialogOpen] = React15.useState(false);
8755
- const [settingsDialogOpen, setSettingsDialogOpen] = React15.useState(false);
8756
- const [selectedEvent, setSelectedEvent] = React15.useState(null);
8757
- const [dialogMode, setDialogMode] = React15.useState("add");
8758
- const [defaultDate, setDefaultDate] = React15.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());
8759
12031
  const isMobile = useMediaQuery("(max-width: 768px)");
8760
12032
  const isCompact = compact === "auto" ? isMobile : compact;
8761
12033
  const handleAddClick = () => {
@@ -8914,6 +12186,6 @@ function CalendarView({
8914
12186
  }
8915
12187
  }
8916
12188
 
8917
- 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, DateBadge, DayView, 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, 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, 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, WeekView, YearView, badgeVariants, buttonGroupVariants, buttonVariants, calculateDropDates, calculateMonthEventPositions, cardVariants, createDefaultEvent, formatDateRange, formatTime, generateEventId, getCalendarCells, getCurrentEvents, getDayHours, getEventBlockStyle, getEventDuration, getEventDurationMinutes, getEventsCount, getEventsForDate, getEventsInRange, getHeaderLabel, getMonthCellEvents, getMonthDays, getTimeHeight, getTimePosition, getViewDateRange, getVisibleHours, getWeekDayNames, getWeekDays, 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 };
8918
12190
  //# sourceMappingURL=index.js.map
8919
12191
  //# sourceMappingURL=index.js.map