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