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